more optimizations

This commit is contained in:
Patrick Nagurny 2015-07-07 13:26:12 -04:00
parent 4954be9aa2
commit 938eb53a77
3 changed files with 33 additions and 21 deletions

View File

@ -9,7 +9,6 @@ var NULL = '0000000000000000000000000000000000000000000000000000000000000000';
function BlockChain() { function BlockChain() {
this.tip = NULL; this.tip = NULL;
this.header = {};
this.work = {}; this.work = {};
this.work[NULL] = 0; this.work[NULL] = 0;
this.height = {}; this.height = {};
@ -19,7 +18,7 @@ function BlockChain() {
}; };
this.next = {}; this.next = {};
this.prev = {}; this.prev = {};
this.cachedHeaders = []; this.cache = [];
} }
BlockChain.NULL = NULL; BlockChain.NULL = NULL;
@ -46,7 +45,6 @@ BlockChain.prototype.addData = function(header) {
var prevHash = BufferUtil.reverse(header.prevHash).toString('hex'); var prevHash = BufferUtil.reverse(header.prevHash).toString('hex');
var hash = header.hash; var hash = header.hash;
this.header[hash] = header;
this.work[hash] = this.work[prevHash] + getWork(header.bits); this.work[hash] = this.work[prevHash] + getWork(header.bits);
this.prev[hash] = prevHash; this.prev[hash] = prevHash;
}; };
@ -115,7 +113,7 @@ BlockChain.prototype.confirm = function(hash) {
this.next[prevHash] = hash; this.next[prevHash] = hash;
this.hashByHeight[height] = hash; this.hashByHeight[height] = hash;
this.height[hash] = height; this.height[hash] = height;
this.cachedHeaders.unshift(this.header[hash]); this.cache.push(this.getCachedDataForHash(hash));
}; };
BlockChain.prototype.unconfirm = function(hash) { BlockChain.prototype.unconfirm = function(hash) {
@ -127,7 +125,7 @@ BlockChain.prototype.unconfirm = function(hash) {
delete this.next[prevHash]; delete this.next[prevHash];
delete this.hashByHeight[height]; delete this.hashByHeight[height];
delete this.height[hash]; delete this.height[hash];
this.cachedHeaders.shift(); this.cache.pop();
}; };
BlockChain.prototype.hasData = function(hash) { BlockChain.prototype.hasData = function(hash) {
@ -183,8 +181,24 @@ BlockChain.prototype.getCurrentHeight = function() {
return this.height[this.tip]; return this.height[this.tip];
}; };
BlockChain.prototype.getHeaders = function() { BlockChain.prototype.loadFromCache = function(cache) {
return this.cachedHeaders; for(var i = 0; i < cache.length; i++) {
this.prev[cache[i].hash] = cache[i].prevHash;
this.work[cache[i].hash] = cache[i].work;
this.confirm(cache[i].hash);
}
};
BlockChain.prototype.getCache = function() {
return this.cache;
};
BlockChain.prototype.getCachedDataForHash = function(hash) {
return {
hash: hash,
prevHash: this.prev[hash],
work: this.work[hash]
};
}; };
module.exports = BlockChain; module.exports = BlockChain;

View File

@ -131,7 +131,7 @@ BitcoreNode.prototype.initialize = function() {
.then(function() { .then(function() {
// Update header cache every 100 blocks // Update header cache every 100 blocks
if(block.height % 100 === 0) { if(block.height % 100 === 0) {
return self.blockService.saveHeaders(self.blockchain.getHeaders()) return self.blockService.saveBlockchainCache(self.blockchain.getCache());
} }
}) })
.catch(function(error) { .catch(function(error) {

View File

@ -39,7 +39,7 @@ var Index = {
tip: 'tip', // tip -> { hash: hex, height: int }, the latest tip tip: 'tip', // tip -> { hash: hex, height: int }, the latest tip
work: 'wk-', // wk-<hash> -> amount of work for block work: 'wk-', // wk-<hash> -> amount of work for block
header: 'header-', // header-<hash> -> JSON for block header header: 'header-', // header-<hash> -> JSON for block header
headersCached: 'hc-' blockchain: 'bc-'
}; };
_.extend(Index, { _.extend(Index, {
getNextBlock: helper(Index.next), getNextBlock: helper(Index.next),
@ -49,7 +49,7 @@ _.extend(Index, {
getBlockByTs: function(block) { getBlockByTs: function(block) {
return Index.timestamp + block.header.time; return Index.timestamp + block.header.time;
}, },
getBlockHeader: helper(Index.header) getBlockHeader: helper(Index.header),
}); });
function BlockService(opts) { function BlockService(opts) {
@ -469,26 +469,22 @@ BlockService.prototype.getBlockchain = function() {
console.log('Fetching hashes from db...'); console.log('Fetching hashes from db...');
return self.database.getAsync(Index.headersCached, {valueEncoding: 'json'}) return self.database.getAsync(Index.blockchain, {valueEncoding: 'json'})
.catch(function(err) { .catch(function(err) {
if(err instanceof LevelUp.errors.NotFoundError) { if(err instanceof LevelUp.errors.NotFoundError) {
return []; return [];
} }
throw err; throw err;
}) })
.then(function(cachedHeaders) { .then(function(blockchainCache) {
console.log(cachedHeaders.length + ' headers cached'); console.log(blockchainCache.length + ' headers cached');
cachedHeaders = cachedHeaders.map(function(json) {
return bitcore.Block.BlockHeader.fromJSON(json);
});
console.log('Cached headers parsed. Loading remaining headers from DB');
var fetchHeader = function(blockHash) { var fetchHeader = function(blockHash) {
if (blockHash === BlockChain.NULL) { if (blockHash === BlockChain.NULL) {
console.log('All headers fetched, total =', headers.length); console.log('All headers fetched, total =', headers.length);
return Promise.resolve(); return Promise.resolve();
} else if(cachedHeaders[0] && cachedHeaders[0].hash === blockHash) { } else if(blockchainCache.length && blockchainCache[blockchainCache.length - 1].hash === blockHash) {
headers = headers.concat(cachedHeaders); console.log(headers.length + ' non-cached headers loaded');
return Promise.resolve(); return Promise.resolve();
} }
var headerKey = Index.getBlockHeader(blockHash); var headerKey = Index.getBlockHeader(blockHash);
@ -512,6 +508,8 @@ BlockService.prototype.getBlockchain = function() {
return fetchHeader(tip) return fetchHeader(tip)
.then(function() { .then(function() {
blockchain.loadFromCache(blockchainCache);
while (headers.length !== 0) { while (headers.length !== 0) {
var header = headers.pop(); var header = headers.pop();
blockchain.proposeNewHeader(header); blockchain.proposeNewHeader(header);
@ -522,8 +520,8 @@ BlockService.prototype.getBlockchain = function() {
}); });
}; };
BlockService.prototype.saveHeaders = function(headers) { BlockService.prototype.saveBlockchainCache = function(cache) {
return this.database.putAsync(Index.headersCached, JSON.stringify(headers)); return this.database.putAsync(Index.blockchain, JSON.stringify(cache));
} }
module.exports = BlockService; module.exports = BlockService;