diff --git a/lib/transaction/transaction.js b/lib/transaction/transaction.js index accd86e..a22114f 100644 --- a/lib/transaction/transaction.js +++ b/lib/transaction/transaction.js @@ -337,6 +337,13 @@ Transaction.prototype.from = function(utxo, pubkeys, threshold) { }); return this; } + var exists = _.any(this.inputs, function(input) { + // TODO: Maybe prevTxId should be a string? Or defined as read only property? + return input.prevTxId.toString('hex') === utxo.txId && input.outputIndex === utxo.outputIndex; + }); + if (exists) { + return; + } if (pubkeys && threshold) { this._fromMultisigUtxo(utxo, pubkeys, threshold); } else { diff --git a/test/transaction/transaction.js b/test/transaction/transaction.js index 0892a2f..2f53350 100644 --- a/test/transaction/transaction.js +++ b/test/transaction/transaction.js @@ -120,6 +120,40 @@ describe('Transaction', function() { var changeAddressP2SH = '2N7T3TAetJrSCruQ39aNrJvYLhG1LJosujf'; var privateKey = 'cSBnVM4xvxarwGQuAfQFwqDg9k5tErHUHzgWsEfD4zdwUasvqRVY'; + var simpleUtxoWith1BTC = { + address: fromAddress, + txId: 'a477af6b2667c29670467e4e0728b685ee07b240235771862318e29ddbe58458', + outputIndex: 0, + script: Script.buildPublicKeyHashOut(fromAddress).toString(), + satoshis: 1e8 + }; + + describe('adding inputs', function() { + + it('it only adds once one utxo', function() { + var tx = new Transaction(); + tx.from(simpleUtxoWith1BTC); + tx.from(simpleUtxoWith1BTC); + tx.inputs.length.should.equal(1); + }); + + describe('not enough information errors', function() { + it('fails when Inputs are not subclassed and isFullySigned is called', function() { + var tx = new Transaction(tx_1_hex); + expect(function() { + return tx.isFullySigned(); + }).to.throw(errors.Transaction.UnableToVerifySignature); + }); + + it('fails when Inputs are not subclassed and verifySignature is called', function() { + var tx = new Transaction(tx_1_hex); + expect(function() { + return tx.isValidSignature({inputIndex: 0}); + }).to.throw(errors.Transaction.UnableToVerifySignature); + }); + }); + }); + describe('change address', function() { it('can calculate simply the output amount', function() { var transaction = new Transaction() @@ -190,30 +224,6 @@ describe('Transaction', function() { }); }); - var simpleUtxoWith1BTC = { - address: fromAddress, - txId: 'a477af6b2667c29670467e4e0728b685ee07b240235771862318e29ddbe58458', - outputIndex: 0, - script: Script.buildPublicKeyHashOut(fromAddress).toString(), - satoshis: 1e8 - }; - - describe('not enough information errors', function() { - it('fails when Inputs are not subclassed and isFullySigned is called', function() { - var tx = new Transaction(tx_1_hex); - expect(function() { - return tx.isFullySigned(); - }).to.throw(errors.Transaction.UnableToVerifySignature); - }); - - it('fails when Inputs are not subclassed and verifySignature is called', function() { - var tx = new Transaction(tx_1_hex); - expect(function() { - return tx.isValidSignature({inputIndex: 0}); - }).to.throw(errors.Transaction.UnableToVerifySignature); - }); - }); - describe('serialization', function() { it('stores the change address correctly', function() { var serialized = new Transaction()