Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 16 additions & 8 deletions src/wallet.js
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -103,7 +103,8 @@ function Wallet(seed, network) {
return {
receive: key,
address: o.address,
value: o.value
value: o.value,
pending: o.pending
}
}

Expand Down Expand Up @@ -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){
Expand All @@ -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]
})
}

Expand Down Expand Up @@ -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){
Expand Down
157 changes: 80 additions & 77 deletions test/wallet.js
Original file line number Diff line number Diff line change
Expand Up @@ -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(){
Expand All @@ -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(){
Expand Down Expand Up @@ -252,7 +239,7 @@ describe('Wallet', function() {
})
})

describe('processTx', function(){
describe('Process transaction', function(){
var addresses
var tx

Expand All @@ -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
Expand Down Expand Up @@ -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(){
Expand Down