handle verification better. make use of cache.

This commit is contained in:
Christopher Jeffrey 2016-02-19 20:57:06 -08:00
parent ad95ffbfcd
commit 8ed054cbda
2 changed files with 78 additions and 52 deletions

View File

@ -1131,67 +1131,27 @@ Chain.prototype.add = function add(initial, peer, callback, force) {
// Lookup previous entry.
// We can do this synchronously:
// it is already cached.
prev = self.db.getSync(prevHeight);
// This will be cached in 99.9% of cases.
if (!self.db.isCached(prevHeight))
utils.debug('Warning: height %d is not cached.', prevHeight);
try {
prev = self.db.getSync(prevHeight);
} catch (e) {
return done(e);
}
assert(prev);
// Do "contextual" verification on our block
// now that we're certain its previous
// block is in the chain.
self._verifyContext(block, prev, function(err, verified) {
var existing;
if (err)
return done(err);
// Real fork resolution would just be this.
// if (entry.chainwork.cmp(self.tip.chainwork) > 0)
// return self.setBestChain(entry);
// return done();
// See if the entry already exists.
if (self.db.has(entry.height)) {
return self.db.getAsync(entry.height, function(err, existing) {
if (err)
return done(err);
// Shouldn't be the same by this point.
assert(existing.hash !== entry.hash);
// A valid block with an already existing
// height came in, that spells fork. We
// don't store by hash so we can't compare
// chainworks. We reset the chain, find a
// new peer, and wait to see who wins.
assert(self.db.getHeight(entry.hash) === -1);
// The tip has more chainwork, it is a
// higher height than the entry. This is
// not an alternate tip. Ignore it.
if (existing.chainwork.cmp(entry.chainwork) > 0)
return done();
// The block has equal chainwork (an
// alternate tip). Reset the chain, find
// a new peer, and wait to see who wins.
// self.revertHeight(existing.height - 1, function(err) {
self._revertLast(existing, function(err, existingBlock) {
if (err)
return done(err);
self.emit('fork', block, {
height: existing.height,
expected: existing.hash,
received: entry.hash,
checkpoint: false
}, peer);
return done();
}, true);
});
}
// Add entry if we do not have it.
assert(self.db.getHeight(entry.hash) === -1);
if (!verified) {
self.invalid[entry.hash] = true;
self.emit('invalid', block, {
@ -1203,6 +1163,62 @@ Chain.prototype.add = function add(initial, peer, callback, force) {
return done();
}
// Real fork resolution would just be this.
// if (entry.chainwork.cmp(self.tip.chainwork) > 0)
// return self.setBestChain(entry);
// return done();
// See if the height already exists (fork).
// Do this synchronously: This will
// be cached in 99.9% of cases.
if (self.db.has(entry.height)) {
if (!self.db.isCached(entry.height))
utils.debug('Warning: height %d is not cached.', entry.height);
try {
existing = self.db.getSync(entry.height);
} catch (e) {
return done(e);
}
// Shouldn't be the same by this point.
assert(existing.hash !== entry.hash);
// A valid block with an already existing
// height came in, that spells fork. We
// don't store by hash so we can't compare
// chainworks. We reset the chain, find a
// new peer, and wait to see who wins.
assert(self.db.getHeight(entry.hash) === -1);
// The tip has more chainwork, it is a
// higher height than the entry. This is
// not an alternate tip. Ignore it.
if (existing.chainwork.cmp(entry.chainwork) > 0)
return done();
// The block has equal chainwork (an
// alternate tip). Reset the chain, find
// a new peer, and wait to see who wins.
// return self.revertHeight(existing.height - 1, function(err) {
return self._revertLast(existing, function(err, existingBlock) {
if (err)
return done(err);
self.emit('fork', block, {
height: existing.height,
expected: existing.hash,
received: entry.hash,
checkpoint: false
}, peer);
return done();
}, true);
}
// Add entry if we do not have it.
assert(self.db.getHeight(entry.hash) === -1);
// Update the block height
block.height = entry.height;
block.txs.forEach(function(tx) {

View File

@ -243,6 +243,16 @@ ChainDB.prototype._cache = function _cache(entry) {
}
};
ChainDB.prototype.isCached = function isCached(height) {
if (this.queue[height] != null)
return true;
if (this.cache[height] != null)
return true;
return false;
};
ChainDB.prototype.getHeight = function getHeight(hash) {
var height = this.heightLookup[hash];