diff --git a/lib/bcoin/chain.js b/lib/bcoin/chain.js index 61bcce70..81a9a1cd 100644 --- a/lib/bcoin/chain.js +++ b/lib/bcoin/chain.js @@ -266,6 +266,32 @@ Chain.prototype._preload = function _preload(callback) { }; } + function save(entry) { + if (save.locked) + return save.queue.push(entry); + + save.locked = true; + + self.db.save(entry, null, true, function(err) { + if (err) + return callback(err, 0); + + save.locked = false; + + if (save.queue.length === 0) { + if (save.ended) + return callback(null, height + 1); + return; + } + + save(save.queue.shift()); + }); + } + + save.locked = false; + save.queue = []; + save.ended = false; + this.db.getChainHeight(function(err, chainHeight) { if (err) return callback(err); @@ -288,7 +314,7 @@ Chain.prototype._preload = function _preload(callback) { var start = Math.max(0, height - 2); self.reset(start, function(e) { if (e) - throw e; + return callback(e, 0); return callback(err, start + 1); }); }); @@ -319,7 +345,12 @@ Chain.prototype._preload = function _preload(callback) { blocks.forEach(function(data) { var block, entry, start; - data = parseHeader(data); + try { + data = parseHeader(data); + } catch (e) { + return callback(e, Math.max(0, height - 2)); + } + data.height = height; // Make sure the genesis block is correct. @@ -334,7 +365,7 @@ Chain.prototype._preload = function _preload(callback) { stream.destroy(); return self.reset(start, function(err) { if (err) - throw err; + return callback(err, 0); return callback(new Error('Corrupt headers.'), start + 1); }); } @@ -349,7 +380,7 @@ Chain.prototype._preload = function _preload(callback) { stream.destroy(); return self.reset(start, function(err) { if (err) - throw err; + return callback(err, 0); return callback(new Error('Bad headers.'), start + 1); }); } @@ -360,7 +391,7 @@ Chain.prototype._preload = function _preload(callback) { if (entry.height <= chainHeight) self.db.addCache(entry); else - self.db.save(entry, null, true); + save(entry); if ((height + 1) % 50000 === 0) utils.debug('Received %d headers from electrum.org.', height + 1); @@ -371,7 +402,9 @@ Chain.prototype._preload = function _preload(callback) { }); stream.on('end', function() { - return callback(null, height + 1); + save.ended = true; + if (!save.locked && save.queue.length === 0) + return callback(null, height + 1); }); }); }; @@ -909,8 +942,12 @@ Chain.prototype._setBestChain = function _setBestChain(entry, block, callback) { // We don't have a genesis block yet. if (!this.tip) { - if (entry.hash !== network.genesis.hash) - return utils.asyncify(callback)(new Error('Bad genesis block.')); + if (entry.hash !== network.genesis.hash) { + return utils.asyncify(callback)(new VerifyError(block, + 'invalid', + 'bad-genblk', + 100)); + } return done(); } @@ -946,13 +983,11 @@ Chain.prototype.reset = function reset(height, callback, force) { if (!unlock) return; - callback = utils.ensure(callback); + callback = utils.wrap(callback, unlock); this.db.reset(height, function(err, result) { - if (err) { - unlock(); + if (err) return callback(err); - } // Reset the orphan map completely. There may // have been some orphans on a forked chain we @@ -960,7 +995,6 @@ Chain.prototype.reset = function reset(height, callback, force) { self.purgeOrphans(); self.purgePending(); - unlock(); callback(null, result); }); }; @@ -972,25 +1006,16 @@ Chain.prototype.resetTime = function resetTime(ts, callback, force) { if (!unlock) return; - callback = utils.ensure(callback); + callback = utils.wrap(callback, unlock); this.byTime(ts, function(err, entry) { - if (err) { - unlock(); - callback(err); - return; - } + if (err) + return callback(err); - if (!entry) { - unlock(); - callback(); - return; - } + if (!entry) + return callback(); - self.reset(entry.height, function(err) { - unlock(); - callback(err); - }, true); + self.reset(entry.height, callback, true); }, true); }; @@ -1009,6 +1034,8 @@ Chain.prototype.add = function add(block, callback, force) { if (!unlock) return; + callback = utils.wrap(callback, unlock); + (function next(block, initial) { var hash = block.hash('hex'); var prevHash = block.prevBlock; @@ -1240,13 +1267,15 @@ Chain.prototype.add = function add(block, callback, force) { // Emit our block (and potentially resolved // orphan) only if it is on the main chain. - if (mainChain) + if (mainChain) { self.emit('block', block, entry); - else + if (!initial) + self.emit('resolved', block, entry); + } else { self.emit('competitor', block, entry); - - if (!initial) - self.emit('resolved', block, entry); + if (!initial) + self.emit('competitor resolved', block, entry); + } // No orphan chain. if (!self.orphan.map[hash]) @@ -1285,8 +1314,6 @@ Chain.prototype.add = function add(block, callback, force) { if (self.isFull()) self.emit('full'); - unlock(); - if (err) callback(err); else @@ -1368,31 +1395,23 @@ Chain.prototype.byTime = function byTime(ts, callback, force) { var end = this.height; var pos, delta; - var unlock = this._lock(byTime, [ts, callback], force); - if (!unlock) - return; - - callback = utils.asyncify(callback); + // var unlock = this._lock(byTime, [ts, callback], force); + // if (!unlock) + // return; + // callback = utils.wrap(callback, unlock); function done(err, result) { - if (err) { - unlock(); + if (err) return callback(err); - } - if (result) { - unlock(); + if (result) return callback(null, result); - } - self.db.get(start, function(err, entry) { - unlock(); - callback(err, entry); - }); + self.db.get(start, callback); } if (ts >= this.tip.ts) - return done(null, this.tip); + return utils.asyncify(done)(null, this.tip); // Do a binary search for a block // mined within an hour of the @@ -1501,29 +1520,25 @@ Chain.prototype.getProgress = function getProgress() { Chain.prototype.getHashRange = function getHashRange(start, end, callback, force) { var self = this; - var unlock = this._lock(getHashRange, [start, end, callback], force); - if (!unlock) - return; - - function done(err, result) { - unlock(); - callback(err, result); - } + // var unlock = this._lock(getHashRange, [start, end, callback], force); + // if (!unlock) + // return; + // callback = utils.wrap(callback, unlock); this.byTime(start, function(err, start) { if (err) - return done(err); + return callback(err); self.byTime(end, function(err, end) { var hashes; if (err) - return done(err); + return callback(err); hashes = []; if (!start || !end) - return done(null, hashes); + return callback(null, hashes); utils.forRange(start.height, end.height + 1, function(i, next) { self.db.get(i, function(err, entry) { @@ -1539,8 +1554,8 @@ Chain.prototype.getHashRange = function getHashRange(start, end, callback, force }); }, function(err) { if (err) - return done(err); - return done(null, hashes); + return callback(err); + return callback(null, hashes); }); }, true); }, true); @@ -1556,6 +1571,7 @@ Chain.prototype.getLocator = function getLocator(start, callback, force) { var unlock = this._lock(getLocator, [start, callback], force); if (!unlock) return; + callback = utils.wrap(callback, unlock); if (start) { if (Buffer.isBuffer(start)) @@ -1589,10 +1605,8 @@ Chain.prototype.getLocator = function getLocator(start, callback, force) { } return getTop(function(err, top) { - if (err) { - unlock(); + if (err) return callback(err); - } i = top; for (;;) { @@ -1622,7 +1636,6 @@ Chain.prototype.getLocator = function getLocator(start, callback, force) { next(); }); }, function(err) { - unlock(); if (err) return callback(err); return callback(null, hashes); @@ -1952,11 +1965,10 @@ Chain.prototype.isSegwitActive = function isSegwitActive(callback) { if (!this.tip) return utils.asyncify(callback)(null, false); - unlock = this._lock(isSegwitActive, [callback]); - if (!unlock) - return; - - callback = utils.wrap(callback, unlock); + // unlock = this._lock(isSegwitActive, [callback]); + // if (!unlock) + // return; + // callback = utils.wrap(callback, unlock); if (network.type === 'segnet4') { return this.tip.getPrevious(function(err, prev) { @@ -2090,6 +2102,12 @@ Chain.prototype.evalLocks = function evalLocks(entry, minHeight, minTime, callba Chain.prototype.checkLocks = function checkLocks(tx, flags, entry, callback) { var self = this; + + // var unlock = this._lock(checkLocks, [tx, flags, entry, callback], force); + // if (!unlock) + // return; + // callback = utils.wrap(callback, unlock); + this.getLocks(tx, flags, entry, function(err, minHeight, minTime) { if (err) return callback(err); diff --git a/lib/bcoin/peer.js b/lib/bcoin/peer.js index 17c9c14a..6cc26e84 100644 --- a/lib/bcoin/peer.js +++ b/lib/bcoin/peer.js @@ -140,6 +140,7 @@ Peer.prototype._init = function init() { this.parser.on('error', function(err) { utils.debug(err.stack + ''); + peer.sendReject(null, 'malformed', 'error parsing message', 100); self._error(err); // Something is wrong here. // Ignore this peer. diff --git a/lib/bcoin/pool.js b/lib/bcoin/pool.js index d1cc5687..fab7a3d2 100644 --- a/lib/bcoin/pool.js +++ b/lib/bcoin/pool.js @@ -1925,19 +1925,28 @@ Pool.prototype.isMisbehaving = function isMisbehaving(host) { }; Pool.prototype.reject = function reject(peer, obj, code, reason, score) { + if (obj) { + utils.debug('Rejecting %s %s from %s: ccode=%s reason=%s', + obj.type, obj.hash('hex'), peer.host, code, reason); + + peer.reject({ + ccode: code, + reason: reason, + data: obj.hash() + }); + } else { + utils.debug('Rejecting packet from %s: ccode=%s reason=%s', + peer.host, code, reason); + + peer.reject({ + ccode: code, + reason: reason, + data: null + }); + } + if (score != null) peer.setMisbehavior(score); - - utils.debug('Rejecting %s %s: ccode=%s reason=%s', - obj.type, obj.hash('hex'), code, reason); - - peer.reject({ - ccode: code, - reason: reason, - data: obj.hash() - }); - - return false; }; /**