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 inherits = require('inherits');
|
||||||
var EventEmitter = require('events').EventEmitter;
|
var EventEmitter = require('events').EventEmitter;
|
||||||
|
var request = require('request');
|
||||||
|
|
||||||
var bcoin = require('../bcoin');
|
var bcoin = require('../bcoin');
|
||||||
var bn = require('bn.js');
|
var bn = require('bn.js');
|
||||||
@ -95,42 +96,137 @@ Chain.prototype._init = function _init() {
|
|||||||
|
|
||||||
utils.debug('Chain is loading.');
|
utils.debug('Chain is loading.');
|
||||||
|
|
||||||
utils.nextTick(function() {
|
this.preload(function(start) {
|
||||||
var count = self.db.count();
|
utils.nextTick(function() {
|
||||||
var lastEntry;
|
var count = self.db.count();
|
||||||
var i = 1;
|
var i = start || 1;
|
||||||
|
var lastEntry;
|
||||||
|
|
||||||
function done(height) {
|
function done(height) {
|
||||||
if (height != null) {
|
if (height != null) {
|
||||||
utils.debug(
|
utils.debug(
|
||||||
'Blockchain is corrupt after height %d. Resetting.',
|
'Blockchain is corrupt after height %d. Resetting.',
|
||||||
height);
|
height);
|
||||||
self.resetHeight(height);
|
self.resetHeight(height);
|
||||||
} else {
|
} else {
|
||||||
utils.debug('Chain successfully loaded.');
|
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 (data.length > 0) {
|
||||||
if (i >= count)
|
assert(data.length < 80);
|
||||||
return done();
|
buf.data.push(data);
|
||||||
|
buf.size += data.length;
|
||||||
|
}
|
||||||
|
|
||||||
self.db.getAsync(i, function(err, entry) {
|
if (blocks.length === 0)
|
||||||
if (err)
|
return;
|
||||||
throw err;
|
|
||||||
|
|
||||||
// Do some paranoid checks.
|
blocks.forEach(function(data) {
|
||||||
if (lastEntry && entry.prevBlock !== lastEntry.hash)
|
var entry = bcoin.chainblock.fromRaw(self, height, data);
|
||||||
return done(Math.max(0, i - 2));
|
|
||||||
|
|
||||||
self._saveEntry(entry);
|
// Do some paranoid checks.
|
||||||
lastEntry = entry;
|
if (lastEntry && entry.prevBlock !== lastEntry.hash) {
|
||||||
i += 1;
|
utils.debug('Electrum headers are corrupt. Resetting.');
|
||||||
next();
|
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