refactor tx.utxos().

This commit is contained in:
Christopher Jeffrey 2015-12-23 18:27:57 -08:00
parent 389ee296b0
commit b14c4daee0

View File

@ -655,73 +655,69 @@ TX.prototype.maxSize = function maxSize() {
return size; return size;
}; };
TX.prototype.utxos = function utxos(unspent) { TX.prototype.getUnspent = function getUnspent(unspent) {
var tx = this.clone();
// NOTE: tx should be prefilled with all outputs // NOTE: tx should be prefilled with all outputs
var cost = this.funds('out'); var cost = tx.funds('out');
// Use initial fee for starters // Use initial fee for starters
var fee = 1; var fee = 1;
// total = cost + fee // total = cost + fee
var total = cost.add(new bn(TX.fee)); var total = cost.addn(TX.fee);
var inputs = this.inputs.slice(); var inputs = [];
var utxos = [];
var lastAdded = 0; var lastAdded = 0;
var byteSize, addFee, change; var byteSize, addFee, change;
function addInput(unspent, i) { function addInput(unspent) {
// Add new inputs until TX will have enough funds to cover both // Add new inputs until TX will have enough funds to cover both
// minimum post cost and fee // minimum post cost and fee
var index = this._input(unspent); var index = tx._input(unspent);
utxos.push(this.inputs[index]); inputs.push(tx.inputs[index]);
lastAdded++; lastAdded++;
return this.funds('in').cmp(total) < 0; return tx.funds('in').cmp(total) < 0;
} }
// Transfer `total` funds maximum // Transfer `total` funds maximum
// var unspent = wallet.unspent(); // var unspent = wallet.unspent();
unspent.every(addInput, this); unspent.every(addInput);
// Add dummy output (for `change`) to calculate maximum TX size // Add dummy output (for `change`) to calculate maximum TX size
this.output({ address: null, value: new bn(0) }); tx.output({ address: null, value: new bn(0) });
// Change fee value if it is more than 1024 bytes // Change fee value if it is more than 1024 bytes
// (10000 satoshi for every 1024 bytes) // (10000 satoshi for every 1024 bytes)
do { do {
// Calculate maximum possible size after signing // Calculate maximum possible size after signing
byteSize = this.maxSize(); byteSize = tx.maxSize();
addFee = Math.ceil(byteSize / 1024) - fee; addFee = Math.ceil(byteSize / 1024) - fee;
total.iadd(new bn(addFee * TX.fee)); total.iaddn(addFee * TX.fee);
fee += addFee; fee += addFee;
// Failed to get enough funds, add more inputs // Failed to get enough funds, add more inputs
if (this.funds('in').cmp(total) < 0) if (tx.funds('in').cmp(total) < 0)
unspent.slice(lastAdded).every(addInput, this); unspent.slice(lastAdded).every(addInput);
} while (this.funds('in').cmp(total) < 0 && lastAdded < unspent.length); } while (tx.funds('in').cmp(total) < 0 && lastAdded < unspent.length);
// Still failing to get enough funds // Still failing to get enough funds
if (this.funds('in').cmp(total) < 0) { if (tx.funds('in').cmp(total) < 0) {
this.inputs = inputs;
this.total = total; this.total = total;
this.outputs.pop();
return null; return null;
} }
// How much money is left after sending outputs // How much money is left after sending outputs
change = this.funds('in').sub(total); change = tx.funds('in').sub(total);
// Clear the tx of everything we added.
this.inputs = inputs;
this.total = total; this.total = total;
this.outputs.pop();
// Return necessary utxos and change. // Return necessary inputs and change.
return { return {
utxos: utxos, inputs: inputs,
change: change, change: change,
cost: cost, cost: cost,
fee: total.sub(cost), fee: total.sub(cost),
@ -730,22 +726,25 @@ TX.prototype.utxos = function utxos(unspent) {
}; };
TX.prototype.fillUnspent = function fillUnspent(unspent, changeAddress) { TX.prototype.fillUnspent = function fillUnspent(unspent, changeAddress) {
var result = unspent.utxos ? unspent : this.utxos(unspent); var result = unspent.cost ? unspent : this.getUnspent(unspent);
this.changeAddress = changeAddress
|| this.changeAddress
|| utxos[0].output.addr;
if (!result) if (!result)
return result; return result;
result.utxos.forEach(function(input) { this.changeAddress = changeAddress
|| this.changeAddress
|| result.inputs[0].output.addr;
result.inputs.forEach(function(input) {
this.input(input); this.input(input);
}, this); }, this);
if (result.change.cmpn(TX.dust) < 0) { if (result.change.cmpn(TX.dust) < 0) {
// Do nothing. Change is added to fee. // Do nothing. Change is added to fee.
assert(this.getFee().cmp(result.fee.add(result.change)) === 0); assert.equal(
this.getFee().toNumber(),
result.fee.add(result.change).toNumber()
);
this.changeOutput = null; this.changeOutput = null;
} else { } else {
if (!this.changeAddress) if (!this.changeAddress)