From 82dd1dfe3f3ec3899681983ff4f01331afb87c96 Mon Sep 17 00:00:00 2001 From: Chris Kleeschulte Date: Fri, 8 Sep 2017 14:18:55 -0400 Subject: [PATCH] Fixed reorging. --- lib/services/address/index.js | 1 + lib/services/header/index.js | 62 +++++++++++++++++++++---- package-lock.json | 2 +- test/services/transaction/index.unit.js | 10 ++-- 4 files changed, 61 insertions(+), 14 deletions(-) diff --git a/lib/services/address/index.js b/lib/services/address/index.js index 8cfaa819..fcde178a 100644 --- a/lib/services/address/index.js +++ b/lib/services/address/index.js @@ -18,6 +18,7 @@ var AddressService = function(options) { this._header = this.node.services.header; this._block = this.node.services.block; this._timestamp = this.node.services.timestamp; + this._transaction = this.node.services.transaction; this._network = this.node.network; this._db = this.node.services.db; diff --git a/lib/services/header/index.js b/lib/services/header/index.js index e1a184a6..3b9dd975 100644 --- a/lib/services/header/index.js +++ b/lib/services/header/index.js @@ -565,7 +565,7 @@ HeaderService.prototype._detectReorg = function(block, callback) { var nextBlock = prevHash === self._lastHeader.hash; // this is the last block the block service asked for - if (prevHash === this.lastBlockQueried) { + if (prevHash === this.lastBlockQueried && this.blockServiceSyncing) { return callback(null, false, true); } @@ -575,7 +575,7 @@ HeaderService.prototype._detectReorg = function(block, callback) { } // could really be a reorg block - var key = this._encoding.encodeHeaderHashKey(bcoin.util.revHex(block.prevBlock)); + var key = this._encoding.encodeHeaderHashKey(prevHash); this._db.get(key, function(err, val) { @@ -621,28 +621,39 @@ HeaderService.prototype._detectStartupReorg = function(callback) { HeaderService.prototype._handleReorg = function(block, header, callback) { var self = this; + self.getAllHeaders(function(err, headers) { if (err || !headers) { return callback(err || new Error('Missing headers')); } - var header = headers.getIndex(self._originalTip.height); + var originalTipHeader = headers.getIndex(self._originalTip.height); assert(header, 'Atempted to get reorg header for the original tip: ' + self._originalTip.hash + ' at height: ' + self._originalTip.height + ' but could not find in the database.'); - var hash = header.hash; + var hash = originalTipHeader.hash; + // reorg from new blocks if (block && header) { + hash = block.rhash(); - self._lastHeader = headers.get(header.prevHash); - assert(self._lastHeader, 'Expected our reorg block to have a header entry, but it did not.'); headers.set(hash, header); // appends to the end - self.emit('reorg', hash, headers, block); - return callback(); + + // this will ensure our own headers collection is correct + return self._onReorg(block, headers, function(err) { + + if (err) { + return callback(err); + } + + self.emit('reorg', hash, headers, block); + return callback(); + }); } + // reorg from startup assert(hash, 'To reorg, we need a hash to reorg to.'); self.emit('reorg', hash, headers); callback(); @@ -651,6 +662,41 @@ HeaderService.prototype._handleReorg = function(block, header, callback) { }; +HeaderService.prototype._onReorg = function(block, headers, callback) { + + // this will be called when a new block (not historical) arrives and + // has a common ancestor with a block that we already received. + + var self = this; + // remove the current last header from the db + var ops = [ + { + type: 'del', + key: self._encoding.encodeHeaderHashKey(self._lastHeader.hash) + }, + { + type: 'del', + key: self._encoding.encodeHeaderHeightKey(self._lastHeader.height) + } + ]; + + self._db.batch(ops, function(err) { + + if (err) { + return callback(err); + } + + // set the last header to the common ancestor + self._lastHeader = headers.get(bcoin.util.revHex(block.prevBlock)); + assert(self._lastHeader, 'Expected our reorg block to have a header entry, but it did not.'); + + // add the new block + self._syncBlock(block, callback); + + }); + +}; + HeaderService.prototype._setListeners = function() { this._p2p.once('bestHeight', this._onBestHeight.bind(this)); diff --git a/package-lock.json b/package-lock.json index c015bc19..53b82989 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "bitcore-node", - "version": "5.0.0-beta.5", + "version": "5.0.0-beta.6", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/test/services/transaction/index.unit.js b/test/services/transaction/index.unit.js index e70fb3bb..5eedd334 100644 --- a/test/services/transaction/index.unit.js +++ b/test/services/transaction/index.unit.js @@ -73,7 +73,7 @@ describe('Transaction Service', function() { it('should process new blocks that come in from the block service', function(done) { - var _processTransaction = sandbox.stub(txService, '_processTransaction'); + var _processTransaction = sandbox.stub(txService, '_processTransaction').callsArgWith(2, null, {}); txService.onBlock(block, function(err, ops) { if (err) { @@ -101,9 +101,9 @@ describe('Transaction Service', function() { }); - describe('#getInputValues', function() { + describe('#_getInputValues', function() { - it('should add missing input values on a tx', function(done) { + it('should get input values', function(done) { var put = sandbox.stub().callsArgWith(2, null); txService._db = { put: put }; @@ -112,12 +112,12 @@ describe('Transaction Service', function() { tx.__inputValues = []; - txService.getInputValues(tx, {}, function(err, tx) { + txService._getInputValues(tx, {}, function(err, values) { if (err) { return done(err); } - tx.__inputValues.should.deep.equal([1139033, 1139033, 500000, 1139033]); + values.should.deep.equal([1139033, 1139033, 500000, 1139033]); done(); });