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);
}
};
AddressController.prototype.check = function(req, res, next, addresses) {
if(!addresses.length || !addresses[0]) {

View File

@ -5,11 +5,16 @@ var async = require('async');
var bitcore = require('bitcore-lib');
var pools = require('../pools.json');
var BN = bitcore.crypto.BN;
var LRU = require('lru-cache');
function BlockController(node) {
var self = this;
this.node = node;
this.blockSummaryCache = LRU(1000000);
this.blockCache = LRU(1000);
this.poolStrings = {};
pools.forEach(function(pool) {
pool.searchStrings.forEach(function(s) {
@ -29,23 +34,34 @@ var BLOCK_LIMIT = 200;
BlockController.prototype.block = function(req, res, next, hash) {
var self = this;
this.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);
}
function finish(blockResult) {
blockResult.confirmations = self.node.services.bitcoind.height - blockResult.height + 1;
req.block = blockResult;
next();
}
self.node.services.bitcoind.getBlockHeader(hash, function(err, info) {
if (err) {
var block = self.blockCache.get(hash);
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);
}
req.block = self.transformBlock(block, info);
next();
self.node.services.bitcoind.getBlockHeader(hash, function(err, info) {
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) {
@ -55,7 +71,6 @@ BlockController.prototype.transformBlock = function(block, info) {
});
return {
hash: block.hash,
confirmations: this.node.services.bitcoind.height - info.height + 1,
size: block.toBuffer().length,
height: info.height,
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
BlockController.prototype.list = function(req, res) {
var self = this;
@ -130,6 +197,8 @@ BlockController.prototype.list = function(req, res) {
return common.handleErrors(err, res);
}
hashes.reverse();
if(hashes.length > limit) {
more = true;
hashes = hashes.slice(0, limit);
@ -138,41 +207,7 @@ BlockController.prototype.list = function(req, res) {
async.mapSeries(
hashes,
function(hash, next) {
self.node.services.bitcoind.getBlock(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)
};
if(moreTs > header.timestamp) {
moreTs = header.timestamp;
}
return next(null, block);
});
});
self._getBlockSummary(hash, moreTs, next);
},
function(err, blocks) {
if(err) {

View File

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