wip
This commit is contained in:
parent
1cf3d6ccd2
commit
90b0e0e94b
@ -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.
|
||||
|
||||
*/
|
||||
|
||||
|
||||
@ -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);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user