diff --git a/lib/bcoin/blockdb.js b/lib/bcoin/blockdb.js index dbb291e0..38422c85 100644 --- a/lib/bcoin/blockdb.js +++ b/lib/bcoin/blockdb.js @@ -1242,6 +1242,15 @@ BlockData.prototype.truncateAsync = function truncateAsync(size, callback) { }); }; +BlockData.prototype._ioError = function _ioError(name, size, offset) { + return new Error(name + + '() failed at offset ' + + offset + + ' with ' + + size + + ' bytes left.'); +}; + BlockData.prototype._readSync = function _readSync(size, offset) { var index = 0; var data, bytes; @@ -1271,7 +1280,7 @@ BlockData.prototype._readSync = function _readSync(size, offset) { this._free(data); - throw new Error('_readSync() failed.'); + throw this._ioError('_readSync', size, offset); }; BlockData.prototype._readAsync = function _readAsync(size, offset, callback) { @@ -1297,7 +1306,7 @@ BlockData.prototype._readAsync = function _readAsync(size, offset, callback) { } if (!bytes) - return callback(new Error('_readAsync() failed at offset ' + offset + ' ' + size + ' to go')); + return callback(self._ioError('_readAsync', size, offset)); index += bytes; size -= bytes; @@ -1342,7 +1351,9 @@ BlockData.prototype._writeSync = function _writeSync(data, offset) { throw e; } - throw new Error('_writeSync() failed.'); + fs.fsyncSync(this.fd); + + throw this._ioError('_writeSync', size, offset); }; BlockData.prototype._writeAsync = function _writeAsync(data, offset, callback) { @@ -1372,7 +1383,7 @@ BlockData.prototype._writeAsync = function _writeAsync(data, offset, callback) { } if (!bytes) - return callback(new Error('_writeAsync() failed.')); + return callback(self._ioError('_writeAsync', size, offset)); index += bytes; size -= bytes; diff --git a/lib/bcoin/chain.js b/lib/bcoin/chain.js index 935c2856..35309311 100644 --- a/lib/bcoin/chain.js +++ b/lib/bcoin/chain.js @@ -47,6 +47,8 @@ function Chain(options) { this.pendingLimit = options.pendingLimit || 10 * 1024 * 1024; this.invalid = {}; this.bestHeight = -1; + this.lastUpdate = utils.now(); + this.blockDelta = 0; this.orphan = { map: {}, @@ -716,7 +718,7 @@ Chain.prototype._fillBlock = function _fillBlock(block, callback) { Chain.prototype._addEntry = function _addEntry(entry, block, callback) { var self = this; - var existing; + var existing, now; callback = utils.asyncify(callback); @@ -731,6 +733,10 @@ Chain.prototype._addEntry = function _addEntry(entry, block, callback) { if (existing && existing.hash === entry.hash) return callback(null, false); + now = utils.now(); + this.blockDelta = now - this.lastUpdate; + this.lastUpdate = now; + this._saveBlock(block, function(err) { if (err) return callback(err); @@ -1539,6 +1545,14 @@ Chain.prototype.isFull = function isFull() { return delta < 40 * 60; }; +Chain.prototype.isInitial = function isInitial() { + if (!this.tip) + return true; + + // Should mimic the original IsInitialBlockDownload() function + return this.blockDelta < 10 && this.tip.ts < utils.now() - 24 * 60 * 60; +}; + Chain.prototype.getProgress = function getProgress() { if (!this.tip) return 0; diff --git a/lib/bcoin/chaindb.js b/lib/bcoin/chaindb.js index b3bcf89e..b93034f8 100644 --- a/lib/bcoin/chaindb.js +++ b/lib/bcoin/chaindb.js @@ -47,6 +47,7 @@ function ChainDB(chain, options) { this.size = 0; this.fd = null; this.loading = false; + this.loaded = false; // Need to cache up to the retarget interval // if we're going to be checking the damn @@ -122,6 +123,7 @@ ChainDB.prototype.load = function load(start, callback) { function finish(err) { self.loading = false; + self.loaded = true; self.emit('load'); if (err) @@ -617,6 +619,15 @@ ChainDB.prototype.has = function has(height) { return false; }; +ChainDB.prototype._ioError = function _ioError(name, size, offset) { + return new Error(name + + '() failed at offset ' + + offset + + ' with ' + + size + + ' bytes left.'); +}; + ChainDB.prototype._readSync = function _readSync(size, offset) { var index = 0; var data, bytes; @@ -646,7 +657,7 @@ ChainDB.prototype._readSync = function _readSync(size, offset) { this._free(data); - throw new Error('_readSync() failed.'); + throw this._ioError('_readSync', size, offset); }; ChainDB.prototype._readAsync = function _readAsync(size, offset, callback) { @@ -672,7 +683,7 @@ ChainDB.prototype._readAsync = function _readAsync(size, offset, callback) { } if (!bytes) - return callback(new Error('_readAsync() failed.')); + return callback(self._ioError('_readAsync', size, offset)); index += bytes; size -= bytes; @@ -717,7 +728,9 @@ ChainDB.prototype._writeSync = function _writeSync(data, offset) { throw e; } - throw new Error('_writeSync() failed.'); + fs.fsyncSync(this.fd); + + throw this._ioError('_writeSync', size, offset); }; ChainDB.prototype._writeAsync = function _writeAsync(data, offset, callback) { @@ -747,14 +760,23 @@ ChainDB.prototype._writeAsync = function _writeAsync(data, offset, callback) { } if (!bytes) - return callback(new Error('_writeAsync() failed.')); + return callback(self._ioError('_writeAsync', size, offset)); index += bytes; size -= bytes; offset += bytes; - if (index === data.length) - return callback(null, true); + if (index === data.length) { + // Don't fsync when we're + // potentially preloading headers. + if (!self.chain.loaded) + return callback(null, true); + return fs.fsync(self.fd, function(err) { + if (err) + return callback(err); + return callback(null, true); + }); + } next(); });