chain: refactor disconnection.
This commit is contained in:
parent
092c1a90df
commit
c9523d91a5
@ -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);
|
||||
|
||||
@ -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}
|
||||
*/
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user