tx-pool: save spending TXs

This commit is contained in:
Fedor Indutny 2014-05-09 21:30:55 +04:00
parent cf2e0042ff
commit 2ee4c7cd3a
4 changed files with 66 additions and 14 deletions

View File

@ -53,13 +53,14 @@ TXPool.prototype.add = function add(tx, noWrite) {
// Transaction was confirmed, update it in storage // Transaction was confirmed, update it in storage
if (tx.ts !== 0 && this._all[hash].ts === 0) { if (tx.ts !== 0 && this._all[hash].ts === 0) {
this._all[hash].ts = tx.ts; this._all[hash].ts = tx.ts;
this._storeTX(hash, tx); if (this._storage)
this._storeTX(hash, tx);
} }
return false; return false;
} }
this._all[hash] = tx; this._all[hash] = tx;
var own = this._wallet.own(tx); var own = this._wallet.ownOutput(tx);
var update = false; var update = false;
// Consume unspent money or add orphans // Consume unspent money or add orphans
@ -87,6 +88,10 @@ TXPool.prototype.add = function add(tx, noWrite) {
if (!own) { if (!own) {
if (updated) if (updated)
this.emit('update', this._lastTs); this.emit('update', this._lastTs);
// Save spending TXs without adding unspents
if (this._storage && this._wallet.ownInput(tx))
this._storeTX(hash, tx);
return; return;
} }
@ -130,8 +135,9 @@ TXPool.prototype._storeTX = function _storeTX(hash, tx) {
TXPool.prototype.all = function all() { TXPool.prototype.all = function all() {
return Object.keys(this._all).map(function(key) { return Object.keys(this._all).map(function(key) {
return this._all[key]; return this._all[key];
}, this).filter(function(item) { }, this).filter(function(tx) {
return this._wallet.own(item.tx, item.index); return this._wallet.ownOutput(tx) ||
this._wallet.ownInput(tx);
}, this); }, this);
}; };
@ -139,7 +145,7 @@ TXPool.prototype.unspent = function unspent() {
return Object.keys(this._unspent).map(function(key) { return Object.keys(this._unspent).map(function(key) {
return this._unspent[key]; return this._unspent[key];
}, this).filter(function(item) { }, this).filter(function(item) {
return this._wallet.own(item.tx, item.index); return this._wallet.ownOutput(item.tx, item.index);
}, this); }, this);
}; };

View File

@ -163,7 +163,9 @@ TX.prototype.subscriptHash = function subscriptHash(index, s, type) {
TX.prototype.verify = function verify() { TX.prototype.verify = function verify() {
return this.inputs.every(function(input, i) { return this.inputs.every(function(input, i) {
assert(input.out.tx); if (!input.out.tx)
return false;
assert(input.out.tx.outputs.length > input.out.index); assert(input.out.tx.outputs.length > input.out.index);
var subscript = input.out.tx.getSubscript(input.out.index); var subscript = input.out.tx.getSubscript(input.out.index);

View File

@ -142,7 +142,7 @@ Wallet.prototype.validateAddress = function validateAddress(addr) {
}; };
Wallet.validateAddress = Wallet.prototype.validateAddress; Wallet.validateAddress = Wallet.prototype.validateAddress;
Wallet.prototype.own = function own(tx, index) { Wallet.prototype.ownOutput = function ownOutput(tx, index) {
var hash = this.getHash(); var hash = this.getHash();
var key = this.getPublicKey(); var key = this.getPublicKey();
var outputs = tx.outputs.filter(function(output, i) { var outputs = tx.outputs.filter(function(output, i) {
@ -165,6 +165,32 @@ Wallet.prototype.own = function own(tx, index) {
return outputs; return outputs;
}; };
Wallet.prototype.ownInput = function ownInput(tx, index) {
var hash = this.getHash();
var key = this.getPublicKey();
var inputs = tx.inputs.filter(function(input, i) {
if (index !== undefined && index !== i)
return false;
if (!input.out.tx)
return false;
var s = input.out.tx.outputs[input.out.index].script;
if (bcoin.script.isPubkeyhash(s, hash))
return true;
if (bcoin.script.isMultisig(s, key))
return true;
return false;
}, this);
if (inputs.length === 0)
return false;
return inputs;
};
Wallet.prototype.sign = function sign(tx, type) { Wallet.prototype.sign = function sign(tx, type) {
if (!type) if (!type)
type = 'all'; type = 'all';
@ -172,7 +198,7 @@ Wallet.prototype.sign = function sign(tx, type) {
// Filter inputs that this wallet own // Filter inputs that this wallet own
var inputs = tx.inputs.filter(function(input) { var inputs = tx.inputs.filter(function(input) {
return input.out.tx && this.own(input.out.tx); return input.out.tx && this.ownOutput(input.out.tx);
}, this); }, this);
var pub = this.getPublicKey(); var pub = this.getPublicKey();

View File

@ -31,8 +31,8 @@ describe('Wallet', function() {
address: w.getAddress() + 'x' address: w.getAddress() + 'x'
}] }]
}); });
assert(w.own(src)); assert(w.ownOutput(src));
assert.equal(w.own(src).reduce(function(acc, out) { assert.equal(w.ownOutput(src).reduce(function(acc, out) {
return acc.iadd(out.value); return acc.iadd(out.value);
}, new bn(0)).toString(10), 5460 * 2); }, new bn(0)).toString(10), 5460 * 2);
@ -58,8 +58,8 @@ describe('Wallet', function() {
address: w.getAddress() + 'x' address: w.getAddress() + 'x'
}] }]
}); });
assert(w.own(src)); assert(w.ownOutput(src));
assert.equal(w.own(src).reduce(function(acc, out) { assert.equal(w.ownOutput(src).reduce(function(acc, out) {
return acc.iadd(out.value); return acc.iadd(out.value);
}, new bn(0)).toString(10), 5460 * 2); }, new bn(0)).toString(10), 5460 * 2);
@ -75,6 +75,7 @@ describe('Wallet', function() {
it('should have TX pool and be serializable', function() { it('should have TX pool and be serializable', function() {
var w = bcoin.wallet(); var w = bcoin.wallet();
var f = bcoin.wallet();
// Coinbase // Coinbase
var t1 = bcoin.tx().out(w, 50000).out(w, 1000); var t1 = bcoin.tx().out(w, 50000).out(w, 1000);
@ -86,13 +87,22 @@ describe('Wallet', function() {
.out(w, 23000); .out(w, 23000);
var t4 = bcoin.tx().input(t2.hash(), 1) var t4 = bcoin.tx().input(t2.hash(), 1)
.input(t3.hash(), 0) .input(t3.hash(), 0)
.out(w, 22000); .out(w, 11000)
.out(w, 11000);
var f1 = bcoin.tx().input(t4.hash(), 1)
.out(f, 10000);
w.sign(t1);
w.sign(t2);
w.sign(t3);
w.sign(t4);
w.sign(f1);
// Just for debugging // Just for debugging
t1.hint = 't1'; t1.hint = 't1';
t2.hint = 't2'; t2.hint = 't2';
t3.hint = 't3'; t3.hint = 't3';
t4.hint = 't4'; t4.hint = 't4';
f1.hint = 'f1';
w.addTX(t4); w.addTX(t4);
assert.equal(w.balance().toString(10), '22000'); assert.equal(w.balance().toString(10), '22000');
@ -102,8 +112,16 @@ describe('Wallet', function() {
assert.equal(w.balance().toString(10), '47000'); assert.equal(w.balance().toString(10), '47000');
w.addTX(t3); w.addTX(t3);
assert.equal(w.balance().toString(10), '22000'); assert.equal(w.balance().toString(10), '22000');
w.addTX(f1);
assert.equal(w.balance().toString(10), '11000');
assert(w.all().some(function(tx) {
return tx.hash('hex') === f1.hash('hex');
}));
var w2 = bcoin.wallet.fromJSON(w.toJSON()); var w2 = bcoin.wallet.fromJSON(w.toJSON());
assert.equal(w2.balance().toString(10), '22000'); assert.equal(w2.balance().toString(10), '11000');
assert(w2.all().some(function(tx) {
return tx.hash('hex') === f1.hash('hex');
}));
}); });
}); });