diff --git a/lib/bcoin/block.js b/lib/bcoin/block.js index 29a3bfcc..d213dbe6 100644 --- a/lib/bcoin/block.js +++ b/lib/bcoin/block.js @@ -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; } diff --git a/lib/bcoin/script.js b/lib/bcoin/script.js index 76ab1f76..4e7fe717 100644 --- a/lib/bcoin/script.js +++ b/lib/bcoin/script.js @@ -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