From c68ab4ee7d3ee933f9b9eaf7d60be3ec8fe22ef0 Mon Sep 17 00:00:00 2001 From: Christopher Jeffrey Date: Tue, 15 Dec 2015 01:21:11 -0800 Subject: [PATCH] implement all sighash types. add hasUnspent(). --- lib/bcoin/protocol/constants.js | 2 +- lib/bcoin/script.js | 30 +++++++++++++++------------- lib/bcoin/tx-pool.js | 35 +++++++++++++++++++++++++++++++++ lib/bcoin/tx.js | 35 +++++++++++++++++++++++++++++++++ 4 files changed, 87 insertions(+), 15 deletions(-) diff --git a/lib/bcoin/protocol/constants.js b/lib/bcoin/protocol/constants.js index 7f9722c1..f4b7e031 100644 --- a/lib/bcoin/protocol/constants.js +++ b/lib/bcoin/protocol/constants.js @@ -135,7 +135,7 @@ exports.hashType = { all: 1, none: 2, single: 3, - anyonecaypay: 0x80 + anyonecanpay: 0x80 }; exports.rhashType = Object.keys(exports.hashType).reduce(function(out, type) { diff --git a/lib/bcoin/script.js b/lib/bcoin/script.js index c6e6672f..70db9d27 100644 --- a/lib/bcoin/script.js +++ b/lib/bcoin/script.js @@ -88,19 +88,21 @@ script.encode = function encode(s) { return res; }; -script.subscript = function subscript(s) { +script.subscript = function subscript(s, lastSep) { if (!s) return []; - var lastSep = -1; - for (var i = 0; i < s.length; i++) { - if (s[i] === 'codesep') - lastSep = i; - else if (s[i] === 'checksig' || - s[i] === 'checksigverify' || - s[i] === 'checkmultisig' || - s[i] === 'checkmultisigverify') { - break; + if (lastSep == null) { + lastSep = -1; + for (var i = 0; i < s.length; i++) { + if (s[i] === 'codesep') + lastSep = i; + else if (s[i] === 'checksig' || + s[i] === 'checksigverify' || + s[i] === 'checkmultisig' || + s[i] === 'checkmultisigverify') { + break; + } } } @@ -579,13 +581,13 @@ script.execute = function execute(s, stack, tx, index) { var pub = stack.pop(); var sig = stack.pop(); var type = sig[sig.length - 1]; - if (!constants.rhashType[type & 0x7f]) + if (!constants.rhashType[type & 0x1f]) return false; if (!script.isValidSig(sig)) return false; - var subscript = s.slice(lastSep + 1); + var subscript = script.subscript(s, lastSep); var hash = tx.subscriptHash(index, subscript, type); var res = script.verify(hash, sig.slice(0, -1), pub); @@ -633,13 +635,13 @@ script.execute = function execute(s, stack, tx, index) { for (var i = 0; i < m; i++) { var sig = stack.pop(); var type = sig[sig.length - 1]; - if (!constants.rhashType[type & 0x7f]) + if (!constants.rhashType[type & 0x1f]) return false; if (!script.isValidSig(sig)) return false; - var subscript = s.slice(lastSep + 1); + var subscript = script.subscript(s, lastSep); var hash = tx.subscriptHash(index, subscript, type); // Strict order: diff --git a/lib/bcoin/tx-pool.js b/lib/bcoin/tx-pool.js index 57cad41b..59d465e8 100644 --- a/lib/bcoin/tx-pool.js +++ b/lib/bcoin/tx-pool.js @@ -207,6 +207,41 @@ TXPool.prototype.unspent = function unspent() { }, this); }; +TXPool.prototype.hasUnspent = function hasUnspent(hash, unspent) { + if (Array.isArray(hash) && hash.length && typeof hash[0] !== 'number') { + unspent = this.unspent(); + var has = hash.map(function(hash) { + var h = this.hasUnspent(hash, unspent); + if (!h) + return false; + return h[0]; + }, this).filter(Boolean); + if (has.length !== hash.length) + return null; + return has; + } + + if (Array.isArray(hash)) + hash = utils.toHex(hash); + else if (hash.out) + hash = hash.out.hash; + else if (hash.tx) + hash = hash.tx.hash('hex'); + else if (hash instanceof bcoin.tx) + hash = hash.hash('hex'); + + unspent = unspent || this.unspent(); + + var has = unspent.filter(function(item) { + return item.tx.hash('hex') === hash; + }); + + if (!has.length) + return null; + + return has; +}; + TXPool.prototype.pending = function pending() { return Object.keys(this._all).map(function(key) { return this._all[key]; diff --git a/lib/bcoin/tx.js b/lib/bcoin/tx.js index de0edc6d..02a67015 100644 --- a/lib/bcoin/tx.js +++ b/lib/bcoin/tx.js @@ -417,8 +417,43 @@ TX.prototype.subscriptHash = function subscriptHash(index, s, type) { copy.inputs.forEach(function(input, i) { input.script = index === i ? s : []; }); + + if ((type & 0x1f) === constants.hashType.all) { + ; + } else if ((type & 0x1f) === constants.hashType.none) { + copy.outputs = []; + copy.inputs.forEach(function(input, i) { + if (i !== index) + input.seq = 0; + }); + } else if ((type & 0x1f) === constants.hashType.single) { + while (copy.outputs.length < index + 1) + copy.outputs.push({}); + while (copy.outputs.length > index + 1) + copy.outputs.pop(); + copy.outputs.forEach(function(output, i) { + if (i !== index) { + output.script = []; + // output.value = new bn('ffffffffffffffff', 'hex'); + output.value = [0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff]; + output.value.toArray = function() { return this; }; + } + }); + copy.inputs.forEach(function(input, i) { + if (i !== index) + input.seq = 0; + }); + } + + if (type & constants.hashType.anyonecanpay) { + copy.inputs.length = 1; + copy.inputs[0].script = s; + } + var verifyStr = copy.render(); + utils.writeU32(verifyStr, type, verifyStr.length); + var hash = utils.dsha256(verifyStr); return hash;