From 1b77fdf5e4a1deab4e547341e39069871b1eef00 Mon Sep 17 00:00:00 2001 From: Chris Kleeschulte Date: Mon, 26 Jun 2017 15:28:22 -0400 Subject: [PATCH] wip --- lib/services/block/index.js | 56 +++++++++++++------------------ test/services/block/index.unit.js | 35 ++++++++++++++++++- 2 files changed, 58 insertions(+), 33 deletions(-) diff --git a/lib/services/block/index.js b/lib/services/block/index.js index 2a90600a..0c5ab433 100644 --- a/lib/services/block/index.js +++ b/lib/services/block/index.js @@ -265,67 +265,59 @@ BlockService.prototype._blockAlreadyProcessed = function(block) { BlockService.prototype._mergeBlockIntoChainTips = function(block) { - function getPrevHashChain(keys, hash) { - - for(var i = 0; i < keys.length; i++) { -console.log('here'); - - var key = keys[i]; - - var searchChain = this._chainTips.get(key); - console.log(searchChain); - - var chainIndex = searchChain.indexOf(hash); - - if (chainIndex > -1) { - return searchChain.slice(chainIndex); - } - } - - } - - var prevHash = utils.reverseBufferToString(block.header.prevHash); var hasChildren = false; var chain = this._chainTips.get(prevHash); + + this._chainTips.del(prevHash); + if (chain) { chain.unshift(prevHash); } var keys = this._chainTips.keys(); - - // looking for chains where this block is an ancestor of the tip of the chain 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(block.hash); if (chainIndex > -1) { hasChildren = true; - var newChain = searchChain.concat(chain || getPrevHashChain(keys, prevHash)); - this._chainTips.set(key, newChain); + this._chainTips.set(key, searchChain.concat(chain || [prevHash])); } - } if (chain && !hasChildren) { - this._chainTips.set(block.hash, chain); - } - this._chainTips.del(prevHash); + if (!chain && !hasChildren) { - // if we have don't have any parents or children in chainTips, then create a new chain with this block - if (!hasChildren && !chain) { - this._chainTips.set(block.hash, getPrevHashChain(keys, prevHash)); + var longestChain = []; + for(var j = 0; j < keys.length; j++) { + var key = keys[j]; + var searchChain = this._chainTips.get(key); + var chainIndex = searchChain.indexOf(prevHash); + if (chainIndex > -1) { + var chain = searchChain.slice(chainIndex); + if (chain.length > longestChain.length) { + longestChain = chain; + } + } + } + longestChain = longestChain.length <= 1 ? [prevHash] : longestChain; + this._chainTips.set(block.hash, longestChain); } +console.log(block.hash); +console.log(this._chainTips); }; +BlockService.prototype._onBlock = function(block) { BlockService.prototype._onBlock = function(block) { // 1. have we already seen this block? diff --git a/test/services/block/index.unit.js b/test/services/block/index.unit.js index 5b140f4a..7651a8d6 100644 --- a/test/services/block/index.unit.js +++ b/test/services/block/index.unit.js @@ -49,7 +49,7 @@ describe('Block Service', function() { expect(blockService._chainTips.get('ee')).to.deep.equal(['dd', 'cc', 'bb', 'aa', '00']); }); - it('should merge chain tips where there is a fork (a parent block has more than one child)' , function() { + it('should merge blocks where there is a fork (a parent block has more than one child)' , function() { var blocks = ['aa','bb','cc','dd','ee']; var prevBlocks = ['00','aa','aa','cc','dd']; @@ -62,8 +62,41 @@ describe('Block Service', function() { 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']); }); + it('should merge blocks where there is a fork (a parent block has more than one child) and blocks are received out of order' , function() { + + var blocks = ['cc','aa','bb','ee','dd']; + var prevBlocks = ['aa','00','aa','dd','cc']; + + blocks.forEach(function(n, index) { + var block = { header: { prevHash: new Buffer(prevBlocks[index], 'hex') }, hash: n }; + 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']); + }); + + it('should merge blocks where there is a three-way fork (a parent block has more than one child) and blocks are received out of order' , function() { + + var blocks = ['cc','aa','bb','ee','dd']; + var prevBlocks = ['aa','00','aa','dd','aa']; + + blocks.forEach(function(n, index) { + var block = { header: { prevHash: new Buffer(prevBlocks[index], 'hex') }, hash: n }; + blockService._mergeBlockIntoChainTips(block); + }); + + + expect(blockService._chainTips.length).to.equal(3); + expect(blockService._chainTips.get('ee')).to.deep.equal(['dd', 'aa', '00']); + expect(blockService._chainTips.get('bb')).to.deep.equal(['aa', '00']); + expect(blockService._chainTips.get('cc')).to.deep.equal(['aa', '00']); + }); });