Fixed tests and repaired reorg logic.
This commit is contained in:
parent
299b905d5b
commit
0a4e0dd9fd
@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"network": "livenet",
|
"network": "testnet",
|
||||||
"port": 3001,
|
"port": 3001,
|
||||||
"datadir": "/tmp",
|
"datadir": "/tmp",
|
||||||
"services": [
|
"services": [
|
||||||
@ -7,16 +7,28 @@
|
|||||||
"db",
|
"db",
|
||||||
"header",
|
"header",
|
||||||
"block",
|
"block",
|
||||||
|
"mempool",
|
||||||
|
"address",
|
||||||
"transaction",
|
"transaction",
|
||||||
"timestamp",
|
"timestamp",
|
||||||
"mempool",
|
"fee",
|
||||||
"address"
|
"insight-api",
|
||||||
|
"web"
|
||||||
],
|
],
|
||||||
"servicesConfig": {
|
"servicesConfig": {
|
||||||
"p2p": {
|
"insight-api": {
|
||||||
"peers": [
|
"routePrefix": "api",
|
||||||
{ "ip": { "v4": "<some trusted full node>" } }
|
"disableRateLimiter": true,
|
||||||
]
|
"enableCache": true
|
||||||
|
},
|
||||||
|
"fee": {
|
||||||
|
"rpc": {
|
||||||
|
"user": "local",
|
||||||
|
"pass": "local",
|
||||||
|
"host": "localhost",
|
||||||
|
"protocol": "http",
|
||||||
|
"port": 18332
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -421,6 +421,9 @@ BlockService.prototype.syncPercentage = function(callback) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
BlockService.prototype._detectReorg = function(block) {
|
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;
|
return bcoin.util.revHex(block.prevBlock) !== this._tip.hash;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -617,7 +620,7 @@ BlockService.prototype._findLatestValidBlockHeader = function(callback) {
|
|||||||
|
|
||||||
async.until(function() {
|
async.until(function() {
|
||||||
|
|
||||||
return iterCount++ >= self._recentBlockHashes.length || header;
|
return iterCount++ > self._recentBlockHashes.length || header;
|
||||||
|
|
||||||
}, function(next) {
|
}, function(next) {
|
||||||
|
|
||||||
@ -627,15 +630,24 @@ BlockService.prototype._findLatestValidBlockHeader = function(callback) {
|
|||||||
return next(err);
|
return next(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var hash = blockServiceHash;
|
||||||
|
var height = blockServiceHeight;
|
||||||
|
|
||||||
|
blockServiceHeight--;
|
||||||
|
blockServiceHash = self._recentBlockHashes.get(hash);
|
||||||
|
|
||||||
if (!_header) {
|
if (!_header) {
|
||||||
|
// try again with the previous hash of the current hash
|
||||||
return next();
|
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;
|
header = _header;
|
||||||
|
return next();
|
||||||
}
|
}
|
||||||
|
|
||||||
blockServiceHash = self._recentBlockHashes.get(blockServiceHash);
|
|
||||||
next();
|
next();
|
||||||
|
|
||||||
});
|
});
|
||||||
@ -648,9 +660,8 @@ BlockService.prototype._findLatestValidBlockHeader = function(callback) {
|
|||||||
// the header could be undefined
|
// the header could be undefined
|
||||||
// this means that the header service has no record of
|
// this means that the header service has no record of
|
||||||
// any of our recent block hashes in its indexes.
|
// any of our recent block hashes in its indexes.
|
||||||
// this means we've reorged deeper than recentBlockHashesCount number
|
// if some joker mines a block using an orphan block as its prev block, then the effect of this will be
|
||||||
// of blocks or the header service connected to the wrong chain.
|
// us detecting a reorg, but not actually reorging anything
|
||||||
// either way, we can't continue
|
|
||||||
assert(header, 'Block Service: we could not locate any of our recent block hashes in the header service ' +
|
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?');
|
'index. Perhaps our header service sync\'ed to the wrong chain?');
|
||||||
|
|
||||||
@ -718,7 +729,7 @@ BlockService.prototype._handleReorg = function(callback) {
|
|||||||
|
|
||||||
var self = this;
|
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();
|
self._p2p.clearInventoryCache();
|
||||||
|
|
||||||
var commonAncestorHeader;
|
var commonAncestorHeader;
|
||||||
@ -734,6 +745,11 @@ BlockService.prototype._handleReorg = function(callback) {
|
|||||||
return next(err);
|
return next(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// nothing to do, skip and proceed
|
||||||
|
if (_commonAncestorHeader.hash === self._tip.hash) {
|
||||||
|
return callback();
|
||||||
|
}
|
||||||
|
|
||||||
commonAncestorHeader = _commonAncestorHeader;
|
commonAncestorHeader = _commonAncestorHeader;
|
||||||
next();
|
next();
|
||||||
|
|
||||||
|
|||||||
@ -195,13 +195,33 @@ HeaderService.prototype.start = function(callback) {
|
|||||||
|
|
||||||
self._adjustTipBackToCheckpoint();
|
self._adjustTipBackToCheckpoint();
|
||||||
|
|
||||||
if (self._tip.height === 0) {
|
async.waterfall([
|
||||||
return self._setGenesisBlock(next);
|
|
||||||
}
|
|
||||||
|
|
||||||
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) {
|
], function(err) {
|
||||||
|
|
||||||
if (err) {
|
if (err) {
|
||||||
|
|||||||
@ -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', height: 2 };
|
||||||
blockService._tip = { hash: 'aa' };
|
|
||||||
var headers = new utils.SimpleMap();
|
|
||||||
|
|
||||||
blockService._header = { getBlockHeader: sandbox.stub().callsArgWith(1, null, { hash: 'bb' }) };
|
blockService._header = { getBlockHeader: sandbox.stub().callsArgWith(1, null, { hash: 'aa', height: 2 }) };
|
||||||
blockService._findCommonAncestorAndBlockHashesToRemove(function(err, header, hashes) {
|
blockService._findLatestValidBlockHeader(function(err, header) {
|
||||||
|
|
||||||
if(err) {
|
if(err) {
|
||||||
return done(err);
|
return done(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
expect(header).to.deep.equal({ hash: 'bb' });
|
expect(header).to.deep.equal({ hash: 'aa', height: 2 });
|
||||||
done();
|
done();
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|||||||
@ -52,7 +52,7 @@ describe('Header Service', function() {
|
|||||||
|
|
||||||
headerService.start(function() {
|
headerService.start(function() {
|
||||||
expect(setGenesisBlock.calledOnce).to.be.true;
|
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(setListeners.calledOnce).to.be.true;
|
||||||
expect(headerService._tip).to.be.deep.equal({ height: 0, hash: '00' });
|
expect(headerService._tip).to.be.deep.equal({ height: 0, hash: '00' });
|
||||||
expect(headerService._encoding).to.be.instanceOf(Encoding);
|
expect(headerService._encoding).to.be.instanceOf(Encoding);
|
||||||
|
|||||||
@ -32,12 +32,10 @@ describe('Mempool Service', function() {
|
|||||||
|
|
||||||
it('should get the db prefix', function(done) {
|
it('should get the db prefix', function(done) {
|
||||||
var getPrefix = sandbox.stub().callsArgWith(1, null, new Buffer('0001', 'hex'));
|
var getPrefix = sandbox.stub().callsArgWith(1, null, new Buffer('0001', 'hex'));
|
||||||
var startSubs = sandbox.stub(mempoolService, '_startSubscriptions');
|
|
||||||
mempoolService._db = { getPrefix: getPrefix };
|
mempoolService._db = { getPrefix: getPrefix };
|
||||||
|
|
||||||
mempoolService.start(function() {
|
mempoolService.start(function() {
|
||||||
expect(getPrefix.calledOnce).to.be.true;
|
expect(getPrefix.calledOnce).to.be.true;
|
||||||
expect(startSubs.calledOnce).to.be.true;
|
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -82,6 +80,9 @@ describe('Mempool Service', function() {
|
|||||||
|
|
||||||
describe('#_onBlock', function() {
|
describe('#_onBlock', function() {
|
||||||
it('should remove block\'s txs from database', function(done) {
|
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.enable();
|
||||||
mempoolService.onBlock(block, function(err, ops) {
|
mempoolService.onBlock(block, function(err, ops) {
|
||||||
expect(ops[0].type).to.deep.equal('del');
|
expect(ops[0].type).to.deep.equal('del');
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user