From 0658444eb5233197fcfc03e600b3a1f621f086b2 Mon Sep 17 00:00:00 2001 From: Christopher Jeffrey Date: Sat, 9 Jan 2016 14:21:17 -0800 Subject: [PATCH] chain improvements. --- lib/bcoin/chain.js | 36 +++++++++++++++++++++++++--------- lib/bcoin/pool.js | 49 +++++++++++++++++++--------------------------- 2 files changed, 47 insertions(+), 38 deletions(-) diff --git a/lib/bcoin/chain.js b/lib/bcoin/chain.js index 36b9977f..c0f7b9c5 100644 --- a/lib/bcoin/chain.js +++ b/lib/bcoin/chain.js @@ -109,7 +109,7 @@ Chain.messages = { }; Chain.msg = function msg(code) { - return new Error(Chain.messages[code] || 'Unknown'); + return Chain.messages[code] || 'Unknown'; }; Chain.prototype._init = function _init() { @@ -286,13 +286,7 @@ Chain.prototype.add = function add(block, peer) { var initial = block; var code = Chain.codes.unchanged; var hash, prevHash, prevHeight, entry, tip; - - if (this.loading) { - this.once('load', function() { - this.add(block); - }); - return; - } + var total = 0; for (;;) { // Validate the block we want to add. @@ -310,6 +304,22 @@ Chain.prototype.add = function add(block, peer) { // If the block is already known to be // an orphan, ignore it. if (this.orphan.map[prevHash]) { + // If the orphan chain forked, simply + // reset the orphans and find a new peer. + if (this.orphan.map[prevHash].hash('hex') !== hash) { + this.orphan.map = {}; + this.orphan.bmap = {}; + this.orphan.count = 0; + this.orphan.size = 0; + this.emit('fork', { + height: -1, + expected: this.orphan.map[prevHash].hash('hex'), + received: hash, + checkpoint: null + }); + code = Chain.codes.forked; + break; + } code = Chain.codes.knownOrphan; break; } @@ -325,6 +335,7 @@ Chain.prototype.add = function add(block, peer) { this.orphan.map[prevHash] = block; this.orphan.bmap[hash] = block; code = Chain.codes.newOrphan; + total++; break; } @@ -398,6 +409,10 @@ Chain.prototype.add = function add(block, peer) { if (code !== Chain.codes.okay) break; + // Keep track of the number of blocks we + // added and the number of orphans resolved. + total++; + // Emit our block (and potentially resolved // orphan) so the programmer can save it. this.emit('block', block, peer); @@ -436,7 +451,10 @@ Chain.prototype.add = function add(block, peer) { // this.compact(); // } - return code; + if (code !== Chain.codes.okay) + this.emit('debug', 'Chain Error: %s', Chain.msg(code)); + + return total; }; Chain.prototype.has = function has(hash, cb) { diff --git a/lib/bcoin/pool.js b/lib/bcoin/pool.js index 5cfda7a2..c3c832d7 100644 --- a/lib/bcoin/pool.js +++ b/lib/bcoin/pool.js @@ -326,15 +326,21 @@ Pool.prototype._addLoader = function _addLoader() { }); peer.on('merkleblock', function(block) { - self._startInterval(); - self._startTimer(); - self._handleBlock(block, peer); + // If the peer sent us a block that was added + // to the chain (not orphans), reset the timeout. + if (self._handleBlock(block, peer)) { + self._startInterval(); + self._startTimer(); + } }); peer.on('block', function(block) { - self._startInterval(); - self._startTimer(); - self._handleBlock(block, peer); + // If the peer sent us a block that was added + // to the chain (not orphans), reset the timeout. + if (self._handleBlock(block, peer)) { + self._startInterval(); + self._startTimer(); + } }); if (self.options.headers) { @@ -499,7 +505,7 @@ Pool.prototype._handleBlock = function _handleBlock(block, peer) { // Ignore if we already have if (this.chain.has(block)) { this.emit('debug', 'Already have block %s (%s)', block.height, peer.host); - return; + return false; } // Make sure the block is valid @@ -507,7 +513,7 @@ Pool.prototype._handleBlock = function _handleBlock(block, peer) { this.emit('debug', 'Block verification failed for %s (%s)', block.rhash, peer.host); - return; + return false; } // Someone is sending us blocks without us requesting them. @@ -531,38 +537,23 @@ Pool.prototype._handleBlock = function _handleBlock(block, peer) { this.chain.getOrphanRoot(block) ); this.emit('debug', 'Handled orphan %s (%s)', block.rhash, peer.host); - return; + return false; } } // Add to index and emit/save - if (this._addIndex(block, peer)) + if (this._addIndex(block, peer)) { this.emit('pool block', block, peer); + return true; + } }; Pool.prototype._addIndex = function _addIndex(block, peer) { - var self = this; - var hash, size, orphans, res; - - hash = block.hash('hex'); - size = this.chain.size(); - orphans = this.chain.orphan.count; - - res = this.chain.add(block, peer); - - if (res !== bcoin.chain.codes.okay) - this.emit('chain-error', bcoin.chain.msg(res)); - - // Do not emit if nothing was added to the chain - if (this.chain.size() === size) { - if (this.chain.orphan.count > orphans) - return true; - return false; - } + var added = this.chain.add(block, peer); this.emit('chain-progress', this.chain.fillPercent(), peer); - return true; + return added > 0; }; Pool.prototype.isFull = function isFull() {