signature work. script function renames. add wallet.fillTX/tx.fill.

This commit is contained in:
Christopher Jeffrey 2016-01-11 15:14:48 -08:00
parent 6f86ca2d02
commit b77314dd0f
3 changed files with 126 additions and 34 deletions

View File

@ -743,11 +743,11 @@ script.execute = function execute(s, stack, tx, index, flags, recurse) {
if (!script.isKey(key))
return false;
if (!script.isSig(sig))
if (!script.isSignature(sig))
return false;
if (flags.strictder !== false) {
if (!script.isValidSig(sig))
if (!script.isValidSignature(sig))
return false;
}
@ -815,11 +815,11 @@ script.execute = function execute(s, stack, tx, index, flags, recurse) {
for (i = 0, j = 0; i < m && j < n; i++) {
sig = stack.pop();
if (!script.isSig(sig))
if (!script.isSignature(sig))
return false;
if (flags.strictder !== false) {
if (!script.isValidSig(sig))
if (!script.isValidSignature(sig))
return false;
}
@ -1193,7 +1193,7 @@ script.isPubkeyInput = function isPubkeyInput(s, key, tx, i) {
if (s.length !== 1 || !Array.isArray(s[0]))
return false;
if (!script.isSig(s[0]))
if (!script.isSignature(s[0]))
return false;
// Execute the script against our key's
@ -1211,7 +1211,7 @@ script.isPubkeyhashInput = function isPubkeyhashInput(s, key) {
if (s.length !== 2 || !Array.isArray(s[0]) || !Array.isArray(s[1]))
return false;
if (!script.isSig(s[0]))
if (!script.isSignature(s[0]))
return false;
if (!script.isKey(s[1]))
@ -1240,7 +1240,7 @@ script.isMultisigInput = function isMultisigInput(s, keys, tx, i) {
return false;
for (i = 1; i < s.length; i++) {
if (!script.isSig(s[i]))
if (!script.isSignature(s[i]))
return false;
}
@ -1411,7 +1411,7 @@ script.isKey = function isKey(key) {
return key.length >= 33 && key.length <= 65;
};
script.isSig = function isSig(sig, allowZero) {
script.isSignature = function isSignature(sig, allowZero) {
if (!utils.isBuffer(sig))
return false;
@ -1432,7 +1432,7 @@ script.isSig = function isSig(sig, allowZero) {
*
* This function is consensus-critical since BIP66.
*/
script.isValidSig = function isValidSig(sig, allowZero) {
script.isValidSignature = function isValidSignature(sig, allowZero) {
var lenR, lenS;
if (!utils.isBuffer(sig))

View File

@ -158,7 +158,7 @@ TX.prototype._inputIndex = function _inputIndex(hash, index) {
// Build the scriptSigs for inputs, excluding the signatures
TX.prototype.scriptInput = function scriptInput(index, pub, redeem) {
var input, s, standard, n, i;
var input, s, n, i;
if (typeof index !== 'number')
index = this.inputs.indexOf(index);
@ -167,6 +167,9 @@ TX.prototype.scriptInput = function scriptInput(index, pub, redeem) {
input = this.inputs[index];
assert(input);
// We should have previous outputs by now.
assert(input.out.tx);
// Get the previous output's subscript
s = input.out.tx.getSubscript(input.out.index);
@ -194,10 +197,13 @@ TX.prototype.scriptInput = function scriptInput(index, pub, redeem) {
// but we create n signature slots so we can order
// the signatures properly.
input.script = [ [] ];
// Grab `n` value (number of keys).
n = s[s.length - 2];
// If using pushdata instead of OP_1-16:
if (Array.isArray(n))
n = n[0] || 0;
// Fill script with `n` signature slots.
for (i = 0; i < n; i++)
input.script[i + 1] = [];
}
@ -212,7 +218,7 @@ TX.prototype.scriptInput = function scriptInput(index, pub, redeem) {
// Sign the now-built scriptSigs
TX.prototype.signInput = function signInput(index, key, type) {
var input, s, hash, signature;
var len, redeem, m, keys, pub, pubn, ki, signatures, i;
var len, redeem, m, n, keys, pub, pubn, ki, signatures, i;
if (typeof index !== 'number')
index = this.inputs.indexOf(index);
@ -227,6 +233,9 @@ TX.prototype.signInput = function signInput(index, key, type) {
input = this.inputs[index];
assert(input);
// We should have previous outputs by now.
assert(input.out.tx);
// Get the previous output's subscript
s = input.out.tx.getSubscript(input.out.index);
@ -256,19 +265,56 @@ TX.prototype.signInput = function signInput(index, key, type) {
len--;
}
// Add signatures.
if (bcoin.script.isPubkey(s)) {
// P2PK
input.script[0] = signature;
if (Array.isArray(input.script[0]) && !input.script[0].length)
input.script[0] = signature;
return true;
} else if (bcoin.script.isPubkeyhash(s)) {
// P2PKH
input.script[0] = signature;
if (Array.isArray(input.script[0]) && !input.script[0].length)
input.script[0] = signature;
return true;
} else if (bcoin.script.isMultisig(s)) {
// Multisig
// Grab `m` value (number of sigs required).
m = s[0];
// If using pushdata instead of OP_1-16:
if (Array.isArray(m))
m = m[0] || 0;
// Grab `n` value (number of keys).
n = s[s.length - 2];
if (Array.isArray(m))
n = n[0] || 0;
// Something is very wrong here. Abort.
if (m < 1 || m > 15 || n < m || n > 15 || len - 1 > n)
return;
// Count the number of current signatures.
signatures = 0;
for (i = 1; i < len; i++) {
if (Array.isArray(input.script[i]) && input.script[i].length)
signatures++;
}
// Signatures are already finalized.
if (signatures === m && len - 1 === m)
return;
// This can happen in a case where another
// implementation adds signatures willy-nilly
// or by `m`. Add some signature slots for
// us to use.
while (len - 1 < n) {
input.script.splice(len, 0, []);
len++;
}
// Grab the redeem script's keys to figure
// out where our key should go.
keys = s.slice(1, -2);
pub = key.getPublic(true, 'array');
pubn = key.getPublic(false, 'array');
@ -280,39 +326,57 @@ TX.prototype.signInput = function signInput(index, key, type) {
break;
}
// Public key is not in the prev_out script
// Our public key is not in the prev_out
// script. We tried to sign a transaction
// that is not redeemable by us.
if (ki === keys.length)
return;
// No signature slot available
if (ki + 1 > len - 1)
return;
// Offset key index by one to turn it into
// "sig index". Accounts for OP_0 byte at
// the start.
ki++;
// Add our signature to the correct slot
// and count the total number of signatures.
signatures = 0;
for (i = 1; i < len; i++) {
if (Array.isArray(input.script[i]) && input.script[i].length) {
signatures++;
continue;
}
if (i - 1 === ki) {
if (signatures >= m)
continue;
input.script[i] = signature;
// and increment the total number of
// signatures.
if (ki < len && signatures < m) {
if (Array.isArray(input.script[ki]) && !input.script[ki].length) {
input.script[ki] = signature;
signatures++;
}
}
// All signatures added. Finalize by removing empty slots.
// All signatures added. Finalize.
if (signatures >= m) {
// Remove empty slots left over.
for (i = len - 1; i >= 1; i--) {
if (Array.isArray(input.script[i]) && !input.script[i].length)
if (Array.isArray(input.script[i]) && !input.script[i].length) {
input.script.splice(i, 1);
len--;
}
}
// Remove signatures which are not required.
// If just using bcoin for signing, this
// should never happen except with dealing
// with implementations that potentially
// handle signature slots differently.
while (signatures > m) {
input.script.splice(len - 1, 1);
signatures--;
len--;
}
// Sanity checks.
assert.equal(signatures, m);
assert.equal(len - 1, m);
}
return signatures === m;
}
return false;
};
TX.prototype.scriptSig = function scriptSig(index, key, pub, redeem, type) {
@ -857,6 +921,30 @@ TX.prototype.funds = function funds(side) {
return acc;
};
TX.prototype.fill = function fill(txs) {
var inputs;
if (txs instanceof bcoin.txPool)
txs = txs._all;
else if (txs instanceof bcoin.wallet)
txs = txs.tx._all;
if (Array.isArray(txs)) {
txs = txs.reduce(function(out, tx) {
out[tx.hash('hex')] = tx;
return out;
}, {});
}
inputs = this.inputs.filter(function(input) {
if (!input.out.tx && txs[input.out.hash])
input.out.tx = txs[input.out.hash];
return !!input.out.tx;
}, this);
return inputs.length === this.inputs.length;
};
// Used for postVerify/ContextualBlockCheck and miner isFinalTx call.
// BIP113 will require that time-locked transactions have nLockTime set to
// less than the median time of the previous block they're contained in.

View File

@ -242,7 +242,7 @@ Wallet.prototype.getPrivateKey = function getPrivateKey(enc) {
return priv;
};
Wallet.prototype.getScript = function getScript(enc) {
Wallet.prototype.getScript = function getScript() {
if (this.redeem)
return this.redeem.slice();
return bcoin.script.encode(bcoin.script.redeem(this.keys, this.m, this.n));
@ -448,6 +448,10 @@ Wallet.prototype.fillUnspent = function fillUnspent(tx, changeAddress) {
return tx.fillUnspent(this.unspent(), changeAddress);
};
Wallet.prototype.fillTX = function fillTX(tx) {
return tx.fill(this);
};
Wallet.prototype.scriptInputs = function scriptInputs(tx) {
var pub = this.getPublicKey();
var redeem = this.getScript();