diff --git a/app/app.go b/app/app.go index c3db6222..45391fe6 100644 --- a/app/app.go +++ b/app/app.go @@ -378,16 +378,38 @@ func (app *KiichainApp) EndBlocker(ctx sdk.Context) (sdk.EndBlock, error) { func (app *KiichainApp) InitChainer(ctx sdk.Context, req *abci.RequestInitChain) (*abci.ResponseInitChain, error) { var genesisState GenesisState if err := tmjson.Unmarshal(req.AppStateBytes, &genesisState); err != nil { - panic(err) + return nil, fmt.Errorf("failed to unmarshal genesis state: %w", err) } if err := app.UpgradeKeeper.SetModuleVersionMap(ctx, app.mm.GetVersionMap()); err != nil { - panic(err) + return nil, fmt.Errorf("failed to set module version map: %w", err) } - response, err := app.mm.InitGenesis(ctx, app.appCodec, genesisState) - if err != nil { - panic(err) + var ( + response *abci.ResponseInitChain + initErr error + ) + + // Use recover() as a safety net for module InitGenesis panics. + // Cosmos SDK v0.53.6's Manager.InitGenesis does NOT recover panics, so a + // panic in any module's InitGenesis would crash the node. This guard + // converts module panics to returned errors, allowing the app to shut + // down cleanly instead of crashing mid-genesis. + // + // Long-term fix: refactor the four custom modules (x/tokenfactory, + // x/rewards, x/feeabstraction, x/oracle) to return errors instead of + // panicking in their InitGenesis implementations. + func() { + defer func() { + if r := recover(); r != nil { + initErr = fmt.Errorf("panic recovered during InitGenesis: %v", r) + } + }() + response, initErr = app.mm.InitGenesis(ctx, app.appCodec, genesisState) + }() + + if initErr != nil { + return nil, fmt.Errorf("failed to run InitGenesis: %w", initErr) } return response, nil diff --git a/x/feeabstraction/module.go b/x/feeabstraction/module.go index 3e91963c..b2a0f862 100644 --- a/x/feeabstraction/module.go +++ b/x/feeabstraction/module.go @@ -147,7 +147,9 @@ func (am AppModule) RegisterServices(c module.Configurator) { func (am AppModule) InitGenesis(ctx sdk.Context, cdc codec.JSONCodec, gs json.RawMessage) []abci.ValidatorUpdate { // Unmarshal the genesis state var genState types.GenesisState - cdc.MustUnmarshalJSON(gs, &genState) + if err := cdc.UnmarshalJSON(gs, &genState); err != nil { + panic(fmt.Errorf("failed to unmarshal %s genesis state: %w", types.ModuleName, err)) + } // Initialize the genesis err := am.keeper.InitGenesis(ctx, genState) diff --git a/x/oracle/module.go b/x/oracle/module.go index 231e3373..7919dfdd 100644 --- a/x/oracle/module.go +++ b/x/oracle/module.go @@ -145,7 +145,9 @@ func (am AppModule) RegisterServices(cfg module.Configurator) { // InitGenesis trigger the genesis initialization func (am AppModule) InitGenesis(ctx sdk.Context, cdc codec.JSONCodec, data json.RawMessage) []abci.ValidatorUpdate { genesis := &types.GenesisState{} - cdc.MustUnmarshalJSON(data, genesis) + if err := cdc.UnmarshalJSON(data, genesis); err != nil { + panic(fmt.Errorf("failed to unmarshal %s genesis state: %w", types.ModuleName, err)) + } // Initialize the genesis state err := InitGenesis(ctx, am.Kepper, genesis) if err != nil { diff --git a/x/oracle/types/genesis.go b/x/oracle/types/genesis.go index 7c6b3739..aa1f9ab3 100644 --- a/x/oracle/types/genesis.go +++ b/x/oracle/types/genesis.go @@ -2,6 +2,7 @@ package types import ( "encoding/json" + "fmt" "github.com/cosmos/cosmos-sdk/codec" ) @@ -45,7 +46,9 @@ func GetGenesisStateFromAppState(cdc codec.JSONCodec, appState map[string]json.R // Unmarshal current genesis state if appState[ModuleName] != nil { - cdc.MustUnmarshalJSON(appState[ModuleName], &genesisState) + if err := cdc.UnmarshalJSON(appState[ModuleName], &genesisState); err != nil { + panic(fmt.Errorf("failed to unmarshal %s genesis state: %w", ModuleName, err)) + } } return &genesisState diff --git a/x/rewards/module.go b/x/rewards/module.go index 3d8a934e..228365f3 100644 --- a/x/rewards/module.go +++ b/x/rewards/module.go @@ -149,7 +149,9 @@ func (am AppModule) RegisterServices(cfg module.Configurator) { // returns no validator updates. func (am AppModule) InitGenesis(ctx sdk.Context, cdc codec.JSONCodec, gs json.RawMessage) []abci.ValidatorUpdate { var genState types.GenesisState - cdc.MustUnmarshalJSON(gs, &genState) + if err := cdc.UnmarshalJSON(gs, &genState); err != nil { + panic(fmt.Errorf("failed to unmarshal %s genesis state: %w", types.ModuleName, err)) + } am.keeper.InitGenesis(ctx, genState) diff --git a/x/tokenfactory/module.go b/x/tokenfactory/module.go index d4d20030..faaa79c5 100644 --- a/x/tokenfactory/module.go +++ b/x/tokenfactory/module.go @@ -166,7 +166,9 @@ func (am AppModule) RegisterServices(cfg module.Configurator) { // returns no validator updates. func (am AppModule) InitGenesis(ctx sdk.Context, cdc codec.JSONCodec, gs json.RawMessage) []abci.ValidatorUpdate { var genState types.GenesisState - cdc.MustUnmarshalJSON(gs, &genState) + if err := cdc.UnmarshalJSON(gs, &genState); err != nil { + panic(fmt.Errorf("failed to unmarshal %s genesis state: %w", types.ModuleName, err)) + } am.keeper.InitGenesis(ctx, genState)