improve locktime checks and coinbase parsing.

This commit is contained in:
Christopher Jeffrey 2015-12-23 02:34:37 -08:00
parent 4ac398e41b
commit b3f457ee31
2 changed files with 91 additions and 25 deletions

View File

@ -62,7 +62,7 @@ function Block(data, subtype) {
if (this.version >= 2) {
tx = this.txs[0];
if (tx && tx.inputs[0] && +tx.inputs[0].out.hash === 0) {
height = bcoin.script.coinbaseHeight(tx.inputs[0].script);
height = bcoin.script.coinbaseHeight(tx.inputs[0].script, this);
if (height > 0)
this._height = height;
}

View File

@ -384,7 +384,10 @@ script.execute = function execute(s, stack, tx, index, recurse) {
case 'roll': {
if (stack.length < 2)
return false;
n = new bn(stack.pop()).toNumber();
v = stack.pop();
if (v.length > 6)
return false;
n = new bn(v).toNumber();
if (n < 0 || n >= stack.length)
return false;
v = stack[-n - 1];
@ -772,7 +775,15 @@ script.execute = function execute(s, stack, tx, index, recurse) {
if (!tx || stack.length === 0)
return false;
lock = new bn(stack[stack.length - 1]).toNumber();
lock = stack[stack.length - 1];
if (!Array.isArray(lock))
return false;
if (lock.length > 6)
return false;
lock = new bn(lock).toNumber();
if (lock < 0)
return false;
@ -878,11 +889,20 @@ script.standard = function standard(s) {
};
script.lockTime = function lockTime(s) {
return s.length > 3
var lock = s[0];
var res = s.length > 3
&& Array.isArray(s[0])
&& s[1] === 'checklocktimeverify'
&& s[2] === 'drop'
&& new bn(s[0]);
&& s[2] === 'drop';
if (!res)
return false;
// Number can only store 6 & 5/8 bytes
if (lock.length > 6)
lock = [0x1f].concat(lock.slice(0, 6));
return new bn(lock);
};
script.spendable = function spendable(s, lockTime) {
@ -1138,38 +1158,84 @@ script.isScripthashInput = function isScripthashInput(s, redeem) {
return keys;
};
script.coinbaseHeight = function coinbaseHeight(s) {
var raw = s._raw || script.encode(s);
var height;
script.coinbaseBits = function coinbaseBits(s, block) {
var value;
if (!Array.isArray(s[0]))
return -1;
return { type: 'value', value: s[0] };
if (raw[0] < 0x03 || s[0].length < 3)
return -1;
// Number can only store up to 53 bits (6 & 5/8 bytes)
if (s[0].length > 6)
return { type: 'value', value: s[0] };
height = new bn(s[0].reverse()).toNumber();
value = new bn(s[0].reverse()).toNumber();
if (block) {
if (value === block.bits)
return { type: 'bits', value: value };
if (value === block.ts)
return { type: 'ts', value: value };
if (block.version < 2)
return { type: 'value', value: value };
}
// Last v1 block
if (height < 227835)
return -1;
if (s[0].length < 3 || value < 227835)
return { type: 'value', value: value };
return height;
return { type: 'height', value: value };
};
script.coinbase = function coinbase(s) {
var raw = s._raw || script.encode(s);
var data = script.coinbaseHeight(s);
script.coinbaseHeight = function coinbaseHeight(s, block) {
var data = script.coinbaseBits(s, block);
if (data.type !== 'height')
return -1;
return data.value;
};
if (height > 0)
raw = raw.slice(raw[0] + 1);
script.coinbase = function coinbase(s, block) {
var coinbase, data, nonce, flags;
return {
height: height,
coinbase = {
script: s,
data: raw,
text: utils.array2utf8(raw)
raw: s._raw || script.encode(s)
};
data = script.coinbaseBits(s, block);
if (Array.isArray(s[1]))
nonce = new bn(s[1]);
flags = s.slice(2);
coinbase[data.type] = data.value;
coinbase.nonce = nonce;
coinbase.flags = flags;
coinbase.text = utils.array2utf8(flags);
return coinbase;
};
script.isCoinbase = function isCoinbase(s, block) {
var coinbase = script.coinbase(s, block);
if (coinbase.raw.length > 100 || s.length < 2)
return false;
if (coinbase.value != null)
return false;
if (coinbase.nonce == null)
return false;
if (block) {
if (coinbase.bits != null && coinbase.flags.length)
return false;
}
return coinbase;
};
// https://github.com/bitcoin/bips/blob/master/bip-0066.mediawiki