From 3c355c30a9fee884a02672e077b27b1acd8de6b6 Mon Sep 17 00:00:00 2001 From: Braydon Fuller Date: Wed, 23 Mar 2016 12:57:26 -0400 Subject: [PATCH] blocks: added lru cache --- lib/addresses.js | 2 +- lib/blocks.js | 133 ++++++++++++++++++++++++++++++----------------- package.json | 1 + 3 files changed, 86 insertions(+), 50 deletions(-) diff --git a/lib/addresses.js b/lib/addresses.js index 765faab..065375b 100644 --- a/lib/addresses.js +++ b/lib/addresses.js @@ -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]) { diff --git a/lib/blocks.js b/lib/blocks.js index 6b95a74..96a7edf 100644 --- a/lib/blocks.js +++ b/lib/blocks.js @@ -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) { diff --git a/package.json b/package.json index 869fd93..8eb0f77 100644 --- a/package.json +++ b/package.json @@ -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": {