diff --git a/lib/bcoin/chain.js b/lib/bcoin/chain.js index c9bcb751..4721a49a 100644 --- a/lib/bcoin/chain.js +++ b/lib/bcoin/chain.js @@ -39,8 +39,6 @@ function Chain(options) { this.loading = false; this.mempool = options.mempool; this.blockdb = options.blockdb; - // this.locked = false; - this.handling = false; this.busy = false; this.jobs = []; this.pending = []; @@ -979,13 +977,6 @@ Chain.prototype._onFlush = function _onFlush(callback) { this.once('flush', callback); }; -// Chain.prototype._onUnlock = function _onUnlock(callback) { -// if (!this.handling) -// return callback(); -// -// this.once('unlock', callback); -// }; - Chain.prototype.add = function add(initial, peer, callback, force) { var self = this; var host = peer ? peer.host : 'unknown'; @@ -997,22 +988,6 @@ Chain.prototype.add = function add(initial, peer, callback, force) { if (!unlock) return; - // if (this.locked) { - // this.pending.push([initial, peer, callback]); - // this.pendingBlocks[initial.hash('hex')] = true; - // this.pendingSize += initial.getSize(); - // if (this.pendingSize > this.pendingLimit) { - // utils.debug('Warning: %dmb of pending blocks.', - // utils.mb(this.pendingSize)); - // } - // return; - // } - - assert(!this.handling); - - this.locked = true; - this.handling = true; - (function next(block) { var hash = block.hash('hex'); var prevHash = block.prevBlock; @@ -1309,25 +1284,8 @@ Chain.prototype.add = function add(initial, peer, callback, force) { callback(null, total); self.total += total; - // self.locked = false; - self.handling = false; unlock(); - - // self.emit('unlock'); - // - // // Start resolving the queue - // // (I love asynchronous IO). - // if (self.pending.length === 0) { - // self.emit('flush'); - // return; - // } - // - // item = self.pending.shift(); - // delete self.pendingBlocks[item[0].hash('hex')]; - // self.pendingSize -= item[0].getSize(); - // - // self.add(item[0], item[1], item[2]); }); } }; diff --git a/lib/bcoin/chaindb.js b/lib/bcoin/chaindb.js index 44d080ef..e48c14d0 100644 --- a/lib/bcoin/chaindb.js +++ b/lib/bcoin/chaindb.js @@ -123,10 +123,10 @@ ChainDB.prototype.load = function load(start, callback) { utils.debug( 'Blockchain is corrupt after height %d. Resetting.', height); - self.resetHeightSync(height); - } else { - utils.debug('Chain successfully loaded.'); + self.resetHeightAsync(height, callback); + return; } + utils.debug('Chain successfully loaded.'); callback(); } @@ -427,6 +427,9 @@ ChainDB.prototype._drop = function _drop(height) { ChainDB.prototype.resetHeightSync = function resetHeightSync(height) { var self = this; var size, count, existing; + var osize = this.size; + var ohighest = this.highest; + var otip = this.tip; if (typeof height === 'string') height = this.heightLookup[height]; @@ -449,6 +452,8 @@ ChainDB.prototype.resetHeightSync = function resetHeightSync(height) { delete this.heightLookup[existing.hash]; } + // Prevent any more writes + // by setting this early. this.size = size; this.highest = height; this.tip = this.getSync(height); @@ -458,16 +463,28 @@ ChainDB.prototype.resetHeightSync = function resetHeightSync(height) { // This will be synchronous 99% of the time. this._onFlush(function() { + try { if (!bcoin.fs) self.ramdisk.truncate(size); else fs.ftruncateSync(self.fd, size); + } catch (e) { + self.size = osize; + self.highest = ohighest; + self.tip = otip; + self.height = self.tip.height; + self.emit('tip', self.tip); + throw e; + } }); }; ChainDB.prototype.resetHeightAsync = function resetHeightAsync(height, callback) { var self = this; var size, count, pending, called; + var osize = this.size; + var ohighest = this.highest; + var otip = this.tip; if (typeof height === 'string') height = this.heightLookup[height]; @@ -486,52 +503,74 @@ ChainDB.prototype.resetHeightAsync = function resetHeightAsync(height, callback) assert(height <= count - 1); assert(this.tip); + // Prevent any more writes + // by setting this early. this.size = size; this.highest = height; - this.tip = this.getSync(height); - assert(this.tip); - this.height = this.tip.height; - this.emit('tip', this.tip); - - for (i = height + 1; i < count; i++) - dropEntry(i); - - function dropEntry(i) { - self.getAsync(i, function(err, existing) { - if (err) - return done(err); - - assert(existing); - self._drop(i); - delete self.heightLookup[existing.hash]; - if (!--pending) - done(); - }, true); - } - - function done(err) { - if (called) - return; - - called = true; + this.getAsync(height, function(err, tip) { if (err) - return callback(err); + return done(err); - self._onFlush(function() { - if (!bcoin.fs) { - self.ramdisk.truncate(size); - return callback(); + self.tip = tip; + assert(self.tip); + self.height = self.tip.height; + self.emit('tip', self.tip); + + for (i = height + 1; i < count; i++) + dropEntry(i); + + function dropEntry(i) { + self.getAsync(i, function(err, existing) { + if (err) + return done(err); + + assert(existing); + + self._drop(i); + delete self.heightLookup[existing.hash]; + if (!--pending) + done(); + }, true); + } + + function done(err) { + if (called) + return; + + called = true; + + if (err) + return finish(err); + + self._onFlush(function() { + if (!bcoin.fs) { + self.ramdisk.truncate(size); + return finish(); + } + + fs.ftruncate(self.fd, size, function(err) { + if (err) + return finish(err); + + return finish(); + }); + }); + } + + function finish(err) { + if (err) { + self.size = osize; + self.highest = ohighest; + self.tip = otip; + self.height = self.tip.height; + self.emit('tip', self.tip); + return callback(err); } - fs.ftruncate(self.fd, size, function(err) { - if (err) - return callback(err); - - return callback(); - }); - }); - } + callback(); + } + }); }; ChainDB.prototype._onFlush = function _onFlush(callback) {