Skip to content

Commit

Permalink
e2e: adding ibcwasm e2e upgrade test (cosmos#5333)
Browse files Browse the repository at this point in the history
* e2e: adding ibcwasm e2e upgrade test

* chore: add build tags and update halt height

* ci: add ibcwasm upgrade test to gh workflows

* chore: adding ibcwasm chain upgrade test to e2e workflow exclusions
  • Loading branch information
damiannolan committed Dec 7, 2023
1 parent 87e9d95 commit d76ee9b
Show file tree
Hide file tree
Showing 5 changed files with 184 additions and 2 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/e2e-fork.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ jobs:
- id: set-matrix
run: echo "matrix=$(go run cmd/build_test_matrix/main.go)" >> $GITHUB_OUTPUT
env:
TEST_EXCLUSIONS: 'TestUpgradeTestSuite,TestGrandpaTestSuite'
TEST_EXCLUSIONS: 'TestUpgradeTestSuite,TestGrandpaTestSuite,TestIBCWasmChainUpgrade'

# dynamically build a matrix of test/test suite pairs to run
build-test-matrix-wasm:
Expand Down
14 changes: 14 additions & 0 deletions .github/workflows/e2e-upgrade.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -131,3 +131,17 @@ jobs:
relayer-type: rly
relayer-image: ghcr.io/cosmos/relayer
relayer-tag: latest

upgrade-ibcwasm-v8-hermes:
uses: ./.github/workflows/e2e-test-workflow-call.yml
with:
chain-image: ghcr.io/cosmos/ibc-go-wasm-simd
chain-binary: simd
chain-a-tag: v7.0.0
chain-b-tag: v7.0.0
chain-upgrade-tag: v8.0.0-dev1
upgrade-plan-name: "ibcwasm-v8"
test-entry-point: "IBCWasmUpgradeTestSuite"
test: "TestIBCWasmChainUpgrade"
upload-logs: true
relayer-type: hermes
2 changes: 1 addition & 1 deletion .github/workflows/e2e.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -63,4 +63,4 @@ jobs:
chain-b-tag: '${{ needs.determine-image-tag.outputs.simd-tag }}'
chain-binary: 'simd'
# on regular PRs we won't run upgrade tests.
test-exclusions: 'TestUpgradeTestSuite,TestGrandpaTestSuite'
test-exclusions: 'TestUpgradeTestSuite,TestGrandpaTestSuite,TestIBCWasmChainUpgrade'
157 changes: 157 additions & 0 deletions e2e/tests/wasm/upgrade_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
//go:build !test_e2e

package wasm

import (
"context"
"crypto/sha256"
"encoding/hex"
"fmt"
"io"
"os"
"testing"
"time"

testifysuite "github.com/stretchr/testify/suite"

"github.com/strangelove-ventures/interchaintest/v8/chain/cosmos"
"github.com/strangelove-ventures/interchaintest/v8/ibc"
"github.com/strangelove-ventures/interchaintest/v8/testutil"

upgradetypes "cosmossdk.io/x/upgrade/types"

authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
govtypes "github.com/cosmos/cosmos-sdk/x/gov/types"
"github.com/cosmos/ibc-go/e2e/testsuite"
"github.com/cosmos/ibc-go/e2e/testvalues"
wasmtypes "github.com/cosmos/ibc-go/modules/light-clients/08-wasm/types"
)

const (
haltHeight = uint64(350)
blocksAfterUpgrade = uint64(10)
)

func TestIBCWasmUpgradeTestSuite(t *testing.T) {
testCfg := testsuite.LoadConfig()
if testCfg.UpgradeConfig.Tag == "" || testCfg.UpgradeConfig.PlanName == "" {
t.Fatalf("%s and %s must be set when running an upgrade test", testsuite.ChainUpgradeTagEnv, testsuite.ChainUpgradePlanEnv)
}

// wasm tests require a longer voting period to account for the time it takes to upload a contract.
testvalues.VotingPeriod = time.Minute * 5

testifysuite.Run(t, new(IBCWasmUpgradeTestSuite))
}

type IBCWasmUpgradeTestSuite struct {
testsuite.E2ETestSuite
}

func (s *IBCWasmUpgradeTestSuite) TestIBCWasmChainUpgrade() {
t := s.T()

ctx := context.Background()
chain := s.SetupSingleChain(ctx)
checksum := ""

userWallet := s.CreateUserOnChainA(ctx, testvalues.StartingTokenAmount)
s.Require().NoError(testutil.WaitForBlocks(ctx, 1, chain), "failed to wait for blocks")

t.Run("create and exec store code proposal", func(t *testing.T) {
file, err := os.Open("contracts/ics10_grandpa_cw.wasm.gz")
s.Require().NoError(err)

checksum = s.ExecStoreCodeProposal(ctx, chain.(*cosmos.CosmosChain), userWallet, file)
s.Require().NotEmpty(checksum, "checksum must not be empty")
})

t.Run("upgrade chain", func(t *testing.T) {
testCfg := testsuite.LoadConfig()
s.UpgradeChain(ctx, chain.(*cosmos.CosmosChain), userWallet, testCfg.UpgradeConfig.PlanName, testCfg.ChainConfigs[0].Tag, testCfg.UpgradeConfig.Tag)
})

t.Run("query wasm checksums", func(t *testing.T) {
checksums, err := s.QueryWasmChecksums(ctx, chain)
s.Require().NoError(err)
s.Require().Contains(checksums, checksum)
})
}

// UpgradeChain upgrades a chain to a specific version using the planName provided.
// The software upgrade proposal is broadcast by the provided wallet.
func (s *IBCWasmUpgradeTestSuite) UpgradeChain(ctx context.Context, chain *cosmos.CosmosChain, wallet ibc.Wallet, planName, currentVersion, upgradeVersion string) {
plan := upgradetypes.Plan{
Name: planName,
Height: int64(haltHeight),
Info: fmt.Sprintf("upgrade version test from %s to %s", currentVersion, upgradeVersion),
}

upgradeProposal := upgradetypes.NewSoftwareUpgradeProposal(fmt.Sprintf("upgrade from %s to %s", currentVersion, upgradeVersion), "upgrade chain E2E test", plan)
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 = testutil.WaitForBlocks(timeoutCtx, int(haltHeight-height)+1, chain)
s.Require().Error(err, "chain did not halt at halt height")

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)")

// we are reinitializing the clients because we need to update the hostGRPCAddress after
// the upgrade and subsequent restarting of nodes
s.InitGRPCClients(chain)

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

err = testutil.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")
}

func (s *IBCWasmUpgradeTestSuite) ExecStoreCodeProposal(ctx context.Context, chain *cosmos.CosmosChain, wallet ibc.Wallet, proposalContentReader io.Reader) string {
zippedContent, err := io.ReadAll(proposalContentReader)
s.Require().NoError(err)

computedChecksum := s.extractChecksumFromGzippedContent(zippedContent)

msgStoreCode := wasmtypes.MsgStoreCode{
Signer: authtypes.NewModuleAddress(govtypes.ModuleName).String(),
WasmByteCode: zippedContent,
}

s.ExecuteAndPassGovV1Proposal(ctx, &msgStoreCode, chain, wallet)

checksumBz, err := s.QueryWasmCode(ctx, chain, computedChecksum)
s.Require().NoError(err)

checksum32 := sha256.Sum256(checksumBz)
actualChecksum := hex.EncodeToString(checksum32[:])
s.Require().Equal(computedChecksum, actualChecksum, "checksum returned from query did not match the computed checksum")

return actualChecksum
}

// extractChecksumFromGzippedContent takes a gzipped wasm contract and returns the checksum.
func (s *IBCWasmUpgradeTestSuite) extractChecksumFromGzippedContent(zippedContent []byte) string {
content, err := wasmtypes.Uncompress(zippedContent, wasmtypes.MaxWasmByteSize())
s.Require().NoError(err)

checksum32 := sha256.Sum256(content)
return hex.EncodeToString(checksum32[:])
}
11 changes: 11 additions & 0 deletions e2e/testsuite/grpc_query.go
Original file line number Diff line number Diff line change
Expand Up @@ -425,3 +425,14 @@ func (s *E2ETestSuite) QueryWasmCode(ctx context.Context, chain ibc.Chain, check
}
return res.Data, nil
}

// QueryWasmChecksums queries the wasm code checksums stored within the 08-wasm module.
func (s *E2ETestSuite) QueryWasmChecksums(ctx context.Context, chain ibc.Chain) ([]string, error) {
queryClient := s.GetChainGRCPClients(chain).WasmQueryClient
res, err := queryClient.Checksums(ctx, &wasmtypes.QueryChecksumsRequest{})
if err != nil {
return nil, err
}

return res.Checksums, nil
}

0 comments on commit d76ee9b

Please sign in to comment.