Merge pull request #3 from isocolsky/ref/cache

Cache current blockheight & refresh via notifications
This commit is contained in:
Matias Alejo Garcia 2016-08-08 10:23:23 -03:00 committed by GitHub
commit fa98635843
3 changed files with 99 additions and 37 deletions

View File

@ -77,4 +77,7 @@ Defaults.CONFIRMATIONS_TO_START_CACHING = 6 * 6; // ~ 6hrs
// Number of addresses from which tx history is enabled in a wallet // Number of addresses from which tx history is enabled in a wallet
Defaults.HISTORY_CACHE_ADDRESS_THRESOLD = 100; Defaults.HISTORY_CACHE_ADDRESS_THRESOLD = 100;
// Cache time for blockchain height (in seconds)
Defaults.BLOCKHEIGHT_CACHE_TIME = 10 * 60;
module.exports = Defaults; module.exports = Defaults;

View File

@ -108,11 +108,11 @@ WalletService.initialize = function(opts, cb) {
}; };
function initMessageBroker(cb) { function initMessageBroker(cb) {
if (opts.messageBroker) { messageBroker = opts.messageBroker || new MessageBroker(opts.messageBrokerOpts);
messageBroker = opts.messageBroker; if (messageBroker) {
} else { messageBroker.onMessage(WalletService.handleIncomingNotification);
messageBroker = new MessageBroker(opts.messageBrokerOpts);
} }
return cb(); return cb();
}; };
@ -153,6 +153,14 @@ WalletService.initialize = function(opts, cb) {
}); });
}; };
WalletService.handleIncomingNotification = function(notification, cb) {
cb = cb || function() {};
if (!notification || notification.type != 'NewBlock') return cb();
WalletService._clearBlockchainHeightCache();
return cb();
};
WalletService.shutDown = function(cb) { WalletService.shutDown = function(cb) {
if (!initialized) return cb(); if (!initialized) return cb();
@ -2626,17 +2634,35 @@ WalletService.prototype._normalizeTxHistory = function(txs) {
}); });
}; };
var _lastKnownBlockchainHeight; WalletService._cachedBlockheight;
WalletService.prototype._getLastKnownBlockchainHeight = function(network, cb) { WalletService._clearBlockchainHeightCache = function() {
WalletService._cachedBlockheight.current = null;
};
WalletService.prototype._getBlockchainHeight = function(network, cb) {
var self = this; var self = this;
var bc = self._getBlockchainExplorer(network); var now = Date.now();
bc.getBlockchainHeight(function(err, height) { if (!WalletService._cachedBlockheight) WalletService._cachedBlockheight = {};
if (!err && height > 0) { var cache = WalletService._cachedBlockheight;
_lastKnownBlockchainHeight = height;
} function fetchFromBlockchain(cb) {
return cb(null, _lastKnownBlockchainHeight); var bc = self._getBlockchainExplorer(network);
}); bc.getBlockchainHeight(function(err, height) {
if (!err && height > 0) {
cache.current = height;
cache.last = height;
cache.updatedOn = now;
}
return cb(null, cache.last);
});
};
if (!cache.current || (now - cache.updatedOn) > Defaults.BLOCKHEIGHT_CACHE_TIME * 1000) {
return fetchFromBlockchain(cb);
}
return cb(null, cache.current);
}; };
/** /**
@ -2834,7 +2860,7 @@ WalletService.prototype.getTxHistory = function(opts, cb) {
if (!txs) return next(); if (!txs) return next();
// Fix tx confirmations // Fix tx confirmations
self._getLastKnownBlockchainHeight(network, function(err, height) { self._getBlockchainHeight(network, function(err, height) {
if (err || !height) return next(err); if (err || !height) return next(err);
_.each(txs, function(tx) { _.each(txs, function(tx) {
if (tx.blockheight >= 0) { if (tx.blockheight >= 0) {

View File

@ -6335,64 +6335,97 @@ describe('Wallet service', function() {
it('should get real # of confirmations based on current block height', function(done) { it('should get real # of confirmations based on current block height', function(done) {
var _confirmations = Defaults.CONFIRMATIONS_TO_START_CACHING; var _confirmations = Defaults.CONFIRMATIONS_TO_START_CACHING;
Defaults.CONFIRMATIONS_TO_START_CACHING = 6; Defaults.CONFIRMATIONS_TO_START_CACHING = 6;
WalletService._cachedBlockheight = null;
var h = helpers.historyCacheTest(20); var h = helpers.historyCacheTest(20);
_.each(h, function(x, i) {
x.blockheight = 100 - i;
});
helpers.stubHistory(h); helpers.stubHistory(h);
var storeTxHistoryCacheSpy = sinon.spy(server.storage, 'storeTxHistoryCache'); var storeTxHistoryCacheSpy = sinon.spy(server.storage, 'storeTxHistoryCache');
var skip = 0;
var limit = 20;
blockchainExplorer.getBlockchainHeight = sinon.stub().callsArgWith(0, null, 100); blockchainExplorer.getBlockchainHeight = sinon.stub().callsArgWith(0, null, 100);
// Cache txs
server.getTxHistory({ server.getTxHistory({
skip: skip, skip: 0,
limit: limit, limit: 30,
}, function(err, txs) { }, function(err, txs) {
should.not.exist(err); should.not.exist(err);
should.exist(txs); should.exist(txs);
txs.length.should.equal(limit);
var calls = storeTxHistoryCacheSpy.getCalls(); var calls = storeTxHistoryCacheSpy.getCalls();
calls.length.should.equal(1); calls.length.should.equal(1);
_.first(txs).confirmations.should.equal(82); server.getTxHistory({
_.last(txs).confirmations.should.equal(101); skip: 0,
limit: 30,
}, function(err, txs) {
should.not.exist(err);
txs.length.should.equal(20);
_.first(txs).confirmations.should.equal(1);
_.last(txs).confirmations.should.equal(20);
server.storage.storeTxHistoryCache.restore(); blockchainExplorer.getBlockchainHeight = sinon.stub().callsArgWith(0, null, 200);
Defaults.CONFIRMATIONS_TO_START_CACHING = _confirmations; server._notify('NewBlock', {
done(); hash: 'dummy hash',
}, {
isGlobal: true
}, function(err) {
should.not.exist(err);
setTimeout(function() {
server.getTxHistory({
skip: 0,
limit: 30,
}, function(err, txs) {
should.not.exist(err);
_.first(txs).confirmations.should.equal(101);
_.last(txs).confirmations.should.equal(120);
server.storage.storeTxHistoryCache.restore();
Defaults.CONFIRMATIONS_TO_START_CACHING = _confirmations;
done();
});
}, 100);
});
});
}); });
}); });
it('should get cached # of confirmations if current height unknown', function(done) { it('should get cached # of confirmations if current height unknown', function(done) {
var _confirmations = Defaults.CONFIRMATIONS_TO_START_CACHING; var _confirmations = Defaults.CONFIRMATIONS_TO_START_CACHING;
Defaults.CONFIRMATIONS_TO_START_CACHING = 6; Defaults.CONFIRMATIONS_TO_START_CACHING = 6;
WalletService._cachedBlockheight = null;
var h = helpers.historyCacheTest(20); var h = helpers.historyCacheTest(20);
helpers.stubHistory(h); helpers.stubHistory(h);
var storeTxHistoryCacheSpy = sinon.spy(server.storage, 'storeTxHistoryCache'); var storeTxHistoryCacheSpy = sinon.spy(server.storage, 'storeTxHistoryCache');
var skip = 0;
var limit = 20;
var _getLastKnownBlockchainHeight = server._getLastKnownBlockchainHeight; blockchainExplorer.getBlockchainHeight = sinon.stub().callsArgWith(0, null, null);
server._getLastKnownBlockchainHeight = sinon.stub().callsArgWith(1, null, null);
// Cache txs
server.getTxHistory({ server.getTxHistory({
skip: skip, skip: 0,
limit: limit, limit: 30,
}, function(err, txs) { }, function(err, txs) {
should.not.exist(err); should.not.exist(err);
should.exist(txs); should.exist(txs);
txs.length.should.equal(limit); txs.length.should.equal(20);
var calls = storeTxHistoryCacheSpy.getCalls(); var calls = storeTxHistoryCacheSpy.getCalls();
calls.length.should.equal(1); calls.length.should.equal(1);
_.first(txs).confirmations.should.equal(0); server.getTxHistory({
_.last(txs).confirmations.should.equal(19); skip: 0,
limit: 30,
}, function(err, txs) {
should.not.exist(err);
txs.length.should.equal(20);
_.first(txs).confirmations.should.equal(0);
_.last(txs).confirmations.should.equal(19);
server.storage.storeTxHistoryCache.restore(); server.storage.storeTxHistoryCache.restore();
Defaults.CONFIRMATIONS_TO_START_CACHING = _confirmations; Defaults.CONFIRMATIONS_TO_START_CACHING = _confirmations;
server._getLastKnownBlockchainHeight = _getLastKnownBlockchainHeight; done();
done(); });
}); });
}); });