blocks: added lru cache

This commit is contained in:
Braydon Fuller 2016-03-23 12:57:26 -04:00
parent 13efeec84b
commit 3c355c30a9
3 changed files with 86 additions and 50 deletions

View File

@ -90,7 +90,7 @@ AddressController.prototype.checkAddrs = function(req, res, next) {
} }
this.check(req, res, next, req.addrs); this.check(req, res, next, req.addrs);
} };
AddressController.prototype.check = function(req, res, next, addresses) { AddressController.prototype.check = function(req, res, next, addresses) {
if(!addresses.length || !addresses[0]) { if(!addresses.length || !addresses[0]) {

View File

@ -5,11 +5,16 @@ var async = require('async');
var bitcore = require('bitcore-lib'); var bitcore = require('bitcore-lib');
var pools = require('../pools.json'); var pools = require('../pools.json');
var BN = bitcore.crypto.BN; var BN = bitcore.crypto.BN;
var LRU = require('lru-cache');
function BlockController(node) { function BlockController(node) {
var self = this; var self = this;
this.node = node; this.node = node;
this.blockSummaryCache = LRU(1000000);
this.blockCache = LRU(1000);
this.poolStrings = {}; this.poolStrings = {};
pools.forEach(function(pool) { pools.forEach(function(pool) {
pool.searchStrings.forEach(function(s) { pool.searchStrings.forEach(function(s) {
@ -29,23 +34,34 @@ var BLOCK_LIMIT = 200;
BlockController.prototype.block = function(req, res, next, hash) { BlockController.prototype.block = function(req, res, next, hash) {
var self = this; var self = this;
this.node.getBlock(hash, function(err, block) { function finish(blockResult) {
if(err && err.message === 'Block not found.') { blockResult.confirmations = self.node.services.bitcoind.height - blockResult.height + 1;
// TODO libbitcoind should pass an instance of errors.Block.NotFound req.block = blockResult;
return common.handleErrors(null, res); next();
} else if(err) { }
return common.handleErrors(err, res);
}
self.node.services.bitcoind.getBlockHeader(hash, function(err, info) { var block = self.blockCache.get(hash);
if (err) {
if (block) {
finish(block);
} else {
self.node.getBlock(hash, function(err, block) {
if(err && err.message === 'Block not found.') {
// TODO libbitcoind should pass an instance of errors.Block.NotFound
return common.handleErrors(null, res);
} else if(err) {
return common.handleErrors(err, res); return common.handleErrors(err, res);
} }
req.block = self.transformBlock(block, info); self.node.services.bitcoind.getBlockHeader(hash, function(err, info) {
next(); if (err) {
return common.handleErrors(err, res);
}
var blockResult = self.transformBlock(block, info);
self.blockCache.set(hash, blockResult);
finish(blockResult);
});
}); });
}
});
}; };
BlockController.prototype.transformBlock = function(block, info) { BlockController.prototype.transformBlock = function(block, info) {
@ -55,7 +71,6 @@ BlockController.prototype.transformBlock = function(block, info) {
}); });
return { return {
hash: block.hash, hash: block.hash,
confirmations: this.node.services.bitcoind.height - info.height + 1,
size: block.toBuffer().length, size: block.toBuffer().length,
height: info.height, height: info.height,
version: blockObj.header.version, version: blockObj.header.version,
@ -94,6 +109,58 @@ BlockController.prototype.blockIndex = function(req, res, next, height) {
}); });
}; };
BlockController.prototype._getBlockSummary = function(hash, moreTs, next) {
var self = this;
function finish(result) {
if (moreTs > result.time) {
moreTs = result.time;
}
return next(null, result);
}
var summaryCache = self.blockSummaryCache.get(hash);
if (summaryCache) {
finish(summaryCache);
} else {
self.node.services.bitcoind.getRawBlock(hash, function(err, blockBuffer) {
if(err) {
return next(err);
}
var br = new bitcore.encoding.BufferReader(blockBuffer);
// take a shortcut to get number of transactions and the blocksize.
// Also reads the coinbase transaction and only that.
// Old code parsed all transactions in every block _and_ then encoded
// them all back together to get the binary size of the block.
// FIXME: This code might still read the whole block. Fixing that
// would require changes in bitcore-node.
var header = bitcore.BlockHeader.fromBufferReader(br);
var info = {};
var txlength = br.readVarintNum();
info.transactions = [bitcore.Transaction().fromBufferReader(br)];
self.node.services.bitcoind.getBlockHeader(hash, function(err, blockHeader) {
var block = {
height: blockHeader.height,
size: blockBuffer.length,
hash: hash,
time: header.time,
txlength: txlength,
poolInfo: self.getPoolInfo(info)
};
self.blockSummaryCache.set(hash, summary);
finish(block);
});
});
}
};
// List blocks by date // List blocks by date
BlockController.prototype.list = function(req, res) { BlockController.prototype.list = function(req, res) {
var self = this; var self = this;
@ -130,6 +197,8 @@ BlockController.prototype.list = function(req, res) {
return common.handleErrors(err, res); return common.handleErrors(err, res);
} }
hashes.reverse();
if(hashes.length > limit) { if(hashes.length > limit) {
more = true; more = true;
hashes = hashes.slice(0, limit); hashes = hashes.slice(0, limit);
@ -138,41 +207,7 @@ BlockController.prototype.list = function(req, res) {
async.mapSeries( async.mapSeries(
hashes, hashes,
function(hash, next) { function(hash, next) {
self.node.services.bitcoind.getBlock(hash, function(err, blockBuffer) { self._getBlockSummary(hash, moreTs, next);
if(err) {
return next(err);
}
var br = new bitcore.encoding.BufferReader(blockBuffer);
// take a shortcut to get number of transactions and the blocksize.
// Also reads the coinbase transaction and only that.
// Old code parsed all transactions in every block _and_ then encoded
// them all back together to get the binary size of the block.
// FIXME: This code might still read the whole block. Fixing that
// would require changes in bitcore-node.
var header = bitcore.BlockHeader.fromBufferReader(br);
var info = {};
var txlength = br.readVarintNum();
info.transactions = [bitcore.Transaction().fromBufferReader(br)];
self.node.services.bitcoind.getBlockHeader(hash, function(err, blockHeader) {
var block = {
height: blockHeader.height,
size: blockBuffer.length,
hash: hash,
time: header.time,
txlength: txlength,
poolInfo: self.getPoolInfo(info)
};
if(moreTs > header.timestamp) {
moreTs = header.timestamp;
}
return next(null, block);
});
});
}, },
function(err, blocks) { function(err, blocks) {
if(err) { if(err) {

View File

@ -65,6 +65,7 @@
"bitcore-message": "^1.0.1", "bitcore-message": "^1.0.1",
"body-parser": "^1.13.3", "body-parser": "^1.13.3",
"lodash": "^2.4.1", "lodash": "^2.4.1",
"lru-cache": "^4.0.1",
"request": "^2.64.0" "request": "^2.64.0"
}, },
"devDependencies": { "devDependencies": {