more script data extraction improvements.

This commit is contained in:
Christopher Jeffrey 2016-01-19 15:20:26 -08:00
parent b389dd1b5f
commit ebbb417283
2 changed files with 63 additions and 22 deletions

View File

@ -909,7 +909,7 @@ script.execute = function execute(data, stack, tx, index, flags, recurse) {
val = stack.pop();
if (flags.verifynulldummy !== false) {
if (!Array.isArray(val) || val.length > 0)
if (!script.isDummy(val))
return false;
}
@ -1170,6 +1170,15 @@ script.createMultisig = function createMultisig(keys, m, n) {
);
};
script.createScripthash = function createScripthash(s) {
assert(Array.isArray(s));
return [
'hash160',
utils.ripesha(script.encode(s)),
'equal'
];
};
script.redeem = function redeem(s) {
if (!Array.isArray(s[s.length - 1]))
return;
@ -1249,13 +1258,13 @@ script.spendable = function spendable(s, lockTime) {
};
script.getInputData = function getData(s, prev) {
var output;
var output, type;
if (prev && !script.isScripthash(prev)) {
output = script.getOutputData(prev);
output.side = 'input';
// We could call getInputData, but
// We could call _getInputData, but
// we really only need the signatures.
if (output.type === 'pubkey') {
output.signatures = [s[0]];
@ -1264,6 +1273,11 @@ script.getInputData = function getData(s, prev) {
output.keys = [s[1]];
} else if (output.type === 'multisig') {
output.signatures = s.slice(1);
} else if (output.type === 'scripthash') {
// Scripthash is the only case where
// we get more data from the input
// than the output.
output = script._getInputData(s, output.type);
} else {
output.signatures = script.getUnknownData(s).signatures;
}
@ -1271,13 +1285,24 @@ script.getInputData = function getData(s, prev) {
return output;
}
return script._getInputData(s);
if (script.isPubkeyInput(s))
type = 'pubkey';
else if (script.isPubkeyhashInput(s))
type = 'pubkeyhash';
else if (script.isMultisigInput(s))
type = 'multisig';
else if (script.isScripthashInput(s))
type = 'scripthash';
return script._getInputData(s, type);
};
script._getInputData = function _getInputData(s) {
script._getInputData = function _getInputData(s, type) {
var sig, key, hash, raw, redeem, lock, hash, address, input, output;
if (script.isPubkeyInput(s)) {
assert(typeof type === 'string');
if (type === 'pubkey') {
sig = s[0];
return {
type: 'pubkey',
@ -1287,7 +1312,7 @@ script._getInputData = function _getInputData(s) {
};
}
if (script.isPubkeyhashInput(s)) {
if (type === 'pubkeyhash') {
sig = s[0];
key = s[1];
hash = bcoin.wallet.key2hash(key);
@ -1302,7 +1327,7 @@ script._getInputData = function _getInputData(s) {
};
}
if (script.isMultisigInput(s)) {
if (type === 'multisig') {
sig = s.slice(1);
return {
type: 'multisig',
@ -1313,15 +1338,15 @@ script._getInputData = function _getInputData(s) {
};
}
if (script.isScripthashInput(s)) {
if (type === 'scripthash') {
raw = s[s.length - 1];
redeem = script.decode(raw);
lock = script.lockTime(redeem);
hash = bcoin.wallet.key2hash(raw);
address = bcoin.wallet.hash2addr(hash, 'scripthash');
input = script.getInputData(s.slice(0, -1));
delete input.none;
output = script.getOutputData(script.subscript(redeem));
input = script._getInputData(s.slice(0, -1), output.type);
delete input.none;
return utils.merge(input, output, {
type: 'scripthash',
side: 'input',
@ -1620,8 +1645,10 @@ script.isPubkeyhashInput = function isPubkeyhashInput(s, key) {
script.isMultisigInput = function isMultisigInput(s, keys, tx, i) {
var i, o;
// We need to rule out scripthash
// because it may look like multisig
// We need to rule out scripthash because
// it may look like multisig. This is
// strange because it's technically a
// recursive call.
if (script.isScripthashInput(s))
return false;
@ -1664,7 +1691,7 @@ script.isMultisigInput = function isMultisigInput(s, keys, tx, i) {
};
};
script.isScripthashInput = function isScripthashInput(s, data) {
script.isScripthashInput = function isScripthashInput(s, data, strict) {
var raw, redeem;
// Grab the raw redeem script.
@ -1680,6 +1707,25 @@ script.isScripthashInput = function isScripthashInput(s, data) {
if (!Array.isArray(raw))
return false;
// If the last data element is a valid
// signature or key, it's _extremely_
// unlikely this is a scripthash.
if (script.isSignatureEncoding(raw))
return false;
if (script.isKeyEncoding(raw))
return false;
// Check data against last array in case
// a raw redeem script was passed in.
if (data && utils.isEqual(data, raw))
return raw;
// Return here if we do not want to check
// against standard transaction types.
if (!strict)
return raw;
// P2SH redeem scripts can be nonstandard: make
// it easier for other functions to parse this.
redeem = script.subscript(script.decode(raw));
@ -1694,11 +1740,6 @@ script.isScripthashInput = function isScripthashInput(s, data) {
return false;
}
// Check data against last array in case
// a raw redeem script was passed in.
if (data && utils.isEqual(data, raw))
return raw;
// Test against all other script types
if (!script.isPubkey(redeem, data)
&& !script.isPubkeyhash(redeem, data)
@ -1840,7 +1881,7 @@ script.isSignature = function isSignature(sig) {
return sig.length >= 9 && sig.length <= 73;
};
script.isEmpty = function isEmpty(data) {
script.isDummy = function isDummy(data) {
if (!utils.isBuffer(data))
return false;

View File

@ -423,7 +423,7 @@ TX.prototype.signInput = function signInput(index, key, type) {
// and increment the total number of
// signatures.
if (ki < len && signatures < m) {
if (bcoin.script.isEmpty(input.script[ki])) {
if (bcoin.script.isDummy(input.script[ki])) {
input.script[ki] = signature;
signatures++;
}
@ -433,7 +433,7 @@ TX.prototype.signInput = function signInput(index, key, type) {
if (signatures >= m) {
// Remove empty slots left over.
for (i = len - 1; i >= 1; i--) {
if (bcoin.script.isEmpty(input.script[i])) {
if (bcoin.script.isDummy(input.script[i])) {
input.script.splice(i, 1);
len--;
}