diff --git a/lib/bcoin/chain.js b/lib/bcoin/chain.js index 5e2f22e2..18b5282d 100644 --- a/lib/bcoin/chain.js +++ b/lib/bcoin/chain.js @@ -246,8 +246,11 @@ Chain.prototype._preload = function _preload(callback) { stream.on('error', function(err) { var start = Math.max(0, height - 2); - self.resetHeight(start); - return callback(err, start + 1); + self.resetHeightAsync(start, function(e) { + if (e) + throw e; + return callback(err, start + 1); + }); }); stream.on('data', function(data) { @@ -282,8 +285,11 @@ Chain.prototype._preload = function _preload(callback) { if (lastEntry && entry.prevBlock !== lastEntry.hash) { start = Math.max(0, height - 2); stream.destroy(); - self.resetHeight(start); - return callback(new Error('Corrupt headers.'), start + 1); + self.resetHeightAsync(start, function(e) { + if (e) + throw e; + return callback(new Error('Corrupt headers.'), start + 1); + }); } // Verify the block headers. We don't want to @@ -291,8 +297,11 @@ Chain.prototype._preload = function _preload(callback) { if (!block.verify()) { start = Math.max(0, height - 2); stream.destroy(); - self.resetHeight(start); - return callback(new Error('Bad headers.'), start + 1); + self.resetHeightAsync(start, function(e) { + if (e) + throw e; + return callback(new Error('Bad headers.'), start + 1); + }); } lastEntry = entry; @@ -768,31 +777,34 @@ Chain.prototype.revertHeight = function revertHeight(height, callback) { if (chainHeight === height) return done(); - this.resetHeight(height); - - if (!this.blockdb) - return done(); - - this.blockdb.getHeight(function(err, blockHeight) { + this.resetHeightAsync(height, function(err) { if (err) return done(err); - if (blockHeight < 0) - return done(new Error('Bad block height.')); - - if (blockHeight < height) - return done(new Error('Cannot reset height.')); - - if (blockHeight === height) + if (!self.blockdb) return done(); - self.blockdb.resetHeight(height, function(err) { + self.blockdb.getHeight(function(err, blockHeight) { if (err) return done(err); - return done(); - }, function(block) { - self.emit('remove block', block); + if (blockHeight < 0) + return done(new Error('Bad block height.')); + + if (blockHeight < height) + return done(new Error('Cannot reset height.')); + + if (blockHeight === height) + return done(); + + self.blockdb.resetHeight(height, function(err) { + if (err) + return done(err); + + return done(); + }, function(block) { + self.emit('remove block', block); + }); }); }); }; @@ -809,16 +821,19 @@ Chain.prototype._revertLast = function _revertLast(existing, callback) { callback(err, result); } - this.resetHeight(existing.height - 1); - - this._removeBlock(existing.hash, function(err, existingBlock) { + this.resetHeightAsync(existing.height - 1, function(err) { if (err) return done(err); - if (existingBlock) - self.emit('remove block', existingBlock); + self._removeBlock(existing.hash, function(err, existingBlock) { + if (err) + return done(err); - return done(); + if (existingBlock) + self.emit('remove block', existingBlock); + + return done(); + }); }); }; @@ -859,8 +874,7 @@ Chain.prototype.syncHeight = function syncHeight(callback) { if (blockHeight < chainHeight) { utils.debug('BlockDB is higher than ChainDB. Syncing...'); - self.resetHeight(blockHeight); - return done(); + return self.resetHeightAsync(blockHeight, done); } if (blockHeight > chainHeight) { diff --git a/lib/bcoin/chaindb.js b/lib/bcoin/chaindb.js index 7b77a285..c57bec5e 100644 --- a/lib/bcoin/chaindb.js +++ b/lib/bcoin/chaindb.js @@ -295,7 +295,7 @@ ChainDB.prototype.getSync = function getSync(height) { return entry; }; -ChainDB.prototype.getAsync = function getAsync(height, callback) { +ChainDB.prototype.getAsync = function getAsync(height, callback, force) { var self = this; callback = utils.asyncify(callback); @@ -312,8 +312,10 @@ ChainDB.prototype.getAsync = function getAsync(height, callback) { if (height < 0 || height == null) return callback(); - if ((height + 1) * BLOCK_SIZE > this.size) - return callback(); + if (!force) { + if ((height + 1) * BLOCK_SIZE > this.size) + return callback(); + } return this._readAsync(BLOCK_SIZE, height * BLOCK_SIZE, function(err, data) { var entry; @@ -341,7 +343,11 @@ ChainDB.prototype.saveSync = function saveSync(entry) { var raw, offset; assert(entry.height >= 0); - assert(entry.height * BLOCK_SIZE === this.size); + + if (entry.height * BLOCK_SIZE !== this.size) { + utils.debug('Warning attempt to write to height: %d/%d', this.height); + return; + } // Cache the past 1001 blocks in memory // (necessary for isSuperMajority) @@ -363,7 +369,11 @@ ChainDB.prototype.saveAsync = function saveAsync(entry, callback) { callback = utils.asyncify(callback); assert(entry.height >= 0); - assert(entry.height * BLOCK_SIZE === this.size); + + if (entry.height * BLOCK_SIZE !== this.size) { + utils.debug('Warning attempt to write to height: %d/%d', this.height); + return callback(); + } // Cache the past 1001 blocks in memory // (necessary for isSuperMajority) @@ -480,6 +490,13 @@ ChainDB.prototype.resetHeightAsync = function resetHeightAsync(height, callback) assert(height <= count - 1); assert(this.tip); + this.size = size; + this.highest = height; + this.tip = this.get(height); + assert(this.tip); + this.height = this.tip.height; + this.emit('tip', this.tip); + for (i = height + 1; i < count; i++) dropEntry(i); @@ -493,7 +510,7 @@ ChainDB.prototype.resetHeightAsync = function resetHeightAsync(height, callback) delete self.heightLookup[existing.hash]; if (!--pending) done(); - }); + }, true); } function done(err) { @@ -514,13 +531,6 @@ ChainDB.prototype.resetHeightAsync = function resetHeightAsync(height, callback) if (err) return callback(err); - self.size = size; - self.highest = height; - self.tip = self.get(height); - assert(self.tip); - self.height = self.tip.height; - self.emit('tip', self.tip); - return callback(); }); }