tx: add bip69 sorting.

This commit is contained in:
Christopher Jeffrey 2016-02-02 17:37:50 -08:00
parent 2deccde29e
commit 13d14b0130
2 changed files with 44 additions and 2 deletions

View File

@ -1166,6 +1166,40 @@ TX.prototype.fill = function fill(unspent, address, fee) {
return result;
};
// https://github.com/bitcoin/bips/blob/master/bip-0069.mediawiki
TX.prototype.sortMembers = function sortMembers() {
var changeOutput;
if (this.changeIndex !== -1) {
changeOutput = this.outputs[this.changeIndex];
assert(changeOutput);
}
this.inputs = this.inputs.slice().sort(function(a, b) {
var res = new bn(a.prevout.hash, 'hex').cmp(new bn(b.prevout.hash, 'hex'));
if (res !== 0)
return res;
return a.prevout.index - b.prevout.index;
});
this.outputs = this.outputs.slice().sort(function(a, b) {
var res = a.value.cmp(b.value);
if (res !== 0)
return res;
a = bcoin.script.encode(a.script);
b = bcoin.script.encode(b.script);
return new bn(a).cmp(b);
});
if (this.changeIndex !== -1) {
this.changeIndex = this.outputs.indexOf(changeOutput);
assert(this.changeIndex !== -1);
}
};
// Legacy
TX.prototype.fillUnspent = TX.prototype.fill;
TX.prototype.fillInputs = TX.prototype.fill;
@ -1258,7 +1292,7 @@ TX.prototype.getFunds = function getFunds(side) {
// Legacy
TX.prototype.funds = TX.prototype.getFunds;
TX.prototype.getTargetTime = function getTargetTime() {
TX.prototype.getTargetLocktime = function getTargetLocktime() {
var bestValue = 0;
var i, locktime, bestType;

View File

@ -392,27 +392,35 @@ Wallet.prototype.createTX = function createTX(outputs, fee) {
if (!Array.isArray(outputs))
outputs = [outputs];
// Add the outputs
outputs.forEach(function(output) {
tx.addOutput(output);
});
// Fill the inputs with unspents
if (!this.fill(tx, null, fee))
return;
// Sort members a la BIP69
tx.sortMembers();
// Find the necessary locktime if there is
// a checklocktimeverify script in the unspents.
target = tx.getTargetTime();
target = tx.getTargetLocktime();
// No target value. The unspents have an
// incompatible locktime type.
if (!target)
return;
// Set the locktime to target value or
// `height - whatever` to avoid fee snipping.
if (target.value > 0)
tx.setLocktime(target.value);
else
tx.avoidFeeSnipping();
// Sign the inputs
this.sign(tx);
return tx;