diff --git a/lib/bcoin/chain.js b/lib/bcoin/chain.js index 14660d8d..15239eb2 100644 --- a/lib/bcoin/chain.js +++ b/lib/bcoin/chain.js @@ -1131,67 +1131,27 @@ Chain.prototype.add = function add(initial, peer, callback, force) { // Lookup previous entry. // We can do this synchronously: - // it is already cached. - prev = self.db.getSync(prevHeight); + // This will be cached in 99.9% of cases. + if (!self.db.isCached(prevHeight)) + utils.debug('Warning: height %d is not cached.', prevHeight); + + try { + prev = self.db.getSync(prevHeight); + } catch (e) { + return done(e); + } + assert(prev); // Do "contextual" verification on our block // now that we're certain its previous // block is in the chain. self._verifyContext(block, prev, function(err, verified) { + var existing; + if (err) return done(err); - // Real fork resolution would just be this. - // if (entry.chainwork.cmp(self.tip.chainwork) > 0) - // return self.setBestChain(entry); - // return done(); - - // See if the entry already exists. - if (self.db.has(entry.height)) { - return self.db.getAsync(entry.height, function(err, existing) { - if (err) - return done(err); - - // Shouldn't be the same by this point. - assert(existing.hash !== entry.hash); - - // A valid block with an already existing - // height came in, that spells fork. We - // don't store by hash so we can't compare - // chainworks. We reset the chain, find a - // new peer, and wait to see who wins. - assert(self.db.getHeight(entry.hash) === -1); - - // The tip has more chainwork, it is a - // higher height than the entry. This is - // not an alternate tip. Ignore it. - if (existing.chainwork.cmp(entry.chainwork) > 0) - return done(); - - // The block has equal chainwork (an - // alternate tip). Reset the chain, find - // a new peer, and wait to see who wins. - // self.revertHeight(existing.height - 1, function(err) { - self._revertLast(existing, function(err, existingBlock) { - if (err) - return done(err); - - self.emit('fork', block, { - height: existing.height, - expected: existing.hash, - received: entry.hash, - checkpoint: false - }, peer); - - return done(); - }, true); - }); - } - - // Add entry if we do not have it. - assert(self.db.getHeight(entry.hash) === -1); - if (!verified) { self.invalid[entry.hash] = true; self.emit('invalid', block, { @@ -1203,6 +1163,62 @@ Chain.prototype.add = function add(initial, peer, callback, force) { return done(); } + // Real fork resolution would just be this. + // if (entry.chainwork.cmp(self.tip.chainwork) > 0) + // return self.setBestChain(entry); + // return done(); + + // See if the height already exists (fork). + // Do this synchronously: This will + // be cached in 99.9% of cases. + if (self.db.has(entry.height)) { + if (!self.db.isCached(entry.height)) + utils.debug('Warning: height %d is not cached.', entry.height); + + try { + existing = self.db.getSync(entry.height); + } catch (e) { + return done(e); + } + + // Shouldn't be the same by this point. + assert(existing.hash !== entry.hash); + + // A valid block with an already existing + // height came in, that spells fork. We + // don't store by hash so we can't compare + // chainworks. We reset the chain, find a + // new peer, and wait to see who wins. + assert(self.db.getHeight(entry.hash) === -1); + + // The tip has more chainwork, it is a + // higher height than the entry. This is + // not an alternate tip. Ignore it. + if (existing.chainwork.cmp(entry.chainwork) > 0) + return done(); + + // The block has equal chainwork (an + // alternate tip). Reset the chain, find + // a new peer, and wait to see who wins. + // return self.revertHeight(existing.height - 1, function(err) { + return self._revertLast(existing, function(err, existingBlock) { + if (err) + return done(err); + + self.emit('fork', block, { + height: existing.height, + expected: existing.hash, + received: entry.hash, + checkpoint: false + }, peer); + + return done(); + }, true); + } + + // Add entry if we do not have it. + assert(self.db.getHeight(entry.hash) === -1); + // Update the block height block.height = entry.height; block.txs.forEach(function(tx) { diff --git a/lib/bcoin/chaindb.js b/lib/bcoin/chaindb.js index 1d573ce6..098f9a9b 100644 --- a/lib/bcoin/chaindb.js +++ b/lib/bcoin/chaindb.js @@ -243,6 +243,16 @@ ChainDB.prototype._cache = function _cache(entry) { } }; +ChainDB.prototype.isCached = function isCached(height) { + if (this.queue[height] != null) + return true; + + if (this.cache[height] != null) + return true; + + return false; +}; + ChainDB.prototype.getHeight = function getHeight(hash) { var height = this.heightLookup[hash];