mtx/wallet: refactor keyring.
This commit is contained in:
parent
0f23304a68
commit
c836786b99
@ -278,9 +278,6 @@ ec.rand = function rand(min, max) {
|
||||
ec.verify = function verify(msg, sig, key, historical, high) {
|
||||
var result;
|
||||
|
||||
if (key.getPublicKey)
|
||||
key = key.getPublicKey();
|
||||
|
||||
assert(Buffer.isBuffer(msg));
|
||||
assert(Buffer.isBuffer(sig));
|
||||
assert(Buffer.isBuffer(key));
|
||||
@ -375,8 +372,8 @@ ec.privateKeyVerify = function privateKeyVerify(key) {
|
||||
ec.sign = function sign(msg, key) {
|
||||
var sig;
|
||||
|
||||
if (key.getPrivateKey)
|
||||
key = key.getPrivateKey();
|
||||
assert(Buffer.isBuffer(msg));
|
||||
assert(Buffer.isBuffer(key));
|
||||
|
||||
if (secp256k1) {
|
||||
// Sign message
|
||||
|
||||
@ -2028,7 +2028,7 @@ RPC.prototype.signrawtransaction = function signrawtransaction(args, callback) {
|
||||
RPC.prototype._signrawtransaction = function signrawtransaction(merged, txs, args, callback) {
|
||||
var keys = [];
|
||||
var keyMap = {};
|
||||
var k, i, secret, key, addr;
|
||||
var k, i, secret, key;
|
||||
var coins, prevout, prev;
|
||||
var hash, index, script, value;
|
||||
var redeem, op, j;
|
||||
@ -2038,12 +2038,12 @@ RPC.prototype._signrawtransaction = function signrawtransaction(merged, txs, arg
|
||||
k = args[2];
|
||||
for (i = 0; i < k.length; i++) {
|
||||
secret = k[i];
|
||||
|
||||
if (!utils.isBase58(secret))
|
||||
return callback(new RPCError('Invalid parameter'));
|
||||
key = bcoin.keypair.fromSecret(secret);
|
||||
addr = new bcoin.keyring({ publicKey: key.getPublicKey() });
|
||||
key = { addr: addr, key: key.getPrivateKey() };
|
||||
keyMap[addr.getPublicKey('hex')] = key;
|
||||
|
||||
key = bcoin.keyring.fromSecret(secret);
|
||||
keyMap[key.getPublicKey('hex')] = key;
|
||||
keys.push(key);
|
||||
}
|
||||
}
|
||||
@ -2051,14 +2051,18 @@ RPC.prototype._signrawtransaction = function signrawtransaction(merged, txs, arg
|
||||
coins = [];
|
||||
if (args.length > 1 && Array.isArray(args[1])) {
|
||||
prevout = args[1];
|
||||
|
||||
for (i = 0; i < prevout.length; i++) {
|
||||
prev = prevout[i];
|
||||
|
||||
if (!prev)
|
||||
return callback(new RPCError('Invalid parameter'));
|
||||
|
||||
hash = toHash(prev.txid);
|
||||
index = prev.vout;
|
||||
script = prev.scriptPubKey;
|
||||
value = toSatoshi(prev.amount);
|
||||
|
||||
if (!hash
|
||||
|| !utils.isNumber(index)
|
||||
|| index < 0
|
||||
@ -2081,22 +2085,22 @@ RPC.prototype._signrawtransaction = function signrawtransaction(merged, txs, arg
|
||||
|
||||
if (script.isScripthash() || script.isWitnessScripthash()) {
|
||||
redeem = bcoin.script.fromRaw(prev.redeemScript, 'hex');
|
||||
if (!redeem.isMultisig())
|
||||
continue;
|
||||
for (j = 1; j < redeem.length - 2; j++) {
|
||||
for (j = 0; j < redeem.length; j++) {
|
||||
op = redeem.get(j);
|
||||
|
||||
if (!Buffer.isBuffer(op))
|
||||
continue;
|
||||
|
||||
key = keyMap[op.toString('hex')];
|
||||
if (key) {
|
||||
key.addr.type = bcoin.keyring.types.MULTISIG;
|
||||
key.addr.m = redeem.getSmall(0);
|
||||
key.addr.n = redeem.getSmall(redeem.length - 1);
|
||||
key.addr.keys = redeem.slice(1, -2);
|
||||
key.addr.witness = script.isWitnessScripthash();
|
||||
key.script = redeem;
|
||||
key.witness = script.isWitnessScripthash();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tx.fillCoins(coins);
|
||||
}
|
||||
|
||||
@ -2117,17 +2121,14 @@ RPC.prototype._signrawtransaction = function signrawtransaction(merged, txs, arg
|
||||
|
||||
for (i = 0; i < keys.length; i++) {
|
||||
key = keys[i];
|
||||
key.addr.sign(merged, key.key, null, type);
|
||||
merged.sign(key, type);
|
||||
}
|
||||
|
||||
this.wallet.sign(merged, { type: type }, function(err) {
|
||||
if (err)
|
||||
return callback(err);
|
||||
|
||||
for (i = 1; i < txs.length; i++) {
|
||||
tx = txs[i];
|
||||
mergeSigs(merged, tx);
|
||||
}
|
||||
// TODO: Merge with other txs here.
|
||||
|
||||
callback(null, {
|
||||
hex: merged.toRaw().toString('hex'),
|
||||
@ -2136,28 +2137,6 @@ RPC.prototype._signrawtransaction = function signrawtransaction(merged, txs, arg
|
||||
});
|
||||
};
|
||||
|
||||
function mergeSigs(a, b) {
|
||||
var map = {};
|
||||
var i, input, prev, key, ia, ib;
|
||||
|
||||
for (i = 0; i < b.inputs.length; i++) {
|
||||
input = b.inputs[i];
|
||||
prev = input.prevout;
|
||||
key = prev.hash + prev.index;
|
||||
map[key] = input;
|
||||
}
|
||||
|
||||
for (i = 0; i < b.inputs.length; i++) {
|
||||
ia = a.inputs[i];
|
||||
if (!ia || ia.length !== 0)
|
||||
break;
|
||||
key = prev.hash + prev.index;
|
||||
ib = map[key];
|
||||
if (ib)
|
||||
ia.script = ib.script;
|
||||
}
|
||||
}
|
||||
|
||||
RPC.prototype.fundrawtransaction = function fundrawtransaction(args, callback) {
|
||||
var tx, options, changeAddress, feeRate;
|
||||
|
||||
@ -2223,6 +2202,7 @@ RPC.prototype._createRedeem = function _createRedeem(args, callback) {
|
||||
}
|
||||
|
||||
hash = bcoin.address.getHash(key, 'hex');
|
||||
|
||||
if (!hash)
|
||||
return next(new RPCError('Invalid key.'));
|
||||
|
||||
@ -2233,7 +2213,7 @@ RPC.prototype._createRedeem = function _createRedeem(args, callback) {
|
||||
if (!ring)
|
||||
return next(new RPCError('Invalid key.'));
|
||||
|
||||
keys[i] = ring.getPublicKey();
|
||||
keys[i] = ring.publicKey;
|
||||
|
||||
next();
|
||||
});
|
||||
@ -2597,9 +2577,7 @@ RPC.prototype.dumpprivkey = function dumpprivkey(args, callback) {
|
||||
if (!key)
|
||||
return callback(new RPCError('Wallet is locked.'));
|
||||
|
||||
key = ring.derive(key);
|
||||
|
||||
callback(null, key.toSecret());
|
||||
callback(null, ring.toSecret());
|
||||
});
|
||||
};
|
||||
|
||||
@ -2642,14 +2620,13 @@ RPC.prototype.dumpwallet = function dumpwallet(args, callback) {
|
||||
if (!key)
|
||||
return callback(new RPCError('Wallet is locked.'));
|
||||
|
||||
key = ring.derive(key);
|
||||
address = ring.getAddress('base58');
|
||||
fmt = '%s %s label= addr=%s';
|
||||
|
||||
if (ring.change)
|
||||
fmt = '%s %s change=1 addr=%s';
|
||||
|
||||
str = utils.fmt(fmt, key.toSecret(), time, address);
|
||||
str = utils.fmt(fmt, ring.toSecret(), time, address);
|
||||
|
||||
out.push(str);
|
||||
|
||||
@ -3826,12 +3803,10 @@ RPC.prototype.signmessage = function signmessage(args, callback) {
|
||||
if (!key)
|
||||
return callback(new RPCError('Wallet is locked.'));
|
||||
|
||||
key = ring.derive(key);
|
||||
|
||||
msg = new Buffer(RPC.magic + msg, 'utf8');
|
||||
msg = utils.hash256(msg);
|
||||
|
||||
sig = bcoin.ec.sign(msg, key);
|
||||
sig = ring.sign(msg);
|
||||
|
||||
callback(null, sig.toString('base64'));
|
||||
});
|
||||
|
||||
@ -16,168 +16,82 @@ var BufferWriter = require('./writer');
|
||||
var scriptTypes = constants.scriptTypes;
|
||||
|
||||
/**
|
||||
* Represents a key ring which amounts to an address. Used for {@link Wallet}.
|
||||
* Represents a key ring which amounts to an address.
|
||||
* @exports KeyRing
|
||||
* @constructor
|
||||
* @param {Object} options
|
||||
* @param {HDPrivateKey|HDPublicKey|KeyPair|Buffer} options.key
|
||||
* @param {String?} options.name
|
||||
* @param {Number?} options.account
|
||||
* @param {Number?} options.change
|
||||
* @param {Number?} options.index
|
||||
* @param {String?} options.type - `"pubkeyhash"` or `"multisig"`.
|
||||
* @param {HDPrivateKey|HDPublicKey|Buffer} options.key
|
||||
* @param {Buffer[]} options.keys - Shared multisig keys.
|
||||
* @param {Number?} options.m - Multisig `m` value.
|
||||
* @param {Number?} options.n - Multisig `n` value.
|
||||
* @param {Boolean?} options.witness - Whether witness programs are enabled.
|
||||
*/
|
||||
|
||||
function KeyRing(options) {
|
||||
function KeyRing(options, network) {
|
||||
if (!(this instanceof KeyRing))
|
||||
return new KeyRing(options);
|
||||
return new KeyRing(options, network);
|
||||
|
||||
this.network = bcoin.network.get();
|
||||
this.type = KeyRing.types.PUBKEYHASH;
|
||||
this.m = 1;
|
||||
this.n = 1;
|
||||
this.witness = false;
|
||||
this.publicKey = null;
|
||||
this.privateKey = null;
|
||||
this.script = null;
|
||||
|
||||
this.wid = 0;
|
||||
this.id = null;
|
||||
this.name = null;
|
||||
this.account = 0;
|
||||
this.change = 0;
|
||||
this.index = 0;
|
||||
this.key = null;
|
||||
this.keys = [];
|
||||
|
||||
this._keyHash = null;
|
||||
this._keyAddress = null;
|
||||
this._program = null;
|
||||
this._programHash = null;
|
||||
this._programAddress = null;
|
||||
this._script = null;
|
||||
this._scriptHash160 = null;
|
||||
this._scriptHash256 = null;
|
||||
this._scriptAddress = null;
|
||||
this._addressMap = null;
|
||||
|
||||
if (options)
|
||||
this.fromOptions(options);
|
||||
this.fromOptions(options, network);
|
||||
}
|
||||
|
||||
/**
|
||||
* KeyRing types.
|
||||
* @enum {Number}
|
||||
* @default
|
||||
*/
|
||||
|
||||
KeyRing.types = {
|
||||
PUBKEYHASH: 0,
|
||||
MULTISIG: 1
|
||||
};
|
||||
|
||||
/**
|
||||
* KeyRing types by value.
|
||||
* @const {RevMap}
|
||||
*/
|
||||
|
||||
KeyRing.typesByVal = {
|
||||
0: 'pubkeyhash',
|
||||
1: 'multisig'
|
||||
};
|
||||
|
||||
/**
|
||||
* Inject properties from options object.
|
||||
* @private
|
||||
* @param {Object} options
|
||||
*/
|
||||
|
||||
KeyRing.prototype.fromOptions = function fromOptions(options) {
|
||||
var i;
|
||||
KeyRing.prototype.fromOptions = function fromOptions(options, network) {
|
||||
var key = toKey(options);
|
||||
|
||||
assert(options.key);
|
||||
if (Buffer.isBuffer(key))
|
||||
return this.fromKey(key, network);
|
||||
|
||||
key = toKey(options.key);
|
||||
|
||||
if (options.privateKey)
|
||||
key = toKey(options.privateKey);
|
||||
|
||||
if (options.publicKey)
|
||||
key = toKey(options.publicKey);
|
||||
|
||||
if (options.network)
|
||||
this.network = bcoin.network.get(options.network);
|
||||
|
||||
if (options.type != null) {
|
||||
if (typeof options.type === 'string') {
|
||||
this.type = KeyRing.types[options.type.toUpperCase()];
|
||||
assert(this.type != null);
|
||||
} else {
|
||||
assert(typeof options.type === 'number');
|
||||
this.type = options.type;
|
||||
assert(KeyRing.typesByVal[this.type]);
|
||||
}
|
||||
}
|
||||
|
||||
if (options.m != null) {
|
||||
assert(utils.isNumber(options.m));
|
||||
this.m = options.m;
|
||||
}
|
||||
|
||||
if (options.n != null) {
|
||||
assert(utils.isNumber(options.n));
|
||||
this.n = options.n;
|
||||
}
|
||||
|
||||
if (options.witness != null) {
|
||||
assert(typeof options.witness === 'boolean');
|
||||
this.witness = options.witness;
|
||||
}
|
||||
|
||||
if (options.wid) {
|
||||
assert(utils.isNumber(options.wid));
|
||||
this.wid = options.wid;
|
||||
}
|
||||
if (options.keys)
|
||||
return this.fromKeys(key, options.m, options.n, options.keys, this.network);
|
||||
|
||||
if (options.id) {
|
||||
assert(utils.isName(options.id));
|
||||
this.id = options.id;
|
||||
}
|
||||
if (options.script)
|
||||
return this.fromScript(key, options.script, this.network);
|
||||
|
||||
if (options.name) {
|
||||
assert(utils.isName(options.name));
|
||||
this.name = options.name;
|
||||
}
|
||||
|
||||
if (options.account != null) {
|
||||
assert(utils.isNumber(options.account));
|
||||
this.account = options.account;
|
||||
}
|
||||
|
||||
if (options.change != null) {
|
||||
assert(utils.isNumber(options.change));
|
||||
this.change = options.change;
|
||||
}
|
||||
|
||||
if (options.index != null) {
|
||||
assert(utils.isNumber(options.index));
|
||||
this.index = options.index;
|
||||
}
|
||||
|
||||
this.key = options.key;
|
||||
|
||||
if (this.key.getPublicKey)
|
||||
this.key = this.key.getPublicKey();
|
||||
|
||||
assert(Buffer.isBuffer(this.key));
|
||||
|
||||
if (this.n > 1)
|
||||
this.type = KeyRing.types.MULTISIG;
|
||||
|
||||
if (this.m < 1 || this.m > this.n)
|
||||
throw new Error('m ranges between 1 and n');
|
||||
|
||||
this.addKey(this.key);
|
||||
|
||||
if (options.keys) {
|
||||
assert(Array.isArray(options.keys));
|
||||
for (i = 0; i < options.keys.length; i++)
|
||||
this.addKey(options.keys[i]);
|
||||
}
|
||||
|
||||
return this;
|
||||
this.fromKey(key, this.network);
|
||||
};
|
||||
|
||||
/**
|
||||
@ -190,6 +104,234 @@ KeyRing.fromOptions = function fromOptions(options) {
|
||||
return new KeyRing().fromOptions(options);
|
||||
};
|
||||
|
||||
/**
|
||||
* Inject data from private key.
|
||||
* @private
|
||||
* @param {Buffer} privateKey
|
||||
* @param {Boolean?} compressed
|
||||
* @param {(NetworkType|Network}) network
|
||||
*/
|
||||
|
||||
KeyRing.prototype.fromPrivate = function fromPrivate(privateKey, network) {
|
||||
assert(Buffer.isBuffer(privateKey), 'Private key must be a buffer.');
|
||||
assert(bcoin.ec.privateKeyVerify(privateKey), 'Not a valid private key.');
|
||||
this.network = bcoin.network.get(network);
|
||||
this.privateKey = privateKey;
|
||||
this.publicKey = bcoin.ec.publicKeyCreate(this.privateKey, true);
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Instantiate keyring from a private key.
|
||||
* @param {Buffer} privateKey
|
||||
* @param {Boolean?} compressed
|
||||
* @param {(NetworkType|Network}) network
|
||||
* @returns {KeyRing}
|
||||
*/
|
||||
|
||||
KeyRing.fromPrivate = function fromPrivate(privateKey, network) {
|
||||
return new KeyRing().fromPrivate(privateKey, network);
|
||||
};
|
||||
|
||||
/**
|
||||
* Inject data from public key.
|
||||
* @private
|
||||
* @param {Buffer} privateKey
|
||||
* @param {(NetworkType|Network}) network
|
||||
*/
|
||||
|
||||
KeyRing.prototype.fromPublic = function fromPublic(publicKey, network) {
|
||||
assert(Buffer.isBuffer(publicKey), 'Public key must be a buffer.');
|
||||
assert(bcoin.ec.publicKeyVerify(publicKey), 'Not a valid public key.');
|
||||
this.network = bcoin.network.get(network);
|
||||
this.publicKey = publicKey;
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Generate a keyring.
|
||||
* @param {(Network|NetworkType)?} network
|
||||
* @returns {KeyRing}
|
||||
*/
|
||||
|
||||
KeyRing.generate = function(witness, network) {
|
||||
var key = new KeyRing();
|
||||
key.network = bcoin.network.get(network);
|
||||
key.privateKey = bcoin.ec.generatePrivateKey();
|
||||
key.publicKey = bcoin.ec.publicKeyCreate(key.privateKey, true);
|
||||
key.witness = !!witness;
|
||||
return key;
|
||||
};
|
||||
|
||||
/**
|
||||
* Instantiate keyring from a public key.
|
||||
* @param {Buffer} publicKey
|
||||
* @param {(NetworkType|Network}) network
|
||||
* @returns {KeyRing}
|
||||
*/
|
||||
|
||||
KeyRing.fromPublic = function fromPublic(publicKey, network) {
|
||||
return new KeyRing().fromPublic(publicKey, network);
|
||||
};
|
||||
|
||||
/**
|
||||
* Inject data from public key.
|
||||
* @private
|
||||
* @param {Buffer} privateKey
|
||||
* @param {(NetworkType|Network}) network
|
||||
*/
|
||||
|
||||
KeyRing.prototype.fromKey = function fromKey(key, network) {
|
||||
assert(Buffer.isBuffer(key), 'Key must be a buffer.');
|
||||
assert(key.length === 32 || key.length === 33, 'Not a key.');
|
||||
|
||||
if (key.length === 33)
|
||||
return this.fromPublic(key, network);
|
||||
|
||||
return this.fromPrivate(key, network);
|
||||
};
|
||||
|
||||
/**
|
||||
* Instantiate keyring from a public key.
|
||||
* @param {Buffer} publicKey
|
||||
* @param {(NetworkType|Network}) network
|
||||
* @returns {KeyRing}
|
||||
*/
|
||||
|
||||
KeyRing.fromKey = function fromKey(key, network) {
|
||||
return new KeyRing().fromKey(key, network);
|
||||
};
|
||||
|
||||
/**
|
||||
* Inject data from public key.
|
||||
* @private
|
||||
* @param {Buffer} key
|
||||
* @param {Number} m
|
||||
* @param {Number} n
|
||||
* @param {Buffer[]} keys
|
||||
* @param {(NetworkType|Network}) network
|
||||
*/
|
||||
|
||||
KeyRing.prototype.fromKeys = function fromKeys(key, m, n, keys, network) {
|
||||
var script = bcoin.script.fromMultisig(m, n, keys);
|
||||
this.fromScript(key, script, network);
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Instantiate keyring from keys.
|
||||
* @param {Buffer} key
|
||||
* @param {Number} m
|
||||
* @param {Number} n
|
||||
* @param {Buffer[]} keys
|
||||
* @param {(NetworkType|Network}) network
|
||||
* @returns {KeyRing}
|
||||
*/
|
||||
|
||||
KeyRing.fromKeys = function fromKeys(key, m, n, keys, network) {
|
||||
return new KeyRing().fromKeys(key, m, n, keys, network);
|
||||
};
|
||||
|
||||
/**
|
||||
* Inject data from script.
|
||||
* @private
|
||||
* @param {Buffer} key
|
||||
* @param {Script} script
|
||||
* @param {(NetworkType|Network}) network
|
||||
*/
|
||||
|
||||
KeyRing.prototype.fromScript = function fromScript(key, script, network) {
|
||||
assert(script instanceof bcoin.script, 'Non-script passed into KeyRing.');
|
||||
this.fromKey(key, network);
|
||||
this.script = script;
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Instantiate keyring from script.
|
||||
* @param {Buffer} key
|
||||
* @param {Script} script
|
||||
* @param {(NetworkType|Network}) network
|
||||
* @returns {KeyRing}
|
||||
*/
|
||||
|
||||
KeyRing.fromScript = function fromScript(key, script, network) {
|
||||
return new KeyRing().fromScript(key, script, network);
|
||||
};
|
||||
|
||||
/**
|
||||
* Convert key to a CBitcoinSecret.
|
||||
* @param {(Network|NetworkType)?} network
|
||||
* @returns {Base58String}
|
||||
*/
|
||||
|
||||
KeyRing.prototype.toSecret = function toSecret(network) {
|
||||
var p = new BufferWriter();
|
||||
|
||||
assert(this.privateKey, 'Cannot serialize without private key.');
|
||||
|
||||
if (!network)
|
||||
network = this.network;
|
||||
|
||||
network = bcoin.network.get(network);
|
||||
|
||||
p.writeU8(network.keyPrefix.privkey);
|
||||
p.writeBytes(this.privateKey);
|
||||
|
||||
p.writeU8(1);
|
||||
|
||||
p.writeChecksum();
|
||||
|
||||
return utils.toBase58(p.render());
|
||||
};
|
||||
|
||||
/**
|
||||
* Inject properties from serialized CBitcoinSecret.
|
||||
* @private
|
||||
* @param {Base58String} secret
|
||||
*/
|
||||
|
||||
KeyRing.prototype.fromSecret = function fromSecret(data) {
|
||||
var p = new BufferReader(utils.fromBase58(data), true);
|
||||
var i, prefix, version, type, key, compressed;
|
||||
|
||||
version = p.readU8();
|
||||
|
||||
for (i = 0; i < network.types.length; i++) {
|
||||
type = network.types[i];
|
||||
prefix = network[type].keyPrefix.privkey;
|
||||
if (version === prefix)
|
||||
break;
|
||||
}
|
||||
|
||||
assert(i < network.types.length, 'Network not found.');
|
||||
|
||||
key = p.readBytes(32);
|
||||
|
||||
if (p.left() > 4) {
|
||||
assert(p.readU8() === 1, 'Bad compression flag.');
|
||||
compressed = true;
|
||||
} else {
|
||||
compressed = false;
|
||||
}
|
||||
|
||||
p.verifyChecksum();
|
||||
|
||||
assert(compressed === false, 'Cannot handle uncompressed.');
|
||||
|
||||
return this.fromPrivate(key, type);
|
||||
};
|
||||
|
||||
/**
|
||||
* Instantiate a keyring from a serialized CBitcoinSecret.
|
||||
* @param {Base58String} secret
|
||||
* @returns {KeyRing}
|
||||
*/
|
||||
|
||||
KeyRing.fromSecret = function fromSecret(data) {
|
||||
return new KeyRing().fromSecret(data);
|
||||
};
|
||||
|
||||
/**
|
||||
* Inject properties from account object.
|
||||
* @private
|
||||
@ -201,25 +343,20 @@ KeyRing.fromOptions = function fromOptions(options) {
|
||||
*/
|
||||
|
||||
KeyRing.prototype.fromAccount = function fromAccount(account, key, keys, change, index) {
|
||||
var i;
|
||||
|
||||
this.network = account.network;
|
||||
this.key = key.publicKey;
|
||||
this.publicKey = key.publicKey;
|
||||
|
||||
if (account.n > 1)
|
||||
this.script = bcoin.script.fromMultisig(account.m, account.n, keys);
|
||||
|
||||
this.witness = account.witness;
|
||||
|
||||
this.wid = account.wid;
|
||||
this.id = account.id;
|
||||
this.name = account.name;
|
||||
this.account = account.accountIndex;
|
||||
this.change = change;
|
||||
this.index = index;
|
||||
this.type = account.type;
|
||||
this.witness = account.witness;
|
||||
this.m = account.m;
|
||||
this.n = account.n;
|
||||
|
||||
this.addKey(this.key);
|
||||
|
||||
for (i = 0; i < keys.length; i++)
|
||||
this.addKey(keys[i]);
|
||||
|
||||
return this;
|
||||
};
|
||||
@ -238,36 +375,6 @@ KeyRing.fromAccount = function fromAccount(account, key, keys, change, index) {
|
||||
return new KeyRing().fromAccount(account, key, keys, change, index);
|
||||
};
|
||||
|
||||
/**
|
||||
* Add a key to shared keys.
|
||||
* @param {Buffer} key
|
||||
*/
|
||||
|
||||
KeyRing.prototype.addKey = function addKey(key) {
|
||||
assert(Buffer.isBuffer(key));
|
||||
|
||||
utils.binaryInsert(this.keys, key, utils.cmp, true);
|
||||
|
||||
if (this.keys.length > this.n) {
|
||||
utils.binaryRemove(this.keys, key, utils.cmp);
|
||||
throw new Error('Cannot add more keys.');
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Remove a key from shared keys.
|
||||
* @param {Buffer} key
|
||||
*/
|
||||
|
||||
KeyRing.prototype.removeKey = function removeKey(key) {
|
||||
assert(Buffer.isBuffer(key));
|
||||
|
||||
if (this.keys.length === this.n)
|
||||
throw new Error('Cannot remove key.');
|
||||
|
||||
utils.binaryRemove(this.keys, key, utils.cmp);
|
||||
};
|
||||
|
||||
/**
|
||||
* Get public key.
|
||||
* @param {String?} enc - `"hex"` or `null`.
|
||||
@ -276,12 +383,12 @@ KeyRing.prototype.removeKey = function removeKey(key) {
|
||||
|
||||
KeyRing.prototype.getPublicKey = function getPublicKey(enc) {
|
||||
if (enc === 'base58')
|
||||
return utils.toBase58(this.key);
|
||||
return utils.toBase58(this.publicKey);
|
||||
|
||||
if (enc === 'hex')
|
||||
return this.key.toString('hex');
|
||||
return this.publicKey.toString('hex');
|
||||
|
||||
return this.key;
|
||||
return this.publicKey;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -290,23 +397,7 @@ KeyRing.prototype.getPublicKey = function getPublicKey(enc) {
|
||||
*/
|
||||
|
||||
KeyRing.prototype.getScript = function getScript() {
|
||||
var redeem;
|
||||
|
||||
if (this.type !== KeyRing.types.MULTISIG)
|
||||
return;
|
||||
|
||||
if (!this._script) {
|
||||
assert(this.keys.length === this.n, 'Not all keys have been added.');
|
||||
|
||||
redeem = bcoin.script.fromMultisig(this.m, this.n, this.keys);
|
||||
|
||||
if (redeem.getSize() > 520)
|
||||
throw new Error('Redeem script too large (520 byte limit).');
|
||||
|
||||
this._script = redeem;
|
||||
}
|
||||
|
||||
return this._script;
|
||||
return this.script;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -321,14 +412,12 @@ KeyRing.prototype.getProgram = function getProgram() {
|
||||
return;
|
||||
|
||||
if (!this._program) {
|
||||
if (this.type === KeyRing.types.PUBKEYHASH) {
|
||||
hash = utils.hash160(this.getPublicKey());
|
||||
program = bcoin.script.fromProgram(0, hash);
|
||||
} else if (this.type === KeyRing.types.MULTISIG) {
|
||||
hash = utils.sha256(this.getScript().toRaw());
|
||||
if (!this.script) {
|
||||
hash = utils.hash160(this.publicKey);
|
||||
program = bcoin.script.fromProgram(0, hash);
|
||||
} else {
|
||||
assert(false, 'Unknown address type.');
|
||||
hash = this.script.sha256();
|
||||
program = bcoin.script.fromProgram(0, hash);
|
||||
}
|
||||
this._program = program;
|
||||
}
|
||||
@ -348,7 +437,7 @@ KeyRing.prototype.getProgramHash = function getProgramHash(enc) {
|
||||
return;
|
||||
|
||||
if (!this._programHash)
|
||||
this._programHash = utils.hash160(this.getProgram().toRaw());
|
||||
this._programHash = this.getProgram().hash160();
|
||||
|
||||
return enc === 'hex'
|
||||
? this._programHash.toString('hex')
|
||||
@ -398,11 +487,11 @@ KeyRing.prototype.getScriptHash = function getScriptHash(enc) {
|
||||
*/
|
||||
|
||||
KeyRing.prototype.getScriptHash160 = function getScriptHash256(enc) {
|
||||
if (this.type !== KeyRing.types.MULTISIG)
|
||||
if (!this.script)
|
||||
return;
|
||||
|
||||
if (!this._scriptHash160)
|
||||
this._scriptHash160 = utils.hash160(this.getScript().toRaw());
|
||||
this._scriptHash160 = this.script.hash160();
|
||||
|
||||
return enc === 'hex'
|
||||
? this._scriptHash160.toString('hex')
|
||||
@ -416,11 +505,11 @@ KeyRing.prototype.getScriptHash160 = function getScriptHash256(enc) {
|
||||
*/
|
||||
|
||||
KeyRing.prototype.getScriptHash256 = function getScriptHash256(enc) {
|
||||
if (this.type !== KeyRing.types.MULTISIG)
|
||||
if (!this.script)
|
||||
return;
|
||||
|
||||
if (!this._scriptHash256)
|
||||
this._scriptHash256 = utils.sha256(this.getScript().toRaw());
|
||||
this._scriptHash256 = this.script.sha256();
|
||||
|
||||
return enc === 'hex'
|
||||
? this._scriptHash256.toString('hex')
|
||||
@ -436,7 +525,7 @@ KeyRing.prototype.getScriptHash256 = function getScriptHash256(enc) {
|
||||
KeyRing.prototype.getScriptAddress = function getScriptAddress(enc) {
|
||||
var hash, address;
|
||||
|
||||
if (this.type !== KeyRing.types.MULTISIG)
|
||||
if (!this.script)
|
||||
return;
|
||||
|
||||
if (!this._scriptAddress) {
|
||||
@ -464,7 +553,7 @@ KeyRing.prototype.getScriptAddress = function getScriptAddress(enc) {
|
||||
|
||||
KeyRing.prototype.getKeyHash = function getKeyHash(enc) {
|
||||
if (!this._keyHash)
|
||||
this._keyHash = utils.hash160(this.getPublicKey());
|
||||
this._keyHash = utils.hash160(this.publicKey);
|
||||
|
||||
return enc === 'hex'
|
||||
? this._keyHash.toString('hex')
|
||||
@ -516,7 +605,7 @@ KeyRing.prototype.compile = function compile(hash, type, version) {
|
||||
*/
|
||||
|
||||
KeyRing.prototype.getHash = function getHash(enc) {
|
||||
if (this.type === KeyRing.types.MULTISIG)
|
||||
if (this.script)
|
||||
return this.getScriptHash(enc);
|
||||
return this.getKeyHash(enc);
|
||||
};
|
||||
@ -528,25 +617,33 @@ KeyRing.prototype.getHash = function getHash(enc) {
|
||||
*/
|
||||
|
||||
KeyRing.prototype.getAddress = function getAddress(enc) {
|
||||
if (this.type === KeyRing.types.MULTISIG)
|
||||
if (this.script)
|
||||
return this.getScriptAddress(enc);
|
||||
return this.getKeyAddress(enc);
|
||||
};
|
||||
|
||||
/**
|
||||
* Create the address map for testing txs.
|
||||
* @returns {AddressMap}
|
||||
* Test an address hash against hash and program hash.
|
||||
* @param {Buffer} hash
|
||||
* @returns {Boolean}
|
||||
*/
|
||||
|
||||
KeyRing.prototype.getAddressMap = function getAddressMap() {
|
||||
if (!this._addressMap) {
|
||||
this._addressMap = {};
|
||||
this._addressMap[this.getHash('hex')] = true;
|
||||
if (this.witness)
|
||||
this._addressMap[this.getProgramHash('hex')] = true;
|
||||
KeyRing.prototype.ownHash = function ownHash(hash) {
|
||||
if (!hash)
|
||||
return false;
|
||||
|
||||
if (utils.equal(hash, this.keyHash))
|
||||
return true;
|
||||
|
||||
if (utils.equal(hash, this.scriptHash))
|
||||
return true;
|
||||
|
||||
if (this.witness) {
|
||||
if (utils.equal(hash, this.programHash))
|
||||
return true;
|
||||
}
|
||||
|
||||
return this._addressMap;
|
||||
return false;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -557,8 +654,7 @@ KeyRing.prototype.getAddressMap = function getAddressMap() {
|
||||
*/
|
||||
|
||||
KeyRing.prototype.ownInput = function ownInput(tx, index) {
|
||||
var addressMap = this.getAddressMap();
|
||||
var input, hash;
|
||||
var input;
|
||||
|
||||
if (tx instanceof bcoin.input) {
|
||||
input = tx;
|
||||
@ -567,12 +663,7 @@ KeyRing.prototype.ownInput = function ownInput(tx, index) {
|
||||
assert(input, 'Input does not exist.');
|
||||
}
|
||||
|
||||
hash = input.getHash('hex');
|
||||
|
||||
if (!hash)
|
||||
return false;
|
||||
|
||||
return addressMap[hash] === true;
|
||||
return this.ownHash(input.getHash());
|
||||
};
|
||||
|
||||
/**
|
||||
@ -583,8 +674,7 @@ KeyRing.prototype.ownInput = function ownInput(tx, index) {
|
||||
*/
|
||||
|
||||
KeyRing.prototype.ownOutput = function ownOutput(tx, index) {
|
||||
var addressMap = this.getAddressMap();
|
||||
var output, hash;
|
||||
var output;
|
||||
|
||||
if (tx instanceof bcoin.output) {
|
||||
output = tx;
|
||||
@ -593,61 +683,53 @@ KeyRing.prototype.ownOutput = function ownOutput(tx, index) {
|
||||
assert(output, 'Output does not exist.');
|
||||
}
|
||||
|
||||
hash = output.getHash('hex');
|
||||
|
||||
if (!hash)
|
||||
return false;
|
||||
|
||||
return addressMap[hash] === true;
|
||||
return this.ownHash(output.getHash());
|
||||
};
|
||||
|
||||
/**
|
||||
* Test a hash against script hashes to
|
||||
* find the correct redeem script, if any.
|
||||
* @param {Buffer} hash
|
||||
* @returns {Script|null}
|
||||
*/
|
||||
|
||||
KeyRing.prototype.getRedeem = function(hash) {
|
||||
if (this.program && utils.equal(hash, this.programHash))
|
||||
return this.program;
|
||||
if (this.program) {
|
||||
if (utils.equal(hash, this.programHash))
|
||||
return this.program;
|
||||
}
|
||||
|
||||
if (this.script && utils.equal(hash, this.scriptHash160))
|
||||
return this.script;
|
||||
if (this.script) {
|
||||
if (utils.equal(hash, this.scriptHash160))
|
||||
return this.script;
|
||||
|
||||
if (this.script && utils.equal(hash, this.scriptHash256))
|
||||
return this.script;
|
||||
if (utils.equal(hash, this.scriptHash256))
|
||||
return this.script;
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
/**
|
||||
* Build input scripts templates for a transaction (does not
|
||||
* sign, only creates signature slots). Only builds scripts
|
||||
* for inputs that are redeemable by this address.
|
||||
* @param {MTX} tx
|
||||
* @param {Number?} index - Index of input. If not present,
|
||||
* it will attempt to sign all redeemable inputs.
|
||||
* @returns {Number} Total number of scripts built.
|
||||
* Sign a message.
|
||||
* @param {Buffer} msg
|
||||
* @returns {Buffer} Signature in DER format.
|
||||
*/
|
||||
|
||||
KeyRing.prototype.scriptInputs = function scriptInputs(tx) {
|
||||
return tx.template(this.publicKey, this.script);
|
||||
KeyRing.prototype.sign = function sign(msg) {
|
||||
assert(this.privateKey, 'Cannot sign without private key.');
|
||||
return bcoin.ec.sign(msg, this.privateKey);
|
||||
};
|
||||
|
||||
/**
|
||||
* Build input scripts and sign inputs for a transaction. Only attempts
|
||||
* to build/sign inputs that are redeemable by this address.
|
||||
* @param {MTX} tx
|
||||
* @param {HDPrivateKey|KeyPair|Buffer} key - Private key.
|
||||
* @returns {Number} Total number of inputs scripts built and signed.
|
||||
* Verify a message.
|
||||
* @param {Buffer} msg
|
||||
* @param {Buffer} sig - Signature in DER format.
|
||||
* @returns {Boolean}
|
||||
*/
|
||||
|
||||
KeyRing.prototype.sign = function sign(tx, key) {
|
||||
return tx.sign(key, this.script);
|
||||
};
|
||||
|
||||
/**
|
||||
* Derive to address index.
|
||||
* @param {HDPrivateKey} key
|
||||
* @returns {HDPrivateKey}
|
||||
*/
|
||||
|
||||
KeyRing.prototype.derive = function derive(key) {
|
||||
if (key.isMaster())
|
||||
key = key.deriveAccount44(this.account);
|
||||
return key.derive(this.change).derive(this.index);
|
||||
KeyRing.prototype.verify = function verify(msg, sig) {
|
||||
return bcoin.ec.verify(msg, sig, this.publicKey);
|
||||
};
|
||||
|
||||
/**
|
||||
@ -655,28 +737,20 @@ KeyRing.prototype.derive = function derive(key) {
|
||||
* @returns {ScriptType}
|
||||
*/
|
||||
|
||||
KeyRing.prototype.getScriptType = function getScriptType() {
|
||||
switch (this.type) {
|
||||
case KeyRing.types.PUBKEYHASH:
|
||||
return this.witness
|
||||
? scriptTypes.WITNESSPUBKEYHASH
|
||||
: scriptTypes.PUBKEYHASH;
|
||||
case KeyRing.types.MULTISIG:
|
||||
return this.witness
|
||||
? scriptTypes.WITNESSSCRIPTHASH
|
||||
: scriptTypes.SCRIPTHASH;
|
||||
default:
|
||||
assert(false, 'Bad keyring type.');
|
||||
break;
|
||||
}
|
||||
KeyRing.prototype.getType = function getType() {
|
||||
if (this.program)
|
||||
return this.program.getType();
|
||||
if (this.script)
|
||||
return this.script.getType();
|
||||
return scriptTypes.PUBKEYHASH;
|
||||
};
|
||||
|
||||
KeyRing.prototype.__defineGetter__('publicKey', function() {
|
||||
return this.getPublicKey();
|
||||
});
|
||||
/*
|
||||
* Getters
|
||||
*/
|
||||
|
||||
KeyRing.prototype.__defineGetter__('script', function() {
|
||||
return this.getScript();
|
||||
KeyRing.prototype.__defineGetter__('type', function() {
|
||||
return this.getType();
|
||||
});
|
||||
|
||||
KeyRing.prototype.__defineGetter__('scriptHash', function() {
|
||||
@ -723,6 +797,15 @@ KeyRing.prototype.__defineGetter__('address', function() {
|
||||
return this.getAddress();
|
||||
});
|
||||
|
||||
/**
|
||||
* Inspect keyring.
|
||||
* @returns {Object}
|
||||
*/
|
||||
|
||||
KeyRing.prototype.inspect = function inspect() {
|
||||
return this.toJSON();
|
||||
};
|
||||
|
||||
/**
|
||||
* Convert an KeyRing to a more json-friendly object.
|
||||
* @returns {Object}
|
||||
@ -731,20 +814,16 @@ KeyRing.prototype.__defineGetter__('address', function() {
|
||||
KeyRing.prototype.toJSON = function toJSON() {
|
||||
return {
|
||||
network: this.network.type,
|
||||
type: KeyRing.typesByVal[this.type].toLowerCase(),
|
||||
m: this.m,
|
||||
n: this.n,
|
||||
witness: this.witness,
|
||||
key: this.publicKey.toString('hex'),
|
||||
script: this.script ? this.script.toRaw().toString('hex') : null,
|
||||
type: constants.scriptTypesByVal[this.type].toLowerCase(),
|
||||
wid: this.wid,
|
||||
id: this.id,
|
||||
name: this.name,
|
||||
account: this.account,
|
||||
change: this.change,
|
||||
index: this.index,
|
||||
key: this.key.toString('hex'),
|
||||
keys: this.keys.map(function(key) {
|
||||
return key.toString('hex');
|
||||
}),
|
||||
address: this.getAddress('base58'),
|
||||
programAddress: this.getProgramAddress('base58')
|
||||
};
|
||||
@ -757,39 +836,31 @@ KeyRing.prototype.toJSON = function toJSON() {
|
||||
*/
|
||||
|
||||
KeyRing.prototype.fromJSON = function fromJSON(json) {
|
||||
var i;
|
||||
|
||||
assert(json);
|
||||
assert(typeof json.network === 'string');
|
||||
assert(typeof json.type === 'string');
|
||||
assert(utils.isNumber(json.m));
|
||||
assert(utils.isNumber(json.n));
|
||||
assert(typeof json.witness === 'boolean');
|
||||
assert(typeof json.publicKey === 'string');
|
||||
assert(!json.script || typeof json.script === 'string');
|
||||
|
||||
assert(!json.wid || utils.isNumber(json.wid));
|
||||
assert(!json.id || utils.isName(json.id));
|
||||
assert(!json.name || utils.isName(json.name));
|
||||
assert(utils.isNumber(json.account));
|
||||
assert(utils.isNumber(json.change));
|
||||
assert(utils.isNumber(json.index));
|
||||
assert(typeof json.key === 'string');
|
||||
assert(Array.isArray(json.keys));
|
||||
|
||||
this.nework = bcoin.network.get(json.network);
|
||||
this.type = KeyRing.types[json.type.toUpperCase()];
|
||||
this.m = json.m;
|
||||
this.n = json.n;
|
||||
this.witness = json.witness;
|
||||
this.publicKey = new Buffer(json.publicKey, 'hex');
|
||||
|
||||
if (json.script)
|
||||
this.script = new Buffer(json.script, 'hex');
|
||||
|
||||
this.wid = json.wid;
|
||||
this.name = json.name;
|
||||
this.account = json.account;
|
||||
this.change = json.change;
|
||||
this.index = json.index;
|
||||
this.key = new Buffer(json.key, 'hex');
|
||||
|
||||
assert(this.type != null);
|
||||
|
||||
for (i = 0; i < json.keys.length; i++)
|
||||
this.keys.push(new Buffer(json.keys[i], 'hex'));
|
||||
|
||||
return this;
|
||||
};
|
||||
@ -814,21 +885,18 @@ KeyRing.prototype.toRaw = function toRaw(writer) {
|
||||
var i;
|
||||
|
||||
p.writeU32(this.network.magic);
|
||||
p.writeU8(this.type);
|
||||
p.writeU8(this.m);
|
||||
p.writeU8(this.n);
|
||||
p.writeU8(this.witness ? 1 : 0);
|
||||
p.writeU32(this.wid);
|
||||
p.writeVarString(this.id, 'utf8');
|
||||
p.writeVarString(this.name, 'utf8');
|
||||
p.writeU32(this.account);
|
||||
p.writeU32(this.change);
|
||||
p.writeU32(this.index);
|
||||
p.writeVarBytes(this.key);
|
||||
p.writeU8(this.keys.length);
|
||||
p.writeVarBytes(this.publicKey);
|
||||
|
||||
for (i = 0; i < this.keys.length; i++)
|
||||
p.writeVarBytes(this.keys[i]);
|
||||
if (this.privateKey)
|
||||
p.writeVarBytes(this.privateKey);
|
||||
else
|
||||
p.writeVarint(0);
|
||||
|
||||
if (this.script)
|
||||
p.writeVarBytes(this.script.toRaw());
|
||||
else
|
||||
p.writeVarint(0);
|
||||
|
||||
if (!writer)
|
||||
p = p.render();
|
||||
@ -847,24 +915,18 @@ KeyRing.prototype.fromRaw = function fromRaw(data) {
|
||||
var i, count;
|
||||
|
||||
this.network = bcoin.network.fromMagic(p.readU32());
|
||||
this.type = p.readU8();
|
||||
this.m = p.readU8();
|
||||
this.n = p.readU8();
|
||||
this.witness = p.readU8() === 1;
|
||||
this.wid = p.readU32();
|
||||
this.id = p.readVarString('utf8');
|
||||
this.name = p.readVarString('utf8');
|
||||
this.account = p.readU32();
|
||||
this.change = p.readU32();
|
||||
this.index = p.readU32();
|
||||
this.key = p.readVarBytes();
|
||||
this.publicKey = p.readVarBytes();
|
||||
|
||||
assert(KeyRing.typesByVal[this.type]);
|
||||
this.privateKey = p.readVarBytes();
|
||||
|
||||
count = p.readU8();
|
||||
if (this.privateKey.length === 0)
|
||||
this.privateKey = null;
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
this.keys.push(p.readVarBytes());
|
||||
this.script = p.readVarBytes();
|
||||
|
||||
if (this.script.length === 0)
|
||||
this.script = null;
|
||||
|
||||
return this;
|
||||
};
|
||||
@ -887,10 +949,27 @@ KeyRing.fromRaw = function fromRaw(data) {
|
||||
|
||||
KeyRing.isKeyRing = function isKeyRing(obj) {
|
||||
return obj
|
||||
&& Array.isArray(obj.keys)
|
||||
&& typeof obj.getAddressMap === 'function';
|
||||
&& Buffer.isBuffer(obj.publicKey)
|
||||
&& typeof obj.toSecret === 'function';
|
||||
};
|
||||
|
||||
/*
|
||||
* Helpers
|
||||
*/
|
||||
|
||||
function toKey(opt) {
|
||||
if (!opt)
|
||||
return opt;
|
||||
|
||||
if (opt.getPrivateKey)
|
||||
return opt.getPrivateKey();
|
||||
|
||||
if (opt.getPublicKey)
|
||||
return opt.getPublicKey();
|
||||
|
||||
return opt;
|
||||
}
|
||||
|
||||
/*
|
||||
* Expose
|
||||
*/
|
||||
|
||||
159
lib/bcoin/mtx.js
159
lib/bcoin/mtx.js
@ -211,12 +211,11 @@ MTX.prototype.addOutput = function addOutput(options, value) {
|
||||
* Build input script (or witness) templates (with
|
||||
* OP_0 in place of signatures).
|
||||
* @param {Number} index - Input index.
|
||||
* @param {Buffer} key - Public key.
|
||||
* @param {Script} script - Redeem script.
|
||||
* @param {KeyRing} ring
|
||||
* @returns {Boolean} Whether the script was able to be built.
|
||||
*/
|
||||
|
||||
MTX.prototype.scriptInput = function scriptInput(index, key, script) {
|
||||
MTX.prototype.scriptInput = function scriptInput(index, ring) {
|
||||
var input = this.inputs[index];
|
||||
var prev, redeem;
|
||||
|
||||
@ -233,9 +232,6 @@ MTX.prototype.scriptInput = function scriptInput(index, key, script) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (key.getPublicKey)
|
||||
key = key.getPublicKey();
|
||||
|
||||
// Get the previous output's script
|
||||
prev = input.coin.script;
|
||||
|
||||
@ -243,7 +239,7 @@ MTX.prototype.scriptInput = function scriptInput(index, key, script) {
|
||||
// with segwit: figuring out where the redeem script and witness
|
||||
// redeem scripts go.
|
||||
if (prev.isScripthash()) {
|
||||
redeem = this._getRedeem(prev.get(1), key, script);
|
||||
redeem = ring.getRedeem(prev.get(1));
|
||||
|
||||
if (!redeem)
|
||||
return false;
|
||||
@ -252,12 +248,12 @@ MTX.prototype.scriptInput = function scriptInput(index, key, script) {
|
||||
if (redeem.isProgram()) {
|
||||
// P2WSH nested within pay-to-scripthash.
|
||||
if (redeem.isWitnessScripthash()) {
|
||||
prev = this._getRedeem(redeem.get(1), key, script);
|
||||
prev = ring.getRedeem(redeem.get(1));
|
||||
|
||||
if (!prev)
|
||||
return false;
|
||||
|
||||
if (!this.scriptVector(prev, input.witness, key))
|
||||
if (!this.scriptVector(prev, input.witness, ring))
|
||||
return false;
|
||||
|
||||
input.witness.push(prev.toRaw());
|
||||
@ -269,9 +265,9 @@ MTX.prototype.scriptInput = function scriptInput(index, key, script) {
|
||||
|
||||
// P2WPKH nested within pay-to-scripthash.
|
||||
if (redeem.isWitnessPubkeyhash()) {
|
||||
prev = Script.fromPubkeyhash(utils.hash160(key));
|
||||
prev = Script.fromPubkeyhash(ring.keyHash);
|
||||
|
||||
if (!this.scriptVector(prev, input.witness, key))
|
||||
if (!this.scriptVector(prev, input.witness, ring))
|
||||
return false;
|
||||
|
||||
input.script.push(redeem.toRaw());
|
||||
@ -285,7 +281,7 @@ MTX.prototype.scriptInput = function scriptInput(index, key, script) {
|
||||
}
|
||||
|
||||
// Regular P2SH.
|
||||
if (!this.scriptVector(redeem, input.script, key))
|
||||
if (!this.scriptVector(redeem, input.script, ring))
|
||||
return false;
|
||||
|
||||
input.script.push(redeem.toRaw());
|
||||
@ -298,12 +294,12 @@ MTX.prototype.scriptInput = function scriptInput(index, key, script) {
|
||||
if (prev.isProgram()) {
|
||||
// Bare P2WSH.
|
||||
if (prev.isWitnessScripthash()) {
|
||||
redeem = this._getRedeem(prev.get(1), key, script);
|
||||
redeem = ring.getRedeem(prev.get(1));
|
||||
|
||||
if (!redeem)
|
||||
return false;
|
||||
|
||||
if (!this.scriptVector(redeem, input.witness, key))
|
||||
if (!this.scriptVector(redeem, input.witness, ring))
|
||||
return false;
|
||||
|
||||
input.witness.push(redeem.toRaw());
|
||||
@ -316,7 +312,7 @@ MTX.prototype.scriptInput = function scriptInput(index, key, script) {
|
||||
if (prev.isWitnessPubkeyhash()) {
|
||||
prev = Script.fromPubkeyhash(prev.get(1));
|
||||
|
||||
if (!this.scriptVector(prev, input.witness, key))
|
||||
if (!this.scriptVector(prev, input.witness, ring))
|
||||
return false;
|
||||
|
||||
input.script.compile();
|
||||
@ -329,7 +325,7 @@ MTX.prototype.scriptInput = function scriptInput(index, key, script) {
|
||||
}
|
||||
|
||||
// Wow, a normal output! Praise be to Jengus and Gord.
|
||||
return this.scriptVector(prev, input.script, key);
|
||||
return this.scriptVector(prev, input.script, ring);
|
||||
};
|
||||
|
||||
/**
|
||||
@ -337,16 +333,16 @@ MTX.prototype.scriptInput = function scriptInput(index, key, script) {
|
||||
* based on a previous script.
|
||||
* @param {Script} prev
|
||||
* @param {Witness|Script} vector
|
||||
* @param {Buffer} key
|
||||
* @param {Buffer} ring
|
||||
* @return {Boolean}
|
||||
*/
|
||||
|
||||
MTX.prototype.scriptVector = function scriptVector(prev, vector, key) {
|
||||
MTX.prototype.scriptVector = function scriptVector(prev, vector, ring) {
|
||||
var i, n;
|
||||
|
||||
// P2PK
|
||||
if (prev.isPubkey()) {
|
||||
if (!utils.equal(prev.get(1), key))
|
||||
if (!utils.equal(prev.get(1), ring.publicKey))
|
||||
return false;
|
||||
|
||||
vector.set(0, opcodes.OP_0);
|
||||
@ -356,18 +352,18 @@ MTX.prototype.scriptVector = function scriptVector(prev, vector, key) {
|
||||
|
||||
// P2PKH
|
||||
if (prev.isPubkeyhash()) {
|
||||
if (!utils.equal(prev.get(2), utils.hash160(key)))
|
||||
if (!utils.equal(prev.get(2), ring.keyHash))
|
||||
return false;
|
||||
|
||||
vector.set(0, opcodes.OP_0);
|
||||
vector.set(1, key);
|
||||
vector.set(1, ring.publicKey);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Multisig
|
||||
if (prev.isMultisig()) {
|
||||
if (prev.indexOf(key) === -1)
|
||||
if (prev.indexOf(ring.publicKey) === -1)
|
||||
return false;
|
||||
|
||||
// Technically we should create m signature slots,
|
||||
@ -388,52 +384,6 @@ MTX.prototype.scriptVector = function scriptVector(prev, vector, key) {
|
||||
return false;
|
||||
};
|
||||
|
||||
/**
|
||||
* Calculate a redeem script based on hash.
|
||||
* Test against passed in redeem script.
|
||||
* @private
|
||||
* @param {Buffer} hash - 32 or 20 byte hash.
|
||||
* @param {Buffer} key - Public key.
|
||||
* @param {Script} script - Known redeem script.
|
||||
* @returns {Script|null}
|
||||
*/
|
||||
|
||||
MTX.prototype._getRedeem = function getRedeem(hash, key, script) {
|
||||
var program;
|
||||
|
||||
if (!key)
|
||||
return;
|
||||
|
||||
switch (hash.length) {
|
||||
case 20:
|
||||
program = bcoin.script.fromProgram(0, utils.hash160(key));
|
||||
|
||||
if (utils.equal(program.hash160(), hash))
|
||||
return program;
|
||||
|
||||
if (!script)
|
||||
return;
|
||||
|
||||
program = script.forWitness();
|
||||
|
||||
if (utils.equal(program.hash160(), hash))
|
||||
return program;
|
||||
|
||||
if (utils.equal(script.hash160(), hash))
|
||||
return script;
|
||||
|
||||
break;
|
||||
case 32:
|
||||
if (!script)
|
||||
return;
|
||||
|
||||
if (utils.equal(script.sha256(), hash))
|
||||
return script;
|
||||
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Sign an input.
|
||||
* @param {Number} index - Index of input being signed.
|
||||
@ -454,9 +404,6 @@ MTX.prototype.signInput = function signInput(index, key, type) {
|
||||
if (!input.coin)
|
||||
return false;
|
||||
|
||||
if (key.getPrivateKey)
|
||||
key = key.getPrivateKey();
|
||||
|
||||
// Get the previous output's script
|
||||
prev = input.coin.script;
|
||||
vector = input.script;
|
||||
@ -832,26 +779,23 @@ MTX.prototype.isSigned = function isSigned() {
|
||||
|
||||
/**
|
||||
* Built input scripts (or witnesses) and sign the inputs.
|
||||
* @param {Number} index - Index of input being signed.
|
||||
* @param {KeyRing} ring - Address used to sign. The address
|
||||
* must be able to redeem the coin.
|
||||
* @param {HDPrivateKey|KeyPair|Buffer} key - Private key.
|
||||
* @param {SighashType} type
|
||||
* @returns {Boolean} Whether the input was able to be signed.
|
||||
* @throws on unavailable coins.
|
||||
*/
|
||||
|
||||
MTX.prototype.template = function template(key, script) {
|
||||
MTX.prototype.template = function template(ring) {
|
||||
var total = 0;
|
||||
var i;
|
||||
|
||||
if (key.getPublicKey)
|
||||
key = key.getPublicKey();
|
||||
|
||||
for (i = 0; i < this.inputs.length; i++) {
|
||||
// Build script for input
|
||||
if (!this.scriptInput(i, key, script))
|
||||
if (!ring.ownInput(this, i))
|
||||
continue;
|
||||
|
||||
// Build script for input
|
||||
if (!this.scriptInput(i, ring))
|
||||
continue;
|
||||
|
||||
total++;
|
||||
}
|
||||
|
||||
@ -860,27 +804,32 @@ MTX.prototype.template = function template(key, script) {
|
||||
|
||||
/**
|
||||
* Built input scripts (or witnesses) and sign the inputs.
|
||||
* @param {Number} index - Index of input being signed.
|
||||
* @param {KeyRing} ring - Address used to sign. The address
|
||||
* must be able to redeem the coin.
|
||||
* @param {HDPrivateKey|KeyPair|Buffer} key - Private key.
|
||||
* @param {SighashType} type
|
||||
* @returns {Boolean} Whether the input was able to be signed.
|
||||
* @throws on unavailable coins.
|
||||
*/
|
||||
|
||||
MTX.prototype.sign = function sign(key, script, type) {
|
||||
MTX.prototype.sign = function sign(ring, type) {
|
||||
var total = 0;
|
||||
var i, pub;
|
||||
var i, key;
|
||||
|
||||
if (key.getPrivateKey)
|
||||
key = key.getPrivateKey();
|
||||
if (Array.isArray(ring)) {
|
||||
for (i = 0; i < ring.length; i++)
|
||||
total += this.sign(ring[i], type);
|
||||
return total;
|
||||
}
|
||||
|
||||
pub = bcoin.ec.publicKeyCreate(key, true);
|
||||
key = ring.privateKey;
|
||||
|
||||
assert(key, 'No private key available.');
|
||||
|
||||
for (i = 0; i < this.inputs.length; i++) {
|
||||
if (!ring.ownInput(this, i))
|
||||
continue;
|
||||
|
||||
// Build script for input
|
||||
if (!this.scriptInput(i, pub, script))
|
||||
if (!this.scriptInput(i, ring))
|
||||
continue;
|
||||
|
||||
// Sign input
|
||||
@ -893,6 +842,36 @@ MTX.prototype.sign = function sign(key, script, type) {
|
||||
return total;
|
||||
};
|
||||
|
||||
/**
|
||||
* Sign the transaction inputs on the worker pool
|
||||
* (if workers are enabled).
|
||||
* @param {KeyRing} ring
|
||||
* @param {SighashType?} type
|
||||
* @param {Function} callback
|
||||
* @returns {Boolean} Whether the inputs are valid.
|
||||
*/
|
||||
|
||||
MTX.prototype.signAsync = function signAsync(ring, type, callback) {
|
||||
var result;
|
||||
|
||||
if (typeof type === 'function') {
|
||||
callback = type;
|
||||
type = null;
|
||||
}
|
||||
|
||||
if (!bcoin.useWorkers) {
|
||||
callback = utils.asyncify(callback);
|
||||
try {
|
||||
result = this.sign(ring, type);
|
||||
} catch (e) {
|
||||
return callback(e);
|
||||
}
|
||||
return callback(null, result);
|
||||
}
|
||||
|
||||
bcoin.workerPool.sign(this, ring, type, callback);
|
||||
};
|
||||
|
||||
/**
|
||||
* Test whether the transaction at least
|
||||
* has all script templates built.
|
||||
|
||||
@ -15,8 +15,6 @@ var assert = utils.assert;
|
||||
var BufferReader = require('./reader');
|
||||
var BufferWriter = require('./writer');
|
||||
var TXDB = require('./txdb');
|
||||
var keyTypes = bcoin.keyring.types;
|
||||
var keyTypesByVal = bcoin.keyring.typesByVal;
|
||||
|
||||
/**
|
||||
* BIP44 Wallet
|
||||
@ -943,12 +941,12 @@ Wallet.prototype.createTX = function createTX(options, callback, force) {
|
||||
if (!tx.checkInputs(self.db.height))
|
||||
return callback(new Error('CheckInputs failed.'));
|
||||
|
||||
self.scriptInputs(tx, function(err, total) {
|
||||
self.template(tx, function(err, total) {
|
||||
if (err)
|
||||
return callback(err);
|
||||
|
||||
if (total === 0)
|
||||
return callback(new Error('scriptInputs failed.'));
|
||||
return callback(new Error('template failed.'));
|
||||
|
||||
callback(null, tx);
|
||||
});
|
||||
@ -1029,11 +1027,16 @@ Wallet.prototype.resend = function resend(callback) {
|
||||
* @param {Function} callback - Returns [Error, {@link KeyRing}[]].
|
||||
*/
|
||||
|
||||
Wallet.prototype.deriveInputs = function deriveInputs(tx, callback) {
|
||||
Wallet.prototype.deriveInputs = function deriveInputs(tx, master, callback) {
|
||||
var self = this;
|
||||
var rings = [];
|
||||
var ring;
|
||||
|
||||
if (typeof master === 'function') {
|
||||
callback = master;
|
||||
master = null;
|
||||
}
|
||||
|
||||
this.getInputPaths(tx, function(err, paths) {
|
||||
if (err)
|
||||
return callback(err);
|
||||
@ -1046,7 +1049,7 @@ Wallet.prototype.deriveInputs = function deriveInputs(tx, callback) {
|
||||
if (!account)
|
||||
return next();
|
||||
|
||||
ring = account.deriveAddress(path.change, path.index);
|
||||
ring = account.deriveAddress(path.change, path.index, master);
|
||||
rings.push(ring);
|
||||
|
||||
next();
|
||||
@ -1088,7 +1091,7 @@ Wallet.prototype.getKeyring = function getKeyring(address, callback) {
|
||||
if (!account)
|
||||
return callback();
|
||||
|
||||
ring = account.deriveAddress(path.change, path.index);
|
||||
ring = account.deriveAddress(path.change, path.index, self.master.key);
|
||||
|
||||
callback(null, ring);
|
||||
});
|
||||
@ -1365,16 +1368,18 @@ Wallet.prototype.getRedeem = function getRedeem(hash, callback) {
|
||||
* (total number of scripts built).
|
||||
*/
|
||||
|
||||
Wallet.prototype.scriptInputs = function scriptInputs(tx, callback) {
|
||||
Wallet.prototype.template = function template(tx, callback) {
|
||||
var total = 0;
|
||||
var i;
|
||||
var i, ring;
|
||||
|
||||
this.deriveInputs(tx, function(err, rings) {
|
||||
if (err)
|
||||
return callback(err);
|
||||
|
||||
for (i = 0; i < rings.length; i++)
|
||||
total += rings[i].scriptInputs(tx);
|
||||
for (i = 0; i < rings.length; i++) {
|
||||
ring = rings[i];
|
||||
total += tx.template(ring);
|
||||
}
|
||||
|
||||
callback(null, total);
|
||||
});
|
||||
@ -1404,15 +1409,15 @@ Wallet.prototype.sign = function sign(tx, options, callback) {
|
||||
passphrase = options.passphrase;
|
||||
timeout = options.timeout;
|
||||
|
||||
this.deriveInputs(tx, function(err, rings) {
|
||||
this.unlock(passphrase, timeout, function(err, master) {
|
||||
if (err)
|
||||
return callback(err);
|
||||
|
||||
self.unlock(passphrase, timeout, function(err, master) {
|
||||
self.deriveInputs(tx, master, function(err, rings) {
|
||||
if (err)
|
||||
return callback(err);
|
||||
|
||||
self.signAsync(rings, master, tx, callback);
|
||||
self.signAsync(rings, tx, callback);
|
||||
});
|
||||
});
|
||||
};
|
||||
@ -1420,51 +1425,25 @@ Wallet.prototype.sign = function sign(tx, options, callback) {
|
||||
/**
|
||||
* Sign a transaction asynchronously.
|
||||
* @param {KeyRing[]} rings
|
||||
* @param {HDPrivateKey} master
|
||||
* @param {MTX} tx
|
||||
* @param {Number?} index
|
||||
* @param {SighashType?} type
|
||||
* @param {Function} callback - Returns [Error, Number] (total number
|
||||
* of inputs scripts built and signed).
|
||||
*/
|
||||
|
||||
Wallet.prototype.signAsync = function signAsync(rings, master, tx, callback) {
|
||||
Wallet.prototype.signAsync = function signAsync(rings, tx, callback) {
|
||||
var result;
|
||||
|
||||
if (!this.workerPool) {
|
||||
callback = utils.asyncify(callback);
|
||||
try {
|
||||
result = Wallet.sign(rings, master, tx);
|
||||
result = tx.sign(rings);
|
||||
} catch (e) {
|
||||
return callback(e);
|
||||
}
|
||||
return callback(null, result);
|
||||
}
|
||||
|
||||
this.workerPool.sign(rings, master, tx, callback);
|
||||
};
|
||||
|
||||
/**
|
||||
* Sign a transaction.
|
||||
* @param {KeyRing[]} rings
|
||||
* @param {HDPrivateKey} master
|
||||
* @param {MTX} tx
|
||||
* @param {Number?} index
|
||||
* @param {SighashType?} type
|
||||
*/
|
||||
|
||||
Wallet.sign = function sign(rings, master, tx) {
|
||||
var total = 0;
|
||||
var i, ring, key;
|
||||
|
||||
for (i = 0; i < rings.length; i++) {
|
||||
ring = rings[i];
|
||||
key = ring.derive(master);
|
||||
assert(utils.equal(key.getPublicKey(), ring.key));
|
||||
total += ring.sign(tx, key);
|
||||
}
|
||||
|
||||
return total;
|
||||
this.workerPool.sign(tx, rings, null, callback);
|
||||
};
|
||||
|
||||
/**
|
||||
@ -2072,7 +2051,7 @@ Wallet.fromJSON = function fromJSON(db, json) {
|
||||
Wallet.isWallet = function isWallet(obj) {
|
||||
return obj
|
||||
&& typeof obj.accountDepth === 'number'
|
||||
&& obj.scriptInputs === 'function';
|
||||
&& obj.template === 'function';
|
||||
};
|
||||
|
||||
/**
|
||||
@ -2120,7 +2099,7 @@ function Account(db, options) {
|
||||
this.accountIndex = 0;
|
||||
this.receiveDepth = 0;
|
||||
this.changeDepth = 0;
|
||||
this.type = keyTypes.PUBKEYHASH;
|
||||
this.type = Account.types.PUBKEYHASH;
|
||||
this.m = 1;
|
||||
this.n = 1;
|
||||
this.keys = [];
|
||||
@ -2130,6 +2109,27 @@ function Account(db, options) {
|
||||
this.fromOptions(options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Account types.
|
||||
* @enum {Number}
|
||||
* @default
|
||||
*/
|
||||
|
||||
Account.types = {
|
||||
PUBKEYHASH: 0,
|
||||
MULTISIG: 1
|
||||
};
|
||||
|
||||
/**
|
||||
* Account types by value.
|
||||
* @const {RevMap}
|
||||
*/
|
||||
|
||||
Account.typesByVal = {
|
||||
0: 'pubkeyhash',
|
||||
1: 'multisig'
|
||||
};
|
||||
|
||||
/**
|
||||
* Inject properties from options object.
|
||||
* @private
|
||||
@ -2177,12 +2177,12 @@ Account.prototype.fromOptions = function fromOptions(options) {
|
||||
|
||||
if (options.type != null) {
|
||||
if (typeof options.type === 'string') {
|
||||
this.type = keyTypes[options.type.toUpperCase()];
|
||||
this.type = Account.types[options.type.toUpperCase()];
|
||||
assert(this.type != null);
|
||||
} else {
|
||||
assert(typeof options.type === 'number');
|
||||
this.type = options.type;
|
||||
assert(keyTypesByVal[this.type]);
|
||||
assert(Account.typesByVal[this.type]);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2202,7 +2202,7 @@ Account.prototype.fromOptions = function fromOptions(options) {
|
||||
}
|
||||
|
||||
if (this.n > 1)
|
||||
this.type = keyTypes.MULTISIG;
|
||||
this.type = Account.types.MULTISIG;
|
||||
|
||||
if (this.m < 1 || this.m > this.n)
|
||||
throw new Error('m ranges between 1 and n');
|
||||
@ -2384,7 +2384,7 @@ Account.prototype._checkKeys = function _checkKeys(callback) {
|
||||
var self = this;
|
||||
var ring, hash;
|
||||
|
||||
if (this.initialized || this.type !== keyTypes.MULTISIG)
|
||||
if (this.initialized || this.type !== Account.types.MULTISIG)
|
||||
return callback(null, false);
|
||||
|
||||
if (this.keys.length !== this.n - 1)
|
||||
@ -2486,8 +2486,8 @@ Account.prototype.createAddress = function createAddress(change, callback) {
|
||||
* @returns {KeyRing}
|
||||
*/
|
||||
|
||||
Account.prototype.deriveReceive = function deriveReceive(index) {
|
||||
return this.deriveAddress(false, index);
|
||||
Account.prototype.deriveReceive = function deriveReceive(index, master) {
|
||||
return this.deriveAddress(false, index, master);
|
||||
};
|
||||
|
||||
/**
|
||||
@ -2496,8 +2496,8 @@ Account.prototype.deriveReceive = function deriveReceive(index) {
|
||||
* @returns {KeyRing}
|
||||
*/
|
||||
|
||||
Account.prototype.deriveChange = function deriveChange(index) {
|
||||
return this.deriveAddress(true, index);
|
||||
Account.prototype.deriveChange = function deriveChange(index, master) {
|
||||
return this.deriveAddress(true, index, master);
|
||||
};
|
||||
|
||||
/**
|
||||
@ -2507,13 +2507,20 @@ Account.prototype.deriveChange = function deriveChange(index) {
|
||||
* @returns {KeyRing}
|
||||
*/
|
||||
|
||||
Account.prototype.deriveAddress = function deriveAddress(change, index) {
|
||||
Account.prototype.deriveAddress = function deriveAddress(change, index, master) {
|
||||
var keys = [];
|
||||
var i, key, shared;
|
||||
var i, key, shared, ring;
|
||||
|
||||
change = +change;
|
||||
|
||||
key = this.accountKey.derive(change).derive(index);
|
||||
if (master) {
|
||||
key = master.deriveAccount44(this.accountIndex);
|
||||
key = key.derive(change).derive(index);
|
||||
} else {
|
||||
key = this.accountKey.derive(change).derive(index);
|
||||
}
|
||||
|
||||
keys.push(key.publicKey);
|
||||
|
||||
for (i = 0; i < this.keys.length; i++) {
|
||||
shared = this.keys[i];
|
||||
@ -2521,7 +2528,12 @@ Account.prototype.deriveAddress = function deriveAddress(change, index) {
|
||||
keys.push(shared.publicKey);
|
||||
}
|
||||
|
||||
return bcoin.keyring.fromAccount(this, key, keys, change, index);
|
||||
ring = bcoin.keyring.fromAccount(this, key, keys, change, index);
|
||||
|
||||
if (master)
|
||||
ring.privateKey = key.privateKey;
|
||||
|
||||
return ring;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -2607,7 +2619,7 @@ Account.prototype.inspect = function inspect() {
|
||||
name: this.name,
|
||||
network: this.network,
|
||||
initialized: this.initialized,
|
||||
type: keyTypesByVal[this.type].toLowerCase(),
|
||||
type: Account.typesByVal[this.type].toLowerCase(),
|
||||
m: this.m,
|
||||
n: this.n,
|
||||
address: this.initialized
|
||||
@ -2639,7 +2651,7 @@ Account.prototype.toJSON = function toJSON() {
|
||||
wid: this.wid,
|
||||
name: this.name,
|
||||
initialized: this.initialized,
|
||||
type: keyTypesByVal[this.type].toLowerCase(),
|
||||
type: Account.typesByVal[this.type].toLowerCase(),
|
||||
m: this.m,
|
||||
n: this.n,
|
||||
witness: this.witness,
|
||||
@ -2688,7 +2700,7 @@ Account.prototype.fromJSON = function fromJSON(json) {
|
||||
this.wid = json.wid;
|
||||
this.name = json.name;
|
||||
this.initialized = json.initialized;
|
||||
this.type = keyTypes[json.type.toUpperCase()];
|
||||
this.type = Account.types[json.type.toUpperCase()];
|
||||
this.m = json.m;
|
||||
this.n = json.n;
|
||||
this.witness = json.witness;
|
||||
@ -2763,7 +2775,7 @@ Account.prototype.fromRaw = function fromRaw(data) {
|
||||
this.changeDepth = p.readU32();
|
||||
this.accountKey = bcoin.hd.fromRaw(p.readBytes(82));
|
||||
|
||||
assert(keyTypesByVal[this.type]);
|
||||
assert(Account.typesByVal[this.type]);
|
||||
|
||||
count = p.readU8();
|
||||
|
||||
|
||||
@ -1673,7 +1673,7 @@ Path.prototype.fromKeyRing = function fromKeyRing(ring) {
|
||||
this.index = ring.index;
|
||||
|
||||
this.version = ring.witness ? 0 : -1;
|
||||
this.type = ring.getScriptType();
|
||||
this.type = ring.getType();
|
||||
|
||||
this.id = ring.id;
|
||||
this.hash = ring.getHash('hex');
|
||||
|
||||
@ -248,11 +248,10 @@ Workers.prototype.verify = function verify(tx, flags, callback) {
|
||||
* @param {Function} callback
|
||||
*/
|
||||
|
||||
Workers.prototype.sign = function sign(rings, master, tx, callback) {
|
||||
var args = [rings, master, tx];
|
||||
Workers.prototype.sign = function sign(tx, ring, type, callback) {
|
||||
var i, input, sig, sigs, total;
|
||||
|
||||
this.execute('sign', args, -1, function(err, result) {
|
||||
this.execute('sign', [tx, ring, type], -1, function(err, result) {
|
||||
if (err)
|
||||
return callback(err);
|
||||
|
||||
@ -775,8 +774,8 @@ jobs.verify = function verify(tx, flags) {
|
||||
* @param {MTX} tx
|
||||
*/
|
||||
|
||||
jobs.sign = function sign(rings, master, tx) {
|
||||
var total = bcoin.wallet.sign(rings, master, tx);
|
||||
jobs.sign = function sign(tx, ring, type) {
|
||||
var total = tx.sign(ring, type);
|
||||
var sigs = [];
|
||||
var i, input;
|
||||
|
||||
|
||||
@ -239,7 +239,7 @@ describe('Wallet', function() {
|
||||
var fake = bcoin.mtx().addInput(t1, 1) // 1000 (already redeemed)
|
||||
.addOutput(w, 500);
|
||||
// Script inputs but do not sign
|
||||
w.scriptInputs(fake, function(err) {
|
||||
w.template(fake, function(err) {
|
||||
assert.ifError(err);
|
||||
// Fake signature
|
||||
fake.inputs[0].script.set(0, FAKE_SIG);
|
||||
|
||||
Loading…
Reference in New Issue
Block a user