chain: initial add refactor.
This commit is contained in:
parent
0f529d5f8b
commit
923364a70a
@ -1200,6 +1200,40 @@ Chain.prototype.add = co(function* add(block) {
|
||||
}
|
||||
});
|
||||
|
||||
Chain.prototype.storeOrphan = function storeOrphan(block) {
|
||||
var hash = block.hash('hex');
|
||||
var height = block.getCoinbaseHeight();
|
||||
|
||||
this.orphan.count++;
|
||||
this.orphan.size += block.getSize();
|
||||
this.orphan.map[block.prevBlock] = block;
|
||||
this.orphan.bmap[hash] = block;
|
||||
|
||||
// Update the best height based on the coinbase.
|
||||
// We do this even for orphans (peers will send
|
||||
// us their highest block during the initial
|
||||
// getblocks sync, making it an orphan).
|
||||
if (height > this.bestHeight)
|
||||
this.bestHeight = height;
|
||||
|
||||
this.emit('orphan', block, height);
|
||||
};
|
||||
|
||||
Chain.prototype.resolveOrphan = function resolveOrphan(hash) {
|
||||
var block = this.orphan.map[hash];
|
||||
|
||||
if (!block)
|
||||
return;
|
||||
|
||||
delete this.orphan.bmap[block.hash('hex')];
|
||||
delete this.orphan.map[hash];
|
||||
|
||||
this.orphan.count--;
|
||||
this.orphan.size -= block.getSize();
|
||||
|
||||
return block;
|
||||
};
|
||||
|
||||
/**
|
||||
* Add a block to the chain without a lock.
|
||||
* @private
|
||||
@ -1209,21 +1243,22 @@ Chain.prototype.add = co(function* add(block) {
|
||||
|
||||
Chain.prototype._add = co(function* add(block) {
|
||||
var ret = new VerifyResult();
|
||||
var now = this.network.now();
|
||||
var initial = true;
|
||||
var hash, prevBlock, height, checkpoint;
|
||||
var orphan, entry, existing, prev;
|
||||
var hash, height, checkpoint;
|
||||
var orphan, entry, prev;
|
||||
|
||||
while (block) {
|
||||
hash = block.hash('hex');
|
||||
prevBlock = block.prevBlock;
|
||||
height = -1;
|
||||
|
||||
// Mark the start time.
|
||||
this.mark();
|
||||
|
||||
// Special case for genesis block.
|
||||
if (hash === this.network.genesis.hash)
|
||||
break;
|
||||
|
||||
// Do not revalidate known invalid blocks.
|
||||
if (this.invalid[hash] || this.invalid[prevBlock]) {
|
||||
if (this.invalid[hash] || this.invalid[block.prevBlock]) {
|
||||
this.emit('invalid', block, block.getCoinbaseHeight());
|
||||
this.invalid[hash] = true;
|
||||
throw new VerifyError(block, 'duplicate', 'duplicate', 100);
|
||||
@ -1237,24 +1272,25 @@ Chain.prototype._add = co(function* add(block) {
|
||||
|
||||
// If the block is already known to be
|
||||
// an orphan, ignore it.
|
||||
orphan = this.orphan.map[prevBlock];
|
||||
orphan = this.orphan.map[block.prevBlock];
|
||||
if (orphan) {
|
||||
// The orphan chain forked.
|
||||
if (orphan.hash('hex') !== hash) {
|
||||
this.emit('fork', block,
|
||||
block.getCoinbaseHeight(),
|
||||
orphan.hash('hex'));
|
||||
|
||||
this.resolveOrphan(block.prevBlock);
|
||||
this.storeOrphan(block);
|
||||
|
||||
throw new VerifyError(block, 'invalid', 'bad-prevblk', 0);
|
||||
}
|
||||
|
||||
this.emit('orphan', block, block.getCoinbaseHeight());
|
||||
|
||||
throw new VerifyError(block, 'invalid', 'bad-prevblk', 0);
|
||||
throw new VerifyError(block, 'duplicate', 'duplicate', 0);
|
||||
}
|
||||
|
||||
// Special case for genesis block.
|
||||
if (hash === this.network.genesis.hash)
|
||||
break;
|
||||
|
||||
// Validate the block we want to add.
|
||||
// This is only necessary for new
|
||||
// blocks coming in, not the resolving
|
||||
@ -1266,43 +1302,28 @@ Chain.prototype._add = co(function* add(block) {
|
||||
throw new VerifyError(block, 'invalid', ret.reason, ret.score);
|
||||
}
|
||||
|
||||
existing = yield this.db.hasEntry(hash);
|
||||
|
||||
// Do we already have this block?
|
||||
if (existing) {
|
||||
if (yield this.db.hasEntry(hash)) {
|
||||
this.emit('exists', block, block.getCoinbaseHeight());
|
||||
throw new VerifyError(block, 'duplicate', 'duplicate', 0);
|
||||
}
|
||||
|
||||
// Find the previous block height/index.
|
||||
prev = yield this.db.getEntry(prevBlock);
|
||||
|
||||
if (prev)
|
||||
height = prev.height + 1;
|
||||
|
||||
if (height > this.bestHeight)
|
||||
this.bestHeight = height;
|
||||
prev = yield this.db.getEntry(block.prevBlock);
|
||||
|
||||
// If previous block wasn't ever seen,
|
||||
// add it current to orphans and break.
|
||||
if (!prev) {
|
||||
this.orphan.count++;
|
||||
this.orphan.size += block.getSize();
|
||||
this.orphan.map[prevBlock] = block;
|
||||
this.orphan.bmap[hash] = block;
|
||||
|
||||
// Update the best height based on the coinbase.
|
||||
// We do this even for orphans (peers will send
|
||||
// us their highest block during the initial
|
||||
// getblocks sync, making it an orphan).
|
||||
if (block.getCoinbaseHeight() > this.bestHeight)
|
||||
this.bestHeight = block.getCoinbaseHeight();
|
||||
|
||||
this.emit('orphan', block, block.getCoinbaseHeight());
|
||||
|
||||
this.storeOrphan(block);
|
||||
throw new VerifyError(block, 'invalid', 'bad-prevblk', 0);
|
||||
}
|
||||
|
||||
height = prev.height + 1;
|
||||
|
||||
// Update best height seen.
|
||||
if (height > this.bestHeight)
|
||||
this.bestHeight = height;
|
||||
|
||||
// Verify the checkpoint.
|
||||
if (this.options.useCheckpoints) {
|
||||
checkpoint = this.network.checkpoints[height];
|
||||
@ -1386,25 +1407,14 @@ Chain.prototype._add = co(function* add(block) {
|
||||
// Keep track of stats.
|
||||
this.finish(block, entry);
|
||||
|
||||
// No orphan chain.
|
||||
if (!this.orphan.map[hash])
|
||||
break;
|
||||
|
||||
// An orphan chain was found, start resolving.
|
||||
// Try to resolve orphan chain.
|
||||
block = this.resolveOrphan(hash);
|
||||
initial = false;
|
||||
block = this.orphan.map[hash];
|
||||
delete this.orphan.bmap[block.hash('hex')];
|
||||
delete this.orphan.map[hash];
|
||||
this.orphan.count--;
|
||||
this.orphan.size -= block.getSize();
|
||||
}
|
||||
|
||||
// Failsafe for large orphan chains. Do not
|
||||
// allow more than 20mb stored in memory.
|
||||
if (this.orphan.size > this.orphanLimit)
|
||||
this.pruneOrphans();
|
||||
|
||||
yield co.wait();
|
||||
this.pruneOrphans();
|
||||
|
||||
if (!this.synced && this.isFull()) {
|
||||
this.synced = true;
|
||||
@ -1497,10 +1507,13 @@ Chain.prototype.purgeOrphans = function purgeOrphans() {
|
||||
Chain.prototype.pruneOrphans = function pruneOrphans() {
|
||||
var i, hashes, hash, orphan, height, best, last;
|
||||
|
||||
if (this.orphan.size <= this.orphanLimit)
|
||||
return false;
|
||||
|
||||
hashes = Object.keys(this.orphan.map);
|
||||
|
||||
if (hashes.length === 0)
|
||||
return;
|
||||
return false;
|
||||
|
||||
for (i = 0; i < hashes.length; i++) {
|
||||
hash = hashes[i];
|
||||
@ -1540,6 +1553,8 @@ Chain.prototype.pruneOrphans = function pruneOrphans() {
|
||||
this.orphan.bmap[best.hash('hex')] = best;
|
||||
this.orphan.count = 1;
|
||||
this.orphan.size = best.getSize();
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
Loading…
Reference in New Issue
Block a user