From 73c074117f2d70e04ab54e6c002332535bef545b Mon Sep 17 00:00:00 2001 From: Julien Robert Date: Mon, 15 Jan 2024 18:08:31 +0100 Subject: [PATCH] fix(baseapp): nil check in posthandler events (#19058) --- CHANGELOG.md | 1 + baseapp/baseapp.go | 10 +++++++--- baseapp/baseapp_test.go | 28 ++++++++++++++++++++-------- baseapp/utils_test.go | 14 ++++++++++++++ 4 files changed, 42 insertions(+), 11 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 077cfdd34d..661d890e20 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -80,6 +80,7 @@ Every Module contains its own CHANGELOG.md. Please refer to the module you are i ### Bug Fixes +* (baseapp) [#19058](https://github.com/cosmos/cosmos-sdk/pull/19058) Fix baseapp posthandler branch would fail if the `runMsgs` had returned an error. * (baseapp) [#18609](https://github.com/cosmos/cosmos-sdk/issues/18609) Fixed accounting in the block gas meter after BeginBlock and before DeliverTx, ensuring transaction processing always starts with the expected zeroed out block gas meter. * (baseapp) [#18727](https://github.com/cosmos/cosmos-sdk/pull/18727) Ensure that `BaseApp.Init` firstly returns any errors from a nil commit multistore instead of panicking on nil dereferencing and before sealing the app. * (client) [#18622](https://github.com/cosmos/cosmos-sdk/pull/18622) Fixed a potential under/overflow from `uint64->int64` when computing gas fees as a LegacyDec. diff --git a/baseapp/baseapp.go b/baseapp/baseapp.go index 391f6bc0d1..2309ed135c 100644 --- a/baseapp/baseapp.go +++ b/baseapp/baseapp.go @@ -944,11 +944,15 @@ func (app *BaseApp) runTx(mode execMode, txBytes []byte) (gInfo sdk.GasInfo, res // 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 + newCtx, errPostHandler := app.postHandler(postCtx, tx, mode == execModeSimulate, err == nil) + if errPostHandler != nil { + return gInfo, nil, anteEvents, errors.Join(err, errPostHandler) } + // we don't want runTx to panic if runMsgs has failed earlier + if result == nil { + result = &sdk.Result{} + } result.Events = append(result.Events, newCtx.EventManager().ABCIEvents()...) } diff --git a/baseapp/baseapp_test.go b/baseapp/baseapp_test.go index bb844f570d..68bea97950 100644 --- a/baseapp/baseapp_test.go +++ b/baseapp/baseapp_test.go @@ -1,6 +1,7 @@ package baseapp_test import ( + "bytes" "context" "crypto/sha256" "fmt" @@ -45,9 +46,10 @@ var ( type ( BaseAppSuite struct { - baseApp *baseapp.BaseApp - cdc *codec.ProtoCodec - txConfig client.TxConfig + baseApp *baseapp.BaseApp + cdc *codec.ProtoCodec + txConfig client.TxConfig + logBuffer *bytes.Buffer } SnapshotsConfig struct { @@ -66,8 +68,10 @@ func NewBaseAppSuite(t *testing.T, opts ...func(*baseapp.BaseApp)) *BaseAppSuite txConfig := authtx.NewTxConfig(cdc, authtx.DefaultSignModes) db := dbm.NewMemDB() + logBuffer := new(bytes.Buffer) + logger := log.NewLogger(logBuffer, log.ColorOption(false)) - app := baseapp.NewBaseApp(t.Name(), log.NewTestLogger(t), db, txConfig.TxDecoder(), opts...) + app := baseapp.NewBaseApp(t.Name(), logger, db, txConfig.TxDecoder(), opts...) require.Equal(t, t.Name(), app.Name()) app.SetInterfaceRegistry(cdc.InterfaceRegistry()) @@ -81,9 +85,10 @@ func NewBaseAppSuite(t *testing.T, opts ...func(*baseapp.BaseApp)) *BaseAppSuite require.Nil(t, app.LoadLatestVersion()) return &BaseAppSuite{ - baseApp: app, - cdc: cdc, - txConfig: txConfig, + baseApp: app, + cdc: cdc, + txConfig: txConfig, + logBuffer: logBuffer, } } @@ -638,7 +643,6 @@ func TestBaseAppPostHandler(t *testing.T) { } suite := NewBaseAppSuite(t, anteOpt) - baseapptestutil.RegisterCounterServer(suite.baseApp.MsgServiceRouter(), CounterServerImpl{t, capKey1, []byte("foo")}) _, err := suite.baseApp.InitChain(&abci.RequestInitChain{ @@ -673,6 +677,14 @@ func TestBaseAppPostHandler(t *testing.T) { require.False(t, res.TxResults[0].IsOK(), fmt.Sprintf("%v", res)) require.True(t, postHandlerRun) + + // regression test, should not panic when runMsgs fails + tx = wonkyMsg(t, suite.txConfig, tx) + txBytes, err = suite.txConfig.TxEncoder()(tx) + require.NoError(t, err) + _, err = suite.baseApp.FinalizeBlock(&abci.RequestFinalizeBlock{Height: 1, Txs: [][]byte{txBytes}}) + require.NoError(t, err) + require.NotContains(t, suite.logBuffer.String(), "panic recovered in runTx") } // Test and ensure that invalid block heights always cause errors. diff --git a/baseapp/utils_test.go b/baseapp/utils_test.go index 160ecac8a9..01cea32a41 100644 --- a/baseapp/utils_test.go +++ b/baseapp/utils_test.go @@ -400,3 +400,17 @@ func setFailOnHandler(t *testing.T, cfg client.TxConfig, tx signing.Tx, fail boo require.NoError(t, err) return builder.GetTx() } + +// wonkyMsg is to be used to run a MsgCounter2 message when the MsgCounter2 handler is not registered. +func wonkyMsg(t *testing.T, cfg client.TxConfig, tx signing.Tx) signing.Tx { + t.Helper() + builder := cfg.NewTxBuilder() + builder.SetMemo(tx.GetMemo()) + + msgs := tx.GetMsgs() + msgs = append(msgs, &baseapptestutil.MsgCounter2{}) + + err := builder.SetMsgs(msgs...) + require.NoError(t, err) + return builder.GetTx() +}