diff --git a/CHANGELOG.md b/CHANGELOG.md index 1fa119bc69d3..627d67c80f06 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -84,6 +84,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ ### Improvements +* (x/gov) [#17780](https://github.com/cosmos/cosmos-sdk/pull/17780) Recover panics and turn them into errors when executing x/gov proposals. * (baseapp) [#17667](https://github.com/cosmos/cosmos-sdk/pull/17667) Close databases opened by SDK in `baseApp.Close()`. * (types/module) [#17554](https://github.com/cosmos/cosmos-sdk/pull/17554) Introduce `HasABCIGenesis` which is implemented by a module only when a validatorset update needs to be returned. * (cli) [#17389](https://github.com/cosmos/cosmos-sdk/pull/17389) gRPC CometBFT commands have been added under ` q consensus comet`. CometBFT commands placement in the SDK has been simplified. See the exhaustive list below. diff --git a/x/gov/abci.go b/x/gov/abci.go index 0be4c0f5d384..e6ff70c00cc5 100644 --- a/x/gov/abci.go +++ b/x/gov/abci.go @@ -6,6 +6,7 @@ import ( "cosmossdk.io/collections" + "github.com/cosmos/cosmos-sdk/baseapp" "github.com/cosmos/cosmos-sdk/telemetry" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/gov/keeper" @@ -133,9 +134,8 @@ func EndBlocker(ctx sdk.Context, keeper *keeper.Keeper) error { // execute all messages for idx, msg = range messages { handler := keeper.Router().Handler(msg) - var res *sdk.Result - res, err = handler(cacheCtx, msg) + res, err = safeExecuteHandler(cacheCtx, msg, handler) if err != nil { break } @@ -223,3 +223,15 @@ func EndBlocker(ctx sdk.Context, keeper *keeper.Keeper) error { } return nil } + +// executes handle(msg) and recovers from panic. +func safeExecuteHandler(ctx sdk.Context, msg sdk.Msg, handler baseapp.MsgServiceHandler, +) (res *sdk.Result, err error) { + defer func() { + if r := recover(); r != nil { + err = fmt.Errorf("handling x/gov proposal msg [%s] PANICKED: %v", msg, r) + } + }() + res, err = handler(ctx, msg) + return +} diff --git a/x/gov/abci_internal_test.go b/x/gov/abci_internal_test.go new file mode 100644 index 000000000000..1421a81b5cb6 --- /dev/null +++ b/x/gov/abci_internal_test.go @@ -0,0 +1,32 @@ +package gov + +import ( + "testing" + + "github.com/stretchr/testify/require" + + sdk "github.com/cosmos/cosmos-sdk/types" +) + +func failingHandler(_ sdk.Context, _ sdk.Msg) (*sdk.Result, error) { + panic("test-fail") +} + +func okHandler(_ sdk.Context, _ sdk.Msg) (*sdk.Result, error) { + return new(sdk.Result), nil +} + +func TestSafeExecuteHandler(t *testing.T) { + t.Parallel() + + require := require.New(t) + var ctx sdk.Context + + r, err := safeExecuteHandler(ctx, nil, failingHandler) + require.ErrorContains(err, "test-fail") + require.Nil(r) + + r, err = safeExecuteHandler(ctx, nil, okHandler) + require.Nil(err) + require.NotNil(r) +}