From 397e1f7d0bf4ab56c9fb2e961738fa3ed2c22ec1 Mon Sep 17 00:00:00 2001 From: Christopher Jeffrey Date: Mon, 18 Apr 2016 21:37:27 -0700 Subject: [PATCH] more accurate removeData. --- lib/bcoin/chain.js | 17 ++++++++----- lib/bcoin/script.js | 61 ++++++++++++++++++++++++++++++++++++++++++++- lib/bcoin/utils.js | 22 ++++++++++++++++ 3 files changed, 93 insertions(+), 7 deletions(-) diff --git a/lib/bcoin/chain.js b/lib/bcoin/chain.js index 671e1062..32f515a8 100644 --- a/lib/bcoin/chain.js +++ b/lib/bcoin/chain.js @@ -850,17 +850,22 @@ Chain.prototype._checkInputs = function _checkInputs(block, prev, flags, callbac 100)); } - //if (self.options.verifySync !== true) - // continue; + if (self.options.verifyAsync) + continue; if (!scriptCheck) continue; // Verify the scripts if (!tx.verify(j, true, flags)) { - utils.print(tx.rhash); - console.error(tx.inputs[j]); - //assert(!historical, 'BUG: Invalid inputs in historical data!'); + bcoin.debug( + 'Transaction failed consensus verification: %s', + tx.rhash); + bcoin.debug('TX:'); + bcoin.debug(tx); + bcoin.debug('Input:'); + bcoin.debug(tx.inputs[j]); + assert(!historical, 'BUG: Invalid inputs in historical data!'); return callback(new VerifyError(block, 'invalid', 'mandatory-script-verify-flag-failed', @@ -879,7 +884,7 @@ Chain.prototype._checkInputs = function _checkInputs(block, prev, flags, callbac if (block.getClaimed().cmp(block.getReward()) > 0) return callback(new VerifyError(block, 'invalid', 'bad-cb-amount', 100)); - //if (self.options.verifySync === true) + if (!self.options.verifyAsync) return callback(); if (!scriptCheck) diff --git a/lib/bcoin/script.js b/lib/bcoin/script.js index 04ca3b0e..1c2b2fa7 100644 --- a/lib/bcoin/script.js +++ b/lib/bcoin/script.js @@ -1869,24 +1869,83 @@ Script.array = function(value) { /** * Remove all matched data elements from * a script's code (used to remove signatures - * before verification). + * before verification). Note that this + * compares and removes data on the _byte level_. + * It also reserializes the data to a single + * script with minimaldata encoding beforehand. + * A signature will _not_ be removed if it is + * not minimaldata. + * @see https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2014-November/006878.html + * @see https://test.webbtc.com/tx/19aa42fee0fa57c45d3b16488198b27caaacc4ff5794510d0c17f173f05587ff * @param {Buffer} data - Data element to match against. * @returns {Number} Total. */ Script.prototype.removeData = function removeData(data) { + var total = 0; + var sig, raw, i, a, b; + + if (!this.raw) + return this.removeDataFast(data); + + sig = new Script([data]).encode(); + raw = this.encode(); + + // Note that this is _faster_ than Buffer#indexOf. + for (i = 0; i < raw.length; i++) { + if (raw.length - i < sig.length) + break; + if (this._cmp(raw, sig, i) === 0) { + a = raw.slice(0, i); + b = raw.slice(i + sig.length); + raw = Buffer.concat([a, b]); + total++; + } + } + + this.raw = raw; + + return total; +}; + +Script.prototype._cmp = function _cmp(target, data, start) { + var i, a, b; + + if (target.length - start < data.length) + return -1; + + for (i = 0; i < data.length; i++) { + a = target[i + start]; + b = data[i]; + if (a < b) + return -1; + if (a > b) + return 1; + } + + return 0; +}; + +Script.prototype.removeDataFast = function removeData(data) { var total = 0; var i; for (i = this.code.length - 1; i >= 0; i--) { if (!Buffer.isBuffer(this.code[i])) continue; + if (!Script.checkMinimal(this.code[i])) + continue; if (utils.equals(this.code[i], data)) { this.code.splice(i, 1); total++; } } + if (this.raw && total > 0) { + this.raw = null; + this.encode(); + } + return total; }; diff --git a/lib/bcoin/utils.js b/lib/bcoin/utils.js index 8afee663..d74906e5 100644 --- a/lib/bcoin/utils.js +++ b/lib/bcoin/utils.js @@ -997,6 +997,28 @@ utils.print = function print() { process.stdout.write(msg); }; +/** + * Write a message to stderr (console in browser). + * @param {Object|String} obj + * @param {...String} args + */ + +utils.error = function error() { + var args = Array.prototype.slice.call(arguments); + var msg; + + if (utils.isBrowser) { + msg = typeof args[0] === 'object' + ? args[0] + : utils.format(args, false).slice(0, -1); + console.error(msg); + return; + } + + msg = utils.format(args, true); + process.stderr.write(msg); +}; + /** * Shallow merge between multiple objects. * @param {Object} target