|
|
@ -182,7 +182,8 @@ Transaction.prototype.invalidSatoshis = function() { |
|
|
|
}; |
|
|
|
|
|
|
|
/** |
|
|
|
* 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. |
|
|
|
* |
|
|
|
* @param {Object} opts allows to skip certain tests. {@see Transaction#serialize} |
|
|
|
* @return {bitcore.Error} |
|
|
@ -190,38 +191,23 @@ Transaction.prototype.invalidSatoshis = function() { |
|
|
|
Transaction.prototype.getSerializationError = function(opts) { |
|
|
|
opts = opts || {}; |
|
|
|
|
|
|
|
return this._isInvalidSatoshis() || |
|
|
|
this._hasFeeError(opts) || |
|
|
|
this._hasDustOutputs(opts) || |
|
|
|
this._isMissingSignatures(opts) || |
|
|
|
this._hasMoreOutputThanInput(opts); |
|
|
|
}; |
|
|
|
|
|
|
|
Transaction.prototype._isInvalidSatoshis = function() { |
|
|
|
if (this.invalidSatoshis()) { |
|
|
|
return new errors.Transaction.InvalidSatoshis(); |
|
|
|
} |
|
|
|
}; |
|
|
|
|
|
|
|
var feeIsDifferent = this._isFeeDifferent(); |
|
|
|
if (feeIsDifferent) { |
|
|
|
return new errors.Transaction.FeeError.Different(feeIsDifferent); |
|
|
|
} |
|
|
|
|
|
|
|
var missingChange = this._missingChange(); |
|
|
|
var feeIsTooLarge = this._isFeeTooLarge(); |
|
|
|
var feeIsTooSmall = this._isFeeTooSmall(); |
|
|
|
var isFullySigned = this.isFullySigned(); |
|
|
|
|
|
|
|
if (!opts.disableLargeFees && feeIsTooLarge) { |
|
|
|
if (missingChange) { |
|
|
|
return new errors.Transaction.ChangeAddressMissing('Fee is too large and no change address was provided'); |
|
|
|
} |
|
|
|
return new errors.Transaction.FeeError.TooLarge(feeIsTooLarge); |
|
|
|
} |
|
|
|
if (!opts.disableSmallFees && feeIsTooSmall) { |
|
|
|
return new errors.Transaction.FeeError.TooSmall(feeIsTooSmall); |
|
|
|
} |
|
|
|
if (!opts.disableDustOutputs && this._hasDustOutputs()) { |
|
|
|
return new errors.Transaction.DustOutputs(); |
|
|
|
} |
|
|
|
if (!opts.disableIsFullySigned && !isFullySigned) { |
|
|
|
return new errors.Transaction.MissingSignatures(); |
|
|
|
} |
|
|
|
if (!opts.disableMoreOutputThanInput && this._getUnspentValue() < 0) { |
|
|
|
return new errors.Transaction.InvalidOutputAmountSum(); |
|
|
|
} |
|
|
|
Transaction.prototype._hasFeeError = function(opts) { |
|
|
|
return this._isFeeDifferent() || |
|
|
|
this._isFeeTooLarge(opts) || |
|
|
|
this._isFeeTooSmall(opts); |
|
|
|
}; |
|
|
|
|
|
|
|
Transaction.prototype._isFeeDifferent = function() { |
|
|
@ -229,24 +215,33 @@ Transaction.prototype._isFeeDifferent = function() { |
|
|
|
var fee = this._fee; |
|
|
|
var unspent = this._getUnspentValue(); |
|
|
|
if (fee !== unspent) { |
|
|
|
return 'Unspent value is ' + unspent + ' but specified fee is ' + fee; |
|
|
|
return new errors.Transaction.FeeError.Different('Unspent value is ' + unspent + ' but specified fee is ' + fee); |
|
|
|
} |
|
|
|
} |
|
|
|
}; |
|
|
|
|
|
|
|
Transaction.prototype._isFeeTooLarge = function() { |
|
|
|
Transaction.prototype._isFeeTooLarge = function(opts) { |
|
|
|
if (opts.disableLargeFees) { |
|
|
|
return; |
|
|
|
} |
|
|
|
var fee = this._getUnspentValue(); |
|
|
|
var maximumFee = Math.floor(Transaction.FEE_SECURITY_MARGIN * this._estimateFee()); |
|
|
|
if (fee > maximumFee) { |
|
|
|
return 'expected less than ' + maximumFee + ' but got ' + fee; |
|
|
|
if (this._missingChange()) { |
|
|
|
return new errors.Transaction.ChangeAddressMissing('Fee is too large and no change address was provided'); |
|
|
|
} |
|
|
|
return new errors.Transaction.FeeError.TooLarge('expected less than ' + maximumFee + ' but got ' + fee); |
|
|
|
} |
|
|
|
}; |
|
|
|
|
|
|
|
Transaction.prototype._isFeeTooSmall = function() { |
|
|
|
Transaction.prototype._isFeeTooSmall = function(opts) { |
|
|
|
if (opts.disableSmallFees) { |
|
|
|
return; |
|
|
|
} |
|
|
|
var fee = this._getUnspentValue(); |
|
|
|
var minimumFee = Math.ceil(this._estimateFee() / Transaction.FEE_SECURITY_MARGIN); |
|
|
|
if (fee < minimumFee) { |
|
|
|
return 'expected more than ' + minimumFee + ' but got ' + fee; |
|
|
|
return new errors.Transaction.FeeError.TooSmall('expected more than ' + minimumFee + ' but got ' + fee); |
|
|
|
} |
|
|
|
}; |
|
|
|
|
|
|
@ -254,15 +249,35 @@ Transaction.prototype._missingChange = function() { |
|
|
|
return !this._changeScript; |
|
|
|
}; |
|
|
|
|
|
|
|
Transaction.prototype._hasDustOutputs = function() { |
|
|
|
Transaction.prototype._hasDustOutputs = function(opts) { |
|
|
|
if (opts.disableDustOutputs) { |
|
|
|
return; |
|
|
|
} |
|
|
|
var index, output; |
|
|
|
for (index in this.outputs) { |
|
|
|
output = this.outputs[index]; |
|
|
|
if (output.satoshis < Transaction.DUST_AMOUNT && !output.script.isDataOut()) { |
|
|
|
return true; |
|
|
|
return new errors.Transaction.DustOutputs(); |
|
|
|
} |
|
|
|
} |
|
|
|
return false; |
|
|
|
}; |
|
|
|
|
|
|
|
Transaction.prototype._isMissingSignatures = function(opts) { |
|
|
|
if (opts.disableIsFullySigned) { |
|
|
|
return; |
|
|
|
} |
|
|
|
if (!this.isFullySigned()) { |
|
|
|
return new errors.Transaction.MissingSignatures(); |
|
|
|
} |
|
|
|
}; |
|
|
|
|
|
|
|
Transaction.prototype._hasMoreOutputThanInput = function(opts) { |
|
|
|
if (opts.disableMoreOutputThanInput) { |
|
|
|
return; |
|
|
|
} |
|
|
|
if (this._getUnspentValue() < 0) { |
|
|
|
return new errors.Transaction.InvalidOutputAmountSum(); |
|
|
|
} |
|
|
|
}; |
|
|
|
|
|
|
|
Transaction.prototype.inspect = function() { |
|
|
|