diff --git a/CHANGELOG.md b/CHANGELOG.md index 34ff72e76b9..4b95311f3cc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -49,6 +49,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ * (testing) [\#1418](https://github.com/cosmos/ibc-go/pull/1418) `MockIBCApp` has been renamed to `IBCApp` and `MockEmptyAcknowledgement` has been renamed to `EmptyAcknowledgement` to comply with go linting rules. * (apps/27-interchain-accounts) [\#2058](https://github.com/cosmos/ibc-go/pull/2058) Added `MessageRouter` interface and replaced `*baseapp.MsgServiceRouter` with it. The controller and host keepers of apps/27-interchain-accounts have been updated to use it. * (apps/27-interchain-accounts) [\#2133](https://github.com/cosmos/ibc-go/pull/2133) Generates genesis protos in a separate directory to avoid circular import errors. The protobuf package name has changed for the genesis types. +* (apps/27-interchain-accounts)[\#2302](https://github.com/cosmos/ibc-go/pull/2302) Handle unwrapping of channel version in interchain accounts channel reopening handshake flow. The `host` submodule `Keeper` now requires an `ICS4Wrapper` similarly to the `controller` submodule. * (apps/27-interchain-accounts) [\#2035](https://github.com/cosmos/ibc-go/pull/2035) Interchain accounts host and controller Keepers now expects a keeper which fulfills the expected `ScopedKeeper` interface for the capability keeper. ### State Machine Breaking diff --git a/modules/apps/27-interchain-accounts/controller/keeper/handshake.go b/modules/apps/27-interchain-accounts/controller/keeper/handshake.go index 842857dc844..7847c72a458 100644 --- a/modules/apps/27-interchain-accounts/controller/keeper/handshake.go +++ b/modules/apps/27-interchain-accounts/controller/keeper/handshake.go @@ -70,7 +70,12 @@ func (k Keeper) OnChanOpenInit( return "", sdkerrors.Wrapf(icatypes.ErrActiveChannelAlreadySet, "existing active channel %s for portID %s is already OPEN", activeChannelID, portID) } - if !icatypes.IsPreviousMetadataEqual(channel.Version, metadata) { + appVersion, found := k.GetAppVersion(ctx, portID, activeChannelID) + if !found { + panic(fmt.Sprintf("active channel mapping set for %s, but channel does not exist in channel store", activeChannelID)) + } + + if !icatypes.IsPreviousMetadataEqual(appVersion, metadata) { return "", sdkerrors.Wrap(icatypes.ErrInvalidVersion, "previous active channel metadata does not match provided version") } } diff --git a/modules/apps/27-interchain-accounts/controller/keeper/keeper.go b/modules/apps/27-interchain-accounts/controller/keeper/keeper.go index b7e4974a399..62d9fd487c8 100644 --- a/modules/apps/27-interchain-accounts/controller/keeper/keeper.go +++ b/modules/apps/27-interchain-accounts/controller/keeper/keeper.go @@ -4,7 +4,6 @@ import ( "fmt" "strings" - "github.com/cosmos/cosmos-sdk/baseapp" "github.com/cosmos/cosmos-sdk/codec" storetypes "github.com/cosmos/cosmos-sdk/store/types" sdk "github.com/cosmos/cosmos-sdk/types" @@ -38,7 +37,7 @@ type Keeper struct { func NewKeeper( cdc codec.BinaryCodec, key storetypes.StoreKey, paramSpace paramtypes.Subspace, ics4Wrapper icatypes.ICS4Wrapper, channelKeeper icatypes.ChannelKeeper, portKeeper icatypes.PortKeeper, - scopedKeeper icatypes.ScopedKeeper, msgRouter *baseapp.MsgServiceRouter, + scopedKeeper icatypes.ScopedKeeper, msgRouter icatypes.MessageRouter, ) Keeper { // set KeyTable if it has not already been set if !paramSpace.HasKeyTable() { diff --git a/modules/apps/27-interchain-accounts/host/ibc_module_test.go b/modules/apps/27-interchain-accounts/host/ibc_module_test.go index 6b11ea87760..813bbfcf42b 100644 --- a/modules/apps/27-interchain-accounts/host/ibc_module_test.go +++ b/modules/apps/27-interchain-accounts/host/ibc_module_test.go @@ -13,6 +13,7 @@ import ( "github.com/cosmos/ibc-go/v5/modules/apps/27-interchain-accounts/host/types" icatypes "github.com/cosmos/ibc-go/v5/modules/apps/27-interchain-accounts/types" + feetypes "github.com/cosmos/ibc-go/v5/modules/apps/29-fee/types" clienttypes "github.com/cosmos/ibc-go/v5/modules/core/02-client/types" channeltypes "github.com/cosmos/ibc-go/v5/modules/core/04-channel/types" host "github.com/cosmos/ibc-go/v5/modules/core/24-host" @@ -77,7 +78,7 @@ func RegisterInterchainAccount(endpoint *ibctesting.Endpoint, owner string) erro channelSequence := endpoint.Chain.App.GetIBCKeeper().ChannelKeeper.GetNextChannelSequence(endpoint.Chain.GetContext()) - if err := endpoint.Chain.GetSimApp().ICAControllerKeeper.RegisterInterchainAccount(endpoint.Chain.GetContext(), endpoint.ConnectionID, owner, TestVersion); err != nil { + if err := endpoint.Chain.GetSimApp().ICAControllerKeeper.RegisterInterchainAccount(endpoint.Chain.GetContext(), endpoint.ConnectionID, owner, endpoint.ChannelConfig.Version); err != nil { return err } @@ -618,6 +619,18 @@ func (suite *InterchainAccountsTestSuite) fundICAWallet(ctx sdk.Context, portID // A new channel will be opened for the controller portID. The interchain account address should remain unchanged. func (suite *InterchainAccountsTestSuite) TestControlAccountAfterChannelClose() { path := NewICAPath(suite.chainA, suite.chainB) + + // use a fee enabled version to cover unwrapping channel version code paths + feeMetadata := feetypes.Metadata{ + FeeVersion: feetypes.Version, + AppVersion: TestVersion, + } + + feeICAVersion := string(feetypes.ModuleCdc.MustMarshalJSON(&feeMetadata)) + + path.EndpointA.ChannelConfig.Version = feeICAVersion + path.EndpointB.ChannelConfig.Version = feeICAVersion + suite.coordinator.SetupConnections(path) err := SetupICAPath(path, TestOwnerAddress) diff --git a/modules/apps/27-interchain-accounts/host/keeper/handshake.go b/modules/apps/27-interchain-accounts/host/keeper/handshake.go index d7daa69712f..6b789f80019 100644 --- a/modules/apps/27-interchain-accounts/host/keeper/handshake.go +++ b/modules/apps/27-interchain-accounts/host/keeper/handshake.go @@ -59,7 +59,12 @@ func (k Keeper) OnChanOpenTry( return "", sdkerrors.Wrapf(icatypes.ErrActiveChannelAlreadySet, "existing active channel %s for portID %s is already OPEN", activeChannelID, portID) } - if !icatypes.IsPreviousMetadataEqual(channel.Version, metadata) { + appVersion, found := k.GetAppVersion(ctx, portID, activeChannelID) + if !found { + panic(fmt.Sprintf("active channel mapping set for %s, but channel does not exist in channel store", activeChannelID)) + } + + if !icatypes.IsPreviousMetadataEqual(appVersion, metadata) { return "", sdkerrors.Wrap(icatypes.ErrInvalidVersion, "previous active channel metadata does not match provided version") } } diff --git a/modules/apps/27-interchain-accounts/host/keeper/keeper.go b/modules/apps/27-interchain-accounts/host/keeper/keeper.go index febeb76bf96..93912498170 100644 --- a/modules/apps/27-interchain-accounts/host/keeper/keeper.go +++ b/modules/apps/27-interchain-accounts/host/keeper/keeper.go @@ -4,7 +4,6 @@ import ( "fmt" "strings" - "github.com/cosmos/cosmos-sdk/baseapp" "github.com/cosmos/cosmos-sdk/codec" storetypes "github.com/cosmos/cosmos-sdk/store/types" sdk "github.com/cosmos/cosmos-sdk/types" @@ -25,6 +24,7 @@ type Keeper struct { cdc codec.BinaryCodec paramSpace paramtypes.Subspace + ics4Wrapper icatypes.ICS4Wrapper channelKeeper icatypes.ChannelKeeper portKeeper icatypes.PortKeeper accountKeeper icatypes.AccountKeeper @@ -37,8 +37,8 @@ type Keeper struct { // NewKeeper creates a new interchain accounts host Keeper instance func NewKeeper( cdc codec.BinaryCodec, key storetypes.StoreKey, paramSpace paramtypes.Subspace, - channelKeeper icatypes.ChannelKeeper, portKeeper icatypes.PortKeeper, - accountKeeper icatypes.AccountKeeper, scopedKeeper icatypes.ScopedKeeper, msgRouter *baseapp.MsgServiceRouter, + ics4Wrapper icatypes.ICS4Wrapper, channelKeeper icatypes.ChannelKeeper, portKeeper icatypes.PortKeeper, + accountKeeper icatypes.AccountKeeper, scopedKeeper icatypes.ScopedKeeper, msgRouter icatypes.MessageRouter, ) Keeper { // ensure ibc interchain accounts module account is set if addr := accountKeeper.GetModuleAddress(icatypes.ModuleName); addr == nil { @@ -54,6 +54,7 @@ func NewKeeper( storeKey: key, cdc: cdc, paramSpace: paramSpace, + ics4Wrapper: ics4Wrapper, channelKeeper: channelKeeper, portKeeper: portKeeper, accountKeeper: accountKeeper, @@ -91,6 +92,11 @@ func (k Keeper) ClaimCapability(ctx sdk.Context, cap *capabilitytypes.Capability return k.scopedKeeper.ClaimCapability(ctx, cap, name) } +// GetAppVersion calls the ICS4Wrapper GetAppVersion function. +func (k Keeper) GetAppVersion(ctx sdk.Context, portID, channelID string) (string, bool) { + return k.ics4Wrapper.GetAppVersion(ctx, portID, channelID) +} + // GetActiveChannelID retrieves the active channelID from the store keyed by the provided connectionID and portID func (k Keeper) GetActiveChannelID(ctx sdk.Context, connectionID, portID string) (string, bool) { store := ctx.KVStore(k.storeKey) diff --git a/testing/simapp/app.go b/testing/simapp/app.go index 51352dab95e..562eafc1801 100644 --- a/testing/simapp/app.go +++ b/testing/simapp/app.go @@ -404,6 +404,7 @@ func NewSimApp( // ICA Host keeper app.ICAHostKeeper = icahostkeeper.NewKeeper( appCodec, keys[icahosttypes.StoreKey], app.GetSubspace(icahosttypes.SubModuleName), + app.IBCFeeKeeper, // use ics29 fee as ics4Wrapper in middleware stack app.IBCKeeper.ChannelKeeper, &app.IBCKeeper.PortKeeper, app.AccountKeeper, scopedICAHostKeeper, app.MsgServiceRouter(), )