From c94457cf1f9e4500e8c1ec92d9913ba229e64735 Mon Sep 17 00:00:00 2001 From: Christopher Jeffrey Date: Tue, 12 Jan 2016 05:15:22 -0800 Subject: [PATCH] more tx refactoring. --- lib/bcoin/tx.js | 103 ++++++++++++++++++++++++-------------------- lib/bcoin/wallet.js | 17 +++----- 2 files changed, 63 insertions(+), 57 deletions(-) diff --git a/lib/bcoin/tx.js b/lib/bcoin/tx.js index e616219d..aa3b118e 100644 --- a/lib/bcoin/tx.js +++ b/lib/bcoin/tx.js @@ -41,10 +41,6 @@ function TX(data, block) { this._lock = this.lock; - this._fee = !(data instanceof bcoin.tx) - ? data.fee - : data._fee; - if (data.inputs) { data.inputs.forEach(function(input) { this.input(input, null); @@ -64,8 +60,9 @@ function TX(data, block) { } } + this.hardFee = data.hardFee || null; this.changeAddress = data.changeAddress || null; - this.changeOutput = data.changeOutput || null; + this.changeIndex = data.changeIndex || -1; // ps = Pending Since this.ps = this.ts === 0 ? utils.now() : 0; @@ -785,7 +782,7 @@ TX.prototype.maxSize = function maxSize() { return total; }; -TX.prototype.getUnspent = function getUnspent(unspent, fee) { +TX.prototype.getUnspent = function getUnspent(unspent, address, fee) { var tx = this.clone(); var cost = tx.funds('out'); var totalkb = 1; @@ -794,12 +791,9 @@ TX.prototype.getUnspent = function getUnspent(unspent, fee) { var lastAdded = 0; var size, newkb, change; - if (!fee) - fee = this._fee; - if (fee) { total = cost.add(fee); - this._fee = fee; + this.hardFee = fee; } function addInput(unspent) { @@ -819,7 +813,7 @@ TX.prototype.getUnspent = function getUnspent(unspent, fee) { // Add dummy output (for `change`) to // calculate maximum TX size. tx.output({ - script: [], + address: address, value: new bn(0) }); @@ -839,15 +833,13 @@ TX.prototype.getUnspent = function getUnspent(unspent, fee) { } while (tx.funds('in').cmp(total) < 0 && lastAdded < unspent.length); } - // Expose `total`. Useful for error messages. - this.total = total; - - // Still failing to get enough funds. - if (tx.funds('in').cmp(total) < 0) - return; - - // How much money is left after filling outputs. - change = tx.funds('in').sub(total); + if (tx.funds('in').cmp(total) < 0) { + // Still failing to get enough funds. + inputs = null; + } else { + // How much money is left after filling outputs. + change = tx.funds('in').sub(total); + } // Return necessary inputs and change. return { @@ -855,22 +847,26 @@ TX.prototype.getUnspent = function getUnspent(unspent, fee) { change: change, cost: cost, fee: total.sub(cost), - total: total + total: total, + kb: totalkb }; }; -TX.prototype.fillUnspent = function fillUnspent(unspent, changeAddress, fee) { - var result = this.getUnspent(unspent, fee); +TX.prototype.fillUnspent = function fillUnspent(unspent, address, fee) { + var result; + + if (address) + this.changeAddress = address; if (fee) - this._fee = fee; + this.hardFee = fee; - if (!result) - return; + assert(this.changeAddress); - this.changeAddress = changeAddress - || this.changeAddress - || result.inputs[0].output.address; + result = this.getUnspent(unspent, this.changeAddress, this.hardFee); + + if (!result.inputs) + return result; result.inputs.forEach(function(input) { this.input(input); @@ -882,27 +878,24 @@ TX.prototype.fillUnspent = function fillUnspent(unspent, changeAddress, fee) { this.getFee().toNumber(), result.fee.add(result.change).toNumber() ); - this.changeOutput = null; + this.changeIndex = -1; } else { - if (!this.changeAddress) - throw new Error('No change address'); - this.output({ address: this.changeAddress, value: result.change }); - this.changeOutput = this.outputs[this.outputs.length - 1]; + this.changeIndex = this.outputs.length - 1; } return result; }; TX.prototype._recalculateFee = function recalculateFee() { - var output = this.changeOutput; + var output = this.outputs[this.changeIndex]; var size, real, fee; - if (this._fee) + if (this.hardFee) return; if (!output) { @@ -918,7 +911,7 @@ TX.prototype._recalculateFee = function recalculateFee() { fee = this.getFee().toNumber(); if (real === fee) { - if (!this.changeOutput) + if (this.changeIndex === -1) this.outputs.pop(); return; } @@ -926,7 +919,7 @@ TX.prototype._recalculateFee = function recalculateFee() { if (real > fee) { if (output.value.cmpn(real - fee) < 0) { this.outputs.pop(); - this.changeOutput = null; + this.changeIndex = -1; return; } output.value.isubn(real - fee); @@ -936,11 +929,11 @@ TX.prototype._recalculateFee = function recalculateFee() { if (output.value.cmpn(constants.tx.dust) < 0) { this.outputs.pop(); - this.changeOutput = null; + this.changeIndex = -1; return; } - this.changeOutput = output; + this.changeIndex = this.outputs.indexOf(output); }; TX.prototype.getFee = function getFee() { @@ -1247,7 +1240,9 @@ TX.prototype.toJSON = function toJSON() { block: this.block, network: this.network, relayedBy: this.relayedBy, - changeIndex: this.outputs.indexOf(this.changeOutput), + changeAddress: this.changeAddress, + changeIndex: this.changeIndex, + hardFee: this.hardFee ? utils.btc(this.hardFee) : null, tx: utils.toHex(this.render()) }; }; @@ -1264,6 +1259,12 @@ TX.fromJSON = function fromJSON(json) { data.network = json.network; data.relayedBy = json.relayedBy; + data.changeAddress = json.changeAddress; + data.changeIndex = json.changeIndex; + + if (json.hardFee) + data.hardFee = utils.satoshi(json.hardFee); + data._raw = raw; data._size = raw.length; @@ -1272,14 +1273,24 @@ TX.fromJSON = function fromJSON(json) { tx.block = json.block || null; tx.ps = json.ps; - if (data.changeIndex >= 0) { - tx.changeOutput = tx.outputs[data.changeIndex]; - assert(tx.changeOutput); - } - return tx; }; +TX.prototype.toRaw = function toRaw(enc) { + var raw = this.render(); + + if (enc === 'hex') + return utils.toHex(raw); + + return raw; +}; + +TX.fromRaw = function fromRaw(raw, enc) { + if (enc === 'hex') + raw = utils.toArray(raw, 'hex'); + return new bcoin.protocol.parser().parseTX(raw); +}; + /** * Expose */ diff --git a/lib/bcoin/wallet.js b/lib/bcoin/wallet.js index 6e090c3d..e350f681 100644 --- a/lib/bcoin/wallet.js +++ b/lib/bcoin/wallet.js @@ -436,16 +436,11 @@ Wallet.prototype.ownInput = function ownInput(tx, index) { return inputs; }; -Wallet.prototype.scriptOutputs = function scriptOutputs(tx, options) { - outputs.forEach(function(output) { - tx.scriptOutput(output, output); - }); - return outputs.length; -}; +Wallet.prototype.fillUnspent = function fillUnspent(tx, address, fee) { + if (!address) + address = this.changeAddress || this.getAddress(); -Wallet.prototype.fillUnspent = function fillUnspent(tx, changeAddress) { - changeAddress = changeAddress || this.changeAddress || this.getAddress(); - return tx.fillUnspent(this.unspent(), changeAddress); + return tx.fillUnspent(this.unspent(), address, fee); }; Wallet.prototype.fillTX = function fillTX(tx) { @@ -546,9 +541,9 @@ Wallet.prototype.fill = function fill(tx, changeAddress, cb) { result = this.fillUnspent(tx, changeAddress); - if (!result) { + if (!result.inputs) { err = new Error('Not enough funds'); - err.minBalance = tx.total; + err.minBalance = result.total; cb(err); return null; }