diff --git a/lib/bcoin/chain.js b/lib/bcoin/chain.js index 2e75f790..14660d8d 100644 --- a/lib/bcoin/chain.js +++ b/lib/bcoin/chain.js @@ -980,7 +980,6 @@ Chain.prototype._onFlush = function _onFlush(callback) { Chain.prototype.add = function add(initial, peer, callback, force) { var self = this; - var host = peer ? peer.host : 'unknown'; var total = 0; assert(!this.loading); @@ -994,17 +993,13 @@ Chain.prototype.add = function add(initial, peer, callback, force) { var prevHash = block.prevBlock; var prevHeight, entry, checkpoint, prev, orphan; - // We already have this block. Do regular - // orphan resolution (won't do anything). - // NOTE: Wrap this in a nextTick to avoid - // a stack overflow if there are a lot of - // existing blocks. + // We already have this block. if (self.db.has(hash)) { self.emit('exists', block, { height: entry.height, hash: entry.hash }, peer); - return utils.nextTick(handleOrphans); + return done(); } // Do not revalidate known invalid blocks. @@ -1012,9 +1007,10 @@ Chain.prototype.add = function add(initial, peer, callback, force) { self.emit('invalid', block, { height: -1, hash: hash, - seen: true, - chain: self.invalid[prevHash] + seen: !!self.invalid[hash], + chain: !!self.invalid[prevHash] }, peer); + self.invalid[hash] = true; return done(); } @@ -1133,57 +1129,6 @@ Chain.prototype.add = function add(initial, peer, callback, force) { } } - // 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(); - - // NOTE: We should do contextual verification - // here if we were a fullnode that actually - // stored multiple chains, but since we backoff, - // we can ignore that until the shorter chain - // stops being propogated. - - // 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); - // Lookup previous entry. // We can do this synchronously: // it is already cached. @@ -1197,6 +1142,56 @@ Chain.prototype.add = function add(initial, peer, callback, force) { 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, {