Included satoshis check during checked serialization.
This commit is contained in:
parent
cd12164fae
commit
f8ea7e39cc
|
@ -81,6 +81,9 @@ module.exports = [{
|
||||||
}, {
|
}, {
|
||||||
name: 'DustOutputs',
|
name: 'DustOutputs',
|
||||||
message: 'Dust amount detected in one output'
|
message: 'Dust amount detected in one output'
|
||||||
|
}, {
|
||||||
|
name: 'InvalidSatoshis',
|
||||||
|
message: 'Output satoshis are invalid',
|
||||||
}, {
|
}, {
|
||||||
name: 'FeeError',
|
name: 'FeeError',
|
||||||
message: 'Fees are not correctly set {0}',
|
message: 'Fees are not correctly set {0}',
|
||||||
|
|
|
@ -9,6 +9,8 @@ var BufferWriter = require('../encoding/bufferwriter');
|
||||||
var Script = require('../script');
|
var Script = require('../script');
|
||||||
var $ = require('../util/preconditions');
|
var $ = require('../util/preconditions');
|
||||||
|
|
||||||
|
var MAX_SAFE_INTEGER = 0x1fffffffffffff;
|
||||||
|
|
||||||
function Output(params) {
|
function Output(params) {
|
||||||
if (!(this instanceof Output)) {
|
if (!(this instanceof Output)) {
|
||||||
return new Output(params);
|
return new Output(params);
|
||||||
|
@ -62,6 +64,19 @@ Object.defineProperty(Output.prototype, 'satoshis', {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Output.prototype.invalidSatoshis = function() {
|
||||||
|
if (this._satoshis > MAX_SAFE_INTEGER) {
|
||||||
|
return 'transaction txout satoshis greater than max safe integer';
|
||||||
|
}
|
||||||
|
if (this._satoshis !== this._satoshisBN.toNumber()) {
|
||||||
|
return 'transaction txout satoshis has corrupted value';
|
||||||
|
}
|
||||||
|
if (this._satoshis < 0) {
|
||||||
|
return 'transaction txout negative';
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
Output.prototype._fromObject = function(param) {
|
Output.prototype._fromObject = function(param) {
|
||||||
this.satoshis = param.satoshis;
|
this.satoshis = param.satoshis;
|
||||||
if (param.script || param.scriptBuffer) {
|
if (param.script || param.scriptBuffer) {
|
||||||
|
|
|
@ -23,8 +23,6 @@ var Script = require('../script');
|
||||||
var PrivateKey = require('../privatekey');
|
var PrivateKey = require('../privatekey');
|
||||||
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
|
||||||
*
|
*
|
||||||
|
@ -61,7 +59,7 @@ function Transaction(serialized) {
|
||||||
|
|
||||||
var CURRENT_VERSION = 1;
|
var CURRENT_VERSION = 1;
|
||||||
var DEFAULT_NLOCKTIME = 0;
|
var DEFAULT_NLOCKTIME = 0;
|
||||||
var MAX_SAFE_INTEGER = 0x1fffffffffffff;
|
var MAX_BLOCK_SIZE = 1000000;
|
||||||
|
|
||||||
// Minimum amount for an output for it not to be considered a dust output
|
// Minimum amount for an output for it not to be considered a dust output
|
||||||
Transaction.DUST_AMOUNT = 546;
|
Transaction.DUST_AMOUNT = 546;
|
||||||
|
@ -169,12 +167,22 @@ Transaction.prototype.checkedSerialize = function(opts) {
|
||||||
var serializationError = this.getSerializationError(opts);
|
var serializationError = this.getSerializationError(opts);
|
||||||
if (serializationError) {
|
if (serializationError) {
|
||||||
serializationError.message += ' Use Transaction#uncheckedSerialize if you want to skip security checks. ' +
|
serializationError.message += ' Use Transaction#uncheckedSerialize if you want to skip security checks. ' +
|
||||||
'See http://bitcore.io/guide/transaction.html#Serialization for more info.'
|
'See http://bitcore.io/guide/transaction.html#Serialization for more info.';
|
||||||
throw serializationError;
|
throw serializationError;
|
||||||
}
|
}
|
||||||
return this.uncheckedSerialize();
|
return this.uncheckedSerialize();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Transaction.prototype.invalidSatoshis = function() {
|
||||||
|
var invalid = false;
|
||||||
|
for (var i = 0; i < this.outputs.length; i++) {
|
||||||
|
if (this.outputs[i].invalidSatoshis()) {
|
||||||
|
invalid = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return invalid;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve a possible error that could appear when trying to serialize and broadcast this transaction
|
* Retrieve a possible error that could appear when trying to serialize and broadcast this transaction
|
||||||
*
|
*
|
||||||
|
@ -183,6 +191,11 @@ Transaction.prototype.checkedSerialize = function(opts) {
|
||||||
*/
|
*/
|
||||||
Transaction.prototype.getSerializationError = function(opts) {
|
Transaction.prototype.getSerializationError = function(opts) {
|
||||||
opts = opts || {};
|
opts = opts || {};
|
||||||
|
|
||||||
|
if (this.invalidSatoshis()) {
|
||||||
|
return new errors.Transaction.InvalidSatoshis();
|
||||||
|
}
|
||||||
|
|
||||||
var missingChange = this._missingChange();
|
var missingChange = this._missingChange();
|
||||||
var feeIsTooLarge = this._isFeeTooLarge();
|
var feeIsTooLarge = this._isFeeTooLarge();
|
||||||
var feeIsTooSmall = this._isFeeTooSmall();
|
var feeIsTooSmall = this._isFeeTooSmall();
|
||||||
|
@ -986,14 +999,9 @@ Transaction.prototype.verify = function() {
|
||||||
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) {
|
|
||||||
return 'transaction txout ' + i + ' satoshis greater than max safe integer';
|
if (txout.invalidSatoshis()) {
|
||||||
}
|
return 'transaction txout ' + i + ' satoshis is invalid';
|
||||||
if (txout._satoshis !== txout._satoshisBN.toNumber()) {
|
|
||||||
return 'transaction txout ' + i + ' satoshis has corrupted value';
|
|
||||||
}
|
|
||||||
if (txout._satoshis < 0) {
|
|
||||||
return 'transaction txout ' + i + ' negative';
|
|
||||||
}
|
}
|
||||||
if (txout._satoshisBN.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';
|
||||||
|
|
|
@ -246,6 +246,18 @@ describe('Transaction', function() {
|
||||||
transaction.outputs.length.should.equal(2);
|
transaction.outputs.length.should.equal(2);
|
||||||
transaction.outputs[1].satoshis.should.equal(10000);
|
transaction.outputs[1].satoshis.should.equal(10000);
|
||||||
});
|
});
|
||||||
|
it('if satoshis are invalid', function() {
|
||||||
|
var transaction = new Transaction()
|
||||||
|
.from(simpleUtxoWith100000Satoshis)
|
||||||
|
.to(toAddress, 99999)
|
||||||
|
.change(changeAddress)
|
||||||
|
.sign(privateKey);
|
||||||
|
transaction.outputs[0]._satoshis = 100;
|
||||||
|
transaction.outputs[0]._satoshisBN = new BN(101, 10);
|
||||||
|
expect(function() {
|
||||||
|
return transaction.serialize();
|
||||||
|
}).to.throw(errors.Transaction.InvalidSatoshis);
|
||||||
|
});
|
||||||
it('if fee is too small, fail serialization', function() {
|
it('if fee is too small, fail serialization', function() {
|
||||||
var transaction = new Transaction()
|
var transaction = new Transaction()
|
||||||
.from(simpleUtxoWith100000Satoshis)
|
.from(simpleUtxoWith100000Satoshis)
|
||||||
|
@ -425,7 +437,7 @@ describe('Transaction', function() {
|
||||||
tx.outputs[0]._satoshis = 100;
|
tx.outputs[0]._satoshis = 100;
|
||||||
tx.outputs[0]._satoshisBN = new BN('fffffffffffffff', 16);
|
tx.outputs[0]._satoshisBN = new BN('fffffffffffffff', 16);
|
||||||
var verify = tx.verify();
|
var verify = tx.verify();
|
||||||
verify.should.equal('transaction txout 0 satoshis has corrupted value');
|
verify.should.equal('transaction txout 0 satoshis is invalid');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('not if _satoshis is negative', function() {
|
it('not if _satoshis is negative', function() {
|
||||||
|
@ -440,7 +452,7 @@ describe('Transaction', function() {
|
||||||
tx.outputs[0]._satoshis = -100;
|
tx.outputs[0]._satoshis = -100;
|
||||||
tx.outputs[0]._satoshisBN = new BN(-100, 10);
|
tx.outputs[0]._satoshisBN = new BN(-100, 10);
|
||||||
var verify = tx.verify();
|
var verify = tx.verify();
|
||||||
verify.should.equal('transaction txout 0 negative');
|
verify.should.equal('transaction txout 0 satoshis is invalid');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('not if transaction is greater than max block size', function() {
|
it('not if transaction is greater than max block size', function() {
|
||||||
|
|
Loading…
Reference in New Issue