From c55c3bed190030d9750504859db0534d88d3cdd7 Mon Sep 17 00:00:00 2001 From: Carlos Rodriguez Date: Sun, 7 Jan 2024 23:29:07 +0100 Subject: [PATCH 1/7] e2e: upgrade ICA channel to wire up fee middleware, then close it by timing out a packet --- .../interchain_accounts/upgrades_test.go | 214 ++++++++++++++++++ e2e/testsuite/testconfig.go | 2 +- 2 files changed, 215 insertions(+), 1 deletion(-) create mode 100644 e2e/tests/interchain_accounts/upgrades_test.go diff --git a/e2e/tests/interchain_accounts/upgrades_test.go b/e2e/tests/interchain_accounts/upgrades_test.go new file mode 100644 index 00000000000..7b2b47c967d --- /dev/null +++ b/e2e/tests/interchain_accounts/upgrades_test.go @@ -0,0 +1,214 @@ +//go:build !test_e2e + +package interchainaccounts + +import ( + "context" + "testing" + "time" + + sdkmath "cosmossdk.io/math" + "github.com/strangelove-ventures/interchaintest/v8" + "github.com/strangelove-ventures/interchaintest/v8/ibc" + test "github.com/strangelove-ventures/interchaintest/v8/testutil" + testifysuite "github.com/stretchr/testify/suite" + + sdk "github.com/cosmos/cosmos-sdk/types" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" + "github.com/cosmos/gogoproto/proto" + + "github.com/cosmos/ibc-go/e2e/testsuite" + "github.com/cosmos/ibc-go/e2e/testvalues" + controllertypes "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" + feetypes "github.com/cosmos/ibc-go/v8/modules/apps/29-fee/types" + transfertypes "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types" + channeltypes "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types" + ibctesting "github.com/cosmos/ibc-go/v8/testing" +) + +func TestInterchainAccountsChannelUpgradesTestSuite(t *testing.T) { + testifysuite.Run(t, new(InterchainAccountsChannelUpgradesTestSuite)) +} + +type InterchainAccountsChannelUpgradesTestSuite struct { + testsuite.E2ETestSuite +} + +// TestChannelUpgrade_ICAChannelClosesAfterTimeout_Succeeds tests upgrading an ICA channel to +// wire up fee middleware and then forces it to close it by timing out a packet. +func (s *InterchainAccountsChannelUpgradesTestSuite) TestChannelUpgrade_ICAChannelClosesAfterTimeout_Succeeds() { + t := s.T() + ctx := context.TODO() + + // setup relayers and connection-0 between two chains + // channel-0 is a transfer channel but it will not be used in this test case + relayer, _ := s.SetupChainsRelayerAndChannel(ctx, nil) + chainA, chainB := s.GetChains() + + // setup 2 accounts: controller account on chain A, a second chain B account. + // host account will be created when the ICA is registered + controllerAccount := s.CreateUserOnChainA(ctx, testvalues.StartingTokenAmount) + controllerAddress := controllerAccount.FormattedAddress() + chainBAccount := s.CreateUserOnChainB(ctx, testvalues.StartingTokenAmount) + + chainBDenom := chainB.Config().Denom + chainAWallet := s.CreateUserOnChainA(ctx, testvalues.StartingTokenAmount) + + s.Require().NoError(test.WaitForBlocks(ctx, 1, chainA, chainB), "failed to wait for blocks") + + var ( + channelID = "channel-1" + controllerPortID string + hostPortID = icatypes.HostPortID + interchainAccount string + channelA channeltypes.Channel + ) + + t.Run("register interchain account", func(t *testing.T) { + var err error + // explicitly set the version string because we don't want to use incentivized channels. + version := icatypes.NewDefaultMetadataString(ibctesting.FirstConnectionID, ibctesting.FirstConnectionID) + msgRegisterInterchainAccount := controllertypes.NewMsgRegisterInterchainAccount(ibctesting.FirstConnectionID, controllerAddress, version) + txResp := s.BroadcastMessages(ctx, chainA, controllerAccount, msgRegisterInterchainAccount) + s.AssertTxSuccess(txResp) + + controllerPortID, err = icatypes.NewControllerPortID(controllerAddress) + s.Require().NoError(err) + }) + + t.Run("start relayer", func(t *testing.T) { + s.StartRelayer(relayer) + }) + + t.Run("verify interchain account", func(t *testing.T) { + var err error + interchainAccount, err = s.QueryInterchainAccount(ctx, chainA, controllerAddress, ibctesting.FirstConnectionID) + s.Require().NoError(err) + s.Require().NotZero(len(interchainAccount)) + + channelA, err = s.QueryChannel(ctx, chainA, controllerPortID, channelID) + s.Require().NoError(err) + }) + + t.Run("execute gov proposal to initiate channel upgrade", func(t *testing.T) { + s.initiateChannelUpgrade(ctx, chainA, chainAWallet, controllerPortID, channelID, s.createUpgradeFields(channelA)) + }) + + s.Require().NoError(test.WaitForBlocks(ctx, 10, chainA, chainB), "failed to wait for blocks") + + t.Run("verify channel A upgraded and is fee enabled", func(t *testing.T) { + channel, err := s.QueryChannel(ctx, chainA, controllerPortID, channelID) + s.Require().NoError(err) + + // check the channel version include the fee version + version, err := feetypes.MetadataFromVersion(channel.Version) + s.Require().NoError(err) + s.Require().Equal(feetypes.Version, version.FeeVersion, "the channel version did not include ics29") + + // extra check + feeEnabled, err := s.QueryFeeEnabledChannel(ctx, chainA, controllerPortID, channelID) + s.Require().NoError(err) + s.Require().Equal(true, feeEnabled) + }) + + t.Run("verify channel B upgraded and is fee enabled", func(t *testing.T) { + channel, err := s.QueryChannel(ctx, chainB, hostPortID, channelID) + s.Require().NoError(err) + + // check the channel version include the fee version + version, err := feetypes.MetadataFromVersion(channel.Version) + s.Require().NoError(err) + s.Require().Equal(feetypes.Version, version.FeeVersion, "the channel version did not include ics29") + + // extra check + feeEnabled, err := s.QueryFeeEnabledChannel(ctx, chainB, hostPortID, channelID) + s.Require().NoError(err) + s.Require().Equal(true, feeEnabled) + }) + + // stop the relayer to let the submit tx message time out + t.Run("stop relayer", func(t *testing.T) { + s.StopRelayer(ctx, relayer) + }) + + t.Run("submit tx message with bank transfer message times out", func(t *testing.T) { + t.Run("fund interchain account wallet", func(t *testing.T) { + // fund the host account account so it has some $$ to send + err := chainB.SendFunds(ctx, interchaintest.FaucetAccountKeyName, ibc.WalletAmount{ + Address: interchainAccount, + Amount: sdkmath.NewInt(testvalues.StartingTokenAmount), + Denom: chainBDenom, + }) + s.Require().NoError(err) + }) + + t.Run("broadcast MsgSendTx", func(t *testing.T) { + // assemble bank transfer message from host account to user account on host chain + msgSend := &banktypes.MsgSend{ + FromAddress: interchainAccount, + ToAddress: chainBAccount.FormattedAddress(), + Amount: sdk.NewCoins(testvalues.DefaultTransferAmount(chainBDenom)), + } + + cdc := testsuite.Codec() + + bz, err := icatypes.SerializeCosmosTx(cdc, []proto.Message{msgSend}, icatypes.EncodingProtobuf) + s.Require().NoError(err) + + packetData := icatypes.InterchainAccountPacketData{ + Type: icatypes.EXECUTE_TX, + Data: bz, + Memo: "e2e", + } + + msgSendTx := controllertypes.NewMsgSendTx(controllerAddress, ibctesting.FirstConnectionID, uint64(1), packetData) + + resp := s.BroadcastMessages( + ctx, + chainA, + controllerAccount, + msgSendTx, + ) + + s.AssertTxSuccess(resp) + + // this sleep is to allow the packet to timeout + time.Sleep(1 * time.Second) + }) + }) + + t.Run("start relayer", func(t *testing.T) { + s.StartRelayer(relayer) + }) + + t.Run("verify channel is closed due to timeout on ordered channel", func(t *testing.T) { + channel, err := s.QueryChannel(ctx, chainA, controllerPortID, channelID) + s.Require().NoError(err) + + s.Require().Equal(channeltypes.CLOSED, channel.State, "the channel was not in an expected state") + }) +} + +// createUpgradeFields created the upgrade fields for channel +func (s *InterchainAccountsChannelUpgradesTestSuite) createUpgradeFields(channel channeltypes.Channel) channeltypes.UpgradeFields { + versionMetadata := feetypes.Metadata{ + FeeVersion: feetypes.Version, + AppVersion: transfertypes.Version, + } + versionBytes, err := feetypes.ModuleCdc.MarshalJSON(&versionMetadata) + s.Require().NoError(err) + + return channeltypes.NewUpgradeFields(channel.Ordering, channel.ConnectionHops, string(versionBytes)) +} + +// initiateChannelUpgrade creates and submits a governance proposal to execute the message to initiate a channel upgrade +func (s *InterchainAccountsChannelUpgradesTestSuite) initiateChannelUpgrade(ctx context.Context, chain ibc.Chain, wallet ibc.Wallet, portID, channelID string, upgradeFields channeltypes.UpgradeFields) { + govModuleAddress, err := s.QueryModuleAccountAddress(ctx, govtypes.ModuleName, chain) + s.Require().NoError(err) + s.Require().NotNil(govModuleAddress) + + msg := channeltypes.NewMsgChannelUpgradeInit(portID, channelID, upgradeFields, govModuleAddress.String()) + s.ExecuteAndPassGovV1Proposal(ctx, msg, chain, wallet) +} diff --git a/e2e/testsuite/testconfig.go b/e2e/testsuite/testconfig.go index c88646fc6d9..79fb493113e 100644 --- a/e2e/testsuite/testconfig.go +++ b/e2e/testsuite/testconfig.go @@ -58,7 +58,7 @@ const ( // TODO: https://github.com/cosmos/ibc-go/issues/4965 defaultHyperspaceTag = "20231122v39" // defaultHermesTag is the tag that will be used if no relayer tag is specified for hermes. - defaultHermesTag = "luca_joss-channel-upgrade-authority" + defaultHermesTag = "luca_joss-docker-image-channel-upgrade" // defaultChainTag is the tag that will be used for the chains if none is specified. defaultChainTag = "main" // defaultConfigFileName is the default filename for the config file that can be used to configure From 1167b204337dee84df3d1782310439ab2d21e6d7 Mon Sep 17 00:00:00 2001 From: Carlos Rodriguez Date: Mon, 15 Jan 2024 23:29:10 +0100 Subject: [PATCH 2/7] fix version used in upgrade --- e2e/tests/interchain_accounts/upgrades_test.go | 3 +-- e2e/testsuite/testconfig.go | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/e2e/tests/interchain_accounts/upgrades_test.go b/e2e/tests/interchain_accounts/upgrades_test.go index 7b2b47c967d..7ef8b2bc6d7 100644 --- a/e2e/tests/interchain_accounts/upgrades_test.go +++ b/e2e/tests/interchain_accounts/upgrades_test.go @@ -23,7 +23,6 @@ import ( controllertypes "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" feetypes "github.com/cosmos/ibc-go/v8/modules/apps/29-fee/types" - transfertypes "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types" channeltypes "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types" ibctesting "github.com/cosmos/ibc-go/v8/testing" ) @@ -195,7 +194,7 @@ func (s *InterchainAccountsChannelUpgradesTestSuite) TestChannelUpgrade_ICAChann func (s *InterchainAccountsChannelUpgradesTestSuite) createUpgradeFields(channel channeltypes.Channel) channeltypes.UpgradeFields { versionMetadata := feetypes.Metadata{ FeeVersion: feetypes.Version, - AppVersion: transfertypes.Version, + AppVersion: channel.Version, } versionBytes, err := feetypes.ModuleCdc.MarshalJSON(&versionMetadata) s.Require().NoError(err) diff --git a/e2e/testsuite/testconfig.go b/e2e/testsuite/testconfig.go index 79fb493113e..c88646fc6d9 100644 --- a/e2e/testsuite/testconfig.go +++ b/e2e/testsuite/testconfig.go @@ -58,7 +58,7 @@ const ( // TODO: https://github.com/cosmos/ibc-go/issues/4965 defaultHyperspaceTag = "20231122v39" // defaultHermesTag is the tag that will be used if no relayer tag is specified for hermes. - defaultHermesTag = "luca_joss-docker-image-channel-upgrade" + defaultHermesTag = "luca_joss-channel-upgrade-authority" // defaultChainTag is the tag that will be used for the chains if none is specified. defaultChainTag = "main" // defaultConfigFileName is the default filename for the config file that can be used to configure From 30b9c38a0a490973547ab6f73a2b0fd9cccc0fc0 Mon Sep 17 00:00:00 2001 From: Carlos Rodriguez Date: Tue, 16 Jan 2024 09:18:13 +0100 Subject: [PATCH 3/7] check channel b also is closed --- e2e/tests/interchain_accounts/upgrades_test.go | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/e2e/tests/interchain_accounts/upgrades_test.go b/e2e/tests/interchain_accounts/upgrades_test.go index 7ef8b2bc6d7..6385dd5232e 100644 --- a/e2e/tests/interchain_accounts/upgrades_test.go +++ b/e2e/tests/interchain_accounts/upgrades_test.go @@ -132,7 +132,7 @@ func (s *InterchainAccountsChannelUpgradesTestSuite) TestChannelUpgrade_ICAChann s.StopRelayer(ctx, relayer) }) - t.Run("submit tx message with bank transfer message times out", func(t *testing.T) { + t.Run("submit tx message with bank transfer message that times out", func(t *testing.T) { t.Run("fund interchain account wallet", func(t *testing.T) { // fund the host account account so it has some $$ to send err := chainB.SendFunds(ctx, interchaintest.FaucetAccountKeyName, ibc.WalletAmount{ @@ -182,12 +182,19 @@ func (s *InterchainAccountsChannelUpgradesTestSuite) TestChannelUpgrade_ICAChann s.StartRelayer(relayer) }) - t.Run("verify channel is closed due to timeout on ordered channel", func(t *testing.T) { + t.Run("verify channel A is closed due to timeout on ordered channel", func(t *testing.T) { channel, err := s.QueryChannel(ctx, chainA, controllerPortID, channelID) s.Require().NoError(err) s.Require().Equal(channeltypes.CLOSED, channel.State, "the channel was not in an expected state") }) + + t.Run("verify channel B is closed due to timeout on ordered channel", func(t *testing.T) { + channel, err := s.QueryChannel(ctx, chainB, hostPortID, channelID) + s.Require().NoError(err) + + s.Require().Equal(channeltypes.CLOSED, channel.State, "the channel was not in an expected state") + }) } // createUpgradeFields created the upgrade fields for channel From 66612d3e9584460768d48c99a4a615cba67c2a88 Mon Sep 17 00:00:00 2001 From: Carlos Rodriguez Date: Thu, 18 Jan 2024 21:13:20 +0100 Subject: [PATCH 4/7] fix test --- e2e/tests/interchain_accounts/upgrades_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/e2e/tests/interchain_accounts/upgrades_test.go b/e2e/tests/interchain_accounts/upgrades_test.go index 6385dd5232e..0a4d5bd1809 100644 --- a/e2e/tests/interchain_accounts/upgrades_test.go +++ b/e2e/tests/interchain_accounts/upgrades_test.go @@ -69,7 +69,7 @@ func (s *InterchainAccountsChannelUpgradesTestSuite) TestChannelUpgrade_ICAChann var err error // explicitly set the version string because we don't want to use incentivized channels. version := icatypes.NewDefaultMetadataString(ibctesting.FirstConnectionID, ibctesting.FirstConnectionID) - msgRegisterInterchainAccount := controllertypes.NewMsgRegisterInterchainAccount(ibctesting.FirstConnectionID, controllerAddress, version) + msgRegisterInterchainAccount := controllertypes.NewMsgRegisterInterchainAccount(ibctesting.FirstConnectionID, controllerAddress, version, channeltypes.ORDERED) txResp := s.BroadcastMessages(ctx, chainA, controllerAccount, msgRegisterInterchainAccount) s.AssertTxSuccess(txResp) From 9db3c02625779a7e900f450bb0c70b3af7194353 Mon Sep 17 00:00:00 2001 From: Carlos Rodriguez Date: Fri, 26 Jan 2024 14:22:36 +0100 Subject: [PATCH 5/7] update hermes repository --- e2e/relayer/relayer.go | 2 +- e2e/testsuite/testconfig.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/e2e/relayer/relayer.go b/e2e/relayer/relayer.go index b63e1b86ba7..3ea06b3d3fe 100644 --- a/e2e/relayer/relayer.go +++ b/e2e/relayer/relayer.go @@ -16,7 +16,7 @@ const ( Hermes = "hermes" Hyperspace = "hyperspace" - HermesRelayerRepository = "ghcr.io/informalsystems/hermes" + HermesRelayerRepository = "crodveg/carlos-channel-upgrades" hermesRelayerUser = "1000:1000" RlyRelayerRepository = "ghcr.io/cosmos/relayer" rlyRelayerUser = "100:1000" diff --git a/e2e/testsuite/testconfig.go b/e2e/testsuite/testconfig.go index 3da52060b06..516499b3934 100644 --- a/e2e/testsuite/testconfig.go +++ b/e2e/testsuite/testconfig.go @@ -62,7 +62,7 @@ const ( // TODO: https://github.com/cosmos/ibc-go/issues/4965 defaultHyperspaceTag = "20231122v39" // defaultHermesTag is the tag that will be used if no relayer tag is specified for hermes. - defaultHermesTag = "luca_joss-channel-upgrade-authority" + defaultHermesTag = "latest" // defaultChainTag is the tag that will be used for the chains if none is specified. defaultChainTag = "main" // defaultConfigFileName is the default filename for the config file that can be used to configure From aae7e0ff8d5129994b122bec603dff5afa40b86c Mon Sep 17 00:00:00 2001 From: Carlos Rodriguez Date: Sat, 27 Jan 2024 13:48:07 +0100 Subject: [PATCH 6/7] update hermes repository --- e2e/relayer/relayer.go | 2 +- e2e/testsuite/testconfig.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/e2e/relayer/relayer.go b/e2e/relayer/relayer.go index 3ea06b3d3fe..b63e1b86ba7 100644 --- a/e2e/relayer/relayer.go +++ b/e2e/relayer/relayer.go @@ -16,7 +16,7 @@ const ( Hermes = "hermes" Hyperspace = "hyperspace" - HermesRelayerRepository = "crodveg/carlos-channel-upgrades" + HermesRelayerRepository = "ghcr.io/informalsystems/hermes" hermesRelayerUser = "1000:1000" RlyRelayerRepository = "ghcr.io/cosmos/relayer" rlyRelayerUser = "100:1000" diff --git a/e2e/testsuite/testconfig.go b/e2e/testsuite/testconfig.go index 516499b3934..3da52060b06 100644 --- a/e2e/testsuite/testconfig.go +++ b/e2e/testsuite/testconfig.go @@ -62,7 +62,7 @@ const ( // TODO: https://github.com/cosmos/ibc-go/issues/4965 defaultHyperspaceTag = "20231122v39" // defaultHermesTag is the tag that will be used if no relayer tag is specified for hermes. - defaultHermesTag = "latest" + defaultHermesTag = "luca_joss-channel-upgrade-authority" // defaultChainTag is the tag that will be used for the chains if none is specified. defaultChainTag = "main" // defaultConfigFileName is the default filename for the config file that can be used to configure From 3f7ac9265a8cbc17fa46badcd1dbdb9f2285f797 Mon Sep 17 00:00:00 2001 From: Carlos Rodriguez Date: Mon, 29 Jan 2024 15:09:55 +0100 Subject: [PATCH 7/7] Update e2e/tests/interchain_accounts/upgrades_test.go MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> --- e2e/tests/interchain_accounts/upgrades_test.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/e2e/tests/interchain_accounts/upgrades_test.go b/e2e/tests/interchain_accounts/upgrades_test.go index 0a4d5bd1809..46342dcdcbd 100644 --- a/e2e/tests/interchain_accounts/upgrades_test.go +++ b/e2e/tests/interchain_accounts/upgrades_test.go @@ -162,7 +162,8 @@ func (s *InterchainAccountsChannelUpgradesTestSuite) TestChannelUpgrade_ICAChann Memo: "e2e", } - msgSendTx := controllertypes.NewMsgSendTx(controllerAddress, ibctesting.FirstConnectionID, uint64(1), packetData) + timeout := uint64(1) + msgSendTx := controllertypes.NewMsgSendTx(controllerAddress, ibctesting.FirstConnectionID, timeout, packetData) resp := s.BroadcastMessages( ctx,