better preload. misc fixes.

This commit is contained in:
Christopher Jeffrey 2016-02-09 00:07:04 -08:00
parent 05d4eab0d8
commit 17e25804de
4 changed files with 45 additions and 15 deletions

View File

@ -304,9 +304,6 @@ Block.prototype.verifyContext = function verifyContext() {
var sigops = 0;
var prev, height, ts, i, j, tx, cb, input;
if (this.subtype !== 'block')
return true;
if (this.isGenesis())
return true;
@ -363,6 +360,10 @@ Block.prototype.verifyContext = function verifyContext() {
// return false;
// }
// Can't verify any further when merkleblock or headers.
if (this.subtype !== 'block')
return true;
// Make sure the height contained in the coinbase is correct.
if (this.version >= 2 && prev.isUpgraded(2)) {
cb = bcoin.script.getCoinbaseData(this.txs[0].inputs[0].script);

View File

@ -96,7 +96,7 @@ Chain.prototype._init = function _init() {
utils.debug('Chain is loading.');
this.preload(function(err, start) {
this._preload(function(err, start) {
if (err) {
utils.debug('Preloading chain failed.');
utils.debug('Reason: %s', err.message);
@ -143,7 +143,12 @@ Chain.prototype._init = function _init() {
});
};
Chain.prototype.preload = function preload(callback) {
// Stream headers from electrum.org for quickly
// preloading the chain. Electrum.org stores
// headers in the standard block header format,
// but they do not store chainwork, so we have
// to calculate it ourselves.
Chain.prototype._preload = function _preload(callback) {
var self = this;
var url = 'https://headers.electrum.org/blockchain_headers';
var chainHeight, buf, height, stream;
@ -202,6 +207,7 @@ Chain.prototype.preload = function preload(callback) {
blocks.forEach(function(data) {
var entry = bcoin.chainblock.fromRaw(self, height, data);
var block = bcoin.block(entry, 'headers');
var start;
// Do some paranoid checks.
@ -212,18 +218,34 @@ Chain.prototype.preload = function preload(callback) {
return callback(new Error('Corrupt headers.'), start + 1);
}
// Verify the block headers. We don't want to
// trust an external centralized source completely.
// For very paranoid but slower validation:
// if (!block.verify() || !block.verifyContext()) {
if (!block.verify()) {
start = Math.max(0, height - 2);
stream.destroy();
self.resetHeight(start);
return callback(new Error('Bad headers.'), start + 1);
}
lastEntry = entry;
delete entry.chainwork;
entry.chainwork = entry.getChainwork();
// Skip the genesis block in case it ends up being corrupt
// Skip the genesis block in case
// it ends up being corrupt.
if (height === 0) {
height++;
return;
}
self._saveEntry(entry, height > chainHeight);
// Don't write blocks we already have
// (bad for calculating chainwork).
// self._saveEntry(entry, height > chainHeight);
self._saveEntry(entry, true);
height++;
@ -630,7 +652,7 @@ Chain.prototype.fillPercent = function fillPercent() {
};
Chain.prototype.hashRange = function hashRange(start, end) {
var hashes;
var hashes = [];
start = this.byTime(start);
end = this.byTime(end);
@ -694,13 +716,15 @@ Chain.prototype.getLocator = function getLocator(start) {
Chain.prototype.getOrphanRoot = function getOrphanRoot(hash) {
var self = this;
var root = hash;
var root;
if (utils.isBuffer(hash))
hash = utils.toHex(hash);
else if (hash.hash)
hash = hash.hash('hex');
root = hash;
while (this.orphan.bmap[hash]) {
root = hash;
hash = this.orphan.bmap[hash].prevBlock;

View File

@ -1163,7 +1163,10 @@ TX.prototype.sortMembers = function sortMembers() {
}
this.inputs = this.inputs.slice().sort(function(a, b) {
var res = new bn(a.prevout.hash, 'hex').cmp(new bn(b.prevout.hash, 'hex'));
var h1 = utils.toArray(a.prevout.hash, 'hex');
var h2 = utils.toArray(b.prevout.hash, 'hex');
var res = utils.cmp(h1, h2);
if (res !== 0)
return res;
@ -1178,7 +1181,7 @@ TX.prototype.sortMembers = function sortMembers() {
a = bcoin.script.encode(a.script);
b = bcoin.script.encode(b.script);
return new bn(a).cmp(b);
return utils.cmp(a, b);
});
if (this.changeIndex !== -1) {

View File

@ -787,13 +787,13 @@ utils.hidden = function hidden(obj, prop, value) {
utils.sortKeys = function sortKeys(keys) {
return keys.slice().sort(function(a, b) {
return new bn(a).cmp(new bn(b)) > 0;
return utils.cmp(a, b);
});
};
utils.sortHDKeys = function sortHDKeys(keys) {
return keys.slice().sort(function(a, b) {
return new bn(a.publicKey).cmp(new bn(b.publicKey)) > 0;
return utils.cmp(a.publicKey, b.publicKey);
});
};
@ -1381,16 +1381,18 @@ utils.cmp = function(a, b) {
return 0;
};
// https://cryptocoding.net/index.php/Coding_rules
// memcmp in constant time (can only return true or false)
// https://cryptocoding.net/index.php/Coding_rules
// $ man 3 memcmp (see NetBSD's consttime_memequal)
// This protects us against timing attacks when
// comparing an input against a secret string.
utils.ccmp = function(a, b) {
var res, i;
assert(a.length === b.length);
for (i = 0; i < a.length; i++)
res = a[i] ^ b[i];
res |= a[i] ^ b[i];
return res === 0;
};