wallet/tx/script: n limit. refactor multisig options.
This commit is contained in:
parent
14f08e891c
commit
3dec18c2c7
@ -26,13 +26,6 @@ main.prefixes = {
|
|||||||
xprivkey: 0x0488ade4
|
xprivkey: 0x0488ade4
|
||||||
};
|
};
|
||||||
|
|
||||||
utils.merge(main.prefixes, {
|
|
||||||
normal: main.prefixes.pubkey,
|
|
||||||
p2pkh: main.prefixes.pubkey,
|
|
||||||
multisig: main.prefixes.pubkey,
|
|
||||||
p2sh: main.prefixes.script
|
|
||||||
});
|
|
||||||
|
|
||||||
main.type = 'main';
|
main.type = 'main';
|
||||||
|
|
||||||
main.seeds = [
|
main.seeds = [
|
||||||
@ -115,13 +108,6 @@ testnet.prefixes = {
|
|||||||
xprivkey: 0x04358394
|
xprivkey: 0x04358394
|
||||||
};
|
};
|
||||||
|
|
||||||
utils.merge(testnet.prefixes, {
|
|
||||||
normal: testnet.prefixes.pubkey,
|
|
||||||
p2pkh: testnet.prefixes.pubkey,
|
|
||||||
multisig: testnet.prefixes.pubkey,
|
|
||||||
p2sh: testnet.prefixes.script
|
|
||||||
});
|
|
||||||
|
|
||||||
testnet.seeds = [
|
testnet.seeds = [
|
||||||
'testnet-seed.alexykot.me',
|
'testnet-seed.alexykot.me',
|
||||||
'testnet-seed.bitcoin.petertodd.org',
|
'testnet-seed.bitcoin.petertodd.org',
|
||||||
|
|||||||
@ -604,7 +604,7 @@ script.execute = function execute(s, stack, tx, index) {
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
var n = stack.pop();
|
var n = stack.pop();
|
||||||
if (n.length !== 1 || !(1 <= n[0] && n[0] <= 3))
|
if (n.length !== 1 || !(1 <= n[0] && n[0] <= 15))
|
||||||
return false;
|
return false;
|
||||||
n = n[0] || 0;
|
n = n[0] || 0;
|
||||||
|
|
||||||
@ -718,7 +718,7 @@ script.multisig = function(keys, m, n) {
|
|||||||
throw new Error('wrong amount of pubkeys for multisig script');
|
throw new Error('wrong amount of pubkeys for multisig script');
|
||||||
|
|
||||||
assert(m >= 1 && m <= n);
|
assert(m >= 1 && m <= n);
|
||||||
assert(n >= 1 && n <= 7);
|
assert(n >= 1 && n <= 15);
|
||||||
|
|
||||||
// Format:
|
// Format:
|
||||||
// op_[m] [pubkey1-len] [pubkey1] ... op_[n] op_checkmultisig
|
// op_[m] [pubkey1-len] [pubkey1] ... op_[n] op_checkmultisig
|
||||||
@ -778,7 +778,7 @@ script.isMultisig = function isMultisig(s, key) {
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
var m = s[0];
|
var m = s[0];
|
||||||
if (typeof m === 'number' && m >= 1 && m <= 16)
|
if (typeof m === 'number' && m >= 1 && m <= 15)
|
||||||
m = [m];
|
m = [m];
|
||||||
if (!Array.isArray(m) || m.length !== 1)
|
if (!Array.isArray(m) || m.length !== 1)
|
||||||
return false;
|
return false;
|
||||||
@ -788,7 +788,7 @@ script.isMultisig = function isMultisig(s, key) {
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
var n = s[s.length - 2];
|
var n = s[s.length - 2];
|
||||||
if (typeof n === 'number' && n >= 1 && n <= 16)
|
if (typeof n === 'number' && n >= 1 && n <= 15)
|
||||||
n = [n];
|
n = [n];
|
||||||
if (!Array.isArray(n) || n.length !== 1)
|
if (!Array.isArray(n) || n.length !== 1)
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@ -332,7 +332,7 @@ TX.prototype.scriptOutput = function(options) {
|
|||||||
|
|
||||||
if (keys === options.address) {
|
if (keys === options.address) {
|
||||||
keys = keys.map(function(address) {
|
keys = keys.map(function(address) {
|
||||||
return bcoin.wallet.addr2hash(address, 'normal');
|
return bcoin.wallet.addr2hash(address, 'pubkey');
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -349,18 +349,18 @@ TX.prototype.scriptOutput = function(options) {
|
|||||||
|
|
||||||
assert(m >= 1 && m <= n);
|
assert(m >= 1 && m <= n);
|
||||||
if (options.hash)
|
if (options.hash)
|
||||||
assert(n >= 1 && n <= 7);
|
assert(n >= 1 && n <= 15);
|
||||||
else
|
else
|
||||||
assert(n >= 1 && n <= 3);
|
assert(n >= 1 && n <= 3);
|
||||||
|
|
||||||
script = bcoin.script.multisig(keys, m, n);
|
script = bcoin.script.multisig(keys, m, n);
|
||||||
} else if (bcoin.wallet.validateAddress(options.address, 'p2sh')) {
|
} else if (bcoin.wallet.validateAddress(options.address, 'script')) {
|
||||||
// p2sh transaction
|
// p2sh transaction
|
||||||
// https://github.com/bitcoin/bips/blob/master/bip-0016.mediawiki
|
// https://github.com/bitcoin/bips/blob/master/bip-0016.mediawiki
|
||||||
// hash160 [20-byte-redeemscript-hash] equal
|
// hash160 [20-byte-redeemscript-hash] equal
|
||||||
script = [
|
script = [
|
||||||
'hash160',
|
'hash160',
|
||||||
bcoin.wallet.addr2hash(options.address, 'p2sh'),
|
bcoin.wallet.addr2hash(options.address, 'script'),
|
||||||
'eq'
|
'eq'
|
||||||
];
|
];
|
||||||
} else if (options.address) {
|
} else if (options.address) {
|
||||||
@ -369,7 +369,7 @@ TX.prototype.scriptOutput = function(options) {
|
|||||||
script = [
|
script = [
|
||||||
'dup',
|
'dup',
|
||||||
'hash160',
|
'hash160',
|
||||||
bcoin.wallet.addr2hash(options.address, 'normal'),
|
bcoin.wallet.addr2hash(options.address, 'pubkey'),
|
||||||
'eqverify',
|
'eqverify',
|
||||||
'checksig'
|
'checksig'
|
||||||
];
|
];
|
||||||
@ -525,11 +525,11 @@ TX.prototype.maxSize = function maxSize() {
|
|||||||
} else {
|
} else {
|
||||||
// May end up in a higher fee if we
|
// May end up in a higher fee if we
|
||||||
// do not have the redeem script available.
|
// do not have the redeem script available.
|
||||||
m = 7;
|
m = 15;
|
||||||
n = 7;
|
n = 15;
|
||||||
}
|
}
|
||||||
assert(m >= 1 && m <= n);
|
assert(m >= 1 && m <= n);
|
||||||
assert(n >= 1 && n <= 7);
|
assert(n >= 1 && n <= 15);
|
||||||
// Multisig
|
// Multisig
|
||||||
// Empty byte
|
// Empty byte
|
||||||
size += 1;
|
size += 1;
|
||||||
@ -659,7 +659,7 @@ TX.prototype.inputAddrs = function inputAddrs() {
|
|||||||
}).map(function(input) {
|
}).map(function(input) {
|
||||||
var pub = input.script[1];
|
var pub = input.script[1];
|
||||||
var hash = utils.ripesha(pub);
|
var hash = utils.ripesha(pub);
|
||||||
return bcoin.wallet.hash2addr(hash, 'normal');
|
return bcoin.wallet.hash2addr(hash, 'pubkey');
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -63,8 +63,8 @@ function Wallet(options, passphrase) {
|
|||||||
this.key = bcoin.ecdsa.genKeyPair();
|
this.key = bcoin.ecdsa.genKeyPair();
|
||||||
}
|
}
|
||||||
|
|
||||||
this.addressType = 'normal';
|
this.type = 'pubkey';
|
||||||
this.sharedKeys = [];
|
this.pubkeys = [];
|
||||||
this.m = 1;
|
this.m = 1;
|
||||||
this.n = 1;
|
this.n = 1;
|
||||||
|
|
||||||
@ -117,31 +117,40 @@ Wallet.prototype._init = function init() {
|
|||||||
Wallet.prototype.multisig = function multisig(options) {
|
Wallet.prototype.multisig = function multisig(options) {
|
||||||
var pub = this.getOwnPublicKey();
|
var pub = this.getOwnPublicKey();
|
||||||
|
|
||||||
options.type = options.type || options.addressType;
|
options.type = options.type || options.prefix;
|
||||||
options.keys = options.keys || options.sharedKeys;
|
options.keys = options.keys || options.pubkeys;
|
||||||
|
|
||||||
this.addressType = options.type || 'normal';
|
this.type = options.type || 'pubkey';
|
||||||
|
this.pubkeys = (options.keys || []).map(utils.toKeyArray);
|
||||||
// Multisig
|
|
||||||
this.sharedKeys = (options.keys || []).map(utils.toKeyArray);
|
|
||||||
this.m = options.m || 1;
|
this.m = options.m || 1;
|
||||||
this.n = options.n || 1;
|
this.n = options.n || 1;
|
||||||
|
this.nmax = this.type === 'script'
|
||||||
|
? (this.compressed ? 15 : 7)
|
||||||
|
: 3;
|
||||||
|
|
||||||
this.sharedKeys = this.sharedKeys.filter(function(key) {
|
var hasOwn = this.pubkeys.some(function(key) {
|
||||||
return !utils.isEqual(key, pub);
|
return utils.isEqual(key, pub);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!hasOwn)
|
||||||
|
this.pubkeys.push(pub);
|
||||||
|
|
||||||
|
// Keys need to be in a predictable order.
|
||||||
|
this.pubkeys = this.pubkeys.sort(function(a, b) {
|
||||||
|
return new bn(a).cmp(new bn(b)) > 0;
|
||||||
});
|
});
|
||||||
|
|
||||||
// Use p2sh multisig by default
|
// Use p2sh multisig by default
|
||||||
if (!options.addressType && this.sharedKeys.length)
|
if (!options.type && this.pubkeys.length > 1)
|
||||||
this.addressType = 'p2sh';
|
this.type = 'script';
|
||||||
|
|
||||||
if (this.m < 1 || this.m > this.n)
|
if (this.m < 1 || this.m > this.n)
|
||||||
throw new Error('m ranges between 1 and n');
|
throw new Error('m ranges between 1 and n');
|
||||||
|
|
||||||
if (this.n < 1 || this.n > 7)
|
if (this.n < 1 || this.n > this.nmax)
|
||||||
throw new Error('n ranges between 1 and 7');
|
throw new Error('n ranges between 1 and ' + this.nmax);
|
||||||
|
|
||||||
if (this.sharedKeys.length < this.m - 1)
|
if (this.pubkeys.length < this.m)
|
||||||
throw new Error(this.m + ' public keys required');
|
throw new Error(this.m + ' public keys required');
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -185,7 +194,7 @@ Wallet.prototype.getPrivateKey = function getPrivateKey(enc) {
|
|||||||
Wallet.prototype.getFullPublicKey = function getFullPublicKey(enc) {
|
Wallet.prototype.getFullPublicKey = function getFullPublicKey(enc) {
|
||||||
var pub = this.getOwnPublicKey();
|
var pub = this.getOwnPublicKey();
|
||||||
|
|
||||||
if (this.addressType === 'p2sh') {
|
if (this.type === 'script') {
|
||||||
var keys = this.getPublicKeys();
|
var keys = this.getPublicKeys();
|
||||||
pub = bcoin.script.encode(bcoin.script.multisig(keys, this.m, this.n));
|
pub = bcoin.script.encode(bcoin.script.multisig(keys, this.m, this.n));
|
||||||
}
|
}
|
||||||
@ -214,15 +223,7 @@ Wallet.prototype.getPublicKey = function getPublicKey(enc) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
Wallet.prototype.getPublicKeys = function() {
|
Wallet.prototype.getPublicKeys = function() {
|
||||||
var pub = this.getOwnPublicKey();
|
var keys = this.pubkeys.slice().map(utils.toKeyArray);
|
||||||
|
|
||||||
this.sharedKeys = this.sharedKeys.filter(function(key) {
|
|
||||||
return !utils.isEqual(key, pub);
|
|
||||||
});
|
|
||||||
|
|
||||||
var keys = this.sharedKeys.slice().map(utils.toKeyArray);
|
|
||||||
|
|
||||||
keys.push(pub);
|
|
||||||
|
|
||||||
// Keys need to be in a predictable order.
|
// Keys need to be in a predictable order.
|
||||||
keys = keys.sort(function(a, b) {
|
keys = keys.sort(function(a, b) {
|
||||||
@ -237,7 +238,7 @@ Wallet.prototype.getFullHash = function getFullHash() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
Wallet.prototype.getFullAddress = function getFullAddress() {
|
Wallet.prototype.getFullAddress = function getFullAddress() {
|
||||||
return Wallet.hash2addr(this.getFullHash(), this.addressType);
|
return Wallet.hash2addr(this.getFullHash(), this.type);
|
||||||
};
|
};
|
||||||
|
|
||||||
Wallet.prototype.getOwnHash = function getOwnHash() {
|
Wallet.prototype.getOwnHash = function getOwnHash() {
|
||||||
@ -245,7 +246,7 @@ Wallet.prototype.getOwnHash = function getOwnHash() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
Wallet.prototype.getOwnAddress = function getOwnAddress() {
|
Wallet.prototype.getOwnAddress = function getOwnAddress() {
|
||||||
return Wallet.hash2addr(this.getOwnHash(), this.addressType);
|
return Wallet.hash2addr(this.getOwnHash(), this.type);
|
||||||
};
|
};
|
||||||
|
|
||||||
Wallet.prototype.getHash = function getHash() {
|
Wallet.prototype.getHash = function getHash() {
|
||||||
@ -253,28 +254,28 @@ Wallet.prototype.getHash = function getHash() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
Wallet.prototype.getAddress = function getAddress() {
|
Wallet.prototype.getAddress = function getAddress() {
|
||||||
return Wallet.hash2addr(this.getFullHash(), this.addressType);
|
return Wallet.hash2addr(this.getFullHash(), this.type);
|
||||||
};
|
};
|
||||||
|
|
||||||
Wallet.hash2addr = function hash2addr(hash, version) {
|
Wallet.hash2addr = function hash2addr(hash, prefix) {
|
||||||
hash = utils.toArray(hash, 'hex');
|
hash = utils.toArray(hash, 'hex');
|
||||||
|
|
||||||
version = network.prefixes[version || 'normal'];
|
prefix = network.prefixes[prefix || 'pubkey'];
|
||||||
hash = [ version ].concat(hash);
|
hash = [ prefix ].concat(hash);
|
||||||
|
|
||||||
var addr = hash.concat(utils.checksum(hash));
|
var addr = hash.concat(utils.checksum(hash));
|
||||||
return utils.toBase58(addr);
|
return utils.toBase58(addr);
|
||||||
};
|
};
|
||||||
|
|
||||||
Wallet.addr2hash = function addr2hash(addr, version) {
|
Wallet.addr2hash = function addr2hash(addr, prefix) {
|
||||||
if (!Array.isArray(addr))
|
if (!Array.isArray(addr))
|
||||||
addr = utils.fromBase58(addr);
|
addr = utils.fromBase58(addr);
|
||||||
|
|
||||||
version = network.prefixes[version || 'normal'];
|
prefix = network.prefixes[prefix || 'pubkey'];
|
||||||
|
|
||||||
if (addr.length !== 25)
|
if (addr.length !== 25)
|
||||||
return [];
|
return [];
|
||||||
if (addr[0] !== version)
|
if (addr[0] !== prefix)
|
||||||
return [];
|
return [];
|
||||||
|
|
||||||
var chk = utils.checksum(addr.slice(0, -4));
|
var chk = utils.checksum(addr.slice(0, -4));
|
||||||
@ -284,10 +285,10 @@ Wallet.addr2hash = function addr2hash(addr, version) {
|
|||||||
return addr.slice(1, -4);
|
return addr.slice(1, -4);
|
||||||
};
|
};
|
||||||
|
|
||||||
Wallet.prototype.validateAddress = function validateAddress(addr, version) {
|
Wallet.prototype.validateAddress = function validateAddress(addr, prefix) {
|
||||||
if (!addr)
|
if (!addr)
|
||||||
return false;
|
return false;
|
||||||
var p = Wallet.addr2hash(addr, version);
|
var p = Wallet.addr2hash(addr, prefix);
|
||||||
return p.length !== 0;
|
return p.length !== 0;
|
||||||
};
|
};
|
||||||
Wallet.validateAddress = Wallet.prototype.validateAddress;
|
Wallet.validateAddress = Wallet.prototype.validateAddress;
|
||||||
@ -423,8 +424,8 @@ Wallet.prototype.toJSON = function toJSON() {
|
|||||||
priv: this.getPrivateKey('base58'),
|
priv: this.getPrivateKey('base58'),
|
||||||
tx: this.tx.toJSON(),
|
tx: this.tx.toJSON(),
|
||||||
multisig: {
|
multisig: {
|
||||||
type: this.addressType,
|
type: this.type,
|
||||||
keys: this.sharedKeys.map(utils.toBase58),
|
keys: this.pubkeys.map(utils.toHex),
|
||||||
m: this.m,
|
m: this.m,
|
||||||
n: this.n
|
n: this.n
|
||||||
}
|
}
|
||||||
|
|||||||
@ -277,7 +277,7 @@ describe('Wallet', function() {
|
|||||||
var w1 = bcoin.wallet({
|
var w1 = bcoin.wallet({
|
||||||
key: key1,
|
key: key1,
|
||||||
multisig: {
|
multisig: {
|
||||||
type: 'p2sh',
|
type: 'script',
|
||||||
keys: [pub2, pub3],
|
keys: [pub2, pub3],
|
||||||
m: 2,
|
m: 2,
|
||||||
n: 3
|
n: 3
|
||||||
@ -286,7 +286,7 @@ describe('Wallet', function() {
|
|||||||
var w2 = bcoin.wallet({
|
var w2 = bcoin.wallet({
|
||||||
key: key2,
|
key: key2,
|
||||||
multisig: {
|
multisig: {
|
||||||
type: 'p2sh',
|
type: 'script',
|
||||||
keys: [pub1, pub3],
|
keys: [pub1, pub3],
|
||||||
m: 2,
|
m: 2,
|
||||||
n: 3
|
n: 3
|
||||||
@ -295,7 +295,7 @@ describe('Wallet', function() {
|
|||||||
var w3 = bcoin.wallet({
|
var w3 = bcoin.wallet({
|
||||||
key: key3,
|
key: key3,
|
||||||
multisig: {
|
multisig: {
|
||||||
type: 'p2sh',
|
type: 'script',
|
||||||
keys: [pub1, pub2],
|
keys: [pub1, pub2],
|
||||||
m: 2,
|
m: 2,
|
||||||
n: 3
|
n: 3
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user