diff --git a/lib/primitives/address.js b/lib/primitives/address.js index 84c51df4..5a76a8b1 100644 --- a/lib/primitives/address.js +++ b/lib/primitives/address.js @@ -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 */ diff --git a/lib/primitives/keyring.js b/lib/primitives/keyring.js index 8886ae37..f96f8fb8 100644 --- a/lib/primitives/keyring.js +++ b/lib/primitives/keyring.js @@ -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; diff --git a/lib/wallet/path.js b/lib/wallet/path.js index 1a649705..5066f048 100644 --- a/lib/wallet/path.js +++ b/lib/wallet/path.js @@ -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; }; diff --git a/test/bech32-test.js b/test/bech32-test.js index be6ab58d..010dbb81 100644 --- a/test/bech32-test.js +++ b/test/bech32-test.js @@ -257,8 +257,7 @@ describe('Bech32', function() { ok2 = null; } - ok = ok1 === null && ok2 === null; - assert(ok); + assert(!ok2); }); }); }); diff --git a/test/chain-test.js b/test/chain-test.js index 4b70dc87..55acc3f1 100644 --- a/test/chain-test.js +++ b/test/chain-test.js @@ -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* () { diff --git a/test/wallet-test.js b/test/wallet-test.js index 8cfb643c..be5c1f72 100644 --- a/test/wallet-test.js +++ b/test/wallet-test.js @@ -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);