Skip to content

Commit

Permalink
test: e2e upgrade tests for v8 -> v9 (cosmos#6791)
Browse files Browse the repository at this point in the history
* test: upgrade v8 to v9

* remove temporary code from debugging

* add to e2e ci + cr fixes
  • Loading branch information
gjermundgaraba authored Jul 10, 2024
1 parent 9ff8ddb commit 575902b
Show file tree
Hide file tree
Showing 9 changed files with 331 additions and 14 deletions.
44 changes: 44 additions & 0 deletions .github/workflows/e2e-upgrade.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -159,3 +159,47 @@ jobs:
test: "TestIBCWasmChainUpgrade"
upload-logs: true
relayer-type: hermes

upgrade-v9-hermes:
uses: ./.github/workflows/e2e-test-workflow-call.yml
with:
chain-image: ghcr.io/cosmos/ibc-go-simd
chain-binary: simd
chain-a-tag: v8.3.2
chain-b-tag: v8.3.2
chain-upgrade-tag: pr-6791 # TODO: Update tag to v9.0.0 once it is (pre)released
upgrade-plan-name: "v9"
test-entry-point: "TestUpgradeTestSuite"
test: "TestV8ToV9ChainUpgrade"
upload-logs: true
relayer-type: hermes

upgrade-v9-rly:
uses: ./.github/workflows/e2e-test-workflow-call.yml
with:
chain-image: ghcr.io/cosmos/ibc-go-simd
chain-binary: simd
chain-a-tag: v8.3.2
chain-b-tag: v8.3.2
chain-upgrade-tag: pr-6791 # TODO: Update tag to v9.0.0 once it is (pre)released
upgrade-plan-name: "v9"
test-entry-point: "TestUpgradeTestSuite"
test: "TestV8ToV9ChainUpgrade"
upload-logs: true
relayer-type: rly
relayer-image: ghcr.io/cosmos/relayer
relayer-tag: latest

upgrade-v9-localhost:
uses: ./.github/workflows/e2e-test-workflow-call.yml
with:
chain-image: ghcr.io/cosmos/ibc-go-simd
chain-binary: simd
chain-a-tag: v8.3.2
chain-b-tag: v8.3.2
chain-upgrade-tag: pr-6791 # TODO: Update tag to v9.0.0 once it is (pre)released
upgrade-plan-name: "v9"
test-entry-point: "TestUpgradeTestSuite"
test: "TestV8ToV9ChainUpgrade_Localhost"
upload-logs: true
relayer-type: hermes
2 changes: 2 additions & 0 deletions e2e/tests/upgrades/genesis_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@ type GenesisTestSuite struct {
func (s *GenesisTestSuite) TestIBCGenesis() {
t := s.T()

haltHeight := int64(100)

chainA, chainB := s.GetChains()

ctx := context.Background()
Expand Down
266 changes: 256 additions & 10 deletions e2e/tests/upgrades/upgrade_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,17 +28,19 @@ import (
"github.com/cosmos/ibc-go/e2e/testsuite/query"
"github.com/cosmos/ibc-go/e2e/testvalues"
feetypes "github.com/cosmos/ibc-go/v8/modules/apps/29-fee/types"
transfertypes "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types"
v7migrations "github.com/cosmos/ibc-go/v8/modules/core/02-client/migrations/v7"
clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types"
connectiontypes "github.com/cosmos/ibc-go/v8/modules/core/03-connection/types"
channeltypes "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types"
"github.com/cosmos/ibc-go/v8/modules/core/exported"
solomachine "github.com/cosmos/ibc-go/v8/modules/light-clients/06-solomachine"
localhost "github.com/cosmos/ibc-go/v8/modules/light-clients/09-localhost"
ibctesting "github.com/cosmos/ibc-go/v8/testing"
)

const (
haltHeight = int64(100)
haltHeightOffset = int64(30)
blocksAfterUpgrade = uint64(10)
)

Expand All @@ -62,6 +64,10 @@ func (s *UpgradeTestSuite) CreateUpgradeTestPath(testName string) (ibc.Relayer,
// 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,
Expand All @@ -80,14 +86,14 @@ func (s *UpgradeTestSuite) UpgradeChain(ctx context.Context, chain *cosmos.Cosmo
s.ExecuteAndPassGovV1Beta1Proposal(ctx, chain, wallet, upgradeProposal)
}

height, err := chain.Height(ctx)
s.Require().NoError(err, "error fetching height before upgrade")

timeoutCtx, timeoutCtxCancel := context.WithTimeout(ctx, time.Minute*2)
defer timeoutCtxCancel()

err = test.WaitForBlocks(timeoutCtx, int(haltHeight-height)+1, chain)
s.Require().Error(err, "chain did not halt at halt height")
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() {
Expand All @@ -106,7 +112,7 @@ func (s *UpgradeTestSuite) UpgradeChain(ctx context.Context, chain *cosmos.Cosmo
err = chain.StartAllNodes(ctx)
s.Require().NoError(err, "error starting upgraded node(s)")

timeoutCtx, timeoutCtxCancel = context.WithTimeout(ctx, time.Minute*2)
timeoutCtx, timeoutCtxCancel := context.WithTimeout(ctx, time.Minute*2)
defer timeoutCtxCancel()

err = test.WaitForBlocks(timeoutCtx, int(blocksAfterUpgrade), chain)
Expand Down Expand Up @@ -1031,6 +1037,246 @@ func (s *UpgradeTestSuite) TestV8ToV8_1ChainUpgrade_ChannelUpgrades() {
})
}

func (s *UpgradeTestSuite) TestV8ToV9ChainUpgrade() {
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.DefaultTransferCoins(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.DefaultTransferCoins(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("upgrade chain", func(t *testing.T) {
govProposalWallet := s.CreateUserOnChainA(ctx, testvalues.StartingTokenAmount)
s.UpgradeChain(ctx, chainA.(*cosmos.CosmosChain), govProposalWallet, testCfg.UpgradeConfig.PlanName, testCfg.ChainConfigs[0].Tag, testCfg.UpgradeConfig.Tag)
})

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.DefaultTransferCoins(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) TestV8ToV9ChainUpgrade_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.DefaultTransferCoins(chainADenom), userAWallet.FormattedAddress(), userBWallet.FormattedAddress(), s.GetTimeoutHeight(ctx, chainA), 0, "")
s.AssertTxSuccess(txResp)

packet, err := ibctesting.ParsePacketFromEvents(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) {
status, err := query.ClientStatus(ctx, chainA, exported.LocalhostClientID)
s.Require().NoError(err)
s.Require().Equal(exported.Active.String(), status)

state, err := s.ClientState(ctx, chainA, exported.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.UpgradeConfig.PlanName, testCfg.ChainConfigs[0].Tag, testCfg.UpgradeConfig.Tag)
})

t.Run("localhost does not exist in state after upgrade", func(t *testing.T) {
status, err := query.ClientStatus(ctx, chainA, exported.LocalhostClientID)
s.Require().NoError(err)
s.Require().Equal(exported.Active.String(), status)

state, err := s.ClientState(ctx, chainA, exported.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.DefaultTransferCoins(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.ParsePacketFromEvents(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})
Expand Down
7 changes: 6 additions & 1 deletion e2e/testsuite/query/grpc_query.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,11 @@ func GRPCQuery[T any](ctx context.Context, chain ibc.Chain, req proto.Message, o
return nil, err
}

return grpcQueryWithMethod[T](ctx, chain, req, path, opts...)
}

// grpcQueryWithMethod queries the chain with a query request with a specific method (grpc path) and deserializes the response to T
func grpcQueryWithMethod[T any](ctx context.Context, chain ibc.Chain, req proto.Message, method string, opts ...grpc.CallOption) (*T, error) {
// Create a connection to the gRPC server.
grpcConn, err := grpc.Dial(
chain.GetHostGRPCAddress(),
Expand All @@ -30,7 +35,7 @@ func GRPCQuery[T any](ctx context.Context, chain ibc.Chain, req proto.Message, o
defer grpcConn.Close()

resp := new(T)
err = grpcConn.Invoke(ctx, path, req, resp, opts...)
err = grpcConn.Invoke(ctx, method, req, resp, opts...)
if err != nil {
return nil, err
}
Expand Down
Loading

0 comments on commit 575902b

Please sign in to comment.