Added test coverage to transaction.verify

This commit is contained in:
Braydon Fuller 2015-04-30 12:09:59 -04:00
parent 3d447ded79
commit cd12164fae
2 changed files with 64 additions and 16 deletions

View File

@ -21,9 +21,10 @@ var MultiSigScriptHashInput = Input.MultiSigScriptHash;
var Output = require('./output'); var Output = require('./output');
var Script = require('../script'); var Script = require('../script');
var PrivateKey = require('../privatekey'); var PrivateKey = require('../privatekey');
var Block = require('../block');
var BN = require('../crypto/bn'); var BN = require('../crypto/bn');
var MAX_BLOCK_SIZE = 1000000;
/** /**
* Represents a transaction, a set of inputs and outputs to change ownership of tokens * Represents a transaction, a set of inputs and outputs to change ownership of tokens
* *
@ -186,7 +187,6 @@ Transaction.prototype.getSerializationError = function(opts) {
var feeIsTooLarge = this._isFeeTooLarge(); var feeIsTooLarge = this._isFeeTooLarge();
var feeIsTooSmall = this._isFeeTooSmall(); var feeIsTooSmall = this._isFeeTooSmall();
var isFullySigned = this.isFullySigned(); var isFullySigned = this.isFullySigned();
var hasDustOutputs = this._hasDustOutputs();
if (!opts.disableLargeFees && feeIsTooLarge) { if (!opts.disableLargeFees && feeIsTooLarge) {
if (missingChange) { if (missingChange) {
@ -982,37 +982,33 @@ Transaction.prototype.verify = function() {
return 'transaction txouts empty'; return 'transaction txouts empty';
} }
// Size limits
if (this.toBuffer().length > Block.MAX_BLOCK_SIZE) {
return 'transaction over the maximum block size';
}
// Check for negative or overflow output values // Check for negative or overflow output values
var valueoutbn = new BN(0); var valueoutbn = new BN(0);
for (var i = 0; i < this.outputs.length; i++) { for (var i = 0; i < this.outputs.length; i++) {
var txout = this.outputs[i]; var txout = this.outputs[i];
if (txout._satoshis > MAX_SAFE_INTEGER) { if (txout._satoshis > MAX_SAFE_INTEGER) {
return 'transaction txout ' + i + ' satoshis greater than max safe integer'; return 'transaction txout ' + i + ' satoshis greater than max safe integer';
} }
if (txout._satoshis !== txout._satoshisBN.toNumber()) { if (txout._satoshis !== txout._satoshisBN.toNumber()) {
return 'transaction txout ' + i + ' satoshis has corrupted value'; return 'transaction txout ' + i + ' satoshis has corrupted value';
} }
if (txout._satoshis < 0) {
var valuebn = new BN(txout._satoshis, 10);
if (valuebn.lt(BN.Zero)) {
return 'transaction txout ' + i + ' negative'; return 'transaction txout ' + i + ' negative';
} }
if (valuebn.gt(new BN(Transaction.MAX_MONEY, 10))) { if (txout._satoshisBN.gt(new BN(Transaction.MAX_MONEY, 10))) {
return 'transaction txout ' + i + ' greater than MAX_MONEY'; return 'transaction txout ' + i + ' greater than MAX_MONEY';
} }
valueoutbn = valueoutbn.add(valuebn); valueoutbn = valueoutbn.add(txout._satoshisBN);
if (valueoutbn.gt(new BN(Transaction.MAX_MONEY))) { if (valueoutbn.gt(new BN(Transaction.MAX_MONEY))) {
return 'transaction txout ' + i + ' total output greater than MAX_MONEY'; return 'transaction txout ' + i + ' total output greater than MAX_MONEY';
} }
} }
// Size limits
if (this.toBuffer().length > MAX_BLOCK_SIZE) {
return 'transaction over the maximum block size';
}
// Check for duplicate inputs // Check for duplicate inputs
var txinmap = {}; var txinmap = {};
for (i = 0; i < this.inputs.length; i++) { for (i = 0; i < this.inputs.length; i++) {

View File

@ -8,6 +8,7 @@ var _ = require('lodash');
var sinon = require('sinon'); var sinon = require('sinon');
var bitcore = require('../..'); var bitcore = require('../..');
var BN = bitcore.crypto.BN;
var Transaction = bitcore.Transaction; var Transaction = bitcore.Transaction;
var PrivateKey = bitcore.PrivateKey; var PrivateKey = bitcore.PrivateKey;
var Script = bitcore.Script; var Script = bitcore.Script;
@ -355,7 +356,7 @@ describe('Transaction', function() {
var buildSkipTest = function(builder, check) { var buildSkipTest = function(builder, check) {
return function() { return function() {
var transaction = new Transaction(); var transaction = new Transaction();
transaction.from(simpleUtxoWith1BTC) transaction.from(simpleUtxoWith1BTC);
builder(transaction); builder(transaction);
var options = {}; var options = {};
@ -410,6 +411,57 @@ describe('Transaction', function() {
}); });
}); });
describe('#verify', function() {
it('not if _satoshis and _satoshisBN have different values', function() {
var tx = new Transaction()
.from({
'txId': testPrevTx,
'outputIndex': 0,
'script': testScript,
'satoshis': testAmount
}).to('mrU9pEmAx26HcbKVrABvgL7AwA5fjNFoDc', testAmount - 10000);
tx.outputs[0]._satoshis = 100;
tx.outputs[0]._satoshisBN = new BN('fffffffffffffff', 16);
var verify = tx.verify();
verify.should.equal('transaction txout 0 satoshis has corrupted value');
});
it('not if _satoshis is negative', function() {
var tx = new Transaction()
.from({
'txId': testPrevTx,
'outputIndex': 0,
'script': testScript,
'satoshis': testAmount
}).to('mrU9pEmAx26HcbKVrABvgL7AwA5fjNFoDc', testAmount - 10000);
tx.outputs[0]._satoshis = -100;
tx.outputs[0]._satoshisBN = new BN(-100, 10);
var verify = tx.verify();
verify.should.equal('transaction txout 0 negative');
});
it('not if transaction is greater than max block size', function() {
var tx = new Transaction()
.from({
'txId': testPrevTx,
'outputIndex': 0,
'script': testScript,
'satoshis': testAmount
}).to('mrU9pEmAx26HcbKVrABvgL7AwA5fjNFoDc', testAmount - 10000);
tx.toBuffer = sinon.stub().returns({length: 10000000});
var verify = tx.verify();
verify.should.equal('transaction over the maximum block size');
});
});
describe('to and from JSON', function() { describe('to and from JSON', function() {
it('takes a string that is a valid JSON and deserializes from it', function() { it('takes a string that is a valid JSON and deserializes from it', function() {
var simple = new Transaction(); var simple = new Transaction();