address: make bech32 addrs more sane.

This commit is contained in:
Christopher Jeffrey 2017-05-13 00:16:18 -07:00
parent 1eb08d39f4
commit 0ea341772c
No known key found for this signature in database
GPG Key ID: 8962AB9DE6666BBD
6 changed files with 80 additions and 104 deletions

View File

@ -49,23 +49,14 @@ function Address(options) {
}
/**
* Address types. Note that the values
* have a direct mapping to script types.
* These also represent the "prefix type"
* as a network-agnostic version of the
* prefix byte. They DO NOT represent the
* script type. For example, script type
* `WITNESSMASTHASH` would be prefix type
* `WITNESSSCRIPTHASH` with a `version`
* of 1.
* Address types.
* @enum {Number}
*/
Address.types = {
PUBKEYHASH: common.types.PUBKEYHASH,
SCRIPTHASH: common.types.SCRIPTHASH,
WITNESSSCRIPTHASH: common.types.WITNESSSCRIPTHASH,
WITNESSPUBKEYHASH: common.types.WITNESSPUBKEYHASH
PUBKEYHASH: 2,
SCRIPTHASH: 3,
WITNESS: 4
};
/**
@ -128,7 +119,7 @@ Address.prototype.getPrefix = function getPrefix(network) {
if (!network)
network = this.network;
network = Network.get(network);
return Address.getPrefix(this.type, network);
return Address.getPrefix(this.type, this.hash, network);
};
/**
@ -231,7 +222,6 @@ Address.prototype.toBech32 = function toBech32(network) {
network = this.network;
network = Network.get(network);
hrp = network.addressPrefix.bech32;
data = bech32.bitsify(hash, 65, 8, 5, version, 0);
@ -248,14 +238,24 @@ Address.prototype.toBech32 = function toBech32(network) {
*/
Address.prototype.fromString = function fromString(addr, network) {
var i, type, hrp;
assert(typeof addr === 'string');
assert(addr.length > 2);
if (addr[0] === 'b' && addr[1] === 'c')
return this.fromBech32(addr, network);
if (addr[0] === 't' && addr[1] === 'b')
return this.fromBech32(addr, network);
if (network) {
network = Network.get(network);
hrp = network.addressPrefix.bech32;
if (util.startsWith(addr, hrp))
return this.fromBech32(addr, network);
} else {
for (i = 0; i < networks.types.length; i++) {
type = networks.types[i];
hrp = networks[type].addressPrefix.bech32;
if (util.startsWith(addr, hrp))
return this.fromBech32(addr, type);
}
}
return this.fromBase58(addr, network);
};
@ -383,7 +383,8 @@ Address.fromBase58 = function fromBase58(address, network) {
*/
Address.prototype.fromBech32 = function fromBech32(data, network) {
var i, addr, hash, type, version;
var type = Address.types.WITNESS;
var i, addr, hash, version;
assert(typeof data === 'string');
@ -410,19 +411,6 @@ Address.prototype.fromBech32 = function fromBech32(data, network) {
hash = bech32.bitsify(addr.data, 84, 5, 8, -1, 1);
// TODO: Remove this by dropping old segwit addrs.
switch (hash.length) {
case 20:
type = Address.types.WITNESSPUBKEYHASH;
break;
case 32:
type = Address.types.WITNESSSCRIPTHASH;
break;
default:
assert(false, 'Unknown witness program data length.');
break;
}
return this.fromHash(hash, type, version, network.type);
};
@ -468,21 +456,21 @@ Address.prototype.fromScript = function fromScript(script) {
if (script.isWitnessPubkeyhash()) {
this.hash = script.get(1);
this.type = Address.types.WITNESSPUBKEYHASH;
this.type = Address.types.WITNESS;
this.version = 0;
return this;
}
if (script.isWitnessScripthash()) {
this.hash = script.get(1);
this.type = Address.types.WITNESSSCRIPTHASH;
this.type = Address.types.WITNESS;
this.version = 0;
return this;
}
if (script.isWitnessMasthash()) {
this.hash = script.get(1);
this.type = Address.types.WITNESSSCRIPTHASH;
this.type = Address.types.WITNESS;
this.version = 1;
return this;
}
@ -507,14 +495,14 @@ Address.prototype.fromWitness = function fromWitness(witness) {
// since we can't get the version.
if (witness.isPubkeyhashInput()) {
this.hash = crypto.hash160(witness.get(1));
this.type = Address.types.WITNESSPUBKEYHASH;
this.type = Address.types.WITNESS;
this.version = 0;
return this;
}
if (witness.isScripthashInput()) {
this.hash = crypto.sha256(witness.get(witness.length - 1));
this.type = Address.types.WITNESSSCRIPTHASH;
this.type = Address.types.WITNESS;
this.version = 0;
return this;
}
@ -610,20 +598,19 @@ Address.prototype.fromHash = function fromHash(hash, type, version, network) {
assert(util.isNumber(type));
assert(util.isNumber(version));
assert(Address.getPrefix(type, network) !== -1, 'Not a valid address type.');
assert(type >= Address.types.PUBKEYHASH && type <= Address.types.WITNESS,
'Not a valid address type.');
if (version === -1) {
assert(!Address.isWitness(type), 'Wrong version (witness)');
assert(type !== Address.types.WITNESS, 'Wrong version (witness)');
assert(hash.length === 20, 'Hash is the wrong size.');
} else {
assert(Address.isWitness(type), 'Wrong version (non-witness).');
assert(type === Address.types.WITNESS, 'Wrong version (non-witness).');
assert(version >= 0 && version <= 16, 'Bad program version.');
if (version === 0 && type === Address.types.WITNESSPUBKEYHASH)
assert(hash.length === 20, 'Hash is the wrong size.');
else if (version === 0 && type === Address.types.WITNESSSCRIPTHASH)
assert(hash.length === 32, 'Hash is the wrong size.');
else if (version === 1 && type === Address.types.WITNESSSCRIPTHASH)
assert(hash.length === 32, 'Hash is the wrong size.');
if (version === 0 && type === Address.types.WITNESS) {
assert(hash.length === 20 || hash.length === 32,
'Witness program hash is the wrong size.');
}
assert(hash.length >= 2 && hash.length <= 40, 'Hash is the wrong size.');
}
@ -706,7 +693,8 @@ Address.fromScripthash = function fromScripthash(hash, network) {
*/
Address.prototype.fromWitnessPubkeyhash = function fromWitnessPubkeyhash(hash, network) {
var type = Address.types.WITNESSPUBKEYHASH;
var type = Address.types.WITNESS;
assert(hash.length === 20, 'P2WPKH must be 20 bytes.');
return this.fromHash(hash, type, 0, network);
};
@ -730,7 +718,8 @@ Address.fromWitnessPubkeyhash = function fromWitnessPubkeyhash(hash, network) {
*/
Address.prototype.fromWitnessScripthash = function fromWitnessScripthash(hash, network) {
var type = Address.types.WITNESSSCRIPTHASH;
var type = Address.types.WITNESS;
assert(hash.length === 32, 'P2WPKH must be 32 bytes.');
return this.fromHash(hash, type, 0, network);
};
@ -755,25 +744,13 @@ Address.fromWitnessScripthash = function fromWitnessScripthash(hash, network) {
*/
Address.prototype.fromProgram = function fromProgram(version, hash, network) {
var type;
var type = Address.types.WITNESS;
assert(version >= 0, 'Bad version for witness program.');
if (typeof hash === 'string')
hash = new Buffer(hash, 'hex');
switch (hash.length) {
case 20:
type = Address.types.WITNESSPUBKEYHASH;
break;
case 32:
type = Address.types.WITNESSSCRIPTHASH;
break;
default:
assert(false, 'Unknown witness program data length.');
break;
}
return this.fromHash(hash, type, version, network);
};
@ -813,7 +790,7 @@ Address.prototype.isScripthash = function isScripthash() {
*/
Address.prototype.isWitnessPubkeyhash = function isWitnessPubkeyhash() {
return this.version === 0 && this.type === Address.types.WITNESSPUBKEYHASH;
return this.version === 0 && this.hash.length === 20;
};
/**
@ -822,7 +799,7 @@ Address.prototype.isWitnessPubkeyhash = function isWitnessPubkeyhash() {
*/
Address.prototype.isWitnessScripthash = function isWitnessScripthash() {
return this.version === 0 && this.type === Address.types.WITNESSSCRIPTHASH;
return this.version === 0 && this.hash.length === 32;
};
/**
@ -831,7 +808,7 @@ Address.prototype.isWitnessScripthash = function isWitnessScripthash() {
*/
Address.prototype.isWitnessMasthash = function isWitnessMasthash() {
return this.version === 1 && this.type === Address.types.WITNESSSCRIPTHASH;
return this.version === 1 && this.hash.length === 32;
};
/**
@ -843,6 +820,21 @@ Address.prototype.isProgram = function isProgram() {
return this.version !== -1;
};
/**
* Test whether the address is an unknown witness program.
* @returns {Boolean}
*/
Address.prototype.isUnknown = function isUnknown() {
if (this.version === -1)
return false;
if (this.version > 0)
return true;
return this.hash.length !== 20 && this.hash.length !== 32;
};
/**
* Get the hash of a base58 address or address-related object.
* @param {Base58Address|Address|Hash} data
@ -878,21 +870,24 @@ Address.getHash = function getHash(data, enc) {
/**
* Get a network address prefix for a specified address type.
* @param {AddressPrefix} type
* @param {Buffer} hash
* @param {Network} network
* @returns {Number}
*/
Address.getPrefix = function getPrefix(type, network) {
Address.getPrefix = function getPrefix(type, hash, network) {
var prefixes = network.addressPrefix;
switch (type) {
case Address.types.PUBKEYHASH:
return prefixes.pubkeyhash;
case Address.types.SCRIPTHASH:
return prefixes.scripthash;
case Address.types.WITNESSPUBKEYHASH:
return prefixes.witnesspubkeyhash;
case Address.types.WITNESSSCRIPTHASH:
return prefixes.witnessscripthash;
case Address.types.WITNESS:
if (hash.length === 20)
return prefixes.witnesspubkeyhash;
if (hash.length === 32)
return prefixes.witnessscripthash;
assert(false, 'No witness prefix defined.');
default:
return -1;
}
@ -913,31 +908,14 @@ Address.getType = function getType(prefix, network) {
case prefixes.scripthash:
return Address.types.SCRIPTHASH;
case prefixes.witnesspubkeyhash:
return Address.types.WITNESSPUBKEYHASH;
return Address.types.WITNESS;
case prefixes.witnessscripthash:
return Address.types.WITNESSSCRIPTHASH;
return Address.types.WITNESS;
default:
return -1;
}
};
/**
* Test whether an address type is a witness program.
* @param {AddressPrefix} type
* @returns {Boolean}
*/
Address.isWitness = function isWitness(type) {
switch (type) {
case Address.types.WITNESSPUBKEYHASH:
return true;
case Address.types.WITNESSSCRIPTHASH:
return true;
default:
return false;
}
};
/*
* Expose
*/

View File

@ -763,11 +763,8 @@ KeyRing.prototype.getType = function getType() {
if (this.nested)
return Address.types.SCRIPTHASH;
if (this.witness) {
if (this.script)
return Address.types.WITNESSSCRIPTHASH;
return Address.types.WITNESSPUBKEYHASH;
}
if (this.witness)
return Address.types.WITNESS;
if (this.script)
return Address.types.SCRIPTHASH;

View File

@ -157,6 +157,9 @@ Path.prototype.fromRaw = function fromRaw(data) {
this.version = br.read8();
this.type = br.readU8();
if (this.type === 129 || this.type === 130)
this.type = 4;
return this;
};

View File

@ -257,8 +257,7 @@ describe('Bech32', function() {
ok2 = null;
}
ok = ok1 === null && ok2 === null;
assert(ok);
assert(!ok2);
});
});
});

View File

@ -578,7 +578,7 @@ describe('Chain', function() {
it('should add wit addrs to miner', co(function* () {
miner.addresses.length = 0;
miner.addAddress(wwallet.getReceive());
assert.equal(wwallet.getReceive().getType(), 'witnesspubkeyhash');
assert.equal(wwallet.getReceive().getType(), 'witness');
}));
it('should mine 2000 witness blocks', co(function* () {

View File

@ -16,7 +16,6 @@ var Input = require('../lib/primitives/input');
var Outpoint = require('../lib/primitives/outpoint');
var Script = require('../lib/script/script');
var HD = require('../lib/hd');
var scriptTypes = Script.types;
var KEY1 = 'xprv9s21ZrQH143K3Aj6xQBymM31Zb4BVc7wxqfUhMZrzewdDVCt'
+ 'qUP9iWfcHgJofs25xbaUpCps9GDXj83NiWvQCAkWQhVj5J4CorfnpKX94AZ';
@ -114,9 +113,9 @@ describe('Wallet', function() {
addr = Address.fromString(w.getAddress('string'));
if (witness)
assert.equal(addr.type, scriptTypes.WITNESSPUBKEYHASH);
assert.equal(addr.type, Address.types.WITNESS);
else
assert.equal(addr.type, scriptTypes.PUBKEYHASH);
assert.equal(addr.type, Address.types.PUBKEYHASH);
src = new MTX();
src.addInput(dummy());
@ -652,11 +651,11 @@ describe('Wallet', function() {
if (witness) {
if (bullshitNesting)
assert.equal(addr.type, scriptTypes.SCRIPTHASH);
assert.equal(addr.type, Address.types.SCRIPTHASH);
else
assert.equal(addr.type, scriptTypes.WITNESSSCRIPTHASH);
assert.equal(addr.type, Address.types.WITNESS);
} else {
assert.equal(addr.type, scriptTypes.SCRIPTHASH);
assert.equal(addr.type, Address.types.SCRIPTHASH);
}
assert.equal(w1.account[rec].getAddress('string'), b58);