Skip to content

Commit

Permalink
ica: genesis state implementation (#481)
Browse files Browse the repository at this point in the history
* initial genesis state draft

* updating protos

* including yaml tags, sorting proto file structure

* updating to use range queries for active channels/interchain accounts

* updating GetAllPorts test

* moving test strings to expected vars
  • Loading branch information
damiannolan authored Nov 5, 2021
1 parent cd2f81d commit 3ff5bf8
Show file tree
Hide file tree
Showing 11 changed files with 872 additions and 46 deletions.
38 changes: 37 additions & 1 deletion docs/ibc/proto-docs.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@
- [InterchainAccount](#ibc.applications.interchain_accounts.v1.InterchainAccount)

- [ibc/applications/interchain_accounts/v1/genesis.proto](#ibc/applications/interchain_accounts/v1/genesis.proto)
- [ActiveChannel](#ibc.applications.interchain_accounts.v1.ActiveChannel)
- [GenesisState](#ibc.applications.interchain_accounts.v1.GenesisState)
- [RegisteredInterchainAccount](#ibc.applications.interchain_accounts.v1.RegisteredInterchainAccount)

- [ibc/applications/interchain_accounts/v1/query.proto](#ibc/applications/interchain_accounts/v1/query.proto)
- [QueryInterchainAccountAddressRequest](#ibc.applications.interchain_accounts.v1.QueryInterchainAccountAddressRequest)
Expand Down Expand Up @@ -311,15 +313,49 @@ An InterchainAccount is defined as a BaseAccount & the address of the account ow



<a name="ibc.applications.interchain_accounts.v1.ActiveChannel"></a>

### ActiveChannel
ActiveChannel contains a pairing of port ID and channel ID for an active interchain accounts channel


| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| `port_id` | [string](#string) | | |
| `channel_id` | [string](#string) | | |






<a name="ibc.applications.interchain_accounts.v1.GenesisState"></a>

### GenesisState
GenesisState defines the interchain_account genesis state
GenesisState defines the interchain accounts genesis state


| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| `active_channels` | [ActiveChannel](#ibc.applications.interchain_accounts.v1.ActiveChannel) | repeated | |
| `interchain_accounts` | [RegisteredInterchainAccount](#ibc.applications.interchain_accounts.v1.RegisteredInterchainAccount) | repeated | |
| `ports` | [string](#string) | repeated | |






<a name="ibc.applications.interchain_accounts.v1.RegisteredInterchainAccount"></a>

### RegisteredInterchainAccount
RegisteredInterchainAccount contains a pairing of controller port ID and associated interchain account address


| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| `port_id` | [string](#string) | | |
| `account_address` | [string](#string) | | |



Expand Down
31 changes: 20 additions & 11 deletions modules/apps/27-interchain-accounts/genesis.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,20 +12,29 @@ import (

// InitGenesis initializes the interchain accounts application state from a provided genesis state
func InitGenesis(ctx sdk.Context, keeper keeper.Keeper, state types.GenesisState) {
if !keeper.IsBound(ctx, state.PortId) {
cap := keeper.BindPort(ctx, state.PortId)
if err := keeper.ClaimCapability(ctx, cap, host.PortPath(state.PortId)); err != nil {
panic(fmt.Sprintf("could not claim port capability: %v", err))
for _, portID := range state.Ports {
if !keeper.IsBound(ctx, portID) {
cap := keeper.BindPort(ctx, portID)
if err := keeper.ClaimCapability(ctx, cap, host.PortPath(portID)); err != nil {
panic(fmt.Sprintf("could not claim port capability: %v", err))
}
}
}
}

// ExportGenesis exports transfer module's portID into its geneis state
func ExportGenesis(ctx sdk.Context, keeper keeper.Keeper) *types.GenesisState {
// TODO: Using a range query with KVStorePrefixIterator export all port IDs
// See https://github.com/cosmos/ibc-go/issues/448
for _, ch := range state.ActiveChannels {
keeper.SetActiveChannelID(ctx, ch.PortId, ch.ChannelId)
}

return &types.GenesisState{
PortId: types.PortID,
for _, acc := range state.InterchainAccounts {
keeper.SetInterchainAccountAddress(ctx, acc.PortId, acc.AccountAddress)
}
}

// ExportGenesis returns the interchain accounts exported genesis
func ExportGenesis(ctx sdk.Context, keeper keeper.Keeper) *types.GenesisState {
return types.NewGenesisState(
keeper.GetAllPorts(ctx),
keeper.GetAllActiveChannels(ctx),
keeper.GetAllInterchainAccounts(ctx),
)
}
59 changes: 59 additions & 0 deletions modules/apps/27-interchain-accounts/genesis_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package interchain_accounts_test

import (
ica "github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts"
"github.com/cosmos/ibc-go/v2/modules/apps/27-interchain-accounts/types"
)

func (suite *InterchainAccountsTestSuite) TestInitGenesis() {
var (
expectedChannelID string = "channel-0"
)

suite.SetupTest()

genesisState := types.GenesisState{
Ports: []string{types.PortID, TestPortID},
ActiveChannels: []*types.ActiveChannel{
{
PortId: TestPortID,
ChannelId: expectedChannelID,
},
},
InterchainAccounts: []*types.RegisteredInterchainAccount{
{
PortId: TestPortID,
AccountAddress: TestAccAddress.String(),
},
},
}

ica.InitGenesis(suite.chainA.GetContext(), suite.chainA.GetSimApp().ICAKeeper, genesisState)

channelID, found := suite.chainA.GetSimApp().ICAKeeper.GetActiveChannelID(suite.chainA.GetContext(), TestPortID)
suite.Require().True(found)
suite.Require().Equal(expectedChannelID, channelID)

accountAdrr, found := suite.chainA.GetSimApp().ICAKeeper.GetInterchainAccountAddress(suite.chainA.GetContext(), TestPortID)
suite.Require().True(found)
suite.Require().Equal(TestAccAddress.String(), accountAdrr)
}

func (suite *InterchainAccountsTestSuite) TestExportGenesis() {
suite.SetupTest()
path := NewICAPath(suite.chainA, suite.chainB)
suite.coordinator.SetupConnections(path)

err := SetupICAPath(path, TestOwnerAddress)
suite.Require().NoError(err)

genesisState := ica.ExportGenesis(suite.chainA.GetContext(), suite.chainA.GetSimApp().ICAKeeper)

suite.Require().Equal([]string{types.PortID, TestPortID}, genesisState.GetPorts())

suite.Require().Equal(path.EndpointA.ChannelID, genesisState.ActiveChannels[0].ChannelId)
suite.Require().Equal(path.EndpointA.ChannelConfig.PortID, genesisState.ActiveChannels[0].PortId)

suite.Require().Equal(TestAccAddress.String(), genesisState.InterchainAccounts[0].AccountAddress)
suite.Require().Equal(path.EndpointA.ChannelConfig.PortID, genesisState.InterchainAccounts[0].PortId)
}
41 changes: 41 additions & 0 deletions modules/apps/27-interchain-accounts/keeper/keeper.go
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,27 @@ func (k Keeper) GetActiveChannelID(ctx sdk.Context, portID string) (string, bool
return string(store.Get(key)), true
}

// GetAllActiveChannels returns a list of all active interchain accounts channels and their associated port identifiers
func (k Keeper) GetAllActiveChannels(ctx sdk.Context) []*types.ActiveChannel {
store := ctx.KVStore(k.storeKey)
iterator := sdk.KVStorePrefixIterator(store, []byte(types.ActiveChannelKeyPrefix))
defer iterator.Close()

var activeChannels []*types.ActiveChannel
for ; iterator.Valid(); iterator.Next() {
keySplit := strings.Split(string(iterator.Key()), "/")

ch := &types.ActiveChannel{
PortId: keySplit[1],
ChannelId: string(iterator.Value()),
}

activeChannels = append(activeChannels, ch)
}

return activeChannels
}

// SetActiveChannelID stores the active channelID, keyed by the provided portID
func (k Keeper) SetActiveChannelID(ctx sdk.Context, portID, channelID string) {
store := ctx.KVStore(k.storeKey)
Expand Down Expand Up @@ -143,6 +164,26 @@ func (k Keeper) GetInterchainAccountAddress(ctx sdk.Context, portID string) (str
return string(store.Get(key)), true
}

// GetAllInterchainAccounts returns a list of all registered interchain account addresses and their associated controller port identifiers
func (k Keeper) GetAllInterchainAccounts(ctx sdk.Context) []*types.RegisteredInterchainAccount {
store := ctx.KVStore(k.storeKey)
iterator := sdk.KVStorePrefixIterator(store, []byte(types.OwnerKeyPrefix))

var interchainAccounts []*types.RegisteredInterchainAccount
for ; iterator.Valid(); iterator.Next() {
keySplit := strings.Split(string(iterator.Key()), "/")

acc := &types.RegisteredInterchainAccount{
PortId: keySplit[1],
AccountAddress: string(iterator.Value()),
}

interchainAccounts = append(interchainAccounts, acc)
}

return interchainAccounts
}

// SetInterchainAccountAddress stores the InterchainAccount address, keyed by the associated portID
func (k Keeper) SetInterchainAccountAddress(ctx sdk.Context, portID string, address string) {
store := ctx.KVStore(k.storeKey)
Expand Down
80 changes: 74 additions & 6 deletions modules/apps/27-interchain-accounts/keeper/keeper_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -116,9 +116,11 @@ func (suite *KeeperTestSuite) TestGetAllPorts() {
err := SetupICAPath(path, TestOwnerAddress)
suite.Require().NoError(err)

expectedPorts := []string{types.PortID, TestPortID}

ports := suite.chainA.GetSimApp().ICAKeeper.GetAllPorts(suite.chainA.GetContext())
suite.Require().Contains(ports, types.PortID)
suite.Require().Contains(ports, TestPortID)
suite.Require().Len(ports, len(expectedPorts))
suite.Require().Equal(expectedPorts, ports)
}

func (suite *KeeperTestSuite) TestGetInterchainAccountAddress() {
Expand All @@ -141,6 +143,68 @@ func (suite *KeeperTestSuite) TestGetInterchainAccountAddress() {
suite.Require().Empty(retrievedAddr)
}

func (suite *KeeperTestSuite) TestGetAllActiveChannels() {
var (
expectedChannelID string = "test-channel"
expectedPortID string = "test-port"
)

suite.SetupTest()
path := NewICAPath(suite.chainA, suite.chainB)
suite.coordinator.SetupConnections(path)

err := SetupICAPath(path, TestOwnerAddress)
suite.Require().NoError(err)

suite.chainA.GetSimApp().ICAKeeper.SetActiveChannelID(suite.chainA.GetContext(), expectedPortID, expectedChannelID)

expectedChannels := []*types.ActiveChannel{
{
PortId: TestPortID,
ChannelId: path.EndpointA.ChannelID,
},
{
PortId: expectedPortID,
ChannelId: expectedChannelID,
},
}

activeChannels := suite.chainA.GetSimApp().ICAKeeper.GetAllActiveChannels(suite.chainA.GetContext())
suite.Require().Len(activeChannels, len(expectedChannels))
suite.Require().Equal(expectedChannels, activeChannels)
}

func (suite *KeeperTestSuite) TestGetAllInterchainAccounts() {
var (
expectedAccAddr string = "test-acc-addr"
expectedPortID string = "test-port"
)

suite.SetupTest()
path := NewICAPath(suite.chainA, suite.chainB)
suite.coordinator.SetupConnections(path)

err := SetupICAPath(path, TestOwnerAddress)
suite.Require().NoError(err)

suite.chainA.GetSimApp().ICAKeeper.SetInterchainAccountAddress(suite.chainA.GetContext(), expectedPortID, expectedAccAddr)

expectedAccounts := []*types.RegisteredInterchainAccount{
{
PortId: TestPortID,
AccountAddress: TestAccAddress.String(),
},
{
PortId: expectedPortID,
AccountAddress: expectedAccAddr,
},
}

interchainAccounts := suite.chainA.GetSimApp().ICAKeeper.GetAllInterchainAccounts(suite.chainA.GetContext())
suite.Require().Len(interchainAccounts, len(expectedAccounts))
suite.Require().Equal(expectedAccounts, interchainAccounts)
}

func (suite *KeeperTestSuite) TestIsActiveChannel() {
suite.SetupTest() // reset
path := NewICAPath(suite.chainA, suite.chainB)
Expand All @@ -156,12 +220,16 @@ func (suite *KeeperTestSuite) TestIsActiveChannel() {
}

func (suite *KeeperTestSuite) TestSetInterchainAccountAddress() {
expectedAddr, portID := "address", "port"
suite.chainA.GetSimApp().ICAKeeper.SetInterchainAccountAddress(suite.chainA.GetContext(), portID, expectedAddr)
var (
expectedAccAddr string = "test-acc-addr"
expectedPortID string = "test-port"
)

suite.chainA.GetSimApp().ICAKeeper.SetInterchainAccountAddress(suite.chainA.GetContext(), expectedPortID, expectedAccAddr)

retrievedAddr, found := suite.chainA.GetSimApp().ICAKeeper.GetInterchainAccountAddress(suite.chainA.GetContext(), portID)
retrievedAddr, found := suite.chainA.GetSimApp().ICAKeeper.GetInterchainAccountAddress(suite.chainA.GetContext(), expectedPortID)
suite.Require().True(found)
suite.Require().Equal(expectedAddr, retrievedAddr)
suite.Require().Equal(expectedAccAddr, retrievedAddr)
}

func (suite *KeeperTestSuite) SetupICAPath(path *ibctesting.Path, owner string) error {
Expand Down
13 changes: 12 additions & 1 deletion modules/apps/27-interchain-accounts/types/genesis.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,18 @@
package types

// DefaultGenesis creates and returns the default interchain accounts GenesisState
// The default GenesisState includes the standard port identifier to which all host chains must bind
func DefaultGenesis() *GenesisState {
return &GenesisState{
PortId: PortID,
Ports: []string{PortID},
}
}

// NewGenesisState creates a returns a new GenesisState instance
func NewGenesisState(ports []string, channels []*ActiveChannel, accounts []*RegisteredInterchainAccount) *GenesisState {
return &GenesisState{
ActiveChannels: channels,
InterchainAccounts: accounts,
Ports: ports,
}
}
Loading

0 comments on commit 3ff5bf8

Please sign in to comment.