diff --git a/CHANGELOG.md b/CHANGELOG.md
index 84c14c5136f..95c129cb08b 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -43,6 +43,8 @@ Ref: https://keepachangelog.com/en/1.0.0/
### API Breaking
+* (testing( [\#813](https://github.com/cosmos/ibc-go/pull/813) The `ack` argument to the testing function `RelayPacket` has been removed as it is no longer needed.
+* (testing) [\#774](https://github.com/cosmos/ibc-go/pull/774) Added `ChainID` arg to `SetupWithGenesisValSet` on the testing app. `Coordinator` generated ChainIDs now starts at index 1
* (transfer) [\#675](https://github.com/cosmos/ibc-go/pull/675) Transfer `NewKeeper` now takes in an ICS4Wrapper. The ICS4Wrapper may be the IBC Channel Keeper when ICS20 is not used in a middleware stack. The ICS4Wrapper is required for applications wishing to connect middleware to ICS20.
* (core) [\#650](https://github.com/cosmos/ibc-go/pull/650) Modify `OnChanOpenTry` IBC application module callback to return the negotiated app version. The version passed into the `MsgChanOpenTry` has been deprecated and will be ignored by core IBC.
* (core) [\#629](https://github.com/cosmos/ibc-go/pull/629) Removes the `GetProofSpecs` from the ClientState interface. This function was previously unused by core IBC.
@@ -56,6 +58,7 @@ Ref: https://keepachangelog.com/en/1.0.0/
### Improvements
+* (testing) [\#810](https://github.com/cosmos/ibc-go/pull/810) Additional testing function added to `Endpoint` type called `RecvPacketWithResult`. Performs the same functionality as the existing `RecvPacket` function but also returns the message result. `path.RelayPacket` no longer uses the provided acknowledgement argument and instead obtains the acknowledgement via MsgRecvPacket events.
* (connection) [\#721](https://github.com/cosmos/ibc-go/pull/721) Simplify connection handshake error messages when unpacking client state.
* (channel) [\#692](https://github.com/cosmos/ibc-go/pull/692) Minimize channel logging by only emitting the packet sequence, source port/channel, destination port/channel upon packet receives, acknowledgements and timeouts.
* [\#383](https://github.com/cosmos/ibc-go/pull/383) Adds helper functions for merging and splitting middleware versions from the underlying app version.
diff --git a/RELEASES.md b/RELEASES.md
index 408f51e8a75..27f0874c650 100644
--- a/RELEASES.md
+++ b/RELEASES.md
@@ -21,6 +21,45 @@ To summarize: **All our ibc-go releases allow chains to communicate successfully
We ensure all major releases are supported by relayers ([hermes](https://github.com/informalsystems/ibc-rs), [rly](https://github.com/strangelove-ventures/relayer) and [ts-relayer](https://github.com/confio/ts-relayer) at the moment) which can relay between the new major release and older releases. We have no plans of upgrading to an IBC protocol specification v2.0, as this would be very disruptive to the ecosystem.
+## Stable Release Policy
+
+The beginning of a new major release series is marked by the release of a new major version. A major release series is comprised of all minor and patch releases made under the same major version number. The series continues to receive bug fixes (released as minor or patch releases) until it reaches end of life. The date when a major release series reaches end of life is determined by one of the two following methods:
+- If the next major release is made within the first 6 months, then the end of life date of the major release series is 1 year after its initial release.
+- If the next major release is made 6 months after the initial release, then the end of life date of the major release series is 6 months after the release date of the next major release.
+
+For example, if the current major release series is v1 and was released on January 1st, 2022, then v1 will be supported at least until January 1st, 2023. If v2 is published on August 1st 2022, then v1's end of life will be March 1st, 2023.
+
+Only the following major release series have a stable release status:
+
+|Release|End of Life Date|
+|-------|-------|
+|`v1.1.x`|July 01, 2022|
+|`v1.2.x`|July 01, 2022|
+|`v2.0.x`|February 01, 2023|
+
+**Note**: The v1 major release series will reach end of life 6 months after merging this policy. v2 will reach end of life one year after merging this policy.
+
+### What pull requests will be included in stable patch-releases?
+
+Pull requests that fix bugs and add features that fall in the following categories:
+
+* **Severe regressions**.
+* Bugs that may cause **client applications** to be **largely unusable**.
+* Bugs that may cause **state corruption or data loss**.
+* Bugs that may directly or indirectly cause a **security vulnerability**.
+* Non-breaking features that are strongly requested by the community.
+* Non-breaking CLI improvements that are strongly requested by the community.
+
+### What pull requests will NOT be automatically included in stable patch-releases?
+
+As rule of thumb, the following changes will **NOT** be automatically accepted into stable point-releases:
+
+* **State machine changes**, unless the previous behaviour would result in a consensus halt.
+* **Protobuf-breaking changes**.
+* **Client-breaking changes**, i.e. changes that prevent gRPC, HTTP and RPC clients to continue interacting with the node without any change.
+* **API-breaking changes**, i.e. changes that prevent client applications to *build without modifications* to the client application's source code.
+* **CLI-breaking changes**, i.e. changes that require usage changes for CLI users.
+
## Graphics
The decision tree above was generated with the following code:
diff --git a/docs/.vuepress/config.js b/docs/.vuepress/config.js
index 4ff423484b1..d78f801654c 100644
--- a/docs/.vuepress/config.js
+++ b/docs/.vuepress/config.js
@@ -121,6 +121,11 @@ module.exports = {
directory: false,
path: "/app-modules/interchain-accounts/auth-modules.html"
},
+ {
+ title: "Active Channels",
+ directory: false,
+ path: "/app-modules/interchain-accounts/active-channels.html"
+ },
{
title: "Integration",
directory: false,
diff --git a/docs/app-modules/interchain-accounts/active-channels.md b/docs/app-modules/interchain-accounts/active-channels.md
new file mode 100644
index 00000000000..c574ea87d85
--- /dev/null
+++ b/docs/app-modules/interchain-accounts/active-channels.md
@@ -0,0 +1,25 @@
+
+
+# Understanding Active Channels
+
+The Interchain Accounts module uses [ORDERED channels](https://github.com/cosmos/ibc/tree/master/spec/core/ics-004-channel-and-packet-semantics#ordering) to maintain the order of transactions when sending packets from a controller to a host chain. A limitation when using ORDERED channels is that when a packet times out the channel will be closed.
+
+In the case of a channel closing, a controller chain needs to be able to regain access to the interchain account registered on this channel. `Active Channels` enable this functionality. Future versions of the ICS-27 protocol and the Interchain Accounts module will likely use a new
+channel type that provides ordering of packets without the channel closing on timing out, thus removing the need for `Active Channels` entirely.
+
+When an Interchain Account is registered using the `RegisterInterchainAccount` API, a new channel is created on a particular port. During the `OnChanOpenAck` and `OnChanOpenConfirm` steps (controller & host chain) the `Active Channel` for this interchain account
+is stored in state.
+
+It is possible to create a new channel using the same controller chain portID if the previously set `Active Channel` is now in a `CLOSED` state. This channel creation can be initialized programatically by sending a new `OnChanOpenInit` message like so:
+
+```go
+ msg := channeltypes.NewMsgChannelOpenInit(portID, string(versionBytes), channeltypes.ORDERED, []string{connectionID}, icatypes.PortID, icatypes.ModuleName)
+ handler := k.msgRouter.Handler(msg)
+```
+
+Alternatively, any relayer operator may initiate a new channel handshake for this interchain account once the previously set `Active Channel` is in a `CLOSED` state. This is done by initiating the channel handshake on the controller chain using the same portID associated with the interchain account in question.
+
+It is important to note that once a channel has been opened for a given Interchain Account, new channels can not be opened for this account until the currently set `Active Channel` is set to `CLOSED`.
+
diff --git a/docs/app-modules/interchain-accounts/auth-modules.md b/docs/app-modules/interchain-accounts/auth-modules.md
index 04bc180e3f1..4d8b126dd2f 100644
--- a/docs/app-modules/interchain-accounts/auth-modules.md
+++ b/docs/app-modules/interchain-accounts/auth-modules.md
@@ -145,21 +145,21 @@ func (im IBCModule) OnRecvPacket(
}
```
-## `InitInterchainAccount`
+## `RegisterInterchainAccount`
-The authentication module can begin registering interchain accounts by calling `InitInterchainAccount`:
+The authentication module can begin registering interchain accounts by calling `RegisterInterchainAccount`:
```go
-if err := keeper.icaControllerKeeper.InitInterchainAccount(ctx, connectionID, owner.String()); err != nil {
+if err := keeper.icaControllerKeeper.RegisterInterchainAccount(ctx, connectionID, owner.String()); err != nil {
return err
}
return nil
```
-## `TrySendTx`
+## `SendTx`
-The authentication module can attempt to send a packet by calling `TrySendTx`:
+The authentication module can attempt to send a packet by calling `SendTx`:
```go
// Authenticate owner
@@ -204,7 +204,7 @@ packetData := icatypes.InterchainAccountPacketData{
timeoutTimestamp := obtainTimeoutTimestamp()
// Send the interchain accounts packet, returning the packet sequence
-seq, err = keeper.icaControllerKeeper.TrySendTx(ctx, chanCap, portID, packetData, timeoutTimestamp)
+seq, err = keeper.icaControllerKeeper.SendTx(ctx, chanCap, portID, packetData, timeoutTimestamp)
```
The data within an `InterchainAccountPacketData` must be serialized using a format supported by the host chain.
diff --git a/docs/app-modules/interchain-accounts/integration.md b/docs/app-modules/interchain-accounts/integration.md
index e9ea1afeac9..14757ccca3c 100644
--- a/docs/app-modules/interchain-accounts/integration.md
+++ b/docs/app-modules/interchain-accounts/integration.md
@@ -94,7 +94,7 @@ app.ICAAuthKeeper = icaauthkeeper.NewKeeper(appCodec, keys[icaauthtypes.StoreKey
icaAuthModule := icaauth.NewAppModule(appCodec, app.ICAAuthKeeper)
// ICA auth IBC Module
-ICAAuthIBCModule := icaauth.NewIBCModule(app.ICAAuthKeeper)
+icaAuthIBCModule := icaauth.NewIBCModule(app.ICAAuthKeeper)
// Create host and controller IBC Modules as desired
icaControllerIBCModule := icacontroller.NewIBCModule(app.ICAControllerKeeper, icaAuthIBCModule)
@@ -122,4 +122,44 @@ app.mm.SetOrderInitGenesis(
icatypes.ModuleName,
...
)
-```
\ No newline at end of file
+```
+
+### Using submodules exclusively
+
+As described above, the Interchain Accounts application module is structured to support the ability of exclusively enabling controller or host functionality.
+This can be achieved by simply omitting either controller or host `Keeper` from the Interchain Accounts `NewAppModule` constructor function, and mounting only the desired submodule via the `IBCRouter`.
+Alternatively, submodules can be enabled and disabled dynamically using [on-chain parameters](./parameters.md).
+
+The following snippets show basic examples of statically disabling submodules using `app.go`.
+
+#### Disabling controller chain functionality
+
+```go
+// Create Interchain Accounts AppModule omitting the controller keeper
+icaModule := ica.NewAppModule(nil, &app.ICAHostKeeper)
+
+// Create host IBC Module
+icaHostIBCModule := icahost.NewIBCModule(app.ICAHostKeeper)
+
+// Register host route
+ibcRouter.AddRoute(icahosttypes.SubModuleName, icaHostIBCModule)
+```
+
+#### Disabling host chain functionality
+
+```go
+// Create Interchain Accounts AppModule omitting the host keeper
+icaModule := ica.NewAppModule(&app.ICAControllerKeeper, nil)
+
+// Create your Interchain Accounts authentication module, setting up the Keeper, AppModule and IBCModule appropriately
+app.ICAAuthKeeper = icaauthkeeper.NewKeeper(appCodec, keys[icaauthtypes.StoreKey], app.ICAControllerKeeper, scopedICAAuthKeeper)
+icaAuthModule := icaauth.NewAppModule(appCodec, app.ICAAuthKeeper)
+icaAuthIBCModule := icaauth.NewIBCModule(app.ICAAuthKeeper)
+
+// Create controller IBC Module
+icaControllerIBCModule := icacontroller.NewIBCModule(app.ICAControllerKeeper, icaAuthIBCModule)
+
+// Register controller and authentication routes
+ibcRouter.AddRoute(icacontrollertypes.SubModuleName, icaControllerIBCModule)
+ibcRouter.AddRoute(icaauthtypes.ModuleName, icaControllerIBCModule) // Note, the authentication module is routed to the top level of the middleware stack
+```
diff --git a/docs/app-modules/interchain-accounts/transactions.md b/docs/app-modules/interchain-accounts/transactions.md
index efa7b0e07d5..a78a917387f 100644
--- a/docs/app-modules/interchain-accounts/transactions.md
+++ b/docs/app-modules/interchain-accounts/transactions.md
@@ -1,5 +1,5 @@
# Transactions
@@ -10,7 +10,7 @@ Learn about Interchain Accounts transaction execution {synopsis}
As described in [Authentication Modules](./auth-modules.md#trysendtx) transactions are executed using the interchain accounts controller API and require a `Base Application` as outlined in [ICS30 IBC Middleware](https://github.com/cosmos/ibc/tree/master/spec/app/ics-030-middleware) to facilitate authentication. The method of authentication remains unspecified to provide flexibility for the authentication module developer.
-Transactions are executed via the ICS27 [`TrySendTx` API](./auth-modules.md#trysendtx). This must be invoked through an Interchain Accounts authentication module and follows the outlined path of execution below. Packet relaying semantics provided by the IBC core transport, authentication, and ordering (IBC/TAO) layer are omitted for brevity.
+Transactions are executed via the ICS27 [`SendTx` API](./auth-modules.md#trysendtx). This must be invoked through an Interchain Accounts authentication module and follows the outlined path of execution below. Packet relaying semantics provided by the IBC core transport, authentication, and ordering (IBC/TAO) layer are omitted for brevity.
![send-tx-flow](../../assets/send-interchain-tx.png "Transaction Execution")
@@ -18,4 +18,4 @@ Transactions are executed via the ICS27 [`TrySendTx` API](./auth-modules.md#trys
As the Interchain Accounts module supports the execution of multiple transactions using the Cosmos SDK `Msg` interface, it provides the same atomicity guarantees as Cosmos SDK-based applications, leveraging the [`CacheMultiStore`](https://docs.cosmos.network/master/core/store.html#cachemultistore) architecture provided by the [`Context`](https://docs.cosmos.network/master/core/context.html) type.
-This provides atomic execution of transactions when using Interchain Accounts, where state changes are only committed if all `Msg`s succeed.
\ No newline at end of file
+This provides atomic execution of transactions when using Interchain Accounts, where state changes are only committed if all `Msg`s succeed.
diff --git a/docs/ibc/proto-docs.md b/docs/ibc/proto-docs.md
index 889aee1bad7..667b8b9a4ee 100644
--- a/docs/ibc/proto-docs.md
+++ b/docs/ibc/proto-docs.md
@@ -311,11 +311,12 @@ An InterchainAccount is defined as a BaseAccount & the address of the account ow
### ActiveChannel
-ActiveChannel contains a pairing of port ID and channel ID for an active interchain accounts channel
+ActiveChannel contains a connection ID, port ID and associated active channel ID
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
+| `connection_id` | [string](#string) | | |
| `port_id` | [string](#string) | | |
| `channel_id` | [string](#string) | | |
@@ -379,11 +380,12 @@ HostGenesisState defines the interchain accounts host genesis state
### RegisteredInterchainAccount
-RegisteredInterchainAccount contains a pairing of controller port ID and associated interchain account address
+RegisteredInterchainAccount contains a connection ID, port ID and associated interchain account address
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
+| `connection_id` | [string](#string) | | |
| `port_id` | [string](#string) | | |
| `account_address` | [string](#string) | | |
diff --git a/go.mod b/go.mod
index 4b7ae65835d..cb79c90045a 100644
--- a/go.mod
+++ b/go.mod
@@ -21,7 +21,7 @@ require (
github.com/tendermint/tendermint v0.34.14
github.com/tendermint/tm-db v0.6.4
google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa
- google.golang.org/grpc v1.43.0
+ google.golang.org/grpc v1.44.0
google.golang.org/protobuf v1.27.1
gopkg.in/yaml.v2 v2.4.0
)
diff --git a/go.sum b/go.sum
index 08e561e5c45..aeda86c4ec6 100644
--- a/go.sum
+++ b/go.sum
@@ -1425,8 +1425,9 @@ google.golang.org/grpc v1.39.1/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnD
google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34=
google.golang.org/grpc v1.40.1/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34=
google.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU=
-google.golang.org/grpc v1.43.0 h1:Eeu7bZtDZ2DpRCsLhUlcrLnvYaMK1Gz86a+hMVvELmM=
google.golang.org/grpc v1.43.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU=
+google.golang.org/grpc v1.44.0 h1:weqSxi/TMs1SqFRMHCtBgXRs8k3X39QIDEZ0pRcttUg=
+google.golang.org/grpc v1.44.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU=
google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
diff --git a/modules/apps/27-interchain-accounts/controller/ibc_module_test.go b/modules/apps/27-interchain-accounts/controller/ibc_module_test.go
index 605fa9c6415..ca1b0db6b06 100644
--- a/modules/apps/27-interchain-accounts/controller/ibc_module_test.go
+++ b/modules/apps/27-interchain-accounts/controller/ibc_module_test.go
@@ -22,7 +22,7 @@ var (
// https://github.com/cosmos/cosmos-sdk/issues/10225
//
// TestAccAddress defines a resuable bech32 address for testing purposes
- TestAccAddress = icatypes.GenerateAddress(sdk.AccAddress(crypto.AddressHash([]byte(icatypes.ModuleName))), TestPortID)
+ TestAccAddress = icatypes.GenerateAddress(sdk.AccAddress(crypto.AddressHash([]byte(icatypes.ModuleName))), ibctesting.FirstConnectionID, TestPortID)
// TestOwnerAddress defines a reusable bech32 address for testing purposes
TestOwnerAddress = "cosmos17dtl0mjt3t77kpuhg2edqzjpszulwhgzuj9ljs"
@@ -54,8 +54,8 @@ func TestICATestSuite(t *testing.T) {
func (suite *InterchainAccountsTestSuite) SetupTest() {
suite.coordinator = ibctesting.NewCoordinator(suite.T(), 2)
- suite.chainA = suite.coordinator.GetChain(ibctesting.GetChainID(0))
- suite.chainB = suite.coordinator.GetChain(ibctesting.GetChainID(1))
+ suite.chainA = suite.coordinator.GetChain(ibctesting.GetChainID(1))
+ suite.chainB = suite.coordinator.GetChain(ibctesting.GetChainID(2))
}
func NewICAPath(chainA, chainB *ibctesting.TestChain) *ibctesting.Path {
@@ -70,7 +70,7 @@ func NewICAPath(chainA, chainB *ibctesting.TestChain) *ibctesting.Path {
return path
}
-func InitInterchainAccount(endpoint *ibctesting.Endpoint, owner string) error {
+func RegisterInterchainAccount(endpoint *ibctesting.Endpoint, owner string) error {
portID, err := icatypes.NewControllerPortID(owner)
if err != nil {
return err
@@ -78,7 +78,7 @@ func InitInterchainAccount(endpoint *ibctesting.Endpoint, owner string) error {
channelSequence := endpoint.Chain.App.GetIBCKeeper().ChannelKeeper.GetNextChannelSequence(endpoint.Chain.GetContext())
- if err := endpoint.Chain.GetSimApp().ICAControllerKeeper.InitInterchainAccount(endpoint.Chain.GetContext(), endpoint.ConnectionID, owner); err != nil {
+ if err := endpoint.Chain.GetSimApp().ICAControllerKeeper.RegisterInterchainAccount(endpoint.Chain.GetContext(), endpoint.ConnectionID, owner); err != nil {
return err
}
@@ -95,7 +95,7 @@ func InitInterchainAccount(endpoint *ibctesting.Endpoint, owner string) error {
// SetupICAPath invokes the InterchainAccounts entrypoint and subsequent channel handshake handlers
func SetupICAPath(path *ibctesting.Path, owner string) error {
- if err := InitInterchainAccount(path.EndpointA, owner); err != nil {
+ if err := RegisterInterchainAccount(path.EndpointA, owner); err != nil {
return err
}
@@ -216,11 +216,11 @@ func (suite *InterchainAccountsTestSuite) TestChanOpenTry() {
path := NewICAPath(suite.chainA, suite.chainB)
suite.coordinator.SetupConnections(path)
- err := InitInterchainAccount(path.EndpointA, TestOwnerAddress)
+ err := RegisterInterchainAccount(path.EndpointA, TestOwnerAddress)
suite.Require().NoError(err)
// chainB also creates a controller port
- err = InitInterchainAccount(path.EndpointB, TestOwnerAddress)
+ err = RegisterInterchainAccount(path.EndpointB, TestOwnerAddress)
suite.Require().NoError(err)
path.EndpointA.UpdateClient()
@@ -297,7 +297,7 @@ func (suite *InterchainAccountsTestSuite) TestOnChanOpenAck() {
path = NewICAPath(suite.chainA, suite.chainB)
suite.coordinator.SetupConnections(path)
- err := InitInterchainAccount(path.EndpointA, TestOwnerAddress)
+ err := RegisterInterchainAccount(path.EndpointA, TestOwnerAddress)
suite.Require().NoError(err)
err = path.EndpointB.ChanOpenTry()
@@ -334,7 +334,7 @@ func (suite *InterchainAccountsTestSuite) TestChanOpenConfirm() {
path := NewICAPath(suite.chainA, suite.chainB)
suite.coordinator.SetupConnections(path)
- err := InitInterchainAccount(path.EndpointA, TestOwnerAddress)
+ err := RegisterInterchainAccount(path.EndpointA, TestOwnerAddress)
suite.Require().NoError(err)
err = path.EndpointB.ChanOpenTry()
diff --git a/modules/apps/27-interchain-accounts/controller/keeper/account.go b/modules/apps/27-interchain-accounts/controller/keeper/account.go
index c0c61ab75f7..aacbe751c6b 100644
--- a/modules/apps/27-interchain-accounts/controller/keeper/account.go
+++ b/modules/apps/27-interchain-accounts/controller/keeper/account.go
@@ -9,13 +9,13 @@ import (
host "github.com/cosmos/ibc-go/v3/modules/core/24-host"
)
-// InitInterchainAccount is the entry point to registering an interchain account.
+// RegisterInterchainAccount is the entry point to registering an interchain account.
// It generates a new port identifier using the owner address, connection identifier,
// and counterparty connection identifier. It will bind to the port identifier and
// call 04-channel 'ChanOpenInit'. An error is returned if the port identifier is
// already in use. Gaining access to interchain accounts whose channels have closed
// cannot be done with this function. A regular MsgChanOpenInit must be used.
-func (k Keeper) InitInterchainAccount(ctx sdk.Context, connectionID, owner string) error {
+func (k Keeper) RegisterInterchainAccount(ctx sdk.Context, connectionID, owner string) error {
portID, err := icatypes.NewControllerPortID(owner)
if err != nil {
return err
diff --git a/modules/apps/27-interchain-accounts/controller/keeper/account_test.go b/modules/apps/27-interchain-accounts/controller/keeper/account_test.go
index fa0da9558f7..8086726bdc2 100644
--- a/modules/apps/27-interchain-accounts/controller/keeper/account_test.go
+++ b/modules/apps/27-interchain-accounts/controller/keeper/account_test.go
@@ -6,7 +6,7 @@ import (
ibctesting "github.com/cosmos/ibc-go/v3/testing"
)
-func (suite *KeeperTestSuite) TestInitInterchainAccount() {
+func (suite *KeeperTestSuite) TestRegisterInterchainAccount() {
var (
owner string
path *ibctesting.Path
@@ -41,7 +41,7 @@ func (suite *KeeperTestSuite) TestInitInterchainAccount() {
portID, err := icatypes.NewControllerPortID(TestOwnerAddress)
suite.Require().NoError(err)
- suite.chainA.GetSimApp().ICAControllerKeeper.SetActiveChannelID(suite.chainA.GetContext(), portID, path.EndpointA.ChannelID)
+ suite.chainA.GetSimApp().ICAControllerKeeper.SetActiveChannelID(suite.chainA.GetContext(), ibctesting.FirstConnectionID, portID, path.EndpointA.ChannelID)
counterparty := channeltypes.NewCounterparty(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID)
channel := channeltypes.Channel{
@@ -70,7 +70,7 @@ func (suite *KeeperTestSuite) TestInitInterchainAccount() {
tc.malleate() // malleate mutates test data
- err = suite.chainA.GetSimApp().ICAControllerKeeper.InitInterchainAccount(suite.chainA.GetContext(), path.EndpointA.ConnectionID, owner)
+ err = suite.chainA.GetSimApp().ICAControllerKeeper.RegisterInterchainAccount(suite.chainA.GetContext(), path.EndpointA.ConnectionID, owner)
if tc.expPass {
suite.Require().NoError(err)
diff --git a/modules/apps/27-interchain-accounts/controller/keeper/genesis.go b/modules/apps/27-interchain-accounts/controller/keeper/genesis.go
index 8b0d8b896ee..eab7687236e 100644
--- a/modules/apps/27-interchain-accounts/controller/keeper/genesis.go
+++ b/modules/apps/27-interchain-accounts/controller/keeper/genesis.go
@@ -21,11 +21,11 @@ func InitGenesis(ctx sdk.Context, keeper Keeper, state icatypes.ControllerGenesi
}
for _, ch := range state.ActiveChannels {
- keeper.SetActiveChannelID(ctx, ch.PortId, ch.ChannelId)
+ keeper.SetActiveChannelID(ctx, ch.ConnectionId, ch.PortId, ch.ChannelId)
}
for _, acc := range state.InterchainAccounts {
- keeper.SetInterchainAccountAddress(ctx, acc.PortId, acc.AccountAddress)
+ keeper.SetInterchainAccountAddress(ctx, acc.ConnectionId, acc.PortId, acc.AccountAddress)
}
keeper.SetParams(ctx, state.Params)
diff --git a/modules/apps/27-interchain-accounts/controller/keeper/genesis_test.go b/modules/apps/27-interchain-accounts/controller/keeper/genesis_test.go
index fca58db2e44..7a41608d38f 100644
--- a/modules/apps/27-interchain-accounts/controller/keeper/genesis_test.go
+++ b/modules/apps/27-interchain-accounts/controller/keeper/genesis_test.go
@@ -13,12 +13,14 @@ func (suite *KeeperTestSuite) TestInitGenesis() {
genesisState := icatypes.ControllerGenesisState{
ActiveChannels: []icatypes.ActiveChannel{
{
- PortId: TestPortID,
- ChannelId: ibctesting.FirstChannelID,
+ ConnectionId: ibctesting.FirstConnectionID,
+ PortId: TestPortID,
+ ChannelId: ibctesting.FirstChannelID,
},
},
InterchainAccounts: []icatypes.RegisteredInterchainAccount{
{
+ ConnectionId: ibctesting.FirstConnectionID,
PortId: TestPortID,
AccountAddress: TestAccAddress.String(),
},
@@ -28,11 +30,11 @@ func (suite *KeeperTestSuite) TestInitGenesis() {
keeper.InitGenesis(suite.chainA.GetContext(), suite.chainA.GetSimApp().ICAControllerKeeper, genesisState)
- channelID, found := suite.chainA.GetSimApp().ICAControllerKeeper.GetActiveChannelID(suite.chainA.GetContext(), TestPortID)
+ channelID, found := suite.chainA.GetSimApp().ICAControllerKeeper.GetActiveChannelID(suite.chainA.GetContext(), ibctesting.FirstConnectionID, TestPortID)
suite.Require().True(found)
suite.Require().Equal(ibctesting.FirstChannelID, channelID)
- accountAdrr, found := suite.chainA.GetSimApp().ICAControllerKeeper.GetInterchainAccountAddress(suite.chainA.GetContext(), TestPortID)
+ accountAdrr, found := suite.chainA.GetSimApp().ICAControllerKeeper.GetInterchainAccountAddress(suite.chainA.GetContext(), ibctesting.FirstConnectionID, TestPortID)
suite.Require().True(found)
suite.Require().Equal(TestAccAddress.String(), accountAdrr)
diff --git a/modules/apps/27-interchain-accounts/controller/keeper/handshake.go b/modules/apps/27-interchain-accounts/controller/keeper/handshake.go
index fb38401a0b2..5b1fc619f9e 100644
--- a/modules/apps/27-interchain-accounts/controller/keeper/handshake.go
+++ b/modules/apps/27-interchain-accounts/controller/keeper/handshake.go
@@ -9,7 +9,6 @@ import (
icatypes "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts/types"
channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types"
- porttypes "github.com/cosmos/ibc-go/v3/modules/core/05-port/types"
)
// OnChanOpenInit performs basic validation of channel initialization.
@@ -50,9 +49,9 @@ func (k Keeper) OnChanOpenInit(
return err
}
- activeChannelID, found := k.GetOpenActiveChannel(ctx, portID)
+ activeChannelID, found := k.GetOpenActiveChannel(ctx, connectionHops[0], portID)
if found {
- return sdkerrors.Wrapf(porttypes.ErrInvalidPort, "existing active channel %s for portID %s", activeChannelID, portID)
+ return sdkerrors.Wrapf(icatypes.ErrActiveChannelAlreadySet, "existing active channel %s for portID %s", activeChannelID, portID)
}
return nil
@@ -79,6 +78,10 @@ func (k Keeper) OnChanOpenAck(
return sdkerrors.Wrapf(icatypes.ErrUnknownDataType, "cannot unmarshal ICS-27 interchain accounts metadata")
}
+ if activeChannelID, found := k.GetOpenActiveChannel(ctx, metadata.ControllerConnectionId, portID); found {
+ return sdkerrors.Wrapf(icatypes.ErrActiveChannelAlreadySet, "existing active channel %s for portID %s", activeChannelID, portID)
+ }
+
channel, found := k.channelKeeper.GetChannel(ctx, portID, channelID)
if !found {
return sdkerrors.Wrapf(channeltypes.ErrChannelNotFound, "failed to retrieve channel %s on port %s", channelID, portID)
@@ -92,8 +95,8 @@ func (k Keeper) OnChanOpenAck(
return sdkerrors.Wrap(icatypes.ErrInvalidAccountAddress, "interchain account address cannot be empty")
}
- k.SetActiveChannelID(ctx, portID, channelID)
- k.SetInterchainAccountAddress(ctx, portID, metadata.Address)
+ k.SetActiveChannelID(ctx, metadata.ControllerConnectionId, portID, channelID)
+ k.SetInterchainAccountAddress(ctx, metadata.ControllerConnectionId, portID, metadata.Address)
return nil
}
diff --git a/modules/apps/27-interchain-accounts/controller/keeper/handshake_test.go b/modules/apps/27-interchain-accounts/controller/keeper/handshake_test.go
index 1b45d6166dc..b08a6913aaf 100644
--- a/modules/apps/27-interchain-accounts/controller/keeper/handshake_test.go
+++ b/modules/apps/27-interchain-accounts/controller/keeper/handshake_test.go
@@ -110,7 +110,7 @@ func (suite *KeeperTestSuite) TestOnChanOpenInit() {
{
"channel is already active",
func() {
- suite.chainA.GetSimApp().ICAControllerKeeper.SetActiveChannelID(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID)
+ suite.chainA.GetSimApp().ICAControllerKeeper.SetActiveChannelID(suite.chainA.GetContext(), ibctesting.FirstConnectionID, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID)
counterparty := channeltypes.NewCounterparty(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID)
channel := channeltypes.Channel{
@@ -247,6 +247,17 @@ func (suite *KeeperTestSuite) TestOnChanOpenAck() {
},
false,
},
+ {
+ "active channel already set",
+ func() {
+ // create a new channel and set it in state
+ ch := channeltypes.NewChannel(channeltypes.OPEN, channeltypes.ORDERED, channeltypes.NewCounterparty(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID), []string{path.EndpointB.ConnectionID}, ibctesting.DefaultChannelVersion)
+ suite.chainA.GetSimApp().GetIBCKeeper().ChannelKeeper.SetChannel(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, ch)
+
+ // set the active channelID in state
+ suite.chainA.GetSimApp().ICAControllerKeeper.SetActiveChannelID(suite.chainA.GetContext(), ibctesting.FirstConnectionID, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID)
+ }, false,
+ },
}
for _, tc := range testCases {
@@ -258,7 +269,7 @@ func (suite *KeeperTestSuite) TestOnChanOpenAck() {
path = NewICAPath(suite.chainA, suite.chainB)
suite.coordinator.SetupConnections(path)
- err := InitInterchainAccount(path.EndpointA, TestOwnerAddress)
+ err := RegisterInterchainAccount(path.EndpointA, TestOwnerAddress)
suite.Require().NoError(err)
err = path.EndpointB.ChanOpenTry()
@@ -279,12 +290,12 @@ func (suite *KeeperTestSuite) TestOnChanOpenAck() {
if tc.expPass {
suite.Require().NoError(err)
- activeChannelID, found := suite.chainA.GetSimApp().ICAControllerKeeper.GetActiveChannelID(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID)
+ activeChannelID, found := suite.chainA.GetSimApp().ICAControllerKeeper.GetActiveChannelID(suite.chainA.GetContext(), ibctesting.FirstConnectionID, path.EndpointA.ChannelConfig.PortID)
suite.Require().True(found)
suite.Require().Equal(path.EndpointA.ChannelID, activeChannelID)
- interchainAccAddress, found := suite.chainA.GetSimApp().ICAControllerKeeper.GetInterchainAccountAddress(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID)
+ interchainAccAddress, found := suite.chainA.GetSimApp().ICAControllerKeeper.GetInterchainAccountAddress(suite.chainA.GetContext(), ibctesting.FirstConnectionID, path.EndpointA.ChannelConfig.PortID)
suite.Require().True(found)
suite.Require().Equal(metadata.Address, interchainAccAddress)
@@ -326,7 +337,7 @@ func (suite *KeeperTestSuite) TestOnChanCloseConfirm() {
err = suite.chainB.GetSimApp().ICAControllerKeeper.OnChanCloseConfirm(suite.chainB.GetContext(),
path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID)
- activeChannelID, found := suite.chainB.GetSimApp().ICAControllerKeeper.GetActiveChannelID(suite.chainB.GetContext(), path.EndpointB.ChannelConfig.PortID)
+ activeChannelID, found := suite.chainB.GetSimApp().ICAControllerKeeper.GetActiveChannelID(suite.chainB.GetContext(), ibctesting.FirstConnectionID, path.EndpointB.ChannelConfig.PortID)
if tc.expPass {
suite.Require().NoError(err)
diff --git a/modules/apps/27-interchain-accounts/controller/keeper/keeper.go b/modules/apps/27-interchain-accounts/controller/keeper/keeper.go
index afc1a2eda5d..fc643cea30d 100644
--- a/modules/apps/27-interchain-accounts/controller/keeper/keeper.go
+++ b/modules/apps/27-interchain-accounts/controller/keeper/keeper.go
@@ -102,10 +102,10 @@ func (k Keeper) ClaimCapability(ctx sdk.Context, cap *capabilitytypes.Capability
return k.scopedKeeper.ClaimCapability(ctx, cap, name)
}
-// GetActiveChannelID retrieves the active channelID from the store, keyed by the provided portID
-func (k Keeper) GetActiveChannelID(ctx sdk.Context, portID string) (string, bool) {
+// 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)
- key := icatypes.KeyActiveChannel(portID)
+ key := icatypes.KeyActiveChannel(connectionID, portID)
if !store.Has(key) {
return "", false
@@ -114,9 +114,9 @@ func (k Keeper) GetActiveChannelID(ctx sdk.Context, portID string) (string, bool
return string(store.Get(key)), true
}
-// GetOpenActiveChannel retrieves the active channelID from the store, keyed by the provided portID & checks if the channel in question is in state OPEN
-func (k Keeper) GetOpenActiveChannel(ctx sdk.Context, portID string) (string, bool) {
- channelID, found := k.GetActiveChannelID(ctx, portID)
+// GetOpenActiveChannel retrieves the active channelID from the store, keyed by the provided connectionID and portID & checks if the channel in question is in state OPEN
+func (k Keeper) GetOpenActiveChannel(ctx sdk.Context, connectionID, portID string) (string, bool) {
+ channelID, found := k.GetActiveChannelID(ctx, connectionID, portID)
if !found {
return "", false
}
@@ -130,7 +130,7 @@ func (k Keeper) GetOpenActiveChannel(ctx sdk.Context, portID string) (string, bo
return "", false
}
-// GetAllActiveChannels returns a list of all active interchain accounts controller channels and their associated port identifiers
+// GetAllActiveChannels returns a list of all active interchain accounts controller channels and their associated connection and port identifiers
func (k Keeper) GetAllActiveChannels(ctx sdk.Context) []icatypes.ActiveChannel {
store := ctx.KVStore(k.storeKey)
iterator := sdk.KVStorePrefixIterator(store, []byte(icatypes.ActiveChannelKeyPrefix))
@@ -141,8 +141,9 @@ func (k Keeper) GetAllActiveChannels(ctx sdk.Context) []icatypes.ActiveChannel {
keySplit := strings.Split(string(iterator.Key()), "/")
ch := icatypes.ActiveChannel{
- PortId: keySplit[1],
- ChannelId: string(iterator.Value()),
+ ConnectionId: keySplit[1],
+ PortId: keySplit[2],
+ ChannelId: string(iterator.Value()),
}
activeChannels = append(activeChannels, ch)
@@ -151,22 +152,22 @@ func (k Keeper) GetAllActiveChannels(ctx sdk.Context) []icatypes.ActiveChannel {
return activeChannels
}
-// SetActiveChannelID stores the active channelID, keyed by the provided portID
-func (k Keeper) SetActiveChannelID(ctx sdk.Context, portID, channelID string) {
+// SetActiveChannelID stores the active channelID, keyed by the provided connectionID and portID
+func (k Keeper) SetActiveChannelID(ctx sdk.Context, connectionID, portID, channelID string) {
store := ctx.KVStore(k.storeKey)
- store.Set(icatypes.KeyActiveChannel(portID), []byte(channelID))
+ store.Set(icatypes.KeyActiveChannel(connectionID, portID), []byte(channelID))
}
-// IsActiveChannel returns true if there exists an active channel for the provided portID, otherwise false
-func (k Keeper) IsActiveChannel(ctx sdk.Context, portID string) bool {
- _, ok := k.GetActiveChannelID(ctx, portID)
+// IsActiveChannel returns true if there exists an active channel for the provided connectionID and portID, otherwise false
+func (k Keeper) IsActiveChannel(ctx sdk.Context, connectionID, portID string) bool {
+ _, ok := k.GetActiveChannelID(ctx, connectionID, portID)
return ok
}
-// GetInterchainAccountAddress retrieves the InterchainAccount address from the store keyed by the provided portID
-func (k Keeper) GetInterchainAccountAddress(ctx sdk.Context, portID string) (string, bool) {
+// GetInterchainAccountAddress retrieves the InterchainAccount address from the store associated with the provided connectionID and portID
+func (k Keeper) GetInterchainAccountAddress(ctx sdk.Context, connectionID, portID string) (string, bool) {
store := ctx.KVStore(k.storeKey)
- key := icatypes.KeyOwnerAccount(portID)
+ key := icatypes.KeyOwnerAccount(connectionID, portID)
if !store.Has(key) {
return "", false
@@ -175,7 +176,7 @@ 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
+// GetAllInterchainAccounts returns a list of all registered interchain account addresses and their associated connection and controller port identifiers
func (k Keeper) GetAllInterchainAccounts(ctx sdk.Context) []icatypes.RegisteredInterchainAccount {
store := ctx.KVStore(k.storeKey)
iterator := sdk.KVStorePrefixIterator(store, []byte(icatypes.OwnerKeyPrefix))
@@ -185,7 +186,8 @@ func (k Keeper) GetAllInterchainAccounts(ctx sdk.Context) []icatypes.RegisteredI
keySplit := strings.Split(string(iterator.Key()), "/")
acc := icatypes.RegisteredInterchainAccount{
- PortId: keySplit[1],
+ ConnectionId: keySplit[1],
+ PortId: keySplit[2],
AccountAddress: string(iterator.Value()),
}
@@ -195,8 +197,8 @@ func (k Keeper) GetAllInterchainAccounts(ctx sdk.Context) []icatypes.RegisteredI
return interchainAccounts
}
-// SetInterchainAccountAddress stores the InterchainAccount address, keyed by the associated portID
-func (k Keeper) SetInterchainAccountAddress(ctx sdk.Context, portID string, address string) {
+// SetInterchainAccountAddress stores the InterchainAccount address, keyed by the associated connectionID and portID
+func (k Keeper) SetInterchainAccountAddress(ctx sdk.Context, connectionID, portID, address string) {
store := ctx.KVStore(k.storeKey)
- store.Set(icatypes.KeyOwnerAccount(portID), []byte(address))
+ store.Set(icatypes.KeyOwnerAccount(connectionID, portID), []byte(address))
}
diff --git a/modules/apps/27-interchain-accounts/controller/keeper/keeper_test.go b/modules/apps/27-interchain-accounts/controller/keeper/keeper_test.go
index 75cec2c45d9..eff4ce5fa96 100644
--- a/modules/apps/27-interchain-accounts/controller/keeper/keeper_test.go
+++ b/modules/apps/27-interchain-accounts/controller/keeper/keeper_test.go
@@ -4,7 +4,6 @@ import (
"testing"
sdk "github.com/cosmos/cosmos-sdk/types"
- authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
"github.com/stretchr/testify/suite"
"github.com/tendermint/tendermint/crypto"
@@ -18,7 +17,7 @@ var (
// https://github.com/cosmos/cosmos-sdk/issues/10225
//
// TestAccAddress defines a resuable bech32 address for testing purposes
- TestAccAddress = icatypes.GenerateAddress(sdk.AccAddress(crypto.AddressHash([]byte(icatypes.ModuleName))), TestPortID)
+ TestAccAddress = icatypes.GenerateAddress(sdk.AccAddress(crypto.AddressHash([]byte(icatypes.ModuleName))), ibctesting.FirstConnectionID, TestPortID)
// TestOwnerAddress defines a reusable bech32 address for testing purposes
TestOwnerAddress = "cosmos17dtl0mjt3t77kpuhg2edqzjpszulwhgzuj9ljs"
@@ -47,9 +46,9 @@ type KeeperTestSuite struct {
func (suite *KeeperTestSuite) SetupTest() {
suite.coordinator = ibctesting.NewCoordinator(suite.T(), 3)
- suite.chainA = suite.coordinator.GetChain(ibctesting.GetChainID(0))
- suite.chainB = suite.coordinator.GetChain(ibctesting.GetChainID(1))
- suite.chainC = suite.coordinator.GetChain(ibctesting.GetChainID(2))
+ suite.chainA = suite.coordinator.GetChain(ibctesting.GetChainID(1))
+ suite.chainB = suite.coordinator.GetChain(ibctesting.GetChainID(2))
+ suite.chainC = suite.coordinator.GetChain(ibctesting.GetChainID(3))
}
func NewICAPath(chainA, chainB *ibctesting.TestChain) *ibctesting.Path {
@@ -66,7 +65,7 @@ func NewICAPath(chainA, chainB *ibctesting.TestChain) *ibctesting.Path {
// SetupICAPath invokes the InterchainAccounts entrypoint and subsequent channel handshake handlers
func SetupICAPath(path *ibctesting.Path, owner string) error {
- if err := InitInterchainAccount(path.EndpointA, owner); err != nil {
+ if err := RegisterInterchainAccount(path.EndpointA, owner); err != nil {
return err
}
@@ -85,8 +84,8 @@ func SetupICAPath(path *ibctesting.Path, owner string) error {
return nil
}
-// InitInterchainAccount is a helper function for starting the channel handshake
-func InitInterchainAccount(endpoint *ibctesting.Endpoint, owner string) error {
+// RegisterInterchainAccount is a helper function for starting the channel handshake
+func RegisterInterchainAccount(endpoint *ibctesting.Endpoint, owner string) error {
portID, err := icatypes.NewControllerPortID(owner)
if err != nil {
return err
@@ -94,7 +93,7 @@ func InitInterchainAccount(endpoint *ibctesting.Endpoint, owner string) error {
channelSequence := endpoint.Chain.App.GetIBCKeeper().ChannelKeeper.GetNextChannelSequence(endpoint.Chain.GetContext())
- if err := endpoint.Chain.GetSimApp().ICAControllerKeeper.InitInterchainAccount(endpoint.Chain.GetContext(), endpoint.ConnectionID, owner); err != nil {
+ if err := endpoint.Chain.GetSimApp().ICAControllerKeeper.RegisterInterchainAccount(endpoint.Chain.GetContext(), endpoint.ConnectionID, owner); err != nil {
return err
}
@@ -152,13 +151,13 @@ func (suite *KeeperTestSuite) TestGetInterchainAccountAddress() {
suite.Require().NoError(err)
counterpartyPortID := path.EndpointA.ChannelConfig.PortID
- expectedAddr := authtypes.NewBaseAccountWithAddress(icatypes.GenerateAddress(suite.chainA.GetSimApp().AccountKeeper.GetModuleAddress(icatypes.ModuleName), counterpartyPortID)).GetAddress()
+ expectedAddr := icatypes.GenerateAddress(suite.chainA.GetSimApp().AccountKeeper.GetModuleAddress(icatypes.ModuleName), ibctesting.FirstConnectionID, counterpartyPortID)
- retrievedAddr, found := suite.chainA.GetSimApp().ICAControllerKeeper.GetInterchainAccountAddress(suite.chainA.GetContext(), counterpartyPortID)
+ retrievedAddr, found := suite.chainA.GetSimApp().ICAControllerKeeper.GetInterchainAccountAddress(suite.chainA.GetContext(), ibctesting.FirstConnectionID, counterpartyPortID)
suite.Require().True(found)
suite.Require().Equal(expectedAddr.String(), retrievedAddr)
- retrievedAddr, found = suite.chainA.GetSimApp().ICAControllerKeeper.GetInterchainAccountAddress(suite.chainA.GetContext(), "invalid port")
+ retrievedAddr, found = suite.chainA.GetSimApp().ICAControllerKeeper.GetInterchainAccountAddress(suite.chainA.GetContext(), "invalid conn", "invalid port")
suite.Require().False(found)
suite.Require().Empty(retrievedAddr)
}
@@ -177,16 +176,18 @@ func (suite *KeeperTestSuite) TestGetAllActiveChannels() {
err := SetupICAPath(path, TestOwnerAddress)
suite.Require().NoError(err)
- suite.chainA.GetSimApp().ICAControllerKeeper.SetActiveChannelID(suite.chainA.GetContext(), expectedPortID, expectedChannelID)
+ suite.chainA.GetSimApp().ICAControllerKeeper.SetActiveChannelID(suite.chainA.GetContext(), ibctesting.FirstConnectionID, expectedPortID, expectedChannelID)
expectedChannels := []icatypes.ActiveChannel{
{
- PortId: TestPortID,
- ChannelId: path.EndpointA.ChannelID,
+ ConnectionId: ibctesting.FirstConnectionID,
+ PortId: TestPortID,
+ ChannelId: path.EndpointA.ChannelID,
},
{
- PortId: expectedPortID,
- ChannelId: expectedChannelID,
+ ConnectionId: ibctesting.FirstConnectionID,
+ PortId: expectedPortID,
+ ChannelId: expectedChannelID,
},
}
@@ -209,14 +210,16 @@ func (suite *KeeperTestSuite) TestGetAllInterchainAccounts() {
err := SetupICAPath(path, TestOwnerAddress)
suite.Require().NoError(err)
- suite.chainA.GetSimApp().ICAControllerKeeper.SetInterchainAccountAddress(suite.chainA.GetContext(), expectedPortID, expectedAccAddr)
+ suite.chainA.GetSimApp().ICAControllerKeeper.SetInterchainAccountAddress(suite.chainA.GetContext(), ibctesting.FirstConnectionID, expectedPortID, expectedAccAddr)
expectedAccounts := []icatypes.RegisteredInterchainAccount{
{
+ ConnectionId: ibctesting.FirstConnectionID,
PortId: TestPortID,
AccountAddress: TestAccAddress.String(),
},
{
+ ConnectionId: ibctesting.FirstConnectionID,
PortId: expectedPortID,
AccountAddress: expectedAccAddr,
},
@@ -238,7 +241,7 @@ func (suite *KeeperTestSuite) TestIsActiveChannel() {
suite.Require().NoError(err)
portID := path.EndpointA.ChannelConfig.PortID
- isActive := suite.chainA.GetSimApp().ICAControllerKeeper.IsActiveChannel(suite.chainA.GetContext(), portID)
+ isActive := suite.chainA.GetSimApp().ICAControllerKeeper.IsActiveChannel(suite.chainA.GetContext(), ibctesting.FirstConnectionID, portID)
suite.Require().Equal(isActive, true)
}
@@ -248,9 +251,9 @@ func (suite *KeeperTestSuite) TestSetInterchainAccountAddress() {
expectedPortID string = "test-port"
)
- suite.chainA.GetSimApp().ICAControllerKeeper.SetInterchainAccountAddress(suite.chainA.GetContext(), expectedPortID, expectedAccAddr)
+ suite.chainA.GetSimApp().ICAControllerKeeper.SetInterchainAccountAddress(suite.chainA.GetContext(), ibctesting.FirstConnectionID, expectedPortID, expectedAccAddr)
- retrievedAddr, found := suite.chainA.GetSimApp().ICAControllerKeeper.GetInterchainAccountAddress(suite.chainA.GetContext(), expectedPortID)
+ retrievedAddr, found := suite.chainA.GetSimApp().ICAControllerKeeper.GetInterchainAccountAddress(suite.chainA.GetContext(), ibctesting.FirstConnectionID, expectedPortID)
suite.Require().True(found)
suite.Require().Equal(expectedAccAddr, retrievedAddr)
}
diff --git a/modules/apps/27-interchain-accounts/controller/keeper/relay.go b/modules/apps/27-interchain-accounts/controller/keeper/relay.go
index e49f2e83c0e..4375b3e3ee0 100644
--- a/modules/apps/27-interchain-accounts/controller/keeper/relay.go
+++ b/modules/apps/27-interchain-accounts/controller/keeper/relay.go
@@ -10,16 +10,15 @@ import (
channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types"
)
-// TrySendTx takes pre-built packet data containing messages to be executed on the host chain from an authentication module and attempts to send the packet.
+// SendTx takes pre-built packet data containing messages to be executed on the host chain from an authentication module and attempts to send the packet.
// The packet sequence for the outgoing packet is returned as a result.
// If the base application has the capability to send on the provided portID. An appropriate
// absolute timeoutTimestamp must be provided. If the packet is timed out, the channel will be closed.
// In the case of channel closure, a new channel may be reopened to reconnect to the host chain.
-func (k Keeper) TrySendTx(ctx sdk.Context, chanCap *capabilitytypes.Capability, portID string, icaPacketData icatypes.InterchainAccountPacketData, timeoutTimestamp uint64) (uint64, error) {
- // Check for the active channel
- activeChannelID, found := k.GetActiveChannelID(ctx, portID)
+func (k Keeper) SendTx(ctx sdk.Context, chanCap *capabilitytypes.Capability, connectionID, portID string, icaPacketData icatypes.InterchainAccountPacketData, timeoutTimestamp uint64) (uint64, error) {
+ activeChannelID, found := k.GetActiveChannelID(ctx, connectionID, portID)
if !found {
- return 0, sdkerrors.Wrapf(icatypes.ErrActiveChannelNotFound, "failed to retrieve active channel for port %s", portID)
+ return 0, sdkerrors.Wrapf(icatypes.ErrActiveChannelNotFound, "failed to retrieve active channel on connection %s for port %s", connectionID, portID)
}
sourceChannelEnd, found := k.channelKeeper.GetChannel(ctx, portID, activeChannelID)
diff --git a/modules/apps/27-interchain-accounts/controller/keeper/relay_test.go b/modules/apps/27-interchain-accounts/controller/keeper/relay_test.go
index bc25210b08a..e687e0a751e 100644
--- a/modules/apps/27-interchain-accounts/controller/keeper/relay_test.go
+++ b/modules/apps/27-interchain-accounts/controller/keeper/relay_test.go
@@ -12,7 +12,7 @@ import (
ibctesting "github.com/cosmos/ibc-go/v3/testing"
)
-func (suite *KeeperTestSuite) TestTrySendTx() {
+func (suite *KeeperTestSuite) TestSendTx() {
var (
path *ibctesting.Path
packetData icatypes.InterchainAccountPacketData
@@ -28,7 +28,7 @@ func (suite *KeeperTestSuite) TestTrySendTx() {
{
"success",
func() {
- interchainAccountAddr, found := suite.chainA.GetSimApp().ICAControllerKeeper.GetInterchainAccountAddress(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID)
+ interchainAccountAddr, found := suite.chainA.GetSimApp().ICAControllerKeeper.GetInterchainAccountAddress(suite.chainA.GetContext(), ibctesting.FirstConnectionID, path.EndpointA.ChannelConfig.PortID)
suite.Require().True(found)
msg := &banktypes.MsgSend{
@@ -50,7 +50,7 @@ func (suite *KeeperTestSuite) TestTrySendTx() {
{
"success with multiple sdk.Msg",
func() {
- interchainAccountAddr, found := suite.chainA.GetSimApp().ICAControllerKeeper.GetInterchainAccountAddress(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID)
+ interchainAccountAddr, found := suite.chainA.GetSimApp().ICAControllerKeeper.GetInterchainAccountAddress(suite.chainA.GetContext(), ibctesting.FirstConnectionID, path.EndpointA.ChannelConfig.PortID)
suite.Require().True(found)
msgsBankSend := []sdk.Msg{
@@ -96,7 +96,7 @@ func (suite *KeeperTestSuite) TestTrySendTx() {
{
"channel does not exist",
func() {
- suite.chainA.GetSimApp().ICAControllerKeeper.SetActiveChannelID(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, "channel-100")
+ suite.chainA.GetSimApp().ICAControllerKeeper.SetActiveChannelID(suite.chainA.GetContext(), ibctesting.FirstConnectionID, path.EndpointA.ChannelConfig.PortID, "channel-100")
},
false,
},
@@ -118,7 +118,7 @@ func (suite *KeeperTestSuite) TestTrySendTx() {
{
"timeout timestamp is not in the future",
func() {
- interchainAccountAddr, found := suite.chainA.GetSimApp().ICAControllerKeeper.GetInterchainAccountAddress(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID)
+ interchainAccountAddr, found := suite.chainA.GetSimApp().ICAControllerKeeper.GetInterchainAccountAddress(suite.chainA.GetContext(), ibctesting.FirstConnectionID, path.EndpointA.ChannelConfig.PortID)
suite.Require().True(found)
msg := &banktypes.MsgSend{
@@ -160,7 +160,7 @@ func (suite *KeeperTestSuite) TestTrySendTx() {
tc.malleate() // malleate mutates test data
- _, err = suite.chainA.GetSimApp().ICAControllerKeeper.TrySendTx(suite.chainA.GetContext(), chanCap, path.EndpointA.ChannelConfig.PortID, packetData, timeoutTimestamp)
+ _, err = suite.chainA.GetSimApp().ICAControllerKeeper.SendTx(suite.chainA.GetContext(), chanCap, ibctesting.FirstConnectionID, path.EndpointA.ChannelConfig.PortID, packetData, timeoutTimestamp)
if tc.expPass {
suite.Require().NoError(err)
diff --git a/modules/apps/27-interchain-accounts/host/ibc_module.go b/modules/apps/27-interchain-accounts/host/ibc_module.go
index 15606eb9e74..cec21d258c3 100644
--- a/modules/apps/27-interchain-accounts/host/ibc_module.go
+++ b/modules/apps/27-interchain-accounts/host/ibc_module.go
@@ -111,7 +111,7 @@ func (im IBCModule) OnRecvPacket(
ack := channeltypes.NewResultAcknowledgement([]byte{byte(1)})
if err := im.keeper.OnRecvPacket(ctx, packet); err != nil {
- ack = channeltypes.NewErrorAcknowledgement(icatypes.AcknowledgementError)
+ ack = types.NewErrorAcknowledgement(err)
// Emit an event including the error msg
keeper.EmitWriteErrorAcknowledgementEvent(ctx, packet, err)
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 dce1094e430..ddf90c6d46c 100644
--- a/modules/apps/27-interchain-accounts/host/ibc_module_test.go
+++ b/modules/apps/27-interchain-accounts/host/ibc_module_test.go
@@ -24,7 +24,7 @@ var (
// https://github.com/cosmos/cosmos-sdk/issues/10225
//
// TestAccAddress defines a resuable bech32 address for testing purposes
- TestAccAddress = icatypes.GenerateAddress(sdk.AccAddress(crypto.AddressHash([]byte(icatypes.ModuleName))), TestPortID)
+ TestAccAddress = icatypes.GenerateAddress(sdk.AccAddress(crypto.AddressHash([]byte(icatypes.ModuleName))), ibctesting.FirstConnectionID, TestPortID)
// TestOwnerAddress defines a reusable bech32 address for testing purposes
TestOwnerAddress = "cosmos17dtl0mjt3t77kpuhg2edqzjpszulwhgzuj9ljs"
@@ -56,8 +56,8 @@ func TestICATestSuite(t *testing.T) {
func (suite *InterchainAccountsTestSuite) SetupTest() {
suite.coordinator = ibctesting.NewCoordinator(suite.T(), 2)
- suite.chainA = suite.coordinator.GetChain(ibctesting.GetChainID(0))
- suite.chainB = suite.coordinator.GetChain(ibctesting.GetChainID(1))
+ suite.chainA = suite.coordinator.GetChain(ibctesting.GetChainID(1))
+ suite.chainB = suite.coordinator.GetChain(ibctesting.GetChainID(2))
}
func NewICAPath(chainA, chainB *ibctesting.TestChain) *ibctesting.Path {
@@ -72,7 +72,7 @@ func NewICAPath(chainA, chainB *ibctesting.TestChain) *ibctesting.Path {
return path
}
-func InitInterchainAccount(endpoint *ibctesting.Endpoint, owner string) error {
+func RegisterInterchainAccount(endpoint *ibctesting.Endpoint, owner string) error {
portID, err := icatypes.NewControllerPortID(owner)
if err != nil {
return err
@@ -80,7 +80,7 @@ func InitInterchainAccount(endpoint *ibctesting.Endpoint, owner string) error {
channelSequence := endpoint.Chain.App.GetIBCKeeper().ChannelKeeper.GetNextChannelSequence(endpoint.Chain.GetContext())
- if err := endpoint.Chain.GetSimApp().ICAControllerKeeper.InitInterchainAccount(endpoint.Chain.GetContext(), endpoint.ConnectionID, owner); err != nil {
+ if err := endpoint.Chain.GetSimApp().ICAControllerKeeper.RegisterInterchainAccount(endpoint.Chain.GetContext(), endpoint.ConnectionID, owner); err != nil {
return err
}
@@ -97,7 +97,7 @@ func InitInterchainAccount(endpoint *ibctesting.Endpoint, owner string) error {
// SetupICAPath invokes the InterchainAccounts entrypoint and subsequent channel handshake handlers
func SetupICAPath(path *ibctesting.Path, owner string) error {
- if err := InitInterchainAccount(path.EndpointA, owner); err != nil {
+ if err := RegisterInterchainAccount(path.EndpointA, owner); err != nil {
return err
}
@@ -179,7 +179,7 @@ func (suite *InterchainAccountsTestSuite) TestOnChanOpenTry() {
path = NewICAPath(suite.chainA, suite.chainB)
suite.coordinator.SetupConnections(path)
- err := InitInterchainAccount(path.EndpointA, TestOwnerAddress)
+ err := RegisterInterchainAccount(path.EndpointA, TestOwnerAddress)
suite.Require().NoError(err)
path.EndpointB.ChannelID = ibctesting.FirstChannelID
@@ -230,7 +230,7 @@ func (suite *InterchainAccountsTestSuite) TestChanOpenAck() {
path := NewICAPath(suite.chainA, suite.chainB)
suite.coordinator.SetupConnections(path)
- err := InitInterchainAccount(path.EndpointA, TestOwnerAddress)
+ err := RegisterInterchainAccount(path.EndpointA, TestOwnerAddress)
suite.Require().NoError(err)
err = path.EndpointB.ChanOpenTry()
@@ -294,7 +294,7 @@ func (suite *InterchainAccountsTestSuite) TestOnChanOpenConfirm() {
path := NewICAPath(suite.chainA, suite.chainB)
suite.coordinator.SetupConnections(path)
- err := InitInterchainAccount(path.EndpointA, TestOwnerAddress)
+ err := RegisterInterchainAccount(path.EndpointA, TestOwnerAddress)
suite.Require().NoError(err)
err = path.EndpointB.ChanOpenTry()
@@ -437,7 +437,7 @@ func (suite *InterchainAccountsTestSuite) TestOnRecvPacket() {
// send 100stake to interchain account wallet
amount, _ := sdk.ParseCoinsNormalized("100stake")
- interchainAccountAddr, _ := suite.chainB.GetSimApp().ICAHostKeeper.GetInterchainAccountAddress(suite.chainB.GetContext(), path.EndpointA.ChannelConfig.PortID)
+ interchainAccountAddr, _ := suite.chainB.GetSimApp().ICAHostKeeper.GetInterchainAccountAddress(suite.chainB.GetContext(), ibctesting.FirstConnectionID, path.EndpointA.ChannelConfig.PortID)
bankMsg := &banktypes.MsgSend{FromAddress: suite.chainB.SenderAccount.GetAddress().String(), ToAddress: interchainAccountAddr, Amount: amount}
_, err = suite.chainB.SendMsgs(bankMsg)
@@ -592,7 +592,7 @@ func (suite *InterchainAccountsTestSuite) TestOnTimeoutPacket() {
}
func (suite *InterchainAccountsTestSuite) fundICAWallet(ctx sdk.Context, portID string, amount sdk.Coins) {
- interchainAccountAddr, found := suite.chainB.GetSimApp().ICAHostKeeper.GetInterchainAccountAddress(ctx, portID)
+ interchainAccountAddr, found := suite.chainB.GetSimApp().ICAHostKeeper.GetInterchainAccountAddress(ctx, ibctesting.FirstConnectionID, portID)
suite.Require().True(found)
msgBankSend := &banktypes.MsgSend{
@@ -617,7 +617,7 @@ func (suite *InterchainAccountsTestSuite) TestControlAccountAfterChannelClose()
// check that the account is working as expected
suite.fundICAWallet(suite.chainB.GetContext(), path.EndpointA.ChannelConfig.PortID, sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(10000))))
- interchainAccountAddr, found := suite.chainB.GetSimApp().ICAHostKeeper.GetInterchainAccountAddress(suite.chainB.GetContext(), path.EndpointA.ChannelConfig.PortID)
+ interchainAccountAddr, found := suite.chainB.GetSimApp().ICAHostKeeper.GetInterchainAccountAddress(suite.chainB.GetContext(), ibctesting.FirstConnectionID, path.EndpointA.ChannelConfig.PortID)
suite.Require().True(found)
tokenAmt := sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(5000)))
@@ -641,14 +641,13 @@ func (suite *InterchainAccountsTestSuite) TestControlAccountAfterChannelClose()
chanCap, ok := suite.chainA.GetSimApp().ScopedICAMockKeeper.GetCapability(path.EndpointA.Chain.GetContext(), host.ChannelCapabilityPath(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID))
suite.Require().True(ok)
- _, err = suite.chainA.GetSimApp().ICAControllerKeeper.TrySendTx(suite.chainA.GetContext(), chanCap, path.EndpointA.ChannelConfig.PortID, icaPacketData, ^uint64(0))
+ _, err = suite.chainA.GetSimApp().ICAControllerKeeper.SendTx(suite.chainA.GetContext(), chanCap, ibctesting.FirstConnectionID, path.EndpointA.ChannelConfig.PortID, icaPacketData, ^uint64(0))
suite.Require().NoError(err)
path.EndpointB.UpdateClient()
// relay the packet
packetRelay := channeltypes.NewPacket(icaPacketData.GetBytes(), 1, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, clienttypes.ZeroHeight(), ^uint64(0))
- ack := channeltypes.NewResultAcknowledgement([]byte{byte(1)})
- err = path.RelayPacket(packetRelay, ack.Acknowledgement())
+ err = path.RelayPacket(packetRelay)
suite.Require().NoError(err) // relay committed
// check that the ica balance is updated
@@ -673,14 +672,13 @@ func (suite *InterchainAccountsTestSuite) TestControlAccountAfterChannelClose()
chanCap, ok = suite.chainA.GetSimApp().ScopedICAMockKeeper.GetCapability(path.EndpointA.Chain.GetContext(), host.ChannelCapabilityPath(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID))
suite.Require().True(ok)
- _, err = suite.chainA.GetSimApp().ICAControllerKeeper.TrySendTx(suite.chainA.GetContext(), chanCap, path.EndpointA.ChannelConfig.PortID, icaPacketData, ^uint64(0))
+ _, err = suite.chainA.GetSimApp().ICAControllerKeeper.SendTx(suite.chainA.GetContext(), chanCap, ibctesting.FirstConnectionID, path.EndpointA.ChannelConfig.PortID, icaPacketData, ^uint64(0))
suite.Require().NoError(err)
path.EndpointB.UpdateClient()
// relay the packet
packetRelay = channeltypes.NewPacket(icaPacketData.GetBytes(), 1, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, clienttypes.ZeroHeight(), ^uint64(0))
- ack = channeltypes.NewResultAcknowledgement([]byte{byte(1)})
- err = path.RelayPacket(packetRelay, ack.Acknowledgement())
+ err = path.RelayPacket(packetRelay)
suite.Require().NoError(err) // relay committed
// check that the ica balance is updated
diff --git a/modules/apps/27-interchain-accounts/host/keeper/account.go b/modules/apps/27-interchain-accounts/host/keeper/account.go
index e88c82b16c6..d37cc21f1c2 100644
--- a/modules/apps/27-interchain-accounts/host/keeper/account.go
+++ b/modules/apps/27-interchain-accounts/host/keeper/account.go
@@ -7,20 +7,21 @@ import (
icatypes "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts/types"
)
-// RegisterInterchainAccount attempts to create a new account using the provided address and stores it in state keyed by the provided port identifier
+// RegisterInterchainAccount attempts to create a new account using the provided address and
+// stores it in state keyed by the provided connection and port identifiers
// If an account for the provided address already exists this function returns early (no-op)
-func (k Keeper) RegisterInterchainAccount(ctx sdk.Context, accAddr sdk.AccAddress, controllerPortID string) {
- if acc := k.accountKeeper.GetAccount(ctx, accAddr); acc != nil {
+func (k Keeper) RegisterInterchainAccount(ctx sdk.Context, connectionID, controllerPortID string, accAddress sdk.AccAddress) {
+ if acc := k.accountKeeper.GetAccount(ctx, accAddress); acc != nil {
return
}
interchainAccount := icatypes.NewInterchainAccount(
- authtypes.NewBaseAccountWithAddress(accAddr),
+ authtypes.NewBaseAccountWithAddress(accAddress),
controllerPortID,
)
k.accountKeeper.NewAccount(ctx, interchainAccount)
k.accountKeeper.SetAccount(ctx, interchainAccount)
- k.SetInterchainAccountAddress(ctx, controllerPortID, interchainAccount.Address)
+ k.SetInterchainAccountAddress(ctx, connectionID, controllerPortID, interchainAccount.Address)
}
diff --git a/modules/apps/27-interchain-accounts/host/keeper/account_test.go b/modules/apps/27-interchain-accounts/host/keeper/account_test.go
index 67828c79886..df1966277e4 100644
--- a/modules/apps/27-interchain-accounts/host/keeper/account_test.go
+++ b/modules/apps/27-interchain-accounts/host/keeper/account_test.go
@@ -4,6 +4,7 @@ import (
sdk "github.com/cosmos/cosmos-sdk/types"
icatypes "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts/types"
+ ibctesting "github.com/cosmos/ibc-go/v3/testing"
)
func (suite *KeeperTestSuite) TestRegisterInterchainAccount() {
@@ -12,7 +13,7 @@ func (suite *KeeperTestSuite) TestRegisterInterchainAccount() {
path := NewICAPath(suite.chainA, suite.chainB)
suite.coordinator.SetupConnections(path)
- // InitInterchainAccount
+ //RegisterInterchainAccount
err := SetupICAPath(path, TestOwnerAddress)
suite.Require().NoError(err)
@@ -20,7 +21,7 @@ func (suite *KeeperTestSuite) TestRegisterInterchainAccount() {
suite.Require().NoError(err)
// Get the address of the interchain account stored in state during handshake step
- storedAddr, found := suite.chainB.GetSimApp().ICAHostKeeper.GetInterchainAccountAddress(suite.chainB.GetContext(), portID)
+ storedAddr, found := suite.chainB.GetSimApp().ICAHostKeeper.GetInterchainAccountAddress(suite.chainB.GetContext(), ibctesting.FirstConnectionID, portID)
suite.Require().True(found)
icaAddr, err := sdk.AccAddressFromBech32(storedAddr)
diff --git a/modules/apps/27-interchain-accounts/host/keeper/genesis.go b/modules/apps/27-interchain-accounts/host/keeper/genesis.go
index b784486c150..2a9caa3948b 100644
--- a/modules/apps/27-interchain-accounts/host/keeper/genesis.go
+++ b/modules/apps/27-interchain-accounts/host/keeper/genesis.go
@@ -19,11 +19,11 @@ func InitGenesis(ctx sdk.Context, keeper Keeper, state icatypes.HostGenesisState
}
for _, ch := range state.ActiveChannels {
- keeper.SetActiveChannelID(ctx, ch.PortId, ch.ChannelId)
+ keeper.SetActiveChannelID(ctx, ch.ConnectionId, ch.PortId, ch.ChannelId)
}
for _, acc := range state.InterchainAccounts {
- keeper.SetInterchainAccountAddress(ctx, acc.PortId, acc.AccountAddress)
+ keeper.SetInterchainAccountAddress(ctx, acc.ConnectionId, acc.PortId, acc.AccountAddress)
}
keeper.SetParams(ctx, state.Params)
diff --git a/modules/apps/27-interchain-accounts/host/keeper/genesis_test.go b/modules/apps/27-interchain-accounts/host/keeper/genesis_test.go
index c2da967c56f..138d713cf67 100644
--- a/modules/apps/27-interchain-accounts/host/keeper/genesis_test.go
+++ b/modules/apps/27-interchain-accounts/host/keeper/genesis_test.go
@@ -13,12 +13,14 @@ func (suite *KeeperTestSuite) TestInitGenesis() {
genesisState := icatypes.HostGenesisState{
ActiveChannels: []icatypes.ActiveChannel{
{
- PortId: TestPortID,
- ChannelId: ibctesting.FirstChannelID,
+ ConnectionId: ibctesting.FirstConnectionID,
+ PortId: TestPortID,
+ ChannelId: ibctesting.FirstChannelID,
},
},
InterchainAccounts: []icatypes.RegisteredInterchainAccount{
{
+ ConnectionId: ibctesting.FirstConnectionID,
PortId: TestPortID,
AccountAddress: TestAccAddress.String(),
},
@@ -28,11 +30,11 @@ func (suite *KeeperTestSuite) TestInitGenesis() {
keeper.InitGenesis(suite.chainA.GetContext(), suite.chainA.GetSimApp().ICAHostKeeper, genesisState)
- channelID, found := suite.chainA.GetSimApp().ICAHostKeeper.GetActiveChannelID(suite.chainA.GetContext(), TestPortID)
+ channelID, found := suite.chainA.GetSimApp().ICAHostKeeper.GetActiveChannelID(suite.chainA.GetContext(), ibctesting.FirstConnectionID, TestPortID)
suite.Require().True(found)
suite.Require().Equal(ibctesting.FirstChannelID, channelID)
- accountAdrr, found := suite.chainA.GetSimApp().ICAHostKeeper.GetInterchainAccountAddress(suite.chainA.GetContext(), TestPortID)
+ accountAdrr, found := suite.chainA.GetSimApp().ICAHostKeeper.GetInterchainAccountAddress(suite.chainA.GetContext(), ibctesting.FirstConnectionID, TestPortID)
suite.Require().True(found)
suite.Require().Equal(TestAccAddress.String(), accountAdrr)
@@ -53,7 +55,7 @@ func (suite *KeeperTestSuite) TestExportGenesis() {
genesisState := keeper.ExportGenesis(suite.chainB.GetContext(), suite.chainB.GetSimApp().ICAHostKeeper)
suite.Require().Equal(path.EndpointB.ChannelID, genesisState.ActiveChannels[0].ChannelId)
- suite.Require().Equal(path.EndpointB.ChannelConfig.PortID, genesisState.ActiveChannels[0].PortId)
+ 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)
diff --git a/modules/apps/27-interchain-accounts/host/keeper/handshake.go b/modules/apps/27-interchain-accounts/host/keeper/handshake.go
index a023e42c110..48b3570dd67 100644
--- a/modules/apps/27-interchain-accounts/host/keeper/handshake.go
+++ b/modules/apps/27-interchain-accounts/host/keeper/handshake.go
@@ -47,16 +47,20 @@ func (k Keeper) OnChanOpenTry(
return "", err
}
+ if activeChannelID, found := k.GetOpenActiveChannel(ctx, connectionHops[0], counterparty.PortId); found {
+ return "", sdkerrors.Wrapf(icatypes.ErrActiveChannelAlreadySet, "existing active channel %s for portID %s", activeChannelID, portID)
+ }
+
// On the host chain the capability may only be claimed during the OnChanOpenTry
// The capability being claimed in OpenInit is for a controller chain (the port is different)
if err := k.ClaimCapability(ctx, chanCap, host.ChannelCapabilityPath(portID, channelID)); err != nil {
return "", sdkerrors.Wrapf(err, "failed to claim capability for channel %s on port %s", channelID, portID)
}
- accAddress := icatypes.GenerateAddress(k.accountKeeper.GetModuleAddress(icatypes.ModuleName), counterparty.PortId)
+ accAddress := icatypes.GenerateAddress(k.accountKeeper.GetModuleAddress(icatypes.ModuleName), metadata.HostConnectionId, counterparty.PortId)
// Register interchain account if it does not already exist
- k.RegisterInterchainAccount(ctx, accAddress, counterparty.PortId)
+ k.RegisterInterchainAccount(ctx, metadata.HostConnectionId, counterparty.PortId, accAddress)
metadata.Address = accAddress.String()
versionBytes, err := icatypes.ModuleCdc.MarshalJSON(&metadata)
@@ -73,8 +77,16 @@ func (k Keeper) OnChanOpenConfirm(
portID,
channelID string,
) error {
+ channel, found := k.channelKeeper.GetChannel(ctx, portID, channelID)
+ if !found {
+ return sdkerrors.Wrapf(channeltypes.ErrChannelNotFound, "failed to retrieve channel %s on port %s", channelID, portID)
+ }
- k.SetActiveChannelID(ctx, portID, channelID)
+ // It is assumed the controller chain will not allow multiple active channels to be created for the same connectionID/portID
+ // If the controller chain does allow multiple active channels to be created for the same connectionID/portID,
+ // disallowing overwriting the current active channel guarantees the channel can no longer be used as the controller
+ // and host will disagree on what the currently active channel is
+ k.SetActiveChannelID(ctx, channel.ConnectionHops[0], channel.Counterparty.PortId, channelID)
return nil
}
diff --git a/modules/apps/27-interchain-accounts/host/keeper/handshake_test.go b/modules/apps/27-interchain-accounts/host/keeper/handshake_test.go
index 833ca32f54f..6f3dc0d25e1 100644
--- a/modules/apps/27-interchain-accounts/host/keeper/handshake_test.go
+++ b/modules/apps/27-interchain-accounts/host/keeper/handshake_test.go
@@ -111,6 +111,17 @@ func (suite *KeeperTestSuite) TestOnChanOpenTry() {
},
false,
},
+ {
+ "active channel already set",
+ func() {
+ // create a new channel and set it in state
+ ch := channeltypes.NewChannel(channeltypes.OPEN, channeltypes.ORDERED, channeltypes.NewCounterparty(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID), []string{path.EndpointA.ConnectionID}, ibctesting.DefaultChannelVersion)
+ suite.chainB.GetSimApp().GetIBCKeeper().ChannelKeeper.SetChannel(suite.chainB.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointB.ChannelID, ch)
+
+ // set the active channelID in state
+ suite.chainB.GetSimApp().ICAHostKeeper.SetActiveChannelID(suite.chainB.GetContext(), ibctesting.FirstConnectionID, path.EndpointA.ChannelConfig.PortID, path.EndpointB.ChannelID)
+ }, false,
+ },
}
for _, tc := range testCases {
@@ -122,7 +133,7 @@ func (suite *KeeperTestSuite) TestOnChanOpenTry() {
path = NewICAPath(suite.chainA, suite.chainB)
suite.coordinator.SetupConnections(path)
- err := InitInterchainAccount(path.EndpointA, TestOwnerAddress)
+ err := RegisterInterchainAccount(path.EndpointA, TestOwnerAddress)
suite.Require().NoError(err)
// set the channel id on host
@@ -176,6 +187,14 @@ func (suite *KeeperTestSuite) TestOnChanOpenConfirm() {
{
"success", func() {}, true,
},
+ {
+ "channel not found",
+ func() {
+ path.EndpointB.ChannelID = "invalid-channel-id"
+ path.EndpointB.ChannelConfig.PortID = "invalid-port-id"
+ },
+ false,
+ },
}
for _, tc := range testCases {
@@ -187,7 +206,7 @@ func (suite *KeeperTestSuite) TestOnChanOpenConfirm() {
path = NewICAPath(suite.chainA, suite.chainB)
suite.coordinator.SetupConnections(path)
- err := InitInterchainAccount(path.EndpointA, TestOwnerAddress)
+ err := RegisterInterchainAccount(path.EndpointA, TestOwnerAddress)
suite.Require().NoError(err)
err = path.EndpointB.ChanOpenTry()
@@ -199,7 +218,7 @@ func (suite *KeeperTestSuite) TestOnChanOpenConfirm() {
tc.malleate() // malleate mutates test data
err = suite.chainB.GetSimApp().ICAHostKeeper.OnChanOpenConfirm(suite.chainB.GetContext(),
- path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID)
+ path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID)
if tc.expPass {
suite.Require().NoError(err)
diff --git a/modules/apps/27-interchain-accounts/host/keeper/keeper.go b/modules/apps/27-interchain-accounts/host/keeper/keeper.go
index bf76bce737d..598c68789fc 100644
--- a/modules/apps/27-interchain-accounts/host/keeper/keeper.go
+++ b/modules/apps/27-interchain-accounts/host/keeper/keeper.go
@@ -14,6 +14,7 @@ import (
"github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts/host/types"
icatypes "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts/types"
+ channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types"
host "github.com/cosmos/ibc-go/v3/modules/core/24-host"
)
@@ -90,10 +91,10 @@ func (k Keeper) ClaimCapability(ctx sdk.Context, cap *capabilitytypes.Capability
return k.scopedKeeper.ClaimCapability(ctx, cap, name)
}
-// GetActiveChannelID retrieves the active channelID from the store keyed by the provided portID
-func (k Keeper) GetActiveChannelID(ctx sdk.Context, portID string) (string, bool) {
+// 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)
- key := icatypes.KeyActiveChannel(portID)
+ key := icatypes.KeyActiveChannel(connectionID, portID)
if !store.Has(key) {
return "", false
@@ -102,7 +103,23 @@ 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 host channels and their associated port identifiers
+// GetOpenActiveChannel retrieves the active channelID from the store, keyed by the provided connectionID and portID & checks if the channel in question is in state OPEN
+func (k Keeper) GetOpenActiveChannel(ctx sdk.Context, connectionID, portID string) (string, bool) {
+ channelID, found := k.GetActiveChannelID(ctx, connectionID, portID)
+ if !found {
+ return "", false
+ }
+
+ channel, found := k.channelKeeper.GetChannel(ctx, portID, channelID)
+
+ if found && channel.State == channeltypes.OPEN {
+ return channelID, true
+ }
+
+ return "", false
+}
+
+// GetAllActiveChannels returns a list of all active interchain accounts host channels and their associated connection and port identifiers
func (k Keeper) GetAllActiveChannels(ctx sdk.Context) []icatypes.ActiveChannel {
store := ctx.KVStore(k.storeKey)
iterator := sdk.KVStorePrefixIterator(store, []byte(icatypes.ActiveChannelKeyPrefix))
@@ -113,8 +130,9 @@ func (k Keeper) GetAllActiveChannels(ctx sdk.Context) []icatypes.ActiveChannel {
keySplit := strings.Split(string(iterator.Key()), "/")
ch := icatypes.ActiveChannel{
- PortId: keySplit[1],
- ChannelId: string(iterator.Value()),
+ ConnectionId: keySplit[1],
+ PortId: keySplit[2],
+ ChannelId: string(iterator.Value()),
}
activeChannels = append(activeChannels, ch)
@@ -123,22 +141,22 @@ func (k Keeper) GetAllActiveChannels(ctx sdk.Context) []icatypes.ActiveChannel {
return activeChannels
}
-// SetActiveChannelID stores the active channelID, keyed by the provided portID
-func (k Keeper) SetActiveChannelID(ctx sdk.Context, portID, channelID string) {
+// SetActiveChannelID stores the active channelID, keyed by the provided connectionID and portID
+func (k Keeper) SetActiveChannelID(ctx sdk.Context, connectionID, portID, channelID string) {
store := ctx.KVStore(k.storeKey)
- store.Set(icatypes.KeyActiveChannel(portID), []byte(channelID))
+ store.Set(icatypes.KeyActiveChannel(connectionID, portID), []byte(channelID))
}
-// IsActiveChannel returns true if there exists an active channel for the provided portID, otherwise false
-func (k Keeper) IsActiveChannel(ctx sdk.Context, portID string) bool {
- _, ok := k.GetActiveChannelID(ctx, portID)
+// IsActiveChannel returns true if there exists an active channel for the provided connectionID and portID, otherwise false
+func (k Keeper) IsActiveChannel(ctx sdk.Context, connectionID, portID string) bool {
+ _, ok := k.GetActiveChannelID(ctx, connectionID, portID)
return ok
}
-// GetInterchainAccountAddress retrieves the InterchainAccount address from the store keyed by the provided portID
-func (k Keeper) GetInterchainAccountAddress(ctx sdk.Context, portID string) (string, bool) {
+// GetInterchainAccountAddress retrieves the InterchainAccount address from the store associated with the provided connectionID and portID
+func (k Keeper) GetInterchainAccountAddress(ctx sdk.Context, connectionID, portID string) (string, bool) {
store := ctx.KVStore(k.storeKey)
- key := icatypes.KeyOwnerAccount(portID)
+ key := icatypes.KeyOwnerAccount(connectionID, portID)
if !store.Has(key) {
return "", false
@@ -147,7 +165,7 @@ 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
+// GetAllInterchainAccounts returns a list of all registered interchain account addresses and their associated connection and controller port identifiers
func (k Keeper) GetAllInterchainAccounts(ctx sdk.Context) []icatypes.RegisteredInterchainAccount {
store := ctx.KVStore(k.storeKey)
iterator := sdk.KVStorePrefixIterator(store, []byte(icatypes.OwnerKeyPrefix))
@@ -157,7 +175,8 @@ func (k Keeper) GetAllInterchainAccounts(ctx sdk.Context) []icatypes.RegisteredI
keySplit := strings.Split(string(iterator.Key()), "/")
acc := icatypes.RegisteredInterchainAccount{
- PortId: keySplit[1],
+ ConnectionId: keySplit[1],
+ PortId: keySplit[2],
AccountAddress: string(iterator.Value()),
}
@@ -167,8 +186,8 @@ func (k Keeper) GetAllInterchainAccounts(ctx sdk.Context) []icatypes.RegisteredI
return interchainAccounts
}
-// SetInterchainAccountAddress stores the InterchainAccount address, keyed by the associated portID
-func (k Keeper) SetInterchainAccountAddress(ctx sdk.Context, portID string, address string) {
+// SetInterchainAccountAddress stores the InterchainAccount address, keyed by the associated connectionID and portID
+func (k Keeper) SetInterchainAccountAddress(ctx sdk.Context, connectionID, portID, address string) {
store := ctx.KVStore(k.storeKey)
- store.Set(icatypes.KeyOwnerAccount(portID), []byte(address))
+ store.Set(icatypes.KeyOwnerAccount(connectionID, portID), []byte(address))
}
diff --git a/modules/apps/27-interchain-accounts/host/keeper/keeper_test.go b/modules/apps/27-interchain-accounts/host/keeper/keeper_test.go
index e9824f6dcb2..2b38f6b5e84 100644
--- a/modules/apps/27-interchain-accounts/host/keeper/keeper_test.go
+++ b/modules/apps/27-interchain-accounts/host/keeper/keeper_test.go
@@ -4,7 +4,6 @@ import (
"testing"
sdk "github.com/cosmos/cosmos-sdk/types"
- authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
"github.com/stretchr/testify/suite"
"github.com/tendermint/tendermint/crypto"
@@ -18,7 +17,7 @@ var (
// https://github.com/cosmos/cosmos-sdk/issues/10225
//
// TestAccAddress defines a resuable bech32 address for testing purposes
- TestAccAddress = icatypes.GenerateAddress(sdk.AccAddress(crypto.AddressHash([]byte(icatypes.ModuleName))), TestPortID)
+ TestAccAddress = icatypes.GenerateAddress(sdk.AccAddress(crypto.AddressHash([]byte(icatypes.ModuleName))), ibctesting.FirstConnectionID, TestPortID)
// TestOwnerAddress defines a reusable bech32 address for testing purposes
TestOwnerAddress = "cosmos17dtl0mjt3t77kpuhg2edqzjpszulwhgzuj9ljs"
@@ -47,9 +46,9 @@ type KeeperTestSuite struct {
func (suite *KeeperTestSuite) SetupTest() {
suite.coordinator = ibctesting.NewCoordinator(suite.T(), 3)
- suite.chainA = suite.coordinator.GetChain(ibctesting.GetChainID(0))
- suite.chainB = suite.coordinator.GetChain(ibctesting.GetChainID(1))
- suite.chainC = suite.coordinator.GetChain(ibctesting.GetChainID(2))
+ suite.chainA = suite.coordinator.GetChain(ibctesting.GetChainID(1))
+ suite.chainB = suite.coordinator.GetChain(ibctesting.GetChainID(2))
+ suite.chainC = suite.coordinator.GetChain(ibctesting.GetChainID(3))
}
func NewICAPath(chainA, chainB *ibctesting.TestChain) *ibctesting.Path {
@@ -66,7 +65,7 @@ func NewICAPath(chainA, chainB *ibctesting.TestChain) *ibctesting.Path {
// SetupICAPath invokes the InterchainAccounts entrypoint and subsequent channel handshake handlers
func SetupICAPath(path *ibctesting.Path, owner string) error {
- if err := InitInterchainAccount(path.EndpointA, owner); err != nil {
+ if err := RegisterInterchainAccount(path.EndpointA, owner); err != nil {
return err
}
@@ -85,8 +84,8 @@ func SetupICAPath(path *ibctesting.Path, owner string) error {
return nil
}
-// InitInterchainAccount is a helper function for starting the channel handshake
-func InitInterchainAccount(endpoint *ibctesting.Endpoint, owner string) error {
+// RegisterInterchainAccount is a helper function for starting the channel handshake
+func RegisterInterchainAccount(endpoint *ibctesting.Endpoint, owner string) error {
portID, err := icatypes.NewControllerPortID(owner)
if err != nil {
return err
@@ -94,7 +93,7 @@ func InitInterchainAccount(endpoint *ibctesting.Endpoint, owner string) error {
channelSequence := endpoint.Chain.App.GetIBCKeeper().ChannelKeeper.GetNextChannelSequence(endpoint.Chain.GetContext())
- if err := endpoint.Chain.GetSimApp().ICAControllerKeeper.InitInterchainAccount(endpoint.Chain.GetContext(), endpoint.ConnectionID, owner); err != nil {
+ if err := endpoint.Chain.GetSimApp().ICAControllerKeeper.RegisterInterchainAccount(endpoint.Chain.GetContext(), endpoint.ConnectionID, owner); err != nil {
return err
}
@@ -136,13 +135,13 @@ func (suite *KeeperTestSuite) TestGetInterchainAccountAddress() {
suite.Require().NoError(err)
counterpartyPortID := path.EndpointA.ChannelConfig.PortID
- expectedAddr := authtypes.NewBaseAccountWithAddress(icatypes.GenerateAddress(suite.chainA.GetSimApp().AccountKeeper.GetModuleAddress(icatypes.ModuleName), counterpartyPortID)).GetAddress()
+ expectedAddr := icatypes.GenerateAddress(suite.chainA.GetSimApp().AccountKeeper.GetModuleAddress(icatypes.ModuleName), ibctesting.FirstConnectionID, counterpartyPortID)
- retrievedAddr, found := suite.chainB.GetSimApp().ICAHostKeeper.GetInterchainAccountAddress(suite.chainB.GetContext(), counterpartyPortID)
+ retrievedAddr, found := suite.chainB.GetSimApp().ICAHostKeeper.GetInterchainAccountAddress(suite.chainB.GetContext(), ibctesting.FirstConnectionID, counterpartyPortID)
suite.Require().True(found)
suite.Require().Equal(expectedAddr.String(), retrievedAddr)
- retrievedAddr, found = suite.chainB.GetSimApp().ICAHostKeeper.GetInterchainAccountAddress(suite.chainB.GetContext(), "invalid port")
+ retrievedAddr, found = suite.chainB.GetSimApp().ICAHostKeeper.GetInterchainAccountAddress(suite.chainB.GetContext(), ibctesting.FirstConnectionID, "invalid port")
suite.Require().False(found)
suite.Require().Empty(retrievedAddr)
}
@@ -161,16 +160,18 @@ func (suite *KeeperTestSuite) TestGetAllActiveChannels() {
err := SetupICAPath(path, TestOwnerAddress)
suite.Require().NoError(err)
- suite.chainB.GetSimApp().ICAHostKeeper.SetActiveChannelID(suite.chainB.GetContext(), expectedPortID, expectedChannelID)
+ suite.chainB.GetSimApp().ICAHostKeeper.SetActiveChannelID(suite.chainB.GetContext(), ibctesting.FirstConnectionID, expectedPortID, expectedChannelID)
expectedChannels := []icatypes.ActiveChannel{
{
- PortId: path.EndpointB.ChannelConfig.PortID,
- ChannelId: path.EndpointB.ChannelID,
+ ConnectionId: ibctesting.FirstConnectionID,
+ PortId: path.EndpointA.ChannelConfig.PortID,
+ ChannelId: path.EndpointB.ChannelID,
},
{
- PortId: expectedPortID,
- ChannelId: expectedChannelID,
+ ConnectionId: ibctesting.FirstConnectionID,
+ PortId: expectedPortID,
+ ChannelId: expectedChannelID,
},
}
@@ -193,14 +194,16 @@ func (suite *KeeperTestSuite) TestGetAllInterchainAccounts() {
err := SetupICAPath(path, TestOwnerAddress)
suite.Require().NoError(err)
- suite.chainB.GetSimApp().ICAHostKeeper.SetInterchainAccountAddress(suite.chainB.GetContext(), expectedPortID, expectedAccAddr)
+ suite.chainB.GetSimApp().ICAHostKeeper.SetInterchainAccountAddress(suite.chainB.GetContext(), ibctesting.FirstConnectionID, expectedPortID, expectedAccAddr)
expectedAccounts := []icatypes.RegisteredInterchainAccount{
{
+ ConnectionId: ibctesting.FirstConnectionID,
PortId: TestPortID,
AccountAddress: TestAccAddress.String(),
},
{
+ ConnectionId: ibctesting.FirstConnectionID,
PortId: expectedPortID,
AccountAddress: expectedAccAddr,
},
@@ -220,7 +223,7 @@ func (suite *KeeperTestSuite) TestIsActiveChannel() {
err := SetupICAPath(path, TestOwnerAddress)
suite.Require().NoError(err)
- isActive := suite.chainB.GetSimApp().ICAHostKeeper.IsActiveChannel(suite.chainB.GetContext(), path.EndpointB.ChannelConfig.PortID)
+ isActive := suite.chainB.GetSimApp().ICAHostKeeper.IsActiveChannel(suite.chainB.GetContext(), ibctesting.FirstConnectionID, path.EndpointA.ChannelConfig.PortID)
suite.Require().True(isActive)
}
@@ -230,9 +233,9 @@ func (suite *KeeperTestSuite) TestSetInterchainAccountAddress() {
expectedPortID string = "test-port"
)
- suite.chainB.GetSimApp().ICAHostKeeper.SetInterchainAccountAddress(suite.chainB.GetContext(), expectedPortID, expectedAccAddr)
+ suite.chainB.GetSimApp().ICAHostKeeper.SetInterchainAccountAddress(suite.chainB.GetContext(), ibctesting.FirstConnectionID, expectedPortID, expectedAccAddr)
- retrievedAddr, found := suite.chainB.GetSimApp().ICAHostKeeper.GetInterchainAccountAddress(suite.chainB.GetContext(), expectedPortID)
+ retrievedAddr, found := suite.chainB.GetSimApp().ICAHostKeeper.GetInterchainAccountAddress(suite.chainB.GetContext(), ibctesting.FirstConnectionID, expectedPortID)
suite.Require().True(found)
suite.Require().Equal(expectedAccAddr, retrievedAddr)
}
diff --git a/modules/apps/27-interchain-accounts/host/keeper/relay.go b/modules/apps/27-interchain-accounts/host/keeper/relay.go
index a499b6bc5f0..803045794ad 100644
--- a/modules/apps/27-interchain-accounts/host/keeper/relay.go
+++ b/modules/apps/27-interchain-accounts/host/keeper/relay.go
@@ -9,32 +9,39 @@ import (
channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types"
)
-// AuthenticateTx ensures the provided msgs contain the correct interchain account signer address retrieved
-// from state using the provided controller port identifier
-func (k Keeper) AuthenticateTx(ctx sdk.Context, msgs []sdk.Msg, portID string) error {
- interchainAccountAddr, found := k.GetInterchainAccountAddress(ctx, portID)
- if !found {
- return sdkerrors.Wrapf(icatypes.ErrInterchainAccountNotFound, "failed to retrieve interchain account on port %s", portID)
+// OnRecvPacket handles a given interchain accounts packet on a destination host chain
+func (k Keeper) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet) error {
+ var data icatypes.InterchainAccountPacketData
+
+ if err := icatypes.ModuleCdc.UnmarshalJSON(packet.GetData(), &data); err != nil {
+ // UnmarshalJSON errors are indeterminate and therefore are not wrapped and included in failed acks
+ return sdkerrors.Wrapf(icatypes.ErrUnknownDataType, "cannot unmarshal ICS-27 interchain account packet data")
}
- allowMsgs := k.GetAllowMessages(ctx)
- for _, msg := range msgs {
- if !types.ContainsMsgType(allowMsgs, msg) {
- return sdkerrors.Wrapf(sdkerrors.ErrUnauthorized, "message type not allowed: %s", sdk.MsgTypeURL(msg))
+ switch data.Type {
+ case icatypes.EXECUTE_TX:
+ msgs, err := icatypes.DeserializeCosmosTx(k.cdc, data.Data)
+ if err != nil {
+ return err
}
- for _, signer := range msg.GetSigners() {
- if interchainAccountAddr != signer.String() {
- return sdkerrors.Wrapf(sdkerrors.ErrUnauthorized, "unexpected signer address: expected %s, got %s", interchainAccountAddr, signer.String())
- }
+ if err = k.executeTx(ctx, packet.SourcePort, packet.DestinationPort, packet.DestinationChannel, msgs); err != nil {
+ return err
}
- }
- return nil
+ return nil
+ default:
+ return icatypes.ErrUnknownDataType
+ }
}
func (k Keeper) executeTx(ctx sdk.Context, sourcePort, destPort, destChannel string, msgs []sdk.Msg) error {
- if err := k.AuthenticateTx(ctx, msgs, sourcePort); err != nil {
+ channel, found := k.channelKeeper.GetChannel(ctx, destPort, destChannel)
+ if !found {
+ return channeltypes.ErrChannelNotFound
+ }
+
+ if err := k.authenticateTx(ctx, msgs, channel.ConnectionHops[0], sourcePort); err != nil {
return err
}
@@ -58,6 +65,30 @@ func (k Keeper) executeTx(ctx sdk.Context, sourcePort, destPort, destChannel str
return nil
}
+// authenticateTx ensures the provided msgs contain the correct interchain account signer address retrieved
+// from state using the provided controller port identifier
+func (k Keeper) authenticateTx(ctx sdk.Context, msgs []sdk.Msg, connectionID, portID string) error {
+ interchainAccountAddr, found := k.GetInterchainAccountAddress(ctx, connectionID, portID)
+ if !found {
+ return sdkerrors.Wrapf(icatypes.ErrInterchainAccountNotFound, "failed to retrieve interchain account on port %s", portID)
+ }
+
+ allowMsgs := k.GetAllowMessages(ctx)
+ for _, msg := range msgs {
+ if !types.ContainsMsgType(allowMsgs, msg) {
+ return sdkerrors.Wrapf(sdkerrors.ErrUnauthorized, "message type not allowed: %s", sdk.MsgTypeURL(msg))
+ }
+
+ for _, signer := range msg.GetSigners() {
+ if interchainAccountAddr != signer.String() {
+ return sdkerrors.Wrapf(sdkerrors.ErrUnauthorized, "unexpected signer address: expected %s, got %s", interchainAccountAddr, signer.String())
+ }
+ }
+ }
+
+ return nil
+}
+
// Attempts to get the message handler from the router and if found will then execute the message
func (k Keeper) executeMsg(ctx sdk.Context, msg sdk.Msg) error {
handler := k.msgRouter.Handler(msg)
@@ -75,29 +106,3 @@ func (k Keeper) executeMsg(ctx sdk.Context, msg sdk.Msg) error {
return nil
}
-
-// OnRecvPacket handles a given interchain accounts packet on a destination host chain
-func (k Keeper) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet) error {
- var data icatypes.InterchainAccountPacketData
-
- if err := icatypes.ModuleCdc.UnmarshalJSON(packet.GetData(), &data); err != nil {
- // UnmarshalJSON errors are indeterminate and therefore are not wrapped and included in failed acks
- return sdkerrors.Wrapf(icatypes.ErrUnknownDataType, "cannot unmarshal ICS-27 interchain account packet data")
- }
-
- switch data.Type {
- case icatypes.EXECUTE_TX:
- msgs, err := icatypes.DeserializeCosmosTx(k.cdc, data.Data)
- if err != nil {
- return err
- }
-
- if err = k.executeTx(ctx, packet.SourcePort, packet.DestinationPort, packet.DestinationChannel, msgs); err != nil {
- return err
- }
-
- return nil
- default:
- return icatypes.ErrUnknownDataType
- }
-}
diff --git a/modules/apps/27-interchain-accounts/host/keeper/relay_test.go b/modules/apps/27-interchain-accounts/host/keeper/relay_test.go
index 37cefe34bba..f128804b415 100644
--- a/modules/apps/27-interchain-accounts/host/keeper/relay_test.go
+++ b/modules/apps/27-interchain-accounts/host/keeper/relay_test.go
@@ -32,7 +32,7 @@ func (suite *KeeperTestSuite) TestOnRecvPacket() {
{
"interchain account successfully executes banktypes.MsgSend",
func() {
- interchainAccountAddr, found := suite.chainB.GetSimApp().ICAHostKeeper.GetInterchainAccountAddress(suite.chainB.GetContext(), path.EndpointA.ChannelConfig.PortID)
+ interchainAccountAddr, found := suite.chainB.GetSimApp().ICAHostKeeper.GetInterchainAccountAddress(suite.chainB.GetContext(), ibctesting.FirstConnectionID, path.EndpointA.ChannelConfig.PortID)
suite.Require().True(found)
msg := &banktypes.MsgSend{
@@ -59,7 +59,7 @@ func (suite *KeeperTestSuite) TestOnRecvPacket() {
{
"interchain account successfully executes stakingtypes.MsgDelegate",
func() {
- interchainAccountAddr, found := suite.chainB.GetSimApp().ICAHostKeeper.GetInterchainAccountAddress(suite.chainB.GetContext(), path.EndpointA.ChannelConfig.PortID)
+ interchainAccountAddr, found := suite.chainB.GetSimApp().ICAHostKeeper.GetInterchainAccountAddress(suite.chainB.GetContext(), ibctesting.FirstConnectionID, path.EndpointA.ChannelConfig.PortID)
suite.Require().True(found)
validatorAddr := (sdk.ValAddress)(suite.chainB.Vals.Validators[0].Address)
@@ -87,7 +87,7 @@ func (suite *KeeperTestSuite) TestOnRecvPacket() {
{
"interchain account successfully executes stakingtypes.MsgDelegate and stakingtypes.MsgUndelegate sequentially",
func() {
- interchainAccountAddr, found := suite.chainB.GetSimApp().ICAHostKeeper.GetInterchainAccountAddress(suite.chainB.GetContext(), path.EndpointA.ChannelConfig.PortID)
+ interchainAccountAddr, found := suite.chainB.GetSimApp().ICAHostKeeper.GetInterchainAccountAddress(suite.chainB.GetContext(), ibctesting.FirstConnectionID, path.EndpointA.ChannelConfig.PortID)
suite.Require().True(found)
validatorAddr := (sdk.ValAddress)(suite.chainB.Vals.Validators[0].Address)
@@ -121,7 +121,7 @@ func (suite *KeeperTestSuite) TestOnRecvPacket() {
{
"interchain account successfully executes govtypes.MsgSubmitProposal",
func() {
- interchainAccountAddr, found := suite.chainB.GetSimApp().ICAHostKeeper.GetInterchainAccountAddress(suite.chainB.GetContext(), path.EndpointA.ChannelConfig.PortID)
+ interchainAccountAddr, found := suite.chainB.GetSimApp().ICAHostKeeper.GetInterchainAccountAddress(suite.chainB.GetContext(), ibctesting.FirstConnectionID, path.EndpointA.ChannelConfig.PortID)
suite.Require().True(found)
testProposal := &govtypes.TextProposal{
@@ -156,7 +156,7 @@ func (suite *KeeperTestSuite) TestOnRecvPacket() {
{
"interchain account successfully executes govtypes.MsgVote",
func() {
- interchainAccountAddr, found := suite.chainB.GetSimApp().ICAHostKeeper.GetInterchainAccountAddress(suite.chainB.GetContext(), path.EndpointA.ChannelConfig.PortID)
+ interchainAccountAddr, found := suite.chainB.GetSimApp().ICAHostKeeper.GetInterchainAccountAddress(suite.chainB.GetContext(), ibctesting.FirstConnectionID, path.EndpointA.ChannelConfig.PortID)
suite.Require().True(found)
// Populate the gov keeper in advance with an active proposal
@@ -195,7 +195,7 @@ func (suite *KeeperTestSuite) TestOnRecvPacket() {
{
"interchain account successfully executes disttypes.MsgFundCommunityPool",
func() {
- interchainAccountAddr, found := suite.chainB.GetSimApp().ICAHostKeeper.GetInterchainAccountAddress(suite.chainB.GetContext(), path.EndpointA.ChannelConfig.PortID)
+ interchainAccountAddr, found := suite.chainB.GetSimApp().ICAHostKeeper.GetInterchainAccountAddress(suite.chainB.GetContext(), ibctesting.FirstConnectionID, path.EndpointA.ChannelConfig.PortID)
suite.Require().True(found)
msg := &disttypes.MsgFundCommunityPool{
@@ -221,7 +221,7 @@ func (suite *KeeperTestSuite) TestOnRecvPacket() {
{
"interchain account successfully executes disttypes.MsgSetWithdrawAddress",
func() {
- interchainAccountAddr, found := suite.chainB.GetSimApp().ICAHostKeeper.GetInterchainAccountAddress(suite.chainB.GetContext(), path.EndpointA.ChannelConfig.PortID)
+ interchainAccountAddr, found := suite.chainB.GetSimApp().ICAHostKeeper.GetInterchainAccountAddress(suite.chainB.GetContext(), ibctesting.FirstConnectionID, path.EndpointA.ChannelConfig.PortID)
suite.Require().True(found)
msg := &disttypes.MsgSetWithdrawAddress{
@@ -255,7 +255,7 @@ func (suite *KeeperTestSuite) TestOnRecvPacket() {
suite.coordinator.Setup(transferPath)
- interchainAccountAddr, found := suite.chainB.GetSimApp().ICAHostKeeper.GetInterchainAccountAddress(suite.chainB.GetContext(), path.EndpointA.ChannelConfig.PortID)
+ interchainAccountAddr, found := suite.chainB.GetSimApp().ICAHostKeeper.GetInterchainAccountAddress(suite.chainB.GetContext(), ibctesting.FirstConnectionID, path.EndpointA.ChannelConfig.PortID)
suite.Require().True(found)
msg := &transfertypes.MsgTransfer{
@@ -399,7 +399,7 @@ func (suite *KeeperTestSuite) TestOnRecvPacket() {
suite.Require().NoError(err)
// Get the address of the interchain account stored in state during handshake step
- storedAddr, found := suite.chainB.GetSimApp().ICAHostKeeper.GetInterchainAccountAddress(suite.chainB.GetContext(), portID)
+ storedAddr, found := suite.chainB.GetSimApp().ICAHostKeeper.GetInterchainAccountAddress(suite.chainB.GetContext(), ibctesting.FirstConnectionID, portID)
suite.Require().True(found)
icaAddr, err := sdk.AccAddressFromBech32(storedAddr)
@@ -436,7 +436,7 @@ func (suite *KeeperTestSuite) TestOnRecvPacket() {
}
func (suite *KeeperTestSuite) fundICAWallet(ctx sdk.Context, portID string, amount sdk.Coins) {
- interchainAccountAddr, found := suite.chainB.GetSimApp().ICAHostKeeper.GetInterchainAccountAddress(ctx, portID)
+ interchainAccountAddr, found := suite.chainB.GetSimApp().ICAHostKeeper.GetInterchainAccountAddress(ctx, ibctesting.FirstConnectionID, portID)
suite.Require().True(found)
msgBankSend := &banktypes.MsgSend{
diff --git a/modules/apps/27-interchain-accounts/host/types/ack.go b/modules/apps/27-interchain-accounts/host/types/ack.go
new file mode 100644
index 00000000000..047a7063e46
--- /dev/null
+++ b/modules/apps/27-interchain-accounts/host/types/ack.go
@@ -0,0 +1,27 @@
+package types
+
+import (
+ "fmt"
+
+ sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
+
+ channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types"
+)
+
+const (
+ // ackErrorString defines a string constant included in error acknowledgements
+ // NOTE: Changing this const is state machine breaking as acknowledgements are written into state
+ ackErrorString = "error handling packet on host chain: see events for details"
+)
+
+// AcknowledgementErrorString returns a deterministic error string which may be used in
+// the packet acknowledgement.
+func NewErrorAcknowledgement(err error) channeltypes.Acknowledgement {
+ // the ABCI code is included in the abcitypes.ResponseDeliverTx hash
+ // constructed in Tendermint and is therefore determinstic
+ _, code, _ := sdkerrors.ABCIInfo(err, false) // discard non-determinstic codespace and log values
+
+ errorString := fmt.Sprintf("ABCI code: %d: %s", code, ackErrorString)
+
+ return channeltypes.NewErrorAcknowledgement(errorString)
+}
diff --git a/modules/apps/27-interchain-accounts/host/types/ack_test.go b/modules/apps/27-interchain-accounts/host/types/ack_test.go
new file mode 100644
index 00000000000..bc4e2d07afc
--- /dev/null
+++ b/modules/apps/27-interchain-accounts/host/types/ack_test.go
@@ -0,0 +1,101 @@
+package types_test
+
+import (
+ "testing"
+
+ sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
+ "github.com/stretchr/testify/suite"
+ abcitypes "github.com/tendermint/tendermint/abci/types"
+ tmprotostate "github.com/tendermint/tendermint/proto/tendermint/state"
+ tmstate "github.com/tendermint/tendermint/state"
+
+ "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts/host/types"
+ ibctesting "github.com/cosmos/ibc-go/v3/testing"
+)
+
+const (
+ gasUsed = uint64(100)
+ gasWanted = uint64(100)
+)
+
+type TypesTestSuite struct {
+ suite.Suite
+
+ coordinator *ibctesting.Coordinator
+
+ chainA *ibctesting.TestChain
+ chainB *ibctesting.TestChain
+}
+
+func (suite *TypesTestSuite) SetupTest() {
+ suite.coordinator = ibctesting.NewCoordinator(suite.T(), 2)
+
+ suite.chainA = suite.coordinator.GetChain(ibctesting.GetChainID(1))
+ suite.chainB = suite.coordinator.GetChain(ibctesting.GetChainID(2))
+}
+
+func TestTypesTestSuite(t *testing.T) {
+ suite.Run(t, new(TypesTestSuite))
+}
+
+// The safety of including ABCI error codes in the acknowledgement rests
+// on the inclusion of these ABCI error codes in the abcitypes.ResposneDeliverTx
+// hash. If the ABCI codes get removed from consensus they must no longer be used
+// in the packet acknowledgement.
+//
+// This test acts as an indicator that the ABCI error codes may no longer be deterministic.
+func (suite *TypesTestSuite) TestABCICodeDeterminism() {
+ // same ABCI error code used
+ err := sdkerrors.Wrap(sdkerrors.ErrOutOfGas, "error string 1")
+ errSameABCICode := sdkerrors.Wrap(sdkerrors.ErrOutOfGas, "error string 2")
+
+ // different ABCI error code used
+ errDifferentABCICode := sdkerrors.ErrNotFound
+
+ deliverTx := sdkerrors.ResponseDeliverTx(err, gasUsed, gasWanted, false)
+ responses := tmprotostate.ABCIResponses{
+ DeliverTxs: []*abcitypes.ResponseDeliverTx{
+ &deliverTx,
+ },
+ }
+
+ deliverTxSameABCICode := sdkerrors.ResponseDeliverTx(errSameABCICode, gasUsed, gasWanted, false)
+ responsesSameABCICode := tmprotostate.ABCIResponses{
+ DeliverTxs: []*abcitypes.ResponseDeliverTx{
+ &deliverTxSameABCICode,
+ },
+ }
+
+ deliverTxDifferentABCICode := sdkerrors.ResponseDeliverTx(errDifferentABCICode, gasUsed, gasWanted, false)
+ responsesDifferentABCICode := tmprotostate.ABCIResponses{
+ DeliverTxs: []*abcitypes.ResponseDeliverTx{
+ &deliverTxDifferentABCICode,
+ },
+ }
+
+ hash := tmstate.ABCIResponsesResultsHash(&responses)
+ hashSameABCICode := tmstate.ABCIResponsesResultsHash(&responsesSameABCICode)
+ hashDifferentABCICode := tmstate.ABCIResponsesResultsHash(&responsesDifferentABCICode)
+
+ suite.Require().Equal(hash, hashSameABCICode)
+ suite.Require().NotEqual(hash, hashDifferentABCICode)
+}
+
+// TestAcknowledgementError will verify that only a constant string and
+// ABCI error code are used in constructing the acknowledgement error string
+func (suite *TypesTestSuite) TestAcknowledgementError() {
+ // same ABCI error code used
+ err := sdkerrors.Wrap(sdkerrors.ErrOutOfGas, "error string 1")
+ errSameABCICode := sdkerrors.Wrap(sdkerrors.ErrOutOfGas, "error string 2")
+
+ // different ABCI error code used
+ errDifferentABCICode := sdkerrors.ErrNotFound
+
+ ack := types.NewErrorAcknowledgement(err)
+ ackSameABCICode := types.NewErrorAcknowledgement(errSameABCICode)
+ ackDifferentABCICode := types.NewErrorAcknowledgement(errDifferentABCICode)
+
+ suite.Require().Equal(ack, ackSameABCICode)
+ suite.Require().NotEqual(ack, ackDifferentABCICode)
+
+}
diff --git a/modules/apps/27-interchain-accounts/types/account.go b/modules/apps/27-interchain-accounts/types/account.go
index b3c78c659c9..9cd3fe4d327 100644
--- a/modules/apps/27-interchain-accounts/types/account.go
+++ b/modules/apps/27-interchain-accounts/types/account.go
@@ -39,10 +39,10 @@ type interchainAccountPretty struct {
AccountOwner string `json:"account_owner" yaml:"account_owner"`
}
-// GenerateAddress returns an sdk.AccAddress derived using the provided module account address and port identifier.
-// The sdk.AccAddress returned is a sub-address of the module account, using the controller chain's port identifier as the derivation key
-func GenerateAddress(moduleAccAddr sdk.AccAddress, portID string) sdk.AccAddress {
- return sdk.AccAddress(sdkaddress.Derive(moduleAccAddr, []byte(portID)))
+// GenerateAddress returns an sdk.AccAddress derived using the provided module account address and connection and port identifiers.
+// The sdk.AccAddress returned is a sub-address of the module account, using the host chain connection ID and controller chain's port ID as the derivation key
+func GenerateAddress(moduleAccAddr sdk.AccAddress, connectionID, portID string) sdk.AccAddress {
+ return sdk.AccAddress(sdkaddress.Derive(moduleAccAddr, []byte(connectionID+portID)))
}
// ValidateAccountAddress performs basic validation of interchain account addresses, enforcing constraints
diff --git a/modules/apps/27-interchain-accounts/types/account_test.go b/modules/apps/27-interchain-accounts/types/account_test.go
index 7b50f7f9dee..13acc610152 100644
--- a/modules/apps/27-interchain-accounts/types/account_test.go
+++ b/modules/apps/27-interchain-accounts/types/account_test.go
@@ -34,8 +34,8 @@ type TypesTestSuite struct {
func (suite *TypesTestSuite) SetupTest() {
suite.coordinator = ibctesting.NewCoordinator(suite.T(), 2)
- suite.chainA = suite.coordinator.GetChain(ibctesting.GetChainID(0))
- suite.chainB = suite.coordinator.GetChain(ibctesting.GetChainID(1))
+ suite.chainA = suite.coordinator.GetChain(ibctesting.GetChainID(1))
+ suite.chainB = suite.coordinator.GetChain(ibctesting.GetChainID(2))
}
func TestTypesTestSuite(t *testing.T) {
@@ -43,7 +43,7 @@ func TestTypesTestSuite(t *testing.T) {
}
func (suite *TypesTestSuite) TestGenerateAddress() {
- addr := types.GenerateAddress([]byte{}, "test-port-id")
+ addr := types.GenerateAddress([]byte{}, "test-connection-id", "test-port-id")
accAddr, err := sdk.AccAddressFromBech32(addr.String())
suite.Require().NoError(err, "TestGenerateAddress failed")
diff --git a/modules/apps/27-interchain-accounts/types/errors.go b/modules/apps/27-interchain-accounts/types/errors.go
index 3f2cd77d488..6ce9f2a9dea 100644
--- a/modules/apps/27-interchain-accounts/types/errors.go
+++ b/modules/apps/27-interchain-accounts/types/errors.go
@@ -4,12 +4,6 @@ import (
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
)
-const (
- // AcknowledgementError defines a string constant included in error acknowledgements
- // NOTE: Changing this const is state machine breaking as acknowledgements are written into state
- AcknowledgementError = "error handling packet on host chain: see events for details"
-)
-
var (
ErrUnknownDataType = sdkerrors.Register(ModuleName, 2, "unknown data type")
ErrAccountAlreadyExist = sdkerrors.Register(ModuleName, 3, "account already exist")
@@ -20,11 +14,12 @@ var (
ErrInterchainAccountNotFound = sdkerrors.Register(ModuleName, 8, "interchain account not found")
ErrInterchainAccountAlreadySet = sdkerrors.Register(ModuleName, 9, "interchain account is already set")
ErrActiveChannelNotFound = sdkerrors.Register(ModuleName, 10, "no active channel for this owner")
- ErrInvalidVersion = sdkerrors.Register(ModuleName, 11, "invalid interchain accounts version")
- ErrInvalidAccountAddress = sdkerrors.Register(ModuleName, 12, "invalid account address")
- ErrUnsupported = sdkerrors.Register(ModuleName, 13, "interchain account does not support this action")
- ErrInvalidControllerPort = sdkerrors.Register(ModuleName, 14, "invalid controller port")
- ErrInvalidHostPort = sdkerrors.Register(ModuleName, 15, "invalid host port")
- ErrInvalidTimeoutTimestamp = sdkerrors.Register(ModuleName, 16, "timeout timestamp must be in the future")
- ErrInvalidCodec = sdkerrors.Register(ModuleName, 17, "codec is not supported")
+ ErrActiveChannelAlreadySet = sdkerrors.Register(ModuleName, 11, "active channel already set for this owner")
+ ErrInvalidVersion = sdkerrors.Register(ModuleName, 12, "invalid interchain accounts version")
+ ErrInvalidAccountAddress = sdkerrors.Register(ModuleName, 13, "invalid account address")
+ ErrUnsupported = sdkerrors.Register(ModuleName, 14, "interchain account does not support this action")
+ ErrInvalidControllerPort = sdkerrors.Register(ModuleName, 15, "invalid controller port")
+ ErrInvalidHostPort = sdkerrors.Register(ModuleName, 16, "invalid host port")
+ ErrInvalidTimeoutTimestamp = sdkerrors.Register(ModuleName, 17, "timeout timestamp must be in the future")
+ ErrInvalidCodec = sdkerrors.Register(ModuleName, 18, "codec is not supported")
)
diff --git a/modules/apps/27-interchain-accounts/types/genesis.pb.go b/modules/apps/27-interchain-accounts/types/genesis.pb.go
index 4680272f5c5..c73f5c395f0 100644
--- a/modules/apps/27-interchain-accounts/types/genesis.pb.go
+++ b/modules/apps/27-interchain-accounts/types/genesis.pb.go
@@ -216,10 +216,11 @@ func (m *HostGenesisState) GetParams() types1.Params {
return types1.Params{}
}
-// ActiveChannel contains a pairing of port ID and channel ID for an active interchain accounts channel
+// ActiveChannel contains a connection ID, port ID and associated active channel ID
type ActiveChannel struct {
- PortId string `protobuf:"bytes,1,opt,name=port_id,json=portId,proto3" json:"port_id,omitempty" yaml:"port_id"`
- ChannelId string `protobuf:"bytes,2,opt,name=channel_id,json=channelId,proto3" json:"channel_id,omitempty" yaml:"channel_id"`
+ ConnectionId string `protobuf:"bytes,1,opt,name=connection_id,json=connectionId,proto3" json:"connection_id,omitempty" yaml:"connection_id"`
+ PortId string `protobuf:"bytes,2,opt,name=port_id,json=portId,proto3" json:"port_id,omitempty" yaml:"port_id"`
+ ChannelId string `protobuf:"bytes,3,opt,name=channel_id,json=channelId,proto3" json:"channel_id,omitempty" yaml:"channel_id"`
}
func (m *ActiveChannel) Reset() { *m = ActiveChannel{} }
@@ -255,6 +256,13 @@ func (m *ActiveChannel) XXX_DiscardUnknown() {
var xxx_messageInfo_ActiveChannel proto.InternalMessageInfo
+func (m *ActiveChannel) GetConnectionId() string {
+ if m != nil {
+ return m.ConnectionId
+ }
+ return ""
+}
+
func (m *ActiveChannel) GetPortId() string {
if m != nil {
return m.PortId
@@ -269,10 +277,11 @@ func (m *ActiveChannel) GetChannelId() string {
return ""
}
-// RegisteredInterchainAccount contains a pairing of controller port ID and associated interchain account address
+// RegisteredInterchainAccount contains a connection ID, port ID and associated interchain account address
type RegisteredInterchainAccount struct {
- PortId string `protobuf:"bytes,1,opt,name=port_id,json=portId,proto3" json:"port_id,omitempty" yaml:"port_id"`
- AccountAddress string `protobuf:"bytes,2,opt,name=account_address,json=accountAddress,proto3" json:"account_address,omitempty" yaml:"account_address"`
+ ConnectionId string `protobuf:"bytes,1,opt,name=connection_id,json=connectionId,proto3" json:"connection_id,omitempty" yaml:"connection_id"`
+ PortId string `protobuf:"bytes,2,opt,name=port_id,json=portId,proto3" json:"port_id,omitempty" yaml:"port_id"`
+ AccountAddress string `protobuf:"bytes,3,opt,name=account_address,json=accountAddress,proto3" json:"account_address,omitempty" yaml:"account_address"`
}
func (m *RegisteredInterchainAccount) Reset() { *m = RegisteredInterchainAccount{} }
@@ -308,6 +317,13 @@ func (m *RegisteredInterchainAccount) XXX_DiscardUnknown() {
var xxx_messageInfo_RegisteredInterchainAccount proto.InternalMessageInfo
+func (m *RegisteredInterchainAccount) GetConnectionId() string {
+ if m != nil {
+ return m.ConnectionId
+ }
+ return ""
+}
+
func (m *RegisteredInterchainAccount) GetPortId() string {
if m != nil {
return m.PortId
@@ -335,46 +351,48 @@ func init() {
}
var fileDescriptor_629b3ced0911516b = []byte{
- // 611 bytes of a gzipped FileDescriptorProto
- 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xec, 0x94, 0x4f, 0x6f, 0xd3, 0x3e,
- 0x18, 0xc7, 0x9b, 0x66, 0xbf, 0xfd, 0x54, 0x0f, 0xc6, 0x30, 0x63, 0x0a, 0x45, 0x4a, 0x8b, 0x2f,
- 0xab, 0x84, 0x96, 0x68, 0x7f, 0x60, 0x62, 0x17, 0xb4, 0x14, 0x04, 0xbb, 0xa1, 0x70, 0x41, 0x5c,
- 0x22, 0xd7, 0xb1, 0x52, 0x4b, 0x69, 0x1c, 0xc5, 0x5e, 0xa5, 0x9d, 0xb8, 0x73, 0x81, 0x1b, 0xe2,
- 0x8a, 0xc4, 0xfb, 0xe0, 0xb8, 0xe3, 0x8e, 0x9c, 0x2a, 0xd4, 0xbe, 0x83, 0xbe, 0x02, 0x64, 0x27,
- 0xea, 0x9f, 0xd0, 0x4d, 0xe1, 0xce, 0xa9, 0x76, 0xfc, 0x7c, 0xbf, 0xcf, 0xe7, 0xf1, 0xe3, 0x3e,
- 0xe0, 0x09, 0xeb, 0x11, 0x17, 0xa7, 0x69, 0xcc, 0x08, 0x96, 0x8c, 0x27, 0xc2, 0x65, 0x89, 0xa4,
- 0x19, 0xe9, 0x63, 0x96, 0x04, 0x98, 0x10, 0x7e, 0x9e, 0x48, 0xe1, 0x0e, 0xf7, 0xdd, 0x88, 0x26,
- 0x54, 0x30, 0xe1, 0xa4, 0x19, 0x97, 0x1c, 0xee, 0xb2, 0x1e, 0x71, 0x16, 0x65, 0xce, 0x0a, 0x99,
- 0x33, 0xdc, 0x6f, 0x6e, 0x47, 0x3c, 0xe2, 0x5a, 0xe3, 0xaa, 0x55, 0x2e, 0x6f, 0x76, 0x2b, 0x65,
- 0x25, 0x3c, 0x91, 0x19, 0x8f, 0x63, 0x9a, 0x29, 0x80, 0xf9, 0xae, 0x30, 0x39, 0xae, 0x64, 0xd2,
- 0xe7, 0x42, 0x2a, 0xb9, 0xfa, 0xcd, 0x85, 0xe8, 0x47, 0x1d, 0xdc, 0x7a, 0x95, 0x97, 0xf3, 0x56,
- 0x62, 0x49, 0xe1, 0x37, 0x03, 0x58, 0x73, 0xfb, 0xa0, 0x28, 0x35, 0x10, 0xea, 0xd0, 0x32, 0xda,
- 0x46, 0x67, 0xe3, 0xe0, 0xb9, 0x53, 0xb1, 0x62, 0xa7, 0x3b, 0x33, 0x5a, 0xcc, 0xe1, 0xed, 0x5e,
- 0x8e, 0x5a, 0xb5, 0xe9, 0xa8, 0xd5, 0xba, 0xc0, 0x83, 0xf8, 0x04, 0x5d, 0x97, 0x0e, 0xf9, 0x3b,
- 0x64, 0xa5, 0x01, 0xfc, 0x68, 0x00, 0xa8, 0x8a, 0x28, 0xe1, 0xd5, 0x35, 0xde, 0xb3, 0xca, 0x78,
- 0xaf, 0xb9, 0x90, 0x4b, 0x60, 0x8f, 0x0a, 0xb0, 0x07, 0x39, 0xd8, 0x9f, 0x29, 0x90, 0xbf, 0xd5,
- 0x2f, 0x89, 0xd0, 0x77, 0x13, 0xec, 0xac, 0x2e, 0x14, 0x7e, 0x00, 0x77, 0x30, 0x91, 0x6c, 0x48,
- 0x03, 0xd2, 0xc7, 0x49, 0x42, 0x63, 0x61, 0x19, 0x6d, 0xb3, 0xb3, 0x71, 0xf0, 0xb4, 0x32, 0xe3,
- 0xa9, 0xd6, 0x77, 0x73, 0xb9, 0x67, 0x17, 0x80, 0x3b, 0x39, 0x60, 0xc9, 0x1c, 0xf9, 0x9b, 0x78,
- 0x31, 0x5c, 0xc0, 0xaf, 0x06, 0xb8, 0xb7, 0xc2, 0xd8, 0xaa, 0x6b, 0x8a, 0x17, 0x95, 0x29, 0x7c,
- 0x1a, 0x31, 0x21, 0x69, 0x46, 0xc3, 0xb3, 0x59, 0xc0, 0x69, 0x7e, 0xee, 0xa1, 0x82, 0xa9, 0x99,
- 0x33, 0xad, 0x70, 0x40, 0x3e, 0x64, 0x65, 0x99, 0x80, 0xdb, 0xe0, 0xbf, 0x94, 0x67, 0x52, 0x58,
- 0x66, 0xdb, 0xec, 0x34, 0xfc, 0x7c, 0x03, 0xdf, 0x81, 0xf5, 0x14, 0x67, 0x78, 0x20, 0xac, 0x35,
- 0xdd, 0xcd, 0x93, 0x6a, 0x8c, 0x0b, 0xff, 0x88, 0xe1, 0xbe, 0xf3, 0x46, 0x3b, 0x78, 0x6b, 0x8a,
- 0xcc, 0x2f, 0xfc, 0xd0, 0x17, 0x13, 0x6c, 0x95, 0x3b, 0xfe, 0xaf, 0x43, 0x37, 0x75, 0x08, 0x82,
- 0x35, 0xd5, 0x14, 0xcb, 0x6c, 0x1b, 0x9d, 0x86, 0xaf, 0xd7, 0xd0, 0x2f, 0xf5, 0xe7, 0xa8, 0x1a,
- 0xa1, 0x1e, 0x39, 0xd7, 0x75, 0x26, 0x03, 0xb7, 0x97, 0x2e, 0x11, 0x3e, 0x06, 0xff, 0xab, 0x64,
- 0x01, 0x0b, 0xf5, 0xc8, 0x69, 0x78, 0x70, 0x3a, 0x6a, 0x6d, 0xe6, 0xf4, 0xc5, 0x01, 0xf2, 0xd7,
- 0xd5, 0xea, 0x2c, 0x84, 0x47, 0x00, 0x14, 0xd7, 0xab, 0xe2, 0xeb, 0x3a, 0xfe, 0xfe, 0x74, 0xd4,
- 0xba, 0x5b, 0x4c, 0x97, 0xd9, 0x19, 0xf2, 0x1b, 0xc5, 0xe6, 0x2c, 0x44, 0x9f, 0x0c, 0xf0, 0xf0,
- 0x86, 0x3b, 0xfb, 0x3b, 0x84, 0xae, 0x7a, 0x45, 0x5a, 0x17, 0xe0, 0x30, 0xcc, 0xa8, 0x10, 0x05,
- 0x47, 0x73, 0xf1, 0x25, 0x2c, 0x05, 0xe8, 0x97, 0xa0, 0xbf, 0x9c, 0xe6, 0x1f, 0xbc, 0xe0, 0x72,
- 0x6c, 0x1b, 0x57, 0x63, 0xdb, 0xf8, 0x35, 0xb6, 0x8d, 0xcf, 0x13, 0xbb, 0x76, 0x35, 0xb1, 0x6b,
- 0x3f, 0x27, 0x76, 0xed, 0xfd, 0xcb, 0x88, 0xc9, 0xfe, 0x79, 0xcf, 0x21, 0x7c, 0xe0, 0x12, 0x2e,
- 0x06, 0x5c, 0xb8, 0xac, 0x47, 0xf6, 0x22, 0xee, 0x0e, 0x0f, 0xdd, 0x01, 0x0f, 0xcf, 0x63, 0x2a,
- 0xd4, 0xf4, 0x17, 0xee, 0xc1, 0xf1, 0xde, 0xfc, 0xf6, 0xf7, 0x66, 0x83, 0x5f, 0x5e, 0xa4, 0x54,
- 0xf4, 0xd6, 0xf5, 0xc8, 0x3f, 0xfc, 0x1d, 0x00, 0x00, 0xff, 0xff, 0xf2, 0xb9, 0x8d, 0x2d, 0xe8,
- 0x06, 0x00, 0x00,
+ // 645 bytes of a gzipped FileDescriptorProto
+ 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xec, 0x95, 0x3f, 0x6f, 0x13, 0x3f,
+ 0x18, 0xc7, 0xe3, 0xa4, 0xbf, 0xfe, 0x14, 0xf7, 0x0f, 0xc5, 0x94, 0xea, 0x08, 0xd2, 0x25, 0x78,
+ 0x69, 0x24, 0xd4, 0x3b, 0xf5, 0x0f, 0x54, 0x54, 0x42, 0xa8, 0x17, 0x10, 0x64, 0x43, 0x66, 0x41,
+ 0x2c, 0x27, 0xc7, 0x67, 0x25, 0x96, 0x92, 0x73, 0x74, 0x76, 0x23, 0x75, 0x62, 0x67, 0x62, 0x43,
+ 0xac, 0x48, 0xbc, 0x00, 0xde, 0x01, 0x63, 0x27, 0xd4, 0x91, 0x29, 0x42, 0xed, 0x3b, 0xc8, 0x2b,
+ 0x40, 0xf6, 0x9d, 0x92, 0xf4, 0x48, 0xab, 0x9b, 0x98, 0x98, 0x62, 0xdf, 0xe3, 0xef, 0xf7, 0xf9,
+ 0x3c, 0x7e, 0x1c, 0x1b, 0x3e, 0x12, 0x1d, 0xe6, 0xd3, 0xe1, 0xb0, 0x2f, 0x18, 0xd5, 0x42, 0xc6,
+ 0xca, 0x17, 0xb1, 0xe6, 0x09, 0xeb, 0x51, 0x11, 0x87, 0x94, 0x31, 0x79, 0x12, 0x6b, 0xe5, 0x8f,
+ 0x76, 0xfd, 0x2e, 0x8f, 0xb9, 0x12, 0xca, 0x1b, 0x26, 0x52, 0x4b, 0xb4, 0x2d, 0x3a, 0xcc, 0x9b,
+ 0x97, 0x79, 0x0b, 0x64, 0xde, 0x68, 0xb7, 0xb6, 0xd9, 0x95, 0x5d, 0x69, 0x35, 0xbe, 0x19, 0xa5,
+ 0xf2, 0x5a, 0xab, 0x50, 0x56, 0x26, 0x63, 0x9d, 0xc8, 0x7e, 0x9f, 0x27, 0x06, 0x60, 0x36, 0xcb,
+ 0x4c, 0x0e, 0x0b, 0x99, 0xf4, 0xa4, 0xd2, 0x46, 0x6e, 0x7e, 0x53, 0x21, 0xfe, 0x5e, 0x86, 0xab,
+ 0x2f, 0xd3, 0x72, 0xde, 0x68, 0xaa, 0x39, 0xfa, 0x02, 0xa0, 0x33, 0xb3, 0x0f, 0xb3, 0x52, 0x43,
+ 0x65, 0x82, 0x0e, 0x68, 0x80, 0xe6, 0xca, 0xde, 0x33, 0xaf, 0x60, 0xc5, 0x5e, 0x6b, 0x6a, 0x34,
+ 0x9f, 0x23, 0xd8, 0x3e, 0x1b, 0xd7, 0x4b, 0x93, 0x71, 0xbd, 0x7e, 0x4a, 0x07, 0xfd, 0x23, 0x7c,
+ 0x5d, 0x3a, 0x4c, 0xb6, 0xd8, 0x42, 0x03, 0xf4, 0x01, 0x40, 0x64, 0x8a, 0xc8, 0xe1, 0x95, 0x2d,
+ 0xde, 0x93, 0xc2, 0x78, 0xaf, 0xa4, 0xd2, 0x57, 0xc0, 0x1e, 0x64, 0x60, 0xf7, 0x52, 0xb0, 0x3f,
+ 0x53, 0x60, 0xb2, 0xd1, 0xcb, 0x89, 0xf0, 0xd7, 0x0a, 0xdc, 0x5a, 0x5c, 0x28, 0x7a, 0x0f, 0x6f,
+ 0x51, 0xa6, 0xc5, 0x88, 0x87, 0xac, 0x47, 0xe3, 0x98, 0xf7, 0x95, 0x03, 0x1a, 0x95, 0xe6, 0xca,
+ 0xde, 0xe3, 0xc2, 0x8c, 0xc7, 0x56, 0xdf, 0x4a, 0xe5, 0x81, 0x9b, 0x01, 0x6e, 0xa5, 0x80, 0x39,
+ 0x73, 0x4c, 0xd6, 0xe9, 0xfc, 0x72, 0x85, 0x3e, 0x03, 0x78, 0x67, 0x81, 0xb1, 0x53, 0xb6, 0x14,
+ 0xcf, 0x0b, 0x53, 0x10, 0xde, 0x15, 0x4a, 0xf3, 0x84, 0x47, 0xed, 0xe9, 0x82, 0xe3, 0x34, 0x1e,
+ 0xe0, 0x8c, 0xa9, 0x96, 0x32, 0x2d, 0x70, 0xc0, 0x04, 0x89, 0xbc, 0x4c, 0xa1, 0x4d, 0xf8, 0xdf,
+ 0x50, 0x26, 0x5a, 0x39, 0x95, 0x46, 0xa5, 0x59, 0x25, 0xe9, 0x04, 0xbd, 0x85, 0xcb, 0x43, 0x9a,
+ 0xd0, 0x81, 0x72, 0x96, 0x6c, 0x37, 0x8f, 0x8a, 0x31, 0xce, 0xfd, 0x23, 0x46, 0xbb, 0xde, 0x6b,
+ 0xeb, 0x10, 0x2c, 0x19, 0x32, 0x92, 0xf9, 0xe1, 0x4f, 0x15, 0xb8, 0x91, 0xef, 0xf8, 0xbf, 0x0e,
+ 0xdd, 0xd4, 0x21, 0x04, 0x97, 0x4c, 0x53, 0x9c, 0x4a, 0x03, 0x34, 0xab, 0xc4, 0x8e, 0x11, 0xc9,
+ 0xf5, 0xe7, 0xa0, 0x18, 0xa1, 0xbd, 0x72, 0xae, 0xeb, 0xcc, 0x37, 0x00, 0xd7, 0xae, 0xec, 0x22,
+ 0x7a, 0x0a, 0xd7, 0x98, 0x8c, 0x63, 0xce, 0x8c, 0x63, 0x28, 0x22, 0x7b, 0xf3, 0x54, 0x03, 0x67,
+ 0x32, 0xae, 0x6f, 0x4e, 0x2f, 0x8d, 0x59, 0x18, 0x93, 0xd5, 0xd9, 0xbc, 0x1d, 0xa1, 0x87, 0xf0,
+ 0x7f, 0x03, 0x6b, 0x84, 0x65, 0x2b, 0x44, 0x93, 0x71, 0x7d, 0x3d, 0x15, 0x66, 0x01, 0x4c, 0x96,
+ 0xcd, 0xa8, 0x1d, 0xa1, 0x03, 0x08, 0xb3, 0xf6, 0x98, 0xf5, 0xb6, 0xd6, 0xe0, 0xee, 0x64, 0x5c,
+ 0xbf, 0x9d, 0x25, 0x9a, 0xc6, 0x30, 0xa9, 0x66, 0x93, 0x76, 0x84, 0x7f, 0x00, 0x78, 0xff, 0x86,
+ 0x3d, 0xff, 0xab, 0x15, 0xb4, 0xcc, 0x21, 0xb6, 0x69, 0x43, 0x1a, 0x45, 0x09, 0x57, 0x2a, 0x2b,
+ 0xa3, 0x36, 0x7f, 0x10, 0xaf, 0x2c, 0xb0, 0x07, 0xd1, 0x7e, 0x39, 0x4e, 0x3f, 0x04, 0xe1, 0xd9,
+ 0x85, 0x0b, 0xce, 0x2f, 0x5c, 0xf0, 0xeb, 0xc2, 0x05, 0x1f, 0x2f, 0xdd, 0xd2, 0xf9, 0xa5, 0x5b,
+ 0xfa, 0x79, 0xe9, 0x96, 0xde, 0xbd, 0xe8, 0x0a, 0xdd, 0x3b, 0xe9, 0x78, 0x4c, 0x0e, 0x7c, 0x26,
+ 0xd5, 0x40, 0x2a, 0x5f, 0x74, 0xd8, 0x4e, 0x57, 0xfa, 0xa3, 0x7d, 0x7f, 0x20, 0xa3, 0x93, 0x3e,
+ 0x57, 0xe6, 0xf1, 0x51, 0xfe, 0xde, 0xe1, 0xce, 0xac, 0xf9, 0x3b, 0xd3, 0x77, 0x47, 0x9f, 0x0e,
+ 0xb9, 0xea, 0x2c, 0xdb, 0x17, 0x67, 0xff, 0x77, 0x00, 0x00, 0x00, 0xff, 0xff, 0xf5, 0x08, 0x8f,
+ 0x1f, 0x67, 0x07, 0x00, 0x00,
}
func (m *GenesisState) Marshal() (dAtA []byte, err error) {
@@ -583,13 +601,20 @@ func (m *ActiveChannel) MarshalToSizedBuffer(dAtA []byte) (int, error) {
copy(dAtA[i:], m.ChannelId)
i = encodeVarintGenesis(dAtA, i, uint64(len(m.ChannelId)))
i--
- dAtA[i] = 0x12
+ dAtA[i] = 0x1a
}
if len(m.PortId) > 0 {
i -= len(m.PortId)
copy(dAtA[i:], m.PortId)
i = encodeVarintGenesis(dAtA, i, uint64(len(m.PortId)))
i--
+ dAtA[i] = 0x12
+ }
+ if len(m.ConnectionId) > 0 {
+ i -= len(m.ConnectionId)
+ copy(dAtA[i:], m.ConnectionId)
+ i = encodeVarintGenesis(dAtA, i, uint64(len(m.ConnectionId)))
+ i--
dAtA[i] = 0xa
}
return len(dAtA) - i, nil
@@ -620,13 +645,20 @@ func (m *RegisteredInterchainAccount) MarshalToSizedBuffer(dAtA []byte) (int, er
copy(dAtA[i:], m.AccountAddress)
i = encodeVarintGenesis(dAtA, i, uint64(len(m.AccountAddress)))
i--
- dAtA[i] = 0x12
+ dAtA[i] = 0x1a
}
if len(m.PortId) > 0 {
i -= len(m.PortId)
copy(dAtA[i:], m.PortId)
i = encodeVarintGenesis(dAtA, i, uint64(len(m.PortId)))
i--
+ dAtA[i] = 0x12
+ }
+ if len(m.ConnectionId) > 0 {
+ i -= len(m.ConnectionId)
+ copy(dAtA[i:], m.ConnectionId)
+ i = encodeVarintGenesis(dAtA, i, uint64(len(m.ConnectionId)))
+ i--
dAtA[i] = 0xa
}
return len(dAtA) - i, nil
@@ -718,6 +750,10 @@ func (m *ActiveChannel) Size() (n int) {
}
var l int
_ = l
+ l = len(m.ConnectionId)
+ if l > 0 {
+ n += 1 + l + sovGenesis(uint64(l))
+ }
l = len(m.PortId)
if l > 0 {
n += 1 + l + sovGenesis(uint64(l))
@@ -735,6 +771,10 @@ func (m *RegisteredInterchainAccount) Size() (n int) {
}
var l int
_ = l
+ l = len(m.ConnectionId)
+ if l > 0 {
+ n += 1 + l + sovGenesis(uint64(l))
+ }
l = len(m.PortId)
if l > 0 {
n += 1 + l + sovGenesis(uint64(l))
@@ -1264,6 +1304,38 @@ func (m *ActiveChannel) Unmarshal(dAtA []byte) error {
}
switch fieldNum {
case 1:
+ if wireType != 2 {
+ return fmt.Errorf("proto: wrong wireType = %d for field ConnectionId", wireType)
+ }
+ var stringLen uint64
+ for shift := uint(0); ; shift += 7 {
+ if shift >= 64 {
+ return ErrIntOverflowGenesis
+ }
+ if iNdEx >= l {
+ return io.ErrUnexpectedEOF
+ }
+ b := dAtA[iNdEx]
+ iNdEx++
+ stringLen |= uint64(b&0x7F) << shift
+ if b < 0x80 {
+ break
+ }
+ }
+ intStringLen := int(stringLen)
+ if intStringLen < 0 {
+ return ErrInvalidLengthGenesis
+ }
+ postIndex := iNdEx + intStringLen
+ if postIndex < 0 {
+ return ErrInvalidLengthGenesis
+ }
+ if postIndex > l {
+ return io.ErrUnexpectedEOF
+ }
+ m.ConnectionId = string(dAtA[iNdEx:postIndex])
+ iNdEx = postIndex
+ case 2:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field PortId", wireType)
}
@@ -1295,7 +1367,7 @@ func (m *ActiveChannel) Unmarshal(dAtA []byte) error {
}
m.PortId = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex
- case 2:
+ case 3:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field ChannelId", wireType)
}
@@ -1378,6 +1450,38 @@ func (m *RegisteredInterchainAccount) Unmarshal(dAtA []byte) error {
}
switch fieldNum {
case 1:
+ if wireType != 2 {
+ return fmt.Errorf("proto: wrong wireType = %d for field ConnectionId", wireType)
+ }
+ var stringLen uint64
+ for shift := uint(0); ; shift += 7 {
+ if shift >= 64 {
+ return ErrIntOverflowGenesis
+ }
+ if iNdEx >= l {
+ return io.ErrUnexpectedEOF
+ }
+ b := dAtA[iNdEx]
+ iNdEx++
+ stringLen |= uint64(b&0x7F) << shift
+ if b < 0x80 {
+ break
+ }
+ }
+ intStringLen := int(stringLen)
+ if intStringLen < 0 {
+ return ErrInvalidLengthGenesis
+ }
+ postIndex := iNdEx + intStringLen
+ if postIndex < 0 {
+ return ErrInvalidLengthGenesis
+ }
+ if postIndex > l {
+ return io.ErrUnexpectedEOF
+ }
+ m.ConnectionId = string(dAtA[iNdEx:postIndex])
+ iNdEx = postIndex
+ case 2:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field PortId", wireType)
}
@@ -1409,7 +1513,7 @@ func (m *RegisteredInterchainAccount) Unmarshal(dAtA []byte) error {
}
m.PortId = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex
- case 2:
+ case 3:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field AccountAddress", wireType)
}
diff --git a/modules/apps/27-interchain-accounts/types/keys.go b/modules/apps/27-interchain-accounts/types/keys.go
index a855d878d30..d120fe6ac7c 100644
--- a/modules/apps/27-interchain-accounts/types/keys.go
+++ b/modules/apps/27-interchain-accounts/types/keys.go
@@ -39,13 +39,13 @@ var (
)
// KeyActiveChannel creates and returns a new key used for active channels store operations
-func KeyActiveChannel(portID string) []byte {
- return []byte(fmt.Sprintf("%s/%s", ActiveChannelKeyPrefix, portID))
+func KeyActiveChannel(connectionID, portID string) []byte {
+ return []byte(fmt.Sprintf("%s/%s/%s", ActiveChannelKeyPrefix, connectionID, portID))
}
// KeyOwnerAccount creates and returns a new key used for interchain account store operations
-func KeyOwnerAccount(portID string) []byte {
- return []byte(fmt.Sprintf("%s/%s", OwnerKeyPrefix, portID))
+func KeyOwnerAccount(connectionID, portID string) []byte {
+ return []byte(fmt.Sprintf("%s/%s/%s", OwnerKeyPrefix, connectionID, portID))
}
// KeyPort creates and returns a new key used for port store operations
diff --git a/modules/apps/27-interchain-accounts/types/keys_test.go b/modules/apps/27-interchain-accounts/types/keys_test.go
index f5d48a1f641..4fe7b5a813f 100644
--- a/modules/apps/27-interchain-accounts/types/keys_test.go
+++ b/modules/apps/27-interchain-accounts/types/keys_test.go
@@ -5,11 +5,11 @@ import (
)
func (suite *TypesTestSuite) TestKeyActiveChannel() {
- key := types.KeyActiveChannel("port-id")
- suite.Require().Equal("activeChannel/port-id", string(key))
+ key := types.KeyActiveChannel("connection-id", "port-id")
+ suite.Require().Equal("activeChannel/connection-id/port-id", string(key))
}
func (suite *TypesTestSuite) TestKeyOwnerAccount() {
- key := types.KeyOwnerAccount("port-id")
- suite.Require().Equal("owner/port-id", string(key))
+ key := types.KeyOwnerAccount("connection-id", "port-id")
+ suite.Require().Equal("owner/connection-id/port-id", string(key))
}
diff --git a/modules/apps/transfer/keeper/keeper_test.go b/modules/apps/transfer/keeper/keeper_test.go
index 7a3805e7f12..1e29626c987 100644
--- a/modules/apps/transfer/keeper/keeper_test.go
+++ b/modules/apps/transfer/keeper/keeper_test.go
@@ -27,9 +27,9 @@ type KeeperTestSuite struct {
func (suite *KeeperTestSuite) SetupTest() {
suite.coordinator = ibctesting.NewCoordinator(suite.T(), 3)
- suite.chainA = suite.coordinator.GetChain(ibctesting.GetChainID(0))
- suite.chainB = suite.coordinator.GetChain(ibctesting.GetChainID(1))
- suite.chainC = suite.coordinator.GetChain(ibctesting.GetChainID(2))
+ suite.chainA = suite.coordinator.GetChain(ibctesting.GetChainID(1))
+ suite.chainB = suite.coordinator.GetChain(ibctesting.GetChainID(2))
+ suite.chainC = suite.coordinator.GetChain(ibctesting.GetChainID(3))
queryHelper := baseapp.NewQueryServerTestHelper(suite.chainA.GetContext(), suite.chainA.GetSimApp().InterfaceRegistry())
types.RegisterQueryServer(queryHelper, suite.chainA.GetSimApp().TransferKeeper)
diff --git a/modules/apps/transfer/keeper/relay_test.go b/modules/apps/transfer/keeper/relay_test.go
index be8627cc399..8e77c73db9e 100644
--- a/modules/apps/transfer/keeper/relay_test.go
+++ b/modules/apps/transfer/keeper/relay_test.go
@@ -192,8 +192,7 @@ func (suite *KeeperTestSuite) TestOnRecvPacket() {
// relay send packet
fungibleTokenPacket := types.NewFungibleTokenPacketData(coinFromBToA.Denom, coinFromBToA.Amount.String(), suite.chainB.SenderAccount.GetAddress().String(), suite.chainA.SenderAccount.GetAddress().String())
packet := channeltypes.NewPacket(fungibleTokenPacket.GetBytes(), 1, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, clienttypes.NewHeight(0, 110), 0)
- ack := channeltypes.NewResultAcknowledgement([]byte{byte(1)})
- err = path.RelayPacket(packet, ack.Acknowledgement())
+ err = path.RelayPacket(packet)
suite.Require().NoError(err) // relay committed
seq++
diff --git a/modules/apps/transfer/transfer_test.go b/modules/apps/transfer/transfer_test.go
index 5265b0dcf6c..ec36af78ceb 100644
--- a/modules/apps/transfer/transfer_test.go
+++ b/modules/apps/transfer/transfer_test.go
@@ -25,9 +25,9 @@ type TransferTestSuite struct {
func (suite *TransferTestSuite) SetupTest() {
suite.coordinator = ibctesting.NewCoordinator(suite.T(), 3)
- suite.chainA = suite.coordinator.GetChain(ibctesting.GetChainID(0))
- suite.chainB = suite.coordinator.GetChain(ibctesting.GetChainID(1))
- suite.chainC = suite.coordinator.GetChain(ibctesting.GetChainID(2))
+ suite.chainA = suite.coordinator.GetChain(ibctesting.GetChainID(1))
+ suite.chainB = suite.coordinator.GetChain(ibctesting.GetChainID(2))
+ suite.chainC = suite.coordinator.GetChain(ibctesting.GetChainID(3))
}
func NewTransferPath(chainA, chainB *ibctesting.TestChain) *ibctesting.Path {
@@ -63,8 +63,7 @@ func (suite *TransferTestSuite) TestHandleMsgTransfer() {
// relay send
fungibleTokenPacket := types.NewFungibleTokenPacketData(coinToSendToB.Denom, coinToSendToB.Amount.String(), suite.chainA.SenderAccount.GetAddress().String(), suite.chainB.SenderAccount.GetAddress().String())
packet := channeltypes.NewPacket(fungibleTokenPacket.GetBytes(), 1, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, timeoutHeight, 0)
- ack := channeltypes.NewResultAcknowledgement([]byte{byte(1)})
- err = path.RelayPacket(packet, ack.Acknowledgement())
+ err = path.RelayPacket(packet)
suite.Require().NoError(err) // relay committed
// check that voucher exists on chain B
@@ -92,7 +91,7 @@ func (suite *TransferTestSuite) TestHandleMsgTransfer() {
fullDenomPath := types.GetPrefixedDenom(pathBtoC.EndpointB.ChannelConfig.PortID, pathBtoC.EndpointB.ChannelID, voucherDenomTrace.GetFullDenomPath())
fungibleTokenPacket = types.NewFungibleTokenPacketData(voucherDenomTrace.GetFullDenomPath(), coinSentFromAToB.Amount.String(), suite.chainB.SenderAccount.GetAddress().String(), suite.chainC.SenderAccount.GetAddress().String())
packet = channeltypes.NewPacket(fungibleTokenPacket.GetBytes(), 1, pathBtoC.EndpointA.ChannelConfig.PortID, pathBtoC.EndpointA.ChannelID, pathBtoC.EndpointB.ChannelConfig.PortID, pathBtoC.EndpointB.ChannelID, timeoutHeight, 0)
- err = pathBtoC.RelayPacket(packet, ack.Acknowledgement())
+ err = pathBtoC.RelayPacket(packet)
suite.Require().NoError(err) // relay committed
coinSentFromBToC := sdk.NewCoin(types.ParseDenomTrace(fullDenomPath).IBCDenom(), amount)
@@ -115,7 +114,7 @@ func (suite *TransferTestSuite) TestHandleMsgTransfer() {
// NOTE: fungible token is prefixed with the full trace in order to verify the packet commitment
fungibleTokenPacket = types.NewFungibleTokenPacketData(fullDenomPath, coinSentFromBToC.Amount.String(), suite.chainC.SenderAccount.GetAddress().String(), suite.chainB.SenderAccount.GetAddress().String())
packet = channeltypes.NewPacket(fungibleTokenPacket.GetBytes(), 1, pathBtoC.EndpointB.ChannelConfig.PortID, pathBtoC.EndpointB.ChannelID, pathBtoC.EndpointA.ChannelConfig.PortID, pathBtoC.EndpointA.ChannelID, timeoutHeight, 0)
- err = pathBtoC.RelayPacket(packet, ack.Acknowledgement())
+ err = pathBtoC.RelayPacket(packet)
suite.Require().NoError(err) // relay committed
balance = suite.chainB.GetSimApp().BankKeeper.GetBalance(suite.chainB.GetContext(), suite.chainB.SenderAccount.GetAddress(), coinSentFromAToB.Denom)
diff --git a/modules/core/02-client/abci_test.go b/modules/core/02-client/abci_test.go
index af4723c609a..80ebdb338ec 100644
--- a/modules/core/02-client/abci_test.go
+++ b/modules/core/02-client/abci_test.go
@@ -28,8 +28,8 @@ type ClientTestSuite struct {
func (suite *ClientTestSuite) SetupTest() {
suite.coordinator = ibctesting.NewCoordinator(suite.T(), 2)
- suite.chainA = suite.coordinator.GetChain(ibctesting.GetChainID(0))
- suite.chainB = suite.coordinator.GetChain(ibctesting.GetChainID(1))
+ suite.chainA = suite.coordinator.GetChain(ibctesting.GetChainID(1))
+ suite.chainB = suite.coordinator.GetChain(ibctesting.GetChainID(2))
// set localhost client
revision := types.ParseChainID(suite.chainA.GetContext().ChainID())
diff --git a/modules/core/02-client/keeper/keeper_test.go b/modules/core/02-client/keeper/keeper_test.go
index 0ab53c01c50..e3dfb4d2e3b 100644
--- a/modules/core/02-client/keeper/keeper_test.go
+++ b/modules/core/02-client/keeper/keeper_test.go
@@ -73,8 +73,8 @@ type KeeperTestSuite struct {
func (suite *KeeperTestSuite) SetupTest() {
suite.coordinator = ibctesting.NewCoordinator(suite.T(), 2)
- suite.chainA = suite.coordinator.GetChain(ibctesting.GetChainID(0))
- suite.chainB = suite.coordinator.GetChain(ibctesting.GetChainID(1))
+ suite.chainA = suite.coordinator.GetChain(ibctesting.GetChainID(1))
+ suite.chainB = suite.coordinator.GetChain(ibctesting.GetChainID(2))
isCheckTx := false
suite.now = time.Date(2020, 1, 2, 0, 0, 0, 0, time.UTC)
diff --git a/modules/core/02-client/legacy/v100/store_test.go b/modules/core/02-client/legacy/v100/store_test.go
index 4b16dd1f2ac..a1c1be3034a 100644
--- a/modules/core/02-client/legacy/v100/store_test.go
+++ b/modules/core/02-client/legacy/v100/store_test.go
@@ -32,8 +32,8 @@ func TestLegacyTestSuite(t *testing.T) {
// SetupTest creates a coordinator with 2 test chains.
func (suite *LegacyTestSuite) SetupTest() {
suite.coordinator = ibctesting.NewCoordinator(suite.T(), 2)
- suite.chainA = suite.coordinator.GetChain(ibctesting.GetChainID(0))
- suite.chainB = suite.coordinator.GetChain(ibctesting.GetChainID(1))
+ suite.chainA = suite.coordinator.GetChain(ibctesting.GetChainID(1))
+ suite.chainB = suite.coordinator.GetChain(ibctesting.GetChainID(2))
// commit some blocks so that QueryProof returns valid proof (cannot return valid query if height <= 1)
suite.coordinator.CommitNBlocks(suite.chainA, 2)
suite.coordinator.CommitNBlocks(suite.chainB, 2)
diff --git a/modules/core/02-client/types/msgs_test.go b/modules/core/02-client/types/msgs_test.go
index 2e7631da2de..35dd08aedba 100644
--- a/modules/core/02-client/types/msgs_test.go
+++ b/modules/core/02-client/types/msgs_test.go
@@ -26,8 +26,8 @@ type TypesTestSuite struct {
func (suite *TypesTestSuite) SetupTest() {
suite.coordinator = ibctesting.NewCoordinator(suite.T(), 2)
- suite.chainA = suite.coordinator.GetChain(ibctesting.GetChainID(0))
- suite.chainB = suite.coordinator.GetChain(ibctesting.GetChainID(1))
+ suite.chainA = suite.coordinator.GetChain(ibctesting.GetChainID(1))
+ suite.chainB = suite.coordinator.GetChain(ibctesting.GetChainID(2))
}
func TestTypesTestSuite(t *testing.T) {
diff --git a/modules/core/03-connection/keeper/keeper_test.go b/modules/core/03-connection/keeper/keeper_test.go
index 750246e0406..b4dfa839028 100644
--- a/modules/core/03-connection/keeper/keeper_test.go
+++ b/modules/core/03-connection/keeper/keeper_test.go
@@ -22,8 +22,8 @@ type KeeperTestSuite struct {
func (suite *KeeperTestSuite) SetupTest() {
suite.coordinator = ibctesting.NewCoordinator(suite.T(), 2)
- suite.chainA = suite.coordinator.GetChain(ibctesting.GetChainID(0))
- suite.chainB = suite.coordinator.GetChain(ibctesting.GetChainID(1))
+ suite.chainA = suite.coordinator.GetChain(ibctesting.GetChainID(1))
+ suite.chainB = suite.coordinator.GetChain(ibctesting.GetChainID(2))
}
func TestKeeperTestSuite(t *testing.T) {
diff --git a/modules/core/03-connection/types/msgs_test.go b/modules/core/03-connection/types/msgs_test.go
index 880925bacaf..9cf741bb2c0 100644
--- a/modules/core/03-connection/types/msgs_test.go
+++ b/modules/core/03-connection/types/msgs_test.go
@@ -41,8 +41,8 @@ type MsgTestSuite struct {
func (suite *MsgTestSuite) SetupTest() {
suite.coordinator = ibctesting.NewCoordinator(suite.T(), 2)
- suite.chainA = suite.coordinator.GetChain(ibctesting.GetChainID(0))
- suite.chainB = suite.coordinator.GetChain(ibctesting.GetChainID(1))
+ suite.chainA = suite.coordinator.GetChain(ibctesting.GetChainID(1))
+ suite.chainB = suite.coordinator.GetChain(ibctesting.GetChainID(2))
app := simapp.Setup(false)
db := dbm.NewMemDB()
diff --git a/modules/core/04-channel/keeper/keeper_test.go b/modules/core/04-channel/keeper/keeper_test.go
index c37b7744ff3..60888f11c3c 100644
--- a/modules/core/04-channel/keeper/keeper_test.go
+++ b/modules/core/04-channel/keeper/keeper_test.go
@@ -28,8 +28,8 @@ func TestKeeperTestSuite(t *testing.T) {
// SetupTest creates a coordinator with 2 test chains.
func (suite *KeeperTestSuite) SetupTest() {
suite.coordinator = ibctesting.NewCoordinator(suite.T(), 2)
- suite.chainA = suite.coordinator.GetChain(ibctesting.GetChainID(0))
- suite.chainB = suite.coordinator.GetChain(ibctesting.GetChainID(1))
+ suite.chainA = suite.coordinator.GetChain(ibctesting.GetChainID(1))
+ suite.chainB = suite.coordinator.GetChain(ibctesting.GetChainID(2))
// commit some blocks so that QueryProof returns valid proof (cannot return valid query if height <= 1)
suite.coordinator.CommitNBlocks(suite.chainA, 2)
suite.coordinator.CommitNBlocks(suite.chainB, 2)
diff --git a/modules/core/ante/ante_test.go b/modules/core/ante/ante_test.go
index 2054c260cee..0336e07a3ae 100644
--- a/modules/core/ante/ante_test.go
+++ b/modules/core/ante/ante_test.go
@@ -28,8 +28,8 @@ type AnteTestSuite struct {
// SetupTest creates a coordinator with 2 test chains.
func (suite *AnteTestSuite) SetupTest() {
suite.coordinator = ibctesting.NewCoordinator(suite.T(), 2)
- suite.chainA = suite.coordinator.GetChain(ibctesting.GetChainID(0))
- suite.chainB = suite.coordinator.GetChain(ibctesting.GetChainID(1))
+ suite.chainA = suite.coordinator.GetChain(ibctesting.GetChainID(1))
+ suite.chainB = suite.coordinator.GetChain(ibctesting.GetChainID(2))
// commit some blocks so that QueryProof returns valid proof (cannot return valid query if height <= 1)
suite.coordinator.CommitNBlocks(suite.chainA, 2)
suite.coordinator.CommitNBlocks(suite.chainB, 2)
diff --git a/modules/core/genesis_test.go b/modules/core/genesis_test.go
index 9922e1165c9..00b9a0c3b84 100644
--- a/modules/core/genesis_test.go
+++ b/modules/core/genesis_test.go
@@ -50,8 +50,8 @@ type IBCTestSuite struct {
func (suite *IBCTestSuite) SetupTest() {
suite.coordinator = ibctesting.NewCoordinator(suite.T(), 2)
- suite.chainA = suite.coordinator.GetChain(ibctesting.GetChainID(0))
- suite.chainB = suite.coordinator.GetChain(ibctesting.GetChainID(1))
+ suite.chainA = suite.coordinator.GetChain(ibctesting.GetChainID(1))
+ suite.chainB = suite.coordinator.GetChain(ibctesting.GetChainID(2))
}
func TestIBCTestSuite(t *testing.T) {
diff --git a/modules/core/keeper/msg_server_test.go b/modules/core/keeper/msg_server_test.go
index e3779768dc9..1e1933ee724 100644
--- a/modules/core/keeper/msg_server_test.go
+++ b/modules/core/keeper/msg_server_test.go
@@ -38,8 +38,8 @@ type KeeperTestSuite struct {
func (suite *KeeperTestSuite) SetupTest() {
suite.coordinator = ibctesting.NewCoordinator(suite.T(), 2)
- suite.chainA = suite.coordinator.GetChain(ibctesting.GetChainID(0))
- suite.chainB = suite.coordinator.GetChain(ibctesting.GetChainID(1))
+ suite.chainA = suite.coordinator.GetChain(ibctesting.GetChainID(1))
+ suite.chainB = suite.coordinator.GetChain(ibctesting.GetChainID(2))
// TODO: remove
// commit some blocks so that QueryProof returns valid proof (cannot return valid query if height <= 1)
diff --git a/modules/core/legacy/v100/genesis_test.go b/modules/core/legacy/v100/genesis_test.go
index e06ceba87f7..b0db2e4e1b3 100644
--- a/modules/core/legacy/v100/genesis_test.go
+++ b/modules/core/legacy/v100/genesis_test.go
@@ -38,8 +38,8 @@ func TestLegacyTestSuite(t *testing.T) {
// SetupTest creates a coordinator with 2 test chains.
func (suite *LegacyTestSuite) SetupTest() {
suite.coordinator = ibctesting.NewCoordinator(suite.T(), 2)
- suite.chainA = suite.coordinator.GetChain(ibctesting.GetChainID(0))
- suite.chainB = suite.coordinator.GetChain(ibctesting.GetChainID(1))
+ suite.chainA = suite.coordinator.GetChain(ibctesting.GetChainID(1))
+ suite.chainB = suite.coordinator.GetChain(ibctesting.GetChainID(2))
// commit some blocks so that QueryProof returns valid proof (cannot return valid query if height <= 1)
suite.coordinator.CommitNBlocks(suite.chainA, 2)
suite.coordinator.CommitNBlocks(suite.chainB, 2)
diff --git a/modules/light-clients/06-solomachine/types/solomachine_test.go b/modules/light-clients/06-solomachine/types/solomachine_test.go
index 8487697dcd0..56ebadee3d1 100644
--- a/modules/light-clients/06-solomachine/types/solomachine_test.go
+++ b/modules/light-clients/06-solomachine/types/solomachine_test.go
@@ -34,8 +34,8 @@ type SoloMachineTestSuite struct {
func (suite *SoloMachineTestSuite) SetupTest() {
suite.coordinator = ibctesting.NewCoordinator(suite.T(), 2)
- suite.chainA = suite.coordinator.GetChain(ibctesting.GetChainID(0))
- suite.chainB = suite.coordinator.GetChain(ibctesting.GetChainID(1))
+ suite.chainA = suite.coordinator.GetChain(ibctesting.GetChainID(1))
+ suite.chainB = suite.coordinator.GetChain(ibctesting.GetChainID(2))
suite.solomachine = ibctesting.NewSolomachine(suite.T(), suite.chainA.Codec, "solomachinesingle", "testing", 1)
suite.solomachineMulti = ibctesting.NewSolomachine(suite.T(), suite.chainA.Codec, "solomachinemulti", "testing", 4)
diff --git a/modules/light-clients/07-tendermint/types/tendermint_test.go b/modules/light-clients/07-tendermint/types/tendermint_test.go
index 2c8d43173bf..7c1996abfa8 100644
--- a/modules/light-clients/07-tendermint/types/tendermint_test.go
+++ b/modules/light-clients/07-tendermint/types/tendermint_test.go
@@ -57,8 +57,8 @@ type TendermintTestSuite struct {
func (suite *TendermintTestSuite) SetupTest() {
suite.coordinator = ibctesting.NewCoordinator(suite.T(), 2)
- suite.chainA = suite.coordinator.GetChain(ibctesting.GetChainID(0))
- suite.chainB = suite.coordinator.GetChain(ibctesting.GetChainID(1))
+ suite.chainA = suite.coordinator.GetChain(ibctesting.GetChainID(1))
+ suite.chainB = suite.coordinator.GetChain(ibctesting.GetChainID(2))
// commit some blocks so that QueryProof returns valid proof (cannot return valid query if height <= 1)
suite.coordinator.CommitNBlocks(suite.chainA, 2)
suite.coordinator.CommitNBlocks(suite.chainB, 2)
diff --git a/proto/ibc/applications/interchain_accounts/v1/genesis.proto b/proto/ibc/applications/interchain_accounts/v1/genesis.proto
index 7fa49cbe2a3..3902f890708 100644
--- a/proto/ibc/applications/interchain_accounts/v1/genesis.proto
+++ b/proto/ibc/applications/interchain_accounts/v1/genesis.proto
@@ -36,14 +36,16 @@ message HostGenesisState {
ibc.applications.interchain_accounts.host.v1.Params params = 4 [(gogoproto.nullable) = false];
}
-// ActiveChannel contains a pairing of port ID and channel ID for an active interchain accounts channel
+// ActiveChannel contains a connection ID, port ID and associated active channel ID
message ActiveChannel {
- string port_id = 1 [(gogoproto.moretags) = "yaml:\"port_id\""];
- string channel_id = 2 [(gogoproto.moretags) = "yaml:\"channel_id\""];
+ string connection_id = 1 [(gogoproto.moretags) = "yaml:\"connection_id\""];
+ string port_id = 2 [(gogoproto.moretags) = "yaml:\"port_id\""];
+ string channel_id = 3 [(gogoproto.moretags) = "yaml:\"channel_id\""];
}
-// RegisteredInterchainAccount contains a pairing of controller port ID and associated interchain account address
+// RegisteredInterchainAccount contains a connection ID, port ID and associated interchain account address
message RegisteredInterchainAccount {
- string port_id = 1 [(gogoproto.moretags) = "yaml:\"port_id\""];
- string account_address = 2 [(gogoproto.moretags) = "yaml:\"account_address\""];
-}
+ string connection_id = 1 [(gogoproto.moretags) = "yaml:\"connection_id\""];
+ string port_id = 2 [(gogoproto.moretags) = "yaml:\"port_id\""];
+ string account_address = 3 [(gogoproto.moretags) = "yaml:\"account_address\""];
+}
\ No newline at end of file
diff --git a/testing/README.md b/testing/README.md
index 6cf08516b8c..97f540d5c4c 100644
--- a/testing/README.md
+++ b/testing/README.md
@@ -155,8 +155,8 @@ func TestKeeperTestSuite(t *testing.T) {
// SetupTest creates a coordinator with 2 test chains.
func (suite *KeeperTestSuite) SetupTest() {
suite.coordinator = ibctesting.NewCoordinator(suite.T(), 2) // initializes 2 test chains
- suite.chainA = suite.coordinator.GetChain(ibctesting.GetChainID(0)) // convenience and readability
- suite.chainB = suite.coordinator.GetChain(ibctesting.GetChainID(1)) // convenience and readability
+ suite.chainA = suite.coordinator.GetChain(ibctesting.GetChainID(1)) // convenience and readability
+ suite.chainB = suite.coordinator.GetChain(ibctesting.GetChainID(2)) // convenience and readability
}
```
diff --git a/testing/app.go b/testing/app.go
index 0ce71f43186..1c5bbe7c88a 100644
--- a/testing/app.go
+++ b/testing/app.go
@@ -58,7 +58,7 @@ func SetupTestingApp() (TestingApp, map[string]json.RawMessage) {
// that also act as delegators. For simplicity, each validator is bonded with a delegation
// of one consensus engine unit (10^6) in the default token of the simapp from first genesis
// account. A Nop logger is set in SimApp.
-func SetupWithGenesisValSet(t *testing.T, valSet *tmtypes.ValidatorSet, genAccs []authtypes.GenesisAccount, balances ...banktypes.Balance) TestingApp {
+func SetupWithGenesisValSet(t *testing.T, valSet *tmtypes.ValidatorSet, genAccs []authtypes.GenesisAccount, chainID string, balances ...banktypes.Balance) TestingApp {
app, genesisState := DefaultTestingAppInit()
// set genesis accounts
authGenesis := authtypes.NewGenesisState(authtypes.DefaultParams(), genAccs)
@@ -117,6 +117,7 @@ func SetupWithGenesisValSet(t *testing.T, valSet *tmtypes.ValidatorSet, genAccs
// init chain will set the validator set and initialize the genesis accounts
app.InitChain(
abci.RequestInitChain{
+ ChainId: chainID,
Validators: []abci.ValidatorUpdate{},
ConsensusParams: simapp.DefaultConsensusParams,
AppStateBytes: stateBytes,
@@ -126,6 +127,7 @@ func SetupWithGenesisValSet(t *testing.T, valSet *tmtypes.ValidatorSet, genAccs
// commit genesis changes
app.Commit()
app.BeginBlock(abci.RequestBeginBlock{Header: tmproto.Header{
+ ChainID: chainID,
Height: app.LastBlockHeight() + 1,
AppHash: app.LastCommitID().Hash,
ValidatorsHash: valSet.Hash(),
diff --git a/testing/chain.go b/testing/chain.go
index 9820c527a4d..281782f7837 100644
--- a/testing/chain.go
+++ b/testing/chain.go
@@ -90,7 +90,7 @@ func NewTestChain(t *testing.T, coord *Coordinator, chainID string) *TestChain {
Coins: sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, amount)),
}
- app := SetupWithGenesisValSet(t, valSet, []authtypes.GenesisAccount{acc}, balance)
+ app := SetupWithGenesisValSet(t, valSet, []authtypes.GenesisAccount{acc}, chainID, balance)
// create current header and call begin block
header := tmproto.Header{
diff --git a/testing/coordinator.go b/testing/coordinator.go
index c7a5d6edfd1..615bd830ced 100644
--- a/testing/coordinator.go
+++ b/testing/coordinator.go
@@ -10,9 +10,8 @@ import (
abci "github.com/tendermint/tendermint/abci/types"
)
-const ChainIDPrefix = "testchain"
-
var (
+ ChainIDPrefix = "testchain"
globalStartTime = time.Date(2020, 1, 2, 0, 0, 0, 0, time.UTC)
TimeIncrement = time.Second * 5
)
@@ -34,7 +33,7 @@ func NewCoordinator(t *testing.T, n int) *Coordinator {
CurrentTime: globalStartTime,
}
- for i := 0; i < n; i++ {
+ for i := 1; i <= n; i++ {
chainID := GetChainID(i)
chains[chainID] = NewTestChain(t, coord, chainID)
}
diff --git a/testing/endpoint.go b/testing/endpoint.go
index 4c3804879c9..39fe2b4408c 100644
--- a/testing/endpoint.go
+++ b/testing/endpoint.go
@@ -3,7 +3,7 @@ package ibctesting
import (
"fmt"
- // sdk "github.com/cosmos/cosmos-sdk/types"
+ sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/stretchr/testify/require"
clienttypes "github.com/cosmos/ibc-go/v3/modules/core/02-client/types"
@@ -375,6 +375,17 @@ func (endpoint *Endpoint) SendPacket(packet exported.PacketI) error {
// RecvPacket receives a packet on the associated endpoint.
// The counterparty client is updated.
func (endpoint *Endpoint) RecvPacket(packet channeltypes.Packet) error {
+ _, err := endpoint.RecvPacketWithResult(packet)
+ if err != nil {
+ return err
+ }
+
+ return nil
+}
+
+// RecvPacketWithResult receives a packet on the associated endpoint and the result
+// of the transaction is returned. The counterparty client is updated.
+func (endpoint *Endpoint) RecvPacketWithResult(packet channeltypes.Packet) (*sdk.Result, error) {
// get proof of packet commitment on source
packetKey := host.PacketCommitmentKey(packet.GetSourcePort(), packet.GetSourceChannel(), packet.GetSequence())
proof, proofHeight := endpoint.Counterparty.Chain.QueryProof(packetKey)
@@ -382,11 +393,16 @@ func (endpoint *Endpoint) RecvPacket(packet channeltypes.Packet) error {
recvMsg := channeltypes.NewMsgRecvPacket(packet, proof, proofHeight, endpoint.Chain.SenderAccount.GetAddress().String())
// receive on counterparty and update source client
- if err := endpoint.Chain.sendMsgs(recvMsg); err != nil {
- return err
+ res, err := endpoint.Chain.SendMsgs(recvMsg)
+ if err != nil {
+ return nil, err
}
- return endpoint.Counterparty.UpdateClient()
+ if err := endpoint.Counterparty.UpdateClient(); err != nil {
+ return nil, err
+ }
+
+ return res, nil
}
// WriteAcknowledgement writes an acknowledgement on the channel associated with the endpoint.
diff --git a/testing/events.go b/testing/events.go
index 9666a82ffca..037a4c342e3 100644
--- a/testing/events.go
+++ b/testing/events.go
@@ -55,3 +55,18 @@ func ParseChannelIDFromEvents(events sdk.Events) (string, error) {
}
return "", fmt.Errorf("channel identifier event attribute not found")
}
+
+// ParseAckFromEvents parses events emitted from a MsgRecvPacket and returns the
+// acknowledgement.
+func ParseAckFromEvents(events sdk.Events) ([]byte, error) {
+ for _, ev := range events {
+ if ev.Type == channeltypes.EventTypeWriteAck {
+ for _, attr := range ev.Attributes {
+ if string(attr.Key) == channeltypes.AttributeKeyAck {
+ return attr.Value, nil
+ }
+ }
+ }
+ }
+ return nil, fmt.Errorf("acknowledgement event attribute not found")
+}
diff --git a/testing/path.go b/testing/path.go
index d90bc5e1171..d447102c7b9 100644
--- a/testing/path.go
+++ b/testing/path.go
@@ -38,14 +38,20 @@ func (path *Path) SetChannelOrdered() {
// RelayPacket attempts to relay the packet first on EndpointA and then on EndpointB
// if EndpointA does not contain a packet commitment for that packet. An error is returned
// if a relay step fails or the packet commitment does not exist on either endpoint.
-func (path *Path) RelayPacket(packet channeltypes.Packet, ack []byte) error {
+func (path *Path) RelayPacket(packet channeltypes.Packet) error {
pc := path.EndpointA.Chain.App.GetIBCKeeper().ChannelKeeper.GetPacketCommitment(path.EndpointA.Chain.GetContext(), packet.GetSourcePort(), packet.GetSourceChannel(), packet.GetSequence())
if bytes.Equal(pc, channeltypes.CommitPacket(path.EndpointA.Chain.App.AppCodec(), packet)) {
// packet found, relay from A to B
path.EndpointB.UpdateClient()
- if err := path.EndpointB.RecvPacket(packet); err != nil {
+ res, err := path.EndpointB.RecvPacketWithResult(packet)
+ if err != nil {
+ return err
+ }
+
+ ack, err := ParseAckFromEvents(res.GetEvents())
+ if err != nil {
return err
}
@@ -62,9 +68,16 @@ func (path *Path) RelayPacket(packet channeltypes.Packet, ack []byte) error {
// packet found, relay B to A
path.EndpointA.UpdateClient()
- if err := path.EndpointA.RecvPacket(packet); err != nil {
+ res, err := path.EndpointA.RecvPacketWithResult(packet)
+ if err != nil {
return err
}
+
+ ack, err := ParseAckFromEvents(res.GetEvents())
+ if err != nil {
+ return err
+ }
+
if err := path.EndpointB.AcknowledgePacket(packet, ack); err != nil {
return err
}