diff --git a/docs/migrations/v2-to-v3.md b/docs/migrations/v2-to-v3.md index 6b1c61735fc..a37f74cf420 100644 --- a/docs/migrations/v2-to-v3.md +++ b/docs/migrations/v2-to-v3.md @@ -58,8 +58,8 @@ app.UpgradeKeeper.SetUpgradeHandler("v3", ``` -The host and controller submodule params only need to be set if you integrate those submodules. -For example, if a chain chooses not to integrate a controller submodule, it does not need to set the controller params. +The host and controller submodule params only need to be set if the chain integrates those submodules. +For example, if a chain chooses not to integrate a controller submodule, it may pass empty params into `InitModule`. #### Add `StoreUpgrades` for ICS27 module @@ -76,6 +76,9 @@ if upgradeInfo.Name == "v3" && !app.UpgradeKeeper.IsSkipHeight(upgradeInfo.Heigh ``` This ensures that the new module's stores are added to the multistore before the migrations begin. +The host and controller submodule keys only need to be added if the chain integrates those submodules. +For example, if a chain chooses not to integrate a controller submodule, it does not need to add the controller key to the `Added` field. + ### Genesis migrations diff --git a/modules/apps/27-interchain-accounts/module.go b/modules/apps/27-interchain-accounts/module.go index 969c07caf9d..1bb870fca5d 100644 --- a/modules/apps/27-interchain-accounts/module.go +++ b/modules/apps/27-interchain-accounts/module.go @@ -105,12 +105,17 @@ func NewAppModule(controllerKeeper *controllerkeeper.Keeper, hostKeeper *hostkee // InitModule will initialize the interchain accounts moudule. It should only be // called once and as an alternative to InitGenesis. func (am AppModule) InitModule(ctx sdk.Context, controllerParams controllertypes.Params, hostParams hosttypes.Params) { - am.controllerKeeper.SetParams(ctx, controllerParams) - am.hostKeeper.SetParams(ctx, hostParams) + if am.controllerKeeper != nil { + am.controllerKeeper.SetParams(ctx, controllerParams) + } + + if am.hostKeeper != nil { + am.hostKeeper.SetParams(ctx, hostParams) - cap := am.hostKeeper.BindPort(ctx, types.PortID) - if err := am.hostKeeper.ClaimCapability(ctx, cap, ibchost.PortPath(types.PortID)); err != nil { - panic(fmt.Sprintf("could not claim port capability: %v", err)) + cap := am.hostKeeper.BindPort(ctx, types.PortID) + if err := am.hostKeeper.ClaimCapability(ctx, cap, ibchost.PortPath(types.PortID)); err != nil { + panic(fmt.Sprintf("could not claim port capability: %v", err)) + } } } diff --git a/modules/apps/27-interchain-accounts/module_test.go b/modules/apps/27-interchain-accounts/module_test.go index de5f51ae921..59517ab40e4 100644 --- a/modules/apps/27-interchain-accounts/module_test.go +++ b/modules/apps/27-interchain-accounts/module_test.go @@ -31,8 +31,9 @@ func (suite *InterchainAccountsTestSuite) SetupTest() { } func (suite *InterchainAccountsTestSuite) TestInitModule() { + // setup and basic testing app := simapp.NewSimApp(log.NewNopLogger(), dbm.NewMemDB(), nil, true, map[int64]bool{}, simapp.DefaultNodeHome, 5, simapp.MakeTestEncodingConfig(), simapp.EmptyAppOptions{}) - icamodule, ok := app.GetModuleManager().Modules[types.ModuleName].(ica.AppModule) + appModule, ok := app.GetModuleManager().Modules[types.ModuleName].(ica.AppModule) suite.Require().True(ok) header := tmproto.Header{ @@ -58,17 +59,74 @@ func (suite *InterchainAccountsTestSuite) TestInitModule() { expAllowMessages := []string{"sdk.Msg"} hostParams.HostEnabled = true hostParams.AllowMessages = expAllowMessages - suite.Require().False(app.IBCKeeper.PortKeeper.IsBound(ctx, types.PortID)) - icamodule.InitModule(ctx, controllerParams, hostParams) + testCases := []struct { + name string + malleate func() + expControllerPass bool + expHostPass bool + }{ + { + "both controller and host set", func() { + var ok bool + appModule, ok = app.GetModuleManager().Modules[types.ModuleName].(ica.AppModule) + suite.Require().True(ok) + }, true, true, + }, + { + "neither controller or host is set", func() { + appModule = ica.NewAppModule(nil, nil) + }, false, false, + }, + { + "only controller is set", func() { + appModule = ica.NewAppModule(&app.ICAControllerKeeper, nil) + }, true, false, + }, + { + "only host is set", func() { + appModule = ica.NewAppModule(nil, &app.ICAHostKeeper) + }, false, true, + }, + } + + for _, tc := range testCases { + tc := tc + + suite.Run(tc.name, func() { + suite.SetupTest() // reset + + // reset app state + app = simapp.NewSimApp(log.NewNopLogger(), dbm.NewMemDB(), nil, true, map[int64]bool{}, simapp.DefaultNodeHome, 5, simapp.MakeTestEncodingConfig(), simapp.EmptyAppOptions{}) + header := tmproto.Header{ + ChainID: "testchain", + Height: 1, + Time: suite.coordinator.CurrentTime.UTC(), + } + + ctx := app.GetBaseApp().NewContext(true, header) - controllerParams = app.ICAControllerKeeper.GetParams(ctx) - suite.Require().True(controllerParams.ControllerEnabled) + tc.malleate() - hostParams = app.ICAHostKeeper.GetParams(ctx) - suite.Require().True(hostParams.HostEnabled) - suite.Require().Equal(expAllowMessages, hostParams.AllowMessages) + suite.Require().NotPanics(func() { + appModule.InitModule(ctx, controllerParams, hostParams) + }) + + if tc.expControllerPass { + controllerParams = app.ICAControllerKeeper.GetParams(ctx) + suite.Require().True(controllerParams.ControllerEnabled) + } + + if tc.expHostPass { + hostParams = app.ICAHostKeeper.GetParams(ctx) + suite.Require().True(hostParams.HostEnabled) + suite.Require().Equal(expAllowMessages, hostParams.AllowMessages) + + suite.Require().True(app.IBCKeeper.PortKeeper.IsBound(ctx, types.PortID)) + } + + }) + } - suite.Require().True(app.IBCKeeper.PortKeeper.IsBound(ctx, types.PortID)) }