diff --git a/modules/apps/27-interchain-accounts/genesis.go b/modules/apps/27-interchain-accounts/genesis.go index 0fd975ace00..e052834b8a5 100644 --- a/modules/apps/27-interchain-accounts/genesis.go +++ b/modules/apps/27-interchain-accounts/genesis.go @@ -22,9 +22,10 @@ func InitGenesis(ctx sdk.Context, keeper keeper.Keeper, state types.GenesisState // ExportGenesis exports transfer module's portID into its geneis state func ExportGenesis(ctx sdk.Context, keeper keeper.Keeper) *types.GenesisState { - portID := keeper.GetPort(ctx) + // TODO: Using a range query with KVStorePrefixIterator export all port IDs + // See https://github.com/cosmos/ibc-go/issues/448 return &types.GenesisState{ - PortId: portID, + PortId: types.PortID, } } diff --git a/modules/apps/27-interchain-accounts/keeper/keeper.go b/modules/apps/27-interchain-accounts/keeper/keeper.go index f10f5b8678d..d66026c7a6d 100644 --- a/modules/apps/27-interchain-accounts/keeper/keeper.go +++ b/modules/apps/27-interchain-accounts/keeper/keeper.go @@ -2,6 +2,7 @@ package keeper import ( "fmt" + "strings" baseapp "github.com/cosmos/cosmos-sdk/baseapp" "github.com/cosmos/cosmos-sdk/codec" @@ -83,16 +84,26 @@ func (k Keeper) Logger(ctx sdk.Context) log.Logger { return ctx.Logger().With("module", fmt.Sprintf("x/%s-%s", host.ModuleName, types.ModuleName)) } -// GetPort returns the portID for the interchain accounts module. Used in ExportGenesis -func (k Keeper) GetPort(ctx sdk.Context) string { +// GetAllPorts returns all ports to which the interchain accounts module is bound. Used in ExportGenesis +func (k Keeper) GetAllPorts(ctx sdk.Context) []string { store := ctx.KVStore(k.storeKey) - return string(store.Get([]byte(types.PortKey))) + iterator := sdk.KVStorePrefixIterator(store, []byte(types.PortKeyPrefix)) + defer iterator.Close() + + var ports []string + for ; iterator.Valid(); iterator.Next() { + keySplit := strings.Split(string(iterator.Key()), "/") + + ports = append(ports, keySplit[1]) + } + + return ports } // BindPort stores the provided portID and binds to it, returning the associated capability func (k Keeper) BindPort(ctx sdk.Context, portID string) *capabilitytypes.Capability { store := ctx.KVStore(k.storeKey) - store.Set([]byte(types.PortKey), []byte(portID)) + store.Set(types.KeyPort(portID), []byte{0x01}) return k.portKeeper.BindPort(ctx, portID) } diff --git a/modules/apps/27-interchain-accounts/keeper/keeper_test.go b/modules/apps/27-interchain-accounts/keeper/keeper_test.go index 0c407e88121..307451fd14b 100644 --- a/modules/apps/27-interchain-accounts/keeper/keeper_test.go +++ b/modules/apps/27-interchain-accounts/keeper/keeper_test.go @@ -108,9 +108,17 @@ func (suite *KeeperTestSuite) TestIsBound() { suite.Require().True(isBound) } -func (suite *KeeperTestSuite) TestGetPort() { - port := suite.chainA.GetSimApp().ICAKeeper.GetPort(suite.chainA.GetContext()) - suite.Require().Equal(types.PortID, port) +func (suite *KeeperTestSuite) TestGetAllPorts() { + suite.SetupTest() + path := NewICAPath(suite.chainA, suite.chainB) + suite.coordinator.SetupConnections(path) + + err := SetupICAPath(path, TestOwnerAddress) + suite.Require().NoError(err) + + ports := suite.chainA.GetSimApp().ICAKeeper.GetAllPorts(suite.chainA.GetContext()) + suite.Require().Contains(ports, types.PortID) + suite.Require().Contains(ports, TestPortID) } func (suite *KeeperTestSuite) TestGetInterchainAccountAddress() { diff --git a/modules/apps/27-interchain-accounts/types/keys.go b/modules/apps/27-interchain-accounts/types/keys.go index d8e3e1c1ec4..a71f6c0c32c 100644 --- a/modules/apps/27-interchain-accounts/types/keys.go +++ b/modules/apps/27-interchain-accounts/types/keys.go @@ -38,8 +38,14 @@ const ( ) var ( - // PortKey defines the key to store the port ID in store - PortKey = []byte{0x01} + // ActiveChannelKeyPrefix defines the key prefix used to store active channels + ActiveChannelKeyPrefix = "activeChannel" + + // OwnerKeyPrefix defines the key prefix used to store interchain accounts + OwnerKeyPrefix = "owner" + + // PortKeyPrefix defines the key prefix used to store ports + PortKeyPrefix = "port" ) // NewVersion returns a complete version string in the format: VersionPrefix + Delimter + AccAddress @@ -49,12 +55,17 @@ func NewAppVersion(versionPrefix, accAddr string) string { // KeyActiveChannel creates and returns a new key used for active channels store operations func KeyActiveChannel(portID string) []byte { - return []byte(fmt.Sprintf("activeChannel/%s", portID)) + return []byte(fmt.Sprintf("%s/%s", ActiveChannelKeyPrefix, portID)) } -// KeyOwnerAccount creates and returns a new key used for owner account store operations +// KeyOwnerAccount creates and returns a new key used for interchain account store operations func KeyOwnerAccount(portID string) []byte { - return []byte(fmt.Sprintf("owner/%s", portID)) + return []byte(fmt.Sprintf("%s/%s", OwnerKeyPrefix, portID)) +} + +// KeyPort creates and returns a new key used for port store operations +func KeyPort(portID string) []byte { + return []byte(fmt.Sprintf("%s/%s", PortKeyPrefix, portID)) } // ParseControllerConnSequence attempts to parse the controller connection sequence from the provided port identifier