Skip to content

Commit

Permalink
Fixed tests and repaired reorg logic.
Browse files Browse the repository at this point in the history
  • Loading branch information
Chris Kleeschulte committed Oct 26, 2017
1 parent 299b905 commit 0a4e0dd
Show file tree
Hide file tree
Showing 6 changed files with 77 additions and 30 deletions.
26 changes: 19 additions & 7 deletions bitcore-node.json.sample
Original file line number Diff line number Diff line change
@@ -1,22 +1,34 @@
{
"network": "livenet",
"network": "testnet",
"port": 3001,
"datadir": "/tmp",
"services": [
"p2p",
"db",
"header",
"block",
"mempool",
"address",
"transaction",
"timestamp",
"mempool",
"address"
"fee",
"insight-api",
"web"
],
"servicesConfig": {
"p2p": {
"peers": [
{ "ip": { "v4": "<some trusted full node>" } }
]
"insight-api": {
"routePrefix": "api",
"disableRateLimiter": true,
"enableCache": true
},
"fee": {
"rpc": {
"user": "local",
"pass": "local",
"host": "localhost",
"protocol": "http",
"port": 18332
}
}
}
}
30 changes: 23 additions & 7 deletions lib/services/block/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -421,6 +421,9 @@ BlockService.prototype.syncPercentage = function(callback) {
};

BlockService.prototype._detectReorg = function(block) {
// a block that is regarded as a "reorging block" could be one that was
// mined using a previously-orphaned block as its previous block.
// in this case, we want to completely ignore this block and move on
return bcoin.util.revHex(block.prevBlock) !== this._tip.hash;
};

Expand Down Expand Up @@ -617,7 +620,7 @@ BlockService.prototype._findLatestValidBlockHeader = function(callback) {

async.until(function() {

return iterCount++ >= self._recentBlockHashes.length || header;
return iterCount++ > self._recentBlockHashes.length || header;

}, function(next) {

Expand All @@ -627,15 +630,24 @@ BlockService.prototype._findLatestValidBlockHeader = function(callback) {
return next(err);
}

var hash = blockServiceHash;
var height = blockServiceHeight;

blockServiceHeight--;
blockServiceHash = self._recentBlockHashes.get(hash);

if (!_header) {
// try again with the previous hash of the current hash
return next();
}

if (_header.hash === blockServiceHash && _header.height === blockServiceHeight--) {
// if there was no reorg (the header service just received an orphan block, we should
// get the header of our tip here.
if (_header.hash === hash && _header.height === height) {
header = _header;
return next();
}

blockServiceHash = self._recentBlockHashes.get(blockServiceHash);
next();

});
Expand All @@ -648,9 +660,8 @@ BlockService.prototype._findLatestValidBlockHeader = function(callback) {
// the header could be undefined
// this means that the header service has no record of
// any of our recent block hashes in its indexes.
// this means we've reorged deeper than recentBlockHashesCount number
// of blocks or the header service connected to the wrong chain.
// either way, we can't continue
// if some joker mines a block using an orphan block as its prev block, then the effect of this will be
// us detecting a reorg, but not actually reorging anything
assert(header, 'Block Service: we could not locate any of our recent block hashes in the header service ' +
'index. Perhaps our header service sync\'ed to the wrong chain?');

Expand Down Expand Up @@ -718,7 +729,7 @@ BlockService.prototype._handleReorg = function(callback) {

var self = this;

// we want to ensure that we can reask for previously delievered inventory
// we want to ensure that we can re-ask for previously delievered inventory
self._p2p.clearInventoryCache();

var commonAncestorHeader;
Expand All @@ -734,6 +745,11 @@ BlockService.prototype._handleReorg = function(callback) {
return next(err);
}

// nothing to do, skip and proceed
if (_commonAncestorHeader.hash === self._tip.hash) {
return callback();
}

commonAncestorHeader = _commonAncestorHeader;
next();

Expand Down
30 changes: 25 additions & 5 deletions lib/services/header/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -195,13 +195,33 @@ HeaderService.prototype.start = function(callback) {

self._adjustTipBackToCheckpoint();

if (self._tip.height === 0) {
return self._setGenesisBlock(next);
}
async.waterfall([

self._adjustHeadersForCheckPointTip(next);
function(next) {

if (self._tip.height === 0) {
return self._setGenesisBlock(next);
}

next();

},

function(next) {
self._adjustHeadersForCheckPointTip(next);
}

], function(err) {

if (err) {
return next(err);
}

next();

});
}

},
], function(err) {

if (err) {
Expand Down
14 changes: 6 additions & 8 deletions test/services/block/index.unit.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,22 +44,20 @@ describe('Block Service', function() {
});
});

describe('#_findCommonAncestorAndBlockHashesToRemove', function() {
describe('#_findLatestValidBlockHeader', function() {

it('should find the common ancestor and hashes between the current chain and the new chain', function(done) {
it('should find the latest valid block header whose hash is also in our block index', function(done) {

sandbox.stub(blockService, '_getBlock').callsArgWith(1, null, block2);
blockService._tip = { hash: 'aa' };
var headers = new utils.SimpleMap();
blockService._tip = { hash: 'aa', height: 2 };

blockService._header = { getBlockHeader: sandbox.stub().callsArgWith(1, null, { hash: 'bb' }) };
blockService._findCommonAncestorAndBlockHashesToRemove(function(err, header, hashes) {
blockService._header = { getBlockHeader: sandbox.stub().callsArgWith(1, null, { hash: 'aa', height: 2 }) };
blockService._findLatestValidBlockHeader(function(err, header) {

if(err) {
return done(err);
}

expect(header).to.deep.equal({ hash: 'bb' });
expect(header).to.deep.equal({ hash: 'aa', height: 2 });
done();

});
Expand Down
2 changes: 1 addition & 1 deletion test/services/header/index.unit.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ describe('Header Service', function() {

headerService.start(function() {
expect(setGenesisBlock.calledOnce).to.be.true;
expect(adjustHeadersForCheckPointTip.calledOnce).to.be.false;
expect(adjustHeadersForCheckPointTip.calledOnce).to.be.true;
expect(setListeners.calledOnce).to.be.true;
expect(headerService._tip).to.be.deep.equal({ height: 0, hash: '00' });
expect(headerService._encoding).to.be.instanceOf(Encoding);
Expand Down
5 changes: 3 additions & 2 deletions test/services/mempool/index.unit.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,10 @@ describe('Mempool Service', function() {

it('should get the db prefix', function(done) {
var getPrefix = sandbox.stub().callsArgWith(1, null, new Buffer('0001', 'hex'));
var startSubs = sandbox.stub(mempoolService, '_startSubscriptions');
mempoolService._db = { getPrefix: getPrefix };

mempoolService.start(function() {
expect(getPrefix.calledOnce).to.be.true;
expect(startSubs.calledOnce).to.be.true;
done();
});
});
Expand Down Expand Up @@ -82,6 +80,9 @@ describe('Mempool Service', function() {

describe('#_onBlock', function() {
it('should remove block\'s txs from database', function(done) {
mempoolService.node = { openBus: sinon.stub() };
mempoolService._p2p = { getMempool: sinon.stub() };
sandbox.stub(mempoolService, '_startSubscriptions');
mempoolService.enable();
mempoolService.onBlock(block, function(err, ops) {
expect(ops[0].type).to.deep.equal('del');
Expand Down

0 comments on commit 0a4e0dd

Please sign in to comment.