From a669afa162a6a547f738a7b7ccc8634e0736b9f0 Mon Sep 17 00:00:00 2001 From: Matthew Zipkin Date: Wed, 6 Mar 2019 18:03:11 -0800 Subject: [PATCH 1/2] address: derive network --- lib/primitives/address.js | 29 ++++++++++++++++++++++------- 1 file changed, 22 insertions(+), 7 deletions(-) diff --git a/lib/primitives/address.js b/lib/primitives/address.js index 6bb618c73..d5a4bcd75 100644 --- a/lib/primitives/address.js +++ b/lib/primitives/address.js @@ -62,7 +62,10 @@ class Address { const {hash, type, version} = options; - return this.fromHash(hash, type, version); + if (options.network) + network = options.network; + + return this.fromHash(hash, type, version, network); } /** @@ -208,6 +211,9 @@ class Address { */ toBase58(network) { + if (!network && this.network) + network = this.network; + return base58.encode(this.toRaw(network)); } @@ -222,6 +228,9 @@ class Address { const version = this.version; const hash = this.hash; + if (!network && this.network) + network = this.network; + assert(version !== -1, 'Cannot convert non-program address to bech32.'); @@ -276,6 +285,9 @@ class Address { */ toString(network) { + if(!network && this.network) + network = this.network; + if (this.version !== -1) return this.toBech32(network); return this.toBase58(network); @@ -290,7 +302,7 @@ class Address { return ''; } @@ -305,6 +317,7 @@ class Address { const br = bio.read(data, true); const prefix = br.readU8(); + // will throw if `network` param doesn't match network derived from `data` network = Network.fromAddress(prefix, network); const type = Address.getType(prefix, network); @@ -327,7 +340,7 @@ class Address { br.verifyChecksum(hash256.digest); - return this.fromHash(hash, type, version); + return this.fromHash(hash, type, version, network); } /** @@ -385,10 +398,10 @@ class Address { const addr = bech32.decode(data); - // make sure HRP is correct. - Network.fromBech32(addr.hrp, network); + // make sure HRP is correct and add property to object. + network = Network.fromBech32(addr.hrp, network); - return this.fromHash(addr.hash, type, addr.version); + return this.fromHash(addr.hash, type, addr.version, network); } /** @@ -561,7 +574,7 @@ class Address { * @throws on bad hash size */ - fromHash(hash, type, version) { + fromHash(hash, type, version, network) { if (typeof type === 'string') { type = Address.types[type.toUpperCase()]; assert(type != null, 'Not a valid address type.'); @@ -596,6 +609,8 @@ class Address { this.hash = hash; this.type = type; this.version = version; + if (network) + this.network = network; return this; } From bacf78853c6f096cb8881570e8969bf292e19ed9 Mon Sep 17 00:00:00 2001 From: Matthew Zipkin Date: Thu, 7 Mar 2019 11:13:44 -0800 Subject: [PATCH 2/2] address-test: network properties --- test/address-test.js | 69 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) diff --git a/test/address-test.js b/test/address-test.js index 50ce38cd7..aa11d14bc 100644 --- a/test/address-test.js +++ b/test/address-test.js @@ -191,4 +191,73 @@ describe('Address', function() { assert(fmt.includes('Address')); assert(fmt.includes('str=')); }); + + // addresses pulled from mainnet block 566,000 and testnet block 1,483,000 + const networkAddrs = [ + ['1VVVVVVvzycHkuGinFxUnFgn5kqwFuV9P', 'main'], + ['3A8WoYwkFi8o6kG7a9bjQwNwzsDUqgXPPr', 'main'], + ['bc1qwqdg6squsna38e46795at95yu9atm8azzmyvckulcc7kytlcckxswvvzej', 'main'], + ['bc1qes3zyz5ut9prjvnx2cany3hjskcd5ypfqu0s89', 'main'], + ['tb1ql5f8fkf88r24fe23uc6xmw88jy7x68p6rpf9jy', 'testnet'], + ['2MwozWKyfFDUnvfvMvDV8RKtKWSQXTFHbSa', 'testnet'], + ['mmTGdcpZ8iY8pN34VqPyrictThtwydHdiA', 'testnet'], + ['n4hPuEzKFjUFpVfbMDJMFoLrDUTD8GHuaf', 'testnet'] + ]; + + for (const [addr, network] of networkAddrs) { + it(`should derive ${network} network property from string`, () => { + const addrObject = Address.fromString(addr); + assert.strictEqual(addrObject.network.toString(), network); + // Expect the same string in and out because network property is set + assert.strictEqual(addrObject.toString(), addr); + }); + } + + it('should create address with network option', () => { + const ZERO_HASH160 = Buffer.alloc(20, 0x00); + + // network as an option + const addr1 = new Address({ + network: 'testnet', + hash: ZERO_HASH160 + }); + // network as param #1 + const addr2 = new Address({ + hash: ZERO_HASH160 + },'testnet'); + // default network is `main` + const addr3 = new Address({ + hash: ZERO_HASH160 + }); + + // base58 + assert.strictEqual(addr1.toString(), 'mfWxJ45yp2SFn7UciZyNpvDKrzbhyfKrY8'); + assert.strictEqual(addr2.toString(), 'mfWxJ45yp2SFn7UciZyNpvDKrzbhyfKrY8'); + assert.strictEqual(addr3.toString(), '1111111111111111111114oLvT2'); + + // override object network property when forced + assert.strictEqual(addr1.toString('main'), '1111111111111111111114oLvT2'); + + // witness version 0 bech32 + addr1.version = 0; + addr2.version = 0; + addr3.version = 0; + + assert.strictEqual(addr1.toString(), + 'tb1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq0l98cr'); + assert.strictEqual(addr2.toString(), + 'tb1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq0l98cr'); + assert.strictEqual(addr3.toString(), + 'bc1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq9e75rs'); + + // override object network property when forced + assert.strictEqual(addr1.toString('main'), + 'bc1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq9e75rs'); + }); + + it('should handle invalid base58 prefix', () => { + assert.throws(() => + Address.fromString('1111111111111111111114oLvT2', 'testnet') + ); + }); });