wallet: store timestamp of transactions

This commit is contained in:
Fedor Indutny 2014-05-08 20:25:12 +04:00
parent 292da0625e
commit 048bca0b8a
5 changed files with 44 additions and 35 deletions

View File

@ -20,9 +20,6 @@ function Chain(options) {
this.block = { this.block = {
list: [], list: [],
// Bloom filter for all merkle trees
merkleBloom: new bcoin.bloom(8 * 1024 * 1024, 16, 0xdeadbeed),
// Bloom filter for all known blocks // Bloom filter for all known blocks
bloom: new bcoin.bloom(8 * 1024 * 1024, 16, 0xdeadbeef) bloom: new bcoin.bloom(8 * 1024 * 1024, 16, 0xdeadbeef)
}; };
@ -215,7 +212,6 @@ Chain.prototype._compress = function compress() {
// Bloom filter rebuilt is needed // Bloom filter rebuilt is needed
this.block.list = this.block.list.slice(-1000); this.block.list = this.block.list.slice(-1000);
this.block.bloom.reset(); this.block.bloom.reset();
this.block.merkleBloom.reset();
for (var i = 0; i < this.block.list.length; i++) for (var i = 0; i < this.block.list.length; i++)
this._bloomBlock(this.block.list[i]); this._bloomBlock(this.block.list[i]);
@ -223,8 +219,6 @@ Chain.prototype._compress = function compress() {
Chain.prototype._bloomBlock = function _bloomBlock(block) { Chain.prototype._bloomBlock = function _bloomBlock(block) {
this.block.bloom.add(block.hash(), 'hex'); this.block.bloom.add(block.hash(), 'hex');
for (var i = 0; i < block.hashes.length; i++)
this.block.merkleBloom.add(block.hashes[i], 'hex');
}; };
Chain.prototype.has = function has(hash, noProbe, cb) { Chain.prototype.has = function has(hash, noProbe, cb) {
@ -258,20 +252,6 @@ Chain.prototype.has = function has(hash, noProbe, cb) {
return cb(!!this.orphan.map[hash]); return cb(!!this.orphan.map[hash]);
}; };
Chain.prototype.hasMerkle = function hasMerkle(hash) {
if (!this.block.merkleBloom.test(hash, 'hex'))
return false;
if (!this.strict)
return true;
hash = utils.toHex(hash);
for (var i = 0; i < this.block.list.length; i++)
if (this.block.list[i].hasMerkle(hash))
return true;
return false;
};
Chain.prototype.get = function get(hash, cb) { Chain.prototype.get = function get(hash, cb) {
// Cached block found // Cached block found
if (this.block.bloom.test(hash, 'hex')) { if (this.block.bloom.test(hash, 'hex')) {

View File

@ -250,15 +250,16 @@ Peer.prototype._onPacket = function onPacket(packet) {
else if (cmd === 'pong') else if (cmd === 'pong')
return this._handlePong(payload); return this._handlePong(payload);
if (cmd === 'merkleblock' || cmd === 'block') if (cmd === 'merkleblock' || cmd === 'block') {
payload = bcoin.block(payload); payload = bcoin.block(payload);
else if (cmd === 'tx') this.lastBlock = payload;
payload = bcoin.tx(payload); } else if (cmd === 'tx') {
if (this._res(cmd, payload)) { payload = bcoin.tx(payload, this.lastBlock);
return;
} else {
this.emit(cmd, payload);
} }
if (this._res(cmd, payload))
return;
else
this.emit(cmd, payload);
}; };
Peer.prototype._handleVersion = function handleVersion(payload) { Peer.prototype._handleVersion = function handleVersion(payload) {

View File

@ -12,10 +12,11 @@ function TXPool(wallet) {
this._wallet = wallet; this._wallet = wallet;
this._storage = wallet.storage; this._storage = wallet.storage;
this._prefix = 'bt/' + wallet.getAddress() + '/tx/'; this._prefix = wallet.prefix + 'tx/';
this._all = {}; this._all = {};
this._unspent = {}; this._unspent = {};
this._orphans = {}; this._orphans = {};
this._lastTs = 0;
// Load TXs from storage // Load TXs from storage
this._init(); this._init();
@ -39,6 +40,9 @@ TXPool.prototype._init = function init() {
s.on('error', function(err) { s.on('error', function(err) {
self.emit('error', err); self.emit('error', err);
}); });
s.on('end', function() {
self.emit('load', self._lastTs);
});
}; };
TXPool.prototype.add = function add(tx, noWrite) { TXPool.prototype.add = function add(tx, noWrite) {
@ -76,6 +80,8 @@ TXPool.prototype.add = function add(tx, noWrite) {
if (!own) if (!own)
return; return;
var updated = false;
// Add unspent outputs or fullfill orphans // Add unspent outputs or fullfill orphans
for (var i = 0; i < tx.outputs.length; i++) { for (var i = 0; i < tx.outputs.length; i++) {
var out = tx.outputs[i]; var out = tx.outputs[i];
@ -84,7 +90,7 @@ TXPool.prototype.add = function add(tx, noWrite) {
var orphan = this._orphans[key]; var orphan = this._orphans[key];
if (!orphan) { if (!orphan) {
this._unspent[key] = { tx: tx, index: i }; this._unspent[key] = { tx: tx, index: i };
this.emit('update'); updated = true;
continue; continue;
} }
delete this._orphans[key]; delete this._orphans[key];
@ -93,6 +99,10 @@ TXPool.prototype.add = function add(tx, noWrite) {
orphan.tx.input(tx, orphan.index); orphan.tx.input(tx, orphan.index);
} }
this._lastTs = Math.max(tx.ts, this._lastTs);
if (updated)
this.emit('update', this._lastTs);
if (!noWrite && this._storage) { if (!noWrite && this._storage) {
var self = this; var self = this;
this._storage.put(this._prefix + hash, tx.toJSON(), function(err) { this._storage.put(this._prefix + hash, tx.toJSON(), function(err) {

View File

@ -4,9 +4,9 @@ var bn = require('bn.js');
var bcoin = require('../bcoin'); var bcoin = require('../bcoin');
var utils = bcoin.utils; var utils = bcoin.utils;
function TX(data) { function TX(data, block) {
if (!(this instanceof TX)) if (!(this instanceof TX))
return new TX(data); return new TX(data, block);
this.type = 'tx'; this.type = 'tx';
if (!data) if (!data)
@ -16,6 +16,7 @@ function TX(data) {
this.inputs = []; this.inputs = [];
this.outputs = []; this.outputs = [];
this.lock = data.lock || 0; this.lock = data.lock || 0;
this.ts = data.ts || 0;
this._hash = null; this._hash = null;
this._raw = data._raw || null; this._raw = data._raw || null;
@ -30,6 +31,9 @@ function TX(data) {
this.out(out, null); this.out(out, null);
}, this); }, this);
} }
if (!data.ts && block && block.hasMerkle(this.hash('hex')))
this.ts = block.ts;
} }
module.exports = TX; module.exports = TX;
@ -174,10 +178,19 @@ TX.prototype.verify = function verify() {
TX.prototype.toJSON = function toJSON() { TX.prototype.toJSON = function toJSON() {
// Compact representation // Compact representation
return utils.toBase58(this.render()); var ts = new Array(4);
bcoin.utils.writeU32(ts, this.ts, 0);
return utils.toBase58(this.render().concat(ts));
}; };
TX.fromJSON = function fromJSON(json) { TX.fromJSON = function fromJSON(json) {
// Compact representation // Compact representation
return new TX(new bcoin.protocol.parser().parseTX(utils.fromBase58(json))); var data = utils.fromBase58(json);
var tx = data.slice(0, -4);
var ts = bcoin.utils.readU32(data, data.length - 4);
tx = new TX(new bcoin.protocol.parser().parseTX(tx));
tx.ts = ts;
return tx;
}; };

View File

@ -37,6 +37,7 @@ function Wallet(options, passphrase) {
this.key = bcoin.ecdsa.genKeyPair(); this.key = bcoin.ecdsa.genKeyPair();
} }
this.prefix = 'bt/' + this.getAddress() + '/';
this.tx = new bcoin.txPool(this); this.tx = new bcoin.txPool(this);
this._init(); this._init();
} }
@ -47,13 +48,17 @@ Wallet.prototype._init = function init() {
// Notify owners about new accepted transactions // Notify owners about new accepted transactions
var self = this; var self = this;
var prevBalance = null; var prevBalance = null;
this.tx.on('update', function(tx) { this.tx.on('update', function() {
var b = this.balance(); var b = this.balance();
if (prevBalance && prevBalance.cmp(b) !== 0) if (prevBalance && prevBalance.cmp(b) !== 0)
self.emit('balance', b); self.emit('balance', b);
prevBalance = b; prevBalance = b;
}); });
this.tx.once('load', function(ts) {
self.emit('load', ts);
});
this.tx.on('error', function(err) { this.tx.on('error', function(err) {
self.emit('error', err); self.emit('error', err);
}); });
@ -186,7 +191,7 @@ Wallet.prototype.sign = function sign(tx, type) {
return inputs.length; return inputs.length;
}; };
Wallet.prototype.addTX = function addTX(tx) { Wallet.prototype.addTX = function addTX(tx, block) {
return this.tx.add(tx); return this.tx.add(tx);
}; };