txdb coin cache.
This commit is contained in:
parent
6612b7ced3
commit
5e103f0706
@ -63,6 +63,8 @@ function TXDB(db, options) {
|
||||
this.jobs = [];
|
||||
this.locker = new bcoin.locker(this);
|
||||
|
||||
this.coinCache = new bcoin.lru(10000, 1);
|
||||
|
||||
// Try to optimize for up to 1m addresses.
|
||||
// We use a regular bloom filter here
|
||||
// because we never want members to
|
||||
@ -394,6 +396,8 @@ TXDB.prototype._add = function add(tx, map, callback, force) {
|
||||
|
||||
batch.del('c/' + key);
|
||||
|
||||
self.coinCache.remove(key);
|
||||
|
||||
return next();
|
||||
}
|
||||
|
||||
@ -528,7 +532,12 @@ TXDB.prototype._add = function add(tx, map, callback, force) {
|
||||
batch.put('C/' + id + '/' + key, DUMMY);
|
||||
}
|
||||
|
||||
batch.put('c/' + key, coin.toRaw());
|
||||
coin = coin.toRaw();
|
||||
|
||||
batch.put('c/' + key, coin);
|
||||
|
||||
self.coinCache.set(key, coin);
|
||||
|
||||
updated = true;
|
||||
}
|
||||
|
||||
@ -759,6 +768,7 @@ TXDB.prototype._confirm = function _confirm(tx, map, callback, force) {
|
||||
|
||||
utils.forEachSerial(tx.outputs, function(output, next, i) {
|
||||
var address = output.getHash('hex');
|
||||
var key = hash + '/' + i;
|
||||
|
||||
// Only update coins if this output is ours.
|
||||
if (!map.hasPaths(address))
|
||||
@ -772,8 +782,11 @@ TXDB.prototype._confirm = function _confirm(tx, map, callback, force) {
|
||||
return next();
|
||||
|
||||
coin.height = tx.height;
|
||||
coin = coin.toRaw();
|
||||
|
||||
batch.put('c/' + hash + '/' + i, coin.toRaw());
|
||||
batch.put('c/' + key, coin);
|
||||
|
||||
self.coinCache.set(key, coin);
|
||||
|
||||
next();
|
||||
});
|
||||
@ -864,7 +877,8 @@ TXDB.prototype.lazyRemove = function lazyRemove(tx, callback, force) {
|
||||
|
||||
TXDB.prototype._remove = function remove(tx, map, callback, force) {
|
||||
var self = this;
|
||||
var unlock, hash, batch, i, j, path, id, key, paths, address, input, output;
|
||||
var unlock, hash, batch, i, j, path, id;
|
||||
var key, paths, address, input, output, coin;
|
||||
|
||||
unlock = this._lock(remove, [tx, map, callback], force);
|
||||
|
||||
@ -926,9 +940,13 @@ TXDB.prototype._remove = function remove(tx, map, callback, force) {
|
||||
batch.put('C/' + id + '/' + key, DUMMY);
|
||||
}
|
||||
|
||||
batch.put('c/' + key, input.coin.toRaw());
|
||||
coin = input.coin.toRaw();
|
||||
|
||||
batch.put('c/' + key, coin);
|
||||
batch.del('s/' + key);
|
||||
batch.del('o/' + key);
|
||||
|
||||
self.coinCache.set(key, coin);
|
||||
}
|
||||
|
||||
for (i = 0; i < tx.outputs.length; i++) {
|
||||
@ -951,6 +969,8 @@ TXDB.prototype._remove = function remove(tx, map, callback, force) {
|
||||
}
|
||||
|
||||
batch.del('c/' + key);
|
||||
|
||||
self.coinCache.remove(key);
|
||||
}
|
||||
|
||||
batch.write(function(err) {
|
||||
@ -1049,6 +1069,7 @@ TXDB.prototype._unconfirm = function unconfirm(tx, map, callback, force) {
|
||||
}
|
||||
|
||||
utils.forEachSerial(tx.outputs, function(output, next, i) {
|
||||
var key = hash + '/' + i;
|
||||
self.getCoin(hash, i, function(err, coin) {
|
||||
if (err)
|
||||
return next(err);
|
||||
@ -1057,8 +1078,11 @@ TXDB.prototype._unconfirm = function unconfirm(tx, map, callback, force) {
|
||||
return next();
|
||||
|
||||
coin.height = tx.height;
|
||||
coin = coin.toRaw();
|
||||
|
||||
batch.put('c/' + hash + '/' + i, coin.toRaw());
|
||||
batch.put('c/' + key, coin);
|
||||
|
||||
self.coinCache.set(key, coin);
|
||||
|
||||
next();
|
||||
});
|
||||
@ -1550,10 +1574,25 @@ TXDB.prototype.hasTX = function hasTX(hash, callback) {
|
||||
*/
|
||||
|
||||
TXDB.prototype.getCoin = function getCoin(hash, index, callback) {
|
||||
this.db.fetch('c/' + hash + '/' + index, function(data) {
|
||||
var key = hash + '/' + index;
|
||||
var coin = this.coinCache.get(key);
|
||||
|
||||
if (coin) {
|
||||
try {
|
||||
coin = bcoin.coin.fromRaw(coin);
|
||||
} catch (e) {
|
||||
return callback(e);
|
||||
}
|
||||
coin.hash = hash;
|
||||
coin.index = index;
|
||||
return callback(null, coin);
|
||||
}
|
||||
|
||||
this.db.fetch('c/' + key, function(data) {
|
||||
var coin = bcoin.coin.fromRaw(data);
|
||||
coin.hash = hash;
|
||||
coin.index = index;
|
||||
self.coinCache.set(key, data);
|
||||
return coin;
|
||||
}, callback);
|
||||
};
|
||||
@ -1565,7 +1604,12 @@ TXDB.prototype.getCoin = function getCoin(hash, index, callback) {
|
||||
*/
|
||||
|
||||
TXDB.prototype.hasCoin = function hasCoin(hash, index, callback) {
|
||||
return this.db.has('c/' + hash + '/' + index, callback);
|
||||
var key = hash + '/' + index;
|
||||
|
||||
if (this.coinCache.has(key))
|
||||
return callback(null, true);
|
||||
|
||||
return this.db.has('c/' + key, callback);
|
||||
};
|
||||
|
||||
/**
|
||||
@ -1578,28 +1622,59 @@ TXDB.prototype.getBalance = function getBalance(id, callback) {
|
||||
var self = this;
|
||||
var confirmed = 0;
|
||||
var unconfirmed = 0;
|
||||
var key, coin;
|
||||
|
||||
if (typeof id === 'function') {
|
||||
callback = id;
|
||||
id = null;
|
||||
}
|
||||
|
||||
function parse(data) {
|
||||
var height = data.readUInt32LE(4, true);
|
||||
var value = utils.read64N(data, 8);
|
||||
|
||||
assert(data.length >= 16);
|
||||
|
||||
if (height === 0x7fffffff)
|
||||
unconfirmed += value;
|
||||
else
|
||||
confirmed += value;
|
||||
}
|
||||
|
||||
return this.getCoinHashes(id, function(err, hashes) {
|
||||
if (err)
|
||||
return callback(err);
|
||||
|
||||
utils.forEachSerial(hashes, function(hash, next) {
|
||||
self.db.fetch('c/' + hash[0] + '/' + hash[1], function(data, key) {
|
||||
var height = data.readUInt32LE(4, true);
|
||||
var value = utils.read64N(data, 8);
|
||||
key = hash[0] + '/' + hash[1];
|
||||
coin = self.coinCache.get(key);
|
||||
|
||||
assert(data.length >= 16);
|
||||
if (coin) {
|
||||
try {
|
||||
parse(coin);
|
||||
} catch (e) {
|
||||
return next(e);
|
||||
}
|
||||
return next();
|
||||
}
|
||||
|
||||
if (height === 0x7fffffff)
|
||||
unconfirmed += value;
|
||||
else
|
||||
confirmed += value;
|
||||
}, next);
|
||||
self.db.get('c/' + key, function(err, data) {
|
||||
if (err)
|
||||
return next(err);
|
||||
|
||||
if (!data)
|
||||
return next();
|
||||
|
||||
try {
|
||||
parse(data);
|
||||
} catch (e) {
|
||||
return callback(e);
|
||||
}
|
||||
|
||||
self.coinCache.set(key, data);
|
||||
|
||||
next();
|
||||
});
|
||||
}, function(err) {
|
||||
if (err)
|
||||
return callback(err);
|
||||
|
||||
@ -157,7 +157,6 @@ Wallet.prototype.open = function open(callback) {
|
||||
|
||||
/**
|
||||
* Close the wallet, unregister with the database.
|
||||
* @method
|
||||
* @param {Function} callback
|
||||
*/
|
||||
|
||||
@ -2421,7 +2420,7 @@ MasterKey.fromOptions = function fromOptions(options) {
|
||||
* Decrypt the key and set a timeout to destroy decrypted data.
|
||||
* @param {Buffer|String} passphrase - Zero this yourself.
|
||||
* @param {Number} [timeout=60000] timeout in ms.
|
||||
* @returns {HDPrivateKey}
|
||||
* @param {Function} callback - Returns [Error, {@link HDPrivateKey}].
|
||||
*/
|
||||
|
||||
MasterKey.prototype.unlock = function _unlock(passphrase, timeout, callback) {
|
||||
@ -2515,6 +2514,7 @@ MasterKey.prototype.destroy = function destroy() {
|
||||
/**
|
||||
* Decrypt the key permanently.
|
||||
* @param {Buffer|String} passphrase - Zero this yourself.
|
||||
* @param {Function} callback
|
||||
*/
|
||||
|
||||
MasterKey.prototype.decrypt = function decrypt(passphrase, callback) {
|
||||
@ -2559,6 +2559,7 @@ MasterKey.prototype.decrypt = function decrypt(passphrase, callback) {
|
||||
/**
|
||||
* Encrypt the key permanently.
|
||||
* @param {Buffer|String} passphrase - Zero this yourself.
|
||||
* @param {Function} callback
|
||||
*/
|
||||
|
||||
MasterKey.prototype.encrypt = function encrypt(passphrase, callback) {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user