add preload from electrum.org. check for blockchain corruption.
This commit is contained in:
parent
adb304748f
commit
36c3d72021
@ -6,6 +6,7 @@
|
||||
|
||||
var inherits = require('inherits');
|
||||
var EventEmitter = require('events').EventEmitter;
|
||||
var request = require('request');
|
||||
|
||||
var bcoin = require('../bcoin');
|
||||
var bn = require('bn.js');
|
||||
@ -95,42 +96,137 @@ Chain.prototype._init = function _init() {
|
||||
|
||||
utils.debug('Chain is loading.');
|
||||
|
||||
utils.nextTick(function() {
|
||||
var count = self.db.count();
|
||||
var lastEntry;
|
||||
var i = 1;
|
||||
this.preload(function(start) {
|
||||
utils.nextTick(function() {
|
||||
var count = self.db.count();
|
||||
var i = start || 1;
|
||||
var lastEntry;
|
||||
|
||||
function done(height) {
|
||||
if (height != null) {
|
||||
utils.debug(
|
||||
'Blockchain is corrupt after height %d. Resetting.',
|
||||
height);
|
||||
self.resetHeight(height);
|
||||
} else {
|
||||
utils.debug('Chain successfully loaded.');
|
||||
function done(height) {
|
||||
if (height != null) {
|
||||
utils.debug(
|
||||
'Blockchain is corrupt after height %d. Resetting.',
|
||||
height);
|
||||
self.resetHeight(height);
|
||||
} else {
|
||||
utils.debug('Chain successfully loaded.');
|
||||
}
|
||||
self.loading = false;
|
||||
self.emit('load');
|
||||
}
|
||||
self.loading = false;
|
||||
self.emit('load');
|
||||
|
||||
(function next() {
|
||||
if (i >= count)
|
||||
return done();
|
||||
|
||||
self.db.getAsync(i, function(err, entry) {
|
||||
if (err)
|
||||
throw err;
|
||||
|
||||
// Do some paranoid checks.
|
||||
if (lastEntry && entry.prevBlock !== lastEntry.hash)
|
||||
return done(Math.max(0, i - 2));
|
||||
|
||||
lastEntry = entry;
|
||||
self._saveEntry(entry);
|
||||
i += 1;
|
||||
next();
|
||||
});
|
||||
})();
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
Chain.prototype.preload = function preload(callback) {
|
||||
var self = this;
|
||||
var url = 'https://headers.electrum.org/blockchain_headers';
|
||||
var chainHeight, buf, height, stream;
|
||||
|
||||
if (this.options.preload === false)
|
||||
return callback();
|
||||
|
||||
utils.debug('Loading %s', url);
|
||||
|
||||
stream = request.get(url);
|
||||
chainHeight = this.db.count() - 1;
|
||||
height = 0;
|
||||
buf = {
|
||||
data: [],
|
||||
size: 0
|
||||
};
|
||||
|
||||
stream.on('response', function(res) {
|
||||
if (res.statusCode >= 400) {
|
||||
utils.debug('Could not load electrum headers');
|
||||
utils.debug('Status: %d', res.statusCode);
|
||||
stream.destroy();
|
||||
return callback();
|
||||
}
|
||||
});
|
||||
|
||||
stream.on('error', function(err) {
|
||||
utils.debug('Could not load electrum headers');
|
||||
utils.debug(err.stack + '');
|
||||
self.resetHeight(Math.max(0, height - 2));
|
||||
return callback(Math.max(0, height - 2));
|
||||
});
|
||||
|
||||
stream.on('data', function(data) {
|
||||
var blocks = [];
|
||||
var need = 80 - buf.size;
|
||||
var i, lastEntry;
|
||||
|
||||
while (data.length >= need) {
|
||||
buf.data.push(data.slice(0, need));
|
||||
blocks.push(Buffer.concat(buf.data));
|
||||
buf.data.length = 0;
|
||||
buf.size = 0;
|
||||
data = data.slice(need);
|
||||
need = 80 - buf.size;
|
||||
}
|
||||
|
||||
(function next() {
|
||||
if (i >= count)
|
||||
return done();
|
||||
if (data.length > 0) {
|
||||
assert(data.length < 80);
|
||||
buf.data.push(data);
|
||||
buf.size += data.length;
|
||||
}
|
||||
|
||||
self.db.getAsync(i, function(err, entry) {
|
||||
if (err)
|
||||
throw err;
|
||||
if (blocks.length === 0)
|
||||
return;
|
||||
|
||||
// Do some paranoid checks.
|
||||
if (lastEntry && entry.prevBlock !== lastEntry.hash)
|
||||
return done(Math.max(0, i - 2));
|
||||
blocks.forEach(function(data) {
|
||||
var entry = bcoin.chainblock.fromRaw(self, height, data);
|
||||
|
||||
self._saveEntry(entry);
|
||||
lastEntry = entry;
|
||||
i += 1;
|
||||
next();
|
||||
});
|
||||
})();
|
||||
// Do some paranoid checks.
|
||||
if (lastEntry && entry.prevBlock !== lastEntry.hash) {
|
||||
utils.debug('Electrum headers are corrupt. Resetting.');
|
||||
stream.destroy();
|
||||
self.resetHeight(Math.max(0, height - 2));
|
||||
return callback(Math.max(0, height - 2));
|
||||
}
|
||||
|
||||
lastEntry = entry;
|
||||
|
||||
delete entry.chainwork;
|
||||
entry.chainwork = entry.getChainwork();
|
||||
|
||||
// Skip the genesis block in case it ends up being corrupt
|
||||
if (height === 0) {
|
||||
height++;
|
||||
return;
|
||||
}
|
||||
|
||||
self._saveEntry(entry, height > chainHeight);
|
||||
|
||||
height++;
|
||||
|
||||
if ((height + 1) % 50000 === 0)
|
||||
utils.debug('Received %d headers from electrum.org.', height + 1);
|
||||
});
|
||||
});
|
||||
|
||||
stream.on('end', function() {
|
||||
return callback(null, height + 1);
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user