This commit is contained in:
Chris Kleeschulte 2017-07-06 14:54:53 -04:00
parent 14c54a2fbf
commit ee9a3682b4
2 changed files with 52 additions and 21 deletions

View File

@ -12,18 +12,17 @@ var assert = require('assert');
var BN = require('bn.js');
var consensus = require('bcoin').consensus;
var constants = require('../../constants');
var async = require('async');
var BlockService = function(options) {
BaseService.call(this, options);
this._tip = null;
this._headerTip = null;
this._p2p = this.node.services.p2p;
this._db = this.node.services.db;
this._subscriptions = {};
this._subscriptions.block = [];
this._subscriptions.reorg = [];
this._heightIndex = []; // tracks block height to block hash
this._latestHeaderHashReceived = null;
this._heightIndex = null; // tracks block height to block hash
this._blockHeaderQueue = LRU({
max: 50,
length: function(n) {
@ -113,6 +112,21 @@ BlockService.prototype.unsubscribe = function(name, emitter) {
};
// --- start private prototype functions
BlockService.prototype._applyHeaderHeights = function() {
var genesis = constants.BITCOIN_GENESIS_HASH[this.node.getNetworkName()];
this._heightIndex = new Array(this._blockHeaderQueue.length + 1);
this._heightIndex.push(genesis);
var _tip = this._latestHeaderHashReceived;
while (_tip !== genesis) {
this._heightIndex.push(_tip);
_tip = this._blockHeaderQueue.get(_tip).prevHash;
}
};
BlockService.prototype._blockAlreadyProcessed = function(block) {
return this._blockHeaderQueue.get(block.hash) ? true : false;
@ -150,13 +164,16 @@ BlockService.prototype._cacheBlock = function(block) {
BlockService.prototype._cacheHeader = function(header) {
// 1. save to in-memory cache first
// 1. put a height on the haeder
header.height = ++this._latestBlockHeight;
// 2. save to in-memory cache first
this._blockHeaderQueue.set(header.hash, header.toObject());
// 2. save to in-memory map block index
// 3. save to in-memory map block index
this._heightIndex.push(header);
// 3. get operations
// 4. get operations
return this._getHeaderOperations(header);
};
@ -470,6 +487,11 @@ BlockService.prototype._isOrphanBlock = function(block) {
BlockService.prototype._loadHeaders = function(cb) {
// on initial sync of headers...we don't have block heights with the headers
// we just have a list of headers that have a prevhash pointer and that's about it
// we can't be sure that headers have arrived in order, so we can pick the last header
// that came in and work backwards to the genesis block. If we don't process exactly the
// number of total blocks, then we know we did not really have the last header and we should try again
var self = this;
var start = self._encoding.encodeHashKey(new Array(65).join('0'));
var end = Buffer.concat([ utils.getTerminalKey(start.slice(0, 3)), start.slice(3) ]);
@ -513,18 +535,6 @@ BlockService.prototype._loadHeights = function(cb) {
BlockService.prototype._loadTip = function() {
var self = this;
self._db.getServiceTip('block');
async.parallel([
self._loadHeaders.bind(self),
self._loadHeights.bind(self)
], function(err) {
if (err) {
self._onDbError(err);
return;
}
self._setHeaderTip();
self._startSubscriptions();
self._startSync('header');
});
};
BlockService.prototype._onBestHeight = function(height) {
@ -606,6 +616,8 @@ BlockService.prototype._onTipBlock = function(tip) {
}
self._startSync('header');
};
BlockService.prototype._reportBootStatus = function() {
@ -692,7 +704,7 @@ BlockService.prototype._setTip = function(block) {
BlockService.prototype._startSync = function(type) {
var currentHeight = type === 'block' ? this._tip.height : this._headerTip.height;
var currentHeight = type === 'block' ? this._tip.height : 0; //we gather all headers on each boot
this._numNeeded = this._bestHeight - currentHeight;
this._numCompleted = currentHeight;
if (this._numNeeded <= 0) {
@ -750,7 +762,7 @@ BlockService.prototype._sync = function(type) {
if (counter > 0) {
log.info(name + ' download progress: ' + this._numCompleted + '/' +
log.debug(name + ' download progress: ' + this._numCompleted + '/' +
this._numNeeded + ' (' + (this._numCompleted/this._numNeeded*100).toFixed(2) + '%)');
func.call(this._p2p, obj);
return;
@ -758,7 +770,8 @@ BlockService.prototype._sync = function(type) {
}
if ('header') {
this._startSync('block');
// we are done loading headers, proceed to number them
this._applyHeaderHeights(this._startSync.bind(this, 'block'));
}
};

View File

@ -22,6 +22,24 @@ describe('Block Service', function() {
blockService._encoding = new Encoding(new Buffer('0000', 'hex'));
});
describe.only('#_applyHeaderHeights', function() {
it('should apply heights to the list of headers', function() {
var genesis = '0f9188f13cb7b2c71f2a335e3a4fc328bf5beb436012afca590b1a11466e2206';
blockService._blockHeaderQueue = LRU(100);
blockService._blockHeaderQueue.set(genesis, { prevHash: '00' });
blockService._latestHeaderHashReceived = '100';
blockService.node = { getNetworkName: function() { return 'regtest'; } };
for(var i = 0; i < 99; i++) {
var prevHash = i.toString();
if (i === 0) {
prevHash = genesis;
}
blockService._blockHeaderQueue.set((i+1).toString(), { prevHash: prevHash });
}
blockService._applyHeaderHeights();
});
});
describe('#_blockAlreadyProcessed', function() {
it('should detect that a block has already been delivered to us', function() {