fix(baseapp)!: postHandler should run regardless of result (backport #18627) (#18638)

Co-authored-by: Facundo Medica <14063057+facundomedica@users.noreply.github.com>
Co-authored-by: Julien Robert <julien@rbrt.fr>
This commit is contained in:
mergify[bot]
2023-12-06 20:25:34 +01:00
committed by GitHub
co-authored by Facundo Medica Julien Robert
parent fe7a3ec790
commit c95ebb69c9
3 changed files with 63 additions and 14 deletions
+1
View File
@@ -58,6 +58,7 @@ Ref: https://keepachangelog.com/en/1.0.0/
* [#18531](https://github.com/cosmos/cosmos-sdk/pull/18531) Baseapp's `GetConsensusParams` returns an empty struct instead of panicking if no params are found.
* (client/tx) [#18472](https://github.com/cosmos/cosmos-sdk/pull/18472) Utilizes the correct Pubkey when simulating a transaction.
* (baseapp) [#18486](https://github.com/cosmos/cosmos-sdk/pull/18486) Fixed FinalizeBlock calls not being passed to ABCIListeners.
* (baseapp) [#18627](https://github.com/cosmos/cosmos-sdk/pull/18627) Post handlers are run on non successful transaction executions too.
## [v0.50.1](https://github.com/cosmos/cosmos-sdk/releases/tag/v0.50.1) - 2023-11-07
+15 -14
View File
@@ -925,24 +925,25 @@ func (app *BaseApp) runTx(mode execMode, txBytes []byte) (gInfo sdk.GasInfo, res
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
}
// 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())
result.Events = append(result.Events, newCtx.EventManager().ABCIEvents()...)
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()
+47
View File
@@ -587,6 +587,53 @@ func TestBaseAppAnteHandler(t *testing.T) {
suite.baseApp.Commit()
}
func TestBaseAppPostHandler(t *testing.T) {
postHandlerRun := false
anteOpt := func(bapp *baseapp.BaseApp) {
bapp.SetPostHandler(func(ctx sdk.Context, tx sdk.Tx, simulate, success bool) (newCtx sdk.Context, err error) {
postHandlerRun = true
return ctx, nil
})
}
suite := NewBaseAppSuite(t, anteOpt)
baseapptestutil.RegisterCounterServer(suite.baseApp.MsgServiceRouter(), CounterServerImpl{t, capKey1, []byte("foo")})
_, err := suite.baseApp.InitChain(&abci.RequestInitChain{
ConsensusParams: &cmtproto.ConsensusParams{},
})
require.NoError(t, err)
// execute a tx that will fail ante handler execution
//
// NOTE: State should not be mutated here. This will be implicitly checked by
// the next txs ante handler execution (anteHandlerTxTest).
tx := newTxCounter(t, suite.txConfig, 0, 0)
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.True(t, res.TxResults[0].IsOK(), fmt.Sprintf("%v", res))
// PostHandler runs on successful message execution
require.True(t, postHandlerRun)
// It should also run on failed message execution
postHandlerRun = false
tx = setFailOnHandler(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)
}
// Test and ensure that invalid block heights always cause errors.
// See issues:
// - https://github.com/cosmos/cosmos-sdk/issues/11220