-
Notifications
You must be signed in to change notification settings - Fork 1.1k
fatp: Implement blockchain revert handling #10453
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Conversation
Add support for handling blockchain revert. This is useful in testing.
Changes:
- Add ChainEvent::Reverted variant to represent backward blockchain progression
- Implement handle_reverted() method that:
* Collects transactions from retracted blocks via included_transactions cache
or by fetching block bodies from the API
* Removes all views beyond the revert point to prevent zombie views
* Removes included transactions from mempool (they can be resubmitted later)
* Updates enactment state (recent_finalized_block and recent_best_block)
* Ensures a valid view exists at the revert target block
- Add early return in maintain() for Reverted events to prevent normal
forward-progression logic from running
These changes fix issues where reverting would leave zombie views in the view store,
causing issues at subsequent operations.
Note: Transactions that were pending may not be visible after revert if they fail the
revalidation
Signed-off-by: Alexandru Cihodaru <[email protected]>
|
/cmd fmt |
|
/cmd prdoc --audience runtime_dev --bump patch |
…time_dev --bump patch'
Signed-off-by: Alexandru Cihodaru <[email protected]>
substrate/client/transaction-pool/src/common/enactment_state.rs
Outdated
Show resolved
Hide resolved
substrate/client/transaction-pool/src/fork_aware_txpool/fork_aware_txpool.rs
Outdated
Show resolved
Hide resolved
substrate/client/transaction-pool/src/fork_aware_txpool/fork_aware_txpool.rs
Outdated
Show resolved
Hide resolved
Signed-off-by: Alexandru Cihodaru <[email protected]>
substrate/client/transaction-pool/src/fork_aware_txpool/fork_aware_txpool.rs
Outdated
Show resolved
Hide resolved
substrate/client/transaction-pool/src/fork_aware_txpool/fork_aware_txpool.rs
Outdated
Show resolved
Hide resolved
|
DQ: Is it realistic scenario? Should we handle this properly? If we revert from If we assume that revert can only be called if there is single fork - should we somehow check this in |
Excellent question. I think that in anvil it is not possible to have such a scenario but I believe that we should delete the transactions on all possible paths. |
iulianbarbu
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good in general. It would be great to capture in the event the idea of reverting all existing forks, to have this logic appliable not just to single chain nodes like anvil-polkadot - but tbh not super sure how difficult it is.
Signed-off-by: Alexandru Cihodaru <[email protected]>
|
/cmd fmt |
|
Changes applied to
I guess this PR is ready for review now |
|
We hade some offline discussions with @AlexandruCihodaru regarding this PR. I am leaving here the main concerns I still have about this PR: 1. Inconsistent handling of included vs. in-pool transactions Current implementation removes only transactions included in reverted blocks. Transactions still in ready/future queues are left untouched, even though they may have been sent at the same time. After revert:
This is behavior is inconsistent and hard to understand. It is impossible to control what transactions we have in pool. I would propose to provide explicit API for removal - decouple "remove transactions" from "revert chain" (which are orthogonal operations), giving the node builders flexibility to implement their desired behavior. 2. Missing Dropped event for watchers When using The event flow 3. Better documentation of behavior needed Whatever behavior is chosen, it should be documented (perhaps in
Possible approaches
I think approach 3 is the cleanest. |
|
@michalkucharczyk hadn't we discussed some time ago that it would be the simplest to just re-create the tx pool? So, not requiring any of this code here? |
Could be a solution, but it may have some limitation. E.g.
It depends on the requirements the manual-seal / anvil node has from the reverting mechanism. Honestly I am not sure how they should work, so I try to build mechanism which is flexible enough to handle different scenarios and does not pull specifics of anvil node into the generic pool. |
|
New changes from 121a9be Decoupling the transaction removal from chain revert handling. Now:
Implementation Details
@michalkucharczyk what do you think of this new implementation? |
You can just rebuild B1 by sending all the transactions again. I would assume that the anvil stuff still has all the transactions. Right now this pull request is trying to add a feature that is never used for normal operations and will never be used for them. |
|
technically you would need to “import block” (call pool’s maintain), and resubmit transactions, but this is detail. I see your point, if we can get all the functionality and avoid new complexity in the code - I am all in :). Question if anvil node would be happy with this - I don’t know the answer… Maybe @AlexandruCihodaru or @alindima can comment on this proposal. |
|
Also if we want to have anvil node in our contracts (reliability) toolset, then it becomes normal-like operation, we need to support it, test, etc… |
By "normal operation" I meant anything that you need to run a blockchain network. This here is for testing. I'm not saying that this is not important, but if we can achieve the same results if we don't need to modify the internals of tx pool, we should not do this. Just adds more complexity that we can move closer to where it is needed (anvil node). |
|
Chain reversion is something that can happen in polkadot under "normal" protocol operation (although in the case of disputes, which are exceptional). I remember @sandreim mentioning some issues with the txpool on reversion as well (on some polkadot-based network or locally, not on an anvil-based instance).
No, anvil uses the txpool from substrate, does not have a wrapper over it. Of course, we could have implemented our own txpool but there was no good reason for it at the time (the substrate txpool looked flexible enough for our use case). Since chain reversion is something that needs to work regardless of whether or not anvil uses it, I'd much rather solve this problem for good in here rather than adding a reimplementation to work around this |
|
I think the point is to re-use the existing txpool in anvil-specific pool-wrapper. The inner pool could be dropped and new instance of substrate could be created as inner when reversion happens. I don't have enough information about anvil-node scenarios to judge if this approach is feasible, and if all scenarios can be covered. The ultimate code is to reduce complexity in existing pool. |
|
All GitHub workflows were cancelled due to failure one of the required jobs. |
Chain reversion are not happening under normal protocol operations. We are forking, if an invalid candidate was found by approval voting. But we do not revert, especially we do not revert the finalized chain. |
The context is some block was dropped in RC (never backed on chain). "revert" indeed is not the right word here, forking is accurate, but the percieved effect by the user is that the chain state has been reverted up to the blockheight that we start building the fork on. What I was expecting to happen is that the transactions that were included in the abandoned fork are included in the new one. |
That is happening and if not, it is a bug :) Maybe directly try the forkaware transaction pool, but this should only be required on parachains. For the relay chain the normal tx pool should handle it correctly. But ahh, yeah for the fork case in Polkadot we will not change the best chain until we have a longer/better chain that the old one. So, the old tx pool will not insert the transactions. If you use the forkaware tx pool it should fix this behavior. |
I was using the FATP and I was hitting this on every session boundary (when we clearly drop blocks). |
https://github.com/paritytech/polkadot-sdk/issues/new/choose and ping @michalkucharczyk :D |
|
After reading your comments and investigating the original anvil implementation more in detail, I propose we simplify this PR to only keep what's truly fundamental for anvil revert methods, so the What do you think? @bkchr @michalkucharczyk |
But wouldn't this be solved by just recreating the tx pool? |
That would be technically possible. We would need to copy all transactions from the mempool and carry them to the new pool. I can try implementing it directly in The remaining issue that won't be solved is that watchers from |
|
I dove deeper into
Moreover, all stream subscribers require explicit refresh/reset: mining engine needs to be refreshed, pending transaction filters need to be recreated... This is not a bug, but more a tedious operation. After all that, I still believe that supporting some basic revert functionalities in the Substrate Transaction Pool remains useful for Anvil and for whoever needs a bug-free revert on a Substrate chain. |
|
hm, you should also intercept submit/submit and watch in wrapper. you also can intercept the listener? so orphaned listener should not be a problem. I don’t think transaction source is a problem. You want to resubmit transactions (to new inner pool) previously submitted to wrapper, right? |
You're right. I can intercept all submissions and store the metadata in the wrapper, I can also edit all relevant streams (like pending transaction filters and the mining engine too) to check for pool recreations at each poll. So, in the end, it's technically possible to build a bug-free tx pool wrapper to support reverts, but it's more error-prone and significantly more complex than allowing a basic revert in the Substrate pool. If you think that revert complexity doesn’t justify changing Substrate, I’m fine limiting the changes to Anvil. Please let me know which direction you prefer. |
Let's try to implement it and compare it. I don't see why this should be complicated. |
Add support for handling blockchain revert. This is useful in testing.
Changes:
These changes fix issues where reverting would leave zombie views in the view store, causing issues at subsequent operations.
Note: Transactions that were pending may not be visible after revert if they fail the revalidation