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