From 90b0e0e94b2dfb8a499bbdc1ffcad6b822f1804d Mon Sep 17 00:00:00 2001 From: Chris Kleeschulte Date: Wed, 28 Jun 2017 18:54:15 -0400 Subject: [PATCH] wip --- lib/services/block/index.js | 94 ++++++++++++++----------------- test/services/block/index.unit.js | 16 +++--- 2 files changed, 50 insertions(+), 60 deletions(-) diff --git a/lib/services/block/index.js b/lib/services/block/index.js index c38da518..aeb20b99 100644 --- a/lib/services/block/index.js +++ b/lib/services/block/index.js @@ -25,7 +25,7 @@ var BlockService = function(options) { return n.length * (1 * 1024 * 1024); // 50 MB of blocks } }); // header -> block - this._chainTips = LRU(50); // chain tip -> [ tip-1 hash, tip-2 hash, tip-N hash] + this._chainTips = LRU(50); // chain tip hash -> [ tip-prev hash, tip-prevprev hash, tip-prevprevprev hash, ... ] }; inherits(BlockService, BaseService); @@ -47,22 +47,23 @@ BlockService.prototype.start = function(callback) { self._setListeners(); callback(); }); + }; BlockService.prototype.stop = function(callback) { + if (callback) { setImmediate(callback); } }; BlockService.prototype.getAPIMethods = function() { - var methods = [ - ['processBlockOperations', this, this.processBlockOperations, 1] - ]; + var methods = []; return methods; }; BlockService.prototype.getPublishEvents = function() { + return [ { name: 'block/block', @@ -77,61 +78,35 @@ BlockService.prototype.getPublishEvents = function() { unsubscribe: this.unsubscribe.bind(this, 'reorg') } ]; + }; - BlockService.prototype.subscribe = function(name, emitter) { + this._subscriptions[name].push(emitter); log.info(emitter.remoteAddress, 'subscribe:', 'block/' + name, 'total:', this._subscriptions[name].length); + }; BlockService.prototype.unsubscribe = function(name, emitter) { + var index = this._subscriptions[name].indexOf(emitter); + if (index > -1) { this._subscriptions[name].splice(index, 1); } + log.info(emitter.remoteAddress, 'unsubscribe:', 'block/' + name, 'total:', this._subscriptions[name].length); -}; - -BlockService.prototype._printTipInfo = function(prependedMessage) { - - log.info( - prependedMessage + ' Serial Tip: ' + this.tip.hash + - ' Concurrent tip: ' + this.concurrentTip.hash - ); }; BlockService.prototype._reportBootStatus = function() { + var blockInfoString = utils.getBlockInfoString(this.tip.height, this.bestHeight); + log.info('Block Service tip is currently height: ' + this.tip.height + ' hash: ' + - this.tip.hash + ' P2P network best height: ' + this.bestHeight + '. Block Service is: ' + + this.tip.hash + ' P2P network best height: ' + this._bestHeight + '. Block Service is: ' + blockInfoString); -}; - -BlockService.prototype.processBlockOperations = function(opts, callback) { - - if (!_.isArray(opts.operations)) { - return; - } - - var self = this; - - self._db.batch(opts.operations, function(err) { - - if(err) { - return callback(err); - } - - if (!opts.serviceName) { - opts.serviceName = 'unknown'; - } - - self.setTip(opts); - self._reportStatus(opts.serviceName); - - callback(); - }); }; @@ -155,18 +130,21 @@ BlockService.prototype._startSubscriptions = function() { }; BlockService.prototype._onHeaders = function(headers) { + log.info('New headers received.'); this._cacheHeaders(headers); + }; BlockService.prototype._blockAlreadyProcessed = function(block) { + return this._blockHeaderQueue.get(block.hash); + }; BlockService.prototype._mergeBlockIntoChainTips = function(block) { var prevHash = utils.reverseBufferToString(block.header.prevHash); - var hasChildren = false; var chain = this._chainTips.get(prevHash); @@ -177,8 +155,7 @@ BlockService.prototype._mergeBlockIntoChainTips = function(block) { } var longestChain = this._findLongestChainForHash(prevHash); - hasChildren = this._setChainOnTip(block.hash, chain, longestChain); - + var hasChildren = this._setChainOnTip(block.hash, chain, longestChain); if (!hasChildren) { this._chainTips.set(block.hash, chain || longestChain); @@ -209,20 +186,28 @@ BlockService.prototype._setChainOnTip = function(hash, chain, longestPrevChain) }; BlockService.prototype._findLongestChainForHash = function(hash) { + var longestChain = []; var keys = this._chainTips.keys(); - for(var j = 0; j < keys.length; j++) { - var key = keys[j]; + + for(var i = 0; i < keys.length; i++) { + + var key = keys[i]; var searchChain = this._chainTips.get(key); + assert(searchChain.length > 0, 'chain tips collection appears to be invalid'); + var chainIndex = searchChain.indexOf(hash); + if (chainIndex > -1) { + var chain = searchChain.slice(chainIndex); if (chain.length > longestChain.length) { longestChain = chain; } } } + longestChain = longestChain.length <= 1 ? [hash] : longestChain; return longestChain; }; @@ -261,16 +246,24 @@ BlockService.prototype._onBlock = function(block) { }; -BlockService.prototype._selectActiveChain = function(block) { +BlockService.prototype._selectActiveChain = function(hash) { + // the active chain is the one that the passed in block hash has as its tip. + // there can only be one without there being a ambiguous situation. + // If more than one chain does have the latest incoming block, then we have a reorg + // situation on our hands and the active chain will be decided elsewhere + }; -BlockService.prototype._getAllUnsentBlocksFromActiveChain = function(tip) { +BlockService.prototype._getAllUnsentBlocksFromActiveChain = function(block) { + + var blocksToSend = [block]; if (!this._chainTips.get(block.hash)) { var keys = this._chainTips.keys(); for(var i = 0; i < keys.length; i++) { + var key = keys[i]; var searchChain = this._chainTips.get(key); var index = searchChain.indexOf(block.hash); @@ -281,7 +274,6 @@ BlockService.prototype._getAllUnsentBlocksFromActiveChain = function(tip) { blocksToSend.concat(additionalBlocks); blocksToSend.reverse(); break; - } } } @@ -358,8 +350,6 @@ BlockService.prototype._findCommonAncestor = function(block) { var oldChain = this._chainTips.get(this.tip.hash); var newChain = this._chainTips.get(block.hash); - // if there is more than one chain tip collection that contains this blocks, how do we know which one if the real chain? - // the blocks to come will decide for sure. if (!newChain) { newChain = this._findLongestChainForHash(block.hash); } @@ -404,9 +394,9 @@ BlockService.prototype._determineBlockState = function(block) { In point 1, waiting longer for blocks to arrive is the best action. In point 2, waiting won't help. The block's parent block may be in an orphaned chain and this chain may - never become the main chain. Also, your peers may nor may not give you all the parent blocks for this orphan chain. - It is best to not assign this block a height until all of its parents are linked. We should, however, call getBlocks with - startHash of our tip and end hash of the list of orphaned blocks periodically. + never become the main chain. Also, your peers may nor may not give you all the parent blocks for this orphan + chain. It is best to not assign this block a height until all of its parents are linked. We should, however, + call getBlocks with startHash of our tip and end hash of the list of orphaned blocks periodically. */ diff --git a/test/services/block/index.unit.js b/test/services/block/index.unit.js index ab886ebe..dbdf8ca2 100644 --- a/test/services/block/index.unit.js +++ b/test/services/block/index.unit.js @@ -59,7 +59,6 @@ describe('Block Service', function() { blockService._mergeBlockIntoChainTips(block); }); - expect(blockService._chainTips.length).to.equal(2); expect(blockService._chainTips.get('ee')).to.deep.equal(['dd', 'cc', 'aa', '00']); expect(blockService._chainTips.get('bb')).to.deep.equal(['aa', '00']); @@ -156,16 +155,17 @@ describe('Block Service', function() { }); describe('Send all unsent blocks from main chain', function() { - var blocks = ['ee','aa','bb','dd','cc']; - var prevBlocks = ['dd','00','aa','cc','bb']; - blocks.forEach(function(n, index) { - var block = { header: { prevHash: new Buffer(prevBlocks[index], 'hex') }, hash: n }; - blockService._mergeBlockIntoChainTips(block); + it('should send all unsent blocks from the active/main chain', function() { + var blocks = ['ee','aa','bb','dd','cc']; + var prevBlocks = ['dd','00','aa','cc','bb']; + + blocks.forEach(function(n, index) { + var block = { header: { prevHash: new Buffer(prevBlocks[index], 'hex') }, hash: n }; + blockService._mergeBlockIntoChainTips(block); + }); }); - - }); });