Merge pull request #1271 from isocolsky/fix/fee_estimation

Fix/fee estimation
This commit is contained in:
Matias Alejo Garcia 2015-06-11 15:35:31 -03:00
commit a4ac3f50d3
2 changed files with 40 additions and 7 deletions

View File

@ -205,7 +205,7 @@ Transaction.prototype.getSerializationError = function(opts) {
unspentError = this._hasFeeError(opts, unspent);
}
return unspentError ||
return unspentError ||
this._hasDustOutputs(opts) ||
this._isMissingSignatures(opts);
};
@ -394,7 +394,7 @@ Transaction.prototype._checkConsistency = function() {
$.checkState(this._changeScript);
$.checkState(this.outputs[this._changeIndex]);
$.checkState(this.outputs[this._changeIndex].script.toString() ===
this._changeScript.toString());
this._changeScript.toString());
}
// TODO: add other checks
};
@ -634,6 +634,21 @@ Transaction.prototype.fee = function(amount) {
return this;
};
/**
* Manually set the fee per KB for this transaction. Beware that this resets all the signatures
* for inputs (in further versions, SIGHASH_SINGLE or SIGHASH_NONE signatures will not
* be reset).
*
* @param {number} amount satoshis per KB to be sent
* @return {Transaction} this, for chaining
*/
Transaction.prototype.feePerKb = function(amount) {
$.checkArgument(_.isNumber(amount), 'amount must be a number');
this._feePerKb = amount;
this._updateChangeOutput();
return this;
};
/* Output management */
/**
@ -831,7 +846,7 @@ Transaction.prototype.getFee = function() {
Transaction.prototype._estimateFee = function() {
var estimatedSize = this._estimateSize();
var available = this._getUnspentValue();
return Transaction._estimateFee(estimatedSize, available);
return Transaction._estimateFee(estimatedSize, available, this._feePerKb);
};
Transaction.prototype._getUnspentValue = function() {
@ -844,12 +859,12 @@ Transaction.prototype._clearSignatures = function() {
});
};
Transaction._estimateFee = function(size, amountAvailable) {
var fee = Math.ceil(size / Transaction.FEE_PER_KB);
Transaction._estimateFee = function(size, amountAvailable, feePerKb) {
var fee = Math.ceil(size / 1000) * (feePerKb || Transaction.FEE_PER_KB);
if (amountAvailable > fee) {
size += Transaction.CHANGE_OUTPUT_MAX_SIZE;
}
return Math.ceil(size / 1000) * Transaction.FEE_PER_KB;
return Math.ceil(size / 1000) * (feePerKb || Transaction.FEE_PER_KB);
};
Transaction.prototype._estimateSize = function() {

View File

@ -257,6 +257,22 @@ describe('Transaction', function() {
transaction.outputs.length.should.equal(2);
transaction.outputs[1].satoshis.should.equal(10000);
});
it('fee per kb can be set up manually', function() {
var inputs = _.map(_.range(10), function(i) {
var utxo = _.clone(simpleUtxoWith100000Satoshis);
utxo.outputIndex = i;
return utxo;
});
var transaction = new Transaction()
.from(inputs)
.to(toAddress, 950000)
.feePerKb(8000)
.change(changeAddress)
.sign(privateKey);
transaction._estimateSize().should.be.within(1000, 1999);
transaction.outputs.length.should.equal(2);
transaction.outputs[1].satoshis.should.equal(34000);
});
it('if satoshis are invalid', function() {
var transaction = new Transaction()
.from(simpleUtxoWith100000Satoshis)
@ -406,7 +422,9 @@ describe('Transaction', function() {
.fee(10000000);
expect(function() {
return transaction.serialize({disableMoreOutputThanInput: true});
return transaction.serialize({
disableMoreOutputThanInput: true
});
}).to.throw(errors.Transaction.FeeError.TooLarge);
});
describe('skipping checks', function() {