chain: refactor disconnection.

This commit is contained in:
Christopher Jeffrey 2016-12-10 06:30:04 -08:00
parent 092c1a90df
commit c9523d91a5
No known key found for this signature in database
GPG Key ID: 8962AB9DE6666BBD
2 changed files with 57 additions and 45 deletions

View File

@ -826,7 +826,7 @@ Chain.prototype.reorganizeSPV = co(function* reorganizeSPV(competitor, block) {
var fork = yield this.findFork(tip, competitor);
var disconnect = [];
var entry = tip;
var i;
var i, block, view;
assert(fork, 'No free space or data corruption.');
@ -847,7 +847,9 @@ Chain.prototype.reorganizeSPV = co(function* reorganizeSPV(competitor, block) {
// the chain has successfully reset.
for (i = 0; i < disconnect.length; i++) {
entry = disconnect[i];
this.emit('disconnect', entry, entry.toHeaders());
block = entry.toHeaders();
view = new CoinView();
this.emit('disconnect', entry, block, view);
}
this.emit('reorganize', block, tip.height, tip.hash);
@ -860,8 +862,17 @@ Chain.prototype.reorganizeSPV = co(function* reorganizeSPV(competitor, block) {
*/
Chain.prototype.disconnect = co(function* disconnect(entry) {
var block = yield this.db.disconnect(entry);
var prev = yield entry.getPrevious();
var block = yield this.db.getBlock(entry.hash);
var prev, view;
if (!block) {
if (!this.options.spv)
throw new Error('Block not found.');
block = entry.toHeader();
}
prev = yield entry.getPrevious();
view = yield this.db.disconnect(entry, block);
assert(prev);
@ -870,7 +881,7 @@ Chain.prototype.disconnect = co(function* disconnect(entry) {
this.bestHeight = prev.height;
this.emit('tip', prev);
this.emit('disconnect', entry, block);
this.emit('disconnect', entry, block, view);
});
/**
@ -886,11 +897,10 @@ Chain.prototype.reconnect = co(function* reconnect(entry) {
var block = yield this.db.getBlock(entry.hash);
var prev, result;
if (this.options.spv) {
assert(!block);
block = entry.toHeaders();
} else {
assert(block);
if (!block) {
if (!this.options.spv)
throw new Error('Block not found.');
block = entry.toHeader();
}
prev = yield entry.getPrevious();
@ -983,8 +993,8 @@ Chain.prototype.setBestChain = co(function* setBestChain(entry, block, prev) {
this.setDeploymentState(result.state);
this.emit('tip', entry);
return result.view;
this.emit('block', block, entry);
this.emit('connect', entry, block, result.view);
});
/**
@ -1023,6 +1033,9 @@ Chain.prototype.saveAlternate = co(function* saveAlternate(entry, block, prev) {
}
yield this.db.save(entry, block);
// Emit as a "competitor" block.
this.emit('competitor', block, entry);
});
/**
@ -1212,7 +1225,7 @@ Chain.prototype.add = co(function* add(block) {
Chain.prototype._add = co(function* add(block) {
var ret = new VerifyResult();
var initial = true;
var hash, height, entry, prev, view;
var hash, height, entry, prev;
while (block) {
hash = block.hash('hex');
@ -1319,19 +1332,11 @@ Chain.prototype._add = co(function* add(block) {
// Save block to an alternate chain.
yield this.saveAlternate(entry, block, prev);
// Emit as a "competitor" block.
this.emit('competitor', block, entry);
if (!initial)
this.emit('competitor resolved', block, entry);
} else {
// Attempt to add block to the chain index.
view = yield this.setBestChain(entry, block, prev);
// Emit our block (and potentially resolved
// orphan) only if it is on the main chain.
this.emit('block', block, entry);
this.emit('connect', entry, block, view);
yield this.setBestChain(entry, block, prev);
if (!initial)
this.emit('resolved', block, entry);

View File

@ -1347,16 +1347,17 @@ ChainDB.prototype._reconnect = co(function* reconnect(entry, block, view) {
/**
* Disconnect block from the chain.
* @param {ChainEntry} entry
* @param {Block} block
* @returns {Promise}
*/
ChainDB.prototype.disconnect = co(function* disconnect(entry) {
ChainDB.prototype.disconnect = co(function* disconnect(entry, block) {
var block;
this.start();
try {
block = yield this._disconnect(entry);
block = yield this._disconnect(entry, block);
} catch (e) {
this.drop();
throw e;
@ -1371,11 +1372,12 @@ ChainDB.prototype.disconnect = co(function* disconnect(entry) {
* Disconnect block without a batch.
* @private
* @param {ChainEntry} entry
* @returns {Promise}
* @param {Block} block
* @returns {Promise} - Returns {@link CoinView}.
*/
ChainDB.prototype._disconnect = co(function* disconnect(entry) {
var block;
ChainDB.prototype._disconnect = co(function* disconnect(entry, block) {
var view;
// Remove hash->next-block index.
this.del(layout.n(entry.prevBlock));
@ -1387,18 +1389,13 @@ ChainDB.prototype._disconnect = co(function* disconnect(entry) {
// Update state caches.
this.saveUpdates();
block = yield this.getBlock(entry.hash);
if (!block)
throw new Error('Block not found.');
// Disconnect inputs.
yield this.disconnectBlock(entry, block);
view = yield this.disconnectBlock(entry, block);
// Revert chain state to previous tip.
this.put(layout.R, this.pending.commit(entry.prevBlock));
return block;
return view;
});
/**
@ -1562,18 +1559,21 @@ ChainDB.prototype._removeChain = co(function* removeChain(hash) {
/**
* Save a block (not an entry) to the
* database and potentially connect the inputs.
* @param {ChainEntry} entry
* @param {Block} block
* @param {Boolean} connect - Whether to connect the inputs.
* @param {CoinView?} view
* @returns {Promise} - Returns {@link Block}.
*/
ChainDB.prototype.saveBlock = co(function* saveBlock(entry, block, view) {
var hash = block.hash();
if (this.options.spv)
return;
// Write actual block data (this may be
// better suited to flat files in the future).
this.put(layout.b(block.hash()), block.toRaw());
this.put(layout.b(hash), block.toRaw());
if (!view)
return;
@ -1630,11 +1630,14 @@ ChainDB.prototype.saveView = function saveView(view) {
/**
* Connect block inputs.
* @param {ChainEntry} entry
* @param {Block} block
* @param {CoinView} view
* @returns {Promise} - Returns {@link Block}.
*/
ChainDB.prototype.connectBlock = co(function* connectBlock(entry, block, view) {
var hash = block.hash();
var i, j, tx, input, output;
if (this.options.spv)
@ -1675,7 +1678,7 @@ ChainDB.prototype.connectBlock = co(function* connectBlock(entry, block, view) {
// Write undo coins (if there are any).
if (!view.undo.isEmpty())
this.put(layout.u(block.hash()), view.undo.commit());
this.put(layout.u(hash), view.undo.commit());
// Prune height-288 if pruning is enabled.
yield this.pruneBlock(entry);
@ -1683,18 +1686,20 @@ ChainDB.prototype.connectBlock = co(function* connectBlock(entry, block, view) {
/**
* Disconnect block inputs.
* @param {Block|Hash} block - {@link Block} or hash.
* @returns {Promise} - Returns {@link Block}.
* @param {ChainEntry} entry
* @param {Block} block
* @returns {Promise} - Returns {@link CoinView}.
*/
ChainDB.prototype.disconnectBlock = co(function* disconnectBlock(entry, block) {
var i, j, view, undo, tx, input, output;
var view = new CoinView();
var hash = block.hash();
var i, j, undo, tx, input, output;
if (this.options.spv)
return;
return view;
view = new CoinView();
undo = yield this.getUndoCoins(block.hash());
undo = yield this.getUndoCoins(hash);
this.pending.disconnect(block);
@ -1735,14 +1740,16 @@ ChainDB.prototype.disconnectBlock = co(function* disconnectBlock(entry, block) {
this.saveView(view);
// Remove undo coins.
this.del(layout.u(block.hash()));
this.del(layout.u(hash));
return view;
});
/**
* Prune a block from the chain and
* add current block to the prune queue.
* @private
* @param {Block}
* @param {ChainEntry} entry
* @returns {Promise}
*/