diff --git a/.github/workflows/interchaintest.yml b/.github/workflows/interchaintest.yml index 57d923f2..08a2b9a5 100644 --- a/.github/workflows/interchaintest.yml +++ b/.github/workflows/interchaintest.yml @@ -58,5 +58,20 @@ jobs: uses: actions/checkout@v3 - run: make ictest-ibc + env: + BRANCH_CI: 'latest' + test-upgrade-chain: + runs-on: ubuntu-latest + needs: build-and-push-image + steps: + - name: Set up Go 1.20 + uses: actions/setup-go@v4 + with: + go-version: '1.20' + + - name: checkout code + uses: actions/checkout@v3 + + - run: make ictest-upgrade env: BRANCH_CI: 'latest' \ No newline at end of file diff --git a/Makefile b/Makefile index 43936cb3..ea946e97 100644 --- a/Makefile +++ b/Makefile @@ -101,12 +101,16 @@ docker-build-debug: # Executes start chain tests via interchaintest ictest-start-cosmos: - cd tests/interchaintest && go test -race -v -run TestStartMigaloo . + cd interchaintest && go test -race -v -run TestStartMigaloo . ictest-ibc: - cd tests/interchaintest && go test -race -v -run TestMigalooGaiaIBCTransfer . + cd interchaintest && go test -race -v -run TestMigalooGaiaIBCTransfer . + +# Executes Basic Upgrade Chain tests via interchaintest +ictest-upgrade: + cd interchaintest && go test -timeout=25m -race -v -run TestMigalooUpgrade . # Executes all tests via interchaintest after compling a local image as migaloo:local -ictest-all: ictest-start-cosmos ictest-ibc +ictest-all: ictest-start-cosmos ictest-ibc ictest-upgrade -.PHONY: ictest-start-cosmos ictest-ibc ictest-all +.PHONY: ictest-start-cosmos ictest-ibc ictest-upgrade ictest-all diff --git a/go.work.example b/go.work.example index e140c715..97175630 100644 --- a/go.work.example +++ b/go.work.example @@ -2,5 +2,5 @@ go 1.20 use ( . - ./tests/interchaintest + ./interchaintest ) \ No newline at end of file diff --git a/tests/interchaintest/chain_start_test.go b/interchaintest/chain_start_test.go similarity index 100% rename from tests/interchaintest/chain_start_test.go rename to interchaintest/chain_start_test.go diff --git a/tests/interchaintest/go.mod b/interchaintest/go.mod similarity index 97% rename from tests/interchaintest/go.mod rename to interchaintest/go.mod index c0f57dac..c54aad8c 100644 --- a/tests/interchaintest/go.mod +++ b/interchaintest/go.mod @@ -1,9 +1,10 @@ -module github.com/White-Whale-Defi-Platform/migaloo-chain/tests/interchaintest +module github.com/White-Whale-Defi-Platform/migaloo-chain/interchaintest go 1.20 require ( github.com/cosmos/ibc-go/v5 v5.3.1 + github.com/icza/dyno v0.0.0-20220812133438-f0b6f8a18845 github.com/strangelove-ventures/interchaintest/v5 v5.0.0-20230811013402-d7955286ba12 github.com/stretchr/testify v1.8.4 go.uber.org/zap v1.24.0 @@ -97,7 +98,6 @@ require ( github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d // indirect github.com/hashicorp/hcl v1.0.0 // indirect github.com/hdevalence/ed25519consensus v0.1.0 // indirect - github.com/icza/dyno v0.0.0-20220812133438-f0b6f8a18845 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/ipfs/go-cid v0.2.0 // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect @@ -205,10 +205,10 @@ replace ( github.com/ChainSafe/go-schnorrkel => github.com/ChainSafe/go-schnorrkel v0.0.0-20200405005733-88cbf1b4c40d github.com/ChainSafe/go-schnorrkel/1 => github.com/ChainSafe/go-schnorrkel v1.0.0 github.com/gogo/protobuf => github.com/regen-network/protobuf v1.3.3-alpha.regen.1 - github.com/strangelove-ventures/interchaintest/v5 => github.com/notional-labs/interchaintest/v5 v5.0.0-20230915033529-179203c903bb + github.com/strangelove-ventures/interchaintest/v5 => github.com/notional-labs/interchaintest/v5 v5.0.0-20230915102917-769835b8dbac github.com/tendermint/tendermint => github.com/cometbft/cometbft v0.34.27 // github.com/tidwall/btree => github.com/tidwall/btree v1.5.0 github.com/vedhavyas/go-subkey => github.com/strangelove-ventures/go-subkey v1.0.7 ) -replace github.com/White-Whale-Defi-Platform/migaloo-chain/ => ../../ +replace github.com/White-Whale-Defi-Platform/migaloo-chain/ => ../ diff --git a/tests/interchaintest/go.sum b/interchaintest/go.sum similarity index 99% rename from tests/interchaintest/go.sum rename to interchaintest/go.sum index 99e51ce7..f08be639 100644 --- a/tests/interchaintest/go.sum +++ b/interchaintest/go.sum @@ -480,8 +480,8 @@ github.com/multiformats/go-varint v0.0.6 h1:gk85QWKxh3TazbLxED/NlDVv8+q+ReFJk7Y2 github.com/multiformats/go-varint v0.0.6/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= -github.com/notional-labs/interchaintest/v5 v5.0.0-20230915033529-179203c903bb h1:gBu5uODQkeWTVl49uHsSIxItVX7zbnqvKjzws/eOq74= -github.com/notional-labs/interchaintest/v5 v5.0.0-20230915033529-179203c903bb/go.mod h1:JCEkazqkTCsW1q1MuUcqxEa3cnPq/5ILaW23KK8ABpc= +github.com/notional-labs/interchaintest/v5 v5.0.0-20230915102917-769835b8dbac h1:WpxJfIYKaBjEGevZEiY03WFJjhSu+epizerGTYFT6oM= +github.com/notional-labs/interchaintest/v5 v5.0.0-20230915102917-769835b8dbac/go.mod h1:JCEkazqkTCsW1q1MuUcqxEa3cnPq/5ILaW23KK8ABpc= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= diff --git a/tests/interchaintest/ibc_transfer_test.go b/interchaintest/ibc_transfer_test.go similarity index 100% rename from tests/interchaintest/ibc_transfer_test.go rename to interchaintest/ibc_transfer_test.go diff --git a/tests/interchaintest/setup.go b/interchaintest/setup.go similarity index 100% rename from tests/interchaintest/setup.go rename to interchaintest/setup.go diff --git a/interchaintest/upgrade_chain_test.go b/interchaintest/upgrade_chain_test.go new file mode 100644 index 00000000..7aa29b18 --- /dev/null +++ b/interchaintest/upgrade_chain_test.go @@ -0,0 +1,174 @@ +package interchaintest + +import ( + "context" + "encoding/json" + "fmt" + "testing" + "time" + + "github.com/icza/dyno" + interchaintest "github.com/strangelove-ventures/interchaintest/v5" + "github.com/strangelove-ventures/interchaintest/v5/chain/cosmos" + "github.com/strangelove-ventures/interchaintest/v5/ibc" + "github.com/strangelove-ventures/interchaintest/v5/testutil" + "github.com/stretchr/testify/require" + "go.uber.org/zap/zaptest" +) + +const ( + haltHeightDelta = uint64(20) + blocksAfterUpgrade = uint64(10) + heightDelta = uint64(20) + votingPeriod = "30s" + maxDepositPeriod = "10s" +) + +func TestMigalooUpgrade(t *testing.T) { + repo, version := GetDockerImageInfo() + CosmosChainUpgradeTest(t, repo, version, "v3") +} + +func CosmosChainUpgradeTest(t *testing.T, upgradeContainerRepo, upgradeVersion, upgradeName string) { + if testing.Short() { + t.Skip("skipping in short mode") + } + + t.Parallel() + + cf := interchaintest.NewBuiltinChainFactory(zaptest.NewLogger(t), []*interchaintest.ChainSpec{ + { + ChainConfig: ibc.ChainConfig{ + Type: "cosmos", + Name: "migaloo", + ChainID: "migaloo-2", + Images: []ibc.DockerImage{ + { + Repository: "ghcr.io/white-whale-defi-platform/migaloo-chain", + Version: "2.2.6", + UidGid: "1025:1025", + }, + }, + Bin: "migalood", + Bech32Prefix: "migaloo", + Denom: "stake", + GasPrices: "0.00stake", + GasAdjustment: 1.3, + TrustingPeriod: "504h", + // EncodingConfig: WasmClientEncoding(), + NoHostMount: true, + ModifyGenesis: modifyGenesisShortProposals(votingPeriod, maxDepositPeriod), + }, + }, + }) + + chains, err := cf.Chains(t.Name()) + require.NoError(t, err) + + chain := chains[0].(*cosmos.CosmosChain) + + ic := interchaintest.NewInterchain(). + AddChain(chain) + + ctx := context.Background() + client, network := interchaintest.DockerSetup(t) + + require.NoError(t, ic.Build(ctx, nil, interchaintest.InterchainBuildOptions{ + TestName: t.Name(), + Client: client, + NetworkID: network, + // BlockDatabaseFile: interchaintest.DefaultBlockDatabaseFilepath(), + SkipPathCreation: true, + })) + t.Cleanup(func() { + _ = ic.Close() + }) + + const userFunds = int64(10_000_000_000) + users := interchaintest.GetAndFundTestUsers(t, ctx, t.Name(), userFunds, chain) + chainUser := users[0] + + height, err := chain.Height(ctx) + require.NoError(t, err, "error fetching height before submit upgrade proposal") + + haltHeight := height + haltHeightDelta + + proposal := cosmos.SoftwareUpgradeProposal{ + Deposit: "500000000" + chain.Config().Denom, // greater than min deposit + Title: "Chain Upgrade 1", + Name: upgradeName, + Description: "First chain software upgrade", + Height: haltHeight, + Info: "UPGRADE", + } + + upgradeTx, err := chain.UpgradeProposal(ctx, chainUser.KeyName(), proposal) + require.NoError(t, err, "error submitting software upgrade proposal tx") + + err = chain.VoteOnProposalAllValidators(ctx, upgradeTx.ProposalID, cosmos.ProposalVoteYes) + require.NoError(t, err, "failed to submit votes") + + _, err = cosmos.PollForProposalStatus(ctx, chain, height, haltHeight, upgradeTx.ProposalID, cosmos.ProposalStatusPassed) + require.NoError(t, err, "proposal status did not change to passed in expected number of blocks") + + timeoutCtx, timeoutCtxCancel := context.WithTimeout(ctx, time.Second*45) + defer timeoutCtxCancel() + + height, err = chain.Height(ctx) + require.NoError(t, err, "error fetching height before upgrade") + + // this should timeout due to chain halt at upgrade height. + _ = testutil.WaitForBlocks(timeoutCtx, int(haltHeight-height)+1, chain) + + height, err = chain.Height(ctx) + require.NoError(t, err, "error fetching height after chain should have halted") + + // make sure that chain is halted + require.Equal(t, haltHeight, height, "height is not equal to halt height") + + // bring down nodes to prepare for upgrade + err = chain.StopAllNodes(ctx) + require.NoError(t, err, "error stopping node(s)") + + // upgrade version on all nodes + chain.UpgradeVersion(ctx, client, upgradeContainerRepo, upgradeVersion) + + // start all nodes back up. + // validators reach consensus on first block after upgrade height + // and chain block production resumes. + err = chain.StartAllNodes(ctx) + require.NoError(t, err, "error starting upgraded node(s)") + + timeoutCtx, timeoutCtxCancel = context.WithTimeout(ctx, time.Second*45) + defer timeoutCtxCancel() + + err = testutil.WaitForBlocks(timeoutCtx, int(blocksAfterUpgrade), chain) + require.NoError(t, err, "chain did not produce blocks after upgrade") + + height, err = chain.Height(ctx) + require.NoError(t, err, "error fetching height after upgrade") + + require.GreaterOrEqual(t, height, haltHeight+blocksAfterUpgrade, "height did not increment enough after upgrade") +} +func modifyGenesisShortProposals(votingPeriod, maxDepositPeriod string) func(ibc.ChainConfig, []byte) ([]byte, error) { + return func(chainConfig ibc.ChainConfig, genbz []byte) ([]byte, error) { + g := make(map[string]interface{}) + if err := json.Unmarshal(genbz, &g); err != nil { + return nil, fmt.Errorf("failed to unmarshal genesis file: %w", err) + } + if err := dyno.Set(g, votingPeriod, "app_state", "gov", "params", "voting_period"); err != nil { + return nil, fmt.Errorf("failed to set voting period in genesis json: %w", err) + } + if err := dyno.Set(g, maxDepositPeriod, "app_state", "gov", "params", "max_deposit_period"); err != nil { + return nil, fmt.Errorf("failed to set voting period in genesis json: %w", err) + } + if err := dyno.Set(g, chainConfig.Denom, "app_state", "gov", "params", "min_deposit", 0, "denom"); err != nil { + return nil, fmt.Errorf("failed to set voting period in genesis json: %w", err) + } + out, err := json.Marshal(g) + if err != nil { + return nil, fmt.Errorf("failed to marshal genesis bytes to json: %w", err) + } + return out, nil + } +}