-
Notifications
You must be signed in to change notification settings - Fork 3.7k
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
fix(baseapp)!: postHandler should run regardless of result #18627
Conversation
WalkthroughWalkthroughThe recent update involves a significant change in the behavior of the base application's state machine. The postHandlers, which are optional routines run after message processing, are now executed regardless of whether the message execution was successful or not. This change ensures that postHandlers are consistently run, and the event handling has been adjusted to maintain the correct order and prevent duplicates. Additionally, a new test has been added to verify this updated behavior. Changes
TipsChat with CodeRabbit Bot (
|
This comment has been minimized.
This comment has been minimized.
if err == nil { | ||
result, err = app.runMsgs(runMsgCtx, msgs, msgsV2, mode) | ||
} | ||
if err == nil { | ||
// Run optional postHandlers. | ||
// | ||
// Note: If the postHandler fails, we also revert the runMsgs state. | ||
if app.postHandler != nil { | ||
// The runMsgCtx context currently contains events emitted by the ante handler. | ||
// We clear this to correctly order events without duplicates. | ||
// Note that the state is still preserved. | ||
postCtx := runMsgCtx.WithEventManager(sdk.NewEventManager()) | ||
|
||
newCtx, err := app.postHandler(postCtx, tx, mode == execModeSimulate, err == nil) | ||
if err != nil { | ||
return gInfo, nil, anteEvents, err | ||
} | ||
|
||
result.Events = append(result.Events, newCtx.EventManager().ABCIEvents()...) | ||
// Run optional postHandlers (should run regardless of the execution result). | ||
// | ||
// Note: If the postHandler fails, we also revert the runMsgs state. | ||
if app.postHandler != nil { | ||
// The runMsgCtx context currently contains events emitted by the ante handler. | ||
// We clear this to correctly order events without duplicates. | ||
// Note that the state is still preserved. | ||
postCtx := runMsgCtx.WithEventManager(sdk.NewEventManager()) | ||
|
||
newCtx, err := app.postHandler(postCtx, tx, mode == execModeSimulate, err == nil) | ||
if err != nil { | ||
return gInfo, nil, anteEvents, err | ||
} | ||
|
||
result.Events = append(result.Events, newCtx.EventManager().ABCIEvents()...) | ||
} | ||
|
||
if err == nil { | ||
if mode == execModeFinalize { | ||
// When block gas exceeds, it'll panic and won't commit the cached store. | ||
consumeBlockGas() |
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.
Change potentially affects state.
Call sequence:
(*github.com/cosmos/cosmos-sdk/baseapp.BaseApp).runTx (baseapp/baseapp.go:811)
(*github.com/cosmos/cosmos-sdk/baseapp.BaseApp).deliverTx (baseapp/baseapp.go:741)
(*github.com/cosmos/cosmos-sdk/baseapp.BaseApp).internalFinalizeBlock (baseapp/baseapp.go:699)
(*github.com/cosmos/cosmos-sdk/baseapp.BaseApp).FinalizeBlock (baseapp/baseapp.go:856)
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.
It does affect state, good bot
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.
Review Status
Actionable comments generated: 1
Configuration used: CodeRabbit UI
Files selected for processing (2)
- baseapp/baseapp.go (1 hunks)
- baseapp/baseapp_test.go (1 hunks)
Additional comments: 1
baseapp/baseapp_test.go (1)
- 597-642: The test
TestBaseAppPostHandler
correctly implements the intended behavior of post handlers running irrespective of the transaction outcome, which aligns with the PR objective. It verifies the post-handler execution after both successful and failed message execution.
if err == nil { | ||
result, err = app.runMsgs(runMsgCtx, msgs, msgsV2, mode) | ||
} | ||
if err == nil { | ||
// Run optional postHandlers. | ||
// | ||
// Note: If the postHandler fails, we also revert the runMsgs state. | ||
if app.postHandler != nil { | ||
// The runMsgCtx context currently contains events emitted by the ante handler. | ||
// We clear this to correctly order events without duplicates. | ||
// Note that the state is still preserved. | ||
postCtx := runMsgCtx.WithEventManager(sdk.NewEventManager()) | ||
|
||
newCtx, err := app.postHandler(postCtx, tx, mode == execModeSimulate, err == nil) | ||
if err != nil { | ||
return gInfo, nil, anteEvents, err | ||
} | ||
|
||
result.Events = append(result.Events, newCtx.EventManager().ABCIEvents()...) | ||
// Run optional postHandlers (should run regardless of the execution result). | ||
// | ||
// Note: If the postHandler fails, we also revert the runMsgs state. | ||
if app.postHandler != nil { | ||
// The runMsgCtx context currently contains events emitted by the ante handler. | ||
// We clear this to correctly order events without duplicates. | ||
// Note that the state is still preserved. | ||
postCtx := runMsgCtx.WithEventManager(sdk.NewEventManager()) | ||
|
||
newCtx, err := app.postHandler(postCtx, tx, mode == execModeSimulate, err == nil) | ||
if err != nil { | ||
return gInfo, nil, anteEvents, err | ||
} | ||
|
||
result.Events = append(result.Events, newCtx.EventManager().ABCIEvents()...) | ||
} | ||
|
||
if err == nil { | ||
if mode == execModeFinalize { | ||
// When block gas exceeds, it'll panic and won't commit the cached store. | ||
consumeBlockGas() |
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.
The changes made in the hunk correctly implement the PR objective by ensuring that the postHandler
is executed regardless of the transaction result. The logic to clear the event manager before running the postHandler
to avoid duplicate events is also in place. This aligns with the intended behavior and the PR summary.
However, there is a potential issue with the ordering of events. The anteEvents
are appended after the postHandler
events, which could lead to incorrect event sequencing. The expected behavior would be to have anteEvents
first, followed by message processing events, and finally postHandler
events.
- result.Events = append(result.Events, newCtx.EventManager().ABCIEvents()...)
+ result.Events = append(newCtx.EventManager().ABCIEvents(), result.Events...)
Committable suggestion
❗ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation.
if err == nil { | |
result, err = app.runMsgs(runMsgCtx, msgs, msgsV2, mode) | |
} | |
if err == nil { | |
// Run optional postHandlers. | |
// | |
// Note: If the postHandler fails, we also revert the runMsgs state. | |
if app.postHandler != nil { | |
// The runMsgCtx context currently contains events emitted by the ante handler. | |
// We clear this to correctly order events without duplicates. | |
// Note that the state is still preserved. | |
postCtx := runMsgCtx.WithEventManager(sdk.NewEventManager()) | |
newCtx, err := app.postHandler(postCtx, tx, mode == execModeSimulate, err == nil) | |
if err != nil { | |
return gInfo, nil, anteEvents, err | |
} | |
result.Events = append(result.Events, newCtx.EventManager().ABCIEvents()...) | |
// Run optional postHandlers (should run regardless of the execution result). | |
// | |
// Note: If the postHandler fails, we also revert the runMsgs state. | |
if app.postHandler != nil { | |
// The runMsgCtx context currently contains events emitted by the ante handler. | |
// We clear this to correctly order events without duplicates. | |
// Note that the state is still preserved. | |
postCtx := runMsgCtx.WithEventManager(sdk.NewEventManager()) | |
newCtx, err := app.postHandler(postCtx, tx, mode == execModeSimulate, err == nil) | |
if err != nil { | |
return gInfo, nil, anteEvents, err | |
} | |
result.Events = append(result.Events, newCtx.EventManager().ABCIEvents()...) | |
} | |
if err == nil { | |
if mode == execModeFinalize { | |
// When block gas exceeds, it'll panic and won't commit the cached store. | |
consumeBlockGas() | |
if err == nil { | |
result, err = app.runMsgs(runMsgCtx, msgs, msgsV2, mode) | |
} | |
// Run optional postHandlers (should run regardless of the execution result). | |
// | |
// Note: If the postHandler fails, we also revert the runMsgs state. | |
if app.postHandler != nil { | |
// The runMsgCtx context currently contains events emitted by the ante handler. | |
// We clear this to correctly order events without duplicates. | |
// Note that the state is still preserved. | |
postCtx := runMsgCtx.WithEventManager(sdk.NewEventManager()) | |
newCtx, err := app.postHandler(postCtx, tx, mode == execModeSimulate, err == nil) | |
if err != nil { | |
return gInfo, nil, anteEvents, err | |
} | |
result.Events = append(newCtx.EventManager().ABCIEvents(), result.Events...) | |
} | |
if err == nil { | |
if mode == execModeFinalize { | |
// When block gas exceeds, it'll panic and won't commit the cached store. | |
consumeBlockGas() |
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.
@@ -184,6 +184,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ | |||
|
|||
### State Machine Breaking | |||
|
|||
* (baseapp) [#18627](https://github.com/cosmos/cosmos-sdk/pull/18627) Post handlers are run on non successful transaction executions too. |
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.
The changelog entry for PR 18627 correctly reflects the changes made to the state machine behavior. However, it may be beneficial to include that this is a consensus-breaking change, as indicated in the PR objective, to ensure users are fully aware of the implications.
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 second the bot's suggestion. Perhaps
Run post handlers if set, regardless of if a transaction was successful or not: consensus breaking change!
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.
@odeke-em Thank you for the feedback. The changelog entry can be updated to:
* (baseapp) [#18627](https://github.com/cosmos/cosmos-sdk/pull/18627) Run post handlers if set, regardless of if a transaction was successful or not: consensus breaking change!
This clearly communicates the consensus-breaking nature of the change.
We don't backport that, right? If we do, we really need to check sourcegraph to see for which chain it would be breaking. |
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.
lgtm!
i dont think we can backport this as it could cause consensus breaks. if we do 0.50 then we may need to retract other versions |
Given that no one has integrated with v0.50.x on prod yet, is it maybe too cautious? v0.50.2 will contain bug fixes that no one would want to skip on prod. |
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.
LGTM. I've seen this talked about before. I thought we addressed it, but seems not. Thanks @facundomedica 👍
// It should also run on failed message execution | ||
postHandlerRun = false | ||
tx = setFailOnHandler(t, suite.txConfig, tx, true) | ||
txBytes, err = suite.txConfig.TxEncoder()(tx) | ||
require.NoError(t, err) | ||
res, err = suite.baseApp.FinalizeBlock(&abci.RequestFinalizeBlock{Height: 1, Txs: [][]byte{txBytes}}) | ||
require.NoError(t, err) | ||
require.Empty(t, res.Events) | ||
require.False(t, res.TxResults[0].IsOK(), fmt.Sprintf("%v", res)) | ||
|
||
require.True(t, postHandlerRun) |
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.
// It should also run on failed message execution | |
postHandlerRun = false | |
tx = setFailOnHandler(t, suite.txConfig, tx, true) | |
txBytes, err = suite.txConfig.TxEncoder()(tx) | |
require.NoError(t, err) | |
res, err = suite.baseApp.FinalizeBlock(&abci.RequestFinalizeBlock{Height: 1, Txs: [][]byte{txBytes}}) | |
require.NoError(t, err) | |
require.Empty(t, res.Events) | |
require.False(t, res.TxResults[0].IsOK(), fmt.Sprintf("%v", res)) | |
require.True(t, postHandlerRun) | |
// It should also run on failed message execution | |
postHandlerRun = false | |
tx = setFailOnHandler(t, suite.txConfig, tx, true) | |
txBytes, err = suite.txConfig.TxEncoder()(tx) | |
require.NoError(t, err) | |
res, err = suite.baseApp.FinalizeBlock(&abci.RequestFinalizeBlock{Height: 1, Txs: [][]byte{txBytes}}) | |
require.NoError(t, err) | |
require.Empty(t, res.Events) | |
require.False(t, res.TxResults[0].IsOK(), fmt.Sprintf("%v", res)) | |
require.True(t, postHandlerRun) |
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 for this change @facundomedica, thank you for the test as well; just some suggestions but otherwise LGTM!
// Run optional postHandlers (should run regardless of the execution result). | ||
// | ||
// Note: If the postHandler fails, we also revert the runMsgs state. |
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 think using the comment, "Run optional postHandlers (should run regardless of the execution results)" could still be as ambiguous and not what would stand out to other maintainers reading through this code. How about?
// If the postHandler is set, it MUST be ran regardless of the execution result.
@@ -184,6 +184,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ | |||
|
|||
### State Machine Breaking | |||
|
|||
* (baseapp) [#18627](https://github.com/cosmos/cosmos-sdk/pull/18627) Post handlers are run on non successful transaction executions too. |
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 second the bot's suggestion. Perhaps
Run post handlers if set, regardless of if a transaction was successful or not: consensus breaking change!
Merging now to get this in v0.50.2 tomorrow. |
(cherry picked from commit b2084dc) # Conflicts: # CHANGELOG.md
* feat: secp256k1 public key constant time (cosmos#18026) Signed-off-by: bizk <santiago.yanzon1999@gmail.com> * chore: Fixed changelog duplicated items (cosmos#18628) * adr: Un-Ordered Transaction Inclusion (cosmos#18553) Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> Co-authored-by: Aleksandr Bezobchuk <alexanderbez@users.noreply.github.com> * docs: lint ADR-070 (cosmos#18634) * fix(baseapp)!: postHandler should run regardless of result (cosmos#18627) * docs: fix typos in adr-007-specialization-groups.md (cosmos#18635) * chore: alphabetize labels (cosmos#18640) * docs(x/circuit): add note on ante handler (cosmos#18637) Co-authored-by: Aleksandr Bezobchuk <alexanderbez@users.noreply.github.com> * fix: telemetry metric label variable (cosmos#18643) * chore: typos fix (cosmos#18642) * refactor(store/v2): updates from integration (cosmos#18633) * build(deps): Bump actions/setup-go from 4 to 5 (cosmos#18647) Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: github-actions <41898282+github-actions[bot]@users.noreply.github.com> * feat(store/v2): snapshot manager (cosmos#18458) * chore(client/v2): fix typos in the README.md (cosmos#18657) * fix(baseapp): protocompat.go gogoproto.Merge does not work with custom types (cosmos#18654) Co-authored-by: unknown unknown <unknown@unknown> * chore: fix several minor typos (cosmos#18660) * chore(tools/confix/cmd): fix typo in view.go (cosmos#18659) * refactor(x/staking): check duplicate addresses in StakeAuthorization's params (cosmos#18655) * feat(accounts): use gogoproto API instead of protov2. (cosmos#18653) Co-authored-by: unknown unknown <unknown@unknown> Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * fix(store/commitment/iavl): honor tree.Remove error firstly (cosmos#18651) * build(deps): Bump actions/stale from 8 to 9 (cosmos#18656) Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * chore(docs): fix typos & wording in docs (cosmos#18667) * chore: fix several typos. (cosmos#18666) * feat(telemetry): enable `statsd` and `dogstatsd` telemetry sinks (cosmos#18646) Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> Co-authored-by: Aleksandr Bezobchuk <alexanderbez@users.noreply.github.com> Co-authored-by: marbar3778 <marbar3778@yahoo.com> Co-authored-by: Marko <marko@baricevic.me> * feat(store/v2): add SetInitialVersion in SC (cosmos#18665) * feat(client/keys): support display discreetly for `keys add` (cosmos#18663) Co-authored-by: Julien Robert <julien@rbrt.fr> * ci: add misspell action (cosmos#18671) * chore: typos fix by misspell-fixer (cosmos#18683) Co-authored-by: github-merge-queue <github-merge-queue@users.noreply.github.com> Co-authored-by: Julien Robert <julien@rbrt.fr> * chore: add v0.50.2 changelog to main (cosmos#18682) * build(deps): Bump github.com/jhump/protoreflect from 1.15.3 to 1.15.4 in /tests (cosmos#18678) Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * refactor(bank): remove .String() calls (cosmos#18175) Co-authored-by: Facundo <facundomedica@gmail.com> * ci: use codespell instead of misspell-fixer (cosmos#18686) Co-authored-by: Marko <marbar3778@yahoo.com> * feat(gov): add proposal types and spam votes (cosmos#18532) * feat(accounts): use account number as state prefix for account state (cosmos#18664) Co-authored-by: unknown unknown <unknown@unknown> * chore: typos fixes by cosmos-sdk bot (cosmos#18689) Co-authored-by: github-merge-queue <github-merge-queue@users.noreply.github.com> Co-authored-by: Julien Robert <julien@rbrt.fr> Co-authored-by: marbar3778 <marbar3778@yahoo.com> * feat(client/keys): support display discreetly for keys mnemonic (cosmos#18688) * refactor: remove panic usage in keeper methods (cosmos#18636) * ci: rename pr name in misspell job (cosmos#18693) Co-authored-by: Marko <marko@baricevic.me> * build(deps): Bump github.com/pelletier/go-toml/v2 from 2.1.0 to 2.1.1 in /tools/confix (cosmos#18702) Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: github-actions <41898282+github-actions[bot]@users.noreply.github.com> * feat(client/keys): support display discreetly for keys export (cosmos#18684) * feat(x/gov): better gov genesis validation (cosmos#18707) --------- Signed-off-by: bizk <santiago.yanzon1999@gmail.com> Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: Carlos Santiago Yanzon <27785807+bizk@users.noreply.github.com> Co-authored-by: yihuang <huang@crypto.com> Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> Co-authored-by: Aleksandr Bezobchuk <alexanderbez@users.noreply.github.com> Co-authored-by: Facundo Medica <14063057+facundomedica@users.noreply.github.com> Co-authored-by: Akaonetwo <107335783+Akare123@users.noreply.github.com> Co-authored-by: Marko <marbar3778@yahoo.com> Co-authored-by: Julien Robert <julien@rbrt.fr> Co-authored-by: dreamweaverxyz <153101746+dreamweaverxyz@users.noreply.github.com> Co-authored-by: Pioua <136521243+dzizazda@users.noreply.github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: github-actions <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: cool-developer <51834436+cool-develope@users.noreply.github.com> Co-authored-by: leonarddt05 <139609434+leonarddt05@users.noreply.github.com> Co-authored-by: testinginprod <98415576+testinginprod@users.noreply.github.com> Co-authored-by: unknown unknown <unknown@unknown> Co-authored-by: Sukey <35202440+sukey2008@users.noreply.github.com> Co-authored-by: axie <152680487+azukiboy@users.noreply.github.com> Co-authored-by: Luke Ma <867273263@qq.com> Co-authored-by: Emmanuel T Odeke <emmanuel@orijtech.com> Co-authored-by: 0xn4de <109149873+0xn4de@users.noreply.github.com> Co-authored-by: hattizai <150505746+hattizai@users.noreply.github.com> Co-authored-by: Devon Bear <itsdevbear@berachain.com> Co-authored-by: Marko <marko@baricevic.me> Co-authored-by: Halimao <1065621723@qq.com> Co-authored-by: Cosmos SDK <113218068+github-prbot@users.noreply.github.com> Co-authored-by: github-merge-queue <github-merge-queue@users.noreply.github.com> Co-authored-by: Facundo <facundomedica@gmail.com> Co-authored-by: Likhita Polavarapu <78951027+likhita-809@users.noreply.github.com>
Description
This PR fixes a bug discovered by @testinginprod in which post handlers were only run if the transaction execution succeeded, but they were designed to run regardless of the execution's result.
This fix is consensus breaking (especially for chains that have implemented a post handler, for the rest this shouldn't be an issue).
The original PR adding this feature: #13940
Author Checklist
All items are required. Please add a note to the item if the item is not applicable and
please add links to any relevant follow up issues.
I have...
!
in the type prefix if API or client breaking changeCHANGELOG.md
Reviewers Checklist
All items are required. Please add a note if the item is not applicable and please add
your handle next to the items reviewed if you only reviewed selected items.
I have...
Summary by CodeRabbit
New Features
Bug Fixes
Tests