From ae14c4aaa0095abf9c6f8fc6c61d67c68b7bc29d Mon Sep 17 00:00:00 2001 From: "Ryan X. Charles" Date: Wed, 9 Apr 2014 13:11:24 -0300 Subject: [PATCH 1/2] new convenient interface for creating addresses To create an address from a public key or script, you used to have to do the hashing yourself, and find the version yourself. For example: var hash = bitcore.util.sha256ripe160(pubkey); var version = bitcore.networks['livenet'].addressVersion; var addr = new Address(version, hash); But with this interface, things are much simpler: var addr = Address.fromPubKey(pubkey); The new convenience methods are: Address.fromPubKey (for regular pubkeyhash addresses) Address.fromPubKeys (for p2sh multisig addresses) Address.fromScript (for any p2sh address) --- Address.js | 50 ++++++++++++++++++++++++++++++++++++++++++-- test/test.Address.js | 39 ++++++++++++++++++++++++++++++++++ 2 files changed, 87 insertions(+), 2 deletions(-) diff --git a/Address.js b/Address.js index b9a4ed1..d530bf0 100644 --- a/Address.js +++ b/Address.js @@ -1,7 +1,9 @@ 'use strict'; var imports = require('soop').imports(); -var parent = imports.parent || require('./util/VersionedData'); -var networks= imports.networks || require('./networks'); +var coinUtil = imports.coinUtil || require('./util/util'); +var parent = imports.parent || require('./util/VersionedData'); +var networks = imports.networks || require('./networks'); +var Script = imports.Script || require('./Script'); function Address() { Address.super(this, arguments); @@ -10,6 +12,50 @@ function Address() { Address.parent = parent; parent.applyEncodingsTo(Address); +//create a pubKeyHash address +Address.fromPubKey = function(pubKey, network) { + if (!network) + network = 'livenet'; + + if (pubKey.length != 33 && pubKey.length != 65) + throw new Error('Invalid public key'); + + var version = networks[network].addressVersion; + var hash = coinUtil.sha256ripe160(pubKey); + + return new Address(version, hash); +}; + +//create a p2sh m-of-n multisig address +Address.fromPubKeys = function(mReq, pubKeys, network) { + if (!network) + network = 'livenet'; + + for (var i in pubKeys) { + var pubKey = pubKeys[i]; + if (pubKey.length != 33 && pubKey.length != 65) + throw new Error('Invalid public key'); + } + + var version = networks[network].P2SHVersion; + var script = Script.createMultisig(mReq, pubKeys); + var buf = script.getBuffer(); + var hash = coinUtil.sha256ripe160(buf) + + return new Address(version, hash); +}; + +//create a p2sh address from redeemScript +Address.fromScript = function(script, network) { + if (!network) + network = 'livenet'; + + var version = networks[network].P2SHVersion; + var buf = script.getBuffer(); + var hash = coinUtil.sha256ripe160(buf); + + return new Address(version, hash); +}; Address.prototype.validate = function() { this.doAsBinary(function() { diff --git a/test/test.Address.js b/test/test.Address.js index 1982553..9793902 100644 --- a/test/test.Address.js +++ b/test/test.Address.js @@ -82,5 +82,44 @@ describe('Address', function() { // script testnet new Address('2NBSBcf2KfjPEEqVusmrWdmUeNHRiUTS3Li').isScript().should.equal(true); }); + + describe('#fromPubKey', function() { + it('should make this pubkeyhash address from uncompressed this public key', function() { + var pubkey = new Buffer('04fa05ce8b25010cb6e17a30e0b66668bf083c40687547748ec330ee77adf53a42abd3d26148cbacfcf79c907ddefeb2c37f8bebc0a695ba79d634449d871de218', 'hex'); + var hash = bitcore.util.sha256ripe160(pubkey); + var addr = new Address(0, hash); + addr.toString().should.equal(Address.fromPubKey(pubkey).toString()); + }); + }); + + describe('#fromPubKeys', function() { + it('should make this p2sh multisig address from these pubkeys', function() { + var pubkey1 = new Buffer('03e0973263b4e0d5f5f56d25d430e777ab3838ff644db972c0bf32c31da5686c27', 'hex'); + var pubkey2 = new Buffer('0371f94c57cc013507101e30794161f4e6b9efd58a9ea68838daf429b7feac8cb2', 'hex'); + var pubkey3 = new Buffer('032c0d2e394541e2efdc7ac3500e16e7e69df541f38670402e95aa477202fa06bb', 'hex'); + var sortedPubKeys = [pubkey3, pubkey2, pubkey1]; + var mReq = 2; + var script = bitcore.Script.createMultisig(mReq, sortedPubKeys, {noSorting: true}); + var hash = bitcore.util.sha256ripe160(script.getBuffer()); + var version = bitcore.networks['livenet'].P2SHVersion; + var addr = new Address(version, hash); + var addr2 = Address.fromPubKeys(mReq, sortedPubKeys); + addr.toString().should.equal(addr2.toString()); + }); + }); + + describe('#fromScript', function() { + it('should make this p2sh multisig address from these pubkeys', function() { + var pubkey1 = new Buffer('03e0973263b4e0d5f5f56d25d430e777ab3838ff644db972c0bf32c31da5686c27', 'hex'); + var pubkey2 = new Buffer('0371f94c57cc013507101e30794161f4e6b9efd58a9ea68838daf429b7feac8cb2', 'hex'); + var pubkey3 = new Buffer('032c0d2e394541e2efdc7ac3500e16e7e69df541f38670402e95aa477202fa06bb', 'hex'); + var pubKeys = [pubkey1, pubkey2, pubkey3]; + var mReq = 2; + var script = bitcore.Script.createMultisig(mReq, pubKeys); + var addr = Address.fromScript(script); + var addr2 = Address.fromPubKeys(mReq, pubKeys); + addr.toString().should.equal(addr2.toString()); + }); + }); }); From a7c8cf49b39fab414da0732f1da7e012e87538b8 Mon Sep 17 00:00:00 2001 From: "Ryan X. Charles" Date: Wed, 9 Apr 2014 14:07:56 -0300 Subject: [PATCH 2/2] update fromPubKeys to use fromScript This means fewer code-duplication. Also added another test for fromScript to make sure it is thoroughly tested. Also pass through opts to createMultisig so that you can choose to lot let it be sorted if you want. --- Address.js | 9 +++------ test/test.Address.js | 16 ++++++++++++++++ 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/Address.js b/Address.js index d530bf0..c3bf0ee 100644 --- a/Address.js +++ b/Address.js @@ -27,7 +27,7 @@ Address.fromPubKey = function(pubKey, network) { }; //create a p2sh m-of-n multisig address -Address.fromPubKeys = function(mReq, pubKeys, network) { +Address.fromPubKeys = function(mReq, pubKeys, network, opts) { if (!network) network = 'livenet'; @@ -37,12 +37,9 @@ Address.fromPubKeys = function(mReq, pubKeys, network) { throw new Error('Invalid public key'); } - var version = networks[network].P2SHVersion; - var script = Script.createMultisig(mReq, pubKeys); - var buf = script.getBuffer(); - var hash = coinUtil.sha256ripe160(buf) + var script = Script.createMultisig(mReq, pubKeys, opts); - return new Address(version, hash); + return Address.fromScript(script, network); }; //create a p2sh address from redeemScript diff --git a/test/test.Address.js b/test/test.Address.js index 9793902..bffc08a 100644 --- a/test/test.Address.js +++ b/test/test.Address.js @@ -120,6 +120,22 @@ describe('Address', function() { var addr2 = Address.fromPubKeys(mReq, pubKeys); addr.toString().should.equal(addr2.toString()); }); + + it('it should make this hand-crafted address', function() { + var pubkey1 = new Buffer('03e0973263b4e0d5f5f56d25d430e777ab3838ff644db972c0bf32c31da5686c27', 'hex'); + var pubkey2 = new Buffer('0371f94c57cc013507101e30794161f4e6b9efd58a9ea68838daf429b7feac8cb2', 'hex'); + var pubkey3 = new Buffer('032c0d2e394541e2efdc7ac3500e16e7e69df541f38670402e95aa477202fa06bb', 'hex'); + var pubKeys = [pubkey1, pubkey2, pubkey3]; + var mReq = 2; + var script = bitcore.Script.createMultisig(mReq, pubKeys); + var addr = Address.fromScript(script); + + var hash = bitcore.util.sha256ripe160(script.getBuffer()); + var version = bitcore.networks['livenet'].P2SHVersion; + var addr2 = new Address(version, hash); + + addr.toString().should.equal(addr2.toString()); + }); }); });