Make sure a specified transaction fee and outputs add up to the sum of the inputs. Don't ignore the fee when it's explicitly specified.
This commit is contained in:
parent
baf39f3c5f
commit
16dc489b08
@ -196,11 +196,15 @@ Transaction.prototype.getSerializationError = function(opts) {
|
|||||||
return new errors.Transaction.InvalidSatoshis();
|
return new errors.Transaction.InvalidSatoshis();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var feeIsDifferent = this._isFeeDifferent();
|
||||||
var missingChange = this._missingChange();
|
var missingChange = this._missingChange();
|
||||||
var feeIsTooLarge = this._isFeeTooLarge();
|
var feeIsTooLarge = this._isFeeTooLarge();
|
||||||
var feeIsTooSmall = this._isFeeTooSmall();
|
var feeIsTooSmall = this._isFeeTooSmall();
|
||||||
var isFullySigned = this.isFullySigned();
|
var isFullySigned = this.isFullySigned();
|
||||||
|
|
||||||
|
if (!opts.disableDifferentFees && feeIsDifferent) {
|
||||||
|
return new errors.Transaction.FeeError(feeIsDifferent);
|
||||||
|
}
|
||||||
if (!opts.disableLargeFees && feeIsTooLarge) {
|
if (!opts.disableLargeFees && feeIsTooLarge) {
|
||||||
if (missingChange) {
|
if (missingChange) {
|
||||||
return new errors.Transaction.ChangeAddressMissing('Fee is too large and no change address was provided');
|
return new errors.Transaction.ChangeAddressMissing('Fee is too large and no change address was provided');
|
||||||
@ -221,8 +225,17 @@ Transaction.prototype.getSerializationError = function(opts) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Transaction.prototype._isFeeDifferent = function() {
|
||||||
|
var fee = this.getFee();
|
||||||
|
var unspent = this._getUnspentValue();
|
||||||
|
if (fee !== unspent) {
|
||||||
|
return 'Unspent value ' + unspent + ' is different from specified fee ' +
|
||||||
|
fee + ' and no change address is specified';
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
Transaction.prototype._isFeeTooLarge = function() {
|
Transaction.prototype._isFeeTooLarge = function() {
|
||||||
var fee = this._getUnspentValue();
|
var fee = this.getFee();
|
||||||
var maximumFee = Math.floor(Transaction.FEE_SECURITY_MARGIN * this._estimateFee());
|
var maximumFee = Math.floor(Transaction.FEE_SECURITY_MARGIN * this._estimateFee());
|
||||||
if (fee > maximumFee) {
|
if (fee > maximumFee) {
|
||||||
return 'Fee is too large: expected less than ' + maximumFee + ' but got ' + fee;
|
return 'Fee is too large: expected less than ' + maximumFee + ' but got ' + fee;
|
||||||
@ -230,7 +243,7 @@ Transaction.prototype._isFeeTooLarge = function() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
Transaction.prototype._isFeeTooSmall = function() {
|
Transaction.prototype._isFeeTooSmall = function() {
|
||||||
var fee = this._getUnspentValue();
|
var fee = this.getFee();
|
||||||
var minimumFee = Math.ceil(this._estimateFee() / Transaction.FEE_SECURITY_MARGIN);
|
var minimumFee = Math.ceil(this._estimateFee() / Transaction.FEE_SECURITY_MARGIN);
|
||||||
if (fee < minimumFee) {
|
if (fee < minimumFee) {
|
||||||
return 'Fee is too small: expected more than ' + minimumFee + ' but got ' + fee;
|
return 'Fee is too small: expected more than ' + minimumFee + ' but got ' + fee;
|
||||||
@ -766,6 +779,8 @@ Transaction.prototype._updateChangeOutput = function() {
|
|||||||
/**
|
/**
|
||||||
* Calculates the fee of the transaction.
|
* Calculates the fee of the transaction.
|
||||||
*
|
*
|
||||||
|
* If there's a fixed fee set, return that.
|
||||||
|
*
|
||||||
* If there is no change output set, the fee is the
|
* If there is no change output set, the fee is the
|
||||||
* total value of the outputs minus inputs. Note that
|
* total value of the outputs minus inputs. Note that
|
||||||
* a serialized transaction only specifies the value
|
* a serialized transaction only specifies the value
|
||||||
@ -774,17 +789,20 @@ Transaction.prototype._updateChangeOutput = function() {
|
|||||||
* This method therefore raises a "MissingPreviousOutput"
|
* This method therefore raises a "MissingPreviousOutput"
|
||||||
* error when called on a serialized transaction.
|
* error when called on a serialized transaction.
|
||||||
*
|
*
|
||||||
* If there's a fixed fee set, return that.
|
* If there's no fee set and no change address,
|
||||||
* If there's no fee set, estimate it based on size.
|
* estimate the fee based on size.
|
||||||
*
|
*
|
||||||
* @return {Number} fee of this transaction in satoshis
|
* @return {Number} fee of this transaction in satoshis
|
||||||
*/
|
*/
|
||||||
Transaction.prototype.getFee = function() {
|
Transaction.prototype.getFee = function() {
|
||||||
|
if (!_.isUndefined(this._fee)) {
|
||||||
|
return this._fee;
|
||||||
|
}
|
||||||
// if no change output is set, fees should equal all the unspent amount
|
// if no change output is set, fees should equal all the unspent amount
|
||||||
if (!this._changeScript) {
|
if (!this._changeScript) {
|
||||||
return this._getUnspentValue();
|
return this._getUnspentValue();
|
||||||
}
|
}
|
||||||
return _.isUndefined(this._fee) ? this._estimateFee() : this._fee;
|
return this._estimateFee();
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -364,6 +364,16 @@ describe('Transaction', function() {
|
|||||||
return transaction.serialize();
|
return transaction.serialize();
|
||||||
}).to.not.throw(errors.Transaction.DustOutputs);
|
}).to.not.throw(errors.Transaction.DustOutputs);
|
||||||
});
|
});
|
||||||
|
it('fails when outputs and fee don\'t add to total input', function() {
|
||||||
|
var transaction = new Transaction()
|
||||||
|
.from(simpleUtxoWith1BTC)
|
||||||
|
.to(toAddress, 99900000)
|
||||||
|
.fee(99999)
|
||||||
|
.sign(privateKey);
|
||||||
|
expect(function() {
|
||||||
|
return transaction.serialize();
|
||||||
|
}).to.throw(errors.Transaction.FeeError);
|
||||||
|
});
|
||||||
describe('skipping checks', function() {
|
describe('skipping checks', function() {
|
||||||
var buildSkipTest = function(builder, check) {
|
var buildSkipTest = function(builder, check) {
|
||||||
return function() {
|
return function() {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user