mukan-ibc/e2e/tests/upgrades/upgrade_test.go
Mukan Erkin Törük 88dd97a9f8
Some checks failed
CodeQL / Analyze (push) Waiting to run
golangci-lint / lint (push) Waiting to run
Tests / Code Coverage / build (amd64) (push) Waiting to run
Tests / Code Coverage / build (arm64) (push) Waiting to run
Tests / Code Coverage / unit-tests (map[additional-args:-tags="test_e2e" name:e2e path:./e2e]) (push) Waiting to run
Tests / Code Coverage / unit-tests (map[name:08-wasm path:./modules/light-clients/08-wasm]) (push) Waiting to run
Tests / Code Coverage / unit-tests (map[name:ibc-go path:.]) (push) Waiting to run
Docker Build & Push Simapp (main) / docker-build (push) Has been cancelled
refactor: replace all github.com upstream refs with git.cw.tr/mukan-network
2026-05-11 03:36:22 +03:00

995 lines
40 KiB
Go

//go:build !test_e2e
package upgrades
import (
"context"
"fmt"
"testing"
"time"
"github.com/cosmos/gogoproto/proto"
interchaintest "github.com/cosmos/interchaintest/v10"
"github.com/cosmos/interchaintest/v10/chain/cosmos"
"github.com/cosmos/interchaintest/v10/ibc"
test "github.com/cosmos/interchaintest/v10/testutil"
testifysuite "github.com/stretchr/testify/suite"
sdkmath "cosmossdk.io/math"
upgradetypes "cosmossdk.io/x/upgrade/types"
sdk "git.cw.tr/mukan-network/mukan-sdk/types"
authtypes "git.cw.tr/mukan-network/mukan-sdk/x/auth/types"
govtypes "git.cw.tr/mukan-network/mukan-sdk/x/gov/types"
e2erelayer "github.com/cosmos/ibc-go/e2e/relayer"
"github.com/cosmos/ibc-go/e2e/testsuite"
"github.com/cosmos/ibc-go/e2e/testsuite/query"
"github.com/cosmos/ibc-go/e2e/testvalues"
transfertypes "git.cw.tr/mukan-network/mukan-ibc/modules/apps/transfer/types"
v7migrations "git.cw.tr/mukan-network/mukan-ibc/modules/core/02-client/migrations/v7"
clienttypes "git.cw.tr/mukan-network/mukan-ibc/modules/core/02-client/types"
connectiontypes "git.cw.tr/mukan-network/mukan-ibc/modules/core/03-connection/types"
channeltypes "git.cw.tr/mukan-network/mukan-ibc/modules/core/04-channel/types"
"git.cw.tr/mukan-network/mukan-ibc/modules/core/exported"
solomachine "git.cw.tr/mukan-network/mukan-ibc/modules/light-clients/06-solomachine"
localhost "git.cw.tr/mukan-network/mukan-ibc/modules/light-clients/09-localhost"
ibctesting "git.cw.tr/mukan-network/mukan-ibc/testing"
)
const (
haltHeightOffset = int64(30)
blocksAfterUpgrade = uint64(10)
)
func TestUpgradeTestSuite(t *testing.T) {
testCfg := testsuite.LoadConfig()
if testCfg.UpgradePlanName == "" {
t.Fatalf("%s must be set when running an upgrade test", testsuite.ChainUpgradePlanEnv)
}
testifysuite.Run(t, new(UpgradeTestSuite))
}
type UpgradeTestSuite struct {
testsuite.E2ETestSuite
}
// SetupSuite sets up chains for the current test suite
func (s *UpgradeTestSuite) SetupSuite() {
s.SetupChains(context.TODO(), 2, nil)
}
func (s *UpgradeTestSuite) CreateUpgradeTestPath(testName string) (ibc.Relayer, ibc.ChannelOutput) {
return s.CreatePaths(ibc.DefaultClientOpts(), s.TransferChannelOptions(), testName), s.GetChainAChannelForTest(testName)
}
// UpgradeChain upgrades a chain to a specific version using the planName provided.
// The software upgrade proposal is broadcast by the provided wallet.
func (s *UpgradeTestSuite) UpgradeChain(ctx context.Context, chain *cosmos.CosmosChain, wallet ibc.Wallet, planName, currentVersion, upgradeVersion string) {
height, err := chain.GetNode().Height(ctx)
s.Require().NoError(err, "error fetching height before upgrade")
haltHeight := height + haltHeightOffset
plan := upgradetypes.Plan{
Name: planName,
Height: haltHeight,
Info: fmt.Sprintf("upgrade version test from %s to %s", currentVersion, upgradeVersion),
}
if testvalues.GovV1MessagesFeatureReleases.IsSupported(chain.Config().Images[0].Version) {
msgSoftwareUpgrade := &upgradetypes.MsgSoftwareUpgrade{
Plan: plan,
Authority: authtypes.NewModuleAddress(govtypes.ModuleName).String(),
}
s.ExecuteAndPassGovV1Proposal(ctx, msgSoftwareUpgrade, chain, wallet)
} else {
upgradeProposal := upgradetypes.NewSoftwareUpgradeProposal(fmt.Sprintf("upgrade from %s to %s", currentVersion, upgradeVersion), "upgrade chain E2E test", plan)
s.ExecuteAndPassGovV1Beta1Proposal(ctx, chain, wallet, upgradeProposal)
}
err = test.WaitForCondition(time.Minute*2, time.Second*2, func() (bool, error) {
status, err := chain.GetNode().Client.Status(ctx)
if err != nil {
return false, err
}
return status.SyncInfo.LatestBlockHeight >= haltHeight, nil
})
s.Require().NoError(err, "failed to wait for chain to halt")
var allNodes []test.ChainHeighter
for _, node := range chain.Nodes() {
allNodes = append(allNodes, node)
}
err = test.WaitForInSync(ctx, chain, allNodes...)
s.Require().NoError(err, "error waiting for node(s) to sync")
err = chain.StopAllNodes(ctx)
s.Require().NoError(err, "error stopping node(s)")
repository := chain.Nodes()[0].Image.Repository
chain.UpgradeVersion(ctx, s.DockerClient, repository, upgradeVersion)
err = chain.StartAllNodes(ctx)
s.Require().NoError(err, "error starting upgraded node(s)")
timeoutCtx, timeoutCtxCancel := context.WithTimeout(ctx, time.Minute*2)
defer timeoutCtxCancel()
err = test.WaitForBlocks(timeoutCtx, int(blocksAfterUpgrade), chain)
s.Require().NoError(err, "chain did not produce blocks after upgrade")
height, err = chain.Height(ctx)
s.Require().NoError(err, "error fetching height after upgrade")
s.Require().Greater(height, haltHeight, "height did not increment after upgrade")
// In case the query paths have changed after the upgrade, we need to repopulate them
err = query.PopulateQueryReqToPath(ctx, chain)
s.Require().NoError(err, "error populating query paths after upgrade")
}
func (s *UpgradeTestSuite) TestIBCChainUpgrade() {
t := s.T()
testCfg := testsuite.LoadConfig()
ctx := context.Background()
testName := t.Name()
relayer, channelA := s.CreateUpgradeTestPath(testName)
chainA, chainB := s.GetChains()
var (
chainADenom = chainA.Config().Denom
chainBIBCToken = testsuite.GetIBCToken(chainADenom, channelA.Counterparty.PortID, channelA.Counterparty.ChannelID) // IBC token sent to chainB
chainBDenom = chainB.Config().Denom
chainAIBCToken = testsuite.GetIBCToken(chainBDenom, channelA.PortID, channelA.ChannelID) // IBC token sent to chainA
)
// create separate user specifically for the upgrade proposal to more easily verify starting
// and end balances of the chainA users.
chainAUpgradeProposalWallet := s.CreateUserOnChainA(ctx, testvalues.StartingTokenAmount)
chainAWallet := s.CreateUserOnChainA(ctx, testvalues.StartingTokenAmount)
chainAAddress := chainAWallet.FormattedAddress()
chainBWallet := s.CreateUserOnChainB(ctx, testvalues.StartingTokenAmount)
chainBAddress := chainBWallet.FormattedAddress()
s.Require().NoError(test.WaitForBlocks(ctx, 1, chainA, chainB), "failed to wait for blocks")
t.Run("native IBC token transfer from chainA to chainB, sender is source of tokens", func(t *testing.T) {
transferTxResp := s.Transfer(ctx, chainA, chainAWallet, channelA.PortID, channelA.ChannelID, testvalues.DefaultTransferAmount(chainADenom), chainAAddress, chainBAddress, s.GetTimeoutHeight(ctx, chainB), 0, "")
s.AssertTxSuccess(transferTxResp)
})
t.Run("tokens are escrowed", func(t *testing.T) {
actualBalance, err := s.GetChainANativeBalance(ctx, chainAWallet)
s.Require().NoError(err)
expected := testvalues.StartingTokenAmount - testvalues.IBCTransferAmount
s.Require().Equal(expected, actualBalance)
})
t.Run("start relayer", func(t *testing.T) {
s.StartRelayer(relayer, testName)
})
t.Run("packets are relayed", func(t *testing.T) {
s.AssertPacketRelayed(ctx, chainA, channelA.PortID, channelA.ChannelID, 1)
actualBalance, err := query.Balance(ctx, chainB, chainBAddress, chainBIBCToken.IBCDenom())
s.Require().NoError(err)
expected := testvalues.IBCTransferAmount
s.Require().Equal(expected, actualBalance.Int64())
})
s.Require().NoError(test.WaitForBlocks(ctx, 5, chainA, chainB), "failed to wait for blocks")
t.Run("upgrade chainA", func(t *testing.T) {
s.UpgradeChain(ctx, chainA.(*cosmos.CosmosChain), chainAUpgradeProposalWallet, testCfg.GetUpgradeConfig().PlanName, testCfg.ChainConfigs[0].Tag, testCfg.GetUpgradeConfig().Tag)
})
t.Run("restart relayer", func(t *testing.T) {
s.StopRelayer(ctx, relayer)
s.StartRelayer(relayer, testName)
})
t.Run("native IBC token transfer from chainA to chainB, sender is source of tokens", func(t *testing.T) {
transferTxResp := s.Transfer(ctx, chainA, chainAWallet, channelA.PortID, channelA.ChannelID, testvalues.DefaultTransferAmount(chainADenom), chainAAddress, chainBAddress, s.GetTimeoutHeight(ctx, chainB), 0, "")
s.AssertTxSuccess(transferTxResp)
})
s.Require().NoError(test.WaitForBlocks(ctx, 5, chainA, chainB), "failed to wait for blocks")
t.Run("packets are relayed", func(t *testing.T) {
s.AssertPacketRelayed(ctx, chainA, channelA.PortID, channelA.ChannelID, 2)
actualBalance, err := query.Balance(ctx, chainB, chainBAddress, chainBIBCToken.IBCDenom())
s.Require().NoError(err)
expected := testvalues.IBCTransferAmount * 2
s.Require().Equal(expected, actualBalance.Int64())
})
t.Run("ensure packets can be received, send from chainB to chainA", func(t *testing.T) {
t.Run("send from chainB to chainA", func(t *testing.T) {
transferTxResp := s.Transfer(ctx, chainB, chainBWallet, channelA.Counterparty.PortID, channelA.Counterparty.ChannelID, testvalues.DefaultTransferAmount(chainBDenom), chainBAddress, chainAAddress, s.GetTimeoutHeight(ctx, chainA), 0, "")
s.AssertTxSuccess(transferTxResp)
})
s.Require().NoError(test.WaitForBlocks(ctx, 5, chainA, chainB), "failed to wait for blocks")
t.Run("packets are relayed", func(t *testing.T) {
s.AssertPacketRelayed(ctx, chainA, channelA.Counterparty.PortID, channelA.Counterparty.ChannelID, 1)
actualBalance, err := query.Balance(ctx, chainA, chainAAddress, chainAIBCToken.IBCDenom())
s.Require().NoError(err)
expected := testvalues.IBCTransferAmount
s.Require().Equal(expected, actualBalance.Int64())
})
})
}
func (s *UpgradeTestSuite) TestChainUpgrade() {
t := s.T()
ctx := context.Background()
testName := t.Name()
s.CreateUpgradeTestPath(testName)
// TODO(chatton): this test is still creating a relayer and a channel, but it is not using them.
chain := s.GetAllChains()[0]
userWallet := s.CreateUserOnChainA(ctx, testvalues.StartingTokenAmount)
userWalletAddr := userWallet.FormattedAddress()
s.Require().NoError(test.WaitForBlocks(ctx, 1, chain), "failed to wait for blocks")
t.Run("send funds to test wallet", func(t *testing.T) {
err := chain.SendFunds(ctx, interchaintest.FaucetAccountKeyName, ibc.WalletAmount{
Address: userWalletAddr,
Amount: sdkmath.NewInt(testvalues.StartingTokenAmount),
Denom: chain.Config().Denom,
})
s.Require().NoError(err)
})
t.Run("verify tokens sent", func(t *testing.T) {
balance, err := query.Balance(ctx, chain, userWalletAddr, chain.Config().Denom)
s.Require().NoError(err)
expected := testvalues.StartingTokenAmount * 2
s.Require().Equal(expected, balance)
})
t.Run("upgrade chain", func(t *testing.T) {
testCfg := testsuite.LoadConfig()
proposerWallet := s.CreateUserOnChainA(ctx, testvalues.StartingTokenAmount)
s.UpgradeChain(ctx, chain.(*cosmos.CosmosChain), proposerWallet, testCfg.GetUpgradeConfig().PlanName, testCfg.ChainConfigs[0].Tag, testCfg.GetUpgradeConfig().Tag)
})
t.Run("send funds to test wallet", func(t *testing.T) {
err := chain.SendFunds(ctx, interchaintest.FaucetAccountKeyName, ibc.WalletAmount{
Address: userWalletAddr,
Amount: sdkmath.NewInt(testvalues.StartingTokenAmount),
Denom: chain.Config().Denom,
})
s.Require().NoError(err)
})
t.Run("verify tokens sent", func(t *testing.T) {
balance, err := query.Balance(ctx, chain, userWalletAddr, chain.Config().Denom)
s.Require().NoError(err)
expected := testvalues.StartingTokenAmount * 3
s.Require().Equal(expected, balance)
})
}
// TestV6ToV7ChainUpgrade will test that an upgrade from a v6 ibc-go binary to a v7 ibc-go binary is successful
// and that the automatic migrations associated with the 02-client module are performed. Namely that the solo machine
// proto definition is migrated in state from the v2 to v3 definition. This is checked by creating a solo machine client
// before the upgrade and asserting that its TypeURL has been changed after the upgrade. The test also ensure packets
// can be sent before and after the upgrade without issue
func (s *UpgradeTestSuite) TestV6ToV7ChainUpgrade() {
t := s.T()
testCfg := testsuite.LoadConfig()
ctx := context.Background()
testName := t.Name()
relayer, channelA := s.CreateUpgradeTestPath(testName)
chainA, chainB := s.GetChains()
var (
chainADenom = chainA.Config().Denom
chainBIBCToken = testsuite.GetIBCToken(chainADenom, channelA.Counterparty.PortID, channelA.Counterparty.ChannelID) // IBC token sent to chainB
)
chainAWallet := s.CreateUserOnChainA(ctx, testvalues.StartingTokenAmount)
chainAAddress := chainAWallet.FormattedAddress()
chainBWallet := s.CreateUserOnChainB(ctx, testvalues.StartingTokenAmount)
chainBAddress := chainBWallet.FormattedAddress()
// create second tendermint client
createClientOptions := ibc.CreateClientOptions{
TrustingPeriod: ibctesting.TrustingPeriod.String(),
}
s.SetupClients(ctx, relayer, createClientOptions)
s.Require().NoError(test.WaitForBlocks(ctx, 1, chainA, chainB), "failed to wait for blocks")
t.Run("check that both tendermint clients are active", func(t *testing.T) {
status, err := query.ClientStatus(ctx, chainA, testvalues.TendermintClientID(0))
s.Require().NoError(err)
s.Require().Equal(exported.Active.String(), status)
status, err = query.ClientStatus(ctx, chainA, testvalues.TendermintClientID(1))
s.Require().NoError(err)
s.Require().Equal(exported.Active.String(), status)
})
// create solo machine client using the solomachine implementation from ibctesting
// TODO: the solomachine clientID should be updated when after fix of this issue: https://github.com/cosmos/ibc-go/issues/2907
solo := ibctesting.NewSolomachine(t, testsuite.Codec(), "solomachine", "testing", 1)
legacyConsensusState := &v7migrations.ConsensusState{
PublicKey: solo.ConsensusState().PublicKey,
Diversifier: solo.ConsensusState().Diversifier,
Timestamp: solo.ConsensusState().Timestamp,
}
legacyClientState := &v7migrations.ClientState{
Sequence: solo.ClientState().Sequence,
IsFrozen: solo.ClientState().IsFrozen,
ConsensusState: legacyConsensusState,
AllowUpdateAfterProposal: true,
}
msgCreateSoloMachineClient, err := clienttypes.NewMsgCreateClient(legacyClientState, legacyConsensusState, chainAAddress)
s.Require().NoError(err)
resp := s.BroadcastMessages(
ctx,
chainA.(*cosmos.CosmosChain),
chainAWallet,
msgCreateSoloMachineClient,
)
s.AssertTxSuccess(resp)
t.Run("check that the solomachine is now active and that the clientstate is a pre-upgrade v2 solomachine clientstate", func(t *testing.T) {
status, err := query.ClientStatus(ctx, chainA, testvalues.SolomachineClientID(2))
s.Require().NoError(err)
s.Require().Equal(exported.Active.String(), status)
res, err := s.ClientState(ctx, chainA, testvalues.SolomachineClientID(2))
s.Require().NoError(err)
s.Require().Equal(fmt.Sprint("/", proto.MessageName(&v7migrations.ClientState{})), res.ClientState.TypeUrl)
})
s.Require().NoError(test.WaitForBlocks(ctx, 1, chainA, chainB), "failed to wait for blocks")
t.Run("IBC token transfer from chainA to chainB, sender is source of tokens", func(t *testing.T) {
transferTxResp := s.Transfer(ctx, chainA, chainAWallet, channelA.PortID, channelA.ChannelID, testvalues.DefaultTransferAmount(chainADenom), chainAAddress, chainBAddress, s.GetTimeoutHeight(ctx, chainB), 0, "")
s.AssertTxSuccess(transferTxResp)
})
t.Run("tokens are escrowed", func(t *testing.T) {
actualBalance, err := s.GetChainANativeBalance(ctx, chainAWallet)
s.Require().NoError(err)
expected := testvalues.StartingTokenAmount - testvalues.IBCTransferAmount
s.Require().Equal(expected, actualBalance)
})
t.Run("start relayer", func(t *testing.T) {
s.StartRelayer(relayer, testName)
})
t.Run("packets are relayed", func(t *testing.T) {
s.AssertPacketRelayed(ctx, chainA, channelA.PortID, channelA.ChannelID, 1)
actualBalance, err := query.Balance(ctx, chainB, chainBAddress, chainBIBCToken.IBCDenom())
s.Require().NoError(err)
expected := testvalues.IBCTransferAmount
s.Require().Equal(expected, actualBalance.Int64())
})
// create separate user specifically for the upgrade proposal to more easily verify starting
// and end balances of the chainA users.
chainAUpgradeProposalWallet := s.CreateUserOnChainA(ctx, testvalues.StartingTokenAmount)
t.Run("upgrade chainA", func(t *testing.T) {
s.UpgradeChain(ctx, chainA.(*cosmos.CosmosChain), chainAUpgradeProposalWallet, testCfg.GetUpgradeConfig().PlanName, testCfg.ChainConfigs[0].Tag, testCfg.GetUpgradeConfig().Tag)
})
// see this issue https://github.com/informalsystems/hermes/issues/3579
// this restart is a temporary workaround to a limitation in hermes requiring a restart
// in some cases after an upgrade.
tc := testsuite.LoadConfig()
if tc.GetActiveRelayerConfig().ID == e2erelayer.Hermes {
s.RestartRelayer(ctx, relayer, testName)
}
t.Run("check that the tendermint clients are active again after upgrade", func(t *testing.T) {
status, err := query.ClientStatus(ctx, chainA, testvalues.TendermintClientID(0))
s.Require().NoError(err)
s.Require().Equal(exported.Active.String(), status)
status, err = query.ClientStatus(ctx, chainA, testvalues.TendermintClientID(1))
s.Require().NoError(err)
s.Require().Equal(exported.Active.String(), status)
})
t.Run("IBC token transfer from chainA to chainB, to make sure the upgrade did not break the packet flow", func(t *testing.T) {
transferTxResp := s.Transfer(ctx, chainA, chainAWallet, channelA.PortID, channelA.ChannelID, testvalues.DefaultTransferAmount(chainADenom), chainAAddress, chainBAddress, s.GetTimeoutHeight(ctx, chainB.(*cosmos.CosmosChain)), 0, "")
s.AssertTxSuccess(transferTxResp)
})
t.Run("packets are relayed", func(t *testing.T) {
s.AssertPacketRelayed(ctx, chainA, channelA.PortID, channelA.ChannelID, 1)
actualBalance, err := query.Balance(ctx, chainB, chainBAddress, chainBIBCToken.IBCDenom())
s.Require().NoError(err)
expected := testvalues.IBCTransferAmount * 2
s.Require().Equal(expected, actualBalance.Int64())
})
t.Run("check that the v2 solo machine clientstate has been updated to the v3 solo machine clientstate", func(t *testing.T) {
res, err := s.ClientState(ctx, chainA, testvalues.SolomachineClientID(2))
s.Require().NoError(err)
s.Require().Equal(fmt.Sprint("/", proto.MessageName(&solomachine.ClientState{})), res.ClientState.TypeUrl)
})
}
func (s *UpgradeTestSuite) TestV7ToV7_1ChainUpgrade() {
t := s.T()
testCfg := testsuite.LoadConfig()
ctx := context.Background()
testName := t.Name()
relayer, channelA := s.CreateUpgradeTestPath(testName)
chainA, chainB := s.GetChains()
chainADenom := chainA.Config().Denom
chainAWallet := s.CreateUserOnChainA(ctx, testvalues.StartingTokenAmount)
chainAAddress := chainAWallet.FormattedAddress()
chainBWallet := s.CreateUserOnChainB(ctx, testvalues.StartingTokenAmount)
chainBAddress := chainBWallet.FormattedAddress()
s.Require().NoError(test.WaitForBlocks(ctx, 1, chainA, chainB), "failed to wait for blocks")
t.Run("transfer native tokens from chainA to chainB", func(t *testing.T) {
transferTxResp := s.Transfer(ctx, chainA, chainAWallet, channelA.PortID, channelA.ChannelID, testvalues.DefaultTransferAmount(chainADenom), chainAAddress, chainBAddress, s.GetTimeoutHeight(ctx, chainB.(*cosmos.CosmosChain)), 0, "")
s.AssertTxSuccess(transferTxResp)
})
t.Run("tokens are escrowed", func(t *testing.T) {
actualBalance, err := s.GetChainANativeBalance(ctx, chainAWallet)
s.Require().NoError(err)
expected := testvalues.StartingTokenAmount - testvalues.IBCTransferAmount
s.Require().Equal(expected, actualBalance)
})
t.Run("start relayer", func(t *testing.T) {
s.StartRelayer(relayer, testName)
})
chainBIBCToken := testsuite.GetIBCToken(chainADenom, channelA.Counterparty.PortID, channelA.Counterparty.ChannelID)
t.Run("packet is relayed", func(t *testing.T) {
s.AssertPacketRelayed(ctx, chainA, channelA.PortID, channelA.ChannelID, 1)
actualBalance, err := query.Balance(ctx, chainB, chainBAddress, chainBIBCToken.IBCDenom())
s.Require().NoError(err)
expected := testvalues.IBCTransferAmount
s.Require().Equal(expected, actualBalance.Int64())
})
s.Require().NoError(test.WaitForBlocks(ctx, 5, chainA), "failed to wait for blocks")
t.Run("upgrade chain", func(t *testing.T) {
govProposalWallet := s.CreateUserOnChainA(ctx, testvalues.StartingTokenAmount)
s.UpgradeChain(ctx, chainA.(*cosmos.CosmosChain), govProposalWallet, testCfg.GetUpgradeConfig().PlanName, testCfg.ChainConfigs[0].Tag, testCfg.GetUpgradeConfig().Tag)
})
t.Run("ensure the localhost client is active and sentinel connection is stored in state", func(t *testing.T) {
localhostClientID := exported.LocalhostClientID
if !testvalues.LocalhostWithDashFeatureReleases.IsSupported(chainA.Config().Images[0].Version) {
localhostClientID = exported.Localhost
}
status, err := query.ClientStatus(ctx, chainA, localhostClientID)
s.Require().NoError(err)
s.Require().Equal(exported.Active.String(), status)
connectionResp, err := query.GRPCQuery[connectiontypes.QueryConnectionResponse](ctx, chainA, &connectiontypes.QueryConnectionRequest{ConnectionId: exported.LocalhostConnectionID})
s.Require().NoError(err)
s.Require().Equal(connectiontypes.OPEN, connectionResp.Connection.State)
s.Require().Equal(localhostClientID, connectionResp.Connection.ClientId)
s.Require().Equal(localhostClientID, connectionResp.Connection.Counterparty.ClientId)
s.Require().Equal(exported.LocalhostConnectionID, connectionResp.Connection.Counterparty.ConnectionId)
})
t.Run("ensure escrow amount for native denom is stored in state", func(t *testing.T) {
actualTotalEscrow, err := query.TotalEscrowForDenom(ctx, chainA, chainADenom)
s.Require().NoError(err)
expectedTotalEscrow := sdk.NewCoin(chainADenom, sdkmath.NewInt(testvalues.IBCTransferAmount))
s.Require().Equal(expectedTotalEscrow, actualTotalEscrow) // migration has run and total escrow amount has been set
})
t.Run("IBC token transfer from chainA to chainB, to make sure the upgrade did not break the packet flow", func(t *testing.T) {
transferTxResp := s.Transfer(ctx, chainA, chainAWallet, channelA.PortID, channelA.ChannelID, testvalues.DefaultTransferAmount(chainADenom), chainAAddress, chainBAddress, s.GetTimeoutHeight(ctx, chainB), 0, "")
s.AssertTxSuccess(transferTxResp)
})
t.Run("packets are relayed", func(t *testing.T) {
s.AssertPacketRelayed(ctx, chainA, channelA.PortID, channelA.ChannelID, 1)
actualBalance, err := chainB.GetBalance(ctx, chainBAddress, chainBIBCToken.IBCDenom())
s.Require().NoError(err)
expected := testvalues.IBCTransferAmount * 2
s.Require().Equal(expected, actualBalance.Int64())
})
}
func (s *UpgradeTestSuite) TestV7ToV8ChainUpgrade() {
t := s.T()
testCfg := testsuite.LoadConfig()
ctx := context.Background()
testName := t.Name()
relayer, channelA := s.CreateUpgradeTestPath(testName)
chainA, chainB := s.GetChains()
chainADenom := chainA.Config().Denom
chainAWallet := s.CreateUserOnChainA(ctx, testvalues.StartingTokenAmount)
chainAAddress := chainAWallet.FormattedAddress()
chainBWallet := s.CreateUserOnChainB(ctx, testvalues.StartingTokenAmount)
chainBAddress := chainBWallet.FormattedAddress()
s.Require().NoError(test.WaitForBlocks(ctx, 1, chainA, chainB), "failed to wait for blocks")
t.Run("transfer native tokens from chainA to chainB", func(t *testing.T) {
transferTxResp := s.Transfer(ctx, chainA, chainAWallet, channelA.PortID, channelA.ChannelID, testvalues.DefaultTransferAmount(chainADenom), chainAAddress, chainBAddress, s.GetTimeoutHeight(ctx, chainB), 0, "")
s.AssertTxSuccess(transferTxResp)
})
t.Run("tokens are escrowed", func(t *testing.T) {
actualBalance, err := s.GetChainANativeBalance(ctx, chainAWallet)
s.Require().NoError(err)
expected := testvalues.StartingTokenAmount - testvalues.IBCTransferAmount
s.Require().Equal(expected, actualBalance)
})
t.Run("start relayer", func(t *testing.T) {
s.StartRelayer(relayer, testName)
})
chainBIBCToken := testsuite.GetIBCToken(chainADenom, channelA.Counterparty.PortID, channelA.Counterparty.ChannelID)
t.Run("packet is relayed", func(t *testing.T) {
s.AssertPacketRelayed(ctx, chainA, channelA.PortID, channelA.ChannelID, 1)
actualBalance, err := query.Balance(ctx, chainB, chainBAddress, chainBIBCToken.IBCDenom())
s.Require().NoError(err)
expected := testvalues.IBCTransferAmount
s.Require().Equal(expected, actualBalance.Int64())
})
s.Require().NoError(test.WaitForBlocks(ctx, 5, chainA), "failed to wait for blocks")
t.Run("upgrade chain", func(t *testing.T) {
govProposalWallet := s.CreateUserOnChainB(ctx, testvalues.StartingTokenAmount)
s.UpgradeChain(ctx, chainB.(*cosmos.CosmosChain), govProposalWallet, testCfg.GetUpgradeConfig().PlanName, testCfg.ChainConfigs[0].Tag, testCfg.GetUpgradeConfig().Tag)
})
t.Run("update params", func(t *testing.T) {
authority, err := query.ModuleAccountAddress(ctx, govtypes.ModuleName, chainB)
s.Require().NoError(err)
s.Require().NotNil(authority)
msg := clienttypes.NewMsgUpdateParams(authority.String(), clienttypes.NewParams(exported.Tendermint, "some-client"))
s.ExecuteAndPassGovV1Proposal(ctx, msg, chainB, chainBWallet)
})
t.Run("query params", func(t *testing.T) {
clientParamsResp, err := query.GRPCQuery[clienttypes.QueryClientParamsResponse](ctx, chainB, &clienttypes.QueryClientParamsRequest{})
s.Require().NoError(err)
allowedClients := clientParamsResp.Params.AllowedClients
s.Require().Len(allowedClients, 2)
s.Require().Contains(allowedClients, exported.Tendermint)
s.Require().Contains(allowedClients, "some-client")
})
t.Run("query human readable ibc denom", func(t *testing.T) {
s.AssertHumanReadableDenom(ctx, chainB, chainADenom, channelA)
})
t.Run("IBC token transfer from chainA to chainB, to make sure the upgrade did not break the packet flow", func(t *testing.T) {
transferTxResp := s.Transfer(ctx, chainA, chainAWallet, channelA.PortID, channelA.ChannelID, testvalues.DefaultTransferAmount(chainADenom), chainAAddress, chainBAddress, s.GetTimeoutHeight(ctx, chainB), 0, "")
s.AssertTxSuccess(transferTxResp)
})
t.Run("packets are relayed", func(t *testing.T) {
s.AssertPacketRelayed(ctx, chainA, channelA.PortID, channelA.ChannelID, 1)
actualBalance, err := chainB.GetBalance(ctx, chainBAddress, chainBIBCToken.IBCDenom())
s.Require().NoError(err)
expected := testvalues.IBCTransferAmount * 2
s.Require().Equal(expected, actualBalance.Int64())
})
}
func (s *UpgradeTestSuite) TestV8ToV8_1ChainUpgrade() {
t := s.T()
ctx := context.Background()
testName := t.Name()
relayer := s.CreatePaths(ibc.DefaultClientOpts(), s.TransferChannelOptions(), testName)
channelA := s.GetChainAChannelForTest(testName)
chainA, chainB := s.GetChains()
chainADenom := chainA.Config().Denom
chainAWallet := s.CreateUserOnChainA(ctx, testvalues.StartingTokenAmount)
chainAAddress := chainAWallet.FormattedAddress()
chainBWallet := s.CreateUserOnChainB(ctx, testvalues.StartingTokenAmount)
chainBAddress := chainBWallet.FormattedAddress()
s.Require().NoError(test.WaitForBlocks(ctx, 1, chainA, chainB), "failed to wait for blocks")
t.Run("transfer native tokens from chainA to chainB", func(t *testing.T) {
txResp := s.Transfer(ctx, chainA, chainAWallet, channelA.PortID, channelA.ChannelID, testvalues.DefaultTransferAmount(chainADenom), chainAAddress, chainBAddress, s.GetTimeoutHeight(ctx, chainB), 0, "")
s.AssertTxSuccess(txResp)
})
t.Run("tokens are escrowed", func(t *testing.T) {
actualBalance, err := s.GetChainANativeBalance(ctx, chainAWallet)
s.Require().NoError(err)
expected := testvalues.StartingTokenAmount - testvalues.IBCTransferAmount
s.Require().Equal(expected, actualBalance)
})
t.Run("upgrade chain", func(t *testing.T) {
testCfg := testsuite.LoadConfig()
proposalWallet := s.CreateUserOnChainA(ctx, testvalues.StartingTokenAmount)
s.UpgradeChain(ctx, chainA.(*cosmos.CosmosChain), proposalWallet, testCfg.GetUpgradeConfig().PlanName, testCfg.ChainConfigs[0].Tag, testCfg.GetUpgradeConfig().Tag)
})
t.Run("start relayer", func(t *testing.T) {
s.StartRelayer(relayer, testName)
})
chainBIBCToken := testsuite.GetIBCToken(chainADenom, channelA.Counterparty.PortID, channelA.Counterparty.ChannelID)
t.Run("packet is relayed", func(t *testing.T) {
s.AssertPacketRelayed(ctx, chainA, channelA.PortID, channelA.ChannelID, 1)
actualBalance, err := query.Balance(ctx, chainB, chainBAddress, chainBIBCToken.IBCDenom())
s.Require().NoError(err)
expected := testvalues.IBCTransferAmount
s.Require().Equal(expected, actualBalance.Int64())
})
s.Require().NoError(test.WaitForBlocks(ctx, 5, chainA), "failed to wait for blocks")
t.Run("IBC token transfer from chainA to chainB, to make sure the upgrade did not break the packet flow", func(t *testing.T) {
transferTxResp := s.Transfer(ctx, chainA, chainAWallet, channelA.PortID, channelA.ChannelID, testvalues.DefaultTransferAmount(chainADenom), chainAAddress, chainBAddress, s.GetTimeoutHeight(ctx, chainB), 0, "")
s.AssertTxSuccess(transferTxResp)
})
t.Run("packets are relayed", func(t *testing.T) {
s.AssertPacketRelayed(ctx, chainA, channelA.PortID, channelA.ChannelID, 1)
actualBalance, err := chainB.GetBalance(ctx, chainBAddress, chainBIBCToken.IBCDenom())
s.Require().NoError(err)
expected := testvalues.IBCTransferAmount * 2
s.Require().Equal(expected, actualBalance.Int64())
})
}
func (s *UpgradeTestSuite) TestV8ToV10ChainUpgrade() {
t := s.T()
testCfg := testsuite.LoadConfig()
ctx := context.Background()
testName := t.Name()
relayer, channelA := s.CreateUpgradeTestPath(testName)
chainA, chainB := s.GetChains()
chainADenom := chainA.Config().Denom
chainBDenom := chainB.Config().Denom
chainAWallet := s.CreateUserOnChainA(ctx, testvalues.StartingTokenAmount)
chainAAddress := chainAWallet.FormattedAddress()
chainBWallet := s.CreateUserOnChainB(ctx, testvalues.StartingTokenAmount)
chainBAddress := chainBWallet.FormattedAddress()
chainAIBCToken := testsuite.GetIBCToken(chainBDenom, channelA.PortID, channelA.ChannelID)
chainBIBCToken := testsuite.GetIBCToken(chainADenom, channelA.Counterparty.PortID, channelA.Counterparty.ChannelID)
s.Require().NoError(test.WaitForBlocks(ctx, 1, chainA, chainB), "failed to wait for blocks")
t.Run("start relayer", func(t *testing.T) {
s.StartRelayer(relayer, testName)
})
t.Run("transfer native tokens from chainA to chainB", func(t *testing.T) {
transferTxResp := s.Transfer(ctx, chainA, chainAWallet, channelA.PortID, channelA.ChannelID, testvalues.DefaultTransferAmount(chainADenom), chainAAddress, chainBAddress, s.GetTimeoutHeight(ctx, chainB), 0, "")
s.AssertTxSuccess(transferTxResp)
s.AssertPacketRelayed(ctx, chainA, channelA.PortID, channelA.ChannelID, 1)
actualBalance, err := query.Balance(ctx, chainB, chainBAddress, chainBIBCToken.IBCDenom())
s.Require().NoError(err)
expected := testvalues.IBCTransferAmount
s.Require().Equal(expected, actualBalance.Int64())
})
t.Run("transfer native tokens from chainB to chainA", func(t *testing.T) {
transferTxResp := s.Transfer(ctx, chainB, chainBWallet, channelA.Counterparty.PortID, channelA.Counterparty.ChannelID, testvalues.DefaultTransferAmount(chainBDenom), chainBAddress, chainAAddress, s.GetTimeoutHeight(ctx, chainA.(*cosmos.CosmosChain)), 0, "")
s.AssertTxSuccess(transferTxResp)
s.AssertPacketRelayed(ctx, chainA, channelA.Counterparty.PortID, channelA.Counterparty.ChannelID, 1)
actualBalance, err := query.Balance(ctx, chainA, chainAAddress, chainAIBCToken.IBCDenom())
s.Require().NoError(err)
expected := testvalues.IBCTransferAmount
s.Require().Equal(expected, actualBalance.Int64())
})
s.Require().NoError(test.WaitForBlocks(ctx, 5, chainA), "failed to wait for blocks")
t.Run("stop relayer", func(t *testing.T) {
s.StopRelayer(ctx, relayer)
})
t.Run("upgrade chain", func(t *testing.T) {
govProposalWallet := s.CreateUserOnChainA(ctx, testvalues.StartingTokenAmount)
s.UpgradeChain(ctx, chainA.(*cosmos.CosmosChain), govProposalWallet, testCfg.GetUpgradeConfig().PlanName, testCfg.ChainConfigs[0].Tag, testCfg.GetUpgradeConfig().Tag)
})
t.Run("start relayer", func(t *testing.T) {
s.StartRelayer(relayer, testName)
})
t.Run("query denoms after upgrade", func(t *testing.T) {
resp, err := query.TransferDenoms(ctx, chainA)
s.Require().NoError(err)
s.Require().Len(resp.Denoms, 1)
s.Require().Equal(chainAIBCToken, resp.Denoms[0])
})
t.Run("IBC token transfer from chainA to chainB, to make sure the upgrade did not break the packet flow", func(t *testing.T) {
transferTxResp := s.Transfer(ctx, chainA, chainAWallet, channelA.PortID, channelA.ChannelID, testvalues.DefaultTransferAmount(chainADenom), chainAAddress, chainBAddress, s.GetTimeoutHeight(ctx, chainB), 0, "")
s.AssertTxSuccess(transferTxResp)
s.AssertPacketRelayed(ctx, chainA, channelA.PortID, channelA.ChannelID, 2)
actualBalance, err := chainB.GetBalance(ctx, chainBAddress, chainBIBCToken.IBCDenom())
s.Require().NoError(err)
expected := testvalues.IBCTransferAmount * 2
s.Require().Equal(expected, actualBalance.Int64())
})
}
func (s *UpgradeTestSuite) TestV8ToV10ChainUpgrade_Localhost() {
t := s.T()
testCfg := testsuite.LoadConfig()
ctx := context.Background()
chainA, chainB := s.GetChains()
chainADenom := chainA.Config().Denom
rlyWallet := s.CreateUserOnChainA(ctx, testvalues.StartingTokenAmount)
userAWallet := s.CreateUserOnChainA(ctx, testvalues.StartingTokenAmount)
userBWallet := s.CreateUserOnChainA(ctx, testvalues.StartingTokenAmount)
var (
srcChannelID string
dstChannelID string
)
s.Require().NoError(test.WaitForBlocks(ctx, 1, chainA, chainB), "failed to wait for blocks")
t.Run("open localhost channel", func(t *testing.T) {
var (
msgChanOpenInitRes channeltypes.MsgChannelOpenInitResponse
msgChanOpenTryRes channeltypes.MsgChannelOpenTryResponse
)
msgChanOpenInit := channeltypes.NewMsgChannelOpenInit(
transfertypes.PortID, transfertypes.V1,
channeltypes.UNORDERED, []string{exported.LocalhostConnectionID},
transfertypes.PortID, rlyWallet.FormattedAddress(),
)
txResp := s.BroadcastMessages(ctx, chainA, rlyWallet, msgChanOpenInit)
s.AssertTxSuccess(txResp)
s.Require().NoError(testsuite.UnmarshalMsgResponses(txResp, &msgChanOpenInitRes))
srcChannelID = msgChanOpenInitRes.ChannelId
msgChanOpenTry := channeltypes.NewMsgChannelOpenTry(
transfertypes.PortID, transfertypes.V1,
channeltypes.UNORDERED, []string{exported.LocalhostConnectionID},
transfertypes.PortID, srcChannelID,
transfertypes.V1, localhost.SentinelProof, clienttypes.ZeroHeight(), rlyWallet.FormattedAddress(),
)
txResp = s.BroadcastMessages(ctx, chainA, rlyWallet, msgChanOpenTry)
s.AssertTxSuccess(txResp)
s.Require().NoError(testsuite.UnmarshalMsgResponses(txResp, &msgChanOpenTryRes))
dstChannelID = msgChanOpenTryRes.ChannelId
msgChanOpenAck := channeltypes.NewMsgChannelOpenAck(
transfertypes.PortID, srcChannelID,
dstChannelID, transfertypes.V1,
localhost.SentinelProof, clienttypes.ZeroHeight(), rlyWallet.FormattedAddress(),
)
txResp = s.BroadcastMessages(ctx, chainA, rlyWallet, msgChanOpenAck)
s.AssertTxSuccess(txResp)
msgChanOpenConfirm := channeltypes.NewMsgChannelOpenConfirm(
transfertypes.PortID, dstChannelID,
localhost.SentinelProof, clienttypes.ZeroHeight(), rlyWallet.FormattedAddress(),
)
txResp = s.BroadcastMessages(ctx, chainA, rlyWallet, msgChanOpenConfirm)
s.AssertTxSuccess(txResp)
})
t.Run("ibc transfer over localhost", func(t *testing.T) {
txResp := s.Transfer(ctx, chainA, userAWallet, transfertypes.PortID, srcChannelID, testvalues.DefaultTransferAmount(chainADenom), userAWallet.FormattedAddress(), userBWallet.FormattedAddress(), s.GetTimeoutHeight(ctx, chainA), 0, "")
s.AssertTxSuccess(txResp)
packet, err := ibctesting.ParseV1PacketFromEvents(txResp.Events)
s.Require().NoError(err)
s.Require().NotNil(packet)
msgRecvPacket := channeltypes.NewMsgRecvPacket(packet, localhost.SentinelProof, clienttypes.ZeroHeight(), rlyWallet.FormattedAddress())
txResp = s.BroadcastMessages(ctx, chainA, rlyWallet, msgRecvPacket)
s.AssertTxSuccess(txResp)
ack, err := ibctesting.ParseAckFromEvents(txResp.Events)
s.Require().NoError(err)
s.Require().NotNil(ack)
msgAcknowledgement := channeltypes.NewMsgAcknowledgement(packet, ack, localhost.SentinelProof, clienttypes.ZeroHeight(), rlyWallet.FormattedAddress())
txResp = s.BroadcastMessages(ctx, chainA, rlyWallet, msgAcknowledgement)
s.AssertTxSuccess(txResp)
s.AssertPacketRelayed(ctx, chainA, transfertypes.PortID, srcChannelID, 1)
ibcToken := testsuite.GetIBCToken(chainADenom, transfertypes.PortID, dstChannelID)
actualBalance, err := query.Balance(ctx, chainA, userBWallet.FormattedAddress(), ibcToken.IBCDenom())
s.Require().NoError(err)
s.Require().Equal(testvalues.IBCTransferAmount, actualBalance.Int64())
})
t.Run("localhost exists in state before upgrade", func(t *testing.T) {
localhostClientID := exported.LocalhostClientID
if !testvalues.LocalhostWithDashFeatureReleases.IsSupported(chainA.Config().Images[0].Version) {
localhostClientID = exported.Localhost
}
status, err := query.ClientStatus(ctx, chainA, localhostClientID)
s.Require().NoError(err)
s.Require().Equal(exported.Active.String(), status)
state, err := s.ClientState(ctx, chainA, localhostClientID)
s.Require().NoError(err)
s.Require().NotNil(state)
})
t.Run("upgrade chain", func(t *testing.T) {
govProposalWallet := s.CreateUserOnChainA(ctx, testvalues.StartingTokenAmount)
s.UpgradeChain(ctx, chainA.(*cosmos.CosmosChain), govProposalWallet, testCfg.GetUpgradeConfig().PlanName, testCfg.ChainConfigs[0].Tag, testCfg.GetUpgradeConfig().Tag)
})
t.Run("localhost does not exist in state after upgrade", func(t *testing.T) {
localhostClientID := exported.LocalhostClientID
if !testvalues.LocalhostWithDashFeatureReleases.IsSupported(chainA.Config().Images[0].Version) {
localhostClientID = exported.Localhost
}
status, err := query.ClientStatus(ctx, chainA, localhostClientID)
s.Require().NoError(err)
s.Require().Equal(exported.Active.String(), status)
state, err := s.ClientState(ctx, chainA, localhostClientID)
s.Require().Error(err)
s.Require().Nil(state)
})
t.Run("query localhost transfer channel ends after upgrade", func(t *testing.T) {
channelEndA, err := query.Channel(ctx, chainA, transfertypes.PortID, srcChannelID)
s.Require().NoError(err)
s.Require().NotNil(channelEndA)
channelEndB, err := query.Channel(ctx, chainA, transfertypes.PortID, dstChannelID)
s.Require().NoError(err)
s.Require().NotNil(channelEndB)
s.Require().Equal(channelEndA.ConnectionHops, channelEndB.ConnectionHops)
})
t.Run("ibc transfer back over localhost after upgrade", func(t *testing.T) {
ibcToken := testsuite.GetIBCToken(chainADenom, transfertypes.PortID, dstChannelID)
transferCoins := testvalues.DefaultTransferAmount(ibcToken.IBCDenom())
txResp := s.Transfer(ctx, chainA, userBWallet, transfertypes.PortID, dstChannelID, transferCoins, userBWallet.FormattedAddress(), userAWallet.FormattedAddress(), s.GetTimeoutHeight(ctx, chainA), 0, "")
s.AssertTxSuccess(txResp)
packet, err := ibctesting.ParseV1PacketFromEvents(txResp.Events)
s.Require().NoError(err)
s.Require().NotNil(packet)
msgRecvPacket := channeltypes.NewMsgRecvPacket(packet, localhost.SentinelProof, clienttypes.ZeroHeight(), rlyWallet.FormattedAddress())
txResp = s.BroadcastMessages(ctx, chainA, rlyWallet, msgRecvPacket)
s.AssertTxSuccess(txResp)
ack, err := ibctesting.ParseAckFromEvents(txResp.Events)
s.Require().NoError(err)
s.Require().NotNil(ack)
msgAcknowledgement := channeltypes.NewMsgAcknowledgement(packet, ack, localhost.SentinelProof, clienttypes.ZeroHeight(), rlyWallet.FormattedAddress())
txResp = s.BroadcastMessages(ctx, chainA, rlyWallet, msgAcknowledgement)
s.AssertTxSuccess(txResp)
s.AssertPacketRelayed(ctx, chainA, transfertypes.PortID, dstChannelID, 1)
actualBalance, err := query.Balance(ctx, chainA, userAWallet.FormattedAddress(), chainADenom)
s.Require().NoError(err)
s.Require().Equal(testvalues.StartingTokenAmount, actualBalance.Int64())
})
}
// ClientState queries the current ClientState by clientID
func (*UpgradeTestSuite) ClientState(ctx context.Context, chain ibc.Chain, clientID string) (*clienttypes.QueryClientStateResponse, error) {
res, err := query.GRPCQuery[clienttypes.QueryClientStateResponse](ctx, chain, &clienttypes.QueryClientStateRequest{ClientId: clientID})
if err != nil {
return res, err
}
return res, nil
}