diff --git a/src/wallet.js b/src/wallet.js index b144206..01dc03a 100644 --- a/src/wallet.js +++ b/src/wallet.js @@ -68,7 +68,7 @@ function Wallet(seed, network) { for(var key in this.outputs){ var output = this.outputs[key] - if(!output.spend) utxo.push(outputToUnspentOutput(output)) + utxo.push(outputToUnspentOutput(output)) } return utxo @@ -103,7 +103,8 @@ function Wallet(seed, network) { return { receive: key, address: o.address, - value: o.value + value: o.value, + pending: o.pending } } @@ -136,7 +137,15 @@ function Wallet(seed, network) { return value == undefined } - this.processTx = function(tx) { + this.processPendingTx = function(tx){ + processTx(tx, true) + } + + this.processConfirmedTx = function(tx){ + processTx(tx, false) + } + + function processTx(tx, isPending) { var txhash = tx.getHash() tx.outs.forEach(function(txOut, i){ @@ -155,17 +164,16 @@ function Wallet(seed, network) { receive: output, value: txOut.value, address: address, + pending: isPending } } }) tx.ins.forEach(function(txIn, i){ var op = txIn.outpoint + var output = op.hash + ':' + op.index - var o = me.outputs[op.hash + ':' + op.index] - if (o) { - o.spend = txhash + ':' + i - } + if(me.outputs[output]) delete me.outputs[output] }) } @@ -210,7 +218,7 @@ function Wallet(seed, network) { for (var key in me.outputs) { var output = me.outputs[key] - if (!output.spend) unspent.push(output) + if (!output.pending) unspent.push(output) } var sortByValueDesc = unspent.sort(function(o1, o2){ diff --git a/test/wallet.js b/test/wallet.js index 955eba1..57bb829 100644 --- a/test/wallet.js +++ b/test/wallet.js @@ -195,14 +195,6 @@ describe('Wallet', function() { assert.equal(wallet.getBalance(), 40000) }) - - it('excludes spent outputs', function(){ - addUtxoToOutput(expectedUtxo) - addUtxoToOutput(utxo1) - wallet.outputs[utxo1.hash + ':' + utxo1.outputIndex].spend = "sometxn:m" - - assert.equal(wallet.getBalance(), 20000) - }) }) describe('getUnspentOutputs', function(){ @@ -213,11 +205,6 @@ describe('Wallet', function() { it('parses wallet outputs to the expect format', function(){ assert.deepEqual(wallet.getUnspentOutputs(), [expectedUtxo]) }) - - it('excludes spent outputs', function(){ - wallet.outputs[expectedOutputKey].spend = "sometxn:m" - assert.deepEqual(wallet.getUnspentOutputs(), []) - }) }) describe('setUnspentOutputs', function(){ @@ -252,7 +239,7 @@ describe('Wallet', function() { }) }) - describe('processTx', function(){ + describe('Process transaction', function(){ var addresses var tx @@ -266,90 +253,105 @@ describe('Wallet', function() { tx = Transaction.fromHex(fixtureTx1Hex) }) - it('does not fail on scripts with no corresponding Address', function() { - var pubKey = wallet.getPrivateKey(0).pub - var script = Script.createPubKeyScriptPubKey(pubKey) - var tx2 = new Transaction() - tx2.addInput(fakeTxHash(1), 0) - - // FIXME: Transaction doesn't support custom ScriptPubKeys... yet - // So for now, we hijack the script with our own, and undefine the cached address - tx2.addOutput(addresses[0], 10000) - tx2.outs[0].script = script - tx2.outs[0].address = undefined + describe("processPendingTx", function(){ + it("sets the pending flag on output", function(){ + wallet.addresses = [addresses[0]] + wallet.processPendingTx(tx) - wallet.processTx(tx2) + verifyOutputAdded(0, true) + }) }) - describe("when tx outs contains an address owned by the wallet, an 'output' gets added to wallet.outputs", function(){ - it("works for receive address", function(){ - var totalOuts = outputCount() + describe('processConfirmedTx', function(){ - wallet.addresses = [addresses[0]] - wallet.processTx(tx) + it('does not fail on scripts with no corresponding Address', function() { + var pubKey = wallet.getPrivateKey(0).pub + var script = Script.createPubKeyScriptPubKey(pubKey) + var tx2 = new Transaction() + tx2.addInput(fakeTxHash(1), 0) + + // FIXME: Transaction doesn't support custom ScriptPubKeys... yet + // So for now, we hijack the script with our own, and undefine the cached address + tx2.addOutput(addresses[0], 10000) + tx2.outs[0].script = script + tx2.outs[0].address = undefined - assert.equal(outputCount(), totalOuts + 1) - verifyOutputAdded(0) + wallet.processConfirmedTx(tx2) }) - it("works for change address", function(){ - var totalOuts = outputCount() - wallet.changeAddresses = [addresses[1]] + describe("when tx outs contains an address owned by the wallet, an 'output' gets added to wallet.outputs", function(){ + it("works for receive address", function(){ + var totalOuts = outputCount() - wallet.processTx(tx) + wallet.addresses = [addresses[0]] + wallet.processConfirmedTx(tx) - assert.equal(outputCount(), totalOuts + 1) - verifyOutputAdded(1) - }) + assert.equal(outputCount(), totalOuts + 1) + verifyOutputAdded(0, false) + }) - function outputCount(){ - return Object.keys(wallet.outputs).length - } + it("works for change address", function(){ + var totalOuts = outputCount() + wallet.changeAddresses = [addresses[1]] - function verifyOutputAdded(index) { - var txOut = tx.outs[index] - var key = tx.getHash() + ":" + index - var output = wallet.outputs[key] - assert.equal(output.receive, key) - assert.equal(output.value, txOut.value) + wallet.processConfirmedTx(tx) - var txOutAddress = Address.fromScriptPubKey(txOut.script).toString() - assert.equal(output.address, txOutAddress) - } - }) + assert.equal(outputCount(), totalOuts + 1) + verifyOutputAdded(1, false) + }) - describe("when tx ins outpoint contains a known txhash:i, the corresponding 'output' gets updated", function(){ - beforeEach(function(){ - wallet.addresses = [addresses[0]] // the address fixtureTx2 used as input - wallet.processTx(tx) + function outputCount(){ + return Object.keys(wallet.outputs).length + } - tx = Transaction.fromHex(fixtureTx2Hex) }) - it("does not add to wallet.outputs", function(){ - var outputs = wallet.outputs - wallet.processTx(tx) - assert.deepEqual(wallet.outputs, outputs) - }) + describe("when tx ins outpoint contains a known txhash:i", function(){ + beforeEach(function(){ + wallet.addresses = [addresses[0]] // the address fixtureTx2 used as input + wallet.processConfirmedTx(tx) + + tx = Transaction.fromHex(fixtureTx2Hex) + }) + + it("does not add to wallet.outputs", function(){ + var outputs = wallet.outputs + wallet.processConfirmedTx(tx) + assert.deepEqual(wallet.outputs, outputs) + }) + + it("deletes corresponding 'output'", function(){ + wallet.processConfirmedTx(tx) - it("sets spend with the transaction hash and input index", function(){ - wallet.processTx(tx) + var txIn = tx.ins[0] + var key = txIn.outpoint.hash + ":" + txIn.outpoint.index + var output = wallet.outputs[key] - var txIn = tx.ins[0] - var key = txIn.outpoint.hash + ":" + txIn.outpoint.index - var output = wallet.outputs[key] + assert.equal(output, undefined) + }) + }) - assert.equal(output.spend, tx.getHash() + ':' + 0) + it("does nothing when none of the involved addresses belong to the wallet", function(){ + var outputs = wallet.outputs + wallet.processConfirmedTx(tx) + assert.deepEqual(wallet.outputs, outputs) }) }) - it("does nothing when none of the involved addresses belong to the wallet", function(){ - var outputs = wallet.outputs - wallet.processTx(tx) - assert.deepEqual(wallet.outputs, outputs) - }) + function verifyOutputAdded(index, pending) { + var txOut = tx.outs[index] + var key = tx.getHash() + ":" + index + var output = wallet.outputs[key] + assert.equal(output.receive, key) + assert.equal(output.value, txOut.value) + assert.equal(output.pending, pending) + + var txOutAddress = Address.fromScriptPubKey(txOut.script).toString() + assert.equal(output.address, txOutAddress) + } }) + describe('createTx', function(){ var to, value var address1, address2 @@ -412,23 +414,24 @@ describe('Wallet', function() { assert.deepEqual(tx.ins[0].outpoint, { hash: fakeTxHash(3), index: 0 }) }) - it('ignores spent outputs', function(){ + it('ignores pending outputs', function(){ utxo.push( { "hash": fakeTxHash(4), "outputIndex": 0, "address" : address2, - "value": 530000 // enough but spent before createTx + "value": 530000, + "pending": true } ) wallet.setUnspentOutputs(utxo) - wallet.outputs[fakeTxHash(4) + ":" + 0].spend = fakeTxHash(5) + ":" + 0 var tx = wallet.createTx(to, value) assert.equal(tx.ins.length, 1) assert.deepEqual(tx.ins[0].outpoint, { hash: fakeTxHash(3), index: 0 }) }) + }) describe(networks.testnet, function(){