diff --git a/modules/apps/27-interchain-accounts/controller/ibc_middleware.go b/modules/apps/27-interchain-accounts/controller/ibc_middleware.go index 6e7b9b071f4..199c4f2d9da 100644 --- a/modules/apps/27-interchain-accounts/controller/ibc_middleware.go +++ b/modules/apps/27-interchain-accounts/controller/ibc_middleware.go @@ -293,11 +293,38 @@ func (im IBCMiddleware) OnChanUpgradeAck(ctx sdk.Context, portID, channelID, cou } // OnChanUpgradeOpen implements the IBCModule interface -func (IBCMiddleware) OnChanUpgradeOpen(ctx sdk.Context, portID, channelID string, order channeltypes.Order, connectionHops []string, version string) { +func (im IBCMiddleware) OnChanUpgradeOpen(ctx sdk.Context, portID, channelID string, order channeltypes.Order, connectionHops []string, version string) { + connectionID, err := im.keeper.GetConnectionID(ctx, portID, channelID) + if err != nil { + panic(err) + } + + if im.app != nil && im.keeper.IsMiddlewareEnabled(ctx, portID, connectionID) { + // Only cast to UpgradableModule if the application is set. + cbs, ok := im.app.(porttypes.UpgradableModule) + if !ok { + panic(errorsmod.Wrap(porttypes.ErrInvalidRoute, "upgrade route not found to module in application callstack")) + } + cbs.OnChanUpgradeOpen(ctx, portID, channelID, order, connectionHops, version) + } } // OnChanUpgradeRestore implements the IBCModule interface -func (IBCMiddleware) OnChanUpgradeRestore(ctx sdk.Context, portID, channelID string) {} +func (im IBCMiddleware) OnChanUpgradeRestore(ctx sdk.Context, portID, channelID string) { + connectionID, err := im.keeper.GetConnectionID(ctx, portID, channelID) + if err != nil { + panic(err) + } + + if im.app != nil && im.keeper.IsMiddlewareEnabled(ctx, portID, connectionID) { + // Only cast to UpgradableModule if the application is set. + cbs, ok := im.app.(porttypes.UpgradableModule) + if !ok { + panic(errorsmod.Wrap(porttypes.ErrInvalidRoute, "upgrade route not found to module in application callstack")) + } + cbs.OnChanUpgradeRestore(ctx, portID, channelID) + } +} // SendPacket implements the ICS4 Wrapper interface func (IBCMiddleware) SendPacket( diff --git a/modules/apps/27-interchain-accounts/controller/ibc_middleware_test.go b/modules/apps/27-interchain-accounts/controller/ibc_middleware_test.go index 24212a88f23..568edb2b031 100644 --- a/modules/apps/27-interchain-accounts/controller/ibc_middleware_test.go +++ b/modules/apps/27-interchain-accounts/controller/ibc_middleware_test.go @@ -957,6 +957,139 @@ func (suite *InterchainAccountsTestSuite) TestOnChanUpgradeAck() { } } +func (suite *InterchainAccountsTestSuite) TestOnChanUpgradeOpen() { + var ( + path *ibctesting.Path + isNilApp bool + counterpartyVersion string + ) + + testCases := []struct { + name string + malleate func() + }{ + { + "success", + func() {}, + }, + { + "success: nil app", + func() { + isNilApp = true + }, + }, + { + "middleware disabled", func() { + suite.chainA.GetSimApp().ICAControllerKeeper.DeleteMiddlewareEnabled(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ConnectionID) + suite.chainA.GetSimApp().ICAAuthModule.IBCApp.OnChanUpgradeAck = func(ctx sdk.Context, portID, channelID string, counterpartyVersion string) error { + return ibcmock.MockApplicationCallbackError + } + }, + }, + } + + for _, tc := range testCases { + tc := tc + + suite.Run(tc.name, func() { + suite.SetupTest() // reset + isNilApp = false + + path = NewICAPath(suite.chainA, suite.chainB) + suite.coordinator.SetupConnections(path) + + err := SetupICAPath(path, TestOwnerAddress) + suite.Require().NoError(err) + + counterpartyVersion = path.EndpointB.GetChannel().Version + + tc.malleate() // malleate mutates test data + + module, _, err := suite.chainA.App.GetIBCKeeper().PortKeeper.LookupModuleByPort(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID) + suite.Require().NoError(err) + + app, ok := suite.chainA.App.GetIBCKeeper().Router.GetRoute(module) + suite.Require().True(ok) + cbs, ok := app.(porttypes.UpgradableModule) + suite.Require().True(ok) + + if isNilApp { + cbs = controller.NewIBCMiddleware(nil, suite.chainA.GetSimApp().ICAControllerKeeper) + } + + cbs.OnChanUpgradeOpen( + suite.chainA.GetContext(), + path.EndpointA.ChannelConfig.PortID, + path.EndpointA.ChannelID, + channeltypes.ORDERED, + []string{path.EndpointA.ConnectionID}, + counterpartyVersion, + ) + }) + } +} + +func (suite *InterchainAccountsTestSuite) TestOnChanUpgradeRestore() { + var ( + path *ibctesting.Path + isNilApp bool + ) + + testCases := []struct { + name string + malleate func() + }{ + { + "success", func() {}, + }, + { + "success: nil app", + func() { + isNilApp = true + }, + }, + { + "middleware disabled", func() { + suite.chainA.GetSimApp().ICAControllerKeeper.DeleteMiddlewareEnabled(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ConnectionID) + suite.chainA.GetSimApp().ICAAuthModule.IBCApp.OnChanUpgradeAck = func(ctx sdk.Context, portID, channelID string, counterpartyVersion string) error { + return ibcmock.MockApplicationCallbackError + } + }, + }, + } + + for _, tc := range testCases { + tc := tc + + suite.Run(tc.name, func() { + suite.SetupTest() // reset + isNilApp = false + + path = NewICAPath(suite.chainA, suite.chainB) + suite.coordinator.SetupConnections(path) + + err := SetupICAPath(path, TestOwnerAddress) + suite.Require().NoError(err) + + tc.malleate() // malleate mutates test data + + module, _, err := suite.chainA.App.GetIBCKeeper().PortKeeper.LookupModuleByPort(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID) + suite.Require().NoError(err) + + app, ok := suite.chainA.App.GetIBCKeeper().Router.GetRoute(module) + suite.Require().True(ok) + cbs, ok := app.(porttypes.UpgradableModule) + suite.Require().True(ok) + + if isNilApp { + cbs = controller.NewIBCMiddleware(nil, suite.chainA.GetSimApp().ICAControllerKeeper) + } + + cbs.OnChanUpgradeRestore(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) + }) + } +} + func (suite *InterchainAccountsTestSuite) TestSingleHostMultipleControllers() { var ( pathAToB *ibctesting.Path