-
Notifications
You must be signed in to change notification settings - Fork 46
Description
We have come up with a series of issues to handle forks: #687, #690 (loosely related), and #691. Here I want to come up with a kind of different paradigm, which is closer to blockchain thinking and how substrate does it. Instead of handling roll-backs, we should rather handle forks as branches, operate on a branch based on a certain strategy, and upon finalization, we discard all invalid branches, and commit the finalized data to the state.
On big advantage of this is, substrate has an abstraction for this ForkTree:
Utility library for managing tree-like ordered data with logic for pruning the tree while finalizing nodes.
I have yet to understand the fork-tree to 100%. The following is my current understanding.
This fork tree is very abstract, the data associated with the fork-tree can be anything. I suggest that this data is the accumulated changeset since the last finalized state (maybe including the associated trusted calls that we have executed). Hence, my suggestion is keeping only finalized states as snapshots. All accumulated unfinalized changes will be kept in the fork-tree. When a node in the fork-tree is finalized, it will return the associated data, i.e., the change-set in our case, which we can commit to our finalized state leading to the new finalized state.
Substrate uses the several fork-trees depending on the context, we could also use a separate fork-tree for tracking the state of inblock/finalized transactions.
I think the beauty of this task is that it does not require different handling depending on whether we are on a fork or not, we will always call finalize on one of the tree's branches. The only exception that needs to be covered is if the finalized block does not exist in our fork-tree, which means we must fetch the state from another worker.
To be precise, this issue is not really a task in itself, it rather suggests an overarching strategy how other tasks can be solved that are all subject to fork handling.
Implications of this approach on existing issues:
- Check and act upon sidechain block finalization from parentchain #691 changes the strategy, we always call finalized on the fork-tree nodes, instead of differentiating behaviour based on if we are on the correct branch or not. (the only exception is TOPs, what happens to tops that are not on the finalized branch?)
- Implement roll-back mechanism for sidechain block and state #690 there will be no rollback. Instead, the accumulated state-diff will be applied to the persisted state. So from my point of view, we can remove this task.
- Detect and track forks upon processing sidechain block import queue #687 will be simplified, tracking a fork will simply mean that we insert a new branch in the fork-tree
- Apply 'InBlock' and 'Finalized' state concepts to transactions in the TOP pool #689 can also profit from the fork-tree: non-finalized transactions are put into the fork-tree. When a branch is finalized, all the finalized TOPs are returned and can be removed from the TOP-pool.