Add capability to instantiate an Address from public keys and a threshold

This commit is contained in:
Esteban Ordano 2014-12-16 21:25:58 -03:00
parent 2d78d9697b
commit 5f5cf15241
3 changed files with 56 additions and 16 deletions

View File

@ -1,5 +1,6 @@
'use strict';
var _ = require('lodash');
var $ = require('./util/preconditions');
var base58check = require('./encoding/base58check');
var Networks = require('./networks');
@ -42,6 +43,10 @@ function Address(data, network, type) {
return new Address(data, network, type);
}
if (_.isArray(data) && _.isNumber(network)) {
return Address.createMultisig(data, network, type);
}
if (!data) {
throw new TypeError('First argument is required, please include address data.');
}
@ -225,6 +230,19 @@ Address._transformScript = function(script, network){
return info;
};
/**
* Creates a P2SH address from a set of public keys and a threshold.
*
* @param {Array} publicKeys
* @param {number} threshold
* @param {Network} network
* @return {Address}
*/
Address.createMultisig = function(publicKeys, threshold, network) {
var Script = require('./script');
return new Address(Script.buildMultisigOut(publicKeys, threshold), network || Networks.defaultNetwork);
};
/**
* Internal function to transform a bitcoin address string
*

View File

@ -516,32 +516,30 @@ Script.prototype.removeCodeseparators = function() {
/**
* @returns a new Multisig output script for given public keys,
* requiring m of those public keys to spend
* @param {PublicKey[]} pubkeys - list of all public keys controlling the output
* @param {number} m - amount of required signatures to spend the output
* @param {PublicKey[]} publicKeys - list of all public keys controlling the output
* @param {number} threshold - amount of required signatures to spend the output
* @param {Object} [opts] - Several options:
* - noSorting: defaults to false, if true, don't sort the given
* public keys before creating the script
*/
Script.buildMultisigOut = function(pubkeys, m, opts) {
Script.buildMultisigOut = function(publicKeys, threshold, opts) {
opts = opts || {};
var s = new Script();
s.add(Opcode.smallInt(m));
pubkeys = _.map(pubkeys, function(pubkey) {
return PublicKey(pubkey);
});
var sorted = pubkeys;
var script = new Script();
script.add(Opcode.smallInt(threshold));
publicKeys = _.map(publicKeys, PublicKey);
var sorted = publicKeys;
if (!opts.noSorting) {
sorted = _.sortBy(pubkeys, function(pubkey) {
return pubkey.toString('hex');
sorted = _.sortBy(publicKeys, function(publicKey) {
return publicKey.toString('hex');
});
}
for (var i = 0; i < sorted.length; i++) {
var pubkey = sorted[i];
s.add(pubkey.toBuffer());
var publicKey = sorted[i];
script.add(publicKey.toBuffer());
}
s.add(Opcode.smallInt(pubkeys.length));
s.add(Opcode.OP_CHECKMULTISIG);
return s;
script.add(Opcode.smallInt(publicKeys.length));
script.add(Opcode.OP_CHECKMULTISIG);
return script;
};
/**

View File

@ -448,4 +448,28 @@ describe('Address', function() {
});
});
describe('creating a P2SH address from public keys', function() {
var public1 = '02da5798ed0c055e31339eb9b5cef0d3c0ccdec84a62e2e255eb5c006d4f3e7f5b';
var public2 = '0272073bf0287c4469a2a011567361d42529cd1a72ab0d86aa104ecc89342ffeb0';
var public3 = '02738a516a78355db138e8119e58934864ce222c553a5407cf92b9c1527e03c1a2';
var publics = [public1, public2, public3];
it('can create an address from a set of public keys', function() {
var address = new Address(publics, 2);
address.toString().should.equal('3FtqPRirhPvrf7mVUSkygyZ5UuoAYrTW3y');
});
it('works on testnet also', function() {
var address = new Address(publics, 2, Networks.testnet);
address.toString().should.equal('2N7T3TAetJrSCruQ39aNrJvYLhG1LJosujf');
});
it('can also be created by Address.createMultisig', function() {
var address = Address.createMultisig(publics, 2);
var address2 = Address.createMultisig(publics, 2);
address.toString().should.equal(address2.toString());
});
});
});