refactor tx.verify.

This commit is contained in:
Christopher Jeffrey 2016-06-12 23:16:00 -07:00
parent af8e3945b7
commit e51464f29b
No known key found for this signature in database
GPG Key ID: 8962AB9DE6666BBD
8 changed files with 92 additions and 89 deletions

View File

@ -903,7 +903,7 @@ Chain.prototype._checkInputs = function _checkInputs(block, prev, state, callbac
if (!scriptCheck) if (!scriptCheck)
return next(null, true); return next(null, true);
tx.verifyAsync(null, true, state.flags, next); tx.verifyAsync(state.flags, next);
}, function(err, verified) { }, function(err, verified) {
if (err) if (err)
return callback(err); return callback(err);

View File

@ -1092,12 +1092,12 @@ Mempool.prototype.verify = function verify(entry, callback) {
return callback(new VerifyError(tx, 'invalid', ret.reason, ret.score)); return callback(new VerifyError(tx, 'invalid', ret.reason, ret.score));
// Do this in the worker pool. // Do this in the worker pool.
tx.verifyAsync(null, true, flags, function(err, result) { tx.verifyAsync(flags, function(err, result) {
if (err) if (err)
return callback(err); return callback(err);
if (!result) { if (!result) {
return tx.verifyAsync(null, true, mandatory, function(err, result) { return tx.verifyAsync(mandatory, function(err, result) {
if (err) if (err)
return callback(err); return callback(err);

View File

@ -567,61 +567,67 @@ TX.prototype.signatureHashV1 = function signatureHashV1(index, prev, type) {
}; };
/** /**
* Verify the transaction inputs. * Verify all transaction inputs.
* @param {Number?} index - Index of output being * @param {VerifyFlags} [flags=STANDARD_VERIFY_FLAGS]
* verified. If not present, all outputs will be verified.
* @param {Boolean?} force - Force the transaction to
* be verified, even if it has been confirmed.
* @param {VerifyFlags?} flags
* @returns {Boolean} Whether the inputs are valid. * @returns {Boolean} Whether the inputs are valid.
*/ */
TX.prototype.verify = function verify(index, force, flags) { TX.prototype.verify = function verify(flags) {
var i, input; var i;
// Valid if included in block
if (!force && this.ts !== 0)
return true;
if (this.inputs.length === 0) if (this.inputs.length === 0)
return false; return false;
if (index && typeof index === 'object')
index = this.inputs.indexOf(index);
if (index != null)
assert(this.inputs[index]);
if (this.isCoinbase()) if (this.isCoinbase())
return true; return true;
for (i = 0; i < this.inputs.length; i++) { for (i = 0; i < this.inputs.length; i++) {
input = this.inputs[i]; if (!this.verifyInput(i, flags))
if (index != null && i !== index)
continue;
if (!input.coin) {
bcoin.debug('Warning: Not all coins are available for tx.verify().');
return false; return false;
} }
try { return true;
Script.verify( };
input.script,
input.witness, /**
input.coin.script, * Verify a transaction input.
this, * @param {Number} index - Index of output being
i, * verified.
flags * @param {VerifyFlags} [flags=STANDARD_VERIFY_FLAGS]
); * @returns {Boolean} Whether the input is valid.
} catch (e) { */
if (e.type === 'ScriptError')
bcoin.debug('Script verification error: %s', e.message); TX.prototype.verifyInput = function verifyInput(index, flags) {
else var input;
bcoin.debug('Script interpreter threw: %s', e.stack + '');
return false; if (typeof index === 'object')
} index = this.inputs.indexOf(index);
input = this.inputs[index];
assert(input, 'Input does not exist.');
if (!input.coin) {
bcoin.debug('Coin is not available for verification.');
return false;
}
try {
Script.verify(
input.script,
input.witness,
input.coin.script,
this,
index,
flags
);
} catch (e) {
if (e.type === 'ScriptError')
bcoin.debug('Script verification error: %s', e.message);
else
bcoin.error(e);
return false;
} }
return true; return true;
@ -630,39 +636,40 @@ TX.prototype.verify = function verify(index, force, flags) {
/** /**
* Verify the transaction inputs on the worker pool * Verify the transaction inputs on the worker pool
* (if workers are enabled). * (if workers are enabled).
* @param {Number?} index - Index of output being * @param {VerifyFlags?} [flags=STANDARD_VERIFY_FLAGS]
* verified. If not present, all outputs will be verified.
* @param {Boolean?} force - Force the transaction to
* be verified, even if it has been confirmed.
* @param {VerifyFlags?} flags
* @param {Function} callback * @param {Function} callback
* @returns {Boolean} Whether the inputs are valid. * @returns {Boolean} Whether the inputs are valid.
*/ */
TX.prototype.verifyAsync = function verifyAsync(index, force, flags, callback) { TX.prototype.verifyAsync = function verifyAsync(flags, callback) {
var res; var result;
callback = utils.asyncify(callback); if (typeof flags === 'function') {
callback = flags;
flags = null;
}
if (!bcoin.workerPool) { if (!bcoin.workerPool) {
callback = utils.asyncify(callback);
try { try {
res = this.verify(index, force, flags); result = this.verify(flags);
} catch (e) { } catch (e) {
return callback(e); return callback(e);
} }
return callback(null, res); return callback(null, result);
} }
if (!force && this.ts !== 0) if (this.inputs.length === 0) {
return callback(null, true); callback = utils.asyncify(callback);
if (this.inputs.length === 0)
return callback(null, false); return callback(null, false);
}
if (this.isCoinbase()) if (this.isCoinbase()) {
callback = utils.asyncify(callback);
return callback(null, true); return callback(null, true);
}
bcoin.workerPool.verify(this, index, force, flags, callback); bcoin.workerPool.verify(this, flags, callback);
}; };
/** /**

View File

@ -367,7 +367,7 @@ TXDB.prototype._add = function add(tx, map, callback, force) {
// Skip invalid transactions // Skip invalid transactions
if (self.options.verify) { if (self.options.verify) {
if (!tx.verify(i)) if (!tx.verifyInput(i))
return callback(null, false); return callback(null, false);
} }
@ -406,7 +406,7 @@ TXDB.prototype._add = function add(tx, map, callback, force) {
// Skip invalid transactions // Skip invalid transactions
if (self.options.verify) { if (self.options.verify) {
if (!tx.verify(i)) if (!tx.verifyInput(i))
return callback(null, false, map); return callback(null, false, map);
} }
@ -488,7 +488,7 @@ TXDB.prototype._add = function add(tx, map, callback, force) {
return next(); return next();
} }
if (orphan.tx.verify(orphan.index)) { if (orphan.tx.verifyInput(orphan.index)) {
some = true; some = true;
return next(); return next();
} }

View File

@ -247,14 +247,12 @@ Workers.prototype.execute = function execute(method, args, timeout, callback) {
/** /**
* Execute the tx verification job (default timeout). * Execute the tx verification job (default timeout).
* @param {TX} tx * @param {TX} tx
* @param {Number} index
* @param {Boolean} force
* @param {VerifyFlags} flags * @param {VerifyFlags} flags
* @param {Function} callback - Returns [Error, Boolean]. * @param {Function} callback - Returns [Error, Boolean].
*/ */
Workers.prototype.verify = function verify(tx, index, force, flags, callback) { Workers.prototype.verify = function verify(tx, flags, callback) {
return this.execute('verify', [tx, index, force, flags], -1, callback); return this.execute('verify', [tx, flags], -1, callback);
}; };
/** /**
@ -698,14 +696,12 @@ jobs = {};
* Execute tx.verify() on worker. * Execute tx.verify() on worker.
* @see TX#verify * @see TX#verify
* @param {TX} tx * @param {TX} tx
* @param {Number?} index * @param {VerifyFlags} flags
* @param {Boolean?} force
* @param {VerifyFlags?} flags
* @returns {Boolean} * @returns {Boolean}
*/ */
jobs.verify = function verify(tx, index, force, flags) { jobs.verify = function verify(tx, flags) {
return tx.verify(index, force, flags); return tx.verify(flags);
}; };
/** /**

View File

@ -77,7 +77,7 @@ describe('Block', function() {
assert(b.verify()); assert(b.verify());
}); });
it('should be jsonified and unjsonified and still verify', function() { it('should be serialized and deserialized and still verify', function() {
var raw = mblock.toRaw(); var raw = mblock.toRaw();
var b = bcoin.merkleblock.fromRaw(raw); var b = bcoin.merkleblock.fromRaw(raw);
assert.deepEqual(b.render(), raw); assert.deepEqual(b.render(), raw);
@ -132,7 +132,7 @@ describe('Block', function() {
var tx = block.txs[i]; var tx = block.txs[i];
assert(tx.isSane()); assert(tx.isSane());
assert(tx.checkInputs(block.height)); assert(tx.checkInputs(block.height));
assert(tx.verify(null, true, flags)); assert(tx.verify(flags));
} }
assert.equal(block.getReward(), 2507773345); assert.equal(block.getReward(), 2507773345);
assert.equal(block.getReward(), block.txs[0].outputs[0].value); assert.equal(block.getReward(), block.txs[0].outputs[0].value);

View File

@ -132,27 +132,27 @@ describe('TX', function() {
it('should verify non-minimal output' + suffix, function() { it('should verify non-minimal output' + suffix, function() {
clearCache(tx1, nocache); clearCache(tx1, nocache);
assert(tx1.verify(null, true, constants.flags.VERIFY_P2SH)); assert(tx1.verify(constants.flags.VERIFY_P2SH));
}); });
it('should verify tx.version == 0' + suffix, function() { it('should verify tx.version == 0' + suffix, function() {
clearCache(tx2, nocache); clearCache(tx2, nocache);
assert(tx2.verify(null, true, constants.flags.VERIFY_P2SH)); assert(tx2.verify(constants.flags.VERIFY_P2SH));
}); });
it('should verify sighash_single bug w/ findanddelete' + suffix, function() { it('should verify sighash_single bug w/ findanddelete' + suffix, function() {
clearCache(tx3, nocache); clearCache(tx3, nocache);
assert(tx3.verify(null, true, constants.flags.VERIFY_P2SH)); assert(tx3.verify(constants.flags.VERIFY_P2SH));
}); });
it('should verify high S value with only DERSIG enabled' + suffix, function() { it('should verify high S value with only DERSIG enabled' + suffix, function() {
clearCache(tx4, nocache); clearCache(tx4, nocache);
assert(tx4.verify(0, true, constants.flags.VERIFY_P2SH | constants.flags.VERIFY_DERSIG)); assert(tx4.verifyInput(0, constants.flags.VERIFY_P2SH | constants.flags.VERIFY_DERSIG));
}); });
it('should verify the coolest tx ever sent' + suffix, function() { it('should verify the coolest tx ever sent' + suffix, function() {
clearCache(coolest, nocache); clearCache(coolest, nocache);
assert(coolest.verify(null, true, constants.flags.VERIFY_NONE)); assert(coolest.verify(constants.flags.VERIFY_NONE));
}); });
it('should parse witness tx properly', function() { it('should parse witness tx properly', function() {
@ -249,13 +249,13 @@ describe('TX', function() {
} }
it('should handle valid tx test' + suffix + ': ' + comments, function() { it('should handle valid tx test' + suffix + ': ' + comments, function() {
clearCache(tx, nocache); clearCache(tx, nocache);
assert.ok(tx.verify(null, true, flags)); assert.ok(tx.verify(flags));
}); });
} else { } else {
if (comments === 'Duplicate inputs') { if (comments === 'Duplicate inputs') {
it('should handle duplicate input test' + suffix + ': ' + comments, function() { it('should handle duplicate input test' + suffix + ': ' + comments, function() {
clearCache(tx, nocache); clearCache(tx, nocache);
assert.ok(tx.verify(null, true, flags)); assert.ok(tx.verify(flags));
assert.ok(!tx.isSane()); assert.ok(!tx.isSane());
}); });
return; return;
@ -263,7 +263,7 @@ describe('TX', function() {
if (comments === 'Negative output') { if (comments === 'Negative output') {
it('should handle invalid tx (negative)' + suffix + ': ' + comments, function() { it('should handle invalid tx (negative)' + suffix + ': ' + comments, function() {
clearCache(tx, nocache); clearCache(tx, nocache);
assert.ok(tx.verify(null, true, flags)); assert.ok(tx.verify(flags));
assert.ok(!tx.isSane()); assert.ok(!tx.isSane());
}); });
return; return;
@ -277,7 +277,7 @@ describe('TX', function() {
} }
it('should handle invalid tx test' + suffix + ': ' + comments, function() { it('should handle invalid tx test' + suffix + ': ' + comments, function() {
clearCache(tx, nocache); clearCache(tx, nocache);
assert.ok(!tx.verify(null, true, flags)); assert.ok(!tx.verify(flags));
}); });
} }
}); });

View File

@ -125,7 +125,7 @@ describe('Wallet', function() {
w.sign(tx, function(err) { w.sign(tx, function(err) {
assert.ifError(err); assert.ifError(err);
assert(tx.verify(null, true, flags)); assert(tx.verify(flags));
cb(); cb();
}); });
}); });
@ -649,18 +649,18 @@ describe('Wallet', function() {
// Create a tx requiring 2 signatures // Create a tx requiring 2 signatures
var send = bcoin.mtx(); var send = bcoin.mtx();
send.addOutput({ address: receive.getAddress(), value: 5460 }); send.addOutput({ address: receive.getAddress(), value: 5460 });
assert(!send.verify(null, true, flags)); assert(!send.verify(flags));
w1.fill(send, { rate: 10000, round: true }, function(err) { w1.fill(send, { rate: 10000, round: true }, function(err) {
assert.ifError(err); assert.ifError(err);
w1.sign(send, function(err) { w1.sign(send, function(err) {
assert.ifError(err); assert.ifError(err);
assert(!send.verify(null, true, flags)); assert(!send.verify(flags));
w2.sign(send, function(err) { w2.sign(send, function(err) {
assert.ifError(err); assert.ifError(err);
assert(send.verify(null, true, flags)); assert(send.verify(flags));
assert.equal(w1.changeDepth, 1); assert.equal(w1.changeDepth, 1);
var change = w1.changeAddress.getAddress(); var change = w1.changeAddress.getAddress();
@ -695,7 +695,7 @@ describe('Wallet', function() {
else else
send.inputs[0].script.code[2] = 0; send.inputs[0].script.code[2] = 0;
assert(!send.verify(null, true, flags)); assert(!send.verify(flags));
assert.equal(send.getFee(), 10000); assert.equal(send.getFee(), 10000);
// w3 = bcoin.wallet.fromJSON(w3.toJSON()); // w3 = bcoin.wallet.fromJSON(w3.toJSON());