From 5fd44dbed806826e31c4d0759ac0b7ada68ab87b Mon Sep 17 00:00:00 2001 From: Christopher Jeffrey Date: Thu, 5 May 2016 19:41:14 -0700 Subject: [PATCH] check sequence locks. --- lib/bcoin/chain.js | 150 ++++++++++++++++++++------------------------- 1 file changed, 68 insertions(+), 82 deletions(-) diff --git a/lib/bcoin/chain.js b/lib/bcoin/chain.js index 884e89b4..ccf23a18 100644 --- a/lib/bcoin/chain.js +++ b/lib/bcoin/chain.js @@ -434,7 +434,7 @@ Chain.prototype._preload = function _preload(callback) { Chain.prototype._verifyContext = function _verifyContext(block, prev, callback) { var self = this; - this._verify(block, prev, function(err, flags) { + this._verify(block, prev, function(err, state) { if (err) return callback(err); @@ -442,7 +442,7 @@ Chain.prototype._verifyContext = function _verifyContext(block, prev, callback) if (err) return callback(err); - self._checkInputs(block, prev, flags, function(err) { + self._checkInputs(block, prev, state, function(err) { if (err) return callback(err); @@ -577,7 +577,7 @@ Chain.prototype._verify = function _verify(block, prev, callback) { } } - return done(null, state.flags); + return done(null, state); }); }); }; @@ -786,11 +786,11 @@ Chain.prototype._findDuplicates = function _findDuplicates(block, prev, callback * @see TX#checkInputs * @param {Block} block * @param {ChainBlock} prev - * @param {VerifyFlags} flags + * @param {DeploymentState} state * @param {Function} callback - Returns [{@link VerifyError}]. */ -Chain.prototype._checkInputs = function _checkInputs(block, prev, flags, callback) { +Chain.prototype._checkInputs = function _checkInputs(block, prev, state, callback) { var self = this; var height = prev.height + 1; var scriptCheck = true; @@ -813,103 +813,90 @@ Chain.prototype._checkInputs = function _checkInputs(block, prev, flags, callbac this.db.fillBlock(block, function(err) { var ret = {}; var sigops = 0; - var i, j, input, tx, hash; if (err) return callback(err); // Check all transactions - for (i = 0; i < block.txs.length; i++) { - tx = block.txs[i]; - hash = tx.hash('hex'); + utils.forEachSerial(block.txs, function(tx, next) { + var hash = tx.hash('hex'); - // Count sigops (legacy + scripthash? + witness?) - sigops += tx.getSigopsCost(flags); - - if (sigops > constants.block.MAX_SIGOPS_COST) { - return callback(new VerifyError(block, - 'invalid', - 'bad-blk-sigops', - 100)); - } - - // Coinbases do not have prevouts. - if (tx.isCoinbase()) - continue; - - for (j = 0; j < tx.inputs.length; j++) { - input = tx.inputs[j]; - - // Ensure tx is not double spending an output. - if (!input.coin) { + // Ensure tx is not double spending an output. + if (!tx.isCoinbase()) { + if (!tx.hasCoins()) { assert(!historical, 'BUG: Spent inputs in historical data!'); - return callback(new VerifyError(block, + return next(new VerifyError(block, 'invalid', 'bad-txns-inputs-missingorspent', 100)); } + } - if (!self.options.verifySync) - continue; + self.checkLocks(tx, state.lockFlags, entry, function(err, valid) { + if (err) + return next(err); + if (!valid) { + return next(new VerifyError(block, + 'invalid', + 'bad-txns-nonfinal', + 100)); + } + + // Count sigops (legacy + scripthash? + witness?) + sigops += tx.getSigopsCost(state.flags); + + if (sigops > constants.block.MAX_SIGOPS_COST) { + return next(new VerifyError(block, + 'invalid', + 'bad-blk-sigops', + 100)); + } + + // Contextual sanity checks. + if (!tx.isCoinbase()) { + if (!tx.checkInputs(height, ret)) { + return next(new VerifyError(block, + 'invalid', + ret.reason, + ret.score)); + } + } + + return next(); + }); + }, function(err) { + if (err) + return callback(err); + + // Verify all txs in parallel. + utils.every(block.txs, function(tx, next) { if (!scriptCheck) - continue; + return next(null, true); - // Verify the scripts - if (!tx.verify(j, true, flags)) { - bcoin.debug( - 'Transaction failed consensus verification: %s', - tx.rhash); - bcoin.debug('TX:'); - bcoin.debug(tx); - bcoin.debug('Input (%d):', j); - bcoin.debug(input); - bcoin.debug('Serialized TX (with coins):'); - bcoin.debug(tx.toExtended('hex', true)); - bcoin.debug('Flags: %d', flags); + tx.verifyAsync(null, true, state.flags, next); + }, function(err, verified) { + if (err) + return callback(err); + + if (!verified) { assert(!historical, 'BUG: Invalid inputs in historical data!'); - return callback(new VerifyError(block, + return next(new VerifyError(block, 'invalid', 'mandatory-script-verify-flag-failed', 100)); } - } - // Contextual sanity checks. - if (!tx.checkInputs(height, ret)) { - return callback(new VerifyError(block, - 'invalid', - ret.reason, - ret.score)); - } - } + // Make sure the miner isn't trying to conjure more coins. + if (block.getClaimed().cmp(block.getReward()) > 0) { + return callback(new VerifyError(block, + 'invalid', + 'bad-cb-amount', + 100)); + } - // Make sure the miner isn't trying to conjure more coins. - if (block.getClaimed().cmp(block.getReward()) > 0) - return callback(new VerifyError(block, 'invalid', 'bad-cb-amount', 100)); - - if (self.options.verifySync) - return callback(); - - if (!scriptCheck) - return callback(); - - // Verify all txs in parallel. - utils.every(block.txs, function(tx, next) { - tx.verifyAsync(null, true, flags, next); - }, function(err, verified) { - if (err) - return callback(err); - - if (!verified) { - assert(!historical, 'BUG: Invalid inputs in historical data!'); - return callback(new VerifyError(block, - 'invalid', - 'mandatory-script-verify-flag-failed', - 100)); - } - - return callback(); + return callback(); + }); }); }); }; @@ -2470,7 +2457,7 @@ Chain.prototype.getLocks = function getLocks(tx, flags, entry, callback) { var minTime = -1; var coinHeight; - if (tx.version < 2 || !hasFlag) + if (tx.isCoinbase() || tx.version < 2 || !hasFlag) return utils.asyncify(callback)(null, minHeight, minTime); utils.forEachSerial(tx.inputs, function(input, next) { @@ -2555,7 +2542,6 @@ Chain.prototype.checkLocks = function checkLocks(tx, flags, entry, callback) { }); }; - /** * Calculate the difficulty. * @param {ChainBlock} entry