diff --git a/lib/errors/spec.js b/lib/errors/spec.js index c68150f..5784b08 100644 --- a/lib/errors/spec.js +++ b/lib/errors/spec.js @@ -54,6 +54,9 @@ module.exports = [{ }, { name: 'NeedMoreInfo', message: '{0}' + }, { + name: 'InvalidIndex', + message: 'Invalid index: {0} is not between 0, {1}' }, { name: 'UnableToVerifySignature', message: 'Unable to verify signature: {0}' diff --git a/lib/transaction/transaction.js b/lib/transaction/transaction.js index 421f43f..cc7e4bc 100644 --- a/lib/transaction/transaction.js +++ b/lib/transaction/transaction.js @@ -529,7 +529,7 @@ Transaction.prototype._updateChangeOutput = function() { } this._clearSignatures(); if (!_.isUndefined(this._changeOutput)) { - this.removeOutput(this._changeOutput); + this._removeOutput(this._changeOutput); } var available = this._getUnspentValue(); var fee = this.getFee(); @@ -589,10 +589,33 @@ Transaction.prototype._estimateSize = function() { return result; }; -Transaction.prototype.removeOutput = function(index) { +Transaction.prototype._removeOutput = function(index) { var output = this.outputs[index]; this._outputAmount -= output.satoshis; - this.outputs = _.without(this.outputs, this.outputs[this._changeOutput]); + this.outputs = _.without(this.outputs, output); +}; + +Transaction.prototype.removeOutput = function(index) { + this._removeOutput(index); + this._updateChangeOutput(); +}; + +Transaction.prototype.removeInput = function(txId, outputIndex) { + var index; + if (!outputIndex && _.isNumber(txId)) { + index = txId; + } else { + index = _.findIndex(this.inputs, function(input) { + return input.prevTxId.toString('hex') === txId && input.outputIndex === outputIndex; + }); + } + if (index < 0 || index >= this.inputs.length) { + throw new errors.Transaction.InvalidIndex(index, this.inputs.length); + } + var input = this.inputs[index]; + this._inputAmount -= input.output.satoshis; + this.inputs = _.without(this.inputs, input); + this._updateChangeOutput(); }; /* Signature handling */ diff --git a/test/transaction/transaction.js b/test/transaction/transaction.js index c0f448c..62f6073 100644 --- a/test/transaction/transaction.js +++ b/test/transaction/transaction.js @@ -357,6 +357,40 @@ describe('Transaction', function() { }).to.not.throw(); }); }); + + describe('removeInput and removeOutput', function() { + it('can remove an input by index', function() { + var transaction = new Transaction() + .from(simpleUtxoWith1BTC); + transaction.inputs.length.should.equal(1); + transaction.removeInput(0); + transaction._inputAmount.should.equal(0); + transaction.inputs.length.should.equal(0); + }); + it('can remove an input by transaction id', function() { + var transaction = new Transaction() + .from(simpleUtxoWith1BTC); + transaction.inputs.length.should.equal(1); + transaction.removeInput(simpleUtxoWith1BTC.txId, simpleUtxoWith1BTC.outputIndex); + transaction._inputAmount.should.equal(0); + transaction.inputs.length.should.equal(0); + }); + it('fails if the index provided is invalid', function() { + var transaction = new Transaction() + .from(simpleUtxoWith1BTC); + expect(function() { + transaction.removeInput(2); + }).to.throw(errors.Transaction.InvalidIndex); + }); + it('an output can be removed by index', function() { + var transaction = new Transaction() + .to(toAddress, 40000000) + .to(toAddress, 40000000); + transaction.outputs.length.should.equal(2); + transaction.removeOutput(0); + transaction.outputs.length.should.equal(1); + }); + }); }); var tx_empty_hex = '01000000000000000000';