From bf2e281787e303f29f5f06baf8779716b7b7b57f Mon Sep 17 00:00:00 2001 From: Matias Alejo Garcia Date: Thu, 2 Nov 2017 10:35:34 -0300 Subject: [PATCH] WIP short address cache --- lib/common/defaults.js | 6 +++++ lib/server.js | 16 +++++++++-- lib/storage.js | 60 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 80 insertions(+), 2 deletions(-) diff --git a/lib/common/defaults.js b/lib/common/defaults.js index 30444b5..4181ef7 100644 --- a/lib/common/defaults.js +++ b/lib/common/defaults.js @@ -96,6 +96,12 @@ Defaults.CONFIRMATIONS_TO_START_CACHING = 6 * 6; // ~ 6hrs // Number of addresses from which tx history is enabled in a wallet Defaults.HISTORY_CACHE_ADDRESS_THRESOLD = 100; +// Number of addresses from which balance in cache for a few seconds +Defaults.BALANCE_CACHE_ADDRESS_THRESOLD = Defaults.HISTORY_CACHE_ADDRESS_THRESOLD; + +// Duration in seconds of the balance cache +Defaults.BALANCE_CACHE_DURATION = 5 + // Cache time for blockchain height (in seconds) Defaults.BLOCKHEIGHT_CACHE_TIME = 10 * 60; diff --git a/lib/server.js b/lib/server.js index ac953f5..7f1ef7e 100644 --- a/lib/server.js +++ b/lib/server.js @@ -1243,11 +1243,18 @@ WalletService.prototype._totalizeUtxos = function(utxos) { WalletService.prototype._getBalanceFromAddresses = function(opts, cb, i) { var self = this; - var opts = opts || {}; + var isBig = opts.addresses.length > Default.BALANCE_CACHE_ADDRESS_THRESOLD; // This lock is to prevent server starvation on big wallets self._runLocked(cb, function(cb) { + + if (isBig && self.storage.checkAndUseBalanceCache(addresses,cb)) + log.info('Using UTXO Cache'); + return; + } + + self._getUtxosForCurrentWallet({ coin: opts.coin, addresses: opts.addresses @@ -1271,7 +1278,12 @@ WalletService.prototype._getBalanceFromAddresses = function(opts, cb, i) { }); balance.byAddress = _.values(byAddress); - return cb(null, balance); + + if (isBig) { + return self.storage.storeBalanceCache(addresses, balance, cb); + } else { + return cb(null, balance); + } }); }); }; diff --git a/lib/storage.js b/lib/storage.js index fe0ee75..3e6a691 100644 --- a/lib/storage.js +++ b/lib/storage.js @@ -7,6 +7,7 @@ var log = require('npmlog'); log.debug = log.verbose; log.disableColor(); var util = require('util'); +var Bitcore = require('bitcore-lib'); var mongodb = require('mongodb'); @@ -1065,5 +1066,64 @@ Storage.prototype._dump = function(cb, fn) { }); }; + +Storage.prototype._addressHash = function(addresses) { + var all = addresses.join(); + return Bitcore.crypto.Hash.ripemd160(new Buffer(all)).toString('hex'); +}; + +Storage.prototype.checkAndUseBalanceCache = function(addresses, cb) { + var key = ths._addressHash(addresses); + var now = Date.now(); + + self.db.collection(collections.CACHE).findOne({ + walletId: walletId, + type: 'balanceCache', + key: key, + }, function(err, ret) { + if (err) return cb(err); + if (!ret) return cb(); + + var validFor = ret.ts + Defauls.BALANCE_CACHE_DURATION * 1000 - now; + + if (validFor > 0) { + log.debug('','Using Balance Cache valid for %d ms more', validFor); + return cb(null, ret.result); + } + + return cb(); + + log.debug('','Balance cache expired, deleting'); + self.db.collection(collections.CACHE).remove({ + walletId: walletId, + type: 'balanceCache', + key: key, + }, {}, function() { + }); + }); +}); + + + +Storage.prototype.storeBalanceCache = function (addresses, balance, cb) { + var key = ths._addressHash(addresses); + var now = Date.now(); + + self.db.collection(collections.CACHE).update( { + walletId: walletId, + type: 'balanceCache', + key: key, + }, { + "$set": + { + ts: now, + result: balance, + } + }, { + w: 1, + upsert: true, + }, cb); +}; + Storage.collections = collections; module.exports = Storage;