diff --git a/lib/bcoin/tx.js b/lib/bcoin/tx.js index 08a666dc..59791cde 100644 --- a/lib/bcoin/tx.js +++ b/lib/bcoin/tx.js @@ -74,11 +74,7 @@ function TX(data, block) { } } - this.hardFee = data.hardFee || null; - this.subtractFee = data.subtractFee || null; - this.changeAddress = data.changeAddress || null; this.changeIndex = data.changeIndex != null ? data.changeIndex : -1; - this.total = data.total || null; // ps = Pending Since this.ps = this.ts === 0 ? utils.now() : 0; @@ -919,7 +915,7 @@ TX.prototype.isCoinbase = function isCoinbase() { return this.inputs.length === 1 && +this.inputs[0].prevout.hash === 0; }; -TX.prototype.maxSize = function maxSize() { +TX.prototype.maxSize = function maxSize(maxM, maxN) { var copy = this.clone(); var i, j, input, total, size, s, m, n; @@ -959,7 +955,7 @@ TX.prototype.maxSize = function maxSize() { // OP_PUSHDATA0 [signature] size += 1 + 73; // OP_PUSHDATA0 [key] - size += 1 + 65; + size += 1 + 33; } else if (bcoin.script.isMultisig(s)) { // Bare Multisig // Get the previous m value: @@ -979,9 +975,9 @@ TX.prototype.maxSize = function maxSize() { // simply add more of the fee to the change // output. // m value - m = 15; + m = maxM || 15; // n value - n = 15; + n = maxN || 15; // OP_0 size += 1; // OP_PUSHDATA0 [signature] ... @@ -991,7 +987,7 @@ TX.prototype.maxSize = function maxSize() { // m value size += 1; // OP_PUSHDATA0 [key] ... - size += (1 + 65) * n; + size += (1 + 33) * n; // n value size += 1; // OP_CHECKMULTISIG @@ -1013,7 +1009,7 @@ TX.prototype.maxSize = function maxSize() { return total; }; -TX.prototype.getInputs = function getInputs(unspent, address, fee) { +TX.prototype.getInputs = function getInputs(unspent, options) { var self = this; var tx = this.clone(); var outputValue = tx.getOutputValue(); @@ -1023,6 +1019,14 @@ TX.prototype.getInputs = function getInputs(unspent, address, fee) { var minFee = constants.tx.minFee; var dustThreshold = constants.tx.dustThreshold; var i, size, newkb, change; + var fee; + + if (!options || typeof options !== 'object') { + options = { + changeAddress: arguments[1], + fee: arguments[2] + }; + } // Oldest unspents first unspent = unspent.slice().sort(function(a, b) { @@ -1030,7 +1034,7 @@ TX.prototype.getInputs = function getInputs(unspent, address, fee) { }); function total() { - if (self.subtractFee) + if (options.subtractFee) return outputValue; return outputValue.add(fee); } @@ -1047,16 +1051,21 @@ TX.prototype.getInputs = function getInputs(unspent, address, fee) { // funds to cover both minimum post cost // and fee. index = tx._addInput(unspent[i]); - inputs.push(tx.inputs[index]); + inputs.push(new bcoin.input(tx.inputs[index])); lastAdded++; + if (options.wallet) + options.wallet.scriptInputs(tx, index); + // Stop once we're full. if (isFull()) break; } } - if (fee) { + if (options.fee) { + fee = options.fee; + // Transfer `total` funds maximum. addCoins(); } else { @@ -1068,7 +1077,7 @@ TX.prototype.getInputs = function getInputs(unspent, address, fee) { // Add dummy output (for `change`) to // calculate maximum TX size. tx.addOutput({ - address: address, + address: options.changeAddress, value: new bn(0) }); @@ -1076,7 +1085,7 @@ TX.prototype.getInputs = function getInputs(unspent, address, fee) { // bytes (10000 satoshi for every 1024 bytes). do { // Calculate max possible size after signing. - size = tx.maxSize(); + size = tx.maxSize(options.m, options.n); newkb = Math.ceil(size / 1024) - totalkb; fee.iaddn(newkb * minFee); @@ -1096,7 +1105,7 @@ TX.prototype.getInputs = function getInputs(unspent, address, fee) { change = tx.getInputValue().sub(total()); // Attempt to subtract fee. - if (this.subtractFee) { + if (options.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); @@ -1120,27 +1129,29 @@ TX.prototype.getInputs = function getInputs(unspent, address, fee) { }; }; -TX.prototype.fill = function fill(unspent, address, fee) { +TX.prototype.fill = function fill(unspent, options) { var result; - if (!address) - address = this.changeAddress; - - if (!fee) - fee = this.hardFee; + if (!options || typeof options !== 'object') { + options = { + changeAddress: arguments[1], + fee: arguments[2] + }; + } assert(unspent); - assert(address); + assert(options.changeAddress); - result = this.getInputs(unspent, address, fee); + result = this.getInputs(unspent, options); - this.changeAddress = address; - this.hardFee = fee; this.total = result.total; if (!result.inputs) return result; + this._changeAddress = options.changeAddress; + this._fee = options.fee; + result.inputs.forEach(function(input) { this.addInput(input); }, this); @@ -1154,7 +1165,7 @@ TX.prototype.fill = function fill(unspent, address, fee) { this.changeIndex = -1; } else { this.addOutput({ - address: this.changeAddress, + address: options.changeAddress, value: result.change }); @@ -1211,12 +1222,15 @@ TX.prototype._recalculateFee = function recalculateFee() { var output = this.outputs[this.changeIndex]; var size, real, fee; - if (this.hardFee) + if (!this._changeAddress) + return; + + if (this._fee) return; if (!output) { this.addOutput({ - address: this.changeAddress, + address: this._changeAddress, value: new bn(0) }); output = this.outputs[this.outputs.length - 1]; @@ -1776,7 +1790,9 @@ TX.prototype.inspect = function inspect() { copy.block = this.block; delete copy._raw; delete copy._chain; - delete copy.unspent; + delete copy._changeAddress; + delete copy._fee; + delete copy.total; copy.hash = this.hash('hex'); copy.rhash = this.rhash; copy.rblock = this.rblock; @@ -1785,8 +1801,6 @@ TX.prototype.inspect = function inspect() { copy.confirmations = this.getConfirmations(); copy.priority = this.getPriority().toString(10); copy.date = new Date((copy.ts || 0) * 1000).toISOString(); - if (copy.hardFee) - copy.hardFee = utils.btc(copy.hardFee); return copy; }; @@ -1801,9 +1815,7 @@ TX.prototype.toJSON = function toJSON() { height: this.height, network: this.network, relayedBy: this.relayedBy, - changeAddress: this.changeAddress, changeIndex: this.changeIndex, - hardFee: this.hardFee ? utils.btc(this.hardFee) : null, coins: this.inputs.map(function(input) { return input.output ? input.output.toJSON() : null; }), @@ -1823,12 +1835,8 @@ 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; diff --git a/lib/bcoin/wallet.js b/lib/bcoin/wallet.js index a9a0c174..e03a5085 100644 --- a/lib/bcoin/wallet.js +++ b/lib/bcoin/wallet.js @@ -501,18 +501,20 @@ Wallet.prototype.ownOutput = function ownOutput(tx, index) { }; Wallet.prototype.fill = function fill(tx, options) { - var address, unspent; + var unspent, result; if (!options) options = {}; assert(this._initialized); - address = this.changeAddress.getAddress(); - unspent = this.getUnspent(); - result = tx.fill(unspent, address, options.fee); + result = tx.fill(unspent, utils.merge(options || {}, { + changeAddress: this.changeAddress.getAddress(), + m: this.m, + n: this.n + })); if (!result.inputs) return false; @@ -531,7 +533,7 @@ Wallet.prototype.fillPrevout = function fillPrevout(tx) { // Legacy Wallet.prototype.fillTX = Wallet.prototype.fillPrevout; -Wallet.prototype.createTX = function createTX(outputs, fee) { +Wallet.prototype.createTX = function createTX(outputs, options) { var tx = bcoin.tx(); var target; @@ -544,7 +546,7 @@ Wallet.prototype.createTX = function createTX(outputs, fee) { }); // Fill the inputs with unspents - if (!this.fill(tx, null, fee)) + if (!this.fill(tx, options)) return; // Sort members a la BIP69