From c4818c4bc8a34e44ce856c92d217b6c981606c95 Mon Sep 17 00:00:00 2001 From: Christopher Jeffrey Date: Fri, 12 Feb 2016 02:44:11 -0800 Subject: [PATCH] add subtract fee option. --- lib/bcoin/tx.js | 78 +++++++++++++++++++++++++++++-------------------- 1 file changed, 46 insertions(+), 32 deletions(-) diff --git a/lib/bcoin/tx.js b/lib/bcoin/tx.js index f415d56a..08a666dc 100644 --- a/lib/bcoin/tx.js +++ b/lib/bcoin/tx.js @@ -1014,22 +1014,31 @@ TX.prototype.maxSize = function maxSize() { }; TX.prototype.getInputs = function getInputs(unspent, address, fee) { + var self = this; var tx = this.clone(); - var cost = tx.getOutputValue(); + var outputValue = tx.getOutputValue(); var totalkb = 1; - var total = cost.addn(constants.tx.minFee); var inputs = []; var lastAdded = 0; - var size, newkb, change; - - if (fee) - total = cost.add(fee); + var minFee = constants.tx.minFee; + var dustThreshold = constants.tx.dustThreshold; + var i, size, newkb, change; // Oldest unspents first unspent = unspent.slice().sort(function(a, b) { return a.height - b.height; }); + function total() { + if (self.subtractFee) + return outputValue; + return outputValue.add(fee); + } + + function isFull() { + return tx.getInputValue().cmp(total()) >= 0; + } + function addCoins() { var i, index; @@ -1042,15 +1051,20 @@ TX.prototype.getInputs = function getInputs(unspent, address, fee) { lastAdded++; // Stop once we're full. - if (tx.getInputValue().cmp(total) >= 0) + if (isFull()) break; } } - // Transfer `total` funds maximum. - addCoins(); + if (fee) { + // Transfer `total` funds maximum. + addCoins(); + } else { + fee = new bn(minFee); + + // Transfer `total` funds maximum. + addCoins(); - if (!fee) { // Add dummy output (for `change`) to // calculate maximum TX size. tx.addOutput({ @@ -1058,17 +1072,6 @@ TX.prototype.getInputs = function getInputs(unspent, address, fee) { value: new bn(0) }); - // if (this.subtractFee) { - // var f = new bn((Math.ceil(tx.maxSize() / 1024) - 1) * constants.tx.minFee); - // for (var j = 0; j < this.outputs.length; j++) { - // if (this.outputs[j].value.cmp(f.addn(constants.tx.dustThreshold)) >= 0) { - // this.outputs[j].value = this.outputs[j].value.sub(f); - // break; - // } - // } - // total = tx.getInputValue(); - // } - // Change fee value if it is more than 1024 // bytes (10000 satoshi for every 1024 bytes). do { @@ -1076,30 +1079,42 @@ TX.prototype.getInputs = function getInputs(unspent, address, fee) { size = tx.maxSize(); newkb = Math.ceil(size / 1024) - totalkb; - total.iaddn(newkb * constants.tx.minFee); + fee.iaddn(newkb * minFee); totalkb += newkb; // Failed to get enough funds, add more inputs. - if (tx.getInputValue().cmp(total) < 0) + if (!isFull()) addCoins(); - } while (tx.getInputValue().cmp(total) < 0 && lastAdded < unspent.length); + } while (!isFull() && lastAdded < unspent.length); } - if (tx.getInputValue().cmp(total) < 0) { + if (!isFull()) { // Still failing to get enough funds. inputs = null; } else { // How much money is left after filling outputs. - change = tx.getInputValue().sub(total); + change = tx.getInputValue().sub(total()); + + // Attempt to subtract fee. + if (this.subtractFee) { + for (i = 0; i < tx.outputs.length; i++) { + if (tx.outputs[i].value.cmp(fee.addn(dustThreshold)) >= 0) { + tx.outputs[i].value.isub(fee); + break; + } + } + // Could not subtract fee + if (i === tx.outputs.length) + inputs = null; + } } // Return necessary inputs and change. return { inputs: inputs, change: change, - cost: cost, - fee: total.sub(cost), - total: total, + fee: fee, + total: total(), kb: totalkb, unspent: unspent.slice(0, lastAdded) }; @@ -1144,6 +1159,8 @@ TX.prototype.fill = function fill(unspent, address, fee) { }); this.changeIndex = this.outputs.length - 1; + + assert.equal(this.getFee().toNumber(), result.fee.toNumber()); } return result; @@ -1209,9 +1226,6 @@ TX.prototype._recalculateFee = function recalculateFee() { real = Math.ceil(size / 1024) * constants.tx.minFee; fee = this.getFee().toNumber(); - // if (this.hardFee) - // real = this.hardFee; - if (real === fee) { if (this.changeIndex === -1) this.outputs.pop();