|
|
@ -21,7 +21,6 @@ var MultiSigScriptHashInput = Input.MultiSigScriptHash; |
|
|
|
var Output = require('./output'); |
|
|
|
var Script = require('../script'); |
|
|
|
var PrivateKey = require('../privatekey'); |
|
|
|
var Block = require('../block'); |
|
|
|
var BN = require('../crypto/bn'); |
|
|
|
|
|
|
|
/** |
|
|
@ -60,6 +59,7 @@ function Transaction(serialized) { |
|
|
|
|
|
|
|
var CURRENT_VERSION = 1; |
|
|
|
var DEFAULT_NLOCKTIME = 0; |
|
|
|
var MAX_BLOCK_SIZE = 1000000; |
|
|
|
|
|
|
|
// Minimum amount for an output for it not to be considered a dust output
|
|
|
|
Transaction.DUST_AMOUNT = 546; |
|
|
@ -167,12 +167,22 @@ Transaction.prototype.checkedSerialize = function(opts) { |
|
|
|
var serializationError = this.getSerializationError(opts); |
|
|
|
if (serializationError) { |
|
|
|
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; |
|
|
|
} |
|
|
|
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 |
|
|
|
* |
|
|
@ -181,11 +191,15 @@ Transaction.prototype.checkedSerialize = function(opts) { |
|
|
|
*/ |
|
|
|
Transaction.prototype.getSerializationError = function(opts) { |
|
|
|
opts = opts || {}; |
|
|
|
|
|
|
|
if (this.invalidSatoshis()) { |
|
|
|
return new errors.Transaction.InvalidSatoshis(); |
|
|
|
} |
|
|
|
|
|
|
|
var missingChange = this._missingChange(); |
|
|
|
var feeIsTooLarge = this._isFeeTooLarge(); |
|
|
|
var feeIsTooSmall = this._isFeeTooSmall(); |
|
|
|
var isFullySigned = this.isFullySigned(); |
|
|
|
var hasDustOutputs = this._hasDustOutputs(); |
|
|
|
|
|
|
|
if (!opts.disableLargeFees && feeIsTooLarge) { |
|
|
|
if (missingChange) { |
|
|
@ -644,7 +658,7 @@ Transaction.prototype.getChangeOutput = function() { |
|
|
|
*/ |
|
|
|
Transaction.prototype.to = function(address, amount) { |
|
|
|
$.checkArgument( |
|
|
|
JSUtil.isPositiveInteger(amount), |
|
|
|
JSUtil.isNaturalNumber(amount), |
|
|
|
'Amount is expected to be a positive integer' |
|
|
|
); |
|
|
|
this.addOutput(new Output({ |
|
|
@ -981,28 +995,28 @@ Transaction.prototype.verify = function() { |
|
|
|
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
|
|
|
|
var valueoutbn = new BN(0); |
|
|
|
for (var i = 0; i < this.outputs.length; i++) { |
|
|
|
var txout = this.outputs[i]; |
|
|
|
var valuebn = txout._satoshisBN; |
|
|
|
if (valuebn.lt(BN.Zero)) { |
|
|
|
return 'transaction txout ' + i + ' negative'; |
|
|
|
|
|
|
|
if (txout.invalidSatoshis()) { |
|
|
|
return 'transaction txout ' + i + ' satoshis is invalid'; |
|
|
|
} |
|
|
|
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'; |
|
|
|
} |
|
|
|
valueoutbn = valueoutbn.add(valuebn); |
|
|
|
valueoutbn = valueoutbn.add(txout._satoshisBN); |
|
|
|
if (valueoutbn.gt(new BN(Transaction.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
|
|
|
|
var txinmap = {}; |
|
|
|
for (i = 0; i < this.inputs.length; i++) { |
|
|
|