From 660c95483d6d0d1574608f71116d4d5d34b793bb Mon Sep 17 00:00:00 2001 From: Wei Lu Date: Thu, 12 Jun 2014 12:56:50 +0800 Subject: [PATCH 1/4] wallet.processTx accepts isPending flag and passes it on to output --- src/wallet.js | 3 ++- test/wallet.js | 12 +++++++++++- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/src/wallet.js b/src/wallet.js index b1442063f..5e04b7468 100644 --- a/src/wallet.js +++ b/src/wallet.js @@ -136,7 +136,7 @@ function Wallet(seed, network) { return value == undefined } - this.processTx = function(tx) { + this.processTx = function(tx, isPending) { var txhash = tx.getHash() tx.outs.forEach(function(txOut, i){ @@ -155,6 +155,7 @@ function Wallet(seed, network) { receive: output, value: txOut.value, address: address, + pending: isPending } } }) diff --git a/test/wallet.js b/test/wallet.js index 955eba192..00fea4284 100644 --- a/test/wallet.js +++ b/test/wallet.js @@ -302,16 +302,26 @@ describe('Wallet', function() { verifyOutputAdded(1) }) + describe("when the pending flag is set", function(){ + it("sets the pending flag on output", function(){ + wallet.addresses = [addresses[0]] + wallet.processTx(tx, true) + + verifyOutputAdded(0, true) + }) + }) + function outputCount(){ return Object.keys(wallet.outputs).length } - function verifyOutputAdded(index) { + 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) From e064e9d29da787ad374417b2f09914f0d9ca424c Mon Sep 17 00:00:00 2001 From: Wei Lu Date: Thu, 12 Jun 2014 13:11:28 +0800 Subject: [PATCH 2/4] wallet.createTx ignores pending utxo --- src/wallet.js | 5 +++-- test/wallet.js | 19 +++++++++++++++++++ 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/src/wallet.js b/src/wallet.js index 5e04b7468..14667747f 100644 --- a/src/wallet.js +++ b/src/wallet.js @@ -103,7 +103,8 @@ function Wallet(seed, network) { return { receive: key, address: o.address, - value: o.value + value: o.value, + pending: o.pending } } @@ -211,7 +212,7 @@ function Wallet(seed, network) { for (var key in me.outputs) { var output = me.outputs[key] - if (!output.spend) unspent.push(output) + if (!output.spend && !output.pending) unspent.push(output) } var sortByValueDesc = unspent.sort(function(o1, o2){ diff --git a/test/wallet.js b/test/wallet.js index 00fea4284..2f968993c 100644 --- a/test/wallet.js +++ b/test/wallet.js @@ -439,6 +439,25 @@ describe('Wallet', function() { assert.equal(tx.ins.length, 1) assert.deepEqual(tx.ins[0].outpoint, { hash: fakeTxHash(3), index: 0 }) }) + + it('ignores pending outputs', function(){ + utxo.push( + { + "hash": fakeTxHash(4), + "outputIndex": 0, + "address" : address2, + "value": 530000, + "pending": true + } + ) + wallet.setUnspentOutputs(utxo) + + 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(){ From d265b53b03d60690d3ea866ffb6ce6f11e92473c Mon Sep 17 00:00:00 2001 From: Wei Lu Date: Thu, 12 Jun 2014 15:42:10 +0800 Subject: [PATCH 3/4] wallet: processTx -> processConfirmedTx, processPendingTx --- src/wallet.js | 10 +++- test/wallet.js | 141 +++++++++++++++++++++++++------------------------ 2 files changed, 82 insertions(+), 69 deletions(-) diff --git a/src/wallet.js b/src/wallet.js index 14667747f..dfd0b5fdc 100644 --- a/src/wallet.js +++ b/src/wallet.js @@ -137,7 +137,15 @@ function Wallet(seed, network) { return value == undefined } - this.processTx = function(tx, isPending) { + 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){ diff --git a/test/wallet.js b/test/wallet.js index 2f968993c..92e04622f 100644 --- a/test/wallet.js +++ b/test/wallet.js @@ -252,7 +252,7 @@ describe('Wallet', function() { }) }) - describe('processTx', function(){ + describe('Process transaction', function(){ var addresses var tx @@ -266,100 +266,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) - assert.equal(outputCount(), totalOuts + 1) - verifyOutputAdded(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 + + 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) + }) - describe("when the pending flag is set", function(){ - it("sets the pending flag on output", function(){ - wallet.addresses = [addresses[0]] - wallet.processTx(tx, true) + it("works for change address", function(){ + var totalOuts = outputCount() + wallet.changeAddresses = [addresses[1]] + + wallet.processConfirmedTx(tx) - verifyOutputAdded(0, true) + assert.equal(outputCount(), totalOuts + 1) + verifyOutputAdded(1, false) }) + + function outputCount(){ + return Object.keys(wallet.outputs).length + } + }) - function outputCount(){ - return Object.keys(wallet.outputs).length - } + 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.processConfirmedTx(tx) - 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) + tx = Transaction.fromHex(fixtureTx2Hex) + }) - var txOutAddress = Address.fromScriptPubKey(txOut.script).toString() - assert.equal(output.address, txOutAddress) - } - }) + it("does not add to wallet.outputs", function(){ + var outputs = wallet.outputs + wallet.processConfirmedTx(tx) + assert.deepEqual(wallet.outputs, outputs) + }) - 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) + it("sets spend with the transaction hash and input index", function(){ + wallet.processConfirmedTx(tx) - tx = Transaction.fromHex(fixtureTx2Hex) + var txIn = tx.ins[0] + var key = txIn.outpoint.hash + ":" + txIn.outpoint.index + var output = wallet.outputs[key] + + assert.equal(output.spend, tx.getHash() + ':' + 0) + }) }) - it("does not add to wallet.outputs", function(){ + it("does nothing when none of the involved addresses belong to the wallet", function(){ var outputs = wallet.outputs - wallet.processTx(tx) + wallet.processConfirmedTx(tx) assert.deepEqual(wallet.outputs, outputs) }) - - 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] - - 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.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 From f53e35ed28bf4958fec316b9a07ac7cbb6145d5d Mon Sep 17 00:00:00 2001 From: Wei Lu Date: Thu, 12 Jun 2014 16:47:27 +0800 Subject: [PATCH 4/4] wallet: delete utxo instead of marking it as spend --- src/wallet.js | 10 ++++------ test/wallet.js | 37 +++---------------------------------- 2 files changed, 7 insertions(+), 40 deletions(-) diff --git a/src/wallet.js b/src/wallet.js index dfd0b5fdc..01dc03a51 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 @@ -171,11 +171,9 @@ function Wallet(seed, network) { 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] }) } @@ -220,7 +218,7 @@ function Wallet(seed, network) { for (var key in me.outputs) { var output = me.outputs[key] - if (!output.spend && !output.pending) 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 92e04622f..57bb829e1 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(){ @@ -319,7 +306,7 @@ describe('Wallet', function() { }) - describe("when tx ins outpoint contains a known txhash:i, the corresponding 'output' gets updated", function(){ + 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) @@ -333,14 +320,14 @@ describe('Wallet', function() { assert.deepEqual(wallet.outputs, outputs) }) - it("sets spend with the transaction hash and input index", function(){ + it("deletes corresponding 'output'", function(){ wallet.processConfirmedTx(tx) var txIn = tx.ins[0] var key = txIn.outpoint.hash + ":" + txIn.outpoint.index var output = wallet.outputs[key] - assert.equal(output.spend, tx.getHash() + ':' + 0) + assert.equal(output, undefined) }) }) @@ -427,24 +414,6 @@ describe('Wallet', function() { assert.deepEqual(tx.ins[0].outpoint, { hash: fakeTxHash(3), index: 0 }) }) - it('ignores spent outputs', function(){ - utxo.push( - { - "hash": fakeTxHash(4), - "outputIndex": 0, - "address" : address2, - "value": 530000 // enough but spent before createTx - } - ) - 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 }) - }) - it('ignores pending outputs', function(){ utxo.push( {