Merge pull request #1271 from isocolsky/fix/fee_estimation
Fix/fee estimation
This commit is contained in:
commit
a4ac3f50d3
@ -205,7 +205,7 @@ Transaction.prototype.getSerializationError = function(opts) {
|
|||||||
unspentError = this._hasFeeError(opts, unspent);
|
unspentError = this._hasFeeError(opts, unspent);
|
||||||
}
|
}
|
||||||
|
|
||||||
return unspentError ||
|
return unspentError ||
|
||||||
this._hasDustOutputs(opts) ||
|
this._hasDustOutputs(opts) ||
|
||||||
this._isMissingSignatures(opts);
|
this._isMissingSignatures(opts);
|
||||||
};
|
};
|
||||||
@ -394,7 +394,7 @@ Transaction.prototype._checkConsistency = function() {
|
|||||||
$.checkState(this._changeScript);
|
$.checkState(this._changeScript);
|
||||||
$.checkState(this.outputs[this._changeIndex]);
|
$.checkState(this.outputs[this._changeIndex]);
|
||||||
$.checkState(this.outputs[this._changeIndex].script.toString() ===
|
$.checkState(this.outputs[this._changeIndex].script.toString() ===
|
||||||
this._changeScript.toString());
|
this._changeScript.toString());
|
||||||
}
|
}
|
||||||
// TODO: add other checks
|
// TODO: add other checks
|
||||||
};
|
};
|
||||||
@ -634,6 +634,21 @@ Transaction.prototype.fee = function(amount) {
|
|||||||
return this;
|
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 */
|
/* Output management */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -831,7 +846,7 @@ Transaction.prototype.getFee = function() {
|
|||||||
Transaction.prototype._estimateFee = function() {
|
Transaction.prototype._estimateFee = function() {
|
||||||
var estimatedSize = this._estimateSize();
|
var estimatedSize = this._estimateSize();
|
||||||
var available = this._getUnspentValue();
|
var available = this._getUnspentValue();
|
||||||
return Transaction._estimateFee(estimatedSize, available);
|
return Transaction._estimateFee(estimatedSize, available, this._feePerKb);
|
||||||
};
|
};
|
||||||
|
|
||||||
Transaction.prototype._getUnspentValue = function() {
|
Transaction.prototype._getUnspentValue = function() {
|
||||||
@ -844,12 +859,12 @@ Transaction.prototype._clearSignatures = function() {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
Transaction._estimateFee = function(size, amountAvailable) {
|
Transaction._estimateFee = function(size, amountAvailable, feePerKb) {
|
||||||
var fee = Math.ceil(size / Transaction.FEE_PER_KB);
|
var fee = Math.ceil(size / 1000) * (feePerKb || Transaction.FEE_PER_KB);
|
||||||
if (amountAvailable > fee) {
|
if (amountAvailable > fee) {
|
||||||
size += Transaction.CHANGE_OUTPUT_MAX_SIZE;
|
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() {
|
Transaction.prototype._estimateSize = function() {
|
||||||
|
|||||||
@ -257,6 +257,22 @@ 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('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() {
|
it('if satoshis are invalid', function() {
|
||||||
var transaction = new Transaction()
|
var transaction = new Transaction()
|
||||||
.from(simpleUtxoWith100000Satoshis)
|
.from(simpleUtxoWith100000Satoshis)
|
||||||
@ -406,7 +422,9 @@ describe('Transaction', function() {
|
|||||||
.fee(10000000);
|
.fee(10000000);
|
||||||
|
|
||||||
expect(function() {
|
expect(function() {
|
||||||
return transaction.serialize({disableMoreOutputThanInput: true});
|
return transaction.serialize({
|
||||||
|
disableMoreOutputThanInput: true
|
||||||
|
});
|
||||||
}).to.throw(errors.Transaction.FeeError.TooLarge);
|
}).to.throw(errors.Transaction.FeeError.TooLarge);
|
||||||
});
|
});
|
||||||
describe('skipping checks', function() {
|
describe('skipping checks', function() {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user