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 = {
list: [],
// Bloom filter for all merkle trees
merkleBloom: new bcoin.bloom(8 * 1024 * 1024, 16, 0xdeadbeed),
// Bloom filter for all known blocks
bloom: new bcoin.bloom(8 * 1024 * 1024, 16, 0xdeadbeef)
};
@ -215,7 +212,6 @@ Chain.prototype._compress = function compress() {
// Bloom filter rebuilt is needed
this.block.list = this.block.list.slice(-1000);
this.block.bloom.reset();
this.block.merkleBloom.reset();
for (var i = 0; i < this.block.list.length; i++)
this._bloomBlock(this.block.list[i]);
@ -223,8 +219,6 @@ Chain.prototype._compress = function compress() {
Chain.prototype._bloomBlock = function _bloomBlock(block) {
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) {
@ -258,20 +252,6 @@ Chain.prototype.has = function has(hash, noProbe, cb) {
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) {
// Cached block found
if (this.block.bloom.test(hash, 'hex')) {

View File

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

View File

@ -12,10 +12,11 @@ function TXPool(wallet) {
this._wallet = wallet;
this._storage = wallet.storage;
this._prefix = 'bt/' + wallet.getAddress() + '/tx/';
this._prefix = wallet.prefix + 'tx/';
this._all = {};
this._unspent = {};
this._orphans = {};
this._lastTs = 0;
// Load TXs from storage
this._init();
@ -39,6 +40,9 @@ TXPool.prototype._init = function init() {
s.on('error', function(err) {
self.emit('error', err);
});
s.on('end', function() {
self.emit('load', self._lastTs);
});
};
TXPool.prototype.add = function add(tx, noWrite) {
@ -76,6 +80,8 @@ TXPool.prototype.add = function add(tx, noWrite) {
if (!own)
return;
var updated = false;
// Add unspent outputs or fullfill orphans
for (var i = 0; i < tx.outputs.length; i++) {
var out = tx.outputs[i];
@ -84,7 +90,7 @@ TXPool.prototype.add = function add(tx, noWrite) {
var orphan = this._orphans[key];
if (!orphan) {
this._unspent[key] = { tx: tx, index: i };
this.emit('update');
updated = true;
continue;
}
delete this._orphans[key];
@ -93,6 +99,10 @@ TXPool.prototype.add = function add(tx, noWrite) {
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) {
var self = this;
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 utils = bcoin.utils;
function TX(data) {
function TX(data, block) {
if (!(this instanceof TX))
return new TX(data);
return new TX(data, block);
this.type = 'tx';
if (!data)
@ -16,6 +16,7 @@ function TX(data) {
this.inputs = [];
this.outputs = [];
this.lock = data.lock || 0;
this.ts = data.ts || 0;
this._hash = null;
this._raw = data._raw || null;
@ -30,6 +31,9 @@ function TX(data) {
this.out(out, null);
}, this);
}
if (!data.ts && block && block.hasMerkle(this.hash('hex')))
this.ts = block.ts;
}
module.exports = TX;
@ -174,10 +178,19 @@ TX.prototype.verify = function verify() {
TX.prototype.toJSON = function toJSON() {
// 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) {
// 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.prefix = 'bt/' + this.getAddress() + '/';
this.tx = new bcoin.txPool(this);
this._init();
}
@ -47,13 +48,17 @@ Wallet.prototype._init = function init() {
// Notify owners about new accepted transactions
var self = this;
var prevBalance = null;
this.tx.on('update', function(tx) {
this.tx.on('update', function() {
var b = this.balance();
if (prevBalance && prevBalance.cmp(b) !== 0)
self.emit('balance', b);
prevBalance = b;
});
this.tx.once('load', function(ts) {
self.emit('load', ts);
});
this.tx.on('error', function(err) {
self.emit('error', err);
});
@ -186,7 +191,7 @@ Wallet.prototype.sign = function sign(tx, type) {
return inputs.length;
};
Wallet.prototype.addTX = function addTX(tx) {
Wallet.prototype.addTX = function addTX(tx, block) {
return this.tx.add(tx);
};