diff --git a/CHANGELOG.md b/CHANGELOG.md index 8da14958ab4..f608884ba25 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -55,6 +55,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ * (core/04-channel) [\#6023](https://github.com/cosmos/ibc-go/pull/6023) Remove emission of non-hexlified event attributes `packet_data` and `packet_ack`. * (core) [\#6320](https://github.com/cosmos/ibc-go/pull/6320) Remove unnecessary `Proof` interface from `exported` package. * (core/05-port) [\#6341](https://github.com/cosmos/ibc-go/pull/6341) Modify `UnmarshalPacketData` interface to take in the context, portID, and channelID. This allows for packet data's to be unmarshaled based on the channel version. +* (apps/27-interchain-accounts) [\#6433](https://github.com/cosmos/ibc-go/pull/6433) Use UNORDERED as the default ordering for new ICA channels. * (apps/transfer) [\#6440](https://github.com/cosmos/ibc-go/pull/6440) Remove `GetPrefixedDenom`. ### State Machine Breaking @@ -70,6 +71,8 @@ Ref: https://keepachangelog.com/en/1.0.0/ ### Features +* (apps/transfer) [\#6492](https://github.com/cosmos/ibc-go/pull/6492) Added new `Tokens` field to `MsgTransfer` to enable sending of multiple denoms, and deprecated the `Token` field. + ### Bug Fixes ## [v8.3.0](https://github.com/cosmos/ibc-go/releases/tag/v8.3.0) - 2024-05-16 diff --git a/docs/docs/02-apps/01-transfer/04-messages.md b/docs/docs/02-apps/01-transfer/04-messages.md index 483384a09fe..69300985fef 100644 --- a/docs/docs/02-apps/01-transfer/04-messages.md +++ b/docs/docs/02-apps/01-transfer/04-messages.md @@ -15,12 +15,14 @@ A fungible token cross chain transfer is achieved by using the `MsgTransfer`: type MsgTransfer struct { SourcePort string SourceChannel string + // Deprecated: Use Tokens instead. Token sdk.Coin Sender string Receiver string TimeoutHeight ibcexported.Height TimeoutTimestamp uint64 Memo string + Tokens []sdk.Coin } ``` @@ -28,13 +30,15 @@ This message is expected to fail if: - `SourcePort` is invalid (see [24-host naming requirements](https://github.com/cosmos/ibc/blob/master/spec/core/ics-024-host-requirements/README.md#paths-identifiers-separators). - `SourceChannel` is invalid (see [24-host naming requirements](https://github.com/cosmos/ibc/blob/master/spec/core/ics-024-host-requirements/README.md#paths-identifiers-separators)). -- `Token` is invalid (denom is invalid or amount is negative) - - `Token.Amount` is not positive. - - `Token.Denom` is not a valid IBC denomination as per [ADR 001 - Coin Source Tracing](/architecture/adr-001-coin-source-tracing). +- `Tokens` must not be empty. +- Each `Coin` in `Tokens` must satisfy the following: + - `Amount` must be positive. + - `Denom` must be a valid IBC denomination, as defined in [ADR 001 - Coin Source Tracing](/architecture/adr-001-coin-source-tracing). - `Sender` is empty. - `Receiver` is empty. - `TimeoutHeight` and `TimeoutTimestamp` are both zero. +Please note that the `Token` field is deprecated and users should now use `Tokens` instead. If `Token` is used then `Tokens` must be empty. Similarly, if `Tokens` is used then `Token` should be left empty. This message will send a fungible token to the counterparty chain represented by the counterparty Channel End connected to the Channel End with the identifiers `SourcePort` and `SourceChannel`. The denomination provided for transfer should correspond to the same denomination represented on this chain. The prefixes will be added as necessary upon by the receiving chain. diff --git a/docs/docs/02-apps/01-transfer/05-events.md b/docs/docs/02-apps/01-transfer/05-events.md index 9b222ba3820..0619c7379d4 100644 --- a/docs/docs/02-apps/01-transfer/05-events.md +++ b/docs/docs/02-apps/01-transfer/05-events.md @@ -5,7 +5,6 @@ sidebar_position: 5 slug: /apps/transfer/events --- - # Events ## `MsgTransfer` @@ -14,41 +13,41 @@ slug: /apps/transfer/events |--------------|---------------|-----------------| | ibc_transfer | sender | \{sender\} | | ibc_transfer | receiver | \{receiver\} | -| message | action | transfer | +| ibc_transfer | tokens | \{jsonTokens\} | +| ibc_transfer | memo | \{memo\} | | message | module | transfer | ## `OnRecvPacket` callback -| Type | Attribute Key | Attribute Value | -|-----------------------|---------------|-----------------| -| fungible_token_packet | module | transfer | -| fungible_token_packet | sender | \{sender\} | -| fungible_token_packet | receiver | \{receiver\} | -| fungible_token_packet | denom | \{denom\} | -| fungible_token_packet | amount | \{amount\} | -| fungible_token_packet | success | \{ackSuccess\} | -| fungible_token_packet | memo | \{memo\} | -| denomination_trace | trace_hash | \{hex_hash\} | +| Type | Attribute Key | Attribute Value | +|-----------------------|---------------|------------------| +| fungible_token_packet | sender | \{sender\} | +| fungible_token_packet | receiver | \{receiver\} | +| fungible_token_packet | tokens | \{jsonTokens\} | +| fungible_token_packet | success | \{ackSuccess\} | +| fungible_token_packet | error | \{ackError\} | +| fungible_token_packet | memo | \{memo\} | +| denomination | trace_hash | \{hex_hash\} | +| denomination | denom | \{voucherDenom\} | +| message | module | transfer | ## `OnAcknowledgePacket` callback -| Type | Attribute Key | Attribute Value | -|-----------------------|-----------------|-------------------| -| fungible_token_packet | module | transfer | -| fungible_token_packet | sender | \{sender\} | -| fungible_token_packet | receiver | \{receiver\} | -| fungible_token_packet | denom | \{denom\} | -| fungible_token_packet | amount | \{amount\} | -| fungible_token_packet | memo | \{memo\} | -| fungible_token_packet | acknowledgement | \{ack.String()\} | -| fungible_token_packet | success / error | \{ack.Response\} | +| Type | Attribute Key | Attribute Value | +|-----------------------|-----------------|------------------| +| fungible_token_packet | sender | \{sender\} | +| fungible_token_packet | receiver | \{receiver\} | +| fungible_token_packet | tokens | \{jsonTokens\} | +| fungible_token_packet | memo | \{memo\} | +| fungible_token_packet | acknowledgement | \{ack.String()\} | +| fungible_token_packet | success / error | \{ack.Response\} | +| message | module | transfer | ## `OnTimeoutPacket` callback -| Type | Attribute Key | Attribute Value | -|-----------------------|-----------------|-----------------| -| fungible_token_packet | module | transfer | -| fungible_token_packet | refund_receiver | \{receiver\} | -| fungible_token_packet | denom | \{denom\} | -| fungible_token_packet | amount | \{amount\} | -| fungible_token_packet | memo | \{memo\} | +| Type | Attribute Key | Attribute Value | +|---------|-----------------|-----------------| +| timeout | refund_receiver | \{receiver\} | +| timeout | refund_tokens | \{jsonTokens\} | +| timeout | memo | \{memo\} | +| message | module | transfer | diff --git a/docs/docs/02-apps/02-interchain-accounts/09-active-channels.md b/docs/docs/02-apps/02-interchain-accounts/09-active-channels.md index 09ae7063a68..0845c20ebe6 100644 --- a/docs/docs/02-apps/02-interchain-accounts/09-active-channels.md +++ b/docs/docs/02-apps/02-interchain-accounts/09-active-channels.md @@ -11,7 +11,7 @@ The Interchain Accounts module uses either [ORDERED or UNORDERED](https://github When using `ORDERED` channels, the order of transactions when sending packets from a controller to a host chain is maintained. -When using `UNORDERED` channels, there is no guarantee that the order of transactions when sending packets from the controller to the host chain is maintained. +When using `UNORDERED` channels, there is no guarantee that the order of transactions when sending packets from the controller to the host chain is maintained. If no ordering is specified in `MsgRegisterInterchainAccount`, then the default ordering for new ICA channels is `UNORDERED`. > A limitation when using ORDERED channels is that when a packet times out the channel will be closed. diff --git a/docs/docs/02-apps/02-interchain-accounts/10-legacy/03-keeper-api.md b/docs/docs/02-apps/02-interchain-accounts/10-legacy/03-keeper-api.md index 252c7eaf7ff..120bdcd6365 100644 --- a/docs/docs/02-apps/02-interchain-accounts/10-legacy/03-keeper-api.md +++ b/docs/docs/02-apps/02-interchain-accounts/10-legacy/03-keeper-api.md @@ -19,14 +19,14 @@ The controller submodule keeper exposes two legacy functions that allow respecti The authentication module can begin registering interchain accounts by calling `RegisterInterchainAccount`: ```go -if err := keeper.icaControllerKeeper.RegisterInterchainAccount(ctx, connectionID, owner.String(), version); err != nil { +if err := keeper.icaControllerKeeper.RegisterInterchainAccount(ctx, connectionID, owner.String(), version, channeltypes.UNORDERED); err != nil { return err } return nil ``` -The `version` argument is used to support ICS-29 fee middleware for relayer incentivization of ICS-27 packets. Consumers of the `RegisterInterchainAccount` are expected to build the appropriate JSON encoded version string themselves and pass it accordingly. If an empty string is passed in the `version` argument, then the version will be initialized to a default value in the `OnChanOpenInit` callback of the controller's handler, so that channel handshake can proceed. +The `version` argument is used to support ICS-29 fee middleware for relayer incentivization of ICS-27 packets. The `ordering` argument allows to specify the ordering of the channel that is created; if `NONE` is passed, then the default ordering will be `UNORDERED`. Consumers of the `RegisterInterchainAccount` are expected to build the appropriate JSON encoded version string themselves and pass it accordingly. If an empty string is passed in the `version` argument, then the version will be initialized to a default value in the `OnChanOpenInit` callback of the controller's handler, so that channel handshake can proceed. The following code snippet illustrates how to construct an appropriate interchain accounts `Metadata` and encode it as a JSON bytestring: @@ -44,7 +44,7 @@ if err != nil { return err } -if err := keeper.icaControllerKeeper.RegisterInterchainAccount(ctx, controllerConnectionID, owner.String(), string(appVersion)); err != nil { +if err := keeper.icaControllerKeeper.RegisterInterchainAccount(ctx, controllerConnectionID, owner.String(), string(appVersion), channeltypes.UNORDERED); err != nil { return err } ``` @@ -75,7 +75,7 @@ if err != nil { return err } -if err := keeper.icaControllerKeeper.RegisterInterchainAccount(ctx, controllerConnectionID, owner.String(), string(feeEnabledVersion)); err != nil { +if err := keeper.icaControllerKeeper.RegisterInterchainAccount(ctx, controllerConnectionID, owner.String(), string(feeEnabledVersion), channeltypes.UNORDERED); err != nil { return err } ``` diff --git a/docs/docs/05-migrations/13-v8-to-v9.md b/docs/docs/05-migrations/13-v8-to-v9.md index bd67a09515d..ebeb98b477b 100644 --- a/docs/docs/05-migrations/13-v8-to-v9.md +++ b/docs/docs/05-migrations/13-v8-to-v9.md @@ -84,6 +84,17 @@ func NewKeeper( ) Keeper ``` +The legacy function `RegisterInterchainAccount` now takes an extra parameter to specify the ordering of new ICA channels: + +```diff +func (k Keeper) RegisterInterchainAccount( + ctx sdk.Context, + connectionID, owner, + version string, ++ ordering channeltypes.Order +) error { +``` + ## Relayers - Renaming of event attribute keys in [#5603](https://github.com/cosmos/ibc-go/pull/5603). diff --git a/e2e/go.mod b/e2e/go.mod index 81a76304234..95715c11a86 100644 --- a/e2e/go.mod +++ b/e2e/go.mod @@ -9,7 +9,7 @@ replace github.com/strangelove-ventures/interchaintest/v8 => github.com/Dimitris require ( cosmossdk.io/errors v1.0.1 cosmossdk.io/math v1.3.0 - cosmossdk.io/x/upgrade v0.1.2 + cosmossdk.io/x/upgrade v0.1.3 github.com/cometbft/cometbft v0.38.7 github.com/cosmos/cosmos-sdk v0.50.7 github.com/cosmos/gogoproto v1.4.12 @@ -134,7 +134,7 @@ require ( github.com/gtank/merlin v0.1.1 // indirect github.com/gtank/ristretto255 v0.1.2 // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // indirect - github.com/hashicorp/go-getter v1.7.3 // indirect + github.com/hashicorp/go-getter v1.7.4 // indirect github.com/hashicorp/go-hclog v1.6.1 // indirect github.com/hashicorp/go-immutable-radix v1.3.1 // indirect github.com/hashicorp/go-metrics v0.5.3 // indirect diff --git a/e2e/go.sum b/e2e/go.sum index 4390c572a85..d14f64a0d75 100644 --- a/e2e/go.sum +++ b/e2e/go.sum @@ -210,8 +210,8 @@ cosmossdk.io/x/feegrant v0.1.1 h1:EKFWOeo/pup0yF0svDisWWKAA9Zags6Zd0P3nRvVvw8= cosmossdk.io/x/feegrant v0.1.1/go.mod h1:2GjVVxX6G2fta8LWj7pC/ytHjryA6MHAJroBWHFNiEQ= cosmossdk.io/x/tx v0.13.3 h1:Ha4mNaHmxBc6RMun9aKuqul8yHiL78EKJQ8g23Zf73g= cosmossdk.io/x/tx v0.13.3/go.mod h1:I8xaHv0rhUdIvIdptKIqzYy27+n2+zBVaxO6fscFhys= -cosmossdk.io/x/upgrade v0.1.2 h1:O2FGb0mVSXl7P6BQm9uV3hRVKom1zBLDGhd4G8jysJg= -cosmossdk.io/x/upgrade v0.1.2/go.mod h1:P+e4/ZNd8km7lTAX5hC2pXz/042YDcB7gzKTHuY53nc= +cosmossdk.io/x/upgrade v0.1.3 h1:q4XpXc6zp0dX6x74uBtfN6+J7ikaQev5Bla6Q0ADLK8= +cosmossdk.io/x/upgrade v0.1.3/go.mod h1:jOdQhnaY5B8CDUoUbed23/Lre0Dk+r6BMQE40iKlVVQ= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= @@ -681,8 +681,8 @@ github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtng github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= -github.com/hashicorp/go-getter v1.7.3 h1:bN2+Fw9XPFvOCjB0UOevFIMICZ7G2XSQHzfvLUyOM5E= -github.com/hashicorp/go-getter v1.7.3/go.mod h1:W7TalhMmbPmsSMdNjD0ZskARur/9GJ17cfHTRtXV744= +github.com/hashicorp/go-getter v1.7.4 h1:3yQjWuxICvSpYwqSayAdKRFcvBl1y/vogCxczWSmix0= +github.com/hashicorp/go-getter v1.7.4/go.mod h1:W7TalhMmbPmsSMdNjD0ZskARur/9GJ17cfHTRtXV744= github.com/hashicorp/go-hclog v1.6.1 h1:pa92nu9bPoAqI7p+uPDCIWGAibUdlCi6TYWJEQQkLf8= github.com/hashicorp/go-hclog v1.6.1/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= diff --git a/e2e/testsuite/testsuite.go b/e2e/testsuite/testsuite.go index f531d809bb9..5ccefbb64ad 100644 --- a/e2e/testsuite/testsuite.go +++ b/e2e/testsuite/testsuite.go @@ -519,7 +519,7 @@ func (s *E2ETestSuite) InitiateChannelUpgrade(ctx context.Context, chain ibc.Cha // GetIBCToken returns the denomination of the full token denom sent to the receiving channel func GetIBCToken(fullTokenDenom string, portID, channelID string) transfertypes.Denom { - return transfertypes.ExtractDenomFromFullPath(fmt.Sprintf("%s/%s/%s", portID, channelID, fullTokenDenom)) + return transfertypes.ExtractDenomFromPath(fmt.Sprintf("%s/%s/%s", portID, channelID, fullTokenDenom)) } // getValidatorsAndFullNodes returns the number of validators and full nodes respectively that should be used for diff --git a/go.mod b/go.mod index f00901c281c..a80f0970f5d 100644 --- a/go.mod +++ b/go.mod @@ -17,7 +17,7 @@ require ( cosmossdk.io/x/evidence v0.1.1 cosmossdk.io/x/feegrant v0.1.1 cosmossdk.io/x/tx v0.13.3 - cosmossdk.io/x/upgrade v0.1.2 + cosmossdk.io/x/upgrade v0.1.3 github.com/cometbft/cometbft v0.38.7 github.com/cosmos/cosmos-db v1.0.2 github.com/cosmos/cosmos-proto v1.0.0-beta.5 @@ -114,7 +114,7 @@ require ( github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 // indirect github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // indirect - github.com/hashicorp/go-getter v1.7.3 // indirect + github.com/hashicorp/go-getter v1.7.4 // indirect github.com/hashicorp/go-hclog v1.5.0 // indirect github.com/hashicorp/go-immutable-radix v1.3.1 // indirect github.com/hashicorp/go-plugin v1.5.2 // indirect diff --git a/go.sum b/go.sum index 7d8c46ad0ca..c5a4fd09172 100644 --- a/go.sum +++ b/go.sum @@ -212,8 +212,8 @@ cosmossdk.io/x/feegrant v0.1.1 h1:EKFWOeo/pup0yF0svDisWWKAA9Zags6Zd0P3nRvVvw8= cosmossdk.io/x/feegrant v0.1.1/go.mod h1:2GjVVxX6G2fta8LWj7pC/ytHjryA6MHAJroBWHFNiEQ= cosmossdk.io/x/tx v0.13.3 h1:Ha4mNaHmxBc6RMun9aKuqul8yHiL78EKJQ8g23Zf73g= cosmossdk.io/x/tx v0.13.3/go.mod h1:I8xaHv0rhUdIvIdptKIqzYy27+n2+zBVaxO6fscFhys= -cosmossdk.io/x/upgrade v0.1.2 h1:O2FGb0mVSXl7P6BQm9uV3hRVKom1zBLDGhd4G8jysJg= -cosmossdk.io/x/upgrade v0.1.2/go.mod h1:P+e4/ZNd8km7lTAX5hC2pXz/042YDcB7gzKTHuY53nc= +cosmossdk.io/x/upgrade v0.1.3 h1:q4XpXc6zp0dX6x74uBtfN6+J7ikaQev5Bla6Q0ADLK8= +cosmossdk.io/x/upgrade v0.1.3/go.mod h1:jOdQhnaY5B8CDUoUbed23/Lre0Dk+r6BMQE40iKlVVQ= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= filippo.io/edwards25519 v1.0.0 h1:0wAIcmJUqRdI8IJ/3eGi5/HwXZWPujYXXlkrQogz0Ek= filippo.io/edwards25519 v1.0.0/go.mod h1:N1IkdkCkiLB6tki+MYJoSx2JTY9NUlxZE7eHn5EwJns= @@ -650,8 +650,8 @@ github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtng github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= -github.com/hashicorp/go-getter v1.7.3 h1:bN2+Fw9XPFvOCjB0UOevFIMICZ7G2XSQHzfvLUyOM5E= -github.com/hashicorp/go-getter v1.7.3/go.mod h1:W7TalhMmbPmsSMdNjD0ZskARur/9GJ17cfHTRtXV744= +github.com/hashicorp/go-getter v1.7.4 h1:3yQjWuxICvSpYwqSayAdKRFcvBl1y/vogCxczWSmix0= +github.com/hashicorp/go-getter v1.7.4/go.mod h1:W7TalhMmbPmsSMdNjD0ZskARur/9GJ17cfHTRtXV744= github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c= github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= diff --git a/modules/apps/27-interchain-accounts/controller/client/cli/tx.go b/modules/apps/27-interchain-accounts/controller/client/cli/tx.go index 128e990d52d..6b938eaf10b 100644 --- a/modules/apps/27-interchain-accounts/controller/client/cli/tx.go +++ b/modules/apps/27-interchain-accounts/controller/client/cli/tx.go @@ -71,7 +71,7 @@ the associated capability.`), } cmd.Flags().String(flagVersion, "", "Controller chain channel version") - cmd.Flags().String(flagOrdering, channeltypes.ORDERED.String(), fmt.Sprintf("Channel ordering, can be one of: %s", strings.Join(connectiontypes.SupportedOrderings, ", "))) + cmd.Flags().String(flagOrdering, channeltypes.UNORDERED.String(), fmt.Sprintf("Channel ordering, can be one of: %s", strings.Join(connectiontypes.SupportedOrderings, ", "))) flags.AddTxFlagsToCmd(cmd) return cmd diff --git a/modules/apps/27-interchain-accounts/controller/ibc_middleware_test.go b/modules/apps/27-interchain-accounts/controller/ibc_middleware_test.go index e9ab95cc1b9..5daab5aac36 100644 --- a/modules/apps/27-interchain-accounts/controller/ibc_middleware_test.go +++ b/modules/apps/27-interchain-accounts/controller/ibc_middleware_test.go @@ -58,12 +58,12 @@ func (suite *InterchainAccountsTestSuite) SetupTest() { suite.chainC = suite.coordinator.GetChain(ibctesting.GetChainID(3)) } -func NewICAPath(chainA, chainB *ibctesting.TestChain) *ibctesting.Path { +func NewICAPath(chainA, chainB *ibctesting.TestChain, ordering channeltypes.Order) *ibctesting.Path { path := ibctesting.NewPath(chainA, chainB) path.EndpointA.ChannelConfig.PortID = icatypes.HostPortID path.EndpointB.ChannelConfig.PortID = icatypes.HostPortID - path.EndpointA.ChannelConfig.Order = channeltypes.ORDERED - path.EndpointB.ChannelConfig.Order = channeltypes.ORDERED + path.EndpointA.ChannelConfig.Order = ordering + path.EndpointB.ChannelConfig.Order = ordering path.EndpointA.ChannelConfig.Version = TestVersion path.EndpointB.ChannelConfig.Version = TestVersion @@ -78,7 +78,7 @@ func RegisterInterchainAccount(endpoint *ibctesting.Endpoint, owner string) erro channelSequence := endpoint.Chain.App.GetIBCKeeper().ChannelKeeper.GetNextChannelSequence(endpoint.Chain.GetContext()) - if err := endpoint.Chain.GetSimApp().ICAControllerKeeper.RegisterInterchainAccount(endpoint.Chain.GetContext(), endpoint.ConnectionID, owner, TestVersion); err != nil { + if err := endpoint.Chain.GetSimApp().ICAControllerKeeper.RegisterInterchainAccount(endpoint.Chain.GetContext(), endpoint.ConnectionID, owner, TestVersion, endpoint.ChannelConfig.Order); err != nil { return err } @@ -185,67 +185,69 @@ func (suite *InterchainAccountsTestSuite) TestOnChanOpenInit() { }, } - for _, tc := range testCases { - tc := tc + for _, ordering := range []channeltypes.Order{channeltypes.UNORDERED, channeltypes.ORDERED} { + for _, tc := range testCases { + tc := tc - suite.Run(tc.name, func() { - suite.SetupTest() // reset - isNilApp = false + suite.Run(tc.name, func() { + suite.SetupTest() // reset + isNilApp = false - path = NewICAPath(suite.chainA, suite.chainB) - path.SetupConnections() + path = NewICAPath(suite.chainA, suite.chainB, ordering) + path.SetupConnections() - // mock init interchain account - portID, err := icatypes.NewControllerPortID(TestOwnerAddress) - suite.Require().NoError(err) + // mock init interchain account + portID, err := icatypes.NewControllerPortID(TestOwnerAddress) + suite.Require().NoError(err) - portCap := suite.chainA.GetSimApp().IBCKeeper.PortKeeper.BindPort(suite.chainA.GetContext(), portID) - suite.chainA.GetSimApp().ICAControllerKeeper.ClaimCapability(suite.chainA.GetContext(), portCap, host.PortPath(portID)) //nolint:errcheck // checking this error isn't needed for the test + portCap := suite.chainA.GetSimApp().IBCKeeper.PortKeeper.BindPort(suite.chainA.GetContext(), portID) + suite.chainA.GetSimApp().ICAControllerKeeper.ClaimCapability(suite.chainA.GetContext(), portCap, host.PortPath(portID)) //nolint:errcheck // checking this error isn't needed for the test - path.EndpointA.ChannelConfig.PortID = portID - path.EndpointA.ChannelID = ibctesting.FirstChannelID + path.EndpointA.ChannelConfig.PortID = portID + path.EndpointA.ChannelID = ibctesting.FirstChannelID - suite.chainA.GetSimApp().ICAControllerKeeper.SetMiddlewareEnabled(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ConnectionID) + suite.chainA.GetSimApp().ICAControllerKeeper.SetMiddlewareEnabled(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ConnectionID) - // default values - counterparty := channeltypes.NewCounterparty(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID) - channel = &channeltypes.Channel{ - State: channeltypes.INIT, - Ordering: channeltypes.ORDERED, - Counterparty: counterparty, - ConnectionHops: []string{path.EndpointA.ConnectionID}, - Version: path.EndpointA.ChannelConfig.Version, - } + // default values + counterparty := channeltypes.NewCounterparty(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID) + channel = &channeltypes.Channel{ + State: channeltypes.INIT, + Ordering: ordering, + Counterparty: counterparty, + ConnectionHops: []string{path.EndpointA.ConnectionID}, + Version: path.EndpointA.ChannelConfig.Version, + } - tc.malleate() // malleate mutates test data + tc.malleate() // malleate mutates test data - // ensure channel on chainA is set in state - suite.chainA.GetSimApp().IBCKeeper.ChannelKeeper.SetChannel(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, *channel) + // ensure channel on chainA is set in state + suite.chainA.GetSimApp().IBCKeeper.ChannelKeeper.SetChannel(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, *channel) - module, _, err := suite.chainA.App.GetIBCKeeper().PortKeeper.LookupModuleByPort(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID) - suite.Require().NoError(err) + module, _, err := suite.chainA.App.GetIBCKeeper().PortKeeper.LookupModuleByPort(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID) + suite.Require().NoError(err) - chanCap, err := suite.chainA.App.GetScopedIBCKeeper().NewCapability(suite.chainA.GetContext(), host.ChannelCapabilityPath(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID)) - suite.Require().NoError(err) + chanCap, err := suite.chainA.App.GetScopedIBCKeeper().NewCapability(suite.chainA.GetContext(), host.ChannelCapabilityPath(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID)) + suite.Require().NoError(err) - cbs, ok := suite.chainA.App.GetIBCKeeper().PortKeeper.Route(module) - suite.Require().True(ok) + cbs, ok := suite.chainA.App.GetIBCKeeper().PortKeeper.Route(module) + suite.Require().True(ok) - if isNilApp { - cbs = controller.NewIBCMiddleware(nil, suite.chainA.GetSimApp().ICAControllerKeeper) - } + if isNilApp { + cbs = controller.NewIBCMiddleware(nil, suite.chainA.GetSimApp().ICAControllerKeeper) + } - version, err := cbs.OnChanOpenInit(suite.chainA.GetContext(), channel.Ordering, channel.ConnectionHops, - path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, chanCap, channel.Counterparty, channel.Version, - ) + version, err := cbs.OnChanOpenInit(suite.chainA.GetContext(), channel.Ordering, channel.ConnectionHops, + path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, chanCap, channel.Counterparty, channel.Version, + ) - if tc.expPass { - suite.Require().Equal(TestVersion, version) - suite.Require().NoError(err) - } else { - suite.Require().Error(err) - } - }) + if tc.expPass { + suite.Require().Equal(TestVersion, version) + suite.Require().NoError(err) + } else { + suite.Require().Error(err) + } + }) + } } } @@ -256,48 +258,50 @@ func (suite *InterchainAccountsTestSuite) TestOnChanOpenInit() { // core IBC checks not passing, so a call to the application callback is also // done directly. func (suite *InterchainAccountsTestSuite) TestChanOpenTry() { - suite.SetupTest() // reset - path := NewICAPath(suite.chainA, suite.chainB) - path.SetupConnections() + for _, ordering := range []channeltypes.Order{channeltypes.UNORDERED, channeltypes.ORDERED} { + suite.SetupTest() // reset + path := NewICAPath(suite.chainA, suite.chainB, ordering) + path.SetupConnections() - err := RegisterInterchainAccount(path.EndpointA, TestOwnerAddress) - suite.Require().NoError(err) + err := RegisterInterchainAccount(path.EndpointA, TestOwnerAddress) + suite.Require().NoError(err) - // chainB also creates a controller port - err = RegisterInterchainAccount(path.EndpointB, TestOwnerAddress) - suite.Require().NoError(err) + // chainB also creates a controller port + err = RegisterInterchainAccount(path.EndpointB, TestOwnerAddress) + suite.Require().NoError(err) - err = path.EndpointA.UpdateClient() - suite.Require().NoError(err) + err = path.EndpointA.UpdateClient() + suite.Require().NoError(err) - channelKey := host.ChannelKey(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID) - initProof, proofHeight := path.EndpointB.Chain.QueryProof(channelKey) + channelKey := host.ChannelKey(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID) + initProof, proofHeight := path.EndpointB.Chain.QueryProof(channelKey) - // use chainA (controller) for ChanOpenTry - msg := channeltypes.NewMsgChannelOpenTry(path.EndpointA.ChannelConfig.PortID, TestVersion, channeltypes.ORDERED, []string{path.EndpointA.ConnectionID}, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, TestVersion, initProof, proofHeight, icatypes.ModuleName) - handler := suite.chainA.GetSimApp().MsgServiceRouter().Handler(msg) - _, err = handler(suite.chainA.GetContext(), msg) + // use chainA (controller) for ChanOpenTry + msg := channeltypes.NewMsgChannelOpenTry(path.EndpointA.ChannelConfig.PortID, TestVersion, ordering, []string{path.EndpointA.ConnectionID}, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, TestVersion, initProof, proofHeight, icatypes.ModuleName) + handler := suite.chainA.GetSimApp().MsgServiceRouter().Handler(msg) + _, err = handler(suite.chainA.GetContext(), msg) - suite.Require().Error(err) + suite.Require().Error(err) - // call application callback directly - module, _, err := suite.chainA.App.GetIBCKeeper().PortKeeper.LookupModuleByPort(suite.chainA.GetContext(), path.EndpointB.ChannelConfig.PortID) - suite.Require().NoError(err) + // call application callback directly + module, _, err := suite.chainA.App.GetIBCKeeper().PortKeeper.LookupModuleByPort(suite.chainA.GetContext(), path.EndpointB.ChannelConfig.PortID) + suite.Require().NoError(err) - cbs, ok := suite.chainA.App.GetIBCKeeper().PortKeeper.Route(module) - suite.Require().True(ok) + cbs, ok := suite.chainA.App.GetIBCKeeper().PortKeeper.Route(module) + suite.Require().True(ok) - counterparty := channeltypes.NewCounterparty(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID) - chanCap, found := suite.chainA.App.GetScopedIBCKeeper().GetCapability(suite.chainA.GetContext(), host.ChannelCapabilityPath(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID)) - suite.Require().True(found) + counterparty := channeltypes.NewCounterparty(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID) + chanCap, found := suite.chainA.App.GetScopedIBCKeeper().GetCapability(suite.chainA.GetContext(), host.ChannelCapabilityPath(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID)) + suite.Require().True(found) - version, err := cbs.OnChanOpenTry( - suite.chainA.GetContext(), path.EndpointA.ChannelConfig.Order, []string{path.EndpointA.ConnectionID}, - path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, chanCap, - counterparty, path.EndpointB.ChannelConfig.Version, - ) - suite.Require().Error(err) - suite.Require().Equal("", version) + version, err := cbs.OnChanOpenTry( + suite.chainA.GetContext(), path.EndpointA.ChannelConfig.Order, []string{path.EndpointA.ConnectionID}, + path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, chanCap, + counterparty, path.EndpointB.ChannelConfig.Version, + ) + suite.Require().Error(err) + suite.Require().Equal("", version) + } } func (suite *InterchainAccountsTestSuite) TestOnChanOpenAck() { @@ -351,42 +355,44 @@ func (suite *InterchainAccountsTestSuite) TestOnChanOpenAck() { }, } - for _, tc := range testCases { - tc := tc + for _, ordering := range []channeltypes.Order{channeltypes.UNORDERED, channeltypes.ORDERED} { + for _, tc := range testCases { + tc := tc - suite.Run(tc.name, func() { - suite.SetupTest() // reset - isNilApp = false + suite.Run(tc.name, func() { + suite.SetupTest() // reset + isNilApp = false - path = NewICAPath(suite.chainA, suite.chainB) - path.SetupConnections() + path = NewICAPath(suite.chainA, suite.chainB, ordering) + path.SetupConnections() - err := RegisterInterchainAccount(path.EndpointA, TestOwnerAddress) - suite.Require().NoError(err) + err := RegisterInterchainAccount(path.EndpointA, TestOwnerAddress) + suite.Require().NoError(err) - err = path.EndpointB.ChanOpenTry() - suite.Require().NoError(err) + err = path.EndpointB.ChanOpenTry() + suite.Require().NoError(err) - tc.malleate() // malleate mutates test data + tc.malleate() // malleate mutates test data - module, _, err := suite.chainA.App.GetIBCKeeper().PortKeeper.LookupModuleByPort(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID) - suite.Require().NoError(err) + module, _, err := suite.chainA.App.GetIBCKeeper().PortKeeper.LookupModuleByPort(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID) + suite.Require().NoError(err) - cbs, ok := suite.chainA.App.GetIBCKeeper().PortKeeper.Route(module) - suite.Require().True(ok) + cbs, ok := suite.chainA.App.GetIBCKeeper().PortKeeper.Route(module) + suite.Require().True(ok) - err = cbs.OnChanOpenAck(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelID, path.EndpointB.ChannelConfig.Version) + err = cbs.OnChanOpenAck(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelID, path.EndpointB.ChannelConfig.Version) - if isNilApp { - cbs = controller.NewIBCMiddleware(nil, suite.chainA.GetSimApp().ICAControllerKeeper) - } + if isNilApp { + cbs = controller.NewIBCMiddleware(nil, suite.chainA.GetSimApp().ICAControllerKeeper) + } - if tc.expPass { - suite.Require().NoError(err) - } else { - suite.Require().Error(err) - } - }) + if tc.expPass { + suite.Require().NoError(err) + } else { + suite.Require().Error(err) + } + }) + } } } @@ -396,69 +402,75 @@ func (suite *InterchainAccountsTestSuite) TestOnChanOpenAck() { // core IBC checks not passing, so a call to the application callback is also // done directly. func (suite *InterchainAccountsTestSuite) TestChanOpenConfirm() { - suite.SetupTest() // reset - path := NewICAPath(suite.chainA, suite.chainB) - path.SetupConnections() + for _, ordering := range []channeltypes.Order{channeltypes.UNORDERED, channeltypes.ORDERED} { + suite.SetupTest() // reset + path := NewICAPath(suite.chainA, suite.chainB, ordering) + path.SetupConnections() - err := RegisterInterchainAccount(path.EndpointA, TestOwnerAddress) - suite.Require().NoError(err) + err := RegisterInterchainAccount(path.EndpointA, TestOwnerAddress) + suite.Require().NoError(err) - err = path.EndpointB.ChanOpenTry() - suite.Require().NoError(err) + err = path.EndpointB.ChanOpenTry() + suite.Require().NoError(err) - // chainB maliciously sets channel to OPEN - channel := channeltypes.NewChannel(channeltypes.OPEN, channeltypes.ORDERED, channeltypes.NewCounterparty(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID), []string{path.EndpointB.ConnectionID}, TestVersion) - suite.chainB.GetSimApp().GetIBCKeeper().ChannelKeeper.SetChannel(suite.chainB.GetContext(), path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, channel) + // chainB maliciously sets channel to OPEN + channel := channeltypes.NewChannel(channeltypes.OPEN, ordering, channeltypes.NewCounterparty(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID), []string{path.EndpointB.ConnectionID}, TestVersion) + suite.chainB.GetSimApp().GetIBCKeeper().ChannelKeeper.SetChannel(suite.chainB.GetContext(), path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, channel) - // commit state changes so proof can be created - suite.chainB.NextBlock() + // commit state changes so proof can be created + suite.chainB.NextBlock() - err = path.EndpointA.UpdateClient() - suite.Require().NoError(err) + err = path.EndpointA.UpdateClient() + suite.Require().NoError(err) - // query proof from ChainB - channelKey := host.ChannelKey(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID) - ackProof, proofHeight := path.EndpointB.Chain.QueryProof(channelKey) + // query proof from ChainB + channelKey := host.ChannelKey(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID) + ackProof, proofHeight := path.EndpointB.Chain.QueryProof(channelKey) - // use chainA (controller) for ChanOpenConfirm - msg := channeltypes.NewMsgChannelOpenConfirm(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, ackProof, proofHeight, icatypes.ModuleName) - handler := suite.chainA.GetSimApp().MsgServiceRouter().Handler(msg) - _, err = handler(suite.chainA.GetContext(), msg) + // use chainA (controller) for ChanOpenConfirm + msg := channeltypes.NewMsgChannelOpenConfirm(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, ackProof, proofHeight, icatypes.ModuleName) + handler := suite.chainA.GetSimApp().MsgServiceRouter().Handler(msg) + _, err = handler(suite.chainA.GetContext(), msg) - suite.Require().Error(err) + suite.Require().Error(err) - // call application callback directly - module, _, err := suite.chainA.App.GetIBCKeeper().PortKeeper.LookupModuleByPort(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID) - suite.Require().NoError(err) + // call application callback directly + module, _, err := suite.chainA.App.GetIBCKeeper().PortKeeper.LookupModuleByPort(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID) + suite.Require().NoError(err) - cbs, ok := suite.chainA.App.GetIBCKeeper().PortKeeper.Route(module) - suite.Require().True(ok) + cbs, ok := suite.chainA.App.GetIBCKeeper().PortKeeper.Route(module) + suite.Require().True(ok) - err = cbs.OnChanOpenConfirm( - suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, - ) - suite.Require().Error(err) + err = cbs.OnChanOpenConfirm( + suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, + ) + suite.Require().Error(err) + } } // OnChanCloseInit on controller (chainA) func (suite *InterchainAccountsTestSuite) TestOnChanCloseInit() { - path := NewICAPath(suite.chainA, suite.chainB) - path.SetupConnections() + for _, ordering := range []channeltypes.Order{channeltypes.UNORDERED, channeltypes.ORDERED} { + suite.SetupTest() // reset - err := SetupICAPath(path, TestOwnerAddress) - suite.Require().NoError(err) + path := NewICAPath(suite.chainA, suite.chainB, ordering) + path.SetupConnections() - module, _, err := suite.chainA.App.GetIBCKeeper().PortKeeper.LookupModuleByPort(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID) - suite.Require().NoError(err) + err := SetupICAPath(path, TestOwnerAddress) + suite.Require().NoError(err) - cbs, ok := suite.chainA.App.GetIBCKeeper().PortKeeper.Route(module) - suite.Require().True(ok) + module, _, err := suite.chainA.App.GetIBCKeeper().PortKeeper.LookupModuleByPort(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID) + suite.Require().NoError(err) - err = cbs.OnChanCloseInit( - suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, - ) + cbs, ok := suite.chainA.App.GetIBCKeeper().PortKeeper.Route(module) + suite.Require().True(ok) + + err = cbs.OnChanCloseInit( + suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, + ) - suite.Require().Error(err) + suite.Require().Error(err) + } } func (suite *InterchainAccountsTestSuite) TestOnChanCloseConfirm() { @@ -482,39 +494,41 @@ func (suite *InterchainAccountsTestSuite) TestOnChanCloseConfirm() { }, } - for _, tc := range testCases { - tc := tc + for _, ordering := range []channeltypes.Order{channeltypes.UNORDERED, channeltypes.ORDERED} { + for _, tc := range testCases { + tc := tc - suite.Run(tc.name, func() { - suite.SetupTest() // reset - isNilApp = false + suite.Run(tc.name, func() { + suite.SetupTest() // reset + isNilApp = false - path = NewICAPath(suite.chainA, suite.chainB) - path.SetupConnections() + path = NewICAPath(suite.chainA, suite.chainB, ordering) + path.SetupConnections() - err := SetupICAPath(path, TestOwnerAddress) - suite.Require().NoError(err) + err := SetupICAPath(path, TestOwnerAddress) + suite.Require().NoError(err) - tc.malleate() // malleate mutates test data - module, _, err := suite.chainA.App.GetIBCKeeper().PortKeeper.LookupModuleByPort(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID) - suite.Require().NoError(err) + tc.malleate() // malleate mutates test data + module, _, err := suite.chainA.App.GetIBCKeeper().PortKeeper.LookupModuleByPort(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID) + suite.Require().NoError(err) - cbs, ok := suite.chainA.App.GetIBCKeeper().PortKeeper.Route(module) - suite.Require().True(ok) + cbs, ok := suite.chainA.App.GetIBCKeeper().PortKeeper.Route(module) + suite.Require().True(ok) - if isNilApp { - cbs = controller.NewIBCMiddleware(nil, suite.chainA.GetSimApp().ICAControllerKeeper) - } + if isNilApp { + cbs = controller.NewIBCMiddleware(nil, suite.chainA.GetSimApp().ICAControllerKeeper) + } - err = cbs.OnChanCloseConfirm( - suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) + err = cbs.OnChanCloseConfirm( + suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) - if tc.expPass { - suite.Require().NoError(err) - } else { - suite.Require().Error(err) - } - }) + if tc.expPass { + suite.Require().NoError(err) + } else { + suite.Require().Error(err) + } + }) + } } } @@ -529,54 +543,56 @@ func (suite *InterchainAccountsTestSuite) TestOnRecvPacket() { }, } - for _, tc := range testCases { - tc := tc - - suite.Run(tc.name, func() { - suite.SetupTest() // reset - - path := NewICAPath(suite.chainA, suite.chainB) - path.SetupConnections() - - err := SetupICAPath(path, TestOwnerAddress) - suite.Require().NoError(err) - - tc.malleate() // malleate mutates test data - - module, _, err := suite.chainA.App.GetIBCKeeper().PortKeeper.LookupModuleByPort(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID) - suite.Require().NoError(err) - - cbs, ok := suite.chainA.App.GetIBCKeeper().PortKeeper.Route(module) - suite.Require().True(ok) - - packet := channeltypes.NewPacket( - []byte("empty packet data"), - suite.chainB.SenderAccount.GetSequence(), - path.EndpointB.ChannelConfig.PortID, - path.EndpointB.ChannelID, - path.EndpointA.ChannelConfig.PortID, - path.EndpointA.ChannelID, - clienttypes.NewHeight(0, 100), - 0, - ) - - ctx := suite.chainA.GetContext() - ack := cbs.OnRecvPacket(ctx, packet, nil) - suite.Require().Equal(tc.expPass, ack.Success()) - - expectedEvents := sdk.Events{ - sdk.NewEvent( - icatypes.EventTypePacket, - sdk.NewAttribute(sdk.AttributeKeyModule, icatypes.ModuleName), - sdk.NewAttribute(icatypes.AttributeKeyControllerChannelID, packet.GetDestChannel()), - sdk.NewAttribute(icatypes.AttributeKeyAckSuccess, fmt.Sprintf("%t", false)), - sdk.NewAttribute(icatypes.AttributeKeyAckError, "cannot receive packet on controller chain: invalid message sent to channel end"), - ), - }.ToABCIEvents() - - expectedEvents = sdk.MarkEventsToIndex(expectedEvents, map[string]struct{}{}) - ibctesting.AssertEvents(&suite.Suite, expectedEvents, ctx.EventManager().Events().ToABCIEvents()) - }) + for _, ordering := range []channeltypes.Order{channeltypes.UNORDERED, channeltypes.ORDERED} { + for _, tc := range testCases { + tc := tc + + suite.Run(tc.name, func() { + suite.SetupTest() // reset + + path := NewICAPath(suite.chainA, suite.chainB, ordering) + path.SetupConnections() + + err := SetupICAPath(path, TestOwnerAddress) + suite.Require().NoError(err) + + tc.malleate() // malleate mutates test data + + module, _, err := suite.chainA.App.GetIBCKeeper().PortKeeper.LookupModuleByPort(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID) + suite.Require().NoError(err) + + cbs, ok := suite.chainA.App.GetIBCKeeper().PortKeeper.Route(module) + suite.Require().True(ok) + + packet := channeltypes.NewPacket( + []byte("empty packet data"), + suite.chainB.SenderAccount.GetSequence(), + path.EndpointB.ChannelConfig.PortID, + path.EndpointB.ChannelID, + path.EndpointA.ChannelConfig.PortID, + path.EndpointA.ChannelID, + clienttypes.NewHeight(0, 100), + 0, + ) + + ctx := suite.chainA.GetContext() + ack := cbs.OnRecvPacket(ctx, packet, nil) + suite.Require().Equal(tc.expPass, ack.Success()) + + expectedEvents := sdk.Events{ + sdk.NewEvent( + icatypes.EventTypePacket, + sdk.NewAttribute(sdk.AttributeKeyModule, icatypes.ModuleName), + sdk.NewAttribute(icatypes.AttributeKeyControllerChannelID, packet.GetDestChannel()), + sdk.NewAttribute(icatypes.AttributeKeyAckSuccess, fmt.Sprintf("%t", false)), + sdk.NewAttribute(icatypes.AttributeKeyAckError, "cannot receive packet on controller chain: invalid message sent to channel end"), + ), + }.ToABCIEvents() + + expectedEvents = sdk.MarkEventsToIndex(expectedEvents, map[string]struct{}{}) + ibctesting.AssertEvents(&suite.Suite, expectedEvents, ctx.EventManager().Events().ToABCIEvents()) + }) + } } } @@ -628,50 +644,52 @@ func (suite *InterchainAccountsTestSuite) TestOnAcknowledgementPacket() { }, } - for _, tc := range testCases { - tc := tc + for _, ordering := range []channeltypes.Order{channeltypes.UNORDERED, channeltypes.ORDERED} { + for _, tc := range testCases { + tc := tc - suite.Run(tc.msg, func() { - suite.SetupTest() // reset - isNilApp = false + suite.Run(tc.msg, func() { + suite.SetupTest() // reset + isNilApp = false - path = NewICAPath(suite.chainA, suite.chainB) - path.SetupConnections() + path = NewICAPath(suite.chainA, suite.chainB, ordering) + path.SetupConnections() - err := SetupICAPath(path, TestOwnerAddress) - suite.Require().NoError(err) + err := SetupICAPath(path, TestOwnerAddress) + suite.Require().NoError(err) - packet := channeltypes.NewPacket( - []byte("empty packet data"), - suite.chainA.SenderAccount.GetSequence(), - path.EndpointA.ChannelConfig.PortID, - path.EndpointA.ChannelID, - path.EndpointB.ChannelConfig.PortID, - path.EndpointB.ChannelID, - clienttypes.NewHeight(0, 100), - 0, - ) + packet := channeltypes.NewPacket( + []byte("empty packet data"), + suite.chainA.SenderAccount.GetSequence(), + path.EndpointA.ChannelConfig.PortID, + path.EndpointA.ChannelID, + path.EndpointB.ChannelConfig.PortID, + path.EndpointB.ChannelID, + clienttypes.NewHeight(0, 100), + 0, + ) - tc.malleate() // malleate mutates test data + tc.malleate() // malleate mutates test data - module, _, err := suite.chainA.App.GetIBCKeeper().PortKeeper.LookupModuleByPort(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID) - suite.Require().NoError(err) + module, _, err := suite.chainA.App.GetIBCKeeper().PortKeeper.LookupModuleByPort(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID) + suite.Require().NoError(err) - cbs, ok := suite.chainA.App.GetIBCKeeper().PortKeeper.Route(module) - suite.Require().True(ok) + cbs, ok := suite.chainA.App.GetIBCKeeper().PortKeeper.Route(module) + suite.Require().True(ok) - if isNilApp { - cbs = controller.NewIBCMiddleware(nil, suite.chainA.GetSimApp().ICAControllerKeeper) - } + if isNilApp { + cbs = controller.NewIBCMiddleware(nil, suite.chainA.GetSimApp().ICAControllerKeeper) + } - err = cbs.OnAcknowledgementPacket(suite.chainA.GetContext(), packet, []byte("ack"), nil) + err = cbs.OnAcknowledgementPacket(suite.chainA.GetContext(), packet, []byte("ack"), nil) - if tc.expPass { - suite.Require().NoError(err) - } else { - suite.Require().Error(err) - } - }) + if tc.expPass { + suite.Require().NoError(err) + } else { + suite.Require().Error(err) + } + }) + } } } @@ -723,59 +741,60 @@ func (suite *InterchainAccountsTestSuite) TestOnTimeoutPacket() { }, } - for _, tc := range testCases { - tc := tc + for _, ordering := range []channeltypes.Order{channeltypes.UNORDERED, channeltypes.ORDERED} { + for _, tc := range testCases { + tc := tc - suite.Run(tc.msg, func() { - suite.SetupTest() // reset - isNilApp = false + suite.Run(tc.msg, func() { + suite.SetupTest() // reset + isNilApp = false - path = NewICAPath(suite.chainA, suite.chainB) - path.SetupConnections() + path = NewICAPath(suite.chainA, suite.chainB, ordering) + path.SetupConnections() - err := SetupICAPath(path, TestOwnerAddress) - suite.Require().NoError(err) + err := SetupICAPath(path, TestOwnerAddress) + suite.Require().NoError(err) - packet := channeltypes.NewPacket( - []byte("empty packet data"), - suite.chainA.SenderAccount.GetSequence(), - path.EndpointA.ChannelConfig.PortID, - path.EndpointA.ChannelID, - path.EndpointB.ChannelConfig.PortID, - path.EndpointB.ChannelID, - clienttypes.NewHeight(0, 100), - 0, - ) + packet := channeltypes.NewPacket( + []byte("empty packet data"), + suite.chainA.SenderAccount.GetSequence(), + path.EndpointA.ChannelConfig.PortID, + path.EndpointA.ChannelID, + path.EndpointB.ChannelConfig.PortID, + path.EndpointB.ChannelID, + clienttypes.NewHeight(0, 100), + 0, + ) - tc.malleate() // malleate mutates test data + tc.malleate() // malleate mutates test data - module, _, err := suite.chainA.App.GetIBCKeeper().PortKeeper.LookupModuleByPort(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID) - suite.Require().NoError(err) + module, _, err := suite.chainA.App.GetIBCKeeper().PortKeeper.LookupModuleByPort(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID) + suite.Require().NoError(err) - cbs, ok := suite.chainA.App.GetIBCKeeper().PortKeeper.Route(module) - suite.Require().True(ok) + cbs, ok := suite.chainA.App.GetIBCKeeper().PortKeeper.Route(module) + suite.Require().True(ok) - if isNilApp { - cbs = controller.NewIBCMiddleware(nil, suite.chainA.GetSimApp().ICAControllerKeeper) - } + if isNilApp { + cbs = controller.NewIBCMiddleware(nil, suite.chainA.GetSimApp().ICAControllerKeeper) + } - err = cbs.OnTimeoutPacket(suite.chainA.GetContext(), packet, nil) + err = cbs.OnTimeoutPacket(suite.chainA.GetContext(), packet, nil) - if tc.expPass { - suite.Require().NoError(err) - } else { - suite.Require().Error(err) - } - }) + if tc.expPass { + suite.Require().NoError(err) + } else { + suite.Require().Error(err) + } + }) + } } } func (suite *InterchainAccountsTestSuite) TestOnChanUpgradeInit() { var ( - path *ibctesting.Path - isNilApp bool - version string - channelOrder channeltypes.Order + path *ibctesting.Path + isNilApp bool + version string ) testCases := []struct { @@ -784,12 +803,7 @@ func (suite *InterchainAccountsTestSuite) TestOnChanUpgradeInit() { expError error }{ { - "success w/ ORDERED channel", func() {}, nil, - }, - { - "success w/ UNORDERED channel", func() { - channelOrder = channeltypes.UNORDERED - }, nil, + "success", func() {}, nil, }, { "success: nil underlying app", @@ -825,81 +839,83 @@ func (suite *InterchainAccountsTestSuite) TestOnChanUpgradeInit() { }, } - for _, tc := range testCases { - tc := tc - - suite.Run(tc.name, func() { - suite.SetupTest() // reset - isNilApp = false + for _, ordering := range []channeltypes.Order{channeltypes.UNORDERED, channeltypes.ORDERED} { + for _, tc := range testCases { + tc := tc - path = NewICAPath(suite.chainA, suite.chainB) - path.SetupConnections() + suite.Run(tc.name, func() { + suite.SetupTest() // reset + isNilApp = false - err := RegisterInterchainAccount(path.EndpointA, TestOwnerAddress) - suite.Require().NoError(err) + path = NewICAPath(suite.chainA, suite.chainB, ordering) + path.SetupConnections() - version = icatypes.NewDefaultMetadataString(path.EndpointA.ConnectionID, path.EndpointB.ConnectionID) + err := RegisterInterchainAccount(path.EndpointA, TestOwnerAddress) + suite.Require().NoError(err) - tc.malleate() // malleate mutates test data + version = icatypes.NewDefaultMetadataString(path.EndpointA.ConnectionID, path.EndpointB.ConnectionID) - module, _, err := suite.chainA.App.GetIBCKeeper().PortKeeper.LookupModuleByPort(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID) - suite.Require().NoError(err) + tc.malleate() // malleate mutates test data - app, ok := suite.chainA.App.GetIBCKeeper().PortKeeper.Route(module) - suite.Require().True(ok) - cbs, ok := app.(porttypes.UpgradableModule) - suite.Require().True(ok) + module, _, err := suite.chainA.App.GetIBCKeeper().PortKeeper.LookupModuleByPort(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID) + suite.Require().NoError(err) - if isNilApp { - cbs = controller.NewIBCMiddleware(nil, suite.chainA.GetSimApp().ICAControllerKeeper) - } + app, ok := suite.chainA.App.GetIBCKeeper().PortKeeper.Route(module) + suite.Require().True(ok) + cbs, ok := app.(porttypes.UpgradableModule) + suite.Require().True(ok) - channelOrder = channeltypes.ORDERED + if isNilApp { + cbs = controller.NewIBCMiddleware(nil, suite.chainA.GetSimApp().ICAControllerKeeper) + } - version, err = cbs.OnChanUpgradeInit( - suite.chainA.GetContext(), - path.EndpointA.ChannelConfig.PortID, - path.EndpointA.ChannelID, - channelOrder, - []string{path.EndpointA.ConnectionID}, - version, - ) + version, err = cbs.OnChanUpgradeInit( + suite.chainA.GetContext(), + path.EndpointA.ChannelConfig.PortID, + path.EndpointA.ChannelID, + ordering, + []string{path.EndpointA.ConnectionID}, + version, + ) - if tc.expError == nil { - suite.Require().NoError(err) - } else { - suite.Require().ErrorIs(err, tc.expError) - suite.Require().Empty(version) - } - }) + if tc.expError == nil { + suite.Require().NoError(err) + } else { + suite.Require().ErrorIs(err, tc.expError) + suite.Require().Empty(version) + } + }) + } } } // OnChanUpgradeTry callback returns error on controller chains func (suite *InterchainAccountsTestSuite) TestOnChanUpgradeTry() { - suite.SetupTest() // reset - path := NewICAPath(suite.chainA, suite.chainB) - path.SetupConnections() - - err := SetupICAPath(path, TestOwnerAddress) - suite.Require().NoError(err) - - // call application callback directly - module, _, err := suite.chainA.App.GetIBCKeeper().PortKeeper.LookupModuleByPort(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID) - suite.Require().NoError(err) - - app, ok := suite.chainA.App.GetIBCKeeper().PortKeeper.Route(module) - suite.Require().True(ok) - cbs, ok := app.(porttypes.UpgradableModule) - suite.Require().True(ok) - - version, err := cbs.OnChanUpgradeTry( - suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, - path.EndpointA.ChannelConfig.Order, []string{path.EndpointA.ConnectionID}, path.EndpointB.ChannelConfig.Version, - ) - suite.Require().Error(err) - suite.Require().ErrorIs(err, icatypes.ErrInvalidChannelFlow) - suite.Require().Equal("", version) + for _, ordering := range []channeltypes.Order{channeltypes.UNORDERED, channeltypes.ORDERED} { + suite.SetupTest() // reset + path := NewICAPath(suite.chainA, suite.chainB, ordering) + path.SetupConnections() + + err := SetupICAPath(path, TestOwnerAddress) + suite.Require().NoError(err) + + // call application callback directly + module, _, err := suite.chainA.App.GetIBCKeeper().PortKeeper.LookupModuleByPort(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID) + suite.Require().NoError(err) + + app, ok := suite.chainA.App.GetIBCKeeper().PortKeeper.Route(module) + suite.Require().True(ok) + cbs, ok := app.(porttypes.UpgradableModule) + suite.Require().True(ok) + + version, err := cbs.OnChanUpgradeTry( + suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, + path.EndpointA.ChannelConfig.Order, []string{path.EndpointA.ConnectionID}, path.EndpointB.ChannelConfig.Version, + ) + suite.Require().Error(err) + suite.Require().ErrorIs(err, icatypes.ErrInvalidChannelFlow) + suite.Require().Equal("", version) + } } func (suite *InterchainAccountsTestSuite) TestOnChanUpgradeAck() { @@ -951,48 +967,50 @@ func (suite *InterchainAccountsTestSuite) TestOnChanUpgradeAck() { }, } - for _, tc := range testCases { - tc := tc + for _, ordering := range []channeltypes.Order{channeltypes.UNORDERED, channeltypes.ORDERED} { + for _, tc := range testCases { + tc := tc - suite.Run(tc.name, func() { - suite.SetupTest() // reset - isNilApp = false + suite.Run(tc.name, func() { + suite.SetupTest() // reset + isNilApp = false - path = NewICAPath(suite.chainA, suite.chainB) - path.SetupConnections() + path = NewICAPath(suite.chainA, suite.chainB, ordering) + path.SetupConnections() - err := SetupICAPath(path, TestOwnerAddress) - suite.Require().NoError(err) + err := SetupICAPath(path, TestOwnerAddress) + suite.Require().NoError(err) - counterpartyVersion = path.EndpointB.GetChannel().Version + counterpartyVersion = path.EndpointB.GetChannel().Version - tc.malleate() // malleate mutates test data + tc.malleate() // malleate mutates test data - module, _, err := suite.chainA.App.GetIBCKeeper().PortKeeper.LookupModuleByPort(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID) - suite.Require().NoError(err) + module, _, err := suite.chainA.App.GetIBCKeeper().PortKeeper.LookupModuleByPort(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID) + suite.Require().NoError(err) - app, ok := suite.chainA.App.GetIBCKeeper().PortKeeper.Route(module) - suite.Require().True(ok) - cbs, ok := app.(porttypes.UpgradableModule) - suite.Require().True(ok) + app, ok := suite.chainA.App.GetIBCKeeper().PortKeeper.Route(module) + suite.Require().True(ok) + cbs, ok := app.(porttypes.UpgradableModule) + suite.Require().True(ok) - if isNilApp { - cbs = controller.NewIBCMiddleware(nil, suite.chainA.GetSimApp().ICAControllerKeeper) - } + if isNilApp { + cbs = controller.NewIBCMiddleware(nil, suite.chainA.GetSimApp().ICAControllerKeeper) + } - err = cbs.OnChanUpgradeAck( - suite.chainA.GetContext(), - path.EndpointA.ChannelConfig.PortID, - path.EndpointA.ChannelID, - counterpartyVersion, - ) + err = cbs.OnChanUpgradeAck( + suite.chainA.GetContext(), + path.EndpointA.ChannelConfig.PortID, + path.EndpointA.ChannelID, + counterpartyVersion, + ) - if tc.expError == nil { - suite.Require().NoError(err) - } else { - suite.Require().ErrorIs(err, tc.expError) - } - }) + if tc.expError == nil { + suite.Require().NoError(err) + } else { + suite.Require().ErrorIs(err, tc.expError) + } + }) + } } } @@ -1001,7 +1019,6 @@ func (suite *InterchainAccountsTestSuite) TestOnChanUpgradeOpen() { path *ibctesting.Path isNilApp bool counterpartyVersion string - channelOrder channeltypes.Order ) testCases := []struct { @@ -1010,13 +1027,7 @@ func (suite *InterchainAccountsTestSuite) TestOnChanUpgradeOpen() { expPanic error }{ { - "success w/ ORDERED channel", func() {}, nil, - }, - { - "success w/ UNORDERED channel", func() { - channelOrder = channeltypes.UNORDERED - }, - nil, + "success", func() {}, nil, }, { "success: nil app", func() { @@ -1046,56 +1057,58 @@ func (suite *InterchainAccountsTestSuite) TestOnChanUpgradeOpen() { }, } - for _, tc := range testCases { - tc := tc + for _, ordering := range []channeltypes.Order{channeltypes.UNORDERED, channeltypes.ORDERED} { + for _, tc := range testCases { + tc := tc - suite.Run(tc.name, func() { - suite.SetupTest() // reset - isNilApp = false + suite.Run(tc.name, func() { + suite.SetupTest() // reset + isNilApp = false - path = NewICAPath(suite.chainA, suite.chainB) - path.SetupConnections() + path = NewICAPath(suite.chainA, suite.chainB, ordering) + path.SetupConnections() - err := SetupICAPath(path, TestOwnerAddress) - suite.Require().NoError(err) + err := SetupICAPath(path, TestOwnerAddress) + suite.Require().NoError(err) - counterpartyVersion = path.EndpointB.GetChannel().Version + counterpartyVersion = path.EndpointB.GetChannel().Version - tc.malleate() // malleate mutates test data + tc.malleate() // malleate mutates test data - module, _, err := suite.chainA.App.GetIBCKeeper().PortKeeper.LookupModuleByPort(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID) - suite.Require().NoError(err) + module, _, err := suite.chainA.App.GetIBCKeeper().PortKeeper.LookupModuleByPort(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID) + suite.Require().NoError(err) - app, ok := suite.chainA.App.GetIBCKeeper().PortKeeper.Route(module) - suite.Require().True(ok) - cbs, ok := app.(porttypes.UpgradableModule) - suite.Require().True(ok) + app, ok := suite.chainA.App.GetIBCKeeper().PortKeeper.Route(module) + suite.Require().True(ok) + cbs, ok := app.(porttypes.UpgradableModule) + suite.Require().True(ok) + + upgradeOpenCb := func(cbs porttypes.UpgradableModule) { + cbs.OnChanUpgradeOpen( + suite.chainA.GetContext(), + path.EndpointA.ChannelConfig.PortID, + path.EndpointA.ChannelID, + ordering, + []string{path.EndpointA.ConnectionID}, + counterpartyVersion, + ) + } - upgradeOpenCb := func(cbs porttypes.UpgradableModule) { - cbs.OnChanUpgradeOpen( - suite.chainA.GetContext(), - path.EndpointA.ChannelConfig.PortID, - path.EndpointA.ChannelID, - channelOrder, - []string{path.EndpointA.ConnectionID}, - counterpartyVersion, - ) - } + if tc.expPanic != nil { + mockModule := ibcmock.NewAppModule(suite.chainA.App.GetIBCKeeper().PortKeeper) + mockApp := ibcmock.NewIBCApp(path.EndpointA.ChannelConfig.PortID, suite.chainA.App.GetScopedIBCKeeper()) + cbs = controller.NewIBCMiddleware(ibcmock.NewBlockUpgradeMiddleware(&mockModule, mockApp), suite.chainA.GetSimApp().ICAControllerKeeper) - if tc.expPanic != nil { - mockModule := ibcmock.NewAppModule(suite.chainA.App.GetIBCKeeper().PortKeeper) - mockApp := ibcmock.NewIBCApp(path.EndpointA.ChannelConfig.PortID, suite.chainA.App.GetScopedIBCKeeper()) - cbs = controller.NewIBCMiddleware(ibcmock.NewBlockUpgradeMiddleware(&mockModule, mockApp), suite.chainA.GetSimApp().ICAControllerKeeper) + suite.Require().PanicsWithError(tc.expPanic.Error(), func() { upgradeOpenCb(cbs) }) + } else { + if isNilApp { + cbs = controller.NewIBCMiddleware(nil, suite.chainA.GetSimApp().ICAControllerKeeper) + } - suite.Require().PanicsWithError(tc.expPanic.Error(), func() { upgradeOpenCb(cbs) }) - } else { - if isNilApp { - cbs = controller.NewIBCMiddleware(nil, suite.chainA.GetSimApp().ICAControllerKeeper) + upgradeOpenCb(cbs) } - - upgradeOpenCb(cbs) - } - }) + }) + } } } @@ -1117,174 +1130,198 @@ func (suite *InterchainAccountsTestSuite) TestSingleHostMultipleControllers() { }, } - for _, tc := range testCases { - tc := tc - - suite.Run(tc.msg, func() { - suite.SetupTest() // reset + for _, ordering := range []channeltypes.Order{channeltypes.UNORDERED, channeltypes.ORDERED} { + for _, tc := range testCases { + tc := tc - // Setup a new path from A(controller) -> B(host) - pathAToB = NewICAPath(suite.chainA, suite.chainB) - pathAToB.SetupConnections() + suite.Run(tc.msg, func() { + // reset + suite.SetupTest() + TestVersion = icatypes.NewDefaultMetadataString(ibctesting.FirstConnectionID, ibctesting.FirstConnectionID) - err := SetupICAPath(pathAToB, TestOwnerAddress) - suite.Require().NoError(err) + // Setup a new path from A(controller) -> B(host) + pathAToB = NewICAPath(suite.chainA, suite.chainB, ordering) + pathAToB.SetupConnections() - // Setup a new path from C(controller) -> B(host) - pathCToB = NewICAPath(suite.chainC, suite.chainB) - pathCToB.SetupConnections() - - // NOTE: Here the version metadata is overridden to include to the next host connection sequence (i.e. chainB's connection to chainC) - // SetupICAPath() will set endpoint.ChannelConfig.Version to TestVersion - TestVersion = string(icatypes.ModuleCdc.MustMarshalJSON(&icatypes.Metadata{ - Version: icatypes.Version, - ControllerConnectionId: pathCToB.EndpointA.ConnectionID, - HostConnectionId: pathCToB.EndpointB.ConnectionID, - Encoding: icatypes.EncodingProtobuf, - TxType: icatypes.TxTypeSDKMultiMsg, - })) + err := SetupICAPath(pathAToB, TestOwnerAddress) + suite.Require().NoError(err) - err = SetupICAPath(pathCToB, TestOwnerAddress) - suite.Require().NoError(err) + // Setup a new path from C(controller) -> B(host) + pathCToB = NewICAPath(suite.chainC, suite.chainB, ordering) + pathCToB.SetupConnections() + + // NOTE: Here the version metadata is overridden to include to the next host connection sequence (i.e. chainB's connection to chainC) + // SetupICAPath() will set endpoint.ChannelConfig.Version to TestVersion + TestVersion = string(icatypes.ModuleCdc.MustMarshalJSON(&icatypes.Metadata{ + Version: icatypes.Version, + ControllerConnectionId: pathCToB.EndpointA.ConnectionID, + HostConnectionId: pathCToB.EndpointB.ConnectionID, + Encoding: icatypes.EncodingProtobuf, + TxType: icatypes.TxTypeSDKMultiMsg, + })) + + err = SetupICAPath(pathCToB, TestOwnerAddress) + suite.Require().NoError(err) - tc.malleate() // malleate mutates test data + tc.malleate() // malleate mutates test data - accAddressChainA, found := suite.chainB.GetSimApp().ICAHostKeeper.GetInterchainAccountAddress(suite.chainB.GetContext(), pathAToB.EndpointB.ConnectionID, pathAToB.EndpointA.ChannelConfig.PortID) - suite.Require().True(found) + accAddressChainA, found := suite.chainB.GetSimApp().ICAHostKeeper.GetInterchainAccountAddress(suite.chainB.GetContext(), pathAToB.EndpointB.ConnectionID, pathAToB.EndpointA.ChannelConfig.PortID) + suite.Require().True(found) - accAddressChainC, found := suite.chainB.GetSimApp().ICAHostKeeper.GetInterchainAccountAddress(suite.chainB.GetContext(), pathCToB.EndpointB.ConnectionID, pathCToB.EndpointA.ChannelConfig.PortID) - suite.Require().True(found) + accAddressChainC, found := suite.chainB.GetSimApp().ICAHostKeeper.GetInterchainAccountAddress(suite.chainB.GetContext(), pathCToB.EndpointB.ConnectionID, pathCToB.EndpointA.ChannelConfig.PortID) + suite.Require().True(found) - suite.Require().NotEqual(accAddressChainA, accAddressChainC) + suite.Require().NotEqual(accAddressChainA, accAddressChainC) - chainAChannelID, found := suite.chainB.GetSimApp().ICAHostKeeper.GetActiveChannelID(suite.chainB.GetContext(), pathAToB.EndpointB.ConnectionID, pathAToB.EndpointA.ChannelConfig.PortID) - suite.Require().True(found) + chainAChannelID, found := suite.chainB.GetSimApp().ICAHostKeeper.GetActiveChannelID(suite.chainB.GetContext(), pathAToB.EndpointB.ConnectionID, pathAToB.EndpointA.ChannelConfig.PortID) + suite.Require().True(found) - chainCChannelID, found := suite.chainB.GetSimApp().ICAHostKeeper.GetActiveChannelID(suite.chainB.GetContext(), pathCToB.EndpointB.ConnectionID, pathCToB.EndpointA.ChannelConfig.PortID) - suite.Require().True(found) + chainCChannelID, found := suite.chainB.GetSimApp().ICAHostKeeper.GetActiveChannelID(suite.chainB.GetContext(), pathCToB.EndpointB.ConnectionID, pathCToB.EndpointA.ChannelConfig.PortID) + suite.Require().True(found) - suite.Require().NotEqual(chainAChannelID, chainCChannelID) - }) + suite.Require().NotEqual(chainAChannelID, chainCChannelID) + }) + } } } func (suite *InterchainAccountsTestSuite) TestGetAppVersion() { - path := NewICAPath(suite.chainA, suite.chainB) - path.SetupConnections() + for _, ordering := range []channeltypes.Order{channeltypes.UNORDERED, channeltypes.ORDERED} { + suite.SetupTest() // reset + + path := NewICAPath(suite.chainA, suite.chainB, ordering) + path.SetupConnections() - err := SetupICAPath(path, TestOwnerAddress) - suite.Require().NoError(err) + err := SetupICAPath(path, TestOwnerAddress) + suite.Require().NoError(err) - module, _, err := suite.chainA.App.GetIBCKeeper().PortKeeper.LookupModuleByPort(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID) - suite.Require().NoError(err) + module, _, err := suite.chainA.App.GetIBCKeeper().PortKeeper.LookupModuleByPort(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID) + suite.Require().NoError(err) - cbs, ok := suite.chainA.App.GetIBCKeeper().PortKeeper.Route(module) - suite.Require().True(ok) + cbs, ok := suite.chainA.App.GetIBCKeeper().PortKeeper.Route(module) + suite.Require().True(ok) - controllerStack, ok := cbs.(porttypes.ICS4Wrapper) - suite.Require().True(ok) + controllerStack, ok := cbs.(porttypes.ICS4Wrapper) + suite.Require().True(ok) - appVersion, found := controllerStack.GetAppVersion(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) - suite.Require().True(found) - suite.Require().Equal(path.EndpointA.ChannelConfig.Version, appVersion) + appVersion, found := controllerStack.GetAppVersion(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) + suite.Require().True(found) + suite.Require().Equal(path.EndpointA.ChannelConfig.Version, appVersion) + } } func (suite *InterchainAccountsTestSuite) TestInFlightHandshakeRespectsGoAPICaller() { - path := NewICAPath(suite.chainA, suite.chainB) - path.SetupConnections() + for _, ordering := range []channeltypes.Order{channeltypes.UNORDERED, channeltypes.ORDERED} { + suite.SetupTest() // reset + + path := NewICAPath(suite.chainA, suite.chainB, ordering) + path.SetupConnections() - // initiate a channel handshake such that channel.State == INIT - err := RegisterInterchainAccount(path.EndpointA, suite.chainA.SenderAccount.GetAddress().String()) - suite.Require().NoError(err) + // initiate a channel handshake such that channel.State == INIT + err := RegisterInterchainAccount(path.EndpointA, suite.chainA.SenderAccount.GetAddress().String()) + suite.Require().NoError(err) - // attempt to start a second handshake via the controller msg server - msgServer := controllerkeeper.NewMsgServerImpl(&suite.chainA.GetSimApp().ICAControllerKeeper) - msgRegisterInterchainAccount := types.NewMsgRegisterInterchainAccount(path.EndpointA.ConnectionID, suite.chainA.SenderAccount.GetAddress().String(), TestVersion, channeltypes.ORDERED) + // attempt to start a second handshake via the controller msg server + msgServer := controllerkeeper.NewMsgServerImpl(&suite.chainA.GetSimApp().ICAControllerKeeper) + msgRegisterInterchainAccount := types.NewMsgRegisterInterchainAccount(path.EndpointA.ConnectionID, suite.chainA.SenderAccount.GetAddress().String(), TestVersion, ordering) - res, err := msgServer.RegisterInterchainAccount(suite.chainA.GetContext(), msgRegisterInterchainAccount) - suite.Require().Error(err) - suite.Require().Nil(res) + res, err := msgServer.RegisterInterchainAccount(suite.chainA.GetContext(), msgRegisterInterchainAccount) + suite.Require().Error(err) + suite.Require().Nil(res) + } } func (suite *InterchainAccountsTestSuite) TestInFlightHandshakeRespectsMsgServerCaller() { - path := NewICAPath(suite.chainA, suite.chainB) - path.SetupConnections() + for _, ordering := range []channeltypes.Order{channeltypes.UNORDERED, channeltypes.ORDERED} { + suite.SetupTest() // reset + + path := NewICAPath(suite.chainA, suite.chainB, ordering) + path.SetupConnections() - // initiate a channel handshake such that channel.State == INIT - msgServer := controllerkeeper.NewMsgServerImpl(&suite.chainA.GetSimApp().ICAControllerKeeper) - msgRegisterInterchainAccount := types.NewMsgRegisterInterchainAccount(path.EndpointA.ConnectionID, suite.chainA.SenderAccount.GetAddress().String(), TestVersion, channeltypes.ORDERED) + // initiate a channel handshake such that channel.State == INIT + msgServer := controllerkeeper.NewMsgServerImpl(&suite.chainA.GetSimApp().ICAControllerKeeper) + msgRegisterInterchainAccount := types.NewMsgRegisterInterchainAccount(path.EndpointA.ConnectionID, suite.chainA.SenderAccount.GetAddress().String(), TestVersion, ordering) - res, err := msgServer.RegisterInterchainAccount(suite.chainA.GetContext(), msgRegisterInterchainAccount) - suite.Require().NotNil(res) - suite.Require().NoError(err) + res, err := msgServer.RegisterInterchainAccount(suite.chainA.GetContext(), msgRegisterInterchainAccount) + suite.Require().NotNil(res) + suite.Require().NoError(err) - // attempt to start a second handshake via the legacy Go API - err = RegisterInterchainAccount(path.EndpointA, suite.chainA.SenderAccount.GetAddress().String()) - suite.Require().Error(err) + // attempt to start a second handshake via the legacy Go API + err = RegisterInterchainAccount(path.EndpointA, suite.chainA.SenderAccount.GetAddress().String()) + suite.Require().Error(err) + } } func (suite *InterchainAccountsTestSuite) TestClosedChannelReopensWithMsgServer() { - path := NewICAPath(suite.chainA, suite.chainB) - path.SetupConnections() + for _, ordering := range []channeltypes.Order{channeltypes.UNORDERED, channeltypes.ORDERED} { + suite.SetupTest() // reset + + path := NewICAPath(suite.chainA, suite.chainB, ordering) + path.SetupConnections() - err := SetupICAPath(path, suite.chainA.SenderAccount.GetAddress().String()) - suite.Require().NoError(err) + err := SetupICAPath(path, suite.chainA.SenderAccount.GetAddress().String()) + suite.Require().NoError(err) - // set the channel state to closed - path.EndpointA.UpdateChannel(func(channel *channeltypes.Channel) { channel.State = channeltypes.CLOSED }) - path.EndpointB.UpdateChannel(func(channel *channeltypes.Channel) { channel.State = channeltypes.CLOSED }) + // set the channel state to closed + path.EndpointA.UpdateChannel(func(channel *channeltypes.Channel) { channel.State = channeltypes.CLOSED }) + path.EndpointB.UpdateChannel(func(channel *channeltypes.Channel) { channel.State = channeltypes.CLOSED }) - // reset endpoint channel ids - path.EndpointA.ChannelID = "" - path.EndpointB.ChannelID = "" + // reset endpoint channel ids + path.EndpointA.ChannelID = "" + path.EndpointB.ChannelID = "" - // fetch the next channel sequence before reinitiating the channel handshake - channelSeq := suite.chainA.GetSimApp().GetIBCKeeper().ChannelKeeper.GetNextChannelSequence(suite.chainA.GetContext()) + // fetch the next channel sequence before reinitiating the channel handshake + channelSeq := suite.chainA.GetSimApp().GetIBCKeeper().ChannelKeeper.GetNextChannelSequence(suite.chainA.GetContext()) - // route a new MsgRegisterInterchainAccount in order to reopen the - msgServer := controllerkeeper.NewMsgServerImpl(&suite.chainA.GetSimApp().ICAControllerKeeper) - msgRegisterInterchainAccount := types.NewMsgRegisterInterchainAccount(path.EndpointA.ConnectionID, suite.chainA.SenderAccount.GetAddress().String(), path.EndpointA.ChannelConfig.Version, channeltypes.ORDERED) + // route a new MsgRegisterInterchainAccount in order to reopen the + msgServer := controllerkeeper.NewMsgServerImpl(&suite.chainA.GetSimApp().ICAControllerKeeper) + msgRegisterInterchainAccount := types.NewMsgRegisterInterchainAccount(path.EndpointA.ConnectionID, suite.chainA.SenderAccount.GetAddress().String(), path.EndpointA.ChannelConfig.Version, ordering) - res, err := msgServer.RegisterInterchainAccount(suite.chainA.GetContext(), msgRegisterInterchainAccount) - suite.Require().NoError(err) - suite.Require().Equal(channeltypes.FormatChannelIdentifier(channelSeq), res.ChannelId) + res, err := msgServer.RegisterInterchainAccount(suite.chainA.GetContext(), msgRegisterInterchainAccount) + suite.Require().NoError(err) + suite.Require().Equal(channeltypes.FormatChannelIdentifier(channelSeq), res.ChannelId) - // assign the channel sequence to endpointA before generating proofs and initiating the TRY step - path.EndpointA.ChannelID = channeltypes.FormatChannelIdentifier(channelSeq) + // assign the channel sequence to endpointA before generating proofs and initiating the TRY step + path.EndpointA.ChannelID = channeltypes.FormatChannelIdentifier(channelSeq) - path.EndpointA.Chain.NextBlock() + path.EndpointA.Chain.NextBlock() - err = path.EndpointB.ChanOpenTry() - suite.Require().NoError(err) + err = path.EndpointB.ChanOpenTry() + suite.Require().NoError(err) - err = path.EndpointA.ChanOpenAck() - suite.Require().NoError(err) + err = path.EndpointA.ChanOpenAck() + suite.Require().NoError(err) - err = path.EndpointB.ChanOpenConfirm() - suite.Require().NoError(err) + err = path.EndpointB.ChanOpenConfirm() + suite.Require().NoError(err) + } } func (suite *InterchainAccountsTestSuite) TestPacketDataUnmarshalerInterface() { - path := NewICAPath(suite.chainA, suite.chainB) - path.SetupConnections() - err := SetupICAPath(path, TestOwnerAddress) - suite.Require().NoError(err) - - expPacketData := icatypes.InterchainAccountPacketData{ - Type: icatypes.EXECUTE_TX, - Data: []byte("data"), - Memo: "", + for _, ordering := range []channeltypes.Order{channeltypes.UNORDERED, channeltypes.ORDERED} { + suite.SetupTest() // reset + + path := NewICAPath(suite.chainA, suite.chainB, ordering) + path.SetupConnections() + err := SetupICAPath(path, TestOwnerAddress) + suite.Require().NoError(err) + + expPacketData := icatypes.InterchainAccountPacketData{ + Type: icatypes.EXECUTE_TX, + Data: []byte("data"), + Memo: "", + } + + // Context, port identifier and channel identifier are unused for controller. + packetData, err := controller.IBCMiddleware{}.UnmarshalPacketData(suite.chainA.GetContext(), "", "", expPacketData.GetBytes()) + suite.Require().NoError(err) + suite.Require().Equal(expPacketData, packetData) + + // test invalid packet data + invalidPacketData := []byte("invalid packet data") + // Context, port identifier and channel identifier are not used for controller. + packetData, err = controller.IBCMiddleware{}.UnmarshalPacketData(suite.chainA.GetContext(), "", "", invalidPacketData) + suite.Require().Error(err) + suite.Require().Nil(packetData) } - - // Context, port identifier and channel identifier are unused for controller. - packetData, err := controller.IBCMiddleware{}.UnmarshalPacketData(suite.chainA.GetContext(), "", "", expPacketData.GetBytes()) - suite.Require().NoError(err) - suite.Require().Equal(expPacketData, packetData) - - // test invalid packet data - invalidPacketData := []byte("invalid packet data") - // Context, port identifier and channel identifier are not used for controller. - packetData, err = controller.IBCMiddleware{}.UnmarshalPacketData(suite.chainA.GetContext(), "", "", invalidPacketData) - suite.Require().Error(err) - suite.Require().Nil(packetData) } diff --git a/modules/apps/27-interchain-accounts/controller/keeper/account.go b/modules/apps/27-interchain-accounts/controller/keeper/account.go index a494bb29a50..cb08bb44e19 100644 --- a/modules/apps/27-interchain-accounts/controller/keeper/account.go +++ b/modules/apps/27-interchain-accounts/controller/keeper/account.go @@ -29,7 +29,7 @@ import ( // Prior to v6.x.x of ibc-go, the controller module was only functional as middleware, with authentication performed // by the underlying application. For a full summary of the changes in v6.x.x, please see ADR009. // This API will be removed in later releases. -func (k Keeper) RegisterInterchainAccount(ctx sdk.Context, connectionID, owner, version string) error { +func (k Keeper) RegisterInterchainAccount(ctx sdk.Context, connectionID, owner, version string, ordering channeltypes.Order) error { portID, err := icatypes.NewControllerPortID(owner) if err != nil { return err @@ -41,7 +41,12 @@ func (k Keeper) RegisterInterchainAccount(ctx sdk.Context, connectionID, owner, k.SetMiddlewareEnabled(ctx, portID, connectionID) - _, err = k.registerInterchainAccount(ctx, connectionID, portID, version, channeltypes.ORDERED) + // use ORDER_UNORDERED as default in case ordering is NONE + if ordering == channeltypes.NONE { + ordering = channeltypes.UNORDERED + } + + _, err = k.registerInterchainAccount(ctx, connectionID, portID, version, ordering) 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 c462de350f6..8fac043ccab 100644 --- a/modules/apps/27-interchain-accounts/controller/keeper/account_test.go +++ b/modules/apps/27-interchain-accounts/controller/keeper/account_test.go @@ -8,113 +8,118 @@ import ( ) func (suite *KeeperTestSuite) TestRegisterInterchainAccount() { - var ( - owner string - path *ibctesting.Path - err error - ) - - testCases := []struct { - name string - malleate func() - expPass bool - }{ - { - "success", func() {}, true, - }, - { - "port is already bound for owner but capability is claimed by another module", - func() { - capability := suite.chainA.GetSimApp().IBCKeeper.PortKeeper.BindPort(suite.chainA.GetContext(), TestPortID) - err := suite.chainA.GetSimApp().TransferKeeper.ClaimCapability(suite.chainA.GetContext(), capability, host.PortPath(TestPortID)) - suite.Require().NoError(err) + for _, ordering := range []channeltypes.Order{channeltypes.UNORDERED, channeltypes.ORDERED} { + var ( + owner string + path *ibctesting.Path + err error + ) + + testCases := []struct { + name string + malleate func() + expPass bool + }{ + { + "success", func() {}, true, }, - false, - }, - { - "fails to generate port-id", - func() { - owner = "" + { + "port is already bound for owner but capability is claimed by another module", + func() { + capability := suite.chainA.GetSimApp().IBCKeeper.PortKeeper.BindPort(suite.chainA.GetContext(), TestPortID) + err := suite.chainA.GetSimApp().TransferKeeper.ClaimCapability(suite.chainA.GetContext(), capability, host.PortPath(TestPortID)) + suite.Require().NoError(err) + }, + false, }, - false, - }, - { - "MsgChanOpenInit fails - channel is already active & in state OPEN", - func() { - portID, err := icatypes.NewControllerPortID(TestOwnerAddress) - suite.Require().NoError(err) - - 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{ - State: channeltypes.OPEN, - Ordering: channeltypes.ORDERED, - Counterparty: counterparty, - ConnectionHops: []string{path.EndpointA.ConnectionID}, - Version: TestVersion, - } - suite.chainA.GetSimApp().IBCKeeper.ChannelKeeper.SetChannel(suite.chainA.GetContext(), portID, path.EndpointA.ChannelID, channel) + { + "fails to generate port-id", + func() { + owner = "" + }, + false, }, - false, - }, - } - for _, tc := range testCases { - tc := tc + { + "MsgChanOpenInit fails - channel is already active & in state OPEN", + func() { + portID, err := icatypes.NewControllerPortID(TestOwnerAddress) + suite.Require().NoError(err) + + 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{ + State: channeltypes.OPEN, + Ordering: ordering, + Counterparty: counterparty, + ConnectionHops: []string{path.EndpointA.ConnectionID}, + Version: TestVersion, + } + suite.chainA.GetSimApp().IBCKeeper.ChannelKeeper.SetChannel(suite.chainA.GetContext(), portID, path.EndpointA.ChannelID, channel) + }, + false, + }, + } + + for _, tc := range testCases { + tc := tc - suite.Run(tc.name, func() { - suite.SetupTest() + suite.Run(tc.name, func() { + suite.SetupTest() - owner = TestOwnerAddress // must be explicitly changed + owner = TestOwnerAddress // must be explicitly changed - path = NewICAPath(suite.chainA, suite.chainB) - path.SetupConnections() + path = NewICAPath(suite.chainA, suite.chainB, ordering) + path.SetupConnections() - tc.malleate() // malleate mutates test data + tc.malleate() // malleate mutates test data - err = suite.chainA.GetSimApp().ICAControllerKeeper.RegisterInterchainAccount(suite.chainA.GetContext(), path.EndpointA.ConnectionID, owner, TestVersion) + err = suite.chainA.GetSimApp().ICAControllerKeeper.RegisterInterchainAccount(suite.chainA.GetContext(), path.EndpointA.ConnectionID, owner, TestVersion, ordering) - if tc.expPass { - suite.Require().NoError(err) - } else { - suite.Require().Error(err) - } - }) + if tc.expPass { + suite.Require().NoError(err) + } else { + suite.Require().Error(err) + } + }) + } } } func (suite *KeeperTestSuite) TestRegisterSameOwnerMultipleConnections() { - suite.SetupTest() - - owner := TestOwnerAddress - - pathAToB := NewICAPath(suite.chainA, suite.chainB) - pathAToB.SetupConnections() - - pathAToC := NewICAPath(suite.chainA, suite.chainC) - pathAToC.SetupConnections() - - // build ICS27 metadata with connection identifiers for path A->B - metadata := &icatypes.Metadata{ - Version: icatypes.Version, - ControllerConnectionId: pathAToB.EndpointA.ConnectionID, - HostConnectionId: pathAToB.EndpointB.ConnectionID, - Encoding: icatypes.EncodingProtobuf, - TxType: icatypes.TxTypeSDKMultiMsg, - } - - err := suite.chainA.GetSimApp().ICAControllerKeeper.RegisterInterchainAccount(suite.chainA.GetContext(), pathAToB.EndpointA.ConnectionID, owner, string(icatypes.ModuleCdc.MustMarshalJSON(metadata))) - suite.Require().NoError(err) - - // build ICS27 metadata with connection identifiers for path A->C - metadata = &icatypes.Metadata{ - Version: icatypes.Version, - ControllerConnectionId: pathAToC.EndpointA.ConnectionID, - HostConnectionId: pathAToC.EndpointB.ConnectionID, - Encoding: icatypes.EncodingProtobuf, - TxType: icatypes.TxTypeSDKMultiMsg, + for _, ordering := range []channeltypes.Order{channeltypes.UNORDERED, channeltypes.ORDERED} { + suite.SetupTest() + + owner := TestOwnerAddress + + pathAToB := NewICAPath(suite.chainA, suite.chainB, ordering) + pathAToB.SetupConnections() + + pathAToC := NewICAPath(suite.chainA, suite.chainC, ordering) + pathAToC.SetupConnections() + + // build ICS27 metadata with connection identifiers for path A->B + metadata := &icatypes.Metadata{ + Version: icatypes.Version, + ControllerConnectionId: pathAToB.EndpointA.ConnectionID, + HostConnectionId: pathAToB.EndpointB.ConnectionID, + Encoding: icatypes.EncodingProtobuf, + TxType: icatypes.TxTypeSDKMultiMsg, + } + + err := suite.chainA.GetSimApp().ICAControllerKeeper.RegisterInterchainAccount(suite.chainA.GetContext(), pathAToB.EndpointA.ConnectionID, owner, string(icatypes.ModuleCdc.MustMarshalJSON(metadata)), ordering) + suite.Require().NoError(err) + + // build ICS27 metadata with connection identifiers for path A->C + metadata = &icatypes.Metadata{ + Version: icatypes.Version, + ControllerConnectionId: pathAToC.EndpointA.ConnectionID, + HostConnectionId: pathAToC.EndpointB.ConnectionID, + Encoding: icatypes.EncodingProtobuf, + TxType: icatypes.TxTypeSDKMultiMsg, + } + + err = suite.chainA.GetSimApp().ICAControllerKeeper.RegisterInterchainAccount(suite.chainA.GetContext(), pathAToC.EndpointA.ConnectionID, owner, string(icatypes.ModuleCdc.MustMarshalJSON(metadata)), ordering) + suite.Require().NoError(err) } - - err = suite.chainA.GetSimApp().ICAControllerKeeper.RegisterInterchainAccount(suite.chainA.GetContext(), pathAToC.EndpointA.ConnectionID, owner, string(icatypes.ModuleCdc.MustMarshalJSON(metadata))) - suite.Require().NoError(err) } 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 b8f8acf9537..a27932988d0 100644 --- a/modules/apps/27-interchain-accounts/controller/keeper/genesis_test.go +++ b/modules/apps/27-interchain-accounts/controller/keeper/genesis_test.go @@ -5,6 +5,7 @@ import ( "github.com/cosmos/ibc-go/v8/modules/apps/27-interchain-accounts/controller/types" genesistypes "github.com/cosmos/ibc-go/v8/modules/apps/27-interchain-accounts/genesis/types" icatypes "github.com/cosmos/ibc-go/v8/modules/apps/27-interchain-accounts/types" + channeltypes "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types" host "github.com/cosmos/ibc-go/v8/modules/core/24-host" ibctesting "github.com/cosmos/ibc-go/v8/testing" ) @@ -95,28 +96,30 @@ func (suite *KeeperTestSuite) TestInitGenesis() { } func (suite *KeeperTestSuite) TestExportGenesis() { - suite.SetupTest() + for _, ordering := range []channeltypes.Order{channeltypes.UNORDERED, channeltypes.ORDERED} { + suite.SetupTest() - path := NewICAPath(suite.chainA, suite.chainB) - path.SetupConnections() + path := NewICAPath(suite.chainA, suite.chainB, ordering) + path.SetupConnections() - err := SetupICAPath(path, TestOwnerAddress) - suite.Require().NoError(err) + err := SetupICAPath(path, TestOwnerAddress) + suite.Require().NoError(err) - interchainAccAddr, exists := suite.chainB.GetSimApp().ICAHostKeeper.GetInterchainAccountAddress(suite.chainB.GetContext(), path.EndpointB.ConnectionID, path.EndpointA.ChannelConfig.PortID) - suite.Require().True(exists) + interchainAccAddr, exists := suite.chainB.GetSimApp().ICAHostKeeper.GetInterchainAccountAddress(suite.chainB.GetContext(), path.EndpointB.ConnectionID, path.EndpointA.ChannelConfig.PortID) + suite.Require().True(exists) - genesisState := keeper.ExportGenesis(suite.chainA.GetContext(), suite.chainA.GetSimApp().ICAControllerKeeper) + genesisState := keeper.ExportGenesis(suite.chainA.GetContext(), suite.chainA.GetSimApp().ICAControllerKeeper) - suite.Require().Equal(path.EndpointA.ChannelID, genesisState.ActiveChannels[0].ChannelId) - suite.Require().Equal(path.EndpointA.ChannelConfig.PortID, genesisState.ActiveChannels[0].PortId) - suite.Require().True(genesisState.ActiveChannels[0].IsMiddlewareEnabled) + suite.Require().Equal(path.EndpointA.ChannelID, genesisState.ActiveChannels[0].ChannelId) + suite.Require().Equal(path.EndpointA.ChannelConfig.PortID, genesisState.ActiveChannels[0].PortId) + suite.Require().True(genesisState.ActiveChannels[0].IsMiddlewareEnabled) - suite.Require().Equal(interchainAccAddr, genesisState.InterchainAccounts[0].AccountAddress) - suite.Require().Equal(path.EndpointA.ChannelConfig.PortID, genesisState.InterchainAccounts[0].PortId) + suite.Require().Equal(interchainAccAddr, genesisState.InterchainAccounts[0].AccountAddress) + suite.Require().Equal(path.EndpointA.ChannelConfig.PortID, genesisState.InterchainAccounts[0].PortId) - suite.Require().Equal([]string{TestPortID}, genesisState.GetPorts()) + suite.Require().Equal([]string{TestPortID}, genesisState.GetPorts()) - expParams := types.DefaultParams() - suite.Require().Equal(expParams, genesisState.GetParams()) + expParams := types.DefaultParams() + suite.Require().Equal(expParams, genesisState.GetParams()) + } } diff --git a/modules/apps/27-interchain-accounts/controller/keeper/grpc_query_test.go b/modules/apps/27-interchain-accounts/controller/keeper/grpc_query_test.go index 465f103b924..471d343dc4f 100644 --- a/modules/apps/27-interchain-accounts/controller/keeper/grpc_query_test.go +++ b/modules/apps/27-interchain-accounts/controller/keeper/grpc_query_test.go @@ -2,6 +2,7 @@ package keeper_test import ( "github.com/cosmos/ibc-go/v8/modules/apps/27-interchain-accounts/controller/types" + channeltypes "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types" ibctesting "github.com/cosmos/ibc-go/v8/testing" ) @@ -41,37 +42,39 @@ func (suite *KeeperTestSuite) TestQueryInterchainAccount() { }, } - for _, tc := range testCases { - tc := tc + for _, ordering := range []channeltypes.Order{channeltypes.UNORDERED, channeltypes.ORDERED} { + for _, tc := range testCases { + tc := tc - suite.Run(tc.name, func() { - suite.SetupTest() + suite.Run(tc.name, func() { + suite.SetupTest() - path := NewICAPath(suite.chainA, suite.chainB) - path.SetupConnections() + path := NewICAPath(suite.chainA, suite.chainB, ordering) + path.SetupConnections() - err := SetupICAPath(path, ibctesting.TestAccAddress) - suite.Require().NoError(err) + err := SetupICAPath(path, ibctesting.TestAccAddress) + suite.Require().NoError(err) - req = &types.QueryInterchainAccountRequest{ - ConnectionId: ibctesting.FirstConnectionID, - Owner: ibctesting.TestAccAddress, - } + req = &types.QueryInterchainAccountRequest{ + ConnectionId: ibctesting.FirstConnectionID, + Owner: ibctesting.TestAccAddress, + } - tc.malleate() + tc.malleate() - res, err := suite.chainA.GetSimApp().ICAControllerKeeper.InterchainAccount(suite.chainA.GetContext(), req) + res, err := suite.chainA.GetSimApp().ICAControllerKeeper.InterchainAccount(suite.chainA.GetContext(), req) - if tc.expPass { - expAddress, exists := suite.chainB.GetSimApp().ICAHostKeeper.GetInterchainAccountAddress(suite.chainB.GetContext(), path.EndpointB.ConnectionID, path.EndpointA.ChannelConfig.PortID) - suite.Require().True(exists) + if tc.expPass { + expAddress, exists := suite.chainB.GetSimApp().ICAHostKeeper.GetInterchainAccountAddress(suite.chainB.GetContext(), path.EndpointB.ConnectionID, path.EndpointA.ChannelConfig.PortID) + suite.Require().True(exists) - suite.Require().NoError(err) - suite.Require().Equal(expAddress, res.Address) - } else { - suite.Require().Error(err) - } - }) + suite.Require().NoError(err) + suite.Require().Equal(expAddress, res.Address) + } else { + suite.Require().Error(err) + } + }) + } } } 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 ec8a671b307..7e6f0add2f8 100644 --- a/modules/apps/27-interchain-accounts/controller/keeper/handshake_test.go +++ b/modules/apps/27-interchain-accounts/controller/keeper/handshake_test.go @@ -15,297 +15,304 @@ const ( ) func (suite *KeeperTestSuite) TestOnChanOpenInit() { - var ( - channel *channeltypes.Channel - path *ibctesting.Path - chanCap *capabilitytypes.Capability - metadata icatypes.Metadata - expectedVersion string - ) - - testCases := []struct { - name string - malleate func() - expError error - }{ - { - "success", - func() {}, - nil, - }, - { - "success: previous active channel closed", - func() { - 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{ - State: channeltypes.CLOSED, - Ordering: channeltypes.ORDERED, - Counterparty: counterparty, - ConnectionHops: []string{path.EndpointA.ConnectionID}, - Version: TestVersion, - } - - path.EndpointA.SetChannel(channel) - }, - nil, - }, - { - "success: empty channel version returns default metadata JSON string", - func() { - channel.Version = "" - expectedVersion = icatypes.NewDefaultMetadataString(path.EndpointA.ConnectionID, path.EndpointB.ConnectionID) - }, - nil, - }, - { - "success: channel reopening", - func() { - err := SetupICAPath(path, TestOwnerAddress) + for _, ordering := range []channeltypes.Order{channeltypes.UNORDERED, channeltypes.ORDERED} { + var ( + channel *channeltypes.Channel + path *ibctesting.Path + chanCap *capabilitytypes.Capability + metadata icatypes.Metadata + expectedVersion string + ) + + testCases := []struct { + name string + malleate func() + expError error + }{ + { + "success", + func() {}, + nil, + }, + { + "success: previous active channel closed", + func() { + 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{ + State: channeltypes.CLOSED, + Ordering: ordering, + Counterparty: counterparty, + ConnectionHops: []string{path.EndpointA.ConnectionID}, + Version: TestVersion, + } + + path.EndpointA.SetChannel(channel) + }, + nil, + }, + { + "success: empty channel version returns default metadata JSON string", + func() { + channel.Version = "" + expectedVersion = icatypes.NewDefaultMetadataString(path.EndpointA.ConnectionID, path.EndpointB.ConnectionID) + }, + nil, + }, + { + "success: channel reopening", + func() { + err := SetupICAPath(path, TestOwnerAddress) + suite.Require().NoError(err) + + path.EndpointA.UpdateChannel(func(channel *channeltypes.Channel) { channel.State = channeltypes.CLOSED }) + path.EndpointB.UpdateChannel(func(channel *channeltypes.Channel) { channel.State = channeltypes.CLOSED }) + + path.EndpointA.ChannelID = "" + path.EndpointB.ChannelID = "" + }, + nil, + }, + { + "failure: different ordering from previous channel", + func() { + differentOrdering := channeltypes.UNORDERED + if ordering == channeltypes.UNORDERED { + differentOrdering = channeltypes.ORDERED + } + + 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{ + State: channeltypes.CLOSED, + Ordering: differentOrdering, + Counterparty: counterparty, + ConnectionHops: []string{path.EndpointA.ConnectionID}, + Version: TestVersion, + } + + path.EndpointA.SetChannel(channel) + }, + channeltypes.ErrInvalidChannelOrdering, + }, + { + "invalid metadata - previous metadata is different", + func() { + // set active channel to closed + suite.chainA.GetSimApp().ICAControllerKeeper.SetActiveChannelID(suite.chainA.GetContext(), ibctesting.FirstConnectionID, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) + + // attempt to downgrade version by reinitializing channel with version 1, but setting channel to version 2 + metadata.Version = "ics27-2" + + versionBytes, err := icatypes.ModuleCdc.MarshalJSON(&metadata) + suite.Require().NoError(err) + + counterparty := channeltypes.NewCounterparty(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID) + closedChannel := channeltypes.Channel{ + State: channeltypes.CLOSED, + Ordering: ordering, + Counterparty: counterparty, + ConnectionHops: []string{path.EndpointA.ConnectionID}, + Version: string(versionBytes), + } + path.EndpointA.SetChannel(closedChannel) + }, + icatypes.ErrInvalidVersion, + }, + { + "invalid port ID", + func() { + path.EndpointA.ChannelConfig.PortID = "invalid-port-id" //nolint:goconst + }, + icatypes.ErrInvalidControllerPort, + }, + { + "invalid counterparty port ID", + func() { + path.EndpointA.SetChannel(*channel) + channel.Counterparty.PortId = "invalid-port-id" + }, + icatypes.ErrInvalidHostPort, + }, + { + "invalid metadata bytestring", + func() { + path.EndpointA.SetChannel(*channel) + channel.Version = "invalid-metadata-bytestring" + }, + icatypes.ErrUnknownDataType, + }, + { + "unsupported encoding format", + func() { + metadata.Encoding = "invalid-encoding-format" + + versionBytes, err := icatypes.ModuleCdc.MarshalJSON(&metadata) + suite.Require().NoError(err) + + channel.Version = string(versionBytes) + path.EndpointA.SetChannel(*channel) + }, + icatypes.ErrInvalidCodec, + }, + { + "unsupported transaction type", + func() { + metadata.TxType = "invalid-tx-types" + + versionBytes, err := icatypes.ModuleCdc.MarshalJSON(&metadata) + suite.Require().NoError(err) + + channel.Version = string(versionBytes) + path.EndpointA.SetChannel(*channel) + }, + icatypes.ErrUnknownDataType, + }, + { + "connection not found", + func() { + channel.ConnectionHops = []string{"invalid-connnection-id"} + path.EndpointA.SetChannel(*channel) + }, + connectiontypes.ErrConnectionNotFound, + }, + { + "connection not found with default empty channel version", + func() { + channel.ConnectionHops = []string{"connection-10"} + channel.Version = "" + }, + connectiontypes.ErrConnectionNotFound, + }, + { + "invalid controller connection ID", + func() { + metadata.ControllerConnectionId = "invalid-connnection-id" + + versionBytes, err := icatypes.ModuleCdc.MarshalJSON(&metadata) + suite.Require().NoError(err) + + channel.Version = string(versionBytes) + path.EndpointA.SetChannel(*channel) + }, + connectiontypes.ErrInvalidConnection, + }, + { + "invalid host connection ID", + func() { + metadata.HostConnectionId = "invalid-connnection-id" + + versionBytes, err := icatypes.ModuleCdc.MarshalJSON(&metadata) + suite.Require().NoError(err) + + channel.Version = string(versionBytes) + path.EndpointA.SetChannel(*channel) + }, + connectiontypes.ErrInvalidConnection, + }, + { + "invalid version", + func() { + metadata.Version = "invalid-version" + + versionBytes, err := icatypes.ModuleCdc.MarshalJSON(&metadata) + suite.Require().NoError(err) + + channel.Version = string(versionBytes) + path.EndpointA.SetChannel(*channel) + }, + icatypes.ErrInvalidVersion, + }, + { + "channel is already active (OPEN state)", + func() { + 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{ + State: channeltypes.OPEN, + Ordering: ordering, + Counterparty: counterparty, + ConnectionHops: []string{path.EndpointA.ConnectionID}, + Version: TestVersion, + } + suite.chainA.GetSimApp().IBCKeeper.ChannelKeeper.SetChannel(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, channel) + }, + icatypes.ErrActiveChannelAlreadySet, + }, + { + "channel is already active (FLUSHING state)", + func() { + 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{ + State: channeltypes.FLUSHING, + Ordering: ordering, + Counterparty: counterparty, + ConnectionHops: []string{path.EndpointA.ConnectionID}, + Version: TestVersion, + } + suite.chainA.GetSimApp().IBCKeeper.ChannelKeeper.SetChannel(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, channel) + }, + icatypes.ErrActiveChannelAlreadySet, + }, + } + + for _, tc := range testCases { + tc := tc + + suite.Run(tc.name, func() { + suite.SetupTest() // reset + + path = NewICAPath(suite.chainA, suite.chainB, ordering) + path.SetupConnections() + + // mock init interchain account + portID, err := icatypes.NewControllerPortID(TestOwnerAddress) suite.Require().NoError(err) - path.EndpointA.UpdateChannel(func(channel *channeltypes.Channel) { channel.State = channeltypes.CLOSED }) - path.EndpointB.UpdateChannel(func(channel *channeltypes.Channel) { channel.State = channeltypes.CLOSED }) - - path.EndpointA.ChannelID = "" - path.EndpointB.ChannelID = "" - }, - nil, - }, - { - "failure: different ordering from previous channel", - func() { - 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{ - State: channeltypes.CLOSED, - Ordering: channeltypes.UNORDERED, - Counterparty: counterparty, - ConnectionHops: []string{path.EndpointA.ConnectionID}, - Version: TestVersion, - } - - path.EndpointA.SetChannel(channel) - }, - channeltypes.ErrInvalidChannelOrdering, - }, - { - "invalid metadata - previous metadata is different", - func() { - // set active channel to closed - suite.chainA.GetSimApp().ICAControllerKeeper.SetActiveChannelID(suite.chainA.GetContext(), ibctesting.FirstConnectionID, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) - - // attempt to downgrade version by reinitializing channel with version 1, but setting channel to version 2 - metadata.Version = "ics27-2" + portCap := suite.chainA.GetSimApp().IBCKeeper.PortKeeper.BindPort(suite.chainA.GetContext(), portID) + suite.chainA.GetSimApp().ICAControllerKeeper.ClaimCapability(suite.chainA.GetContext(), portCap, host.PortPath(portID)) //nolint:errcheck // this error check isn't needed for tests + path.EndpointA.ChannelConfig.PortID = portID + // default values + metadata = icatypes.NewMetadata(icatypes.Version, path.EndpointA.ConnectionID, path.EndpointB.ConnectionID, "", icatypes.EncodingProtobuf, icatypes.TxTypeSDKMultiMsg) versionBytes, err := icatypes.ModuleCdc.MarshalJSON(&metadata) suite.Require().NoError(err) + expectedVersion = string(versionBytes) + counterparty := channeltypes.NewCounterparty(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID) - closedChannel := channeltypes.Channel{ - State: channeltypes.CLOSED, - Ordering: channeltypes.ORDERED, + channel = &channeltypes.Channel{ + State: channeltypes.INIT, + Ordering: ordering, Counterparty: counterparty, ConnectionHops: []string{path.EndpointA.ConnectionID}, Version: string(versionBytes), } - path.EndpointA.SetChannel(closedChannel) - }, - icatypes.ErrInvalidVersion, - }, - { - "invalid port ID", - func() { - path.EndpointA.ChannelConfig.PortID = "invalid-port-id" //nolint:goconst - }, - icatypes.ErrInvalidControllerPort, - }, - { - "invalid counterparty port ID", - func() { - path.EndpointA.SetChannel(*channel) - channel.Counterparty.PortId = "invalid-port-id" - }, - icatypes.ErrInvalidHostPort, - }, - { - "invalid metadata bytestring", - func() { - path.EndpointA.SetChannel(*channel) - channel.Version = "invalid-metadata-bytestring" - }, - icatypes.ErrUnknownDataType, - }, - { - "unsupported encoding format", - func() { - metadata.Encoding = "invalid-encoding-format" - versionBytes, err := icatypes.ModuleCdc.MarshalJSON(&metadata) + chanCap, err = suite.chainA.App.GetScopedIBCKeeper().NewCapability(suite.chainA.GetContext(), host.ChannelCapabilityPath(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID)) suite.Require().NoError(err) - channel.Version = string(versionBytes) - path.EndpointA.SetChannel(*channel) - }, - icatypes.ErrInvalidCodec, - }, - { - "unsupported transaction type", - func() { - metadata.TxType = "invalid-tx-types" + tc.malleate() // malleate mutates test data - versionBytes, err := icatypes.ModuleCdc.MarshalJSON(&metadata) - suite.Require().NoError(err) + version, err := suite.chainA.GetSimApp().ICAControllerKeeper.OnChanOpenInit(suite.chainA.GetContext(), channel.Ordering, channel.ConnectionHops, + path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, chanCap, channel.Counterparty, channel.Version, + ) - channel.Version = string(versionBytes) - path.EndpointA.SetChannel(*channel) - }, - icatypes.ErrUnknownDataType, - }, - { - "connection not found", - func() { - channel.ConnectionHops = []string{"invalid-connnection-id"} - path.EndpointA.SetChannel(*channel) - }, - connectiontypes.ErrConnectionNotFound, - }, - { - "connection not found with default empty channel version", - func() { - channel.ConnectionHops = []string{"connection-10"} - channel.Version = "" - }, - connectiontypes.ErrConnectionNotFound, - }, - { - "invalid controller connection ID", - func() { - metadata.ControllerConnectionId = "invalid-connnection-id" - - versionBytes, err := icatypes.ModuleCdc.MarshalJSON(&metadata) - suite.Require().NoError(err) - - channel.Version = string(versionBytes) - path.EndpointA.SetChannel(*channel) - }, - connectiontypes.ErrInvalidConnection, - }, - { - "invalid host connection ID", - func() { - metadata.HostConnectionId = "invalid-connnection-id" - - versionBytes, err := icatypes.ModuleCdc.MarshalJSON(&metadata) - suite.Require().NoError(err) - - channel.Version = string(versionBytes) - path.EndpointA.SetChannel(*channel) - }, - connectiontypes.ErrInvalidConnection, - }, - { - "invalid version", - func() { - metadata.Version = "invalid-version" - - versionBytes, err := icatypes.ModuleCdc.MarshalJSON(&metadata) - suite.Require().NoError(err) - - channel.Version = string(versionBytes) - path.EndpointA.SetChannel(*channel) - }, - icatypes.ErrInvalidVersion, - }, - { - "channel is already active (OPEN state)", - func() { - 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{ - State: channeltypes.OPEN, - Ordering: channeltypes.ORDERED, - Counterparty: counterparty, - ConnectionHops: []string{path.EndpointA.ConnectionID}, - Version: TestVersion, + expPass := tc.expError == nil + if expPass { + suite.Require().NoError(err) + suite.Require().Equal(expectedVersion, version) + } else { + suite.Require().Error(err) + suite.Require().ErrorIs(err, tc.expError) } - suite.chainA.GetSimApp().IBCKeeper.ChannelKeeper.SetChannel(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, channel) - }, - icatypes.ErrActiveChannelAlreadySet, - }, - { - "channel is already active (FLUSHING state)", - func() { - 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{ - State: channeltypes.FLUSHING, - Ordering: channeltypes.ORDERED, - Counterparty: counterparty, - ConnectionHops: []string{path.EndpointA.ConnectionID}, - Version: TestVersion, - } - suite.chainA.GetSimApp().IBCKeeper.ChannelKeeper.SetChannel(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, channel) - }, - icatypes.ErrActiveChannelAlreadySet, - }, - } - - for _, tc := range testCases { - tc := tc - - suite.Run(tc.name, func() { - suite.SetupTest() // reset - - path = NewICAPath(suite.chainA, suite.chainB) - path.SetupConnections() - - // mock init interchain account - portID, err := icatypes.NewControllerPortID(TestOwnerAddress) - suite.Require().NoError(err) - - portCap := suite.chainA.GetSimApp().IBCKeeper.PortKeeper.BindPort(suite.chainA.GetContext(), portID) - suite.chainA.GetSimApp().ICAControllerKeeper.ClaimCapability(suite.chainA.GetContext(), portCap, host.PortPath(portID)) //nolint:errcheck // this error check isn't needed for tests - path.EndpointA.ChannelConfig.PortID = portID - - // default values - metadata = icatypes.NewMetadata(icatypes.Version, path.EndpointA.ConnectionID, path.EndpointB.ConnectionID, "", icatypes.EncodingProtobuf, icatypes.TxTypeSDKMultiMsg) - versionBytes, err := icatypes.ModuleCdc.MarshalJSON(&metadata) - suite.Require().NoError(err) - - expectedVersion = string(versionBytes) - - counterparty := channeltypes.NewCounterparty(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID) - channel = &channeltypes.Channel{ - State: channeltypes.INIT, - Ordering: channeltypes.ORDERED, - Counterparty: counterparty, - ConnectionHops: []string{path.EndpointA.ConnectionID}, - Version: string(versionBytes), - } - - chanCap, err = suite.chainA.App.GetScopedIBCKeeper().NewCapability(suite.chainA.GetContext(), host.ChannelCapabilityPath(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID)) - suite.Require().NoError(err) - - tc.malleate() // malleate mutates test data - - version, err := suite.chainA.GetSimApp().ICAControllerKeeper.OnChanOpenInit(suite.chainA.GetContext(), channel.Ordering, channel.ConnectionHops, - path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, chanCap, channel.Counterparty, channel.Version, - ) - - expPass := tc.expError == nil - if expPass { - suite.Require().NoError(err) - suite.Require().Equal(expectedVersion, version) - } else { - suite.Require().Error(err) - suite.Require().ErrorIs(err, tc.expError) - } - }) + }) + } } } @@ -417,52 +424,54 @@ func (suite *KeeperTestSuite) TestOnChanOpenAck() { }, } - for _, tc := range testCases { - tc := tc + for _, ordering := range []channeltypes.Order{channeltypes.UNORDERED, channeltypes.ORDERED} { + for _, tc := range testCases { + tc := tc - suite.Run(tc.name, func() { - suite.SetupTest() // reset + suite.Run(tc.name, func() { + suite.SetupTest() // reset - path = NewICAPath(suite.chainA, suite.chainB) - path.SetupConnections() + path = NewICAPath(suite.chainA, suite.chainB, ordering) + path.SetupConnections() - err := RegisterInterchainAccount(path.EndpointA, TestOwnerAddress) - suite.Require().NoError(err) + err := RegisterInterchainAccount(path.EndpointA, TestOwnerAddress) + suite.Require().NoError(err) - err = path.EndpointB.ChanOpenTry() - suite.Require().NoError(err) + err = path.EndpointB.ChanOpenTry() + suite.Require().NoError(err) - interchainAccAddr, exists := suite.chainB.GetSimApp().ICAHostKeeper.GetInterchainAccountAddress(suite.chainB.GetContext(), path.EndpointB.ConnectionID, path.EndpointA.ChannelConfig.PortID) - suite.Require().True(exists) + interchainAccAddr, exists := suite.chainB.GetSimApp().ICAHostKeeper.GetInterchainAccountAddress(suite.chainB.GetContext(), path.EndpointB.ConnectionID, path.EndpointA.ChannelConfig.PortID) + suite.Require().True(exists) - metadata = icatypes.NewMetadata(icatypes.Version, ibctesting.FirstConnectionID, ibctesting.FirstConnectionID, interchainAccAddr, icatypes.EncodingProtobuf, icatypes.TxTypeSDKMultiMsg) - versionBytes, err := icatypes.ModuleCdc.MarshalJSON(&metadata) - suite.Require().NoError(err) + metadata = icatypes.NewMetadata(icatypes.Version, ibctesting.FirstConnectionID, ibctesting.FirstConnectionID, interchainAccAddr, icatypes.EncodingProtobuf, icatypes.TxTypeSDKMultiMsg) + versionBytes, err := icatypes.ModuleCdc.MarshalJSON(&metadata) + suite.Require().NoError(err) - path.EndpointB.ChannelConfig.Version = string(versionBytes) + path.EndpointB.ChannelConfig.Version = string(versionBytes) - tc.malleate() // malleate mutates test data + tc.malleate() // malleate mutates test data - err = suite.chainA.GetSimApp().ICAControllerKeeper.OnChanOpenAck(suite.chainA.GetContext(), - path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointA.Counterparty.ChannelConfig.Version, - ) + err = suite.chainA.GetSimApp().ICAControllerKeeper.OnChanOpenAck(suite.chainA.GetContext(), + path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointA.Counterparty.ChannelConfig.Version, + ) - if tc.expPass { - suite.Require().NoError(err) + if tc.expPass { + suite.Require().NoError(err) - activeChannelID, found := suite.chainA.GetSimApp().ICAControllerKeeper.GetActiveChannelID(suite.chainA.GetContext(), ibctesting.FirstConnectionID, path.EndpointA.ChannelConfig.PortID) - suite.Require().True(found) + 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) + suite.Require().Equal(path.EndpointA.ChannelID, activeChannelID) - interchainAccAddress, found := suite.chainA.GetSimApp().ICAControllerKeeper.GetInterchainAccountAddress(suite.chainA.GetContext(), ibctesting.FirstConnectionID, path.EndpointA.ChannelConfig.PortID) - suite.Require().True(found) + 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) - } else { - suite.Require().Error(err) - } - }) + suite.Require().Equal(metadata.Address, interchainAccAddress) + } else { + suite.Require().Error(err) + } + }) + } } } @@ -479,33 +488,35 @@ func (suite *KeeperTestSuite) TestOnChanCloseConfirm() { }, } - for _, tc := range testCases { - tc := tc + for _, ordering := range []channeltypes.Order{channeltypes.UNORDERED, channeltypes.ORDERED} { + for _, tc := range testCases { + tc := tc - suite.Run(tc.name, func() { - suite.SetupTest() // reset + suite.Run(tc.name, func() { + suite.SetupTest() // reset - path = NewICAPath(suite.chainA, suite.chainB) - path.SetupConnections() + path = NewICAPath(suite.chainA, suite.chainB, ordering) + path.SetupConnections() - err := SetupICAPath(path, TestOwnerAddress) - suite.Require().NoError(err) + err := SetupICAPath(path, TestOwnerAddress) + suite.Require().NoError(err) - tc.malleate() // malleate mutates test data + tc.malleate() // malleate mutates test data - err = suite.chainB.GetSimApp().ICAControllerKeeper.OnChanCloseConfirm(suite.chainB.GetContext(), - path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID) + 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(), ibctesting.FirstConnectionID, 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) - suite.Require().False(found) - suite.Require().Empty(activeChannelID) - } else { - suite.Require().Error(err) - } - }) + if tc.expPass { + suite.Require().NoError(err) + suite.Require().False(found) + suite.Require().Empty(activeChannelID) + } else { + suite.Require().Error(err) + } + }) + } } } @@ -640,54 +651,56 @@ func (suite *KeeperTestSuite) TestOnChanUpgradeInit() { }, } - for _, tc := range testCases { - tc := tc + for _, ordering := range []channeltypes.Order{channeltypes.UNORDERED, channeltypes.ORDERED} { + for _, tc := range testCases { + tc := tc - suite.Run(tc.name, func() { - suite.SetupTest() // reset + suite.Run(tc.name, func() { + suite.SetupTest() // reset - path = NewICAPath(suite.chainA, suite.chainB) - path.SetupConnections() + path = NewICAPath(suite.chainA, suite.chainB, ordering) + path.SetupConnections() - err := SetupICAPath(path, TestOwnerAddress) - suite.Require().NoError(err) + err := SetupICAPath(path, TestOwnerAddress) + suite.Require().NoError(err) - currentMetadata, err := suite.chainA.GetSimApp().ICAControllerKeeper.GetAppMetadata(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) - suite.Require().NoError(err) + currentMetadata, err := suite.chainA.GetSimApp().ICAControllerKeeper.GetAppMetadata(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) + suite.Require().NoError(err) - order = channeltypes.ORDERED - metadata = icatypes.NewDefaultMetadata(path.EndpointA.ConnectionID, path.EndpointB.ConnectionID) - // use the same address as the previous metadata. - metadata.Address = currentMetadata.Address + order = channeltypes.ORDERED + metadata = icatypes.NewDefaultMetadata(path.EndpointA.ConnectionID, path.EndpointB.ConnectionID) + // use the same address as the previous metadata. + metadata.Address = currentMetadata.Address - // this is the actual change to the version. - metadata.Encoding = icatypes.EncodingProto3JSON + // this is the actual change to the version. + metadata.Encoding = icatypes.EncodingProto3JSON - path.EndpointA.ChannelConfig.ProposedUpgrade.Fields.Version = string(icatypes.ModuleCdc.MustMarshalJSON(&metadata)) - path.EndpointB.ChannelConfig.ProposedUpgrade.Fields.Version = string(icatypes.ModuleCdc.MustMarshalJSON(&metadata)) + path.EndpointA.ChannelConfig.ProposedUpgrade.Fields.Version = string(icatypes.ModuleCdc.MustMarshalJSON(&metadata)) + path.EndpointB.ChannelConfig.ProposedUpgrade.Fields.Version = string(icatypes.ModuleCdc.MustMarshalJSON(&metadata)) - version = path.EndpointA.ChannelConfig.ProposedUpgrade.Fields.Version + version = path.EndpointA.ChannelConfig.ProposedUpgrade.Fields.Version - tc.malleate() // malleate mutates test data + tc.malleate() // malleate mutates test data - upgradeVersion, err := path.EndpointA.Chain.GetSimApp().ICAControllerKeeper.OnChanUpgradeInit( - path.EndpointA.Chain.GetContext(), - path.EndpointA.ChannelConfig.PortID, - path.EndpointA.ChannelID, - order, - []string{path.EndpointA.ConnectionID}, - version, - ) + upgradeVersion, err := path.EndpointA.Chain.GetSimApp().ICAControllerKeeper.OnChanUpgradeInit( + path.EndpointA.Chain.GetContext(), + path.EndpointA.ChannelConfig.PortID, + path.EndpointA.ChannelID, + order, + []string{path.EndpointA.ConnectionID}, + version, + ) - expPass := tc.expError == nil + expPass := tc.expError == nil - if expPass { - suite.Require().NoError(err) - suite.Require().Equal(upgradeVersion, version) - } else { - suite.Require().ErrorIs(err, tc.expError) - } - }) + if expPass { + suite.Require().NoError(err) + suite.Require().Equal(upgradeVersion, version) + } else { + suite.Require().ErrorIs(err, tc.expError) + } + }) + } } } @@ -806,55 +819,57 @@ func (suite *KeeperTestSuite) TestOnChanUpgradeAck() { }, } - for _, tc := range testCases { - tc := tc + for _, ordering := range []channeltypes.Order{channeltypes.UNORDERED, channeltypes.ORDERED} { + for _, tc := range testCases { + tc := tc - suite.Run(tc.name, func() { - suite.SetupTest() // reset + suite.Run(tc.name, func() { + suite.SetupTest() // reset - path = NewICAPath(suite.chainA, suite.chainB) - path.SetupConnections() + path = NewICAPath(suite.chainA, suite.chainB, ordering) + path.SetupConnections() - err := SetupICAPath(path, TestOwnerAddress) - suite.Require().NoError(err) + err := SetupICAPath(path, TestOwnerAddress) + suite.Require().NoError(err) - currentMetadata, err := suite.chainA.GetSimApp().ICAControllerKeeper.GetAppMetadata(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) - suite.Require().NoError(err) + currentMetadata, err := suite.chainA.GetSimApp().ICAControllerKeeper.GetAppMetadata(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) + suite.Require().NoError(err) - metadata = icatypes.NewDefaultMetadata(path.EndpointA.ConnectionID, path.EndpointB.ConnectionID) - // use the same address as the previous metadata. - metadata.Address = currentMetadata.Address + metadata = icatypes.NewDefaultMetadata(path.EndpointA.ConnectionID, path.EndpointB.ConnectionID) + // use the same address as the previous metadata. + metadata.Address = currentMetadata.Address - // this is the actual change to the version. - metadata.Encoding = icatypes.EncodingProto3JSON + // this is the actual change to the version. + metadata.Encoding = icatypes.EncodingProto3JSON - path.EndpointA.ChannelConfig.ProposedUpgrade.Fields.Version = string(icatypes.ModuleCdc.MustMarshalJSON(&metadata)) - path.EndpointB.ChannelConfig.ProposedUpgrade.Fields.Version = string(icatypes.ModuleCdc.MustMarshalJSON(&metadata)) + path.EndpointA.ChannelConfig.ProposedUpgrade.Fields.Version = string(icatypes.ModuleCdc.MustMarshalJSON(&metadata)) + path.EndpointB.ChannelConfig.ProposedUpgrade.Fields.Version = string(icatypes.ModuleCdc.MustMarshalJSON(&metadata)) - err = path.EndpointA.ChanUpgradeInit() - suite.Require().NoError(err) + err = path.EndpointA.ChanUpgradeInit() + suite.Require().NoError(err) - err = path.EndpointB.ChanUpgradeTry() - suite.Require().NoError(err) + err = path.EndpointB.ChanUpgradeTry() + suite.Require().NoError(err) - counterpartyVersion = path.EndpointB.GetChannel().Version + counterpartyVersion = path.EndpointB.GetChannel().Version - tc.malleate() // malleate mutates test data + tc.malleate() // malleate mutates test data - err = suite.chainA.GetSimApp().ICAControllerKeeper.OnChanUpgradeAck( - suite.chainA.GetContext(), - path.EndpointA.ChannelConfig.PortID, - path.EndpointA.ChannelID, - counterpartyVersion, - ) + err = suite.chainA.GetSimApp().ICAControllerKeeper.OnChanUpgradeAck( + suite.chainA.GetContext(), + path.EndpointA.ChannelConfig.PortID, + path.EndpointA.ChannelID, + counterpartyVersion, + ) - expPass := tc.expError == nil - if expPass { - suite.Require().NoError(err) - suite.Require().Equal(path.EndpointA.GetChannel().Version, counterpartyVersion) - } else { - suite.Require().ErrorIs(err, tc.expError) - } - }) + expPass := tc.expError == nil + if expPass { + suite.Require().NoError(err) + suite.Require().Equal(path.EndpointA.GetChannel().Version, counterpartyVersion) + } else { + suite.Require().ErrorIs(err, tc.expError) + } + }) + } } } 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 b733adff9ca..f8e2486d15d 100644 --- a/modules/apps/27-interchain-accounts/controller/keeper/keeper_test.go +++ b/modules/apps/27-interchain-accounts/controller/keeper/keeper_test.go @@ -52,12 +52,12 @@ func (suite *KeeperTestSuite) SetupTest() { suite.chainC = suite.coordinator.GetChain(ibctesting.GetChainID(3)) } -func NewICAPath(chainA, chainB *ibctesting.TestChain) *ibctesting.Path { +func NewICAPath(chainA, chainB *ibctesting.TestChain, ordering channeltypes.Order) *ibctesting.Path { path := ibctesting.NewPath(chainA, chainB) path.EndpointA.ChannelConfig.PortID = icatypes.HostPortID path.EndpointB.ChannelConfig.PortID = icatypes.HostPortID - path.EndpointA.ChannelConfig.Order = channeltypes.ORDERED - path.EndpointB.ChannelConfig.Order = channeltypes.ORDERED + path.EndpointA.ChannelConfig.Order = ordering + path.EndpointB.ChannelConfig.Order = ordering path.EndpointA.ChannelConfig.Version = TestVersion path.EndpointB.ChannelConfig.Version = TestVersion @@ -90,7 +90,7 @@ func RegisterInterchainAccount(endpoint *ibctesting.Endpoint, owner string) erro channelSequence := endpoint.Chain.App.GetIBCKeeper().ChannelKeeper.GetNextChannelSequence(endpoint.Chain.GetContext()) - if err := endpoint.Chain.GetSimApp().ICAControllerKeeper.RegisterInterchainAccount(endpoint.Chain.GetContext(), endpoint.ConnectionID, owner, TestVersion); err != nil { + if err := endpoint.Chain.GetSimApp().ICAControllerKeeper.RegisterInterchainAccount(endpoint.Chain.GetContext(), endpoint.ConnectionID, owner, TestVersion, endpoint.ChannelConfig.Order); err != nil { return err } @@ -161,127 +161,137 @@ func (suite *KeeperTestSuite) TestNewKeeper() { } func (suite *KeeperTestSuite) TestGetAllPorts() { - suite.SetupTest() + for _, ordering := range []channeltypes.Order{channeltypes.UNORDERED, channeltypes.ORDERED} { + suite.SetupTest() - path := NewICAPath(suite.chainA, suite.chainB) - path.SetupConnections() + path := NewICAPath(suite.chainA, suite.chainB, ordering) + path.SetupConnections() - err := SetupICAPath(path, TestOwnerAddress) - suite.Require().NoError(err) + err := SetupICAPath(path, TestOwnerAddress) + suite.Require().NoError(err) - expectedPorts := []string{TestPortID} + expectedPorts := []string{TestPortID} - ports := suite.chainA.GetSimApp().ICAControllerKeeper.GetAllPorts(suite.chainA.GetContext()) - suite.Require().Len(ports, len(expectedPorts)) - suite.Require().Equal(expectedPorts, ports) + ports := suite.chainA.GetSimApp().ICAControllerKeeper.GetAllPorts(suite.chainA.GetContext()) + suite.Require().Len(ports, len(expectedPorts)) + suite.Require().Equal(expectedPorts, ports) + } } func (suite *KeeperTestSuite) TestGetInterchainAccountAddress() { - suite.SetupTest() + for _, ordering := range []channeltypes.Order{channeltypes.UNORDERED, channeltypes.ORDERED} { + suite.SetupTest() - path := NewICAPath(suite.chainA, suite.chainB) - path.SetupConnections() + path := NewICAPath(suite.chainA, suite.chainB, ordering) + path.SetupConnections() - err := SetupICAPath(path, TestOwnerAddress) - suite.Require().NoError(err) + err := SetupICAPath(path, TestOwnerAddress) + suite.Require().NoError(err) - counterpartyPortID := path.EndpointA.ChannelConfig.PortID + counterpartyPortID := path.EndpointA.ChannelConfig.PortID - retrievedAddr, found := suite.chainA.GetSimApp().ICAControllerKeeper.GetInterchainAccountAddress(suite.chainA.GetContext(), ibctesting.FirstConnectionID, counterpartyPortID) - suite.Require().True(found) - suite.Require().NotEmpty(retrievedAddr) + retrievedAddr, found := suite.chainA.GetSimApp().ICAControllerKeeper.GetInterchainAccountAddress(suite.chainA.GetContext(), ibctesting.FirstConnectionID, counterpartyPortID) + suite.Require().True(found) + suite.Require().NotEmpty(retrievedAddr) - retrievedAddr, found = suite.chainA.GetSimApp().ICAControllerKeeper.GetInterchainAccountAddress(suite.chainA.GetContext(), "invalid conn", "invalid port") - suite.Require().False(found) - suite.Require().Empty(retrievedAddr) + retrievedAddr, found = suite.chainA.GetSimApp().ICAControllerKeeper.GetInterchainAccountAddress(suite.chainA.GetContext(), "invalid conn", "invalid port") + suite.Require().False(found) + suite.Require().Empty(retrievedAddr) + } } func (suite *KeeperTestSuite) TestGetAllActiveChannels() { - var ( - expectedChannelID = "test-channel" - expectedPortID = "test-port" - ) + for _, ordering := range []channeltypes.Order{channeltypes.UNORDERED, channeltypes.ORDERED} { + var ( + expectedChannelID = "test-channel" + expectedPortID = "test-port" + ) - suite.SetupTest() + suite.SetupTest() - path := NewICAPath(suite.chainA, suite.chainB) - path.SetupConnections() - - err := SetupICAPath(path, TestOwnerAddress) - suite.Require().NoError(err) - - suite.chainA.GetSimApp().ICAControllerKeeper.SetActiveChannelID(suite.chainA.GetContext(), ibctesting.FirstConnectionID, expectedPortID, expectedChannelID) - - expectedChannels := []genesistypes.ActiveChannel{ - { - ConnectionId: ibctesting.FirstConnectionID, - PortId: TestPortID, - ChannelId: path.EndpointA.ChannelID, - IsMiddlewareEnabled: true, - }, - { - ConnectionId: ibctesting.FirstConnectionID, - PortId: expectedPortID, - ChannelId: expectedChannelID, - IsMiddlewareEnabled: false, - }, + path := NewICAPath(suite.chainA, suite.chainB, ordering) + path.SetupConnections() + + err := SetupICAPath(path, TestOwnerAddress) + suite.Require().NoError(err) + + suite.chainA.GetSimApp().ICAControllerKeeper.SetActiveChannelID(suite.chainA.GetContext(), ibctesting.FirstConnectionID, expectedPortID, expectedChannelID) + + expectedChannels := []genesistypes.ActiveChannel{ + { + ConnectionId: ibctesting.FirstConnectionID, + PortId: TestPortID, + ChannelId: path.EndpointA.ChannelID, + IsMiddlewareEnabled: true, + }, + { + ConnectionId: ibctesting.FirstConnectionID, + PortId: expectedPortID, + ChannelId: expectedChannelID, + IsMiddlewareEnabled: false, + }, + } + + activeChannels := suite.chainA.GetSimApp().ICAControllerKeeper.GetAllActiveChannels(suite.chainA.GetContext()) + suite.Require().Len(activeChannels, len(expectedChannels)) + suite.Require().Equal(expectedChannels, activeChannels) } - - activeChannels := suite.chainA.GetSimApp().ICAControllerKeeper.GetAllActiveChannels(suite.chainA.GetContext()) - suite.Require().Len(activeChannels, len(expectedChannels)) - suite.Require().Equal(expectedChannels, activeChannels) } func (suite *KeeperTestSuite) TestGetAllInterchainAccounts() { - var ( - expectedAccAddr = "test-acc-addr" - expectedPortID = "test-port" - ) - - suite.SetupTest() - - path := NewICAPath(suite.chainA, suite.chainB) - path.SetupConnections() - - err := SetupICAPath(path, TestOwnerAddress) - suite.Require().NoError(err) - - interchainAccAddr, exists := suite.chainB.GetSimApp().ICAHostKeeper.GetInterchainAccountAddress(suite.chainB.GetContext(), path.EndpointB.ConnectionID, path.EndpointA.ChannelConfig.PortID) - suite.Require().True(exists) + for _, ordering := range []channeltypes.Order{channeltypes.UNORDERED, channeltypes.ORDERED} { + var ( + expectedAccAddr = "test-acc-addr" + expectedPortID = "test-port" + ) - suite.chainA.GetSimApp().ICAControllerKeeper.SetInterchainAccountAddress(suite.chainA.GetContext(), ibctesting.FirstConnectionID, expectedPortID, expectedAccAddr) + suite.SetupTest() - expectedAccounts := []genesistypes.RegisteredInterchainAccount{ - { - ConnectionId: ibctesting.FirstConnectionID, - PortId: TestPortID, - AccountAddress: interchainAccAddr, - }, - { - ConnectionId: ibctesting.FirstConnectionID, - PortId: expectedPortID, - AccountAddress: expectedAccAddr, - }, + path := NewICAPath(suite.chainA, suite.chainB, ordering) + path.SetupConnections() + + err := SetupICAPath(path, TestOwnerAddress) + suite.Require().NoError(err) + + interchainAccAddr, exists := suite.chainB.GetSimApp().ICAHostKeeper.GetInterchainAccountAddress(suite.chainB.GetContext(), path.EndpointB.ConnectionID, path.EndpointA.ChannelConfig.PortID) + suite.Require().True(exists) + + suite.chainA.GetSimApp().ICAControllerKeeper.SetInterchainAccountAddress(suite.chainA.GetContext(), ibctesting.FirstConnectionID, expectedPortID, expectedAccAddr) + + expectedAccounts := []genesistypes.RegisteredInterchainAccount{ + { + ConnectionId: ibctesting.FirstConnectionID, + PortId: TestPortID, + AccountAddress: interchainAccAddr, + }, + { + ConnectionId: ibctesting.FirstConnectionID, + PortId: expectedPortID, + AccountAddress: expectedAccAddr, + }, + } + + interchainAccounts := suite.chainA.GetSimApp().ICAControllerKeeper.GetAllInterchainAccounts(suite.chainA.GetContext()) + suite.Require().Len(interchainAccounts, len(expectedAccounts)) + suite.Require().Equal(expectedAccounts, interchainAccounts) } - - interchainAccounts := suite.chainA.GetSimApp().ICAControllerKeeper.GetAllInterchainAccounts(suite.chainA.GetContext()) - suite.Require().Len(interchainAccounts, len(expectedAccounts)) - suite.Require().Equal(expectedAccounts, interchainAccounts) } func (suite *KeeperTestSuite) TestIsActiveChannel() { - suite.SetupTest() + for _, ordering := range []channeltypes.Order{channeltypes.UNORDERED, channeltypes.ORDERED} { + suite.SetupTest() - path := NewICAPath(suite.chainA, suite.chainB) - owner := TestOwnerAddress - path.SetupConnections() + path := NewICAPath(suite.chainA, suite.chainB, ordering) + owner := TestOwnerAddress + path.SetupConnections() - err := SetupICAPath(path, owner) - suite.Require().NoError(err) - portID := path.EndpointA.ChannelConfig.PortID + err := SetupICAPath(path, owner) + suite.Require().NoError(err) + portID := path.EndpointA.ChannelConfig.PortID - isActive := suite.chainA.GetSimApp().ICAControllerKeeper.IsActiveChannel(suite.chainA.GetContext(), ibctesting.FirstConnectionID, portID) - suite.Require().Equal(isActive, true) + isActive := suite.chainA.GetSimApp().ICAControllerKeeper.IsActiveChannel(suite.chainA.GetContext(), ibctesting.FirstConnectionID, portID) + suite.Require().Equal(isActive, true) + } } func (suite *KeeperTestSuite) TestSetInterchainAccountAddress() { diff --git a/modules/apps/27-interchain-accounts/controller/keeper/migrations_test.go b/modules/apps/27-interchain-accounts/controller/keeper/migrations_test.go index f0011439d14..ec48a442860 100644 --- a/modules/apps/27-interchain-accounts/controller/keeper/migrations_test.go +++ b/modules/apps/27-interchain-accounts/controller/keeper/migrations_test.go @@ -43,37 +43,39 @@ func (suite *KeeperTestSuite) TestAssertChannelCapabilityMigrations() { }, } - for _, tc := range testCases { - tc := tc + for _, ordering := range []channeltypes.Order{channeltypes.UNORDERED, channeltypes.ORDERED} { + for _, tc := range testCases { + tc := tc - suite.Run(tc.name, func() { - suite.SetupTest() + suite.Run(tc.name, func() { + suite.SetupTest() - path := NewICAPath(suite.chainA, suite.chainB) - path.SetupConnections() + path := NewICAPath(suite.chainA, suite.chainB, ordering) + path.SetupConnections() - err := SetupICAPath(path, ibctesting.TestAccAddress) - suite.Require().NoError(err) + err := SetupICAPath(path, ibctesting.TestAccAddress) + suite.Require().NoError(err) - tc.malleate() + tc.malleate() - migrator := icacontrollerkeeper.NewMigrator(&suite.chainA.GetSimApp().ICAControllerKeeper) - err = migrator.AssertChannelCapabilityMigrations(suite.chainA.GetContext()) + migrator := icacontrollerkeeper.NewMigrator(&suite.chainA.GetSimApp().ICAControllerKeeper) + err = migrator.AssertChannelCapabilityMigrations(suite.chainA.GetContext()) - if tc.expPass { - suite.Require().NoError(err) + if tc.expPass { + suite.Require().NoError(err) - isMiddlewareEnabled := suite.chainA.GetSimApp().ICAControllerKeeper.IsMiddlewareEnabled( - suite.chainA.GetContext(), - path.EndpointA.ChannelConfig.PortID, - path.EndpointA.ConnectionID, - ) + isMiddlewareEnabled := suite.chainA.GetSimApp().ICAControllerKeeper.IsMiddlewareEnabled( + suite.chainA.GetContext(), + path.EndpointA.ChannelConfig.PortID, + path.EndpointA.ConnectionID, + ) - suite.Require().True(isMiddlewareEnabled) - } else { - suite.Require().Error(err) - } - }) + suite.Require().True(isMiddlewareEnabled) + } else { + suite.Require().Error(err) + } + }) + } } } diff --git a/modules/apps/27-interchain-accounts/controller/keeper/msg_server.go b/modules/apps/27-interchain-accounts/controller/keeper/msg_server.go index 66ad2afd0a9..1cdeb601eae 100644 --- a/modules/apps/27-interchain-accounts/controller/keeper/msg_server.go +++ b/modules/apps/27-interchain-accounts/controller/keeper/msg_server.go @@ -9,6 +9,7 @@ import ( "github.com/cosmos/ibc-go/v8/modules/apps/27-interchain-accounts/controller/types" icatypes "github.com/cosmos/ibc-go/v8/modules/apps/27-interchain-accounts/types" + channeltypes "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types" ibcerrors "github.com/cosmos/ibc-go/v8/modules/core/errors" ) @@ -39,7 +40,13 @@ func (s msgServer) RegisterInterchainAccount(goCtx context.Context, msg *types.M s.SetMiddlewareDisabled(ctx, portID, msg.ConnectionId) - channelID, err := s.registerInterchainAccount(ctx, msg.ConnectionId, portID, msg.Version, msg.Ordering) + // use ORDER_UNORDERED as default in case msg's ordering is NONE + order := msg.Ordering + if order == channeltypes.NONE { + order = channeltypes.UNORDERED + } + + channelID, err := s.registerInterchainAccount(ctx, msg.ConnectionId, portID, msg.Version, order) if err != nil { s.Logger(ctx).Error("error registering interchain account", "error", err.Error()) return nil, err diff --git a/modules/apps/27-interchain-accounts/controller/keeper/msg_server_test.go b/modules/apps/27-interchain-accounts/controller/keeper/msg_server_test.go index 625c0441859..462bc422a8f 100644 --- a/modules/apps/27-interchain-accounts/controller/keeper/msg_server_test.go +++ b/modules/apps/27-interchain-accounts/controller/keeper/msg_server_test.go @@ -21,6 +21,7 @@ import ( func (suite *KeeperTestSuite) TestRegisterInterchainAccount_MsgServer() { var ( msg *types.MsgRegisterInterchainAccount + expectedOrderding channeltypes.Order expectedChannelID = "channel-0" ) @@ -34,6 +35,14 @@ func (suite *KeeperTestSuite) TestRegisterInterchainAccount_MsgServer() { true, func() {}, }, + { + "success: ordering falls back to UNORDERED if not specified", + true, + func() { + msg.Ordering = channeltypes.NONE + expectedOrderding = channeltypes.UNORDERED + }, + }, { "invalid connection id", false, @@ -66,38 +75,46 @@ func (suite *KeeperTestSuite) TestRegisterInterchainAccount_MsgServer() { }, } - for _, tc := range testCases { - tc := tc + for _, ordering := range []channeltypes.Order{channeltypes.UNORDERED, channeltypes.ORDERED} { + for _, tc := range testCases { + tc := tc - suite.Run(tc.name, func() { - suite.SetupTest() + suite.Run(tc.name, func() { + expectedOrderding = ordering - path := NewICAPath(suite.chainA, suite.chainB) - path.SetupConnections() + suite.SetupTest() - msg = types.NewMsgRegisterInterchainAccount(ibctesting.FirstConnectionID, ibctesting.TestAccAddress, "", channeltypes.ORDERED) + path := NewICAPath(suite.chainA, suite.chainB, ordering) + path.SetupConnections() - tc.malleate() + msg = types.NewMsgRegisterInterchainAccount(ibctesting.FirstConnectionID, ibctesting.TestAccAddress, "", ordering) - ctx := suite.chainA.GetContext() - msgServer := keeper.NewMsgServerImpl(&suite.chainA.GetSimApp().ICAControllerKeeper) - res, err := msgServer.RegisterInterchainAccount(ctx, msg) + tc.malleate() - if tc.expPass { - suite.Require().NoError(err) - suite.Require().NotNil(res) - suite.Require().Equal(expectedChannelID, res.ChannelId) + ctx := suite.chainA.GetContext() + msgServer := keeper.NewMsgServerImpl(&suite.chainA.GetSimApp().ICAControllerKeeper) + res, err := msgServer.RegisterInterchainAccount(ctx, msg) - events := ctx.EventManager().Events() - suite.Require().Len(events, 2) - suite.Require().Equal(events[0].Type, channeltypes.EventTypeChannelOpenInit) - suite.Require().Equal(events[1].Type, sdk.EventTypeMessage) - } else { - suite.Require().Error(err) - suite.Require().Nil(res) - } - }) + if tc.expPass { + suite.Require().NoError(err) + suite.Require().NotNil(res) + suite.Require().Equal(expectedChannelID, res.ChannelId) + + events := ctx.EventManager().Events() + suite.Require().Len(events, 2) + suite.Require().Equal(events[0].Type, channeltypes.EventTypeChannelOpenInit) + suite.Require().Equal(events[1].Type, sdk.EventTypeMessage) + path.EndpointA.ChannelConfig.PortID = res.PortId + path.EndpointA.ChannelID = res.ChannelId + channel := path.EndpointA.GetChannel() + suite.Require().Equal(expectedOrderding, channel.Ordering) + } else { + suite.Require().Error(err) + suite.Require().Nil(res) + } + }) + } } } @@ -149,61 +166,63 @@ func (suite *KeeperTestSuite) TestSubmitTx() { }, } - for _, tc := range testCases { - tc := tc + for _, ordering := range []channeltypes.Order{channeltypes.UNORDERED, channeltypes.ORDERED} { + for _, tc := range testCases { + tc := tc - suite.Run(tc.name, func() { - suite.SetupTest() + suite.Run(tc.name, func() { + suite.SetupTest() - owner := TestOwnerAddress - path = NewICAPath(suite.chainA, suite.chainB) - path.SetupConnections() + owner := TestOwnerAddress + path = NewICAPath(suite.chainA, suite.chainB, ordering) + path.SetupConnections() - err := SetupICAPath(path, owner) - suite.Require().NoError(err) + err := SetupICAPath(path, owner) + suite.Require().NoError(err) - portID, err := icatypes.NewControllerPortID(TestOwnerAddress) - suite.Require().NoError(err) + portID, err := icatypes.NewControllerPortID(TestOwnerAddress) + suite.Require().NoError(err) - // get the address of the interchain account stored in state during handshake step - interchainAccountAddr, found := suite.chainA.GetSimApp().ICAControllerKeeper.GetInterchainAccountAddress(suite.chainA.GetContext(), path.EndpointA.ConnectionID, portID) - suite.Require().True(found) + // get the address of the interchain account stored in state during handshake step + interchainAccountAddr, found := suite.chainA.GetSimApp().ICAControllerKeeper.GetInterchainAccountAddress(suite.chainA.GetContext(), path.EndpointA.ConnectionID, portID) + suite.Require().True(found) - // create bank transfer message that will execute on the host chain - icaMsg := &banktypes.MsgSend{ - FromAddress: interchainAccountAddr, - ToAddress: suite.chainB.SenderAccount.GetAddress().String(), - Amount: sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.NewInt(100))), - } + // create bank transfer message that will execute on the host chain + icaMsg := &banktypes.MsgSend{ + FromAddress: interchainAccountAddr, + ToAddress: suite.chainB.SenderAccount.GetAddress().String(), + Amount: sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.NewInt(100))), + } - data, err := icatypes.SerializeCosmosTx(suite.chainA.GetSimApp().AppCodec(), []proto.Message{icaMsg}, icatypes.EncodingProtobuf) - suite.Require().NoError(err) + data, err := icatypes.SerializeCosmosTx(suite.chainA.GetSimApp().AppCodec(), []proto.Message{icaMsg}, icatypes.EncodingProtobuf) + suite.Require().NoError(err) - packetData := icatypes.InterchainAccountPacketData{ - Type: icatypes.EXECUTE_TX, - Data: data, - Memo: "memo", - } + packetData := icatypes.InterchainAccountPacketData{ + Type: icatypes.EXECUTE_TX, + Data: data, + Memo: "memo", + } - timeoutTimestamp := uint64(suite.chainA.GetContext().BlockTime().Add(time.Minute).UnixNano()) - connectionID := path.EndpointA.ConnectionID + timeoutTimestamp := uint64(suite.chainA.GetContext().BlockTime().Add(time.Minute).UnixNano()) + connectionID := path.EndpointA.ConnectionID - msg = types.NewMsgSendTx(owner, connectionID, timeoutTimestamp, packetData) + msg = types.NewMsgSendTx(owner, connectionID, timeoutTimestamp, packetData) - tc.malleate() // malleate mutates test data + tc.malleate() // malleate mutates test data - ctx := suite.chainA.GetContext() - msgServer := keeper.NewMsgServerImpl(&suite.chainA.GetSimApp().ICAControllerKeeper) - res, err := msgServer.SendTx(ctx, msg) + ctx := suite.chainA.GetContext() + msgServer := keeper.NewMsgServerImpl(&suite.chainA.GetSimApp().ICAControllerKeeper) + res, err := msgServer.SendTx(ctx, msg) - if tc.expPass { - suite.Require().NoError(err) - suite.Require().NotNil(res) - } else { - suite.Require().Error(err) - suite.Require().Nil(res) - } - }) + if tc.expPass { + suite.Require().NoError(err) + suite.Require().NotNil(res) + } else { + suite.Require().Error(err) + suite.Require().Nil(res) + } + }) + } } } 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 3f81bb6dbf6..910e3bf9173 100644 --- a/modules/apps/27-interchain-accounts/controller/keeper/relay_test.go +++ b/modules/apps/27-interchain-accounts/controller/keeper/relay_test.go @@ -142,30 +142,32 @@ func (suite *KeeperTestSuite) TestSendTx() { }, } - for _, tc := range testCases { - tc := tc + for _, ordering := range []channeltypes.Order{channeltypes.UNORDERED, channeltypes.ORDERED} { + for _, tc := range testCases { + tc := tc - suite.Run(tc.msg, func() { - suite.SetupTest() // reset - timeoutTimestamp = ^uint64(0) // default + suite.Run(tc.msg, func() { + suite.SetupTest() // reset + timeoutTimestamp = ^uint64(0) // default - path = NewICAPath(suite.chainA, suite.chainB) - path.SetupConnections() + path = NewICAPath(suite.chainA, suite.chainB, ordering) + path.SetupConnections() - err := SetupICAPath(path, TestOwnerAddress) - suite.Require().NoError(err) + err := SetupICAPath(path, TestOwnerAddress) + suite.Require().NoError(err) - tc.malleate() // malleate mutates test data + tc.malleate() // malleate mutates test data - //nolint: staticcheck // SA1019: ibctesting.FirstConnectionID is deprecated: use path.EndpointA.ConnectionID instead. (staticcheck) - _, err = suite.chainA.GetSimApp().ICAControllerKeeper.SendTx(suite.chainA.GetContext(), nil, ibctesting.FirstConnectionID, path.EndpointA.ChannelConfig.PortID, packetData, timeoutTimestamp) + //nolint: staticcheck // SA1019: ibctesting.FirstConnectionID is deprecated: use path.EndpointA.ConnectionID instead. (staticcheck) + _, err = suite.chainA.GetSimApp().ICAControllerKeeper.SendTx(suite.chainA.GetContext(), nil, ibctesting.FirstConnectionID, path.EndpointA.ChannelConfig.PortID, packetData, timeoutTimestamp) - if tc.expPass { - suite.Require().NoError(err) - } else { - suite.Require().Error(err) - } - }) + if tc.expPass { + suite.Require().NoError(err) + } else { + suite.Require().Error(err) + } + }) + } } } @@ -184,38 +186,40 @@ func (suite *KeeperTestSuite) TestOnTimeoutPacket() { }, } - for _, tc := range testCases { - tc := tc - - suite.Run(tc.msg, func() { - suite.SetupTest() // reset - - path = NewICAPath(suite.chainA, suite.chainB) - path.SetupConnections() + for _, ordering := range []channeltypes.Order{channeltypes.UNORDERED, channeltypes.ORDERED} { + for _, tc := range testCases { + tc := tc - err := SetupICAPath(path, TestOwnerAddress) - suite.Require().NoError(err) + suite.Run(tc.msg, func() { + suite.SetupTest() // reset - tc.malleate() // malleate mutates test data + path = NewICAPath(suite.chainA, suite.chainB, ordering) + path.SetupConnections() - packet := channeltypes.NewPacket( - []byte{}, - 1, - path.EndpointA.ChannelConfig.PortID, - path.EndpointA.ChannelID, - path.EndpointB.ChannelConfig.PortID, - path.EndpointB.ChannelID, - clienttypes.NewHeight(0, 100), - 0, - ) - - err = suite.chainA.GetSimApp().ICAControllerKeeper.OnTimeoutPacket(suite.chainA.GetContext(), packet) - - if tc.expPass { + err := SetupICAPath(path, TestOwnerAddress) suite.Require().NoError(err) - } else { - suite.Require().Error(err) - } - }) + + tc.malleate() // malleate mutates test data + + packet := channeltypes.NewPacket( + []byte{}, + 1, + path.EndpointA.ChannelConfig.PortID, + path.EndpointA.ChannelID, + path.EndpointB.ChannelConfig.PortID, + path.EndpointB.ChannelID, + clienttypes.NewHeight(0, 100), + 0, + ) + + err = suite.chainA.GetSimApp().ICAControllerKeeper.OnTimeoutPacket(suite.chainA.GetContext(), packet) + + if tc.expPass { + suite.Require().NoError(err) + } else { + suite.Require().Error(err) + } + }) + } } } diff --git a/modules/apps/27-interchain-accounts/controller/migrations/v6/migrations_test.go b/modules/apps/27-interchain-accounts/controller/migrations/v6/migrations_test.go index 3c88c512d3d..d63b69ec110 100644 --- a/modules/apps/27-interchain-accounts/controller/migrations/v6/migrations_test.go +++ b/modules/apps/27-interchain-accounts/controller/migrations/v6/migrations_test.go @@ -68,7 +68,7 @@ func (*MigrationsTestSuite) RegisterInterchainAccount(endpoint *ibctesting.Endpo channelSequence := endpoint.Chain.App.GetIBCKeeper().ChannelKeeper.GetNextChannelSequence(endpoint.Chain.GetContext()) - if err := endpoint.Chain.GetSimApp().ICAControllerKeeper.RegisterInterchainAccount(endpoint.Chain.GetContext(), endpoint.ConnectionID, owner, endpoint.ChannelConfig.Version); err != nil { + if err := endpoint.Chain.GetSimApp().ICAControllerKeeper.RegisterInterchainAccount(endpoint.Chain.GetContext(), endpoint.ConnectionID, owner, endpoint.ChannelConfig.Version, channeltypes.ORDERED); err != nil { return 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 9ffb67a8f4d..481856e08a5 100644 --- a/modules/apps/27-interchain-accounts/host/ibc_module_test.go +++ b/modules/apps/27-interchain-accounts/host/ibc_module_test.go @@ -63,12 +63,12 @@ func (suite *InterchainAccountsTestSuite) SetupTest() { suite.chainB = suite.coordinator.GetChain(ibctesting.GetChainID(2)) } -func NewICAPath(chainA, chainB *ibctesting.TestChain) *ibctesting.Path { +func NewICAPath(chainA, chainB *ibctesting.TestChain, ordering channeltypes.Order) *ibctesting.Path { path := ibctesting.NewPath(chainA, chainB) path.EndpointA.ChannelConfig.PortID = icatypes.HostPortID path.EndpointB.ChannelConfig.PortID = icatypes.HostPortID - path.EndpointA.ChannelConfig.Order = channeltypes.ORDERED - path.EndpointB.ChannelConfig.Order = channeltypes.ORDERED + path.EndpointA.ChannelConfig.Order = ordering + path.EndpointB.ChannelConfig.Order = ordering path.EndpointA.ChannelConfig.Version = TestVersion path.EndpointB.ChannelConfig.Version = TestVersion @@ -83,7 +83,7 @@ func RegisterInterchainAccount(endpoint *ibctesting.Endpoint, owner string) erro channelSequence := endpoint.Chain.App.GetIBCKeeper().ChannelKeeper.GetNextChannelSequence(endpoint.Chain.GetContext()) - if err := endpoint.Chain.GetSimApp().ICAControllerKeeper.RegisterInterchainAccount(endpoint.Chain.GetContext(), endpoint.ConnectionID, owner, endpoint.ChannelConfig.Version); err != nil { + if err := endpoint.Chain.GetSimApp().ICAControllerKeeper.RegisterInterchainAccount(endpoint.Chain.GetContext(), endpoint.ConnectionID, owner, endpoint.ChannelConfig.Version, endpoint.ChannelConfig.Order); err != nil { return err } @@ -117,16 +117,18 @@ func SetupICAPath(path *ibctesting.Path, owner string) error { // Test initiating a ChanOpenInit using the host chain instead of the controller chain // ChainA is the controller chain. ChainB is the host chain func (suite *InterchainAccountsTestSuite) TestChanOpenInit() { - suite.SetupTest() // reset - path := NewICAPath(suite.chainA, suite.chainB) - path.SetupConnections() + for _, ordering := range []channeltypes.Order{channeltypes.UNORDERED, channeltypes.ORDERED} { + suite.SetupTest() // reset + path := NewICAPath(suite.chainA, suite.chainB, ordering) + path.SetupConnections() - // use chainB (host) for ChanOpenInit - msg := channeltypes.NewMsgChannelOpenInit(path.EndpointB.ChannelConfig.PortID, icatypes.Version, channeltypes.ORDERED, []string{path.EndpointB.ConnectionID}, path.EndpointA.ChannelConfig.PortID, icatypes.ModuleName) - handler := suite.chainB.GetSimApp().MsgServiceRouter().Handler(msg) - _, err := handler(suite.chainB.GetContext(), msg) + // use chainB (host) for ChanOpenInit + msg := channeltypes.NewMsgChannelOpenInit(path.EndpointB.ChannelConfig.PortID, icatypes.Version, ordering, []string{path.EndpointB.ConnectionID}, path.EndpointA.ChannelConfig.PortID, icatypes.ModuleName) + handler := suite.chainB.GetSimApp().MsgServiceRouter().Handler(msg) + _, err := handler(suite.chainB.GetContext(), msg) - suite.Require().Error(err) + suite.Require().Error(err) + } } func (suite *InterchainAccountsTestSuite) TestOnChanOpenTry() { @@ -141,12 +143,7 @@ func (suite *InterchainAccountsTestSuite) TestOnChanOpenTry() { expPass bool }{ { - "success w/ ORDERED channel", func() {}, true, - }, - { - "success w/ UNORDERED channel", func() { - channel.Ordering = channeltypes.UNORDERED - }, true, + "success", func() {}, true, }, { "account address generation is block dependent", func() { @@ -177,94 +174,98 @@ func (suite *InterchainAccountsTestSuite) TestOnChanOpenTry() { }, } - for _, tc := range testCases { - tc := tc - - suite.Run(tc.name, func() { - suite.SetupTest() // reset + for _, ordering := range []channeltypes.Order{channeltypes.UNORDERED, channeltypes.ORDERED} { + for _, tc := range testCases { + tc := tc - path = NewICAPath(suite.chainA, suite.chainB) - path.SetupConnections() + suite.Run(tc.name, func() { + suite.SetupTest() // reset - err := RegisterInterchainAccount(path.EndpointA, TestOwnerAddress) - suite.Require().NoError(err) - path.EndpointB.ChannelID = ibctesting.FirstChannelID + path = NewICAPath(suite.chainA, suite.chainB, ordering) + path.SetupConnections() - // default values - counterparty := channeltypes.NewCounterparty(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) - channel = &channeltypes.Channel{ - State: channeltypes.TRYOPEN, - Ordering: channeltypes.ORDERED, - Counterparty: counterparty, - ConnectionHops: []string{path.EndpointB.ConnectionID}, - Version: path.EndpointB.ChannelConfig.Version, - } + err := RegisterInterchainAccount(path.EndpointA, TestOwnerAddress) + suite.Require().NoError(err) + path.EndpointB.ChannelID = ibctesting.FirstChannelID + + // default values + counterparty := channeltypes.NewCounterparty(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) + channel = &channeltypes.Channel{ + State: channeltypes.TRYOPEN, + Ordering: ordering, + Counterparty: counterparty, + ConnectionHops: []string{path.EndpointB.ConnectionID}, + Version: path.EndpointB.ChannelConfig.Version, + } - tc.malleate() + tc.malleate() - // ensure channel on chainB is set in state - suite.chainB.GetSimApp().IBCKeeper.ChannelKeeper.SetChannel(suite.chainB.GetContext(), path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, *channel) + // ensure channel on chainB is set in state + suite.chainB.GetSimApp().IBCKeeper.ChannelKeeper.SetChannel(suite.chainB.GetContext(), path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, *channel) - module, _, err := suite.chainB.App.GetIBCKeeper().PortKeeper.LookupModuleByPort(suite.chainB.GetContext(), path.EndpointB.ChannelConfig.PortID) - suite.Require().NoError(err) + module, _, err := suite.chainB.App.GetIBCKeeper().PortKeeper.LookupModuleByPort(suite.chainB.GetContext(), path.EndpointB.ChannelConfig.PortID) + suite.Require().NoError(err) - chanCap, err := suite.chainB.App.GetScopedIBCKeeper().NewCapability(suite.chainB.GetContext(), host.ChannelCapabilityPath(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID)) - suite.Require().NoError(err) + chanCap, err := suite.chainB.App.GetScopedIBCKeeper().NewCapability(suite.chainB.GetContext(), host.ChannelCapabilityPath(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID)) + suite.Require().NoError(err) - cbs, ok := suite.chainB.App.GetIBCKeeper().PortKeeper.Route(module) - suite.Require().True(ok) + cbs, ok := suite.chainB.App.GetIBCKeeper().PortKeeper.Route(module) + suite.Require().True(ok) - version, err := cbs.OnChanOpenTry(suite.chainB.GetContext(), channel.Ordering, channel.ConnectionHops, - path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, chanCap, channel.Counterparty, path.EndpointA.ChannelConfig.Version, - ) + version, err := cbs.OnChanOpenTry(suite.chainB.GetContext(), channel.Ordering, channel.ConnectionHops, + path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, chanCap, channel.Counterparty, path.EndpointA.ChannelConfig.Version, + ) - if tc.expPass { - suite.Require().NoError(err) + if tc.expPass { + suite.Require().NoError(err) - addr, exists := suite.chainB.GetSimApp().ICAHostKeeper.GetInterchainAccountAddress(suite.chainB.GetContext(), path.EndpointB.ConnectionID, counterparty.PortId) - suite.Require().True(exists) - suite.Require().NotNil(addr) - } else { - suite.Require().Error(err) - suite.Require().Equal("", version) - } - }) + addr, exists := suite.chainB.GetSimApp().ICAHostKeeper.GetInterchainAccountAddress(suite.chainB.GetContext(), path.EndpointB.ConnectionID, counterparty.PortId) + suite.Require().True(exists) + suite.Require().NotNil(addr) + } else { + suite.Require().Error(err) + suite.Require().Equal("", version) + } + }) + } } } // Test initiating a ChanOpenAck using the host chain instead of the controller chain // ChainA is the controller chain. ChainB is the host chain func (suite *InterchainAccountsTestSuite) TestChanOpenAck() { - suite.SetupTest() // reset - path := NewICAPath(suite.chainA, suite.chainB) - path.SetupConnections() + for _, ordering := range []channeltypes.Order{channeltypes.UNORDERED, channeltypes.ORDERED} { + suite.SetupTest() // reset + path := NewICAPath(suite.chainA, suite.chainB, ordering) + path.SetupConnections() - err := RegisterInterchainAccount(path.EndpointA, TestOwnerAddress) - suite.Require().NoError(err) + err := RegisterInterchainAccount(path.EndpointA, TestOwnerAddress) + suite.Require().NoError(err) - err = path.EndpointB.ChanOpenTry() - suite.Require().NoError(err) + err = path.EndpointB.ChanOpenTry() + suite.Require().NoError(err) - // chainA maliciously sets channel to TRYOPEN - channel := channeltypes.NewChannel(channeltypes.TRYOPEN, channeltypes.ORDERED, channeltypes.NewCounterparty(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID), []string{path.EndpointA.ConnectionID}, TestVersion) - suite.chainA.GetSimApp().GetIBCKeeper().ChannelKeeper.SetChannel(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, channel) + // chainA maliciously sets channel to TRYOPEN + channel := channeltypes.NewChannel(channeltypes.TRYOPEN, channeltypes.ORDERED, channeltypes.NewCounterparty(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID), []string{path.EndpointA.ConnectionID}, TestVersion) + suite.chainA.GetSimApp().GetIBCKeeper().ChannelKeeper.SetChannel(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, channel) - // commit state changes so proof can be created - suite.chainA.NextBlock() + // commit state changes so proof can be created + suite.chainA.NextBlock() - err = path.EndpointB.UpdateClient() - suite.Require().NoError(err) + err = path.EndpointB.UpdateClient() + suite.Require().NoError(err) - // query proof from ChainA - channelKey := host.ChannelKey(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) - tryProof, proofHeight := path.EndpointA.Chain.QueryProof(channelKey) + // query proof from ChainA + channelKey := host.ChannelKey(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) + tryProof, proofHeight := path.EndpointA.Chain.QueryProof(channelKey) - // use chainB (host) for ChanOpenAck - msg := channeltypes.NewMsgChannelOpenAck(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, path.EndpointA.ChannelID, TestVersion, tryProof, proofHeight, icatypes.ModuleName) - handler := suite.chainB.GetSimApp().MsgServiceRouter().Handler(msg) - _, err = handler(suite.chainB.GetContext(), msg) + // use chainB (host) for ChanOpenAck + msg := channeltypes.NewMsgChannelOpenAck(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, path.EndpointA.ChannelID, TestVersion, tryProof, proofHeight, icatypes.ModuleName) + handler := suite.chainB.GetSimApp().MsgServiceRouter().Handler(msg) + _, err = handler(suite.chainB.GetContext(), msg) - suite.Require().Error(err) + suite.Require().Error(err) + } } func (suite *InterchainAccountsTestSuite) TestOnChanOpenConfirm() { @@ -293,61 +294,67 @@ func (suite *InterchainAccountsTestSuite) TestOnChanOpenConfirm() { }, } - for _, tc := range testCases { - tc := tc + for _, ordering := range []channeltypes.Order{channeltypes.UNORDERED, channeltypes.ORDERED} { + for _, tc := range testCases { + tc := tc - suite.Run(tc.name, func() { - suite.SetupTest() - path := NewICAPath(suite.chainA, suite.chainB) - path.SetupConnections() + suite.Run(tc.name, func() { + suite.SetupTest() + path := NewICAPath(suite.chainA, suite.chainB, ordering) + path.SetupConnections() - err := RegisterInterchainAccount(path.EndpointA, TestOwnerAddress) - suite.Require().NoError(err) + err := RegisterInterchainAccount(path.EndpointA, TestOwnerAddress) + suite.Require().NoError(err) - err = path.EndpointB.ChanOpenTry() - suite.Require().NoError(err) + err = path.EndpointB.ChanOpenTry() + suite.Require().NoError(err) - err = path.EndpointA.ChanOpenAck() - suite.Require().NoError(err) + err = path.EndpointA.ChanOpenAck() + suite.Require().NoError(err) - tc.malleate() + tc.malleate() - module, _, err := suite.chainB.App.GetIBCKeeper().PortKeeper.LookupModuleByPort(suite.chainB.GetContext(), path.EndpointB.ChannelConfig.PortID) - suite.Require().NoError(err) + module, _, err := suite.chainB.App.GetIBCKeeper().PortKeeper.LookupModuleByPort(suite.chainB.GetContext(), path.EndpointB.ChannelConfig.PortID) + suite.Require().NoError(err) - cbs, ok := suite.chainB.App.GetIBCKeeper().PortKeeper.Route(module) - suite.Require().True(ok) + cbs, ok := suite.chainB.App.GetIBCKeeper().PortKeeper.Route(module) + suite.Require().True(ok) - err = cbs.OnChanOpenConfirm(suite.chainB.GetContext(), path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID) + err = cbs.OnChanOpenConfirm(suite.chainB.GetContext(), path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID) - if tc.expPass { - suite.Require().NoError(err) - } else { - suite.Require().Error(err) - } - }) + if tc.expPass { + suite.Require().NoError(err) + } else { + suite.Require().Error(err) + } + }) + } } } // OnChanCloseInit on host (chainB) func (suite *InterchainAccountsTestSuite) TestOnChanCloseInit() { - path := NewICAPath(suite.chainA, suite.chainB) - path.SetupConnections() + for _, ordering := range []channeltypes.Order{channeltypes.UNORDERED, channeltypes.ORDERED} { + suite.SetupTest() // reset - err := SetupICAPath(path, TestOwnerAddress) - suite.Require().NoError(err) + path := NewICAPath(suite.chainA, suite.chainB, ordering) + path.SetupConnections() - module, _, err := suite.chainB.App.GetIBCKeeper().PortKeeper.LookupModuleByPort(suite.chainB.GetContext(), path.EndpointB.ChannelConfig.PortID) - suite.Require().NoError(err) + err := SetupICAPath(path, TestOwnerAddress) + suite.Require().NoError(err) - cbs, ok := suite.chainB.App.GetIBCKeeper().PortKeeper.Route(module) - suite.Require().True(ok) + module, _, err := suite.chainB.App.GetIBCKeeper().PortKeeper.LookupModuleByPort(suite.chainB.GetContext(), path.EndpointB.ChannelConfig.PortID) + suite.Require().NoError(err) - err = cbs.OnChanCloseInit( - suite.chainB.GetContext(), path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, - ) + cbs, ok := suite.chainB.App.GetIBCKeeper().PortKeeper.Route(module) + suite.Require().True(ok) - suite.Require().Error(err) + err = cbs.OnChanCloseInit( + suite.chainB.GetContext(), path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, + ) + + suite.Require().Error(err) + } } func (suite *InterchainAccountsTestSuite) TestOnChanCloseConfirm() { @@ -363,34 +370,36 @@ func (suite *InterchainAccountsTestSuite) TestOnChanCloseConfirm() { }, } - for _, tc := range testCases { - tc := tc + for _, ordering := range []channeltypes.Order{channeltypes.UNORDERED, channeltypes.ORDERED} { + for _, tc := range testCases { + tc := tc - suite.Run(tc.name, func() { - suite.SetupTest() // reset + suite.Run(tc.name, func() { + suite.SetupTest() // reset - path = NewICAPath(suite.chainA, suite.chainB) - path.SetupConnections() + path = NewICAPath(suite.chainA, suite.chainB, ordering) + path.SetupConnections() - err := SetupICAPath(path, TestOwnerAddress) - suite.Require().NoError(err) + err := SetupICAPath(path, TestOwnerAddress) + suite.Require().NoError(err) - tc.malleate() // malleate mutates test data - module, _, err := suite.chainB.App.GetIBCKeeper().PortKeeper.LookupModuleByPort(suite.chainB.GetContext(), path.EndpointB.ChannelConfig.PortID) - suite.Require().NoError(err) + tc.malleate() // malleate mutates test data + module, _, err := suite.chainB.App.GetIBCKeeper().PortKeeper.LookupModuleByPort(suite.chainB.GetContext(), path.EndpointB.ChannelConfig.PortID) + suite.Require().NoError(err) - cbs, ok := suite.chainB.App.GetIBCKeeper().PortKeeper.Route(module) - suite.Require().True(ok) + cbs, ok := suite.chainB.App.GetIBCKeeper().PortKeeper.Route(module) + suite.Require().True(ok) - err = cbs.OnChanCloseConfirm( - suite.chainB.GetContext(), path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID) + err = cbs.OnChanCloseConfirm( + suite.chainB.GetContext(), path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID) - if tc.expPass { - suite.Require().NoError(err) - } else { - suite.Require().Error(err) - } - }) + if tc.expPass { + suite.Require().NoError(err) + } else { + suite.Require().Error(err) + } + }) + } } } @@ -429,106 +438,108 @@ func (suite *InterchainAccountsTestSuite) TestOnRecvPacket() { }, } - for _, tc := range testCases { - tc := tc - - suite.Run(tc.name, func() { - suite.SetupTest() // reset - - path := NewICAPath(suite.chainA, suite.chainB) - path.SetupConnections() - err := SetupICAPath(path, TestOwnerAddress) - suite.Require().NoError(err) - - // send 100stake to interchain account wallet - amount, _ := sdk.ParseCoinsNormalized("100stake") - 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) - suite.Require().NoError(err) - - // build packet data - msg := &banktypes.MsgSend{ - FromAddress: interchainAccountAddr, - ToAddress: suite.chainB.SenderAccount.GetAddress().String(), - Amount: amount, - } - data, err := icatypes.SerializeCosmosTx(suite.chainA.GetSimApp().AppCodec(), []proto.Message{msg}, icatypes.EncodingProtobuf) - suite.Require().NoError(err) - - icaPacketData := icatypes.InterchainAccountPacketData{ - Type: icatypes.EXECUTE_TX, - Data: data, - } - packetData = icaPacketData.GetBytes() - - // build expected ack - protoAny, err := codectypes.NewAnyWithValue(&banktypes.MsgSendResponse{}) - suite.Require().NoError(err) - - expectedTxResponse, err := proto.Marshal(&sdk.TxMsgData{ - MsgResponses: []*codectypes.Any{protoAny}, - }) - suite.Require().NoError(err) + for _, ordering := range []channeltypes.Order{channeltypes.UNORDERED, channeltypes.ORDERED} { + for _, tc := range testCases { + tc := tc - expectedAck := channeltypes.NewResultAcknowledgement(expectedTxResponse) + suite.Run(tc.name, func() { + suite.SetupTest() // reset - params := types.NewParams(true, []string{sdk.MsgTypeURL(msg)}) - suite.chainB.GetSimApp().ICAHostKeeper.SetParams(suite.chainB.GetContext(), params) + path := NewICAPath(suite.chainA, suite.chainB, ordering) + path.SetupConnections() + err := SetupICAPath(path, TestOwnerAddress) + suite.Require().NoError(err) - // malleate packetData for test cases - tc.malleate() + // send 100stake to interchain account wallet + amount, _ := sdk.ParseCoinsNormalized("100stake") + 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} - seq := uint64(1) - packet := channeltypes.NewPacket(packetData, seq, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, clienttypes.NewHeight(0, 100), 0) + _, err = suite.chainB.SendMsgs(bankMsg) + suite.Require().NoError(err) - tc.malleate() + // build packet data + msg := &banktypes.MsgSend{ + FromAddress: interchainAccountAddr, + ToAddress: suite.chainB.SenderAccount.GetAddress().String(), + Amount: amount, + } + data, err := icatypes.SerializeCosmosTx(suite.chainA.GetSimApp().AppCodec(), []proto.Message{msg}, icatypes.EncodingProtobuf) + suite.Require().NoError(err) + + icaPacketData := icatypes.InterchainAccountPacketData{ + Type: icatypes.EXECUTE_TX, + Data: data, + } + packetData = icaPacketData.GetBytes() + + // build expected ack + protoAny, err := codectypes.NewAnyWithValue(&banktypes.MsgSendResponse{}) + suite.Require().NoError(err) + + expectedTxResponse, err := proto.Marshal(&sdk.TxMsgData{ + MsgResponses: []*codectypes.Any{protoAny}, + }) + suite.Require().NoError(err) - module, _, err := suite.chainB.App.GetIBCKeeper().PortKeeper.LookupModuleByPort(suite.chainB.GetContext(), path.EndpointB.ChannelConfig.PortID) - suite.Require().NoError(err) + expectedAck := channeltypes.NewResultAcknowledgement(expectedTxResponse) - cbs, ok := suite.chainB.App.GetIBCKeeper().PortKeeper.Route(module) - suite.Require().True(ok) + params := types.NewParams(true, []string{sdk.MsgTypeURL(msg)}) + suite.chainB.GetSimApp().ICAHostKeeper.SetParams(suite.chainB.GetContext(), params) - ctx := suite.chainB.GetContext() - ack := cbs.OnRecvPacket(ctx, packet, nil) + // malleate packetData for test cases + tc.malleate() - expectedAttributes := []sdk.Attribute{ - sdk.NewAttribute(sdk.AttributeKeyModule, icatypes.ModuleName), - sdk.NewAttribute(icatypes.AttributeKeyHostChannelID, packet.GetDestChannel()), - sdk.NewAttribute(icatypes.AttributeKeyAckSuccess, fmt.Sprintf("%t", ack.Success())), - } + seq := uint64(1) + packet := channeltypes.NewPacket(packetData, seq, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, clienttypes.NewHeight(0, 100), 0) - if tc.expAckSuccess { - suite.Require().True(ack.Success()) - suite.Require().Equal(expectedAck, ack) + tc.malleate() - expectedEvents := sdk.Events{ - sdk.NewEvent( - icatypes.EventTypePacket, - expectedAttributes..., - ), - }.ToABCIEvents() + module, _, err := suite.chainB.App.GetIBCKeeper().PortKeeper.LookupModuleByPort(suite.chainB.GetContext(), path.EndpointB.ChannelConfig.PortID) + suite.Require().NoError(err) - expectedEvents = sdk.MarkEventsToIndex(expectedEvents, map[string]struct{}{}) - ibctesting.AssertEvents(&suite.Suite, expectedEvents, ctx.EventManager().Events().ToABCIEvents()) + cbs, ok := suite.chainB.App.GetIBCKeeper().PortKeeper.Route(module) + suite.Require().True(ok) - } else { - suite.Require().False(ack.Success()) + ctx := suite.chainB.GetContext() + ack := cbs.OnRecvPacket(ctx, packet, nil) - expectedAttributes = append(expectedAttributes, sdk.NewAttribute(icatypes.AttributeKeyAckError, tc.eventErrorMsg)) - expectedEvents := sdk.Events{ - sdk.NewEvent( - icatypes.EventTypePacket, - expectedAttributes..., - ), - }.ToABCIEvents() + expectedAttributes := []sdk.Attribute{ + sdk.NewAttribute(sdk.AttributeKeyModule, icatypes.ModuleName), + sdk.NewAttribute(icatypes.AttributeKeyHostChannelID, packet.GetDestChannel()), + sdk.NewAttribute(icatypes.AttributeKeyAckSuccess, fmt.Sprintf("%t", ack.Success())), + } - expectedEvents = sdk.MarkEventsToIndex(expectedEvents, map[string]struct{}{}) - ibctesting.AssertEvents(&suite.Suite, expectedEvents, ctx.EventManager().Events().ToABCIEvents()) - } - }) + if tc.expAckSuccess { + suite.Require().True(ack.Success()) + suite.Require().Equal(expectedAck, ack) + + expectedEvents := sdk.Events{ + sdk.NewEvent( + icatypes.EventTypePacket, + expectedAttributes..., + ), + }.ToABCIEvents() + + expectedEvents = sdk.MarkEventsToIndex(expectedEvents, map[string]struct{}{}) + ibctesting.AssertEvents(&suite.Suite, expectedEvents, ctx.EventManager().Events().ToABCIEvents()) + + } else { + suite.Require().False(ack.Success()) + + expectedAttributes = append(expectedAttributes, sdk.NewAttribute(icatypes.AttributeKeyAckError, tc.eventErrorMsg)) + expectedEvents := sdk.Events{ + sdk.NewEvent( + icatypes.EventTypePacket, + expectedAttributes..., + ), + }.ToABCIEvents() + + expectedEvents = sdk.MarkEventsToIndex(expectedEvents, map[string]struct{}{}) + ibctesting.AssertEvents(&suite.Suite, expectedEvents, ctx.EventManager().Events().ToABCIEvents()) + } + }) + } } } @@ -543,45 +554,47 @@ func (suite *InterchainAccountsTestSuite) TestOnAcknowledgementPacket() { }, } - for _, tc := range testCases { - tc := tc - - suite.Run(tc.name, func() { - suite.SetupTest() // reset - - path := NewICAPath(suite.chainA, suite.chainB) - path.SetupConnections() - - err := SetupICAPath(path, TestOwnerAddress) - suite.Require().NoError(err) - - tc.malleate() // malleate mutates test data + for _, ordering := range []channeltypes.Order{channeltypes.UNORDERED, channeltypes.ORDERED} { + for _, tc := range testCases { + tc := tc - module, _, err := suite.chainB.App.GetIBCKeeper().PortKeeper.LookupModuleByPort(suite.chainB.GetContext(), path.EndpointB.ChannelConfig.PortID) - suite.Require().NoError(err) + suite.Run(tc.name, func() { + suite.SetupTest() // reset - cbs, ok := suite.chainB.App.GetIBCKeeper().PortKeeper.Route(module) - suite.Require().True(ok) + path := NewICAPath(suite.chainA, suite.chainB, ordering) + path.SetupConnections() - packet := channeltypes.NewPacket( - []byte("empty packet data"), - suite.chainA.SenderAccount.GetSequence(), - path.EndpointB.ChannelConfig.PortID, - path.EndpointB.ChannelID, - path.EndpointA.ChannelConfig.PortID, - path.EndpointA.ChannelID, - clienttypes.NewHeight(0, 100), - 0, - ) + err := SetupICAPath(path, TestOwnerAddress) + suite.Require().NoError(err) - err = cbs.OnAcknowledgementPacket(suite.chainB.GetContext(), packet, []byte("ackBytes"), nil) + tc.malleate() // malleate mutates test data - if tc.expPass { + module, _, err := suite.chainB.App.GetIBCKeeper().PortKeeper.LookupModuleByPort(suite.chainB.GetContext(), path.EndpointB.ChannelConfig.PortID) suite.Require().NoError(err) - } else { - suite.Require().Error(err) - } - }) + + cbs, ok := suite.chainB.App.GetIBCKeeper().PortKeeper.Route(module) + suite.Require().True(ok) + + packet := channeltypes.NewPacket( + []byte("empty packet data"), + suite.chainA.SenderAccount.GetSequence(), + path.EndpointB.ChannelConfig.PortID, + path.EndpointB.ChannelID, + path.EndpointA.ChannelConfig.PortID, + path.EndpointA.ChannelID, + clienttypes.NewHeight(0, 100), + 0, + ) + + err = cbs.OnAcknowledgementPacket(suite.chainB.GetContext(), packet, []byte("ackBytes"), nil) + + if tc.expPass { + suite.Require().NoError(err) + } else { + suite.Require().Error(err) + } + }) + } } } @@ -596,73 +609,79 @@ func (suite *InterchainAccountsTestSuite) TestOnTimeoutPacket() { }, } - for _, tc := range testCases { - tc := tc - - suite.Run(tc.name, func() { - suite.SetupTest() // reset - - path := NewICAPath(suite.chainA, suite.chainB) - path.SetupConnections() - - err := SetupICAPath(path, TestOwnerAddress) - suite.Require().NoError(err) + for _, ordering := range []channeltypes.Order{channeltypes.UNORDERED, channeltypes.ORDERED} { + for _, tc := range testCases { + tc := tc - tc.malleate() // malleate mutates test data + suite.Run(tc.name, func() { + suite.SetupTest() // reset - module, _, err := suite.chainA.App.GetIBCKeeper().PortKeeper.LookupModuleByPort(suite.chainA.GetContext(), path.EndpointB.ChannelConfig.PortID) - suite.Require().NoError(err) + path := NewICAPath(suite.chainA, suite.chainB, ordering) + path.SetupConnections() - cbs, ok := suite.chainA.App.GetIBCKeeper().PortKeeper.Route(module) - suite.Require().True(ok) - - packet := channeltypes.NewPacket( - []byte("empty packet data"), - suite.chainA.SenderAccount.GetSequence(), - path.EndpointB.ChannelConfig.PortID, - path.EndpointB.ChannelID, - path.EndpointA.ChannelConfig.PortID, - path.EndpointA.ChannelID, - clienttypes.NewHeight(0, 100), - 0, - ) + err := SetupICAPath(path, TestOwnerAddress) + suite.Require().NoError(err) - err = cbs.OnTimeoutPacket(suite.chainA.GetContext(), packet, nil) + tc.malleate() // malleate mutates test data - if tc.expPass { + module, _, err := suite.chainA.App.GetIBCKeeper().PortKeeper.LookupModuleByPort(suite.chainA.GetContext(), path.EndpointB.ChannelConfig.PortID) suite.Require().NoError(err) - } else { - suite.Require().Error(err) - } - }) + + cbs, ok := suite.chainA.App.GetIBCKeeper().PortKeeper.Route(module) + suite.Require().True(ok) + + packet := channeltypes.NewPacket( + []byte("empty packet data"), + suite.chainA.SenderAccount.GetSequence(), + path.EndpointB.ChannelConfig.PortID, + path.EndpointB.ChannelID, + path.EndpointA.ChannelConfig.PortID, + path.EndpointA.ChannelID, + clienttypes.NewHeight(0, 100), + 0, + ) + + err = cbs.OnTimeoutPacket(suite.chainA.GetContext(), packet, nil) + + if tc.expPass { + suite.Require().NoError(err) + } else { + suite.Require().Error(err) + } + }) + } } } // OnChanUpgradeInit callback returns error on host chains func (suite *InterchainAccountsTestSuite) TestOnChanUpgradeInit() { - path := NewICAPath(suite.chainA, suite.chainB) - path.SetupConnections() + for _, ordering := range []channeltypes.Order{channeltypes.UNORDERED, channeltypes.ORDERED} { + suite.SetupTest() // reset - err := SetupICAPath(path, TestOwnerAddress) - suite.Require().NoError(err) + path := NewICAPath(suite.chainA, suite.chainB, ordering) + path.SetupConnections() - // call application callback directly - module, _, err := suite.chainB.App.GetIBCKeeper().PortKeeper.LookupModuleByPort(suite.chainB.GetContext(), path.EndpointB.ChannelConfig.PortID) - suite.Require().NoError(err) + err := SetupICAPath(path, TestOwnerAddress) + suite.Require().NoError(err) - app, ok := suite.chainB.App.GetIBCKeeper().PortKeeper.Route(module) - suite.Require().True(ok) - cbs, ok := app.(porttypes.UpgradableModule) - suite.Require().True(ok) + // call application callback directly + module, _, err := suite.chainB.App.GetIBCKeeper().PortKeeper.LookupModuleByPort(suite.chainB.GetContext(), path.EndpointB.ChannelConfig.PortID) + suite.Require().NoError(err) - version, err := cbs.OnChanUpgradeInit( - suite.chainB.GetContext(), path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, - path.EndpointB.ChannelConfig.Order, []string{path.EndpointB.ConnectionID}, path.EndpointB.ChannelConfig.Version, - ) + app, ok := suite.chainB.App.GetIBCKeeper().PortKeeper.Route(module) + suite.Require().True(ok) + cbs, ok := app.(porttypes.UpgradableModule) + suite.Require().True(ok) - suite.Require().Error(err) - suite.Require().ErrorIs(err, icatypes.ErrInvalidChannelFlow) - suite.Require().Equal("", version) + version, err := cbs.OnChanUpgradeInit( + suite.chainB.GetContext(), path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, + path.EndpointB.ChannelConfig.Order, []string{path.EndpointB.ConnectionID}, path.EndpointB.ChannelConfig.Version, + ) + + suite.Require().Error(err) + suite.Require().ErrorIs(err, icatypes.ErrInvalidChannelFlow) + suite.Require().Equal("", version) + } } func (suite *InterchainAccountsTestSuite) TestOnChanUpgradeTry() { @@ -681,81 +700,87 @@ func (suite *InterchainAccountsTestSuite) TestOnChanUpgradeTry() { }, } - for _, tc := range testCases { - tc := tc - - suite.Run(tc.name, func() { - suite.SetupTest() // reset - - path := NewICAPath(suite.chainA, suite.chainB) - path.SetupConnections() + for _, ordering := range []channeltypes.Order{channeltypes.UNORDERED, channeltypes.ORDERED} { + for _, tc := range testCases { + tc := tc - err := SetupICAPath(path, TestOwnerAddress) - suite.Require().NoError(err) + suite.Run(tc.name, func() { + suite.SetupTest() // reset - interchainAccountAddr, found := suite.chainB.GetSimApp().ICAHostKeeper.GetInterchainAccountAddress(suite.chainB.GetContext(), path.EndpointB.ConnectionID, path.EndpointA.ChannelConfig.PortID) - suite.Require().True(found) + path := NewICAPath(suite.chainA, suite.chainB, ordering) + path.SetupConnections() - metadata := icatypes.NewDefaultMetadata(path.EndpointA.ConnectionID, path.EndpointB.ConnectionID) - metadata.Address = interchainAccountAddr - metadata.Encoding = icatypes.EncodingProto3JSON // this is the actual change to the version - path.EndpointA.ChannelConfig.ProposedUpgrade.Fields.Version = string(icatypes.ModuleCdc.MustMarshalJSON(&metadata)) - - err = path.EndpointA.ChanUpgradeInit() - suite.Require().NoError(err) + err := SetupICAPath(path, TestOwnerAddress) + suite.Require().NoError(err) - tc.malleate() // malleate mutates test data + interchainAccountAddr, found := suite.chainB.GetSimApp().ICAHostKeeper.GetInterchainAccountAddress(suite.chainB.GetContext(), path.EndpointB.ConnectionID, path.EndpointA.ChannelConfig.PortID) + suite.Require().True(found) - module, _, err := suite.chainB.App.GetIBCKeeper().PortKeeper.LookupModuleByPort(suite.chainB.GetContext(), path.EndpointB.ChannelConfig.PortID) - suite.Require().NoError(err) + metadata := icatypes.NewDefaultMetadata(path.EndpointA.ConnectionID, path.EndpointB.ConnectionID) + metadata.Address = interchainAccountAddr + metadata.Encoding = icatypes.EncodingProto3JSON // this is the actual change to the version + path.EndpointA.ChannelConfig.ProposedUpgrade.Fields.Version = string(icatypes.ModuleCdc.MustMarshalJSON(&metadata)) - app, ok := suite.chainB.App.GetIBCKeeper().PortKeeper.Route(module) - suite.Require().True(ok) - cbs, ok := app.(porttypes.UpgradableModule) - suite.Require().True(ok) + err = path.EndpointA.ChanUpgradeInit() + suite.Require().NoError(err) - version, err := cbs.OnChanUpgradeTry( - suite.chainB.GetContext(), - path.EndpointB.ChannelConfig.PortID, - path.EndpointB.ChannelID, - channeltypes.ORDERED, - []string{path.EndpointB.ConnectionID}, - path.EndpointA.ChannelConfig.ProposedUpgrade.Fields.Version, - ) + tc.malleate() // malleate mutates test data - if tc.expError == nil { + module, _, err := suite.chainB.App.GetIBCKeeper().PortKeeper.LookupModuleByPort(suite.chainB.GetContext(), path.EndpointB.ChannelConfig.PortID) suite.Require().NoError(err) - } else { - suite.Require().Error(err) - suite.Require().Empty(version) - } - }) + + app, ok := suite.chainB.App.GetIBCKeeper().PortKeeper.Route(module) + suite.Require().True(ok) + cbs, ok := app.(porttypes.UpgradableModule) + suite.Require().True(ok) + + version, err := cbs.OnChanUpgradeTry( + suite.chainB.GetContext(), + path.EndpointB.ChannelConfig.PortID, + path.EndpointB.ChannelID, + ordering, + []string{path.EndpointB.ConnectionID}, + path.EndpointA.ChannelConfig.ProposedUpgrade.Fields.Version, + ) + + if tc.expError == nil { + suite.Require().NoError(err) + } else { + suite.Require().Error(err) + suite.Require().Empty(version) + } + }) + } } } // OnChanUpgradeAck callback returns error on host chains func (suite *InterchainAccountsTestSuite) TestOnChanUpgradeAck() { - path := NewICAPath(suite.chainA, suite.chainB) - path.SetupConnections() + for _, ordering := range []channeltypes.Order{channeltypes.UNORDERED, channeltypes.ORDERED} { + suite.SetupTest() // reset - err := SetupICAPath(path, TestOwnerAddress) - suite.Require().NoError(err) + path := NewICAPath(suite.chainA, suite.chainB, ordering) + path.SetupConnections() - // call application callback directly - module, _, err := suite.chainB.App.GetIBCKeeper().PortKeeper.LookupModuleByPort(suite.chainB.GetContext(), path.EndpointB.ChannelConfig.PortID) - suite.Require().NoError(err) + err := SetupICAPath(path, TestOwnerAddress) + suite.Require().NoError(err) - app, ok := suite.chainB.App.GetIBCKeeper().PortKeeper.Route(module) - suite.Require().True(ok) - cbs, ok := app.(porttypes.UpgradableModule) - suite.Require().True(ok) + // call application callback directly + module, _, err := suite.chainB.App.GetIBCKeeper().PortKeeper.LookupModuleByPort(suite.chainB.GetContext(), path.EndpointB.ChannelConfig.PortID) + suite.Require().NoError(err) - err = cbs.OnChanUpgradeAck( - suite.chainB.GetContext(), path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, path.EndpointA.ChannelConfig.Version, - ) + app, ok := suite.chainB.App.GetIBCKeeper().PortKeeper.Route(module) + suite.Require().True(ok) + cbs, ok := app.(porttypes.UpgradableModule) + suite.Require().True(ok) - suite.Require().Error(err) - suite.Require().ErrorIs(err, icatypes.ErrInvalidChannelFlow) + err = cbs.OnChanUpgradeAck( + suite.chainB.GetContext(), path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, path.EndpointA.ChannelConfig.Version, + ) + + suite.Require().Error(err) + suite.Require().ErrorIs(err, icatypes.ErrInvalidChannelFlow) + } } func (suite *InterchainAccountsTestSuite) fundICAWallet(ctx sdk.Context, portID string, amount sdk.Coins) { @@ -776,92 +801,96 @@ func (suite *InterchainAccountsTestSuite) fundICAWallet(ctx sdk.Context, portID // TestControlAccountAfterChannelClose tests that a controller chain can control a registered interchain account after the currently active channel for that interchain account has been closed. // A new channel will be opened for the controller portID. The interchain account address should remain unchanged. func (suite *InterchainAccountsTestSuite) TestControlAccountAfterChannelClose() { - path := NewICAPath(suite.chainA, suite.chainB) - - // use a fee enabled version to cover unwrapping channel version code paths - feeMetadata := feetypes.Metadata{ - FeeVersion: feetypes.Version, - AppVersion: TestVersion, + for _, ordering := range []channeltypes.Order{channeltypes.UNORDERED, channeltypes.ORDERED} { + suite.SetupTest() // reset + + path := NewICAPath(suite.chainA, suite.chainB, ordering) + + // use a fee enabled version to cover unwrapping channel version code paths + feeMetadata := feetypes.Metadata{ + FeeVersion: feetypes.Version, + AppVersion: TestVersion, + } + + feeICAVersion := string(feetypes.ModuleCdc.MustMarshalJSON(&feeMetadata)) + + path.EndpointA.ChannelConfig.Version = feeICAVersion + path.EndpointB.ChannelConfig.Version = feeICAVersion + + path.SetupConnections() + + err := SetupICAPath(path, TestOwnerAddress) + suite.Require().NoError(err) + + // two sends will be performed, one after initial creation of the account and one after channel closure and reopening + var ( + startingBal = sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.NewInt(100000))) + tokenAmt = sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.NewInt(5000))) + expBalAfterFirstSend = startingBal.Sub(tokenAmt...) + expBalAfterSecondSend = expBalAfterFirstSend.Sub(tokenAmt...) + ) + + // check that the account is working as expected + suite.fundICAWallet(suite.chainB.GetContext(), path.EndpointA.ChannelConfig.PortID, startingBal) + interchainAccountAddr, found := suite.chainB.GetSimApp().ICAHostKeeper.GetInterchainAccountAddress(suite.chainB.GetContext(), path.EndpointB.ConnectionID, path.EndpointA.ChannelConfig.PortID) + suite.Require().True(found) + + msg := &banktypes.MsgSend{ + FromAddress: interchainAccountAddr, + ToAddress: suite.chainB.SenderAccount.GetAddress().String(), + Amount: tokenAmt, + } + + data, err := icatypes.SerializeCosmosTx(suite.chainA.GetSimApp().AppCodec(), []proto.Message{msg}, icatypes.EncodingProtobuf) + suite.Require().NoError(err) + + icaPacketData := icatypes.InterchainAccountPacketData{ + Type: icatypes.EXECUTE_TX, + Data: data, + } + + params := types.NewParams(true, []string{sdk.MsgTypeURL(msg)}) + suite.chainB.GetSimApp().ICAHostKeeper.SetParams(suite.chainB.GetContext(), params) + + //nolint: staticcheck // SA1019: ibctesting.FirstConnectionID is deprecated: use path.EndpointA.ConnectionID instead. (staticcheck) + _, err = suite.chainA.GetSimApp().ICAControllerKeeper.SendTx(suite.chainA.GetContext(), nil, ibctesting.FirstConnectionID, path.EndpointA.ChannelConfig.PortID, icaPacketData, ^uint64(0)) + suite.Require().NoError(err) + err = path.EndpointB.UpdateClient() + suite.Require().NoError(err) + + // 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)) + err = path.RelayPacket(packetRelay) + suite.Require().NoError(err) // relay committed + + // check that the ica balance is updated + icaAddr, err := sdk.AccAddressFromBech32(interchainAccountAddr) + suite.Require().NoError(err) + + suite.assertBalance(icaAddr, expBalAfterFirstSend) + + // close the channel + path.EndpointA.UpdateChannel(func(channel *channeltypes.Channel) { channel.State = channeltypes.CLOSED }) + path.EndpointB.UpdateChannel(func(channel *channeltypes.Channel) { channel.State = channeltypes.CLOSED }) + + // open a new channel on the same port + path.EndpointA.ChannelID = "" + path.EndpointB.ChannelID = "" + path.CreateChannels() + + //nolint: staticcheck // SA1019: ibctesting.FirstConnectionID is deprecated: use path.EndpointA.ConnectionID instead. (staticcheck) + _, err = suite.chainA.GetSimApp().ICAControllerKeeper.SendTx(suite.chainA.GetContext(), nil, ibctesting.FirstConnectionID, path.EndpointA.ChannelConfig.PortID, icaPacketData, ^uint64(0)) + suite.Require().NoError(err) + err = path.EndpointB.UpdateClient() + suite.Require().NoError(err) + + // 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)) + err = path.RelayPacket(packetRelay) + suite.Require().NoError(err) // relay committed + + suite.assertBalance(icaAddr, expBalAfterSecondSend) } - - feeICAVersion := string(feetypes.ModuleCdc.MustMarshalJSON(&feeMetadata)) - - path.EndpointA.ChannelConfig.Version = feeICAVersion - path.EndpointB.ChannelConfig.Version = feeICAVersion - - path.SetupConnections() - - err := SetupICAPath(path, TestOwnerAddress) - suite.Require().NoError(err) - - // two sends will be performed, one after initial creation of the account and one after channel closure and reopening - var ( - startingBal = sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.NewInt(100000))) - tokenAmt = sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.NewInt(5000))) - expBalAfterFirstSend = startingBal.Sub(tokenAmt...) - expBalAfterSecondSend = expBalAfterFirstSend.Sub(tokenAmt...) - ) - - // check that the account is working as expected - suite.fundICAWallet(suite.chainB.GetContext(), path.EndpointA.ChannelConfig.PortID, startingBal) - interchainAccountAddr, found := suite.chainB.GetSimApp().ICAHostKeeper.GetInterchainAccountAddress(suite.chainB.GetContext(), path.EndpointB.ConnectionID, path.EndpointA.ChannelConfig.PortID) - suite.Require().True(found) - - msg := &banktypes.MsgSend{ - FromAddress: interchainAccountAddr, - ToAddress: suite.chainB.SenderAccount.GetAddress().String(), - Amount: tokenAmt, - } - - data, err := icatypes.SerializeCosmosTx(suite.chainA.GetSimApp().AppCodec(), []proto.Message{msg}, icatypes.EncodingProtobuf) - suite.Require().NoError(err) - - icaPacketData := icatypes.InterchainAccountPacketData{ - Type: icatypes.EXECUTE_TX, - Data: data, - } - - params := types.NewParams(true, []string{sdk.MsgTypeURL(msg)}) - suite.chainB.GetSimApp().ICAHostKeeper.SetParams(suite.chainB.GetContext(), params) - - //nolint: staticcheck // SA1019: ibctesting.FirstConnectionID is deprecated: use path.EndpointA.ConnectionID instead. (staticcheck) - _, err = suite.chainA.GetSimApp().ICAControllerKeeper.SendTx(suite.chainA.GetContext(), nil, ibctesting.FirstConnectionID, path.EndpointA.ChannelConfig.PortID, icaPacketData, ^uint64(0)) - suite.Require().NoError(err) - err = path.EndpointB.UpdateClient() - suite.Require().NoError(err) - - // 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)) - err = path.RelayPacket(packetRelay) - suite.Require().NoError(err) // relay committed - - // check that the ica balance is updated - icaAddr, err := sdk.AccAddressFromBech32(interchainAccountAddr) - suite.Require().NoError(err) - - suite.assertBalance(icaAddr, expBalAfterFirstSend) - - // close the channel - path.EndpointA.UpdateChannel(func(channel *channeltypes.Channel) { channel.State = channeltypes.CLOSED }) - path.EndpointB.UpdateChannel(func(channel *channeltypes.Channel) { channel.State = channeltypes.CLOSED }) - - // open a new channel on the same port - path.EndpointA.ChannelID = "" - path.EndpointB.ChannelID = "" - path.CreateChannels() - - //nolint: staticcheck // SA1019: ibctesting.FirstConnectionID is deprecated: use path.EndpointA.ConnectionID instead. (staticcheck) - _, err = suite.chainA.GetSimApp().ICAControllerKeeper.SendTx(suite.chainA.GetContext(), nil, ibctesting.FirstConnectionID, path.EndpointA.ChannelConfig.PortID, icaPacketData, ^uint64(0)) - suite.Require().NoError(err) - err = path.EndpointB.UpdateClient() - suite.Require().NoError(err) - - // 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)) - err = path.RelayPacket(packetRelay) - suite.Require().NoError(err) // relay committed - - suite.assertBalance(icaAddr, expBalAfterSecondSend) } // assertBalance asserts that the provided address has exactly the expected balance. @@ -872,26 +901,30 @@ func (suite *InterchainAccountsTestSuite) assertBalance(addr sdk.AccAddress, exp } func (suite *InterchainAccountsTestSuite) TestPacketDataUnmarshalerInterface() { - path := NewICAPath(suite.chainA, suite.chainB) - path.SetupConnections() - err := SetupICAPath(path, TestOwnerAddress) - suite.Require().NoError(err) - - expPacketData := icatypes.InterchainAccountPacketData{ - Type: icatypes.EXECUTE_TX, - Data: []byte("data"), - Memo: "", + for _, ordering := range []channeltypes.Order{channeltypes.UNORDERED, channeltypes.ORDERED} { + suite.SetupTest() // reset + + path := NewICAPath(suite.chainA, suite.chainB, ordering) + path.SetupConnections() + err := SetupICAPath(path, TestOwnerAddress) + suite.Require().NoError(err) + + expPacketData := icatypes.InterchainAccountPacketData{ + Type: icatypes.EXECUTE_TX, + Data: []byte("data"), + Memo: "", + } + + // Context, port identifier and channel identifier are unused for host. + packetData, err := icahost.IBCModule{}.UnmarshalPacketData(suite.chainA.GetContext(), "", "", expPacketData.GetBytes()) + suite.Require().NoError(err) + suite.Require().Equal(expPacketData, packetData) + + // test invalid packet data + invalidPacketData := []byte("invalid packet data") + // Context, port identifier and channel identifier are unused for host. + packetData, err = icahost.IBCModule{}.UnmarshalPacketData(suite.chainA.GetContext(), "", "", invalidPacketData) + suite.Require().Error(err) + suite.Require().Nil(packetData) } - - // Context, port identifier and channel identifier are unused for host. - packetData, err := icahost.IBCModule{}.UnmarshalPacketData(suite.chainA.GetContext(), "", "", expPacketData.GetBytes()) - suite.Require().NoError(err) - suite.Require().Equal(expPacketData, packetData) - - // test invalid packet data - invalidPacketData := []byte("invalid packet data") - // Context, port identifier and channel identifier are unused for host. - packetData, err = icahost.IBCModule{}.UnmarshalPacketData(suite.chainA.GetContext(), "", "", invalidPacketData) - suite.Require().Error(err) - suite.Require().Nil(packetData) } 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 642288fed3f..5bb0f58d046 100644 --- a/modules/apps/27-interchain-accounts/host/keeper/genesis_test.go +++ b/modules/apps/27-interchain-accounts/host/keeper/genesis_test.go @@ -5,6 +5,7 @@ import ( "github.com/cosmos/ibc-go/v8/modules/apps/27-interchain-accounts/host/keeper" "github.com/cosmos/ibc-go/v8/modules/apps/27-interchain-accounts/host/types" icatypes "github.com/cosmos/ibc-go/v8/modules/apps/27-interchain-accounts/types" + channeltypes "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types" host "github.com/cosmos/ibc-go/v8/modules/core/24-host" ibctesting "github.com/cosmos/ibc-go/v8/testing" ) @@ -112,27 +113,29 @@ func (suite *KeeperTestSuite) TestGenesisParams() { } func (suite *KeeperTestSuite) TestExportGenesis() { - suite.SetupTest() + for _, ordering := range []channeltypes.Order{channeltypes.UNORDERED, channeltypes.ORDERED} { + suite.SetupTest() - path := NewICAPath(suite.chainA, suite.chainB, icatypes.EncodingProtobuf) - path.SetupConnections() + path := NewICAPath(suite.chainA, suite.chainB, icatypes.EncodingProtobuf, ordering) + path.SetupConnections() - err := SetupICAPath(path, TestOwnerAddress) - suite.Require().NoError(err) + err := SetupICAPath(path, TestOwnerAddress) + suite.Require().NoError(err) - interchainAccAddr, exists := suite.chainB.GetSimApp().ICAHostKeeper.GetInterchainAccountAddress(suite.chainB.GetContext(), path.EndpointB.ConnectionID, path.EndpointA.ChannelConfig.PortID) - suite.Require().True(exists) + interchainAccAddr, exists := suite.chainB.GetSimApp().ICAHostKeeper.GetInterchainAccountAddress(suite.chainB.GetContext(), path.EndpointB.ConnectionID, path.EndpointA.ChannelConfig.PortID) + suite.Require().True(exists) - genesisState := keeper.ExportGenesis(suite.chainB.GetContext(), suite.chainB.GetSimApp().ICAHostKeeper) + genesisState := keeper.ExportGenesis(suite.chainB.GetContext(), suite.chainB.GetSimApp().ICAHostKeeper) - suite.Require().Equal(path.EndpointB.ChannelID, genesisState.ActiveChannels[0].ChannelId) - suite.Require().Equal(path.EndpointA.ChannelConfig.PortID, genesisState.ActiveChannels[0].PortId) + suite.Require().Equal(path.EndpointB.ChannelID, genesisState.ActiveChannels[0].ChannelId) + suite.Require().Equal(path.EndpointA.ChannelConfig.PortID, genesisState.ActiveChannels[0].PortId) - suite.Require().Equal(interchainAccAddr, genesisState.InterchainAccounts[0].AccountAddress) - suite.Require().Equal(path.EndpointA.ChannelConfig.PortID, genesisState.InterchainAccounts[0].PortId) + suite.Require().Equal(interchainAccAddr, genesisState.InterchainAccounts[0].AccountAddress) + suite.Require().Equal(path.EndpointA.ChannelConfig.PortID, genesisState.InterchainAccounts[0].PortId) - suite.Require().Equal(icatypes.HostPortID, genesisState.GetPort()) + suite.Require().Equal(icatypes.HostPortID, genesisState.GetPort()) - expParams := types.DefaultParams() - suite.Require().Equal(expParams, genesisState.GetParams()) + expParams := types.DefaultParams() + suite.Require().Equal(expParams, genesisState.GetParams()) + } } 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 46c653c8dc0..2e37ddb4418 100644 --- a/modules/apps/27-interchain-accounts/host/keeper/handshake_test.go +++ b/modules/apps/27-interchain-accounts/host/keeper/handshake_test.go @@ -43,318 +43,320 @@ func (suite *KeeperTestSuite) openAndCloseChannel(path *ibctesting.Path) { } func (suite *KeeperTestSuite) TestOnChanOpenTry() { - var ( - channel *channeltypes.Channel - path *ibctesting.Path - chanCap *capabilitytypes.Capability - metadata icatypes.Metadata - ) - - testCases := []struct { - name string - malleate func() - expPass bool - }{ - { - "success", - func() {}, - true, - }, - { - "success - reopening closed active channel", - func() { - // create interchain account - // undo setup - path.EndpointB.ChannelID = "" - err := suite.chainB.App.GetScopedIBCKeeper().ReleaseCapability(suite.chainB.GetContext(), chanCap) - suite.Require().NoError(err) - - suite.openAndCloseChannel(path) + for _, ordering := range []channeltypes.Order{channeltypes.UNORDERED, channeltypes.ORDERED} { + var ( + channel *channeltypes.Channel + path *ibctesting.Path + chanCap *capabilitytypes.Capability + metadata icatypes.Metadata + ) + + testCases := []struct { + name string + malleate func() + expPass bool + }{ + { + "success", + func() {}, + true, }, - true, - }, - { - "success - reopening account with new address", - func() { - // create interchain account - // undo setup - path.EndpointB.ChannelID = "" - err := suite.chainB.App.GetScopedIBCKeeper().ReleaseCapability(suite.chainB.GetContext(), chanCap) - suite.Require().NoError(err) - - suite.openAndCloseChannel(path) - - // delete interchain account address - store := suite.chainB.GetContext().KVStore(suite.chainB.GetSimApp().GetKey(hosttypes.SubModuleName)) - store.Delete(icatypes.KeyOwnerAccount(path.EndpointA.ChannelConfig.PortID, path.EndpointB.ConnectionID)) - - // assert interchain account address mapping was deleted - _, found := suite.chainB.GetSimApp().ICAHostKeeper.GetInterchainAccountAddress(suite.chainB.GetContext(), path.EndpointB.ConnectionID, path.EndpointA.ChannelConfig.PortID) - suite.Require().False(found) + { + "success - reopening closed active channel", + func() { + // create interchain account + // undo setup + path.EndpointB.ChannelID = "" + err := suite.chainB.App.GetScopedIBCKeeper().ReleaseCapability(suite.chainB.GetContext(), chanCap) + suite.Require().NoError(err) + + suite.openAndCloseChannel(path) + }, + true, }, - true, - }, - { - "success - empty host connection ID", - func() { - metadata.HostConnectionId = "" - - versionBytes, err := icatypes.ModuleCdc.MarshalJSON(&metadata) - suite.Require().NoError(err) - - path.EndpointA.ChannelConfig.Version = string(versionBytes) + { + "success - reopening account with new address", + func() { + // create interchain account + // undo setup + path.EndpointB.ChannelID = "" + err := suite.chainB.App.GetScopedIBCKeeper().ReleaseCapability(suite.chainB.GetContext(), chanCap) + suite.Require().NoError(err) + + suite.openAndCloseChannel(path) + + // delete interchain account address + store := suite.chainB.GetContext().KVStore(suite.chainB.GetSimApp().GetKey(hosttypes.SubModuleName)) + store.Delete(icatypes.KeyOwnerAccount(path.EndpointA.ChannelConfig.PortID, path.EndpointB.ConnectionID)) + + // assert interchain account address mapping was deleted + _, found := suite.chainB.GetSimApp().ICAHostKeeper.GetInterchainAccountAddress(suite.chainB.GetContext(), path.EndpointB.ConnectionID, path.EndpointA.ChannelConfig.PortID) + suite.Require().False(found) + }, + true, }, - true, - }, - { - "success - previous metadata is different", - func() { - // set the active channelID in state - suite.chainB.GetSimApp().ICAHostKeeper.SetActiveChannelID(suite.chainB.GetContext(), path.EndpointB.ConnectionID, path.EndpointA.ChannelConfig.PortID, path.EndpointB.ChannelID) + { + "success - empty host connection ID", + func() { + metadata.HostConnectionId = "" - // set the previous encoding to be proto3json. - // the new encoding is set to be protobuf in the test below. - metadata.Encoding = icatypes.EncodingProto3JSON - - versionBytes, err := icatypes.ModuleCdc.MarshalJSON(&metadata) - suite.Require().NoError(err) + versionBytes, err := icatypes.ModuleCdc.MarshalJSON(&metadata) + suite.Require().NoError(err) - channel.State = channeltypes.CLOSED - channel.Version = string(versionBytes) - - path.EndpointB.SetChannel(*channel) - }, true, - }, - { - "reopening account fails - no existing account", - func() { - // create interchain account - // undo setup - path.EndpointB.ChannelID = "" - err := suite.chainB.App.GetScopedIBCKeeper().ReleaseCapability(suite.chainB.GetContext(), chanCap) - suite.Require().NoError(err) - - suite.openAndCloseChannel(path) - - // delete existing account - addr, found := suite.chainB.GetSimApp().ICAHostKeeper.GetInterchainAccountAddress(suite.chainB.GetContext(), path.EndpointB.ConnectionID, path.EndpointA.ChannelConfig.PortID) - suite.Require().True(found) - - acc := suite.chainB.GetSimApp().AccountKeeper.GetAccount(suite.chainB.GetContext(), sdk.MustAccAddressFromBech32(addr)) - suite.chainB.GetSimApp().AccountKeeper.RemoveAccount(suite.chainB.GetContext(), acc) + path.EndpointA.ChannelConfig.Version = string(versionBytes) + }, + true, }, - false, - }, - { - "reopening account fails - existing account is not interchain account type", - func() { - // create interchain account - // undo setup - path.EndpointB.ChannelID = "" - err := suite.chainB.App.GetScopedIBCKeeper().ReleaseCapability(suite.chainB.GetContext(), chanCap) - suite.Require().NoError(err) - - suite.openAndCloseChannel(path) + { + "success - previous metadata is different", + func() { + // set the active channelID in state + suite.chainB.GetSimApp().ICAHostKeeper.SetActiveChannelID(suite.chainB.GetContext(), path.EndpointB.ConnectionID, path.EndpointA.ChannelConfig.PortID, path.EndpointB.ChannelID) - addr, found := suite.chainB.GetSimApp().ICAHostKeeper.GetInterchainAccountAddress(suite.chainB.GetContext(), path.EndpointB.ConnectionID, path.EndpointA.ChannelConfig.PortID) - suite.Require().True(found) + // set the previous encoding to be proto3json. + // the new encoding is set to be protobuf in the test below. + metadata.Encoding = icatypes.EncodingProto3JSON - accAddress := sdk.MustAccAddressFromBech32(addr) - acc := suite.chainB.GetSimApp().AccountKeeper.GetAccount(suite.chainB.GetContext(), accAddress) + versionBytes, err := icatypes.ModuleCdc.MarshalJSON(&metadata) + suite.Require().NoError(err) - icaAcc, ok := acc.(*icatypes.InterchainAccount) - suite.Require().True(ok) + channel.State = channeltypes.CLOSED + channel.Version = string(versionBytes) - // overwrite existing account with only base account type, not intercahin account type - suite.chainB.GetSimApp().AccountKeeper.SetAccount(suite.chainB.GetContext(), icaAcc.BaseAccount) + path.EndpointB.SetChannel(*channel) + }, true, }, - false, - }, - { - "account already exists", - func() { - interchainAccAddr := icatypes.GenerateAddress(suite.chainB.GetContext(), path.EndpointB.ConnectionID, path.EndpointA.ChannelConfig.PortID) - err := suite.chainB.GetSimApp().BankKeeper.SendCoins(suite.chainB.GetContext(), suite.chainB.SenderAccount.GetAddress(), interchainAccAddr, sdk.Coins{sdk.NewCoin("stake", sdkmath.NewInt(1))}) - suite.Require().NoError(err) - suite.Require().True(suite.chainB.GetSimApp().AccountKeeper.HasAccount(suite.chainB.GetContext(), interchainAccAddr)) + { + "reopening account fails - no existing account", + func() { + // create interchain account + // undo setup + path.EndpointB.ChannelID = "" + err := suite.chainB.App.GetScopedIBCKeeper().ReleaseCapability(suite.chainB.GetContext(), chanCap) + suite.Require().NoError(err) + + suite.openAndCloseChannel(path) + + // delete existing account + addr, found := suite.chainB.GetSimApp().ICAHostKeeper.GetInterchainAccountAddress(suite.chainB.GetContext(), path.EndpointB.ConnectionID, path.EndpointA.ChannelConfig.PortID) + suite.Require().True(found) + + acc := suite.chainB.GetSimApp().AccountKeeper.GetAccount(suite.chainB.GetContext(), sdk.MustAccAddressFromBech32(addr)) + suite.chainB.GetSimApp().AccountKeeper.RemoveAccount(suite.chainB.GetContext(), acc) + }, + false, }, - false, - }, - { - "invalid port ID", - func() { - path.EndpointB.ChannelConfig.PortID = "invalid-port-id" //nolint:goconst + { + "reopening account fails - existing account is not interchain account type", + func() { + // create interchain account + // undo setup + path.EndpointB.ChannelID = "" + err := suite.chainB.App.GetScopedIBCKeeper().ReleaseCapability(suite.chainB.GetContext(), chanCap) + suite.Require().NoError(err) + + suite.openAndCloseChannel(path) + + addr, found := suite.chainB.GetSimApp().ICAHostKeeper.GetInterchainAccountAddress(suite.chainB.GetContext(), path.EndpointB.ConnectionID, path.EndpointA.ChannelConfig.PortID) + suite.Require().True(found) + + accAddress := sdk.MustAccAddressFromBech32(addr) + acc := suite.chainB.GetSimApp().AccountKeeper.GetAccount(suite.chainB.GetContext(), accAddress) + + icaAcc, ok := acc.(*icatypes.InterchainAccount) + suite.Require().True(ok) + + // overwrite existing account with only base account type, not intercahin account type + suite.chainB.GetSimApp().AccountKeeper.SetAccount(suite.chainB.GetContext(), icaAcc.BaseAccount) + }, + false, }, - false, - }, - { - "connection not found", - func() { - channel.ConnectionHops = []string{"invalid-connnection-id"} - path.EndpointB.SetChannel(*channel) + { + "account already exists", + func() { + interchainAccAddr := icatypes.GenerateAddress(suite.chainB.GetContext(), path.EndpointB.ConnectionID, path.EndpointA.ChannelConfig.PortID) + err := suite.chainB.GetSimApp().BankKeeper.SendCoins(suite.chainB.GetContext(), suite.chainB.SenderAccount.GetAddress(), interchainAccAddr, sdk.Coins{sdk.NewCoin("stake", sdkmath.NewInt(1))}) + suite.Require().NoError(err) + suite.Require().True(suite.chainB.GetSimApp().AccountKeeper.HasAccount(suite.chainB.GetContext(), interchainAccAddr)) + }, + false, }, - false, - }, - { - "invalid metadata bytestring", - func() { - // the try step will propose a new valid version - path.EndpointA.ChannelConfig.Version = "invalid-metadata-bytestring" + { + "invalid port ID", + func() { + path.EndpointB.ChannelConfig.PortID = "invalid-port-id" //nolint:goconst + }, + false, }, - true, - }, - { - "unsupported encoding format", - func() { - metadata.Encoding = "invalid-encoding-format" + { + "connection not found", + func() { + channel.ConnectionHops = []string{"invalid-connnection-id"} + path.EndpointB.SetChannel(*channel) + }, + false, + }, + { + "invalid metadata bytestring", + func() { + // the try step will propose a new valid version + path.EndpointA.ChannelConfig.Version = "invalid-metadata-bytestring" + }, + true, + }, + { + "unsupported encoding format", + func() { + metadata.Encoding = "invalid-encoding-format" - versionBytes, err := icatypes.ModuleCdc.MarshalJSON(&metadata) - suite.Require().NoError(err) + versionBytes, err := icatypes.ModuleCdc.MarshalJSON(&metadata) + suite.Require().NoError(err) - path.EndpointA.ChannelConfig.Version = string(versionBytes) + path.EndpointA.ChannelConfig.Version = string(versionBytes) + }, + false, }, - false, - }, - { - "unsupported transaction type", - func() { - metadata.TxType = "invalid-tx-types" + { + "unsupported transaction type", + func() { + metadata.TxType = "invalid-tx-types" - versionBytes, err := icatypes.ModuleCdc.MarshalJSON(&metadata) - suite.Require().NoError(err) + versionBytes, err := icatypes.ModuleCdc.MarshalJSON(&metadata) + suite.Require().NoError(err) - path.EndpointA.ChannelConfig.Version = string(versionBytes) + path.EndpointA.ChannelConfig.Version = string(versionBytes) + }, + false, }, - false, - }, - { - "invalid controller connection ID", - func() { - metadata.ControllerConnectionId = "invalid-connnection-id" + { + "invalid controller connection ID", + func() { + metadata.ControllerConnectionId = "invalid-connnection-id" - versionBytes, err := icatypes.ModuleCdc.MarshalJSON(&metadata) - suite.Require().NoError(err) + versionBytes, err := icatypes.ModuleCdc.MarshalJSON(&metadata) + suite.Require().NoError(err) - path.EndpointA.ChannelConfig.Version = string(versionBytes) + path.EndpointA.ChannelConfig.Version = string(versionBytes) + }, + false, }, - false, - }, - { - "invalid counterparty version", - func() { - metadata.Version = "invalid-version" + { + "invalid counterparty version", + func() { + metadata.Version = "invalid-version" - versionBytes, err := icatypes.ModuleCdc.MarshalJSON(&metadata) - suite.Require().NoError(err) + versionBytes, err := icatypes.ModuleCdc.MarshalJSON(&metadata) + suite.Require().NoError(err) - path.EndpointA.ChannelConfig.Version = string(versionBytes) + path.EndpointA.ChannelConfig.Version = string(versionBytes) + }, + false, }, - false, - }, - { - "capability already claimed", - func() { - path.EndpointB.SetChannel(*channel) - err := suite.chainB.GetSimApp().ScopedICAHostKeeper.ClaimCapability(suite.chainB.GetContext(), chanCap, host.ChannelCapabilityPath(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID)) - suite.Require().NoError(err) + { + "capability already claimed", + func() { + path.EndpointB.SetChannel(*channel) + err := suite.chainB.GetSimApp().ScopedICAHostKeeper.ClaimCapability(suite.chainB.GetContext(), chanCap, host.ChannelCapabilityPath(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID)) + suite.Require().NoError(err) + }, + false, }, - false, - }, - { - "active channel already set (OPEN state)", - 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.EndpointB.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) + { + "active channel already set (OPEN state)", + func() { + // create a new channel and set it in state + ch := channeltypes.NewChannel(channeltypes.OPEN, ordering, 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.EndpointB.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, }, - false, - }, - { - "channel is already active (FLUSHING state)", - func() { - suite.chainB.GetSimApp().ICAHostKeeper.SetActiveChannelID(suite.chainB.GetContext(), ibctesting.FirstConnectionID, path.EndpointA.ChannelConfig.PortID, path.EndpointB.ChannelID) - - counterparty := channeltypes.NewCounterparty(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) - channel := channeltypes.Channel{ - State: channeltypes.FLUSHING, - Ordering: channeltypes.ORDERED, - Counterparty: counterparty, - ConnectionHops: []string{path.EndpointB.ConnectionID}, - Version: TestVersion, - } - suite.chainB.GetSimApp().IBCKeeper.ChannelKeeper.SetChannel(suite.chainB.GetContext(), path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, channel) + { + "channel is already active (FLUSHING state)", + func() { + suite.chainB.GetSimApp().ICAHostKeeper.SetActiveChannelID(suite.chainB.GetContext(), ibctesting.FirstConnectionID, path.EndpointA.ChannelConfig.PortID, path.EndpointB.ChannelID) + + counterparty := channeltypes.NewCounterparty(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) + channel := channeltypes.Channel{ + State: channeltypes.FLUSHING, + Ordering: ordering, + Counterparty: counterparty, + ConnectionHops: []string{path.EndpointB.ConnectionID}, + Version: TestVersion, + } + suite.chainB.GetSimApp().IBCKeeper.ChannelKeeper.SetChannel(suite.chainB.GetContext(), path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, channel) + }, + false, }, - false, - }, - } + } - for _, tc := range testCases { - tc := tc + for _, tc := range testCases { + tc := tc - suite.Run(tc.name, func() { - suite.SetupTest() // reset + suite.Run(tc.name, func() { + suite.SetupTest() // reset - path = NewICAPath(suite.chainA, suite.chainB, icatypes.EncodingProtobuf) - path.SetupConnections() + path = NewICAPath(suite.chainA, suite.chainB, icatypes.EncodingProtobuf, ordering) + path.SetupConnections() - err := RegisterInterchainAccount(path.EndpointA, TestOwnerAddress) - suite.Require().NoError(err) + err := RegisterInterchainAccount(path.EndpointA, TestOwnerAddress) + suite.Require().NoError(err) - // set the channel id on host - channelSequence := path.EndpointB.Chain.App.GetIBCKeeper().ChannelKeeper.GetNextChannelSequence(path.EndpointB.Chain.GetContext()) - path.EndpointB.ChannelID = channeltypes.FormatChannelIdentifier(channelSequence) + // set the channel id on host + channelSequence := path.EndpointB.Chain.App.GetIBCKeeper().ChannelKeeper.GetNextChannelSequence(path.EndpointB.Chain.GetContext()) + path.EndpointB.ChannelID = channeltypes.FormatChannelIdentifier(channelSequence) - // default values - metadata = icatypes.NewMetadata(icatypes.Version, ibctesting.FirstConnectionID, ibctesting.FirstConnectionID, "", icatypes.EncodingProtobuf, icatypes.TxTypeSDKMultiMsg) - versionBytes, err := icatypes.ModuleCdc.MarshalJSON(&metadata) - suite.Require().NoError(err) + // default values + metadata = icatypes.NewMetadata(icatypes.Version, ibctesting.FirstConnectionID, ibctesting.FirstConnectionID, "", icatypes.EncodingProtobuf, icatypes.TxTypeSDKMultiMsg) + versionBytes, err := icatypes.ModuleCdc.MarshalJSON(&metadata) + suite.Require().NoError(err) - expectedMetadata := metadata + expectedMetadata := metadata - counterparty := channeltypes.NewCounterparty(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) - channel = &channeltypes.Channel{ - State: channeltypes.TRYOPEN, - Ordering: channeltypes.ORDERED, - Counterparty: counterparty, - ConnectionHops: []string{path.EndpointB.ConnectionID}, - Version: string(versionBytes), - } + counterparty := channeltypes.NewCounterparty(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) + channel = &channeltypes.Channel{ + State: channeltypes.TRYOPEN, + Ordering: ordering, + Counterparty: counterparty, + ConnectionHops: []string{path.EndpointB.ConnectionID}, + Version: string(versionBytes), + } - chanCap, err = suite.chainB.App.GetScopedIBCKeeper().NewCapability(suite.chainB.GetContext(), host.ChannelCapabilityPath(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID)) - suite.Require().NoError(err) + chanCap, err = suite.chainB.App.GetScopedIBCKeeper().NewCapability(suite.chainB.GetContext(), host.ChannelCapabilityPath(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID)) + suite.Require().NoError(err) - tc.malleate() // malleate mutates test data + tc.malleate() // malleate mutates test data - version, err := suite.chainB.GetSimApp().ICAHostKeeper.OnChanOpenTry(suite.chainB.GetContext(), channel.Ordering, channel.ConnectionHops, - path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, chanCap, channel.Counterparty, path.EndpointA.ChannelConfig.Version, - ) + version, err := suite.chainB.GetSimApp().ICAHostKeeper.OnChanOpenTry(suite.chainB.GetContext(), channel.Ordering, channel.ConnectionHops, + path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, chanCap, channel.Counterparty, path.EndpointA.ChannelConfig.Version, + ) - if tc.expPass { - suite.Require().NoError(err) + if tc.expPass { + suite.Require().NoError(err) - storedAddr, found := suite.chainB.GetSimApp().ICAHostKeeper.GetInterchainAccountAddress(suite.chainB.GetContext(), path.EndpointB.ConnectionID, path.EndpointA.ChannelConfig.PortID) - suite.Require().True(found) + storedAddr, found := suite.chainB.GetSimApp().ICAHostKeeper.GetInterchainAccountAddress(suite.chainB.GetContext(), path.EndpointB.ConnectionID, path.EndpointA.ChannelConfig.PortID) + suite.Require().True(found) - interchainAccAddr, err := sdk.AccAddressFromBech32(storedAddr) - suite.Require().NoError(err) + interchainAccAddr, err := sdk.AccAddressFromBech32(storedAddr) + suite.Require().NoError(err) - // Check if account is created - interchainAccount := suite.chainB.GetSimApp().AccountKeeper.GetAccount(suite.chainB.GetContext(), interchainAccAddr) - suite.Require().Equal(interchainAccount.GetAddress().String(), storedAddr) + // Check if account is created + interchainAccount := suite.chainB.GetSimApp().AccountKeeper.GetAccount(suite.chainB.GetContext(), interchainAccAddr) + suite.Require().Equal(interchainAccount.GetAddress().String(), storedAddr) - expectedMetadata.Address = storedAddr - expectedVersionBytes, err := icatypes.ModuleCdc.MarshalJSON(&expectedMetadata) - suite.Require().NoError(err) + expectedMetadata.Address = storedAddr + expectedVersionBytes, err := icatypes.ModuleCdc.MarshalJSON(&expectedMetadata) + suite.Require().NoError(err) - suite.Require().Equal(string(expectedVersionBytes), version) - } else { - suite.Require().Error(err) - suite.Require().Equal("", version) - } - }) + suite.Require().Equal(string(expectedVersionBytes), version) + } else { + suite.Require().Error(err) + suite.Require().Equal("", version) + } + }) + } } } @@ -379,35 +381,37 @@ func (suite *KeeperTestSuite) TestOnChanOpenConfirm() { }, } - for _, tc := range testCases { - tc := tc + for _, ordering := range []channeltypes.Order{channeltypes.UNORDERED, channeltypes.ORDERED} { + for _, tc := range testCases { + tc := tc - suite.Run(tc.name, func() { - suite.SetupTest() // reset + suite.Run(tc.name, func() { + suite.SetupTest() // reset - path = NewICAPath(suite.chainA, suite.chainB, icatypes.EncodingProtobuf) - path.SetupConnections() + path = NewICAPath(suite.chainA, suite.chainB, icatypes.EncodingProtobuf, ordering) + path.SetupConnections() - err := RegisterInterchainAccount(path.EndpointA, TestOwnerAddress) - suite.Require().NoError(err) + err := RegisterInterchainAccount(path.EndpointA, TestOwnerAddress) + suite.Require().NoError(err) - err = path.EndpointB.ChanOpenTry() - suite.Require().NoError(err) + err = path.EndpointB.ChanOpenTry() + suite.Require().NoError(err) - err = path.EndpointA.ChanOpenAck() - suite.Require().NoError(err) + err = path.EndpointA.ChanOpenAck() + suite.Require().NoError(err) - tc.malleate() // malleate mutates test data + tc.malleate() // malleate mutates test data - err = suite.chainB.GetSimApp().ICAHostKeeper.OnChanOpenConfirm(suite.chainB.GetContext(), - path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID) + err = suite.chainB.GetSimApp().ICAHostKeeper.OnChanOpenConfirm(suite.chainB.GetContext(), + path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID) - if tc.expPass { - suite.Require().NoError(err) - } else { - suite.Require().Error(err) - } - }) + if tc.expPass { + suite.Require().NoError(err) + } else { + suite.Require().Error(err) + } + }) + } } } @@ -424,27 +428,29 @@ func (suite *KeeperTestSuite) TestOnChanCloseConfirm() { }, } - for _, tc := range testCases { - suite.Run(tc.name, func() { - suite.SetupTest() // reset + for _, ordering := range []channeltypes.Order{channeltypes.UNORDERED, channeltypes.ORDERED} { + for _, tc := range testCases { + suite.Run(tc.name, func() { + suite.SetupTest() // reset - path = NewICAPath(suite.chainA, suite.chainB, icatypes.EncodingProtobuf) - path.SetupConnections() + path = NewICAPath(suite.chainA, suite.chainB, icatypes.EncodingProtobuf, ordering) + path.SetupConnections() - err := SetupICAPath(path, TestOwnerAddress) - suite.Require().NoError(err) + err := SetupICAPath(path, TestOwnerAddress) + suite.Require().NoError(err) - tc.malleate() // malleate mutates test data + tc.malleate() // malleate mutates test data - err = suite.chainB.GetSimApp().ICAHostKeeper.OnChanCloseConfirm(suite.chainB.GetContext(), - path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID) + err = suite.chainB.GetSimApp().ICAHostKeeper.OnChanCloseConfirm(suite.chainB.GetContext(), + path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID) - if tc.expPass { - suite.Require().NoError(err) - } else { - suite.Require().Error(err) - } - }) + if tc.expPass { + suite.Require().NoError(err) + } else { + suite.Require().Error(err) + } + }) + } } } @@ -572,54 +578,56 @@ func (suite *KeeperTestSuite) TestOnChanUpgradeTry() { }, } - for _, tc := range testCases { - tc := tc + for _, ordering := range []channeltypes.Order{channeltypes.UNORDERED, channeltypes.ORDERED} { + for _, tc := range testCases { + tc := tc - suite.Run(tc.name, func() { - suite.SetupTest() // reset + suite.Run(tc.name, func() { + suite.SetupTest() // reset - path = NewICAPath(suite.chainA, suite.chainB, icatypes.EncodingProtobuf) - path.SetupConnections() + path = NewICAPath(suite.chainA, suite.chainB, icatypes.EncodingProtobuf, ordering) + path.SetupConnections() - err := SetupICAPath(path, TestOwnerAddress) - suite.Require().NoError(err) - - currentMetadata, err := suite.chainB.GetSimApp().ICAHostKeeper.GetAppMetadata(suite.chainB.GetContext(), path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID) - suite.Require().NoError(err) - - order = channeltypes.ORDERED - metadata = icatypes.NewDefaultMetadata(path.EndpointA.ConnectionID, path.EndpointB.ConnectionID) - // use the same address as the previous metadata. - metadata.Address = currentMetadata.Address - // this is the actual change to the version. - metadata.Encoding = icatypes.EncodingProto3JSON - - path.EndpointA.ChannelConfig.ProposedUpgrade.Fields.Version = string(icatypes.ModuleCdc.MustMarshalJSON(&metadata)) - path.EndpointB.ChannelConfig.ProposedUpgrade.Fields.Version = string(icatypes.ModuleCdc.MustMarshalJSON(&metadata)) - - err = path.EndpointA.ChanUpgradeInit() - suite.Require().NoError(err) + err := SetupICAPath(path, TestOwnerAddress) + suite.Require().NoError(err) - counterpartyVersion = path.EndpointA.GetChannel().Version + currentMetadata, err := suite.chainB.GetSimApp().ICAHostKeeper.GetAppMetadata(suite.chainB.GetContext(), path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID) + suite.Require().NoError(err) - tc.malleate() // malleate mutates test data + order = channeltypes.ORDERED + metadata = icatypes.NewDefaultMetadata(path.EndpointA.ConnectionID, path.EndpointB.ConnectionID) + // use the same address as the previous metadata. + metadata.Address = currentMetadata.Address + // this is the actual change to the version. + metadata.Encoding = icatypes.EncodingProto3JSON - version, err := suite.chainB.GetSimApp().ICAHostKeeper.OnChanUpgradeTry( - suite.chainB.GetContext(), - path.EndpointB.ChannelConfig.PortID, - path.EndpointB.ChannelID, - order, - []string{path.EndpointB.ConnectionID}, - counterpartyVersion, - ) + path.EndpointA.ChannelConfig.ProposedUpgrade.Fields.Version = string(icatypes.ModuleCdc.MustMarshalJSON(&metadata)) + path.EndpointB.ChannelConfig.ProposedUpgrade.Fields.Version = string(icatypes.ModuleCdc.MustMarshalJSON(&metadata)) - expPass := tc.expError == nil - if expPass { + err = path.EndpointA.ChanUpgradeInit() suite.Require().NoError(err) - suite.Require().Equal(path.EndpointB.GetChannel().Version, version) - } else { - suite.Require().ErrorIs(err, tc.expError) - } - }) + + counterpartyVersion = path.EndpointA.GetChannel().Version + + tc.malleate() // malleate mutates test data + + version, err := suite.chainB.GetSimApp().ICAHostKeeper.OnChanUpgradeTry( + suite.chainB.GetContext(), + path.EndpointB.ChannelConfig.PortID, + path.EndpointB.ChannelID, + order, + []string{path.EndpointB.ConnectionID}, + counterpartyVersion, + ) + + expPass := tc.expError == nil + if expPass { + suite.Require().NoError(err) + suite.Require().Equal(path.EndpointB.GetChannel().Version, version) + } else { + suite.Require().ErrorIs(err, tc.expError) + } + }) + } } } 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 acbc274ef2f..9d947129dc8 100644 --- a/modules/apps/27-interchain-accounts/host/keeper/keeper_test.go +++ b/modules/apps/27-interchain-accounts/host/keeper/keeper_test.go @@ -63,7 +63,7 @@ func (suite *KeeperTestSuite) SetupTest() { suite.chainC = suite.coordinator.GetChain(ibctesting.GetChainID(3)) } -func NewICAPath(chainA, chainB *ibctesting.TestChain, encoding string) *ibctesting.Path { +func NewICAPath(chainA, chainB *ibctesting.TestChain, encoding string, ordering channeltypes.Order) *ibctesting.Path { path := ibctesting.NewPath(chainA, chainB) var version string @@ -78,8 +78,8 @@ func NewICAPath(chainA, chainB *ibctesting.TestChain, encoding string) *ibctesti path.EndpointA.ChannelConfig.PortID = icatypes.HostPortID path.EndpointB.ChannelConfig.PortID = icatypes.HostPortID - path.EndpointA.ChannelConfig.Order = channeltypes.ORDERED - path.EndpointB.ChannelConfig.Order = channeltypes.ORDERED + path.EndpointA.ChannelConfig.Order = ordering + path.EndpointB.ChannelConfig.Order = ordering path.EndpointA.ChannelConfig.Version = version path.EndpointB.ChannelConfig.Version = version @@ -112,7 +112,7 @@ func RegisterInterchainAccount(endpoint *ibctesting.Endpoint, owner string) erro channelSequence := endpoint.Chain.App.GetIBCKeeper().ChannelKeeper.GetNextChannelSequence(endpoint.Chain.GetContext()) - if err := endpoint.Chain.GetSimApp().ICAControllerKeeper.RegisterInterchainAccount(endpoint.Chain.GetContext(), endpoint.ConnectionID, owner, endpoint.ChannelConfig.Version); err != nil { + if err := endpoint.Chain.GetSimApp().ICAControllerKeeper.RegisterInterchainAccount(endpoint.Chain.GetContext(), endpoint.ConnectionID, owner, endpoint.ChannelConfig.Version, endpoint.ChannelConfig.Order); err != nil { return err } @@ -227,107 +227,115 @@ func (suite *KeeperTestSuite) TestNewModuleQuerySafeAllowList() { } func (suite *KeeperTestSuite) TestGetInterchainAccountAddress() { - suite.SetupTest() + for _, ordering := range []channeltypes.Order{channeltypes.UNORDERED, channeltypes.ORDERED} { + suite.SetupTest() - path := NewICAPath(suite.chainA, suite.chainB, icatypes.EncodingProtobuf) - path.SetupConnections() + path := NewICAPath(suite.chainA, suite.chainB, icatypes.EncodingProtobuf, ordering) + path.SetupConnections() - err := SetupICAPath(path, TestOwnerAddress) - suite.Require().NoError(err) + err := SetupICAPath(path, TestOwnerAddress) + suite.Require().NoError(err) - counterpartyPortID := path.EndpointA.ChannelConfig.PortID + counterpartyPortID := path.EndpointA.ChannelConfig.PortID - retrievedAddr, found := suite.chainB.GetSimApp().ICAHostKeeper.GetInterchainAccountAddress(suite.chainB.GetContext(), ibctesting.FirstConnectionID, counterpartyPortID) - suite.Require().True(found) - suite.Require().NotEmpty(retrievedAddr) + retrievedAddr, found := suite.chainB.GetSimApp().ICAHostKeeper.GetInterchainAccountAddress(suite.chainB.GetContext(), ibctesting.FirstConnectionID, counterpartyPortID) + suite.Require().True(found) + suite.Require().NotEmpty(retrievedAddr) - retrievedAddr, found = suite.chainB.GetSimApp().ICAHostKeeper.GetInterchainAccountAddress(suite.chainB.GetContext(), ibctesting.FirstConnectionID, "invalid port") - suite.Require().False(found) - suite.Require().Empty(retrievedAddr) + retrievedAddr, found = suite.chainB.GetSimApp().ICAHostKeeper.GetInterchainAccountAddress(suite.chainB.GetContext(), ibctesting.FirstConnectionID, "invalid port") + suite.Require().False(found) + suite.Require().Empty(retrievedAddr) + } } func (suite *KeeperTestSuite) TestGetAllActiveChannels() { - var ( - expectedChannelID = "test-channel" - expectedPortID = "test-port" - ) + for _, ordering := range []channeltypes.Order{channeltypes.UNORDERED, channeltypes.ORDERED} { + var ( + expectedChannelID = "test-channel" + expectedPortID = "test-port" + ) - suite.SetupTest() + suite.SetupTest() - path := NewICAPath(suite.chainA, suite.chainB, icatypes.EncodingProtobuf) - path.SetupConnections() - - err := SetupICAPath(path, TestOwnerAddress) - suite.Require().NoError(err) - - suite.chainB.GetSimApp().ICAHostKeeper.SetActiveChannelID(suite.chainB.GetContext(), ibctesting.FirstConnectionID, expectedPortID, expectedChannelID) - - expectedChannels := []genesistypes.ActiveChannel{ - { - ConnectionId: ibctesting.FirstConnectionID, - PortId: path.EndpointA.ChannelConfig.PortID, - ChannelId: path.EndpointB.ChannelID, - }, - { - ConnectionId: ibctesting.FirstConnectionID, - PortId: expectedPortID, - ChannelId: expectedChannelID, - }, + path := NewICAPath(suite.chainA, suite.chainB, icatypes.EncodingProtobuf, ordering) + path.SetupConnections() + + err := SetupICAPath(path, TestOwnerAddress) + suite.Require().NoError(err) + + suite.chainB.GetSimApp().ICAHostKeeper.SetActiveChannelID(suite.chainB.GetContext(), ibctesting.FirstConnectionID, expectedPortID, expectedChannelID) + + expectedChannels := []genesistypes.ActiveChannel{ + { + ConnectionId: ibctesting.FirstConnectionID, + PortId: path.EndpointA.ChannelConfig.PortID, + ChannelId: path.EndpointB.ChannelID, + }, + { + ConnectionId: ibctesting.FirstConnectionID, + PortId: expectedPortID, + ChannelId: expectedChannelID, + }, + } + + activeChannels := suite.chainB.GetSimApp().ICAHostKeeper.GetAllActiveChannels(suite.chainB.GetContext()) + suite.Require().Len(activeChannels, len(expectedChannels)) + suite.Require().Equal(expectedChannels, activeChannels) } - - activeChannels := suite.chainB.GetSimApp().ICAHostKeeper.GetAllActiveChannels(suite.chainB.GetContext()) - suite.Require().Len(activeChannels, len(expectedChannels)) - suite.Require().Equal(expectedChannels, activeChannels) } func (suite *KeeperTestSuite) TestGetAllInterchainAccounts() { - var ( - expectedAccAddr = "test-acc-addr" - expectedPortID = "test-port" - ) - - suite.SetupTest() - - path := NewICAPath(suite.chainA, suite.chainB, icatypes.EncodingProtobuf) - path.SetupConnections() - - err := SetupICAPath(path, TestOwnerAddress) - suite.Require().NoError(err) - - interchainAccAddr, exists := suite.chainB.GetSimApp().ICAHostKeeper.GetInterchainAccountAddress(suite.chainB.GetContext(), path.EndpointB.ConnectionID, path.EndpointA.ChannelConfig.PortID) - suite.Require().True(exists) + for _, ordering := range []channeltypes.Order{channeltypes.UNORDERED, channeltypes.ORDERED} { + var ( + expectedAccAddr = "test-acc-addr" + expectedPortID = "test-port" + ) - suite.chainB.GetSimApp().ICAHostKeeper.SetInterchainAccountAddress(suite.chainB.GetContext(), ibctesting.FirstConnectionID, expectedPortID, expectedAccAddr) + suite.SetupTest() - expectedAccounts := []genesistypes.RegisteredInterchainAccount{ - { - ConnectionId: ibctesting.FirstConnectionID, - PortId: TestPortID, - AccountAddress: interchainAccAddr, - }, - { - ConnectionId: ibctesting.FirstConnectionID, - PortId: expectedPortID, - AccountAddress: expectedAccAddr, - }, + path := NewICAPath(suite.chainA, suite.chainB, icatypes.EncodingProtobuf, ordering) + path.SetupConnections() + + err := SetupICAPath(path, TestOwnerAddress) + suite.Require().NoError(err) + + interchainAccAddr, exists := suite.chainB.GetSimApp().ICAHostKeeper.GetInterchainAccountAddress(suite.chainB.GetContext(), path.EndpointB.ConnectionID, path.EndpointA.ChannelConfig.PortID) + suite.Require().True(exists) + + suite.chainB.GetSimApp().ICAHostKeeper.SetInterchainAccountAddress(suite.chainB.GetContext(), ibctesting.FirstConnectionID, expectedPortID, expectedAccAddr) + + expectedAccounts := []genesistypes.RegisteredInterchainAccount{ + { + ConnectionId: ibctesting.FirstConnectionID, + PortId: TestPortID, + AccountAddress: interchainAccAddr, + }, + { + ConnectionId: ibctesting.FirstConnectionID, + PortId: expectedPortID, + AccountAddress: expectedAccAddr, + }, + } + + interchainAccounts := suite.chainB.GetSimApp().ICAHostKeeper.GetAllInterchainAccounts(suite.chainB.GetContext()) + suite.Require().Len(interchainAccounts, len(expectedAccounts)) + suite.Require().Equal(expectedAccounts, interchainAccounts) } - - interchainAccounts := suite.chainB.GetSimApp().ICAHostKeeper.GetAllInterchainAccounts(suite.chainB.GetContext()) - suite.Require().Len(interchainAccounts, len(expectedAccounts)) - suite.Require().Equal(expectedAccounts, interchainAccounts) } func (suite *KeeperTestSuite) TestIsActiveChannel() { - suite.SetupTest() + for _, ordering := range []channeltypes.Order{channeltypes.UNORDERED, channeltypes.ORDERED} { + suite.SetupTest() - path := NewICAPath(suite.chainA, suite.chainB, icatypes.EncodingProtobuf) - path.SetupConnections() + path := NewICAPath(suite.chainA, suite.chainB, icatypes.EncodingProtobuf, ordering) + path.SetupConnections() - err := SetupICAPath(path, TestOwnerAddress) - suite.Require().NoError(err) + err := SetupICAPath(path, TestOwnerAddress) + suite.Require().NoError(err) - isActive := suite.chainB.GetSimApp().ICAHostKeeper.IsActiveChannel(suite.chainB.GetContext(), ibctesting.FirstConnectionID, path.EndpointA.ChannelConfig.PortID) - suite.Require().True(isActive) + isActive := suite.chainB.GetSimApp().ICAHostKeeper.IsActiveChannel(suite.chainB.GetContext(), ibctesting.FirstConnectionID, path.EndpointA.ChannelConfig.PortID) + suite.Require().True(isActive) + } } func (suite *KeeperTestSuite) TestSetInterchainAccountAddress() { 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 f49e623e939..28c71b36d73 100644 --- a/modules/apps/27-interchain-accounts/host/keeper/relay_test.go +++ b/modules/apps/27-interchain-accounts/host/keeper/relay_test.go @@ -25,7 +25,9 @@ import ( ) func (suite *KeeperTestSuite) TestOnRecvPacket() { + testedOrderings := []channeltypes.Order{channeltypes.UNORDERED, channeltypes.ORDERED} testedEncodings := []string{icatypes.EncodingProtobuf, icatypes.EncodingProto3JSON} + var ( path *ibctesting.Path packetData []byte @@ -523,59 +525,61 @@ func (suite *KeeperTestSuite) TestOnRecvPacket() { }, } - for _, encoding := range testedEncodings { - for _, tc := range testCases { - tc := tc - - suite.Run(tc.msg, func() { - suite.SetupTest() // reset - - path = NewICAPath(suite.chainA, suite.chainB, encoding) - path.SetupConnections() - - err := SetupICAPath(path, TestOwnerAddress) - suite.Require().NoError(err) - - portID, err := icatypes.NewControllerPortID(TestOwnerAddress) - 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(), ibctesting.FirstConnectionID, portID) - suite.Require().True(found) + for _, ordering := range testedOrderings { + for _, encoding := range testedEncodings { + for _, tc := range testCases { + tc := tc - icaAddr, err := sdk.AccAddressFromBech32(storedAddr) - suite.Require().NoError(err) + suite.Run(tc.msg, func() { + suite.SetupTest() // reset - // Check if account is created - interchainAccount := suite.chainB.GetSimApp().AccountKeeper.GetAccount(suite.chainB.GetContext(), icaAddr) - suite.Require().Equal(interchainAccount.GetAddress().String(), storedAddr) + path = NewICAPath(suite.chainA, suite.chainB, encoding, ordering) + path.SetupConnections() - suite.fundICAWallet(suite.chainB.GetContext(), path.EndpointA.ChannelConfig.PortID, sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.NewInt(1000000)))) - - tc.malleate(encoding) // malleate mutates test data + err := SetupICAPath(path, TestOwnerAddress) + suite.Require().NoError(err) - packet := channeltypes.NewPacket( - packetData, - suite.chainA.SenderAccount.GetSequence(), - path.EndpointA.ChannelConfig.PortID, - path.EndpointA.ChannelID, - path.EndpointB.ChannelConfig.PortID, - path.EndpointB.ChannelID, - suite.chainB.GetTimeoutHeight(), - 0, - ) + portID, err := icatypes.NewControllerPortID(TestOwnerAddress) + suite.Require().NoError(err) - txResponse, err := suite.chainB.GetSimApp().ICAHostKeeper.OnRecvPacket(suite.chainB.GetContext(), packet) + // Get the address of the interchain account stored in state during handshake step + storedAddr, found := suite.chainB.GetSimApp().ICAHostKeeper.GetInterchainAccountAddress(suite.chainB.GetContext(), ibctesting.FirstConnectionID, portID) + suite.Require().True(found) - expPass := tc.expErr == nil - if expPass { + icaAddr, err := sdk.AccAddressFromBech32(storedAddr) suite.Require().NoError(err) - suite.Require().NotNil(txResponse) - } else { - suite.Require().ErrorIs(err, tc.expErr) - suite.Require().Nil(txResponse) - } - }) + + // Check if account is created + interchainAccount := suite.chainB.GetSimApp().AccountKeeper.GetAccount(suite.chainB.GetContext(), icaAddr) + suite.Require().Equal(interchainAccount.GetAddress().String(), storedAddr) + + suite.fundICAWallet(suite.chainB.GetContext(), path.EndpointA.ChannelConfig.PortID, sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.NewInt(1000000)))) + + tc.malleate(encoding) // malleate mutates test data + + packet := channeltypes.NewPacket( + packetData, + suite.chainA.SenderAccount.GetSequence(), + path.EndpointA.ChannelConfig.PortID, + path.EndpointA.ChannelID, + path.EndpointB.ChannelConfig.PortID, + path.EndpointB.ChannelID, + suite.chainB.GetTimeoutHeight(), + 0, + ) + + txResponse, err := suite.chainB.GetSimApp().ICAHostKeeper.OnRecvPacket(suite.chainB.GetContext(), packet) + + expPass := tc.expErr == nil + if expPass { + suite.Require().NoError(err) + suite.Require().NotNil(txResponse) + } else { + suite.Require().ErrorIs(err, tc.expErr) + suite.Require().Nil(txResponse) + } + }) + } } } } @@ -874,51 +878,53 @@ func (suite *KeeperTestSuite) TestJSONOnRecvPacket() { }, } - for _, tc := range testCases { - tc := tc + for _, ordering := range []channeltypes.Order{channeltypes.UNORDERED, channeltypes.ORDERED} { + for _, tc := range testCases { + tc := tc - suite.Run(tc.msg, func() { - suite.SetupTest() // reset + suite.Run(tc.msg, func() { + suite.SetupTest() // reset - path = NewICAPath(suite.chainA, suite.chainB, icatypes.EncodingProto3JSON) - path.SetupConnections() + path = NewICAPath(suite.chainA, suite.chainB, icatypes.EncodingProto3JSON, ordering) + path.SetupConnections() - err := SetupICAPath(path, TestOwnerAddress) - suite.Require().NoError(err) + err := SetupICAPath(path, TestOwnerAddress) + suite.Require().NoError(err) - portID, err := icatypes.NewControllerPortID(TestOwnerAddress) - suite.Require().NoError(err) + portID, err := icatypes.NewControllerPortID(TestOwnerAddress) + suite.Require().NoError(err) - // Get the address of the interchain account stored in state during handshake step - icaAddress, found := suite.chainB.GetSimApp().ICAHostKeeper.GetInterchainAccountAddress(suite.chainB.GetContext(), ibctesting.FirstConnectionID, portID) - suite.Require().True(found) + // Get the address of the interchain account stored in state during handshake step + icaAddress, found := suite.chainB.GetSimApp().ICAHostKeeper.GetInterchainAccountAddress(suite.chainB.GetContext(), ibctesting.FirstConnectionID, portID) + suite.Require().True(found) - suite.fundICAWallet(suite.chainB.GetContext(), path.EndpointA.ChannelConfig.PortID, sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.NewInt(100000000)))) + suite.fundICAWallet(suite.chainB.GetContext(), path.EndpointA.ChannelConfig.PortID, sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.NewInt(100000000)))) - tc.malleate(icaAddress) // malleate mutates test data + tc.malleate(icaAddress) // malleate mutates test data - packet := channeltypes.NewPacket( - packetData, - suite.chainA.SenderAccount.GetSequence(), - path.EndpointA.ChannelConfig.PortID, - path.EndpointA.ChannelID, - path.EndpointB.ChannelConfig.PortID, - path.EndpointB.ChannelID, - suite.chainB.GetTimeoutHeight(), - 0, - ) + packet := channeltypes.NewPacket( + packetData, + suite.chainA.SenderAccount.GetSequence(), + path.EndpointA.ChannelConfig.PortID, + path.EndpointA.ChannelID, + path.EndpointB.ChannelConfig.PortID, + path.EndpointB.ChannelID, + suite.chainB.GetTimeoutHeight(), + 0, + ) - txResponse, err := suite.chainB.GetSimApp().ICAHostKeeper.OnRecvPacket(suite.chainB.GetContext(), packet) + txResponse, err := suite.chainB.GetSimApp().ICAHostKeeper.OnRecvPacket(suite.chainB.GetContext(), packet) - expPass := tc.expErr == nil - if expPass { - suite.Require().NoError(err) - suite.Require().NotNil(txResponse) - } else { - suite.Require().ErrorIs(err, tc.expErr) - suite.Require().Nil(txResponse) - } - }) + expPass := tc.expErr == nil + if expPass { + suite.Require().NoError(err) + suite.Require().NotNil(txResponse) + } else { + suite.Require().ErrorIs(err, tc.expErr) + suite.Require().Nil(txResponse) + } + }) + } } } diff --git a/modules/apps/29-fee/ibc_middleware_test.go b/modules/apps/29-fee/ibc_middleware_test.go index dc59f277d3f..b0a4a7301a9 100644 --- a/modules/apps/29-fee/ibc_middleware_test.go +++ b/modules/apps/29-fee/ibc_middleware_test.go @@ -73,70 +73,72 @@ func (suite *FeeTestSuite) TestOnChanOpenInit() { }, } - for _, tc := range testCases { - tc := tc + for _, ordering := range []channeltypes.Order{channeltypes.UNORDERED, channeltypes.ORDERED} { + for _, tc := range testCases { + tc := tc - suite.Run(tc.name, func() { - // reset suite - suite.SetupTest() - suite.path.SetupConnections() + suite.Run(tc.name, func() { + // reset suite + suite.SetupTest() + suite.path.SetupConnections() - // setup mock callback - suite.chainA.GetSimApp().FeeMockModule.IBCApp.OnChanOpenInit = func(ctx sdk.Context, order channeltypes.Order, connectionHops []string, - portID, channelID string, chanCap *capabilitytypes.Capability, - counterparty channeltypes.Counterparty, version string, - ) (string, error) { - if version != ibcmock.Version { - return "", fmt.Errorf("incorrect mock version") + // setup mock callback + suite.chainA.GetSimApp().FeeMockModule.IBCApp.OnChanOpenInit = func(ctx sdk.Context, order channeltypes.Order, connectionHops []string, + portID, channelID string, chanCap *capabilitytypes.Capability, + counterparty channeltypes.Counterparty, version string, + ) (string, error) { + if version != ibcmock.Version { + return "", fmt.Errorf("incorrect mock version") + } + return ibcmock.Version, nil } - return ibcmock.Version, nil - } - suite.path.EndpointA.ChannelID = ibctesting.FirstChannelID + suite.path.EndpointA.ChannelID = ibctesting.FirstChannelID - counterparty := channeltypes.NewCounterparty(suite.path.EndpointB.ChannelConfig.PortID, suite.path.EndpointB.ChannelID) - channel := &channeltypes.Channel{ - State: channeltypes.INIT, - Ordering: channeltypes.UNORDERED, - Counterparty: counterparty, - ConnectionHops: []string{suite.path.EndpointA.ConnectionID}, - Version: tc.version, - } + counterparty := channeltypes.NewCounterparty(suite.path.EndpointB.ChannelConfig.PortID, suite.path.EndpointB.ChannelID) + channel := &channeltypes.Channel{ + State: channeltypes.INIT, + Ordering: ordering, + Counterparty: counterparty, + ConnectionHops: []string{suite.path.EndpointA.ConnectionID}, + Version: tc.version, + } - module, _, err := suite.chainA.App.GetIBCKeeper().PortKeeper.LookupModuleByPort(suite.chainA.GetContext(), ibctesting.MockFeePort) - suite.Require().NoError(err) + module, _, err := suite.chainA.App.GetIBCKeeper().PortKeeper.LookupModuleByPort(suite.chainA.GetContext(), ibctesting.MockFeePort) + suite.Require().NoError(err) - chanCap, err := suite.chainA.App.GetScopedIBCKeeper().NewCapability(suite.chainA.GetContext(), host.ChannelCapabilityPath(suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID)) - suite.Require().NoError(err) + chanCap, err := suite.chainA.App.GetScopedIBCKeeper().NewCapability(suite.chainA.GetContext(), host.ChannelCapabilityPath(suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID)) + suite.Require().NoError(err) - cbs, ok := suite.chainA.App.GetIBCKeeper().PortKeeper.Route(module) - suite.Require().True(ok) + cbs, ok := suite.chainA.App.GetIBCKeeper().PortKeeper.Route(module) + suite.Require().True(ok) - version, err := cbs.OnChanOpenInit(suite.chainA.GetContext(), channel.Ordering, channel.ConnectionHops, - suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID, chanCap, counterparty, channel.Version) + version, err := cbs.OnChanOpenInit(suite.chainA.GetContext(), channel.Ordering, channel.ConnectionHops, + suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID, chanCap, counterparty, channel.Version) - if tc.expPass { - // check if the channel is fee enabled. If so version string should include metaData - if tc.isFeeEnabled { - versionMetadata := types.Metadata{ - FeeVersion: types.Version, - AppVersion: ibcmock.Version, - } + if tc.expPass { + // check if the channel is fee enabled. If so version string should include metaData + if tc.isFeeEnabled { + versionMetadata := types.Metadata{ + FeeVersion: types.Version, + AppVersion: ibcmock.Version, + } - versionBytes, err := types.ModuleCdc.MarshalJSON(&versionMetadata) - suite.Require().NoError(err) + versionBytes, err := types.ModuleCdc.MarshalJSON(&versionMetadata) + suite.Require().NoError(err) + + suite.Require().Equal(version, string(versionBytes)) + } else { + suite.Require().Equal(ibcmock.Version, version) + } - suite.Require().Equal(version, string(versionBytes)) + suite.Require().NoError(err, "unexpected error from version: %s", tc.version) } else { - suite.Require().Equal(ibcmock.Version, version) + suite.Require().Error(err, "error not returned for version: %s", tc.version) + suite.Require().Equal("", version) } - - suite.Require().NoError(err, "unexpected error from version: %s", tc.version) - } else { - suite.Require().Error(err, "error not returned for version: %s", tc.version) - suite.Require().Equal("", version) - } - }) + }) + } } } @@ -169,61 +171,63 @@ func (suite *FeeTestSuite) TestOnChanOpenTry() { }, } - for _, tc := range testCases { - tc := tc + for _, ordering := range []channeltypes.Order{channeltypes.UNORDERED, channeltypes.ORDERED} { + for _, tc := range testCases { + tc := tc - suite.Run(tc.name, func() { - // reset suite - suite.SetupTest() - suite.path.SetupConnections() - err := suite.path.EndpointB.ChanOpenInit() - suite.Require().NoError(err) + suite.Run(tc.name, func() { + // reset suite + suite.SetupTest() + suite.path.SetupConnections() + err := suite.path.EndpointB.ChanOpenInit() + suite.Require().NoError(err) - // setup mock callback - suite.chainA.GetSimApp().FeeMockModule.IBCApp.OnChanOpenTry = func(ctx sdk.Context, order channeltypes.Order, connectionHops []string, - portID, channelID string, chanCap *capabilitytypes.Capability, - counterparty channeltypes.Counterparty, counterpartyVersion string, - ) (string, error) { - if counterpartyVersion != ibcmock.Version { - return "", fmt.Errorf("incorrect mock version") + // setup mock callback + suite.chainA.GetSimApp().FeeMockModule.IBCApp.OnChanOpenTry = func(ctx sdk.Context, order channeltypes.Order, connectionHops []string, + portID, channelID string, chanCap *capabilitytypes.Capability, + counterparty channeltypes.Counterparty, counterpartyVersion string, + ) (string, error) { + if counterpartyVersion != ibcmock.Version { + return "", fmt.Errorf("incorrect mock version") + } + return ibcmock.Version, nil } - return ibcmock.Version, nil - } - var ( - chanCap *capabilitytypes.Capability - ok bool - ) + var ( + chanCap *capabilitytypes.Capability + ok bool + ) - chanCap, err = suite.chainA.App.GetScopedIBCKeeper().NewCapability(suite.chainA.GetContext(), host.ChannelCapabilityPath(suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID)) - suite.Require().NoError(err) + chanCap, err = suite.chainA.App.GetScopedIBCKeeper().NewCapability(suite.chainA.GetContext(), host.ChannelCapabilityPath(suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID)) + suite.Require().NoError(err) - suite.path.EndpointA.ChannelID = ibctesting.FirstChannelID + suite.path.EndpointA.ChannelID = ibctesting.FirstChannelID - counterparty := channeltypes.NewCounterparty(suite.path.EndpointB.ChannelConfig.PortID, suite.path.EndpointB.ChannelID) - channel := &channeltypes.Channel{ - State: channeltypes.INIT, - Ordering: channeltypes.UNORDERED, - Counterparty: counterparty, - ConnectionHops: []string{suite.path.EndpointA.ConnectionID}, - Version: tc.cpVersion, - } + counterparty := channeltypes.NewCounterparty(suite.path.EndpointB.ChannelConfig.PortID, suite.path.EndpointB.ChannelID) + channel := &channeltypes.Channel{ + State: channeltypes.INIT, + Ordering: ordering, + Counterparty: counterparty, + ConnectionHops: []string{suite.path.EndpointA.ConnectionID}, + Version: tc.cpVersion, + } - module, _, err := suite.chainA.App.GetIBCKeeper().PortKeeper.LookupModuleByPort(suite.chainA.GetContext(), ibctesting.MockFeePort) - suite.Require().NoError(err) + module, _, err := suite.chainA.App.GetIBCKeeper().PortKeeper.LookupModuleByPort(suite.chainA.GetContext(), ibctesting.MockFeePort) + suite.Require().NoError(err) - cbs, ok := suite.chainA.App.GetIBCKeeper().PortKeeper.Route(module) - suite.Require().True(ok) + cbs, ok := suite.chainA.App.GetIBCKeeper().PortKeeper.Route(module) + suite.Require().True(ok) - _, err = cbs.OnChanOpenTry(suite.chainA.GetContext(), channel.Ordering, channel.ConnectionHops, - suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID, chanCap, counterparty, tc.cpVersion) + _, err = cbs.OnChanOpenTry(suite.chainA.GetContext(), channel.Ordering, channel.ConnectionHops, + suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID, chanCap, counterparty, tc.cpVersion) - if tc.expPass { - suite.Require().NoError(err) - } else { - suite.Require().Error(err) - } - }) + if tc.expPass { + suite.Require().NoError(err) + } else { + suite.Require().Error(err) + } + }) + } } } diff --git a/modules/apps/29-fee/ica_test.go b/modules/apps/29-fee/ica_test.go index ed121ae6e44..9cf67aa759a 100644 --- a/modules/apps/29-fee/ica_test.go +++ b/modules/apps/29-fee/ica_test.go @@ -29,7 +29,7 @@ var ( ) // NewIncentivizedICAPath creates and returns a new ibctesting path configured for a fee enabled interchain accounts channel -func NewIncentivizedICAPath(chainA, chainB *ibctesting.TestChain) *ibctesting.Path { +func NewIncentivizedICAPath(chainA, chainB *ibctesting.TestChain, ordering channeltypes.Order) *ibctesting.Path { path := ibctesting.NewPath(chainA, chainB) feeMetadata := types.Metadata{ @@ -39,11 +39,12 @@ func NewIncentivizedICAPath(chainA, chainB *ibctesting.TestChain) *ibctesting.Pa feeICAVersion := string(types.ModuleCdc.MustMarshalJSON(&feeMetadata)) - path.SetChannelOrdered() path.EndpointA.ChannelConfig.Version = feeICAVersion path.EndpointB.ChannelConfig.Version = feeICAVersion path.EndpointA.ChannelConfig.PortID = defaultPortID path.EndpointB.ChannelConfig.PortID = icatypes.HostPortID + path.EndpointA.ChannelConfig.Order = ordering + path.EndpointB.ChannelConfig.Order = ordering return path } @@ -75,7 +76,7 @@ func RegisterInterchainAccount(endpoint *ibctesting.Endpoint, owner string) erro channelSequence := endpoint.Chain.App.GetIBCKeeper().ChannelKeeper.GetNextChannelSequence(endpoint.Chain.GetContext()) - if err := endpoint.Chain.GetSimApp().ICAControllerKeeper.RegisterInterchainAccount(endpoint.Chain.GetContext(), endpoint.ConnectionID, owner, endpoint.ChannelConfig.Version); err != nil { + if err := endpoint.Chain.GetSimApp().ICAControllerKeeper.RegisterInterchainAccount(endpoint.Chain.GetContext(), endpoint.ConnectionID, owner, endpoint.ChannelConfig.Version, endpoint.ChannelConfig.Order); err != nil { return err } @@ -91,119 +92,127 @@ func RegisterInterchainAccount(endpoint *ibctesting.Endpoint, owner string) erro // TestFeeInterchainAccounts Integration test to ensure ics29 works with ics27 func (suite *FeeTestSuite) TestFeeInterchainAccounts() { - path := NewIncentivizedICAPath(suite.chainA, suite.chainB) - path.SetupConnections() - - err := SetupPath(path, defaultOwnerAddress) - suite.Require().NoError(err) - - // assert the newly established channel is fee enabled on both ends - suite.Require().True(suite.chainA.GetSimApp().IBCFeeKeeper.IsFeeEnabled(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID)) - suite.Require().True(suite.chainB.GetSimApp().IBCFeeKeeper.IsFeeEnabled(suite.chainB.GetContext(), path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID)) - - // register counterparty address on destination chainB as chainA.SenderAccounts[1] for recv fee distribution - suite.chainB.GetSimApp().IBCFeeKeeper.SetCounterpartyPayeeAddress(suite.chainB.GetContext(), suite.chainB.SenderAccount.GetAddress().String(), suite.chainA.SenderAccounts[1].SenderAccount.GetAddress().String(), path.EndpointB.ChannelID) - - // escrow a packet fee for the next send sequence - expectedFee := types.NewFee(defaultRecvFee, defaultAckFee, defaultTimeoutFee) - msgPayPacketFee := types.NewMsgPayPacketFee(expectedFee, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, suite.chainA.SenderAccount.GetAddress().String(), nil) - - // fetch the account balance before fees are escrowed and assert the difference below - preEscrowBalance := suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), suite.chainA.SenderAccount.GetAddress(), sdk.DefaultBondDenom) - - res, err := suite.chainA.SendMsgs(msgPayPacketFee) - suite.Require().NotNil(res) - suite.Require().NoError(err) - - postEscrowBalance := suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), suite.chainA.SenderAccount.GetAddress(), sdk.DefaultBondDenom) - suite.Require().Equal(postEscrowBalance.AddAmount(expectedFee.Total().AmountOf(sdk.DefaultBondDenom)), preEscrowBalance) - - packetID := channeltypes.NewPacketID(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, 1) - packetFees, found := suite.chainA.GetSimApp().IBCFeeKeeper.GetFeesInEscrow(suite.chainA.GetContext(), packetID) - suite.Require().True(found) - suite.Require().Equal(expectedFee, packetFees.PacketFees[0].Fee) - - interchainAccountAddr, found := suite.chainB.GetSimApp().ICAHostKeeper.GetInterchainAccountAddress(suite.chainB.GetContext(), ibctesting.FirstConnectionID, path.EndpointA.ChannelConfig.PortID) - suite.Require().True(found) - - // fund the interchain account on chainB - coins := sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.NewInt(100000))) - msgBankSend := &banktypes.MsgSend{ - FromAddress: suite.chainB.SenderAccount.GetAddress().String(), - ToAddress: interchainAccountAddr, - Amount: coins, - } - - res, err = suite.chainB.SendMsgs(msgBankSend) - suite.Require().NotEmpty(res) - suite.Require().NoError(err) - - // prepare a simple stakingtypes.MsgDelegate to be used as the interchain account msg executed on chainB - validatorAddr := (sdk.ValAddress)(suite.chainB.Vals.Validators[0].Address) - msgDelegate := &stakingtypes.MsgDelegate{ - DelegatorAddress: interchainAccountAddr, - ValidatorAddress: validatorAddr.String(), - Amount: sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.NewInt(5000)), - } - - data, err := icatypes.SerializeCosmosTx(suite.chainA.GetSimApp().AppCodec(), []proto.Message{msgDelegate}, icatypes.EncodingProtobuf) - suite.Require().NoError(err) - - icaPacketData := icatypes.InterchainAccountPacketData{ - Type: icatypes.EXECUTE_TX, - Data: data, + for _, ordering := range []channeltypes.Order{channeltypes.UNORDERED, channeltypes.ORDERED} { + suite.SetupTest() // reset + + path := NewIncentivizedICAPath(suite.chainA, suite.chainB, ordering) + path.SetupConnections() + + err := SetupPath(path, defaultOwnerAddress) + suite.Require().NoError(err) + + // assert the newly established channel is fee enabled on both ends + suite.Require().True(suite.chainA.GetSimApp().IBCFeeKeeper.IsFeeEnabled(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID)) + suite.Require().True(suite.chainB.GetSimApp().IBCFeeKeeper.IsFeeEnabled(suite.chainB.GetContext(), path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID)) + + // register counterparty address on destination chainB as chainA.SenderAccounts[1] for recv fee distribution + suite.chainB.GetSimApp().IBCFeeKeeper.SetCounterpartyPayeeAddress(suite.chainB.GetContext(), suite.chainB.SenderAccount.GetAddress().String(), suite.chainA.SenderAccounts[1].SenderAccount.GetAddress().String(), path.EndpointB.ChannelID) + + // escrow a packet fee for the next send sequence + expectedFee := types.NewFee(defaultRecvFee, defaultAckFee, defaultTimeoutFee) + msgPayPacketFee := types.NewMsgPayPacketFee(expectedFee, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, suite.chainA.SenderAccount.GetAddress().String(), nil) + + // fetch the account balance before fees are escrowed and assert the difference below + preEscrowBalance := suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), suite.chainA.SenderAccount.GetAddress(), sdk.DefaultBondDenom) + + res, err := suite.chainA.SendMsgs(msgPayPacketFee) + suite.Require().NotNil(res) + suite.Require().NoError(err) + + postEscrowBalance := suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), suite.chainA.SenderAccount.GetAddress(), sdk.DefaultBondDenom) + suite.Require().Equal(postEscrowBalance.AddAmount(expectedFee.Total().AmountOf(sdk.DefaultBondDenom)), preEscrowBalance) + + packetID := channeltypes.NewPacketID(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, 1) + packetFees, found := suite.chainA.GetSimApp().IBCFeeKeeper.GetFeesInEscrow(suite.chainA.GetContext(), packetID) + suite.Require().True(found) + suite.Require().Equal(expectedFee, packetFees.PacketFees[0].Fee) + + interchainAccountAddr, found := suite.chainB.GetSimApp().ICAHostKeeper.GetInterchainAccountAddress(suite.chainB.GetContext(), ibctesting.FirstConnectionID, path.EndpointA.ChannelConfig.PortID) + suite.Require().True(found) + + // fund the interchain account on chainB + coins := sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.NewInt(100000))) + msgBankSend := &banktypes.MsgSend{ + FromAddress: suite.chainB.SenderAccount.GetAddress().String(), + ToAddress: interchainAccountAddr, + Amount: coins, + } + + res, err = suite.chainB.SendMsgs(msgBankSend) + suite.Require().NotEmpty(res) + suite.Require().NoError(err) + + // prepare a simple stakingtypes.MsgDelegate to be used as the interchain account msg executed on chainB + validatorAddr := (sdk.ValAddress)(suite.chainB.Vals.Validators[0].Address) + msgDelegate := &stakingtypes.MsgDelegate{ + DelegatorAddress: interchainAccountAddr, + ValidatorAddress: validatorAddr.String(), + Amount: sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.NewInt(5000)), + } + + data, err := icatypes.SerializeCosmosTx(suite.chainA.GetSimApp().AppCodec(), []proto.Message{msgDelegate}, icatypes.EncodingProtobuf) + suite.Require().NoError(err) + + icaPacketData := icatypes.InterchainAccountPacketData{ + Type: icatypes.EXECUTE_TX, + Data: data, + } + + // ensure chainB is allowed to execute stakingtypes.MsgDelegate + params := icahosttypes.NewParams(true, []string{sdk.MsgTypeURL(msgDelegate)}) + suite.chainB.GetSimApp().ICAHostKeeper.SetParams(suite.chainB.GetContext(), params) + + // build the interchain accounts packet + packet := buildInterchainAccountsPacket(path, icaPacketData.GetBytes(), 1) + + // write packet commitment to state on chainA and commit state + commitment := channeltypes.CommitPacket(suite.chainA.GetSimApp().AppCodec(), packet) + suite.chainA.GetSimApp().IBCKeeper.ChannelKeeper.SetPacketCommitment(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, 1, commitment) + suite.chainA.NextBlock() + + err = path.RelayPacket(packet) + suite.Require().NoError(err) + + // ensure escrowed fees are cleaned up + packetFees, found = suite.chainA.GetSimApp().IBCFeeKeeper.GetFeesInEscrow(suite.chainA.GetContext(), packetID) + suite.Require().False(found) + suite.Require().Empty(packetFees) + + // assert the value of the account balance after fee distribution + // NOTE: the balance after fee distribution should be equal to the pre-escrow balance minus the recv fee + // as chainA.SenderAccount is used as the msg signer and refund address for msgPayPacketFee above as well as the relyer account for acknowledgements in path.RelayPacket() + postDistBalance := suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), suite.chainA.SenderAccount.GetAddress(), sdk.DefaultBondDenom) + suite.Require().Equal(preEscrowBalance.SubAmount(defaultRecvFee.AmountOf(sdk.DefaultBondDenom)), postDistBalance) } - - // ensure chainB is allowed to execute stakingtypes.MsgDelegate - params := icahosttypes.NewParams(true, []string{sdk.MsgTypeURL(msgDelegate)}) - suite.chainB.GetSimApp().ICAHostKeeper.SetParams(suite.chainB.GetContext(), params) - - // build the interchain accounts packet - packet := buildInterchainAccountsPacket(path, icaPacketData.GetBytes(), 1) - - // write packet commitment to state on chainA and commit state - commitment := channeltypes.CommitPacket(suite.chainA.GetSimApp().AppCodec(), packet) - suite.chainA.GetSimApp().IBCKeeper.ChannelKeeper.SetPacketCommitment(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, 1, commitment) - suite.chainA.NextBlock() - - err = path.RelayPacket(packet) - suite.Require().NoError(err) - - // ensure escrowed fees are cleaned up - packetFees, found = suite.chainA.GetSimApp().IBCFeeKeeper.GetFeesInEscrow(suite.chainA.GetContext(), packetID) - suite.Require().False(found) - suite.Require().Empty(packetFees) - - // assert the value of the account balance after fee distribution - // NOTE: the balance after fee distribution should be equal to the pre-escrow balance minus the recv fee - // as chainA.SenderAccount is used as the msg signer and refund address for msgPayPacketFee above as well as the relyer account for acknowledgements in path.RelayPacket() - postDistBalance := suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), suite.chainA.SenderAccount.GetAddress(), sdk.DefaultBondDenom) - suite.Require().Equal(preEscrowBalance.SubAmount(defaultRecvFee.AmountOf(sdk.DefaultBondDenom)), postDistBalance) } func (suite *FeeTestSuite) TestOnesidedFeeMiddlewareICAHandshake() { - RemoveFeeMiddleware(suite.chainB) // remove fee middleware from chainB + for _, ordering := range []channeltypes.Order{channeltypes.UNORDERED, channeltypes.ORDERED} { + suite.SetupTest() // reset + + RemoveFeeMiddleware(suite.chainB) // remove fee middleware from chainB - path := NewIncentivizedICAPath(suite.chainA, suite.chainB) + path := NewIncentivizedICAPath(suite.chainA, suite.chainB, ordering) - path.SetupConnections() + path.SetupConnections() - err := SetupPath(path, defaultOwnerAddress) - suite.Require().NoError(err) + err := SetupPath(path, defaultOwnerAddress) + suite.Require().NoError(err) - // assert the newly established channel is not fee enabled on chainB - interchainAccountAddr, found := suite.chainB.GetSimApp().ICAHostKeeper.GetInterchainAccountAddress(suite.chainB.GetContext(), ibctesting.FirstConnectionID, path.EndpointA.ChannelConfig.PortID) - suite.Require().True(found) + // assert the newly established channel is not fee enabled on chainB + interchainAccountAddr, found := suite.chainB.GetSimApp().ICAHostKeeper.GetInterchainAccountAddress(suite.chainB.GetContext(), ibctesting.FirstConnectionID, path.EndpointA.ChannelConfig.PortID) + suite.Require().True(found) - expVersionMetadata, err := icatypes.MetadataFromVersion(defaultICAVersion) - suite.Require().NoError(err) + expVersionMetadata, err := icatypes.MetadataFromVersion(defaultICAVersion) + suite.Require().NoError(err) - expVersionMetadata.Address = interchainAccountAddr + expVersionMetadata.Address = interchainAccountAddr - expVersion := string(icatypes.ModuleCdc.MustMarshalJSON(&expVersionMetadata)) + expVersion := string(icatypes.ModuleCdc.MustMarshalJSON(&expVersionMetadata)) - suite.Require().Equal(path.EndpointA.ChannelConfig.Version, expVersion) - suite.Require().Equal(path.EndpointB.ChannelConfig.Version, expVersion) + suite.Require().Equal(path.EndpointA.ChannelConfig.Version, expVersion) + suite.Require().Equal(path.EndpointB.ChannelConfig.Version, expVersion) + } } func buildInterchainAccountsPacket(path *ibctesting.Path, data []byte, seq uint64) channeltypes.Packet { diff --git a/modules/apps/callbacks/go.mod b/modules/apps/callbacks/go.mod index 4901dad1021..3d5aca987c8 100644 --- a/modules/apps/callbacks/go.mod +++ b/modules/apps/callbacks/go.mod @@ -21,7 +21,7 @@ require ( cosmossdk.io/x/evidence v0.1.1 cosmossdk.io/x/feegrant v0.1.1 cosmossdk.io/x/tx v0.13.3 - cosmossdk.io/x/upgrade v0.1.2 + cosmossdk.io/x/upgrade v0.1.3 github.com/cometbft/cometbft v0.38.7 github.com/cosmos/cosmos-db v1.0.2 github.com/cosmos/cosmos-sdk v0.50.7 @@ -114,7 +114,7 @@ require ( github.com/grpc-ecosystem/grpc-gateway v1.16.0 // indirect github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // indirect - github.com/hashicorp/go-getter v1.7.3 // indirect + github.com/hashicorp/go-getter v1.7.4 // indirect github.com/hashicorp/go-hclog v1.5.0 // indirect github.com/hashicorp/go-immutable-radix v1.3.1 // indirect github.com/hashicorp/go-metrics v0.5.3 // indirect diff --git a/modules/apps/callbacks/go.sum b/modules/apps/callbacks/go.sum index 7d8c46ad0ca..c5a4fd09172 100644 --- a/modules/apps/callbacks/go.sum +++ b/modules/apps/callbacks/go.sum @@ -212,8 +212,8 @@ cosmossdk.io/x/feegrant v0.1.1 h1:EKFWOeo/pup0yF0svDisWWKAA9Zags6Zd0P3nRvVvw8= cosmossdk.io/x/feegrant v0.1.1/go.mod h1:2GjVVxX6G2fta8LWj7pC/ytHjryA6MHAJroBWHFNiEQ= cosmossdk.io/x/tx v0.13.3 h1:Ha4mNaHmxBc6RMun9aKuqul8yHiL78EKJQ8g23Zf73g= cosmossdk.io/x/tx v0.13.3/go.mod h1:I8xaHv0rhUdIvIdptKIqzYy27+n2+zBVaxO6fscFhys= -cosmossdk.io/x/upgrade v0.1.2 h1:O2FGb0mVSXl7P6BQm9uV3hRVKom1zBLDGhd4G8jysJg= -cosmossdk.io/x/upgrade v0.1.2/go.mod h1:P+e4/ZNd8km7lTAX5hC2pXz/042YDcB7gzKTHuY53nc= +cosmossdk.io/x/upgrade v0.1.3 h1:q4XpXc6zp0dX6x74uBtfN6+J7ikaQev5Bla6Q0ADLK8= +cosmossdk.io/x/upgrade v0.1.3/go.mod h1:jOdQhnaY5B8CDUoUbed23/Lre0Dk+r6BMQE40iKlVVQ= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= filippo.io/edwards25519 v1.0.0 h1:0wAIcmJUqRdI8IJ/3eGi5/HwXZWPujYXXlkrQogz0Ek= filippo.io/edwards25519 v1.0.0/go.mod h1:N1IkdkCkiLB6tki+MYJoSx2JTY9NUlxZE7eHn5EwJns= @@ -650,8 +650,8 @@ github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtng github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= -github.com/hashicorp/go-getter v1.7.3 h1:bN2+Fw9XPFvOCjB0UOevFIMICZ7G2XSQHzfvLUyOM5E= -github.com/hashicorp/go-getter v1.7.3/go.mod h1:W7TalhMmbPmsSMdNjD0ZskARur/9GJ17cfHTRtXV744= +github.com/hashicorp/go-getter v1.7.4 h1:3yQjWuxICvSpYwqSayAdKRFcvBl1y/vogCxczWSmix0= +github.com/hashicorp/go-getter v1.7.4/go.mod h1:W7TalhMmbPmsSMdNjD0ZskARur/9GJ17cfHTRtXV744= github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c= github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= diff --git a/modules/apps/transfer/client/cli/tx.go b/modules/apps/transfer/client/cli/tx.go index 54989e2b62e..e3cc4be4366 100644 --- a/modules/apps/transfer/client/cli/tx.go +++ b/modules/apps/transfer/client/cli/tx.go @@ -60,7 +60,7 @@ using the {packet-timeout-timestamp} flag. If no timeout value is set then a def for i, coin := range coins { if !strings.HasPrefix(coin.Denom, "ibc/") { - denom := types.ExtractDenomFromFullPath(coin.Denom) + denom := types.ExtractDenomFromPath(coin.Denom) coins[i].Denom = denom.IBCDenom() } } diff --git a/modules/apps/transfer/ibc_module.go b/modules/apps/transfer/ibc_module.go index 0c825965a7e..299b17f735e 100644 --- a/modules/apps/transfer/ibc_module.go +++ b/modules/apps/transfer/ibc_module.go @@ -12,6 +12,7 @@ import ( capabilitytypes "github.com/cosmos/ibc-go/modules/capability/types" "github.com/cosmos/ibc-go/v8/modules/apps/transfer/internal" + "github.com/cosmos/ibc-go/v8/modules/apps/transfer/internal/events" "github.com/cosmos/ibc-go/v8/modules/apps/transfer/keeper" "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types" channeltypes "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types" @@ -184,12 +185,7 @@ func (im IBCModule) OnRecvPacket( ) ibcexported.Acknowledgement { ack := channeltypes.NewResultAcknowledgement([]byte{byte(1)}) - ics20Version, found := im.keeper.GetICS4Wrapper().GetAppVersion(ctx, packet.DestinationPort, packet.DestinationChannel) - if !found { - return channeltypes.NewErrorAcknowledgement(errorsmod.Wrapf(ibcerrors.ErrNotFound, "app version not found for port %s and channel %s", packet.DestinationPort, packet.DestinationChannel)) - } - - data, ackErr := internal.UnmarshalPacketData(packet.GetData(), ics20Version) + data, ackErr := im.getICS20PacketData(ctx, packet.GetData(), packet.GetDestPort(), packet.GetDestChannel()) if ackErr != nil { ackErr = errorsmod.Wrapf(ibcerrors.ErrInvalidType, ackErr.Error()) im.keeper.Logger(ctx).Error(fmt.Sprintf("%s sequence %d", ackErr.Error(), packet.Sequence)) @@ -209,28 +205,7 @@ func (im IBCModule) OnRecvPacket( } } - eventAttributes := []sdk.Attribute{ - sdk.NewAttribute(types.AttributeKeySender, data.Sender), - sdk.NewAttribute(types.AttributeKeyReceiver, data.Receiver), - sdk.NewAttribute(types.AttributeKeyTokens, types.Tokens(data.Tokens).String()), - sdk.NewAttribute(types.AttributeKeyMemo, data.Memo), - sdk.NewAttribute(types.AttributeKeyAckSuccess, fmt.Sprintf("%t", ack.Success())), - } - - if ackErr != nil { - eventAttributes = append(eventAttributes, sdk.NewAttribute(types.AttributeKeyAckError, ackErr.Error())) - } - - ctx.EventManager().EmitEvents(sdk.Events{ - sdk.NewEvent( - types.EventTypePacket, - eventAttributes..., - ), - sdk.NewEvent( - sdk.EventTypeMessage, - sdk.NewAttribute(sdk.AttributeKeyModule, types.ModuleName), - ), - }) + events.EmitOnRecvPacketEvent(ctx, data, ack, ackErr) // NOTE: acknowledgement will be written synchronously during IBC handler execution. return ack @@ -248,12 +223,7 @@ func (im IBCModule) OnAcknowledgementPacket( return errorsmod.Wrapf(ibcerrors.ErrUnknownRequest, "cannot unmarshal ICS-20 transfer packet acknowledgement: %v", err) } - ics20Version, found := im.keeper.GetICS4Wrapper().GetAppVersion(ctx, packet.SourcePort, packet.SourceChannel) - if !found { - return errorsmod.Wrapf(ibcerrors.ErrNotFound, "app version not found for port %s and channel %s", packet.SourcePort, packet.SourceChannel) - } - - data, err := internal.UnmarshalPacketData(packet.GetData(), ics20Version) + data, err := im.getICS20PacketData(ctx, packet.GetData(), packet.GetSourcePort(), packet.GetSourceChannel()) if err != nil { return err } @@ -262,37 +232,7 @@ func (im IBCModule) OnAcknowledgementPacket( return err } - ctx.EventManager().EmitEvents(sdk.Events{ - sdk.NewEvent( - types.EventTypePacket, - sdk.NewAttribute(sdk.AttributeKeySender, data.Sender), - sdk.NewAttribute(types.AttributeKeyReceiver, data.Receiver), - sdk.NewAttribute(types.AttributeKeyTokens, types.Tokens(data.Tokens).String()), - sdk.NewAttribute(types.AttributeKeyMemo, data.Memo), - sdk.NewAttribute(types.AttributeKeyAck, ack.String()), - ), - sdk.NewEvent( - sdk.EventTypeMessage, - sdk.NewAttribute(sdk.AttributeKeyModule, types.ModuleName), - ), - }) - - switch resp := ack.Response.(type) { - case *channeltypes.Acknowledgement_Result: - ctx.EventManager().EmitEvent( - sdk.NewEvent( - types.EventTypePacket, - sdk.NewAttribute(types.AttributeKeyAckSuccess, string(resp.Result)), - ), - ) - case *channeltypes.Acknowledgement_Error: - ctx.EventManager().EmitEvent( - sdk.NewEvent( - types.EventTypePacket, - sdk.NewAttribute(types.AttributeKeyAckError, resp.Error), - ), - ) - } + events.EmitOnAcknowledgementPacketEvent(ctx, data, ack) return nil } @@ -303,12 +243,7 @@ func (im IBCModule) OnTimeoutPacket( packet channeltypes.Packet, relayer sdk.AccAddress, ) error { - ics20Version, found := im.keeper.GetICS4Wrapper().GetAppVersion(ctx, packet.SourcePort, packet.SourceChannel) - if !found { - return errorsmod.Wrapf(ibcerrors.ErrNotFound, "app version not found for port %s and channel %s", packet.SourcePort, packet.SourceChannel) - } - - data, err := internal.UnmarshalPacketData(packet.GetData(), ics20Version) + data, err := im.getICS20PacketData(ctx, packet.GetData(), packet.GetSourcePort(), packet.GetSourceChannel()) if err != nil { return err } @@ -318,19 +253,7 @@ func (im IBCModule) OnTimeoutPacket( return err } - ctx.EventManager().EmitEvents(sdk.Events{ - sdk.NewEvent( - types.EventTypeTimeout, - sdk.NewAttribute(types.AttributeKeyReceiver, data.Sender), - sdk.NewAttribute(types.AttributeKeyRefundTokens, types.Tokens(data.Tokens).String()), - sdk.NewAttribute(types.AttributeKeyMemo, data.Memo), - ), - sdk.NewEvent( - sdk.EventTypeMessage, - sdk.NewAttribute(sdk.AttributeKeyModule, types.ModuleName), - ), - }) - + events.EmitOnTimeoutEvent(ctx, data) return nil } @@ -378,15 +301,16 @@ func (IBCModule) OnChanUpgradeOpen(ctx sdk.Context, portID, channelID string, pr // into a FungibleTokenPacketData. This function implements the optional // PacketDataUnmarshaler interface required for ADR 008 support. func (im IBCModule) UnmarshalPacketData(ctx sdk.Context, portID, channelID string, bz []byte) (interface{}, error) { + return im.getICS20PacketData(ctx, bz, portID, channelID) +} + +// getICS20PacketData determines the current version of ICS20 and unmarshals the packet data into either a FungibleTokenPacketData +// or a FungibleTokenPacketDataV2 depending on the application version. +func (im IBCModule) getICS20PacketData(ctx sdk.Context, packetData []byte, portID, channelID string) (types.FungibleTokenPacketDataV2, error) { ics20Version, found := im.keeper.GetICS4Wrapper().GetAppVersion(ctx, portID, channelID) if !found { - return nil, errorsmod.Wrapf(ibcerrors.ErrNotFound, "app version not found for port %s and channel %s", portID, channelID) - } - - ftpd, err := internal.UnmarshalPacketData(bz, ics20Version) - if err != nil { - return nil, err + return types.FungibleTokenPacketDataV2{}, errorsmod.Wrapf(ibcerrors.ErrNotFound, "app version not found for port %s and channel %s", portID, channelID) } - return ftpd, nil + return internal.UnmarshalPacketData(packetData, ics20Version) } diff --git a/modules/apps/transfer/internal/events/events.go b/modules/apps/transfer/internal/events/events.go new file mode 100644 index 00000000000..40ef44e3d15 --- /dev/null +++ b/modules/apps/transfer/internal/events/events.go @@ -0,0 +1,136 @@ +package events + +import ( + "encoding/json" + "fmt" + + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types" + channeltypes "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types" +) + +// EmitTransferEvent emits a ibc transfer event on successful transfers. +func EmitTransferEvent(ctx sdk.Context, sender, receiver string, tokens types.Tokens, memo string) { + jsonTokens := mustMarshalType[types.Tokens](tokens) + + ctx.EventManager().EmitEvents(sdk.Events{ + sdk.NewEvent( + types.EventTypeTransfer, + sdk.NewAttribute(types.AttributeKeySender, sender), + sdk.NewAttribute(types.AttributeKeyReceiver, receiver), + sdk.NewAttribute(types.AttributeKeyTokens, jsonTokens), + sdk.NewAttribute(types.AttributeKeyMemo, memo), + ), + sdk.NewEvent( + sdk.EventTypeMessage, + sdk.NewAttribute(sdk.AttributeKeyModule, types.ModuleName), + ), + }) +} + +// EmitOnRecvPacketEvent emits a fungible token packet event in the OnRecvPacket callback +func EmitOnRecvPacketEvent(ctx sdk.Context, packetData types.FungibleTokenPacketDataV2, ack channeltypes.Acknowledgement, ackErr error) { + jsonTokens := mustMarshalType[types.Tokens](types.Tokens(packetData.Tokens)) + + eventAttributes := []sdk.Attribute{ + sdk.NewAttribute(types.AttributeKeySender, packetData.Sender), + sdk.NewAttribute(types.AttributeKeyReceiver, packetData.Receiver), + sdk.NewAttribute(types.AttributeKeyTokens, jsonTokens), + sdk.NewAttribute(types.AttributeKeyMemo, packetData.Memo), + sdk.NewAttribute(types.AttributeKeyAckSuccess, fmt.Sprintf("%t", ack.Success())), + } + + if ackErr != nil { + eventAttributes = append(eventAttributes, sdk.NewAttribute(types.AttributeKeyAckError, ackErr.Error())) + } + + ctx.EventManager().EmitEvents(sdk.Events{ + sdk.NewEvent( + types.EventTypePacket, + eventAttributes..., + ), + sdk.NewEvent( + sdk.EventTypeMessage, + sdk.NewAttribute(sdk.AttributeKeyModule, types.ModuleName), + ), + }) +} + +// EmitOnAcknowledgementPacketEvent emits a fungible token packet event in the OnAcknowledgementPacket callback +func EmitOnAcknowledgementPacketEvent(ctx sdk.Context, packetData types.FungibleTokenPacketDataV2, ack channeltypes.Acknowledgement) { + jsonTokens := mustMarshalType[types.Tokens](types.Tokens(packetData.Tokens)) + + ctx.EventManager().EmitEvents(sdk.Events{ + sdk.NewEvent( + types.EventTypePacket, + sdk.NewAttribute(sdk.AttributeKeySender, packetData.Sender), + sdk.NewAttribute(types.AttributeKeyReceiver, packetData.Receiver), + sdk.NewAttribute(types.AttributeKeyTokens, jsonTokens), + sdk.NewAttribute(types.AttributeKeyMemo, packetData.Memo), + sdk.NewAttribute(types.AttributeKeyAck, ack.String()), + ), + sdk.NewEvent( + sdk.EventTypeMessage, + sdk.NewAttribute(sdk.AttributeKeyModule, types.ModuleName), + ), + }) + + switch resp := ack.Response.(type) { + case *channeltypes.Acknowledgement_Result: + ctx.EventManager().EmitEvent( + sdk.NewEvent( + types.EventTypePacket, + sdk.NewAttribute(types.AttributeKeyAckSuccess, string(resp.Result)), + ), + ) + case *channeltypes.Acknowledgement_Error: + ctx.EventManager().EmitEvent( + sdk.NewEvent( + types.EventTypePacket, + sdk.NewAttribute(types.AttributeKeyAckError, resp.Error), + ), + ) + } +} + +// EmitOnTimeoutPacketEvent emits a fungible token packet event in the OnTimeoutPacket callback +func EmitOnTimeoutEvent(ctx sdk.Context, packetData types.FungibleTokenPacketDataV2) { + jsonTokens := mustMarshalType[types.Tokens](types.Tokens(packetData.Tokens)) + + ctx.EventManager().EmitEvents(sdk.Events{ + sdk.NewEvent( + types.EventTypeTimeout, + sdk.NewAttribute(types.AttributeKeyReceiver, packetData.Sender), + sdk.NewAttribute(types.AttributeKeyRefundTokens, jsonTokens), + sdk.NewAttribute(types.AttributeKeyMemo, packetData.Memo), + ), + sdk.NewEvent( + sdk.EventTypeMessage, + sdk.NewAttribute(sdk.AttributeKeyModule, types.ModuleName), + ), + }) +} + +// EmitDenomEvent emits a denomination event in the OnRecv callback. +func EmitDenomEvent(ctx sdk.Context, token types.Token) { + jsonDenom := mustMarshalType[types.Denom](token.Denom) + + ctx.EventManager().EmitEvent( + sdk.NewEvent( + types.EventTypeDenom, + sdk.NewAttribute(types.AttributeKeyDenomHash, jsonDenom), + sdk.NewAttribute(types.AttributeKeyDenom, token.Denom.String()), + ), + ) +} + +// mustMarshalType json marshals the given type and panics on failure. +func mustMarshalType[T any](v T) string { + bz, err := json.Marshal(v) + if err != nil { + panic(err) + } + + return string(bz) +} diff --git a/modules/apps/transfer/internal/packet.go b/modules/apps/transfer/internal/packet.go index 83e35b794e9..0d5c7a9456e 100644 --- a/modules/apps/transfer/internal/packet.go +++ b/modules/apps/transfer/internal/packet.go @@ -43,7 +43,7 @@ func packetDataV1ToV2(packetData types.FungibleTokenPacketData) (types.FungibleT return types.FungibleTokenPacketDataV2{}, errorsmod.Wrapf(err, "invalid packet data") } - denom := types.ExtractDenomFromFullPath(packetData.Denom) + denom := types.ExtractDenomFromPath(packetData.Denom) return types.FungibleTokenPacketDataV2{ Tokens: []types.Token{ { diff --git a/modules/apps/transfer/keeper/export_test.go b/modules/apps/transfer/keeper/export_test.go index c2a30839dc6..8c6f3961c79 100644 --- a/modules/apps/transfer/keeper/export_test.go +++ b/modules/apps/transfer/keeper/export_test.go @@ -31,3 +31,8 @@ func (k Keeper) GetAllDenomTraces(ctx sdk.Context) []types.DenomTrace { func (k Keeper) TokenFromCoin(ctx sdk.Context, coin sdk.Coin) (types.Token, error) { return k.tokenFromCoin(ctx, coin) } + +// CreatePacketDataBytesFromVersion is a wrapper around createPacketDataBytesFromVersion for testing purposes +func CreatePacketDataBytesFromVersion(appVersion, sender, receiver, memo string, tokens types.Tokens) []byte { + return createPacketDataBytesFromVersion(appVersion, sender, receiver, memo, tokens) +} diff --git a/modules/apps/transfer/keeper/grpc_query.go b/modules/apps/transfer/keeper/grpc_query.go index a16605d6c47..01a8e6ddc6b 100644 --- a/modules/apps/transfer/keeper/grpc_query.go +++ b/modules/apps/transfer/keeper/grpc_query.go @@ -96,7 +96,7 @@ func (k Keeper) DenomHash(c context.Context, req *types.QueryDenomHashRequest) ( } // Convert given request trace path to Denom struct to confirm the path in a valid denom trace format - denom := types.ExtractDenomFromFullPath(req.Trace) + denom := types.ExtractDenomFromPath(req.Trace) if err := denom.Validate(); err != nil { return nil, status.Error(codes.InvalidArgument, err.Error()) } diff --git a/modules/apps/transfer/keeper/mbt_relay_test.go b/modules/apps/transfer/keeper/mbt_relay_test.go index 81d672a072e..585fc596364 100644 --- a/modules/apps/transfer/keeper/mbt_relay_test.go +++ b/modules/apps/transfer/keeper/mbt_relay_test.go @@ -143,7 +143,7 @@ func BalancesFromTla(tla []TlaBalance) []Balance { } func FungibleTokenPacketFromTla(packet TlaFungibleTokenPacket) FungibleTokenPacket { - denom := types.ExtractDenomFromFullPath(DenomFromTla(packet.Data.Denom)) + denom := types.ExtractDenomFromPath(DenomFromTla(packet.Data.Denom)) return FungibleTokenPacket{ SourceChannel: packet.SourceChannel, SourcePort: packet.SourcePort, diff --git a/modules/apps/transfer/keeper/migrations.go b/modules/apps/transfer/keeper/migrations.go index 57e5668d3bf..81306a4d986 100644 --- a/modules/apps/transfer/keeper/migrations.go +++ b/modules/apps/transfer/keeper/migrations.go @@ -80,7 +80,7 @@ func (m Migrator) MigrateDenomTraceToDenom(ctx sdk.Context) error { m.keeper.iterateDenomTraces(ctx, func(dt types.DenomTrace) (stop bool) { // convert denomTrace to denom - denom := types.ExtractDenomFromFullPath(dt.GetFullDenomPath()) + denom := types.ExtractDenomFromPath(dt.GetFullDenomPath()) err := denom.Validate() if err != nil { panic(err) diff --git a/modules/apps/transfer/keeper/msg_server.go b/modules/apps/transfer/keeper/msg_server.go index 70120fe2810..c8cc0f5b0eb 100644 --- a/modules/apps/transfer/keeper/msg_server.go +++ b/modules/apps/transfer/keeper/msg_server.go @@ -43,20 +43,6 @@ func (k Keeper) Transfer(goCtx context.Context, msg *types.MsgTransfer) (*types. return nil, err } - ctx.EventManager().EmitEvents(sdk.Events{ - sdk.NewEvent( - types.EventTypeTransfer, - sdk.NewAttribute(types.AttributeKeySender, msg.Sender), - sdk.NewAttribute(types.AttributeKeyReceiver, msg.Receiver), - sdk.NewAttribute(types.AttributeKeyTokens, coins.String()), - sdk.NewAttribute(types.AttributeKeyMemo, msg.Memo), - ), - sdk.NewEvent( - sdk.EventTypeMessage, - sdk.NewAttribute(sdk.AttributeKeyModule, types.ModuleName), - ), - }) - k.Logger(ctx).Info("IBC fungible token transfer", "tokens", coins, "sender", msg.Sender, "receiver", msg.Receiver) return &types.MsgTransferResponse{Sequence: sequence}, nil diff --git a/modules/apps/transfer/keeper/msg_server_test.go b/modules/apps/transfer/keeper/msg_server_test.go index 58624015d07..2c67c9c01e1 100644 --- a/modules/apps/transfer/keeper/msg_server_test.go +++ b/modules/apps/transfer/keeper/msg_server_test.go @@ -1,6 +1,7 @@ package keeper_test import ( + "encoding/json" "errors" "strings" @@ -40,7 +41,7 @@ func (suite *KeeperTestSuite) TestMsgTransfer() { "success: multidenom", func() { coin2 = sdk.NewCoin("bond", sdkmath.NewInt(100)) - coins := sdk.NewCoins(coin1, coin2) + coins := []sdk.Coin{coin1, coin2} // send some coins of the second denom from bank module to the sender account as well suite.Require().NoError(suite.chainA.GetSimApp().BankKeeper.MintCoins(suite.chainA.GetContext(), types.ModuleName, sdk.NewCoins(coin2))) @@ -204,40 +205,40 @@ func (suite *KeeperTestSuite) TestMsgTransfer() { tc.malleate() ctx := suite.chainA.GetContext() - res, err := suite.chainA.GetSimApp().TransferKeeper.Transfer(ctx, msg) - // Verify events - events := ctx.EventManager().Events().ToABCIEvents() + var tokens []types.Token + token1, err := suite.chainA.GetSimApp().TransferKeeper.TokenFromCoin(ctx, coin1) + suite.Require().NoError(err) + tokens = append(tokens, token1) var expEvents []abci.Event if tc.multiDenom { - expEvents = sdk.Events{ - sdk.NewEvent(types.EventTypeTransfer, - sdk.NewAttribute(types.AttributeKeySender, msg.Sender), - sdk.NewAttribute(types.AttributeKeyReceiver, msg.Receiver), - sdk.NewAttribute(types.AttributeKeyMemo, msg.Memo), - sdk.NewAttribute(types.AttributeKeyTokens, sdk.NewCoins(coin1, coin2).String()), - ), - sdk.NewEvent( - sdk.EventTypeMessage, - sdk.NewAttribute(sdk.AttributeKeyModule, types.ModuleName), - ), - }.ToABCIEvents() - } else { - expEvents = sdk.Events{ - sdk.NewEvent(types.EventTypeTransfer, - sdk.NewAttribute(types.AttributeKeySender, msg.Sender), - sdk.NewAttribute(types.AttributeKeyReceiver, msg.Receiver), - sdk.NewAttribute(types.AttributeKeyMemo, msg.Memo), - sdk.NewAttribute(types.AttributeKeyTokens, coin1.String()), - ), - sdk.NewEvent( - sdk.EventTypeMessage, - sdk.NewAttribute(sdk.AttributeKeyModule, types.ModuleName), - ), - }.ToABCIEvents() + token2, err := suite.chainA.GetSimApp().TransferKeeper.TokenFromCoin(ctx, coin2) + suite.Require().NoError(err) + tokens = append(tokens, token2) } + jsonTokens, err := json.Marshal(types.Tokens(tokens)) + suite.Require().NoError(err) + + res, err := suite.chainA.GetSimApp().TransferKeeper.Transfer(ctx, msg) + + // Verify events + events := ctx.EventManager().Events().ToABCIEvents() + + expEvents = sdk.Events{ + sdk.NewEvent(types.EventTypeTransfer, + sdk.NewAttribute(types.AttributeKeySender, msg.Sender), + sdk.NewAttribute(types.AttributeKeyReceiver, msg.Receiver), + sdk.NewAttribute(types.AttributeKeyTokens, string(jsonTokens)), + sdk.NewAttribute(types.AttributeKeyMemo, msg.Memo), + ), + sdk.NewEvent( + sdk.EventTypeMessage, + sdk.NewAttribute(sdk.AttributeKeyModule, types.ModuleName), + ), + }.ToABCIEvents() + expPass := tc.expError == nil if expPass { suite.Require().NoError(err) diff --git a/modules/apps/transfer/keeper/relay.go b/modules/apps/transfer/keeper/relay.go index 475adfb1841..a9d57e66084 100644 --- a/modules/apps/transfer/keeper/relay.go +++ b/modules/apps/transfer/keeper/relay.go @@ -12,6 +12,7 @@ import ( "github.com/cosmos/cosmos-sdk/telemetry" sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/ibc-go/v8/modules/apps/transfer/internal/events" "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types" clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" channeltypes "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types" @@ -137,25 +138,15 @@ func (k Keeper) sendTransfer( tokens = append(tokens, token) } - var packetDataBytes []byte - switch appVersion { - case types.V1: - // Length of coins has been checked earlier to be 1 if version is V1. - token := tokens[0] - packetData := types.NewFungibleTokenPacketData(token.Denom.Path(), token.Amount, sender.String(), receiver, memo) - packetDataBytes = packetData.GetBytes() - case types.V2: - packetData := types.NewFungibleTokenPacketDataV2(tokens, sender.String(), receiver, memo) - packetDataBytes = packetData.GetBytes() - default: - panic(fmt.Errorf("app version must be one of %s", types.SupportedVersions)) - } + packetDataBytes := createPacketDataBytesFromVersion(appVersion, sender.String(), receiver, memo, tokens) sequence, err := k.ics4Wrapper.SendPacket(ctx, channelCap, sourcePort, sourceChannel, timeoutHeight, timeoutTimestamp, packetDataBytes) if err != nil { return 0, err } + events.EmitTransferEvent(ctx, sender.String(), receiver, tokens, memo) + defer func() { for _, token := range tokens { amount, ok := sdkmath.NewIntFromString(token.Amount) @@ -273,13 +264,8 @@ func (k Keeper) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet, data t k.setDenomMetadata(ctx, token.Denom) } - ctx.EventManager().EmitEvent( - sdk.NewEvent( - types.EventTypeDenomTrace, - sdk.NewAttribute(types.AttributeKeyTraceHash, token.Denom.Hash().String()), - sdk.NewAttribute(types.AttributeKeyDenom, voucherDenom), - ), - ) + events.EmitDenomEvent(ctx, token) + voucher := sdk.NewCoin(voucherDenom, transferAmount) // mint new tokens if the source of the transfer is the same chain @@ -453,3 +439,26 @@ func (k Keeper) tokenFromCoin(ctx sdk.Context, coin sdk.Coin) (types.Token, erro Amount: coin.Amount.String(), }, nil } + +// createPacketDataBytesFromVersion creates the packet data bytes to be sent based on the application version. +func createPacketDataBytesFromVersion(appVersion, sender, receiver, memo string, tokens types.Tokens) []byte { + var packetDataBytes []byte + switch appVersion { + case types.V1: + // Sanity check, tokens must always be of length 1 if using app version V1. + if len(tokens) != 1 { + panic(fmt.Errorf("length of tokens must be equal to 1 if using %s version", types.V1)) + } + + token := tokens[0] + packetData := types.NewFungibleTokenPacketData(token.Denom.Path(), token.Amount, sender, receiver, memo) + packetDataBytes = packetData.GetBytes() + case types.V2: + packetData := types.NewFungibleTokenPacketDataV2(tokens, sender, receiver, memo) + packetDataBytes = packetData.GetBytes() + default: + panic(fmt.Errorf("app version must be one of %s", types.SupportedVersions)) + } + + return packetDataBytes +} diff --git a/modules/apps/transfer/keeper/relay_test.go b/modules/apps/transfer/keeper/relay_test.go index 4d4ea87a026..bb3b2094852 100644 --- a/modules/apps/transfer/keeper/relay_test.go +++ b/modules/apps/transfer/keeper/relay_test.go @@ -12,11 +12,13 @@ import ( banktestutil "github.com/cosmos/cosmos-sdk/x/bank/testutil" banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + transferkeeper "github.com/cosmos/ibc-go/v8/modules/apps/transfer/keeper" "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types" clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" channeltypes "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types" ibcerrors "github.com/cosmos/ibc-go/v8/modules/core/errors" ibctesting "github.com/cosmos/ibc-go/v8/testing" + ibcmock "github.com/cosmos/ibc-go/v8/testing/mock" ) // TestSendTransfer tests sending from chainA to chainB using both coin @@ -614,13 +616,13 @@ func (suite *KeeperTestSuite) TestOnRecvPacketSetsTotalEscrowAmountForSourceIBCT path2 := ibctesting.NewTransferPath(suite.chainA, suite.chainB) path2.Setup() - // denomTrace path: {transfer/channel-1/transfer/channel-0} - denomTrace := types.DenomTrace{ - BaseDenom: sdk.DefaultBondDenom, - Path: fmt.Sprintf("%s/%s/%s/%s", path2.EndpointA.ChannelConfig.PortID, path2.EndpointA.ChannelID, path1.EndpointB.ChannelConfig.PortID, path1.EndpointB.ChannelID), - } + // denom path: {transfer/channel-1/transfer/channel-0} + denom := types.NewDenom( + sdk.DefaultBondDenom, + types.NewTrace(path2.EndpointA.ChannelConfig.PortID, path2.EndpointA.ChannelID), + types.NewTrace(path1.EndpointB.ChannelConfig.PortID, path1.EndpointB.ChannelID), + ) - denom := types.ExtractDenomFromFullPath(denomTrace.GetFullDenomPath()) data := types.NewFungibleTokenPacketDataV2( []types.Token{ { @@ -628,6 +630,7 @@ func (suite *KeeperTestSuite) TestOnRecvPacketSetsTotalEscrowAmountForSourceIBCT Amount: amount.String(), }, }, suite.chainA.SenderAccount.GetAddress().String(), suite.chainB.SenderAccount.GetAddress().String(), "") + packet := channeltypes.NewPacket( data.GetBytes(), seq, @@ -639,13 +642,14 @@ func (suite *KeeperTestSuite) TestOnRecvPacketSetsTotalEscrowAmountForSourceIBCT ) // fund escrow account for transfer and channel-1 on chain B - // denomTrace path: transfer/channel-0 - denomTrace = types.DenomTrace{ - BaseDenom: sdk.DefaultBondDenom, - Path: fmt.Sprintf("%s/%s", path1.EndpointB.ChannelConfig.PortID, path1.EndpointB.ChannelID), - } + // denom path: transfer/channel-0 + denom = types.NewDenom( + sdk.DefaultBondDenom, + types.NewTrace(path1.EndpointB.ChannelConfig.PortID, path1.EndpointB.ChannelID), + ) + escrowAddress := types.GetEscrowAddress(path2.EndpointB.ChannelConfig.PortID, path2.EndpointB.ChannelID) - coin := sdk.NewCoin(denomTrace.IBCDenom(), amount) + coin := sdk.NewCoin(denom.IBCDenom(), amount) suite.Require().NoError( banktestutil.FundAccount( suite.chainB.GetContext(), @@ -828,13 +832,11 @@ func (suite *KeeperTestSuite) TestOnAcknowledgementPacketSetsTotalEscrowAmountFo path2.Setup() // fund escrow account for transfer and channel-1 on chain B - // denomTrace path = transfer/channel-0 - denomTrace := types.DenomTrace{ - BaseDenom: sdk.DefaultBondDenom, - Path: fmt.Sprintf("%s/%s", path1.EndpointB.ChannelConfig.PortID, path1.EndpointB.ChannelID), - } + // denom path: transfer/channel-0 + denom := types.NewDenom(sdk.DefaultBondDenom, types.NewTrace(path1.EndpointB.ChannelConfig.PortID, path1.EndpointB.ChannelID)) + escrowAddress := types.GetEscrowAddress(path2.EndpointB.ChannelConfig.PortID, path2.EndpointB.ChannelID) - coin := sdk.NewCoin(denomTrace.IBCDenom(), amount) + coin := sdk.NewCoin(denom.IBCDenom(), amount) suite.Require().NoError( banktestutil.FundAccount( suite.chainB.GetContext(), @@ -844,7 +846,6 @@ func (suite *KeeperTestSuite) TestOnAcknowledgementPacketSetsTotalEscrowAmountFo ), ) - denom := types.ExtractDenomFromFullPath(denomTrace.GetFullDenomPath()) data := types.NewFungibleTokenPacketDataV2( []types.Token{ { @@ -885,7 +886,7 @@ func (suite *KeeperTestSuite) TestOnAcknowledgementPacketSetsTotalEscrowAmountFo func (suite *KeeperTestSuite) TestOnTimeoutPacket() { var ( path *ibctesting.Path - amount sdkmath.Int + amount string sender string denom types.Denom expEscrowAmount sdkmath.Int @@ -901,7 +902,9 @@ func (suite *KeeperTestSuite) TestOnTimeoutPacket() { func() { escrow := types.GetEscrowAddress(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) denom = types.NewDenom(sdk.DefaultBondDenom) - coin := sdk.NewCoin(denom.IBCDenom(), amount) + coinAmount, ok := sdkmath.NewIntFromString(amount) + suite.Require().True(ok) + coin := sdk.NewCoin(denom.IBCDenom(), coinAmount) expEscrowAmount = sdkmath.ZeroInt() // funds the escrow account to have balance @@ -916,7 +919,9 @@ func (suite *KeeperTestSuite) TestOnTimeoutPacket() { func() { escrow := types.GetEscrowAddress(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) denom = types.NewDenom(sdk.DefaultBondDenom, types.NewTrace(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID)) - coin := sdk.NewCoin(denom.IBCDenom(), amount) + coinAmount, ok := sdkmath.NewIntFromString(amount) + suite.Require().True(ok) + coin := sdk.NewCoin(denom.IBCDenom(), coinAmount) expEscrowAmount = sdkmath.ZeroInt() // funds the escrow account to have balance @@ -928,10 +933,12 @@ func (suite *KeeperTestSuite) TestOnTimeoutPacket() { "failure: funds cannot be refunded because escrow account has no balance for non-native coin", func() { denom = types.NewDenom("bitcoin") - expEscrowAmount = amount + var ok bool + expEscrowAmount, ok = sdkmath.NewIntFromString(amount) + suite.Require().True(ok) // set escrow amount that would have been stored after successful execution of MsgTransfer - suite.chainA.GetSimApp().TransferKeeper.SetTotalEscrowForDenom(suite.chainA.GetContext(), sdk.NewCoin(denom.IBCDenom(), amount)) + suite.chainA.GetSimApp().TransferKeeper.SetTotalEscrowForDenom(suite.chainA.GetContext(), sdk.NewCoin(denom.IBCDenom(), expEscrowAmount)) }, sdkerrors.ErrInsufficientFunds, }, @@ -939,10 +946,12 @@ func (suite *KeeperTestSuite) TestOnTimeoutPacket() { "failure: funds cannot be refunded because escrow account has no balance for native coin", func() { denom = types.NewDenom(sdk.DefaultBondDenom) - expEscrowAmount = amount + var ok bool + expEscrowAmount, ok = sdkmath.NewIntFromString(amount) + suite.Require().True(ok) // set escrow amount that would have been stored after successful execution of MsgTransfer - suite.chainA.GetSimApp().TransferKeeper.SetTotalEscrowForDenom(suite.chainA.GetContext(), sdk.NewCoin(denom.IBCDenom(), amount)) + suite.chainA.GetSimApp().TransferKeeper.SetTotalEscrowForDenom(suite.chainA.GetContext(), sdk.NewCoin(denom.IBCDenom(), expEscrowAmount)) }, sdkerrors.ErrInsufficientFunds, }, @@ -950,11 +959,19 @@ func (suite *KeeperTestSuite) TestOnTimeoutPacket() { "failure: cannot mint because sender address is invalid", func() { denom = types.NewDenom(sdk.DefaultBondDenom) - amount = sdkmath.OneInt() + amount = sdkmath.OneInt().String() sender = "invalid address" }, errors.New("decoding bech32 failed"), }, + { + "failure: invalid amount", + func() { + denom = types.NewDenom(sdk.DefaultBondDenom) + amount = "invalid" + }, + types.ErrInvalidAmount, + }, } for _, tc := range testCases { @@ -966,7 +983,7 @@ func (suite *KeeperTestSuite) TestOnTimeoutPacket() { path = ibctesting.NewTransferPath(suite.chainA, suite.chainB) path.Setup() - amount = sdkmath.NewInt(100) // must be explicitly changed + amount = sdkmath.NewInt(100).String() // must be explicitly changed sender = suite.chainA.SenderAccount.GetAddress().String() expEscrowAmount = sdkmath.ZeroInt() @@ -976,7 +993,7 @@ func (suite *KeeperTestSuite) TestOnTimeoutPacket() { []types.Token{ { Denom: denom, - Amount: amount.String(), + Amount: amount, }, }, sender, suite.chainB.SenderAccount.GetAddress().String(), "") packet := channeltypes.NewPacket(data.GetBytes(), 1, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, clienttypes.NewHeight(1, 100), 0) @@ -994,7 +1011,9 @@ func (suite *KeeperTestSuite) TestOnTimeoutPacket() { expPass := tc.expError == nil if expPass { suite.Require().NoError(err) - suite.Require().Equal(amount.Int64(), deltaAmount.Int64(), "successful timeout did not trigger refund") + amountParsed, ok := sdkmath.NewIntFromString(amount) + suite.Require().True(ok) + suite.Require().Equal(amountParsed, deltaAmount, "successful timeout did not trigger refund") } else { suite.Require().Error(err) suite.Require().ErrorContains(err, tc.expError.Error()) @@ -1043,12 +1062,10 @@ func (suite *KeeperTestSuite) TestOnTimeoutPacketSetsTotalEscrowAmountForSourceI path2.Setup() // fund escrow account for transfer and channel-1 on chain B - denomTrace := types.DenomTrace{ - BaseDenom: sdk.DefaultBondDenom, - Path: fmt.Sprintf("%s/%s", path1.EndpointB.ChannelConfig.PortID, path1.EndpointB.ChannelID), - } + denom := types.NewDenom(sdk.DefaultBondDenom, types.NewTrace(path1.EndpointB.ChannelConfig.PortID, path1.EndpointB.ChannelID)) + escrowAddress := types.GetEscrowAddress(path2.EndpointB.ChannelConfig.PortID, path2.EndpointB.ChannelID) - coin := sdk.NewCoin(denomTrace.IBCDenom(), amount) + coin := sdk.NewCoin(denom.IBCDenom(), amount) suite.Require().NoError( banktestutil.FundAccount( suite.chainB.GetContext(), @@ -1058,7 +1075,6 @@ func (suite *KeeperTestSuite) TestOnTimeoutPacketSetsTotalEscrowAmountForSourceI ), ) - denom := types.ExtractDenomFromFullPath(denomTrace.GetFullDenomPath()) data := types.NewFungibleTokenPacketDataV2( []types.Token{ { @@ -1243,3 +1259,75 @@ func (suite *KeeperTestSuite) TestPacketForwardsCompatibility() { }) } } + +func (suite *KeeperTestSuite) TestCreatePacketDataBytesFromVersion() { + var ( + bz []byte + tokens types.Tokens + ) + + testCases := []struct { + name string + appVersion string + malleate func() + expResult func(bz []byte) + expPanicErr error + }{ + { + "success", + types.V1, + func() {}, + func(bz []byte) { + expPacketData := types.NewFungibleTokenPacketData("", "", "", "", "") + suite.Require().Equal(bz, expPacketData.GetBytes()) + }, + nil, + }, + { + "success: version 2", + types.V2, + func() {}, + func(bz []byte) { + expPacketData := types.NewFungibleTokenPacketDataV2(types.Tokens{types.Token{}}, "", "", "") + suite.Require().Equal(bz, expPacketData.GetBytes()) + }, + nil, + }, + { + "failure: must have single coin if using version 1.", + types.V1, + func() { + tokens = types.Tokens{} + }, + nil, + fmt.Errorf("length of tokens must be equal to 1 if using %s version", types.V1), + }, + { + "failure: invalid version", + ibcmock.Version, + func() {}, + nil, + fmt.Errorf("app version must be one of %s", types.SupportedVersions), + }, + } + + for _, tc := range testCases { + suite.Run(tc.name, func() { + tokens = types.Tokens{types.Token{}} + + tc.malleate() + + createFunc := func() { + bz = transferkeeper.CreatePacketDataBytesFromVersion(tc.appVersion, "", "", "", tokens) + } + + expPanic := tc.expPanicErr != nil + if expPanic { + suite.Require().PanicsWithError(tc.expPanicErr.Error(), createFunc) + } else { + createFunc() + tc.expResult(bz) + } + }) + } +} diff --git a/modules/apps/transfer/types/denom_test.go b/modules/apps/transfer/types/denom_test.go index 7c583b53f1d..08919c4a3f3 100644 --- a/modules/apps/transfer/types/denom_test.go +++ b/modules/apps/transfer/types/denom_test.go @@ -118,3 +118,95 @@ func (suite *TypesTestSuite) TestPath() { }) } } + +func (suite *TypesTestSuite) TestDenomChainSource() { + testCases := []struct { + name string + denom types.Denom + sourcePort string + sourceChannel string + expReceiverChainIsSource bool + }{ + { + "sender chain is source: empty trace", + types.Denom{ + Base: "uatom", + Trace: []types.Trace{}, + }, + "transfer", + "channel-0", + false, + }, + { + "sender chain is source: nil trace", + types.Denom{ + Base: "uatom", + Trace: nil, + }, + "transfer", + "channel-0", + false, + }, + { + "sender chain is source: single trace", + types.Denom{ + Base: "ubtc", + Trace: []types.Trace{types.NewTrace("transfer", "channel-1")}, + }, + "transfer", + "channel-0", + false, + }, + { + "sender chain is source: swapped portID and channelID", + types.Denom{ + Base: "uatom", + Trace: []types.Trace{types.NewTrace("transfer", "channel-0")}, + }, + "channel-0", + "transfer", + false, + }, + { + "sender chain is source: multi-trace", + types.Denom{ + Base: "uatom", + Trace: []types.Trace{ + types.NewTrace("transfer", "channel-0"), + types.NewTrace("transfer", "channel-52"), + }, + }, + "transfer", + "channel-1", + false, + }, + { + "receiver chain is source: single trace", + types.Denom{ + Base: "factory/stars16da2uus9zrsy83h23ur42v3lglg5rmyrpqnju4/dust", + Trace: []types.Trace{types.NewTrace("transfer", "channel-0")}, + }, + "transfer", + "channel-0", + true, + }, + { + "receiver chain is source: multi-trace", + types.Denom{ + Base: "uatom", + Trace: []types.Trace{types.NewTrace("transfer", "channel-0"), types.NewTrace("transfer", "channel-52")}, + }, + "transfer", + "channel-0", + true, + }, + } + + for _, tc := range testCases { + tc := tc + suite.Run(tc.name, func() { + suite.Require().Equal(tc.expReceiverChainIsSource, tc.denom.ReceiverChainIsSource(tc.sourcePort, tc.sourceChannel)) + suite.Require().Equal(!tc.expReceiverChainIsSource, tc.denom.SenderChainIsSource(tc.sourcePort, tc.sourceChannel)) + }) + } +} diff --git a/modules/apps/transfer/types/events.go b/modules/apps/transfer/types/events.go index f310ba5d0d9..d982298c12b 100644 --- a/modules/apps/transfer/types/events.go +++ b/modules/apps/transfer/types/events.go @@ -6,17 +6,17 @@ const ( EventTypePacket = "fungible_token_packet" EventTypeTransfer = "ibc_transfer" EventTypeChannelClose = "channel_closed" - EventTypeDenomTrace = "denomination_trace" + EventTypeDenom = "denomination" AttributeKeySender = "sender" AttributeKeyReceiver = "receiver" AttributeKeyDenom = "denom" + AttributeKeyDenomHash = "denom_hash" AttributeKeyTokens = "tokens" AttributeKeyRefundReceiver = "refund_receiver" AttributeKeyRefundTokens = "refund_tokens" AttributeKeyAckSuccess = "success" AttributeKeyAck = "acknowledgement" AttributeKeyAckError = "error" - AttributeKeyTraceHash = "trace_hash" AttributeKeyMemo = "memo" ) diff --git a/modules/apps/transfer/types/msgs_test.go b/modules/apps/transfer/types/msgs_test.go index f05ad3cdc68..9c1d84ceea8 100644 --- a/modules/apps/transfer/types/msgs_test.go +++ b/modules/apps/transfer/types/msgs_test.go @@ -40,7 +40,8 @@ var ( receiver = sdk.AccAddress("testaddr2").String() emptyAddr string - coins = sdk.NewCoins(sdk.NewCoin("atom", sdkmath.NewInt(100))) + coin = ibctesting.TestCoin + coins = ibctesting.TestCoins ibcCoins = sdk.NewCoins(sdk.NewCoin("ibc/7F1D3FCF4AE79E1554D670D1AD949A9BA4E4A3C76C63093E17E446A46061A7A2", sdkmath.NewInt(100))) invalidIBCCoins = sdk.NewCoins(sdk.NewCoin("ibc/7F1D3FCF4AE79E1554", sdkmath.NewInt(100))) invalidDenomCoins = []sdk.Coin{{Denom: "0atom", Amount: sdkmath.NewInt(100)}} @@ -77,6 +78,7 @@ func TestMsgTransferValidation(t *testing.T) { {"multidenom: invalid ibc denom", types.NewMsgTransfer(validPort, validChannel, coins.Add(invalidIBCCoins...), sender, receiver, timeoutHeight, 0, ""), ibcerrors.ErrInvalidCoins}, {"multidenom: zero coins", types.NewMsgTransfer(validPort, validChannel, zeroCoins, sender, receiver, timeoutHeight, 0, ""), ibcerrors.ErrInvalidCoins}, {"multidenom: too many coins", types.NewMsgTransfer(validPort, validChannel, make([]sdk.Coin, types.MaximumTokensLength+1), sender, receiver, timeoutHeight, 0, ""), ibcerrors.ErrInvalidCoins}, + {"multidenom: both token and tokens are set", &types.MsgTransfer{validPort, validChannel, coin, sender, receiver, timeoutHeight, 0, "", coins}, ibcerrors.ErrInvalidCoins}, } for _, tc := range testCases { diff --git a/modules/apps/transfer/types/packet.go b/modules/apps/transfer/types/packet.go index 3eea8d5724d..e55b1d67ee5 100644 --- a/modules/apps/transfer/types/packet.go +++ b/modules/apps/transfer/types/packet.go @@ -49,7 +49,7 @@ func (ftpd FungibleTokenPacketData) ValidateBasic() error { if strings.TrimSpace(ftpd.Receiver) == "" { return errorsmod.Wrap(ibcerrors.ErrInvalidAddress, "receiver address cannot be blank") } - denom := ExtractDenomFromFullPath(ftpd.Denom) + denom := ExtractDenomFromPath(ftpd.Denom) return denom.Validate() } diff --git a/modules/apps/transfer/types/token.go b/modules/apps/transfer/types/token.go index 0b826929d0f..58a1eec402f 100644 --- a/modules/apps/transfer/types/token.go +++ b/modules/apps/transfer/types/token.go @@ -1,12 +1,13 @@ package types import ( - "strings" - errorsmod "cosmossdk.io/errors" sdkmath "cosmossdk.io/math" ) +// Tokens is a slice of Tokens +type Tokens []Token + // Validate validates a token denomination and amount. func (t Token) Validate() error { if err := t.Denom.Validate(); err != nil { @@ -24,25 +25,3 @@ func (t Token) Validate() error { return nil } - -// Tokens is a set of Token -type Tokens []Token - -// String prints out the tokens array as a string. -// If the array is empty, an empty string is returned -func (tokens Tokens) String() string { - if len(tokens) == 0 { - return "" - } else if len(tokens) == 1 { - return tokens[0].String() - } - - var out strings.Builder - for _, token := range tokens[:len(tokens)-1] { - out.WriteString(token.String()) // nolint:revive // no error returned by WriteString - out.WriteByte(',') //nolint:revive // no error returned by WriteByte - - } - out.WriteString(tokens[len(tokens)-1].String()) //nolint:revive - return out.String() -} diff --git a/modules/apps/transfer/types/token_test.go b/modules/apps/transfer/types/token_test.go index e7fdc15f982..85f529a2e50 100644 --- a/modules/apps/transfer/types/token_test.go +++ b/modules/apps/transfer/types/token_test.go @@ -149,104 +149,3 @@ func TestValidate(t *testing.T) { }) } } - -func TestTokens_String(t *testing.T) { - cases := []struct { - name string - input Tokens - expected string - }{ - { - "empty tokens", - Tokens{}, - "", - }, - { - "single token, no trace", - Tokens{ - Token{ - Denom: Denom{ - Base: "tree", - Trace: []Trace{}, - }, - Amount: "1", - }, - }, - `denom: amount:"1" `, - }, - { - "single token with trace", - Tokens{ - Token{ - Denom: Denom{ - Base: "tree", - Trace: []Trace{ - NewTrace("portid", "channelid"), - }, - }, - Amount: "1", - }, - }, - `denom: > amount:"1" `, - }, - { - "multiple tokens, no trace", - Tokens{ - Token{ - Denom: Denom{ - Base: "tree", - }, - Amount: "1", - }, - Token{ - Denom: Denom{ - Base: "gas", - }, - Amount: "2", - }, - Token{ - Denom: Denom{ - Base: "mineral", - }, - Amount: "3", - }, - }, - `denom: amount:"1" ,denom: amount:"2" ,denom: amount:"3" `, - }, - { - "multiple tokens, trace and no trace", - Tokens{ - Token{ - Denom: Denom{ - Base: "tree", - }, - Amount: "1", - }, - Token{ - Denom: Denom{ - Base: "gas", - Trace: []Trace{ - NewTrace("portid", "channelid"), - }, - }, - Amount: "2", - }, - Token{ - Denom: Denom{ - Base: "mineral", - Trace: []Trace{ - NewTrace("portid", "channelid"), - NewTrace("transfer", "channel-52"), - }, - }, - Amount: "3", - }, - }, - `denom: amount:"1" ,denom: > amount:"2" ,denom: trace: > amount:"3" `, - }, - } - - for _, tt := range cases { - require.Equal(t, tt.expected, tt.input.String()) - } -} diff --git a/modules/apps/transfer/types/trace.go b/modules/apps/transfer/types/trace.go index e695ca4c080..44e1cd95d41 100644 --- a/modules/apps/transfer/types/trace.go +++ b/modules/apps/transfer/types/trace.go @@ -41,9 +41,9 @@ func (t Trace) String() string { return fmt.Sprintf("%s/%s", t.PortId, t.ChannelId) } -// ExtractDenomFromFullPath returns the denom from the full path. +// ExtractDenomFromPath returns the denom from the full path. // Used to support v1 denoms. -func ExtractDenomFromFullPath(fullPath string) Denom { +func ExtractDenomFromPath(fullPath string) Denom { denomSplit := strings.Split(fullPath, "/") if denomSplit[0] == fullPath { diff --git a/modules/apps/transfer/types/trace_test.go b/modules/apps/transfer/types/trace_test.go index 7865a732b9b..7d9ca914b6a 100644 --- a/modules/apps/transfer/types/trace_test.go +++ b/modules/apps/transfer/types/trace_test.go @@ -38,7 +38,7 @@ func TestValidateIBCDenom(t *testing.T) { } } -func TestExtractDenomFromFullPath(t *testing.T) { +func TestExtractDenomFromPath(t *testing.T) { testCases := []struct { name string fullPath string @@ -68,7 +68,7 @@ func TestExtractDenomFromFullPath(t *testing.T) { for _, tc := range testCases { tc := tc - denom := types.ExtractDenomFromFullPath(tc.fullPath) + denom := types.ExtractDenomFromPath(tc.fullPath) require.Equal(t, tc.expDenom, denom, tc.name) } } diff --git a/modules/apps/transfer/types/transfer_authorization.go b/modules/apps/transfer/types/transfer_authorization.go index 333519a86a2..01bcafb48c6 100644 --- a/modules/apps/transfer/types/transfer_authorization.go +++ b/modules/apps/transfer/types/transfer_authorization.go @@ -52,14 +52,13 @@ func (a TransferAuthorization) Accept(goCtx context.Context, msg proto.Message) return authz.AcceptResponse{}, errorsmod.Wrapf(ibcerrors.ErrNotFound, "requested port and channel allocation does not exist") } - allocation := a.Allocations[index] ctx := sdk.UnwrapSDKContext(goCtx) - if !isAllowedAddress(ctx, msgTransfer.Receiver, allocation.AllowList) { + if !isAllowedAddress(ctx, msgTransfer.Receiver, a.Allocations[index].AllowList) { return authz.AcceptResponse{}, errorsmod.Wrap(ibcerrors.ErrInvalidAddress, "not allowed receiver address for transfer") } - err := validateMemo(ctx, msgTransfer.Memo, allocation.AllowedPacketData) + err := validateMemo(ctx, msgTransfer.Memo, a.Allocations[index].AllowedPacketData) if err != nil { return authz.AcceptResponse{}, err } @@ -71,7 +70,7 @@ func (a TransferAuthorization) Accept(goCtx context.Context, msg proto.Message) for _, coin := range msgTransfer.GetCoins() { // If the spend limit is set to the MaxUint256 sentinel value, do not subtract the amount from the spend limit. // if there is no unlimited spend, then we need to subtract the amount from the spend limit to get the limit left - if allocation.SpendLimit.AmountOf(coin.Denom).Equal(UnboundedSpendLimit()) { + if a.Allocations[index].SpendLimit.AmountOf(coin.Denom).Equal(UnboundedSpendLimit()) { continue } @@ -82,16 +81,13 @@ func (a TransferAuthorization) Accept(goCtx context.Context, msg proto.Message) allocationModified = true - a.Allocations[index] = Allocation{ - SourcePort: allocation.SourcePort, - SourceChannel: allocation.SourceChannel, - SpendLimit: limitLeft, - AllowList: allocation.AllowList, - AllowedPacketData: allocation.AllowedPacketData, - } + // modify the spend limit with the reduced amount. + a.Allocations[index].SpendLimit = limitLeft } // if the spend limit is zero of the associated allocation then we delete it. + // NOTE: SpendLimit is an array of coins, with each one representing the remaining spend limit for an + // individual denomination. if a.Allocations[index].SpendLimit.IsZero() { a.Allocations = append(a.Allocations[:index], a.Allocations[index+1:]...) } diff --git a/modules/apps/transfer/types/transfer_authorization_test.go b/modules/apps/transfer/types/transfer_authorization_test.go index c02be46aa03..a6a02d41369 100644 --- a/modules/apps/transfer/types/transfer_authorization_test.go +++ b/modules/apps/transfer/types/transfer_authorization_test.go @@ -9,6 +9,7 @@ import ( "github.com/cosmos/cosmos-sdk/x/authz" "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types" + ibcerrors "github.com/cosmos/ibc-go/v8/modules/core/errors" ibctesting "github.com/cosmos/ibc-go/v8/testing" "github.com/cosmos/ibc-go/v8/testing/mock" ) @@ -71,47 +72,6 @@ func (suite *TypesTestSuite) TestTransferAuthorizationAccept() { suite.Require().Nil(res.Updated) }, }, - { - "success: with multiple allocations and multidenom transfer", - func() { - coins := sdk.NewCoins( - ibctesting.TestCoin, - sdk.NewCoin("atom", sdkmath.NewInt(100)), - sdk.NewCoin("osmo", sdkmath.NewInt(100)), - ) - - allocation := types.Allocation{ - SourcePort: ibctesting.MockPort, - SourceChannel: "channel-9", - SpendLimit: coins, - } - - transferAuthz.Allocations = append(transferAuthz.Allocations, allocation) - - msgTransfer = types.NewMsgTransfer( - ibctesting.MockPort, - "channel-9", - coins, - suite.chainA.SenderAccount.GetAddress().String(), - ibctesting.TestAccAddress, - suite.chainB.GetTimeoutHeight(), - 0, - "", - ) - }, - func(res authz.AcceptResponse, err error) { - suite.Require().NoError(err) - - suite.Require().True(res.Accept) - suite.Require().False(res.Delete) - - updatedAuthz, ok := res.Updated.(*types.TransferAuthorization) - suite.Require().True(ok) - - // assert spent spendlimits are removed from the list - suite.Require().Len(updatedAuthz.Allocations, 1) - }, - }, { "success: with unlimited spend limit of max uint256", func() { @@ -247,6 +207,117 @@ func (suite *TypesTestSuite) TestTransferAuthorizationAccept() { suite.Require().Error(err) }, }, + { + "success: with multiple allocations and multidenom transfer", + func() { + coins := sdk.NewCoins( + ibctesting.TestCoin, + sdk.NewCoin("atom", sdkmath.NewInt(100)), + sdk.NewCoin("osmo", sdkmath.NewInt(100)), + ) + + transferAuthz.Allocations = append(transferAuthz.Allocations, types.Allocation{ + SourcePort: ibctesting.MockPort, + SourceChannel: "channel-9", + SpendLimit: coins, + }) + + msgTransfer = types.NewMsgTransfer( + ibctesting.MockPort, + "channel-9", + coins, + suite.chainA.SenderAccount.GetAddress().String(), + ibctesting.TestAccAddress, + suite.chainB.GetTimeoutHeight(), + 0, + "", + ) + }, + func(res authz.AcceptResponse, err error) { + suite.Require().NoError(err) + + suite.Require().True(res.Accept) + suite.Require().False(res.Delete) + + updatedAuthz, ok := res.Updated.(*types.TransferAuthorization) + suite.Require().True(ok) + + // assert spent spendlimits are removed from the list + suite.Require().Len(updatedAuthz.Allocations, 1) + }, + }, + { + "failure: multidenom transfer spend limit is exceeded", + func() { + coins := sdk.NewCoins( + ibctesting.TestCoin, + sdk.NewCoin("atom", sdkmath.NewInt(100)), + sdk.NewCoin("osmo", sdkmath.NewInt(100)), + ) + + transferAuthz.Allocations = append(transferAuthz.Allocations, types.Allocation{ + SourcePort: ibctesting.MockPort, + SourceChannel: "channel-9", + SpendLimit: coins, + }) + + // spending more than the spend limit + coins = coins.Add(sdk.NewCoin("atom", sdkmath.NewInt(1))) + + msgTransfer = types.NewMsgTransfer( + ibctesting.MockPort, + "channel-9", + coins, + suite.chainA.SenderAccount.GetAddress().String(), + ibctesting.TestAccAddress, + suite.chainB.GetTimeoutHeight(), + 0, + "", + ) + }, + func(res authz.AcceptResponse, err error) { + suite.Require().ErrorIs(err, ibcerrors.ErrInsufficientFunds) + suite.Require().False(res.Accept) + suite.Require().False(res.Delete) + suite.Require().Nil(res.Updated) + }, + }, + { + "failure: multidenom transfer denom not in allocation", + func() { + coins := sdk.NewCoins( + ibctesting.TestCoin, + sdk.NewCoin("atom", sdkmath.NewInt(100)), + sdk.NewCoin("osmo", sdkmath.NewInt(100)), + ) + + transferAuthz.Allocations = append(transferAuthz.Allocations, types.Allocation{ + SourcePort: ibctesting.MockPort, + SourceChannel: "channel-9", + SpendLimit: coins, + }) + + // spend a coin not in the allocation + coins = coins.Add(sdk.NewCoin("newdenom", sdkmath.NewInt(1))) + + msgTransfer = types.NewMsgTransfer( + ibctesting.MockPort, + "channel-9", + coins, + suite.chainA.SenderAccount.GetAddress().String(), + ibctesting.TestAccAddress, + suite.chainB.GetTimeoutHeight(), + 0, + "", + ) + }, + func(res authz.AcceptResponse, err error) { + suite.Require().ErrorIs(err, ibcerrors.ErrInsufficientFunds) + suite.Require().False(res.Accept) + suite.Require().False(res.Delete) + suite.Require().Nil(res.Updated) + }, + }, } for _, tc := range testCases { diff --git a/modules/apps/transfer/types/tx.pb.go b/modules/apps/transfer/types/tx.pb.go index 860b32b2549..b6ad9e9b57a 100644 --- a/modules/apps/transfer/types/tx.pb.go +++ b/modules/apps/transfer/types/tx.pb.go @@ -40,8 +40,8 @@ type MsgTransfer struct { SourcePort string `protobuf:"bytes,1,opt,name=source_port,json=sourcePort,proto3" json:"source_port,omitempty"` // the channel by which the packet will be sent SourceChannel string `protobuf:"bytes,2,opt,name=source_channel,json=sourceChannel,proto3" json:"source_channel,omitempty"` - // the tokens to be transferred - Token types.Coin `protobuf:"bytes,3,opt,name=token,proto3" json:"token"` + // the token to be transferred. this field has been replaced by the tokens field. + Token types.Coin `protobuf:"bytes,3,opt,name=token,proto3" json:"token"` // Deprecated: Do not use. // the sender address Sender string `protobuf:"bytes,4,opt,name=sender,proto3" json:"sender,omitempty"` // the recipient address on the destination chain @@ -223,47 +223,47 @@ func init() { } var fileDescriptor_7401ed9bed2f8e09 = []byte{ - // 630 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x54, 0xb1, 0x6e, 0x13, 0x4d, - 0x10, 0xf6, 0xfd, 0x76, 0xfc, 0x27, 0x6b, 0x92, 0x90, 0x05, 0x25, 0x17, 0x0b, 0x9d, 0x2d, 0x8b, - 0x48, 0xc1, 0x51, 0x76, 0xe5, 0x20, 0x14, 0x64, 0x51, 0x39, 0x0d, 0x05, 0x91, 0x82, 0x15, 0x1a, - 0x9a, 0xe8, 0x6e, 0x3d, 0x9c, 0x57, 0xf1, 0xed, 0x1e, 0xb7, 0x6b, 0x0b, 0x1a, 0x84, 0xa8, 0x10, - 0x15, 0x8f, 0x40, 0x49, 0x99, 0x27, 0xa0, 0x4e, 0x99, 0x92, 0x0a, 0xa1, 0xa4, 0x48, 0xc3, 0x43, - 0xa0, 0xdd, 0x5b, 0x9b, 0x83, 0x22, 0x84, 0xc6, 0xde, 0x99, 0xf9, 0xe6, 0x9b, 0xf9, 0x66, 0x3c, - 0x46, 0x1b, 0x3c, 0x62, 0x34, 0x4c, 0xd3, 0x11, 0x67, 0xa1, 0xe6, 0x52, 0x28, 0xaa, 0xb3, 0x50, - 0xa8, 0x17, 0x90, 0xd1, 0x49, 0x87, 0xea, 0x57, 0x24, 0xcd, 0xa4, 0x96, 0xf8, 0x0e, 0x8f, 0x18, - 0x29, 0xc2, 0xc8, 0x14, 0x46, 0x26, 0x9d, 0xfa, 0x4a, 0x98, 0x70, 0x21, 0xa9, 0xfd, 0xcc, 0x13, - 0xea, 0xb7, 0x63, 0x19, 0x4b, 0xfb, 0xa4, 0xe6, 0xe5, 0xbc, 0x6b, 0x4c, 0xaa, 0x44, 0x2a, 0x9a, - 0xa8, 0xd8, 0xd0, 0x27, 0x2a, 0x76, 0x81, 0xc0, 0x05, 0xa2, 0x50, 0x01, 0x9d, 0x74, 0x22, 0xd0, - 0x61, 0x87, 0x32, 0xc9, 0x85, 0x8b, 0x37, 0x4c, 0x9b, 0x4c, 0x66, 0x40, 0xd9, 0x88, 0x83, 0xd0, - 0x26, 0x3b, 0x7f, 0x39, 0xc0, 0xd6, 0xd5, 0x3a, 0xa6, 0xcd, 0x5a, 0x70, 0xeb, 0x4b, 0x19, 0xd5, - 0xf6, 0x55, 0x7c, 0xe8, 0xbc, 0xb8, 0x81, 0x6a, 0x4a, 0x8e, 0x33, 0x06, 0x47, 0xa9, 0xcc, 0xb4, - 0xef, 0x35, 0xbd, 0xcd, 0x85, 0x3e, 0xca, 0x5d, 0x07, 0x32, 0xd3, 0x78, 0x03, 0x2d, 0x39, 0x00, - 0x1b, 0x86, 0x42, 0xc0, 0xc8, 0xff, 0xcf, 0x62, 0x16, 0x73, 0xef, 0x5e, 0xee, 0xc4, 0x5d, 0x34, - 0xa7, 0xe5, 0x31, 0x08, 0xbf, 0xdc, 0xf4, 0x36, 0x6b, 0x3b, 0xeb, 0x24, 0x57, 0x45, 0x8c, 0x2a, - 0xe2, 0x54, 0x91, 0x3d, 0xc9, 0x45, 0x6f, 0xe1, 0xf4, 0x5b, 0xa3, 0xf4, 0xf9, 0xf2, 0xa4, 0xed, - 0xf5, 0xf3, 0x14, 0xbc, 0x8a, 0xaa, 0x0a, 0xc4, 0x00, 0x32, 0xbf, 0x62, 0xa9, 0x9d, 0x85, 0xeb, - 0x68, 0x3e, 0x03, 0x06, 0x7c, 0x02, 0x99, 0x3f, 0x67, 0x23, 0x33, 0x1b, 0x3f, 0x41, 0x4b, 0x9a, - 0x27, 0x20, 0xc7, 0xfa, 0x68, 0x08, 0x3c, 0x1e, 0x6a, 0xbf, 0x6a, 0x0b, 0xd7, 0x89, 0x59, 0x97, - 0x19, 0x17, 0x71, 0x43, 0x9a, 0x74, 0xc8, 0x63, 0x8b, 0x28, 0x56, 0x5e, 0x74, 0xc9, 0x79, 0x04, - 0x6f, 0xa1, 0x95, 0x29, 0x9b, 0xf9, 0x56, 0x3a, 0x4c, 0x52, 0xff, 0xff, 0xa6, 0xb7, 0x59, 0xe9, - 0xdf, 0x74, 0x81, 0xc3, 0xa9, 0x1f, 0x63, 0x54, 0x49, 0x20, 0x91, 0xfe, 0xbc, 0x6d, 0xc9, 0xbe, - 0xf1, 0x23, 0x54, 0xb5, 0x5a, 0x94, 0xbf, 0xd0, 0x2c, 0x5f, 0x5b, 0xbf, 0xcb, 0xe9, 0xb6, 0xdf, - 0x7f, 0x6a, 0x94, 0xde, 0x5d, 0x9e, 0xb4, 0x9d, 0xf2, 0x0f, 0x97, 0x27, 0xed, 0xd5, 0x9c, 0x60, - 0x5b, 0x0d, 0x8e, 0x69, 0x61, 0x61, 0xad, 0x5d, 0x74, 0xab, 0x60, 0xf6, 0x41, 0xa5, 0x52, 0x28, - 0x30, 0xb3, 0x52, 0xf0, 0x72, 0x0c, 0x82, 0x81, 0x5d, 0x62, 0xa5, 0x3f, 0xb3, 0xbb, 0x15, 0x43, - 0xdf, 0x7a, 0x83, 0x96, 0xf7, 0x55, 0xfc, 0x2c, 0x1d, 0x84, 0x1a, 0x0e, 0xc2, 0x2c, 0x4c, 0x94, - 0x1d, 0x3c, 0x8f, 0x05, 0x64, 0x6e, 0xef, 0xce, 0xc2, 0x3d, 0x54, 0x4d, 0x2d, 0xc2, 0xee, 0xba, - 0xb6, 0x73, 0x97, 0x5c, 0x75, 0x03, 0x24, 0x67, 0xeb, 0x55, 0x8c, 0xb0, 0xbe, 0xcb, 0xec, 0x2e, - 0xff, 0xd2, 0x64, 0x49, 0x5b, 0xeb, 0x68, 0xed, 0x8f, 0xfa, 0xd3, 0xe6, 0x77, 0x7e, 0x78, 0xa8, - 0xbc, 0xaf, 0x62, 0x3c, 0x44, 0xf3, 0xb3, 0x1f, 0xe6, 0xbd, 0xab, 0x6b, 0x16, 0x66, 0x50, 0xef, - 0x5c, 0x1b, 0x3a, 0x1b, 0x97, 0x46, 0x37, 0x7e, 0x9b, 0xc4, 0xf6, 0x5f, 0x29, 0x8a, 0xf0, 0xfa, - 0x83, 0x7f, 0x82, 0x4f, 0xab, 0xd6, 0xe7, 0xde, 0x9a, 0xb5, 0xf7, 0x9e, 0x9e, 0x9e, 0x07, 0xde, - 0xd9, 0x79, 0xe0, 0x7d, 0x3f, 0x0f, 0xbc, 0x8f, 0x17, 0x41, 0xe9, 0xec, 0x22, 0x28, 0x7d, 0xbd, - 0x08, 0x4a, 0xcf, 0x77, 0x63, 0xae, 0x87, 0xe3, 0x88, 0x30, 0x99, 0x50, 0xf7, 0xb7, 0xc0, 0x23, - 0xb6, 0x1d, 0x4b, 0x3a, 0x79, 0x48, 0x13, 0x39, 0x18, 0x8f, 0x40, 0x99, 0x53, 0x2f, 0x9c, 0xb8, - 0x7e, 0x9d, 0x82, 0x8a, 0xaa, 0xf6, 0xba, 0xef, 0xff, 0x0c, 0x00, 0x00, 0xff, 0xff, 0x29, 0xee, - 0x20, 0x91, 0xd4, 0x04, 0x00, 0x00, + // 634 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x54, 0x3f, 0x6f, 0xd3, 0x40, + 0x14, 0x8f, 0x49, 0x1a, 0xda, 0x0b, 0x6d, 0xa9, 0x41, 0xad, 0x6b, 0x21, 0x27, 0x8a, 0xa8, 0x54, + 0x52, 0xf5, 0x4e, 0x29, 0x42, 0x45, 0x15, 0x53, 0xba, 0x30, 0x50, 0xa9, 0x58, 0x65, 0x61, 0xa9, + 0xec, 0xcb, 0xc3, 0x39, 0x35, 0xbe, 0x33, 0xbe, 0x4b, 0x04, 0x0b, 0x42, 0x4c, 0x88, 0x89, 0x8f, + 0xc0, 0xc8, 0xd8, 0x9d, 0x2f, 0xd0, 0xb1, 0x23, 0x13, 0x42, 0xed, 0xd0, 0x85, 0x0f, 0x81, 0xee, + 0x7c, 0x0e, 0x81, 0x21, 0xc0, 0x92, 0xdc, 0x7b, 0xef, 0xf7, 0xfe, 0xfc, 0x7e, 0xef, 0xce, 0x68, + 0x83, 0xc5, 0x94, 0x44, 0x59, 0x36, 0x64, 0x34, 0x52, 0x4c, 0x70, 0x49, 0x54, 0x1e, 0x71, 0xf9, + 0x02, 0x72, 0x32, 0xee, 0x12, 0xf5, 0x0a, 0x67, 0xb9, 0x50, 0xc2, 0xbd, 0xc3, 0x62, 0x8a, 0xa7, + 0x61, 0xb8, 0x84, 0xe1, 0x71, 0xd7, 0x5f, 0x89, 0x52, 0xc6, 0x05, 0x31, 0xbf, 0x45, 0x82, 0x7f, + 0x3b, 0x11, 0x89, 0x30, 0x47, 0xa2, 0x4f, 0xd6, 0xbb, 0x46, 0x85, 0x4c, 0x85, 0x24, 0xa9, 0x4c, + 0x74, 0xf9, 0x54, 0x26, 0x36, 0x10, 0xd8, 0x40, 0x1c, 0x49, 0x20, 0xe3, 0x6e, 0x0c, 0x2a, 0xea, + 0x12, 0x2a, 0x18, 0xb7, 0xf1, 0xa6, 0x1e, 0x93, 0x8a, 0x1c, 0x08, 0x1d, 0x32, 0xe0, 0x4a, 0x67, + 0x17, 0x27, 0x0b, 0xd8, 0x9a, 0xcd, 0xa3, 0x1c, 0xd6, 0x80, 0xdb, 0x5f, 0xaa, 0xa8, 0x71, 0x20, + 0x93, 0x23, 0xeb, 0x75, 0x9b, 0xa8, 0x21, 0xc5, 0x28, 0xa7, 0x70, 0x9c, 0x89, 0x5c, 0x79, 0x4e, + 0xcb, 0xd9, 0x5c, 0x08, 0x51, 0xe1, 0x3a, 0x14, 0xb9, 0x72, 0x37, 0xd0, 0x92, 0x05, 0xd0, 0x41, + 0xc4, 0x39, 0x0c, 0xbd, 0x6b, 0x06, 0xb3, 0x58, 0x78, 0xf7, 0x0b, 0xa7, 0xfb, 0x08, 0xcd, 0x29, + 0x71, 0x02, 0xdc, 0xab, 0xb6, 0x9c, 0xcd, 0xc6, 0xce, 0x3a, 0x2e, 0x58, 0x61, 0xcd, 0x0a, 0x5b, + 0x56, 0x78, 0x5f, 0x30, 0xde, 0x6b, 0x9c, 0x7d, 0x6b, 0x56, 0x3e, 0x5f, 0x9d, 0x76, 0x1c, 0xcf, + 0x09, 0x8b, 0x24, 0x77, 0x15, 0xd5, 0x25, 0xf0, 0x3e, 0xe4, 0x5e, 0xcd, 0x14, 0xb7, 0x96, 0xeb, + 0xa3, 0xf9, 0x1c, 0x28, 0xb0, 0x31, 0xe4, 0xde, 0x9c, 0x89, 0x4c, 0x6c, 0xf7, 0x09, 0x5a, 0x52, + 0x2c, 0x05, 0x31, 0x52, 0xc7, 0x03, 0x60, 0xc9, 0x40, 0x79, 0x75, 0xd3, 0xda, 0xc7, 0x7a, 0x61, + 0x5a, 0x30, 0x6c, 0x65, 0x1a, 0x77, 0xf1, 0x63, 0x83, 0xe8, 0x2d, 0x4c, 0x7a, 0x87, 0x8b, 0x36, + 0xb9, 0x88, 0xb8, 0x5b, 0x68, 0xa5, 0xac, 0xa6, 0xff, 0xa5, 0x8a, 0xd2, 0xcc, 0xbb, 0xde, 0x72, + 0x36, 0x6b, 0xe1, 0x4d, 0x1b, 0x38, 0x2a, 0xfd, 0xae, 0x8b, 0x6a, 0x29, 0xa4, 0xc2, 0x9b, 0x37, + 0x23, 0x99, 0xb3, 0xbb, 0x8b, 0xea, 0x86, 0x8b, 0xf4, 0x16, 0x5a, 0xd5, 0xd9, 0x0a, 0xd4, 0xf4, + 0x14, 0xa1, 0x85, 0xef, 0x75, 0xde, 0x7f, 0x6a, 0x56, 0xde, 0x5d, 0x9d, 0x76, 0x2c, 0xe9, 0x0f, + 0x57, 0xa7, 0x9d, 0xd5, 0x22, 0x77, 0x5b, 0xf6, 0x4f, 0xc8, 0xd4, 0xb6, 0xda, 0xbb, 0xe8, 0xd6, + 0x94, 0x19, 0x82, 0xcc, 0x04, 0x97, 0xa0, 0x65, 0x92, 0xf0, 0x72, 0x04, 0x9c, 0x82, 0xd9, 0x60, + 0x2d, 0x9c, 0xd8, 0x7b, 0x35, 0x5d, 0xbe, 0xfd, 0x06, 0x2d, 0x1f, 0xc8, 0xe4, 0x59, 0xd6, 0x8f, + 0x14, 0x1c, 0x46, 0x79, 0x94, 0x4a, 0xa3, 0x39, 0x4b, 0x38, 0xe4, 0x76, 0xe9, 0xd6, 0x72, 0x7b, + 0xa8, 0x9e, 0x19, 0x84, 0x59, 0x74, 0x63, 0xe7, 0x2e, 0x9e, 0xf5, 0x00, 0x70, 0x51, 0xad, 0xe4, + 0x54, 0x64, 0xee, 0x2d, 0xff, 0xe2, 0x64, 0x8a, 0xb6, 0xd7, 0xd1, 0xda, 0x1f, 0xfd, 0xcb, 0xe1, + 0x77, 0x7e, 0x38, 0xa8, 0x7a, 0x20, 0x13, 0x77, 0x80, 0xe6, 0x27, 0xb7, 0xf2, 0xde, 0xec, 0x9e, + 0x53, 0x1a, 0xf8, 0xdd, 0x7f, 0x86, 0x4e, 0xe4, 0x52, 0xe8, 0xc6, 0x6f, 0x4a, 0x6c, 0xff, 0xb5, + 0xc4, 0x34, 0xdc, 0x7f, 0xf0, 0x5f, 0xf0, 0xb2, 0xab, 0x3f, 0xf7, 0x56, 0xdf, 0xbb, 0xde, 0xd3, + 0xb3, 0x8b, 0xc0, 0x39, 0xbf, 0x08, 0x9c, 0xef, 0x17, 0x81, 0xf3, 0xf1, 0x32, 0xa8, 0x9c, 0x5f, + 0x06, 0x95, 0xaf, 0x97, 0x41, 0xe5, 0xf9, 0x6e, 0xc2, 0xd4, 0x60, 0x14, 0x63, 0x2a, 0x52, 0x62, + 0xbf, 0x09, 0x2c, 0xa6, 0xdb, 0x89, 0x20, 0xe3, 0x87, 0x24, 0x15, 0xfd, 0xd1, 0x10, 0xa4, 0x7e, + 0xe7, 0x53, 0xef, 0x5b, 0xbd, 0xce, 0x40, 0xc6, 0x75, 0xf3, 0xb4, 0xef, 0xff, 0x0c, 0x00, 0x00, + 0xff, 0xff, 0xfe, 0xf1, 0xb5, 0xf1, 0xd1, 0x04, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. diff --git a/modules/core/02-client/abci.go b/modules/core/02-client/abci.go index 44dfca138b2..c8d36b414ec 100644 --- a/modules/core/02-client/abci.go +++ b/modules/core/02-client/abci.go @@ -4,6 +4,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/ibc-go/v8/modules/core/02-client/keeper" + "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" "github.com/cosmos/ibc-go/v8/modules/core/exported" ibctm "github.com/cosmos/ibc-go/v8/modules/light-clients/07-tendermint" ) @@ -24,7 +25,7 @@ func BeginBlocker(ctx sdk.Context, k *keeper.Keeper) { Timestamp: ctx.BlockTime(), NextValidatorsHash: ctx.BlockHeader().NextValidatorsHash, } - bz := k.MustMarshalConsensusState(upgradedConsState) + bz := types.MustMarshalConsensusState(k.Codec(), upgradedConsState) // SetUpgradedConsensusState always returns nil, hence the blank here. _ = k.SetUpgradedConsensusState(ctx, plan.Height, bz) diff --git a/modules/core/02-client/keeper/encoding.go b/modules/core/02-client/keeper/encoding.go deleted file mode 100644 index 19a927165e2..00000000000 --- a/modules/core/02-client/keeper/encoding.go +++ /dev/null @@ -1,42 +0,0 @@ -package keeper - -import ( - "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" - "github.com/cosmos/ibc-go/v8/modules/core/exported" -) - -// UnmarshalClientState attempts to decode and return an ClientState object from -// raw encoded bytes. -func (k *Keeper) UnmarshalClientState(bz []byte) (exported.ClientState, error) { - return types.UnmarshalClientState(k.cdc, bz) -} - -// MustUnmarshalClientState attempts to decode and return an ClientState object from -// raw encoded bytes. It panics on error. -func (k *Keeper) MustUnmarshalClientState(bz []byte) exported.ClientState { - return types.MustUnmarshalClientState(k.cdc, bz) -} - -// UnmarshalConsensusState attempts to decode and return an ConsensusState object from -// raw encoded bytes. -func (k *Keeper) UnmarshalConsensusState(bz []byte) (exported.ConsensusState, error) { - return types.UnmarshalConsensusState(k.cdc, bz) -} - -// MustUnmarshalConsensusState attempts to decode and return an ConsensusState object from -// raw encoded bytes. It panics on error. -func (k *Keeper) MustUnmarshalConsensusState(bz []byte) exported.ConsensusState { - return types.MustUnmarshalConsensusState(k.cdc, bz) -} - -// MustMarshalClientState attempts to encode an ClientState object and returns the -// raw encoded bytes. It panics on error. -func (k *Keeper) MustMarshalClientState(clientState exported.ClientState) []byte { - return types.MustMarshalClientState(k.cdc, clientState) -} - -// MustMarshalConsensusState attempts to encode an ConsensusState object and returns the -// raw encoded bytes. It panics on error. -func (k *Keeper) MustMarshalConsensusState(consensusState exported.ConsensusState) []byte { - return types.MustMarshalConsensusState(k.cdc, consensusState) -} diff --git a/modules/core/02-client/keeper/grpc_query.go b/modules/core/02-client/keeper/grpc_query.go index 41c52f7c7d6..cd95a83588d 100644 --- a/modules/core/02-client/keeper/grpc_query.go +++ b/modules/core/02-client/keeper/grpc_query.go @@ -73,7 +73,7 @@ func (k *Keeper) ClientStates(c context.Context, req *types.QueryClientStatesReq return false, nil } - clientState, err := k.UnmarshalClientState(value) + clientState, err := types.UnmarshalClientState(k.cdc, value) if err != nil { return false, err } @@ -172,7 +172,7 @@ func (k *Keeper) ConsensusStates(c context.Context, req *types.QueryConsensusSta return false, err } - consensusState, err := k.UnmarshalConsensusState(value) + consensusState, err := types.UnmarshalConsensusState(k.cdc, value) if err != nil { return false, err } diff --git a/modules/core/02-client/keeper/keeper.go b/modules/core/02-client/keeper/keeper.go index f65f76746a7..d30d50554e4 100644 --- a/modules/core/02-client/keeper/keeper.go +++ b/modules/core/02-client/keeper/keeper.go @@ -48,6 +48,11 @@ func NewKeeper(cdc codec.BinaryCodec, key storetypes.StoreKey, legacySubspace ty } } +// Codec returns the IBC Client module codec. +func (k *Keeper) Codec() codec.BinaryCodec { + return k.cdc +} + // Logger returns a module-specific logger. func (Keeper) Logger(ctx sdk.Context) log.Logger { return ctx.Logger().With("module", "x/"+exported.ModuleName+"/"+types.SubModuleName) @@ -110,14 +115,14 @@ func (k *Keeper) GetClientState(ctx sdk.Context, clientID string) (exported.Clie return nil, false } - clientState := k.MustUnmarshalClientState(bz) + clientState := types.MustUnmarshalClientState(k.cdc, bz) return clientState, true } // SetClientState sets a particular Client to the store func (k *Keeper) SetClientState(ctx sdk.Context, clientID string, clientState exported.ClientState) { store := k.ClientStore(ctx, clientID) - store.Set(host.ClientStateKey(), k.MustMarshalClientState(clientState)) + store.Set(host.ClientStateKey(), types.MustMarshalClientState(k.cdc, clientState)) } // GetClientConsensusState gets the stored consensus state from a client at a given height. @@ -128,7 +133,7 @@ func (k *Keeper) GetClientConsensusState(ctx sdk.Context, clientID string, heigh return nil, false } - consensusState := k.MustUnmarshalConsensusState(bz) + consensusState := types.MustUnmarshalConsensusState(k.cdc, bz) return consensusState, true } @@ -136,7 +141,7 @@ func (k *Keeper) GetClientConsensusState(ctx sdk.Context, clientID string, heigh // height func (k *Keeper) SetClientConsensusState(ctx sdk.Context, clientID string, height exported.Height, consensusState exported.ConsensusState) { store := k.ClientStore(ctx, clientID) - store.Set(host.ConsensusStateKey(height), k.MustMarshalConsensusState(consensusState)) + store.Set(host.ConsensusStateKey(height), types.MustMarshalConsensusState(k.cdc, consensusState)) } // GetNextClientSequence gets the next client sequence from the store. @@ -173,7 +178,7 @@ func (k *Keeper) IterateConsensusStates(ctx sdk.Context, cb func(clientID string } clientID := keySplit[1] height := types.MustParseHeight(keySplit[3]) - consensusState := k.MustUnmarshalConsensusState(iterator.Value()) + consensusState := types.MustUnmarshalConsensusState(k.cdc, iterator.Value()) consensusStateWithHeight := types.NewConsensusStateWithHeight(height, consensusState) @@ -359,7 +364,7 @@ func (k *Keeper) IterateClientStates(ctx sdk.Context, storePrefix []byte, cb fun } clientID := host.MustParseClientStatePath(path) - clientState := k.MustUnmarshalClientState(iterator.Value()) + clientState := types.MustUnmarshalClientState(k.cdc, iterator.Value()) if cb(clientID, clientState) { break diff --git a/modules/core/02-client/simulation/decoder.go b/modules/core/02-client/simulation/decoder.go index 0fd8baeb12b..58b062527b9 100644 --- a/modules/core/02-client/simulation/decoder.go +++ b/modules/core/02-client/simulation/decoder.go @@ -4,33 +4,25 @@ import ( "bytes" "fmt" + "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/types/kv" - "github.com/cosmos/ibc-go/v8/modules/core/02-client/keeper" + "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" host "github.com/cosmos/ibc-go/v8/modules/core/24-host" - "github.com/cosmos/ibc-go/v8/modules/core/exported" ) -var _ ClientUnmarshaler = (*keeper.Keeper)(nil) - -// ClientUnmarshaler defines an interface for unmarshaling ICS02 interfaces. -type ClientUnmarshaler interface { - MustUnmarshalClientState([]byte) exported.ClientState - MustUnmarshalConsensusState([]byte) exported.ConsensusState -} - // NewDecodeStore returns a decoder function closure that unmarshals the KVPair's // Value to the corresponding client type. -func NewDecodeStore(cdc ClientUnmarshaler, kvA, kvB kv.Pair) (string, bool) { +func NewDecodeStore(cdc codec.BinaryCodec, kvA, kvB kv.Pair) (string, bool) { switch { case bytes.HasPrefix(kvA.Key, host.KeyClientStorePrefix) && bytes.HasSuffix(kvA.Key, host.ClientStateKey()): - clientStateA := cdc.MustUnmarshalClientState(kvA.Value) - clientStateB := cdc.MustUnmarshalClientState(kvB.Value) + clientStateA := types.MustUnmarshalClientState(cdc, kvA.Value) + clientStateB := types.MustUnmarshalClientState(cdc, kvB.Value) return fmt.Sprintf("ClientState A: %v\nClientState B: %v", clientStateA, clientStateB), true case bytes.HasPrefix(kvA.Key, host.KeyClientStorePrefix) && bytes.Contains(kvA.Key, []byte(host.KeyConsensusStatePrefix)): - consensusStateA := cdc.MustUnmarshalConsensusState(kvA.Value) - consensusStateB := cdc.MustUnmarshalConsensusState(kvB.Value) + consensusStateA := types.MustUnmarshalConsensusState(cdc, kvA.Value) + consensusStateB := types.MustUnmarshalConsensusState(cdc, kvB.Value) return fmt.Sprintf("ConsensusState A: %v\nConsensusState B: %v", consensusStateA, consensusStateB), true default: diff --git a/modules/core/02-client/simulation/decoder_test.go b/modules/core/02-client/simulation/decoder_test.go index f84e12b9325..c727eaceb67 100644 --- a/modules/core/02-client/simulation/decoder_test.go +++ b/modules/core/02-client/simulation/decoder_test.go @@ -34,11 +34,11 @@ func TestDecodeStore(t *testing.T) { Pairs: []kv.Pair{ { Key: host.FullClientStateKey(clientID), - Value: app.IBCKeeper.ClientKeeper.MustMarshalClientState(clientState), + Value: types.MustMarshalClientState(app.AppCodec(), clientState), }, { Key: host.FullConsensusStateKey(clientID, height), - Value: app.IBCKeeper.ClientKeeper.MustMarshalConsensusState(consState), + Value: types.MustMarshalConsensusState(app.AppCodec(), consState), }, { Key: []byte{0x99}, @@ -58,7 +58,7 @@ func TestDecodeStore(t *testing.T) { for i, tt := range tests { i, tt := i, tt t.Run(tt.name, func(t *testing.T) { - res, found := simulation.NewDecodeStore(app.IBCKeeper.ClientKeeper, kvPairs.Pairs[i], kvPairs.Pairs[i]) + res, found := simulation.NewDecodeStore(app.AppCodec(), kvPairs.Pairs[i], kvPairs.Pairs[i]) if i == len(tests)-1 { require.False(t, found, string(kvPairs.Pairs[i].Key)) require.Empty(t, res, string(kvPairs.Pairs[i].Key)) diff --git a/modules/core/simulation/decoder.go b/modules/core/simulation/decoder.go index 0f9a0c7f346..204881f397d 100644 --- a/modules/core/simulation/decoder.go +++ b/modules/core/simulation/decoder.go @@ -16,7 +16,7 @@ import ( // Value to the corresponding ibc type. func NewDecodeStore(k keeper.Keeper) func(kvA, kvB kv.Pair) string { return func(kvA, kvB kv.Pair) string { - if res, found := clientsim.NewDecodeStore(k.ClientKeeper, kvA, kvB); found { + if res, found := clientsim.NewDecodeStore(k.Codec(), kvA, kvB); found { return res } diff --git a/modules/core/simulation/decoder_test.go b/modules/core/simulation/decoder_test.go index 438b69577e9..83c1819ec9f 100644 --- a/modules/core/simulation/decoder_test.go +++ b/modules/core/simulation/decoder_test.go @@ -42,7 +42,7 @@ func TestDecodeStore(t *testing.T) { Pairs: []kv.Pair{ { Key: host.FullClientStateKey(clientID), - Value: app.IBCKeeper.ClientKeeper.MustMarshalClientState(clientState), + Value: clienttypes.MustMarshalClientState(app.AppCodec(), clientState), }, { Key: host.ConnectionKey(connectionID), diff --git a/modules/light-clients/07-tendermint/store_test.go b/modules/light-clients/07-tendermint/store_test.go index fac0199ca5f..5eae11a5af7 100644 --- a/modules/light-clients/07-tendermint/store_test.go +++ b/modules/light-clients/07-tendermint/store_test.go @@ -38,7 +38,7 @@ func (suite *TendermintTestSuite) TestGetConsensusState() { "not a consensus state interface", func() { // marshal an empty client state and set as consensus state store := suite.chainA.App.GetIBCKeeper().ClientKeeper.ClientStore(suite.chainA.GetContext(), path.EndpointA.ClientID) - clientStateBz := suite.chainA.App.GetIBCKeeper().ClientKeeper.MustMarshalClientState(&tendermint.ClientState{}) + clientStateBz := clienttypes.MustMarshalClientState(suite.chainA.App.AppCodec(), &tendermint.ClientState{}) store.Set(host.ConsensusStateKey(height), clientStateBz) }, false, true, }, @@ -46,7 +46,7 @@ func (suite *TendermintTestSuite) TestGetConsensusState() { "invalid consensus state (solomachine)", func() { // marshal and set solomachine consensus state store := suite.chainA.App.GetIBCKeeper().ClientKeeper.ClientStore(suite.chainA.GetContext(), path.EndpointA.ClientID) - consensusStateBz := suite.chainA.App.GetIBCKeeper().ClientKeeper.MustMarshalConsensusState(&solomachine.ConsensusState{}) + consensusStateBz := clienttypes.MustMarshalConsensusState(suite.chainA.App.AppCodec(), &solomachine.ConsensusState{}) store.Set(host.ConsensusStateKey(height), consensusStateBz) }, false, true, }, diff --git a/modules/light-clients/08-wasm/go.mod b/modules/light-clients/08-wasm/go.mod index 41e7b6ed0f3..ef26ba2dfd0 100644 --- a/modules/light-clients/08-wasm/go.mod +++ b/modules/light-clients/08-wasm/go.mod @@ -22,7 +22,7 @@ require ( cosmossdk.io/x/evidence v0.1.1 cosmossdk.io/x/feegrant v0.1.1 cosmossdk.io/x/tx v0.13.3 - cosmossdk.io/x/upgrade v0.1.2 + cosmossdk.io/x/upgrade v0.1.3 github.com/CosmWasm/wasmvm/v2 v2.0.1 github.com/cometbft/cometbft v0.38.7 github.com/cosmos/cosmos-db v1.0.2 @@ -117,7 +117,7 @@ require ( github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 // indirect github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // indirect - github.com/hashicorp/go-getter v1.7.3 // indirect + github.com/hashicorp/go-getter v1.7.4 // indirect github.com/hashicorp/go-hclog v1.5.0 // indirect github.com/hashicorp/go-immutable-radix v1.3.1 // indirect github.com/hashicorp/go-metrics v0.5.3 // indirect diff --git a/modules/light-clients/08-wasm/go.sum b/modules/light-clients/08-wasm/go.sum index 272d1db6801..b3b3cd21701 100644 --- a/modules/light-clients/08-wasm/go.sum +++ b/modules/light-clients/08-wasm/go.sum @@ -212,8 +212,8 @@ cosmossdk.io/x/feegrant v0.1.1 h1:EKFWOeo/pup0yF0svDisWWKAA9Zags6Zd0P3nRvVvw8= cosmossdk.io/x/feegrant v0.1.1/go.mod h1:2GjVVxX6G2fta8LWj7pC/ytHjryA6MHAJroBWHFNiEQ= cosmossdk.io/x/tx v0.13.3 h1:Ha4mNaHmxBc6RMun9aKuqul8yHiL78EKJQ8g23Zf73g= cosmossdk.io/x/tx v0.13.3/go.mod h1:I8xaHv0rhUdIvIdptKIqzYy27+n2+zBVaxO6fscFhys= -cosmossdk.io/x/upgrade v0.1.2 h1:O2FGb0mVSXl7P6BQm9uV3hRVKom1zBLDGhd4G8jysJg= -cosmossdk.io/x/upgrade v0.1.2/go.mod h1:P+e4/ZNd8km7lTAX5hC2pXz/042YDcB7gzKTHuY53nc= +cosmossdk.io/x/upgrade v0.1.3 h1:q4XpXc6zp0dX6x74uBtfN6+J7ikaQev5Bla6Q0ADLK8= +cosmossdk.io/x/upgrade v0.1.3/go.mod h1:jOdQhnaY5B8CDUoUbed23/Lre0Dk+r6BMQE40iKlVVQ= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= filippo.io/edwards25519 v1.0.0 h1:0wAIcmJUqRdI8IJ/3eGi5/HwXZWPujYXXlkrQogz0Ek= filippo.io/edwards25519 v1.0.0/go.mod h1:N1IkdkCkiLB6tki+MYJoSx2JTY9NUlxZE7eHn5EwJns= @@ -652,8 +652,8 @@ github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtng github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= -github.com/hashicorp/go-getter v1.7.3 h1:bN2+Fw9XPFvOCjB0UOevFIMICZ7G2XSQHzfvLUyOM5E= -github.com/hashicorp/go-getter v1.7.3/go.mod h1:W7TalhMmbPmsSMdNjD0ZskARur/9GJ17cfHTRtXV744= +github.com/hashicorp/go-getter v1.7.4 h1:3yQjWuxICvSpYwqSayAdKRFcvBl1y/vogCxczWSmix0= +github.com/hashicorp/go-getter v1.7.4/go.mod h1:W7TalhMmbPmsSMdNjD0ZskARur/9GJ17cfHTRtXV744= github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c= github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= diff --git a/modules/light-clients/08-wasm/light_client_module_test.go b/modules/light-clients/08-wasm/light_client_module_test.go index 1feaf29d327..ecac00a24d1 100644 --- a/modules/light-clients/08-wasm/light_client_module_test.go +++ b/modules/light-clients/08-wasm/light_client_module_test.go @@ -380,7 +380,7 @@ func (suite *WasmTestSuite) TestVerifyMembership() { { "success", func() { - expClientStateBz = GetSimApp(suite.chainA).GetIBCKeeper().ClientKeeper.MustMarshalClientState(clientState) + expClientStateBz = clienttypes.MustMarshalClientState(suite.chainA.App.AppCodec(), clientState) suite.mockVM.RegisterSudoCallback(types.VerifyMembershipMsg{}, func(_ wasmvm.Checksum, _ wasmvmtypes.Env, sudoMsg []byte, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction, ) (*wasmvmtypes.ContractResult, uint64, error) { @@ -526,7 +526,7 @@ func (suite *WasmTestSuite) TestVerifyNonMembership() { { "success", func() { - expClientStateBz = GetSimApp(suite.chainA).GetIBCKeeper().ClientKeeper.MustMarshalClientState(clientState) + expClientStateBz = clienttypes.MustMarshalClientState(suite.chainA.App.AppCodec(), clientState) suite.mockVM.RegisterSudoCallback(types.VerifyNonMembershipMsg{}, func(_ wasmvm.Checksum, _ wasmvmtypes.Env, sudoMsg []byte, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction, ) (*wasmvmtypes.ContractResult, uint64, error) { diff --git a/proto/ibc/applications/transfer/v1/tx.proto b/proto/ibc/applications/transfer/v1/tx.proto index 52e5d29b7e1..24101fff0a9 100644 --- a/proto/ibc/applications/transfer/v1/tx.proto +++ b/proto/ibc/applications/transfer/v1/tx.proto @@ -35,8 +35,8 @@ message MsgTransfer { string source_port = 1; // the channel by which the packet will be sent string source_channel = 2; - // the tokens to be transferred - cosmos.base.v1beta1.Coin token = 3 [(gogoproto.nullable) = false, (amino.dont_omitempty) = true]; + // the token to be transferred. this field has been replaced by the tokens field. + cosmos.base.v1beta1.Coin token = 3 [(gogoproto.nullable) = false, (amino.dont_omitempty) = true, deprecated = true]; // the sender address string sender = 4; // the recipient address on the destination chain @@ -50,7 +50,7 @@ message MsgTransfer { // optional memo string memo = 8; // tokens to be transferred - repeated cosmos.base.v1beta1.Coin tokens = 9 [(gogoproto.nullable) = false, (amino.dont_omitempty) = true]; + repeated cosmos.base.v1beta1.Coin tokens = 9 [(gogoproto.nullable) = false]; } // MsgTransferResponse defines the Msg/Transfer response type.