-
Notifications
You must be signed in to change notification settings - Fork 2.6k
Finalized block event triggers tx maintanance #12305
Finalized block event triggers tx maintanance #12305
Conversation
Signed-off-by: Michal Kucharczyk <1728078+michalkucharczyk@users.noreply.github.com>
…-triggers-tx-maintanance
ChainApi::tree_route return type changed to Result<Option<..>>, as some implementations (tests) are not required to provide this tree route.
(thanks to @koute)
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.
While reviewing this PR I was trying to come up with a way to simplify this. I also think there is another bug with the original implementation, i.e. when we retract blocks by finalizing some other fork we don't re-add the retracted transactions to the pool (since we only run that logic on NewBestBlock
events). Let's try to break down the problem:
- We want to keep track of some "canon" block that represents our internal status of tx pool "enactment"
- This block can be updated either by processing
NewBestBlock
events orFinalized
events and it should work properly under "inconsistent" ordering of events - Whenever we update this "canon" block we can retract blocks (in comparison to our previous "canon"), enact new blocks and also finalize some blocks
- For the retracted blocks we want to extract the txs in them and re-add them to the pool
- For enacted blocks we want to extract the txs in them and remove them from the pool
- For finalized blocks we want to notify this to tx pool listeners
I think the overall logic should be:
- Compute new "canon" block on new event
- Compute enacted, retracted and finalized in relation to new event
- Do all the actions in "maintain" regardless of event type but instead using the extracted values above
To compute "canon" block and the remaining necessary data we do as follows (roughly the stuff that's being done in update_and_check_if_new_enactment_is_valid
now):
- When we receive a
NewBestBlock
event we calculate the tree route between our "canon" block and the block in the event. If there are no enacted blocks then we can ignore the event (we can ignore retracted blocks since they must have been processed in an earlier event). If there are enacted blocks then we update our "canon" block to this block and we return the given enacted, retracted from the tree route we computed and no finalized blocks - When we receive a
Finalized
event we calculate the tree route between our "canon" block and the block in the event, we then return the enacted and retracted from this route, and we return the finalized blocks from the tree route that comes from the event. We update our "canon" block to the finalized block from the event
Let me know what you think about this, it's very possible my logic is faulty.
Co-authored-by: André Silva <123550+andresilva@users.noreply.github.com>
After talking to @michalkucharczyk there is something wrong in my suggestion above which is that my solution treats "conflicting" |
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.
Some last nitpicks, otherwise it looks good 👍
Co-authored-by: Bastian Köcher <git@kchr.de>
Co-authored-by: Bastian Köcher <git@kchr.de>
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.
Thank you 👍
{ | ||
let header = pool.api().push_block(5, vec![from_dave, from_bob], true); | ||
// let header = pool.api().push_block(5, vec![from_dave, from_bob], true); | ||
let header = pool.api().push_block_with_parent(d1, vec![from_dave, from_bob], true); |
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.
DQ: Why do you changed this?
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.
I explained it in: https://github.com/paritytech/substrate/pull/12305/files#r982204082
Please cross-check if my reasoning is correct.
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.
Speculating - this maybe related to the isbestblock
bug in the testapi
implementation. (this)
Co-authored-by: Bastian Köcher <git@kchr.de>
Just pushed a commit to address some small nits and avoid another review loop. Thanks for the PR @michalkucharczyk 👍 |
bot merge |
Waiting for commit status. |
Thanks for the fix! And I have a question 🙋♂️ *Before* the fix, for More particularly, if I have a tx like this with // triggers [F(a), NBB(a)] sequence
extrinsic.signAndSend(sender, (result) => {
if (result.status.isInBlock) {
// this will not happen since enactment phase was not executed
} else if (result.status.isFinalized) {
console.log('will this happen???')
}
}); |
Before the fix only substrate/client/transaction-pool/tests/pool.rs Lines 1080 to 1093 in 2eb8ad2
|
* finalized block event triggers tx maintanance * tx-pool: enactment helper introduced * tx-pool: ChainApi: added tree_route method * enactment logic implemented + tests Signed-off-by: Michal Kucharczyk <1728078+michalkucharczyk@users.noreply.github.com> * Some additional tests * minor improvements * trigger CI job * fix compilation errors ChainApi::tree_route return type changed to Result<Option<..>>, as some implementations (tests) are not required to provide this tree route. * formatting * trait removed * implementation slightly simplified (thanks to @koute) * get rid of Arc<> in EnactmentState return value * minor improvement * Apply suggestions from code review Co-authored-by: André Silva <123550+andresilva@users.noreply.github.com> * Apply suggestions from code review * comment updated + formatting * Apply suggestions from code review Co-authored-by: André Silva <123550+andresilva@users.noreply.github.com> Co-authored-by: Davide Galassi <davxy@datawok.net> * formatting * finalization notification bug fix + new test case + log::warn message when finalized block is being retracted by new event * added error message on tree_route failure * Apply suggestions from code review Co-authored-by: Bastian Köcher <git@kchr.de> * use provided tree_route in Finalized event * Option removed from ChainApi::tree_route * doc added, test and logs improved * handle_enactment aligned with original implementation * use async-await * Apply suggestions from code review Co-authored-by: André Silva <123550+andresilva@users.noreply.github.com> * Apply suggestions from code review Co-authored-by: Bastian Köcher <git@kchr.de> * formatting + warn->debug * compilation error fix * enactment_state initializers added * enactment_state: Option removed * manual-seal: compilation & tests fix * manual-seal: tests fixed * tests cleanup * another compilation error fixed * TreeRoute::new added * get rid of pub hack * one more test added * formatting * TreeRoute::new doc added + formatting * Apply suggestions from code review Co-authored-by: Davide Galassi <davxy@datawok.net> * (bool,Option) simplified to Option * log message improved * yet another review suggestions applied * get rid of hash in handle_enactment * Apply suggestions from code review Co-authored-by: Bastian Köcher <git@kchr.de> * Update client/transaction-pool/src/lib.rs Co-authored-by: Bastian Köcher <git@kchr.de> * minor corrections * EnactmentState moved to new file * File header corrected * error formatting aligned with codebase * Apply suggestions from code review Co-authored-by: Bastian Köcher <git@kchr.de> * remove commented code * small nits Signed-off-by: Michal Kucharczyk <1728078+michalkucharczyk@users.noreply.github.com> Co-authored-by: André Silva <123550+andresilva@users.noreply.github.com> Co-authored-by: Davide Galassi <davxy@datawok.net> Co-authored-by: Bastian Köcher <git@kchr.de> Co-authored-by: André Silva <andrerfosilva@gmail.com>
tx-pool is driven by ChainEvents:
NewBestBlock
(NBB
) andFinalized
(F
) which can be delivered in arbitrary order.Existing implementation of tx-pool, handles correctly the typical sequence of events:
[NBB(a), F(a)]
.Maintenance of tx-pool is performed in two steps:
Existing implementation does not handle properly
[F(a), NBB(a)]
sequence of events (which was a case forinstant-seal
consensus): enactment phase was not executed whenF
was reported beforeNBB
event.For
F
events coming first both phases of maintenance should be executed. ForNBB
event coming afterF
the enactment phase should not be executed.This PR:
handle_enactment
) which is called for both NBB and F events.enactment_helper
which decides if enactment phase of maintenance should be executed for incoming event.Please note that this PR ignores
tree_route
provided within event, and usestree_route
function to compute retractred/enacted blocks.Consider the following chain:
The following list presents some scenarios and expected behavior:
NBB(C1)
,F(C1)
-> false (enactment phase was already performed inNBB(C1)
)F(C1)
,NBB(C1)
-> false (enactmant phase was already performed inF(C1)
)F(E1)
,F(B1)
-> false (enactmant phase was already performed inF(E1)
)F(C1)
,NBB(D2)
-> false (enactment phase was already performed inF(C1)
, we should not retract finalized block)F(C1)
,F(C2)
-> false (enactment phase was already performed inF(C1)
, we should not retract finalized block)F(C1)
,F(C2)
,NBB(C1)
-> false (enactmant phase was already performed inF(C1)
)NBB(C1)
,NBB(C2)
-> true (switching fork is OK)Closes #10279