From 7a356c24e2c7eea0c56aa1e6654a499c1c392d45 Mon Sep 17 00:00:00 2001 From: Alex Peters Date: Thu, 17 Aug 2023 16:19:48 +0200 Subject: [PATCH 01/27] Start chain upgrade tests --- app/upgrades.go | 2 +- tests/system/.gitignore | 1 + tests/system/cli.go | 2 +- tests/system/genesis_io.go | 10 +++ tests/system/main_test.go | 6 +- tests/system/staking_test.go | 2 +- tests/system/system.go | 136 +++++++++++++++++++++++++++-------- tests/system/upgrade_test.go | 135 ++++++++++++++++++++++++++++++++++ 8 files changed, 258 insertions(+), 36 deletions(-) create mode 100644 tests/system/upgrade_test.go diff --git a/app/upgrades.go b/app/upgrades.go index 992621cae0..2738c011d3 100644 --- a/app/upgrades.go +++ b/app/upgrades.go @@ -15,7 +15,7 @@ import ( // NOTE: This upgrade defines a reference implementation of what an upgrade // could look like when an application is migrating from Cosmos SDK version // v0.47.x to v0.50.x. -const UpgradeName = "v047-to-v050" +const UpgradeName = "my chain upgrade" func (app WasmApp) RegisterUpgradeHandlers() { app.UpgradeKeeper.SetUpgradeHandler( diff --git a/tests/system/.gitignore b/tests/system/.gitignore index 73423081ac..22873da42d 100644 --- a/tests/system/.gitignore +++ b/tests/system/.gitignore @@ -1 +1,2 @@ /testnet +/binaries diff --git a/tests/system/cli.go b/tests/system/cli.go index 949df64d97..0634b72453 100644 --- a/tests/system/cli.go +++ b/tests/system/cli.go @@ -48,7 +48,7 @@ type WasmdCli struct { func NewWasmdCLI(t *testing.T, sut *SystemUnderTest, verbose bool) *WasmdCli { return NewWasmdCLIx( t, - sut.execBinary, + sut.ExecBinary, sut.rpcAddr, sut.chainID, sut.AwaitNextBlock, diff --git a/tests/system/genesis_io.go b/tests/system/genesis_io.go index 4b286304d2..0e75c85655 100644 --- a/tests/system/genesis_io.go +++ b/tests/system/genesis_io.go @@ -3,6 +3,7 @@ package system import ( "fmt" "testing" + "time" "github.com/stretchr/testify/require" "github.com/tidwall/gjson" @@ -46,3 +47,12 @@ func SetCodeUploadPermission(t *testing.T, permission string, addresses ...strin return []byte(state) } } + +func SetGovVotingPeriod(t *testing.T, period time.Duration) GenesisMutator { + return func(genesis []byte) []byte { + t.Helper() + state, err := sjson.SetRawBytes(genesis, "app_state.gov.params.voting_period", []byte(fmt.Sprintf("%q", period.String()))) + require.NoError(t, err) + return state + } +} diff --git a/tests/system/main_test.go b/tests/system/main_test.go index e806addd4f..046f2977b2 100644 --- a/tests/system/main_test.go +++ b/tests/system/main_test.go @@ -19,8 +19,9 @@ import ( ) var ( - sut *SystemUnderTest - verbose bool + sut *SystemUnderTest + verbose bool + execBinaryName string ) func TestMain(m *testing.M) { @@ -50,6 +51,7 @@ func TestMain(m *testing.M) { if *execBinary == "" { panic("executable binary name must not be empty") } + execBinaryName = *execBinary sut = NewSystemUnderTest(*execBinary, verbose, *nodesCount, *blockTime) if *rebuild { sut.BuildNewBinary() diff --git a/tests/system/staking_test.go b/tests/system/staking_test.go index 32c80b5f23..d5f3bacb68 100644 --- a/tests/system/staking_test.go +++ b/tests/system/staking_test.go @@ -21,7 +21,7 @@ func TestStakeUnstake(t *testing.T) { // add genesis account with some tokens account1Addr := cli.AddKey("account1") sut.ModifyGenesisCLI(t, - []string{"genesis", "add-genesis-account", account1Addr, "100000000stake"}, + []string{"genesis", "add-genesis-account", account1Addr, "10000000stake"}, ) sut.StartChain(t) diff --git a/tests/system/system.go b/tests/system/system.go index e05451a5da..d101cef533 100644 --- a/tests/system/system.go +++ b/tests/system/system.go @@ -13,6 +13,7 @@ import ( "strconv" "strings" "sync/atomic" + "syscall" "testing" "time" @@ -32,7 +33,7 @@ var workDir string // SystemUnderTest blockchain provisioning type SystemUnderTest struct { - execBinary string + ExecBinary string blockListener *EventListener currentHeight int64 chainID string @@ -48,16 +49,21 @@ type SystemUnderTest struct { out io.Writer verbose bool ChainStarted bool + projectName string dirty bool // requires full reset when marked dirty + + pidsLock sync.RWMutex + pids []int } func NewSystemUnderTest(execBinary string, verbose bool, nodesCount int, blockTime time.Duration) *SystemUnderTest { if execBinary == "" { panic("executable binary name must not be empty") } + xxx := "wasmd" // todo: extract unversioned name from ExecBinary return &SystemUnderTest{ chainID: "testing", - execBinary: execBinary, + ExecBinary: execBinary, outputDir: "./testnet", blockTime: blockTime, rpcAddr: "tcp://localhost:26657", @@ -67,6 +73,7 @@ func NewSystemUnderTest(execBinary string, verbose bool, nodesCount int, blockTi out: os.Stdout, verbose: verbose, minGasPrice: fmt.Sprintf("0.000001%s", sdk.DefaultBondDenom), + projectName: xxx, } } @@ -88,9 +95,9 @@ func (s *SystemUnderTest) SetupChain() { "--starting-ip-address", "", // empty to use host systems "--single-host", } - fmt.Printf("+++ %s %s\n", s.execBinary, strings.Join(args, " ")) + fmt.Printf("+++ %s %s\n", s.ExecBinary, strings.Join(args, " ")) cmd := exec.Command( //nolint:gosec - locateExecutable(s.execBinary), + locateExecutable(s.ExecBinary), args..., ) cmd.Dir = workDir @@ -135,7 +142,7 @@ func (s *SystemUnderTest) StartChain(t *testing.T, xargs ...string) { t.Helper() s.Log("Start chain\n") s.ChainStarted = true - s.forEachNodesExecAsync(t, append([]string{"start", "--trace", "--log_level=info"}, xargs...)...) + s.startNodesAsync(t, append([]string{"start", "--trace", "--log_level=info"}, xargs...)...) s.AwaitNodeUp(t, s.rpcAddr) @@ -216,6 +223,12 @@ func isLogNoise(text string) bool { return false } +func (s *SystemUnderTest) AwaitChainStopped() { + for s.anyNodeRunning() { + time.Sleep(s.blockTime) + } +} + // AwaitNodeUp ensures the node is running func (s *SystemUnderTest) AwaitNodeUp(t *testing.T, rpcAddr string) { t.Helper() @@ -264,29 +277,41 @@ func (s *SystemUnderTest) StopChain() { } s.cleanupFn = nil // send SIGTERM - cmd := exec.Command(locateExecutable("pkill"), "-15", s.execBinary) //nolint:gosec - cmd.Dir = workDir - if _, err := cmd.CombinedOutput(); err != nil { - s.Logf("failed to stop chain: %s\n", err) + s.pidsLock.RLock() + for _, pid := range s.pids { + p, err := os.FindProcess(pid) + if err != nil { + continue + } + if err := p.Signal(syscall.Signal(15)); err == nil { + s.Logf("failed to stop node with pid %d: %s\n", pid, err) + } } - + s.pidsLock.RUnlock() var shutdown bool for timeout := time.NewTimer(500 * time.Millisecond).C; !shutdown; { select { case <-timeout: s.Log("killing nodes now") - cmd = exec.Command(locateExecutable("pkill"), "-9", s.execBinary) //nolint:gosec - cmd.Dir = workDir - if _, err := cmd.CombinedOutput(); err != nil { - s.Logf("failed to kill process: %s\n", err) + s.pidsLock.RLock() + for _, pid := range s.pids { + p, err := os.FindProcess(pid) + if err != nil { + continue + } + if err := p.Kill(); err == nil { + s.Logf("failed to kill node with pid %d: %s\n", pid, err) + } } + s.pidsLock.RUnlock() shutdown = true default: - if err := exec.Command(locateExecutable("pgrep"), s.execBinary).Run(); err != nil { //nolint:gosec - shutdown = true - } + shutdown = shutdown || s.anyNodeRunning() } } + s.pidsLock.Lock() + s.pids = nil + s.pidsLock.Unlock() s.ChainStarted = false } @@ -317,6 +342,30 @@ func (s SystemUnderTest) BuildNewBinary() { } } +// AwaitBlockHeight blocks until te target height is reached. An optional timout parameter can be passed to abort early +func (s *SystemUnderTest) AwaitBlockHeight(t *testing.T, targetHeight int64, timeout ...time.Duration) { + t.Helper() + require.Greater(t, targetHeight, s.currentHeight) + var maxWaitTime time.Duration + if len(timeout) != 0 { + maxWaitTime = timeout[0] + } else { + maxWaitTime = time.Duration(targetHeight-s.currentHeight+3) * s.blockTime + } + abort := time.NewTimer(maxWaitTime).C + for { + select { + case <-abort: + t.Fatalf("Timeout - block %d not reached within %s", targetHeight, maxWaitTime) + return + default: + if current := s.AwaitNextBlock(t); current == targetHeight { + return + } + } + } +} + // AwaitNextBlock is a first class function that any caller can use to ensure a new block was minted. // Returns the new height func (s *SystemUnderTest) AwaitNextBlock(t *testing.T, timeout ...time.Duration) int64 { @@ -454,9 +503,9 @@ func (s *SystemUnderTest) ForEachNodeExecAndWait(t *testing.T, cmds ...[]string) result[i] = make([]string, len(cmds)) for j, xargs := range cmds { xargs = append(xargs, "--home", home) - s.Logf("Execute `%s %s`\n", s.execBinary, strings.Join(xargs, " ")) + s.Logf("Execute `%s %s`\n", s.ExecBinary, strings.Join(xargs, " ")) cmd := exec.Command( //nolint:gosec - locateExecutable(s.execBinary), + locateExecutable(s.ExecBinary), xargs..., ) cmd.Dir = workDir @@ -469,22 +518,40 @@ func (s *SystemUnderTest) ForEachNodeExecAndWait(t *testing.T, cmds ...[]string) return result } -// forEachNodesExecAsync runs the given app cli command for all cluster nodes and returns without waiting -func (s *SystemUnderTest) forEachNodesExecAsync(t *testing.T, xargs ...string) []func() error { - r := make([]func() error, s.nodesCount) +// startNodesAsync runs the given app cli command for all cluster nodes and returns without waiting +func (s *SystemUnderTest) startNodesAsync(t *testing.T, xargs ...string) { s.withEachNodeHome(func(i int, home string) { args := append(xargs, "--home", home) //nolint:gocritic - s.Logf("Execute `%s %s`\n", s.execBinary, strings.Join(args, " ")) + s.Logf("Execute `%s %s`\n", s.ExecBinary, strings.Join(args, " ")) cmd := exec.Command( //nolint:gosec - locateExecutable(s.execBinary), + locateExecutable(s.ExecBinary), args..., ) cmd.Dir = workDir s.watchLogs(i, cmd) require.NoError(t, cmd.Start(), "node %d", i) - r[i] = cmd.Wait + + s.pidsLock.Lock() + s.pids = append(s.pids, cmd.Process.Pid) + s.pidsLock.Unlock() + + // cleanup when stopped + go func() { + _ = cmd.Wait() + s.pidsLock.Lock() + defer s.pidsLock.Unlock() + if len(s.pids) == 0 { + return + } + newPids := make([]int, 0, len(s.pids)-1) + for _, p := range s.pids { + if p != cmd.Process.Pid { + newPids = append(newPids, p) + } + } + s.pids = newPids + }() }) - return r } func (s SystemUnderTest) withEachNodeHome(cb func(i int, home string)) { @@ -495,7 +562,7 @@ func (s SystemUnderTest) withEachNodeHome(cb func(i int, home string)) { // nodePath returns the path of the node within the work dir. not absolute func (s SystemUnderTest) nodePath(i int) string { - return fmt.Sprintf("%s/node%d/%s", s.outputDir, i, s.execBinary) + return fmt.Sprintf("%s/node%d/%s", s.outputDir, i, s.projectName) } func (s SystemUnderTest) Log(msg string) { @@ -553,9 +620,9 @@ func (s *SystemUnderTest) AddFullnode(t *testing.T, beforeStart ...func(nodeNumb // prepare new node moniker := fmt.Sprintf("node%d", nodeNumber) args := []string{"init", moniker, "--home", nodePath, "--overwrite"} - s.Logf("Execute `%s %s`\n", s.execBinary, strings.Join(args, " ")) + s.Logf("Execute `%s %s`\n", s.ExecBinary, strings.Join(args, " ")) cmd := exec.Command( //nolint:gosec - locateExecutable(s.execBinary), + locateExecutable(s.ExecBinary), args..., ) cmd.Dir = workDir @@ -590,9 +657,9 @@ func (s *SystemUnderTest) AddFullnode(t *testing.T, beforeStart ...func(nodeNumb "--log_level=info", "--home", nodePath, } - s.Logf("Execute `%s %s`\n", s.execBinary, strings.Join(args, " ")) + s.Logf("Execute `%s %s`\n", s.ExecBinary, strings.Join(args, " ")) cmd = exec.Command( //nolint:gosec - locateExecutable(s.execBinary), + locateExecutable(s.ExecBinary), args..., ) cmd.Dir = workDir @@ -606,6 +673,13 @@ func (s *SystemUnderTest) NewEventListener(t *testing.T) *EventListener { return NewEventListener(t, s.rpcAddr) } +// is any process let running? +func (s *SystemUnderTest) anyNodeRunning() bool { + s.pidsLock.RLock() + defer s.pidsLock.RUnlock() + return len(s.pids) != 0 +} + type Node struct { ID string IP string diff --git a/tests/system/upgrade_test.go b/tests/system/upgrade_test.go new file mode 100644 index 0000000000..c88c43bcc9 --- /dev/null +++ b/tests/system/upgrade_test.go @@ -0,0 +1,135 @@ +//go:build system_test + +package system + +import ( + "archive/tar" + "compress/gzip" + "fmt" + "io" + "net/http" + "os" + "path/filepath" + "testing" + "time" + + "github.com/stretchr/testify/require" + "github.com/tidwall/gjson" +) + +func TestChainUpgrade(t *testing.T) { + // Scenario: + // start a legacy chain with some state + // when a chain upgrade proposal is executed + // then the chain upgrades successfully + + // todo: this test works only with linux, currently + legacyBinary := FetchExecutable(t, "v0.41.0") + t.Logf("+++ legacy binary: %s\n", legacyBinary) + targetBinary := sut.ExecBinary + sut.ExecBinary = legacyBinary + sut.SetupChain() + votingPeriod := 15 * time.Second + sut.ModifyGenesisJSON(t, SetGovVotingPeriod(t, votingPeriod)) + + const upgradeHeight int64 = 20 // + sut.StartChain(t, fmt.Sprintf("--halt-height=%d", upgradeHeight-1)) + + cli := NewWasmdCLI(t, sut, verbose) + + // todo: set some state to ensure that migrations work + + // submit upgrade proposal + // todo: all of this can be moved into the test_cli to make it more readable in the tests + upgradeName := "my chain upgrade" + proposal := fmt.Sprintf(` +{ + "messages": [ + { + "@type": "/cosmos.upgrade.v1beta1.MsgSoftwareUpgrade", + "authority": "wasm10d07y265gmmuvt4z0w9aw880jnsr700js7zslc", + "plan": { + "name": %q, + "height": "%d" + } + } + ], + "metadata": "ipfs://CID", + "deposit": "100000000stake", + "title": "my upgrade", + "summary": "testing" +}`, upgradeName, upgradeHeight) + pathToProposal := filepath.Join(t.TempDir(), "proposal.json") + err := os.WriteFile(pathToProposal, []byte(proposal), os.FileMode(0o744)) + require.NoError(t, err) + t.Log("Submit upgrade proposal") + rsp := cli.CustomCommand("tx", "gov", "submit-proposal", pathToProposal, "--from", cli.GetKeyAddr(defaultSrcAddr)) + RequireTxSuccess(t, rsp) + raw := cli.CustomQuery("q", "gov", "proposals", "--depositor", cli.GetKeyAddr(defaultSrcAddr)) + proposals := gjson.Get(raw, "proposals.#.id").Array() + require.NotEmpty(t, proposals, raw) + ourProposalID := proposals[len(proposals)-1].String() // last is ours + sut.withEachNodeHome(func(n int, _ string) { + t.Logf("Voting: validator %d\n", n) + rsp = cli.CustomCommand("tx", "gov", "vote", ourProposalID, "yes", "--from", cli.GetKeyAddr(fmt.Sprintf("node%d", n))) + RequireTxSuccess(t, rsp) + }) + t.Logf("current_height: %d\n", sut.currentHeight) + raw = cli.CustomQuery("q", "gov", "proposal", ourProposalID) + t.Log(raw) + + sut.AwaitChainStopped() + t.Log("Upgrade height was reached. Upgrading chain") + sut.ExecBinary = targetBinary + sut.StartChain(t) + // todo: ensure that state matches expectations +} + +const cacheDir = "binaries" + +// FetchExecutable to download and extract tar.gz for linux +func FetchExecutable(t *testing.T, version string) string { + // use local cache + cacheFile := filepath.Join(workDir, cacheDir, fmt.Sprintf("%s_%s", execBinaryName, version)) + if _, err := os.Stat(cacheFile); err == nil { + return cacheFile + } + t.Logf("+++ version not in cache, downloading from github") + + // then download from GH releases: only works with Linux currently as we are not publishing OSX binaries + const releaseUrl = "https://github.com/CosmWasm/wasmd/releases/download/%s/wasmd-%s-linux-amd64.tar.gz" + destDir := t.TempDir() + rsp, err := http.Get(fmt.Sprintf(releaseUrl, version, version)) + require.NoError(t, err) + defer rsp.Body.Close() + gzr, err := gzip.NewReader(rsp.Body) + require.NoError(t, err) + defer gzr.Close() + tr := tar.NewReader(gzr) + + var workFileName string + for { + header, err := tr.Next() + switch { + case err == io.EOF: + require.NotEmpty(t, workFileName) + require.NoError(t, os.Rename(workFileName, cacheFile)) + return cacheFile + case err != nil: + require.NoError(t, err) + case header == nil: + continue + } + workFileName = filepath.Join(destDir, header.Name) + switch header.Typeflag { + case tar.TypeDir: + t.Fatalf("unexpected type") + case tar.TypeReg: + f, err := os.OpenFile(workFileName, os.O_CREATE|os.O_RDWR, os.FileMode(0o755)) + require.NoError(t, err) + _, err = io.Copy(f, tr) + require.NoError(t, err) + _ = f.Close() + } + } +} From a66a0dcbf5b7d5841f22bd537ea850e4621a3c44 Mon Sep 17 00:00:00 2001 From: Pino' Surace Date: Fri, 18 Aug 2023 12:40:15 +0200 Subject: [PATCH 02/27] Fix stakeunstake test --- tests/system/staking_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/system/staking_test.go b/tests/system/staking_test.go index d5f3bacb68..5e5df6df3c 100644 --- a/tests/system/staking_test.go +++ b/tests/system/staking_test.go @@ -35,7 +35,7 @@ func TestStakeUnstake(t *testing.T) { RequireTxSuccess(t, rsp) t.Log(cli.QueryBalance(account1Addr, "stake")) - assert.Equal(t, int64(99989999), cli.QueryBalance(account1Addr, "stake")) + assert.Equal(t, int64(9989999), cli.QueryBalance(account1Addr, "stake")) rsp = cli.CustomQuery("q", "staking", "delegation", account1Addr, valAddr) assert.Equal(t, "10000", gjson.Get(rsp, "delegation_response.balance.amount").String(), rsp) From 045f65564820821cdf03c0cc1ebba0a45578291a Mon Sep 17 00:00:00 2001 From: Pino' Surace Date: Mon, 21 Aug 2023 17:17:04 +0200 Subject: [PATCH 03/27] Make test pass --- tests/system/upgrade_test.go | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/tests/system/upgrade_test.go b/tests/system/upgrade_test.go index c88c43bcc9..e4f07d26ce 100644 --- a/tests/system/upgrade_test.go +++ b/tests/system/upgrade_test.go @@ -90,7 +90,13 @@ const cacheDir = "binaries" // FetchExecutable to download and extract tar.gz for linux func FetchExecutable(t *testing.T, version string) string { // use local cache - cacheFile := filepath.Join(workDir, cacheDir, fmt.Sprintf("%s_%s", execBinaryName, version)) + cacheFolder := filepath.Join(workDir, cacheDir) + err := os.MkdirAll(cacheFolder, 0777) + if err != nil && !os.IsExist(err) { + panic(err) + } + + cacheFile := filepath.Join(cacheFolder, fmt.Sprintf("%s_%s", execBinaryName, version)) if _, err := os.Stat(cacheFile); err == nil { return cacheFile } From 5ac9787325bf458498437b7ca324c48e1220d6c6 Mon Sep 17 00:00:00 2001 From: Alex Peters Date: Fri, 29 Sep 2023 13:14:59 +0200 Subject: [PATCH 04/27] Better stop chain --- tests/system/cli.go | 20 ++-- tests/system/cli_test.go | 9 +- tests/system/fraud_test.go | 4 +- tests/system/main_test.go | 7 +- tests/system/system.go | 185 ++++++++++++++++++----------------- tests/system/upgrade_test.go | 6 +- 6 files changed, 118 insertions(+), 113 deletions(-) diff --git a/tests/system/cli.go b/tests/system/cli.go index 0634b72453..7fc419c35b 100644 --- a/tests/system/cli.go +++ b/tests/system/cli.go @@ -10,17 +10,17 @@ import ( "testing" "time" - codectypes "github.com/cosmos/cosmos-sdk/codec/types" - "github.com/cosmos/cosmos-sdk/std" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "github.com/tidwall/gjson" + "golang.org/x/exp/slices" "github.com/cosmos/cosmos-sdk/client/grpc/cmtservice" "github.com/cosmos/cosmos-sdk/codec" + codectypes "github.com/cosmos/cosmos-sdk/codec/types" cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" + "github.com/cosmos/cosmos-sdk/std" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - "github.com/tidwall/gjson" - "golang.org/x/exp/slices" ) type ( @@ -52,7 +52,7 @@ func NewWasmdCLI(t *testing.T, sut *SystemUnderTest, verbose bool) *WasmdCli { sut.rpcAddr, sut.chainID, sut.AwaitNextBlock, - filepath.Join(workDir, sut.outputDir), + filepath.Join(WorkDir, sut.outputDir), "1"+sdk.DefaultBondDenom, verbose, assert.NoError, @@ -211,7 +211,7 @@ func (c WasmdCli) runWithInput(args []string, input io.Reader) (output string, o } }() cmd := exec.Command(locateExecutable("wasmd"), args...) //nolint:gosec - cmd.Dir = workDir + cmd.Dir = WorkDir cmd.Stdin = input return cmd.CombinedOutput() }() @@ -236,7 +236,7 @@ func (c WasmdCli) withTXFlags(args ...string) []string { } func (c WasmdCli) withKeyringFlags(args ...string) []string { - r := append(args, //nolint:gocritic + r := append(args, "--home", c.homeDir, "--keyring-backend", "test", ) @@ -262,7 +262,7 @@ func (c WasmdCli) WasmExecute(contractAddr, msg, from string, args ...string) st // AddKey add key to default keyring. Returns address func (c WasmdCli) AddKey(name string) string { - cmd := c.withKeyringFlags("keys", "add", name) //, "--no-backup") + cmd := c.withKeyringFlags("keys", "add", name, "--no-backup") out, _ := c.run(cmd) addr := gjson.Get(out, "address").String() require.NotEmpty(c.t, addr, "got %q", out) diff --git a/tests/system/cli_test.go b/tests/system/cli_test.go index fd001dc6bf..09b8b7b080 100644 --- a/tests/system/cli_test.go +++ b/tests/system/cli_test.go @@ -9,12 +9,13 @@ import ( "testing" "time" - sdkmath "cosmossdk.io/math" - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/tidwall/gjson" + + sdkmath "cosmossdk.io/math" + + sdk "github.com/cosmos/cosmos-sdk/types" ) func TestUnsafeResetAll(t *testing.T) { @@ -23,7 +24,7 @@ func TestUnsafeResetAll(t *testing.T) { // when `unsafe-reset-all` is executed // then the dir and all files in it are removed - wasmDir := filepath.Join(workDir, sut.nodePath(0), "wasm") + wasmDir := filepath.Join(WorkDir, sut.nodePath(0), "wasm") require.NoError(t, os.MkdirAll(wasmDir, os.ModePerm)) _, err := os.CreateTemp(wasmDir, "testing") diff --git a/tests/system/fraud_test.go b/tests/system/fraud_test.go index 9e5e4d61d5..65e4335d24 100644 --- a/tests/system/fraud_test.go +++ b/tests/system/fraud_test.go @@ -7,9 +7,9 @@ import ( "math" "testing" - sdkmath "cosmossdk.io/math" - "github.com/stretchr/testify/require" + + sdkmath "cosmossdk.io/math" ) func TestRecursiveMsgsExternalTrigger(t *testing.T) { diff --git a/tests/system/main_test.go b/tests/system/main_test.go index 046f2977b2..85d2e7f483 100644 --- a/tests/system/main_test.go +++ b/tests/system/main_test.go @@ -14,6 +14,7 @@ import ( "time" "github.com/cometbft/cometbft/libs/rand" + sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/address" ) @@ -41,9 +42,9 @@ func TestMain(m *testing.M) { if err != nil { panic(err) } - workDir = dir + WorkDir = dir if verbose { - println("Work dir: ", workDir) + println("Work dir: ", WorkDir) } initSDKConfig(*bech32Prefix) @@ -80,7 +81,7 @@ func requireEnoughFileHandlers(nodesCount int) { } cmd := exec.Command(ulimit, "-n") - cmd.Dir = workDir + cmd.Dir = WorkDir out, err := cmd.CombinedOutput() if err != nil { panic(fmt.Sprintf("unexpected error :%#+v, output: %s", err, string(out))) diff --git a/tests/system/system.go b/tests/system/system.go index d101cef533..b41426fcf4 100644 --- a/tests/system/system.go +++ b/tests/system/system.go @@ -10,6 +10,7 @@ import ( "os" "os/exec" "path/filepath" + "regexp" "strconv" "strings" "sync/atomic" @@ -17,19 +18,24 @@ import ( "testing" "time" - sdk "github.com/cosmos/cosmos-sdk/types" - - "github.com/tidwall/sjson" - "github.com/cometbft/cometbft/libs/sync" client "github.com/cometbft/cometbft/rpc/client/http" ctypes "github.com/cometbft/cometbft/rpc/core/types" tmtypes "github.com/cometbft/cometbft/types" - "github.com/cosmos/cosmos-sdk/server" "github.com/stretchr/testify/require" + "github.com/tidwall/sjson" + + "github.com/cosmos/cosmos-sdk/server" + sdk "github.com/cosmos/cosmos-sdk/types" ) -var workDir string +var ( + // WorkDir is the directory where tests are executed. Path should be relative to this dir + WorkDir string + + // ExecBinaryUnversionedRegExp regular expression to extract the unversioned binary name + ExecBinaryUnversionedRegExp = regexp.MustCompile(`^(\w+)-?.*$`) +) // SystemUnderTest blockchain provisioning type SystemUnderTest struct { @@ -53,14 +59,18 @@ type SystemUnderTest struct { dirty bool // requires full reset when marked dirty pidsLock sync.RWMutex - pids []int + pids map[int]struct{} } func NewSystemUnderTest(execBinary string, verbose bool, nodesCount int, blockTime time.Duration) *SystemUnderTest { if execBinary == "" { panic("executable binary name must not be empty") } - xxx := "wasmd" // todo: extract unversioned name from ExecBinary + nameTokens := ExecBinaryUnversionedRegExp.FindAllString(execBinary, 1) + if len(nameTokens) == 0 || nameTokens[0] == "" { + panic("failed to parse project name from binary") + } + return &SystemUnderTest{ chainID: "testing", ExecBinary: execBinary, @@ -73,13 +83,14 @@ func NewSystemUnderTest(execBinary string, verbose bool, nodesCount int, blockTi out: os.Stdout, verbose: verbose, minGasPrice: fmt.Sprintf("0.000001%s", sdk.DefaultBondDenom), - projectName: xxx, + projectName: nameTokens[0], + pids: make(map[int]struct{}, nodesCount), } } func (s *SystemUnderTest) SetupChain() { s.Logf("Setup chain: %s\n", s.outputDir) - if err := os.RemoveAll(filepath.Join(workDir, s.outputDir)); err != nil { + if err := os.RemoveAll(filepath.Join(WorkDir, s.outputDir)); err != nil { panic(err.Error()) } @@ -100,7 +111,7 @@ func (s *SystemUnderTest) SetupChain() { locateExecutable(s.ExecBinary), args..., ) - cmd.Dir = workDir + cmd.Dir = WorkDir out, err := cmd.CombinedOutput() if err != nil { panic(fmt.Sprintf("unexpected error :%#+v, output: %s", err, string(out))) @@ -109,7 +120,7 @@ func (s *SystemUnderTest) SetupChain() { s.nodesCount = s.initialNodesCount // modify genesis with system test defaults - src := filepath.Join(workDir, s.nodePath(0), "config", "genesis.json") + src := filepath.Join(WorkDir, s.nodePath(0), "config", "genesis.json") genesisBz, err := os.ReadFile(src) if err != nil { panic(fmt.Sprintf("failed to load genesis: %s", err)) @@ -126,13 +137,13 @@ func (s *SystemUnderTest) SetupChain() { }) // backup genesis - dest := filepath.Join(workDir, s.nodePath(0), "config", "genesis.json.orig") + dest := filepath.Join(WorkDir, s.nodePath(0), "config", "genesis.json.orig") if _, err := copyFile(src, dest); err != nil { panic(fmt.Sprintf("copy failed :%#+v", err)) } // backup keyring - src = filepath.Join(workDir, s.nodePath(0), "keyring-test") - dest = filepath.Join(workDir, s.outputDir, "keyring-test") + src = filepath.Join(WorkDir, s.nodePath(0), "keyring-test") + dest = filepath.Join(WorkDir, s.outputDir, "keyring-test") if err := copyFilesInDir(src, dest); err != nil { panic(fmt.Sprintf("copy files from dir :%#+v", err)) } @@ -165,13 +176,13 @@ func (s *SystemUnderTest) MarkDirty() { } // IsDirty true when non default genesis or other state modification were applied that might create incompatibility for tests -func (s SystemUnderTest) IsDirty() bool { +func (s *SystemUnderTest) IsDirty() bool { return s.dirty } // watchLogs stores stdout/stderr in a file and in a ring buffer to output the last n lines on test error func (s *SystemUnderTest) watchLogs(node int, cmd *exec.Cmd) { - logfile, err := os.Create(filepath.Join(workDir, s.outputDir, fmt.Sprintf("node%d.out", node))) + logfile, err := os.Create(filepath.Join(WorkDir, s.outputDir, fmt.Sprintf("node%d.out", node))) if err != nil { panic(fmt.Sprintf("open logfile error %#+v", err)) } @@ -277,46 +288,44 @@ func (s *SystemUnderTest) StopChain() { } s.cleanupFn = nil // send SIGTERM - s.pidsLock.RLock() - for _, pid := range s.pids { - p, err := os.FindProcess(pid) - if err != nil { - continue + s.withEachPid(func(p *os.Process) { + if err := p.Signal(syscall.SIGTERM); err != nil { + s.Logf("failed to stop node with pid %d: %s\n", p.Pid, err) } - if err := p.Signal(syscall.Signal(15)); err == nil { - s.Logf("failed to stop node with pid %d: %s\n", pid, err) + }) + // give some final time to shut down + s.withEachPid(func(p *os.Process) { + time.Sleep(200 * time.Millisecond) + }) + // goodbye + s.withEachPid(func(p *os.Process) { + s.Logf("killing node %d\n", p.Pid) + if err := p.Kill(); err != nil { + s.Logf("failed to kill node with pid %d: %s\n", p.Pid, err) } + }) + for s.anyNodeRunning() { + time.Sleep(100 * time.Millisecond) } + s.ChainStarted = false +} + +func (s *SystemUnderTest) withEachPid(cb func(p *os.Process)) { + s.pidsLock.RLock() + pids := s.pids s.pidsLock.RUnlock() - var shutdown bool - for timeout := time.NewTimer(500 * time.Millisecond).C; !shutdown; { - select { - case <-timeout: - s.Log("killing nodes now") - s.pidsLock.RLock() - for _, pid := range s.pids { - p, err := os.FindProcess(pid) - if err != nil { - continue - } - if err := p.Kill(); err == nil { - s.Logf("failed to kill node with pid %d: %s\n", pid, err) - } - } - s.pidsLock.RUnlock() - shutdown = true - default: - shutdown = shutdown || s.anyNodeRunning() + + for pid := range pids { + p, err := os.FindProcess(pid) + if err != nil { + continue } + cb(p) } - s.pidsLock.Lock() - s.pids = nil - s.pidsLock.Unlock() - s.ChainStarted = false } // PrintBuffer prints the chain logs to the console -func (s SystemUnderTest) PrintBuffer() { +func (s *SystemUnderTest) PrintBuffer() { s.outBuff.Do(func(v interface{}) { if v != nil { fmt.Fprintf(s.out, "out> %s\n", v) @@ -331,11 +340,11 @@ func (s SystemUnderTest) PrintBuffer() { } // BuildNewBinary builds and installs new executable binary -func (s SystemUnderTest) BuildNewBinary() { +func (s *SystemUnderTest) BuildNewBinary() { s.Log("Install binaries\n") makePath := locateExecutable("make") cmd := exec.Command(makePath, "clean", "install") - cmd.Dir = workDir + cmd.Dir = WorkDir out, err := cmd.CombinedOutput() if err != nil { panic(fmt.Sprintf("unexpected error %#v : output: %s", err, string(out))) @@ -403,18 +412,18 @@ func (s *SystemUnderTest) ResetChain(t *testing.T) { t.Helper() t.Log("Reset chain") s.StopChain() - restoreOriginalGenesis(t, *s) - restoreOriginalKeyring(t, *s) + restoreOriginalGenesis(t, s) + restoreOriginalKeyring(t, s) s.resetBuffers() // remove all additional nodes for i := s.initialNodesCount; i < s.nodesCount; i++ { - os.RemoveAll(filepath.Join(workDir, s.nodePath(i))) - os.Remove(filepath.Join(workDir, s.outputDir, fmt.Sprintf("node%d.out", i))) + _ = os.RemoveAll(filepath.Join(WorkDir, s.nodePath(i))) + _ = os.Remove(filepath.Join(WorkDir, s.outputDir, fmt.Sprintf("node%d.out", i))) } s.nodesCount = s.initialNodesCount - // reset all validataor nodes + // reset all validator nodes s.ForEachNodeExecAndWait(t, []string{"tendermint", "unsafe-reset-all"}) s.currentHeight = 0 s.dirty = false @@ -445,7 +454,7 @@ func (s *SystemUnderTest) ModifyGenesisJSON(t *testing.T, mutators ...GenesisMut // modify json without enforcing a reset func (s *SystemUnderTest) modifyGenesisJSON(t *testing.T, mutators ...GenesisMutator) { require.Empty(t, s.currentHeight, "forced chain reset required") - current, err := os.ReadFile(filepath.Join(workDir, s.nodePath(0), "config", "genesis.json")) + current, err := os.ReadFile(filepath.Join(WorkDir, s.nodePath(0), "config", "genesis.json")) require.NoError(t, err) for _, m := range mutators { current = m(current) @@ -458,7 +467,7 @@ func (s *SystemUnderTest) modifyGenesisJSON(t *testing.T, mutators ...GenesisMut // ReadGenesisJSON returns current genesis.json content as raw string func (s *SystemUnderTest) ReadGenesisJSON(t *testing.T) string { - content, err := os.ReadFile(filepath.Join(workDir, s.nodePath(0), "config", "genesis.json")) + content, err := os.ReadFile(filepath.Join(WorkDir, s.nodePath(0), "config", "genesis.json")) require.NoError(t, err) return string(content) } @@ -479,7 +488,7 @@ func (s *SystemUnderTest) setGenesis(t *testing.T, srcPath string) { } func saveGenesis(home string, content []byte) error { - out, err := os.Create(filepath.Join(workDir, home, "config", "genesis.json")) + out, err := os.Create(filepath.Join(WorkDir, home, "config", "genesis.json")) if err != nil { return fmt.Errorf("out file: %w", err) } @@ -508,7 +517,7 @@ func (s *SystemUnderTest) ForEachNodeExecAndWait(t *testing.T, cmds ...[]string) locateExecutable(s.ExecBinary), xargs..., ) - cmd.Dir = workDir + cmd.Dir = WorkDir out, err := cmd.CombinedOutput() require.NoError(t, err, "node %d: %s", i, string(out)) s.Logf("Result: %s\n", string(out)) @@ -521,65 +530,59 @@ func (s *SystemUnderTest) ForEachNodeExecAndWait(t *testing.T, cmds ...[]string) // startNodesAsync runs the given app cli command for all cluster nodes and returns without waiting func (s *SystemUnderTest) startNodesAsync(t *testing.T, xargs ...string) { s.withEachNodeHome(func(i int, home string) { - args := append(xargs, "--home", home) //nolint:gocritic + args := append(xargs, "--home", home) s.Logf("Execute `%s %s`\n", s.ExecBinary, strings.Join(args, " ")) cmd := exec.Command( //nolint:gosec locateExecutable(s.ExecBinary), args..., ) - cmd.Dir = workDir + cmd.Dir = WorkDir s.watchLogs(i, cmd) require.NoError(t, cmd.Start(), "node %d", i) + pid := cmd.Process.Pid s.pidsLock.Lock() - s.pids = append(s.pids, cmd.Process.Pid) + s.pids[pid] = struct{}{} s.pidsLock.Unlock() + s.Logf("Node started: %d\n", pid) // cleanup when stopped go func() { - _ = cmd.Wait() + _ = cmd.Wait() // blocks until shutdown s.pidsLock.Lock() - defer s.pidsLock.Unlock() - if len(s.pids) == 0 { - return - } - newPids := make([]int, 0, len(s.pids)-1) - for _, p := range s.pids { - if p != cmd.Process.Pid { - newPids = append(newPids, p) - } - } - s.pids = newPids + delete(s.pids, pid) + s.pidsLock.Unlock() + s.Logf("Node stopped: %d\n", pid) }() }) } -func (s SystemUnderTest) withEachNodeHome(cb func(i int, home string)) { +func (s *SystemUnderTest) withEachNodeHome(cb func(i int, home string)) { for i := 0; i < s.nodesCount; i++ { cb(i, s.nodePath(i)) } } // nodePath returns the path of the node within the work dir. not absolute -func (s SystemUnderTest) nodePath(i int) string { +func (s *SystemUnderTest) nodePath(i int) string { return fmt.Sprintf("%s/node%d/%s", s.outputDir, i, s.projectName) } -func (s SystemUnderTest) Log(msg string) { +func (s *SystemUnderTest) Log(msg string) { if s.verbose { - fmt.Fprint(s.out, msg) + _, _ = fmt.Fprint(s.out, msg) } } -func (s SystemUnderTest) Logf(msg string, args ...interface{}) { +func (s *SystemUnderTest) Logf(msg string, args ...interface{}) { s.Log(fmt.Sprintf(msg, args...)) } -func (s SystemUnderTest) RPCClient(t *testing.T) RPCClient { +func (s *SystemUnderTest) RPCClient(t *testing.T) RPCClient { return NewRPCClient(t, s.rpcAddr) } -func (s SystemUnderTest) AllPeers(t *testing.T) []string { +func (s *SystemUnderTest) AllPeers(t *testing.T) []string { result := make([]string, s.nodesCount) for i, n := range s.AllNodes(t) { result[i] = n.PeerAddr() @@ -587,7 +590,7 @@ func (s SystemUnderTest) AllPeers(t *testing.T) []string { return result } -func (s SystemUnderTest) AllNodes(t *testing.T) []Node { +func (s *SystemUnderTest) AllNodes(t *testing.T) []Node { result := make([]Node, s.nodesCount) outs := s.ForEachNodeExecAndWait(t, []string{"tendermint", "show-node-id"}) ip, err := server.ExternalIP() @@ -625,15 +628,15 @@ func (s *SystemUnderTest) AddFullnode(t *testing.T, beforeStart ...func(nodeNumb locateExecutable(s.ExecBinary), args..., ) - cmd.Dir = workDir + cmd.Dir = WorkDir s.watchLogs(nodeNumber, cmd) require.NoError(t, cmd.Run(), "failed to start node with id %d", nodeNumber) require.NoError(t, saveGenesis(nodePath, []byte(s.ReadGenesisJSON(t)))) // quick hack: copy config and overwrite by start params - configFile := filepath.Join(workDir, nodePath, "config", "config.toml") + configFile := filepath.Join(WorkDir, nodePath, "config", "config.toml") _ = os.Remove(configFile) - _, err := copyFile(filepath.Join(workDir, s.nodePath(0), "config", "config.toml"), configFile) + _, err := copyFile(filepath.Join(WorkDir, s.nodePath(0), "config", "config.toml"), configFile) require.NoError(t, err) // start node @@ -662,7 +665,7 @@ func (s *SystemUnderTest) AddFullnode(t *testing.T, beforeStart ...func(nodeNumb locateExecutable(s.ExecBinary), args..., ) - cmd.Dir = workDir + cmd.Dir = WorkDir s.watchLogs(nodeNumber, cmd) require.NoError(t, cmd.Start(), "node %d", nodeNumber) return node @@ -847,17 +850,17 @@ func CaptureAllEventsConsumer(t *testing.T, optMaxWaitTime ...time.Duration) (c } // restoreOriginalGenesis replace nodes genesis by the one created on setup -func restoreOriginalGenesis(t *testing.T, s SystemUnderTest) { - src := filepath.Join(workDir, s.nodePath(0), "config", "genesis.json.orig") +func restoreOriginalGenesis(t *testing.T, s *SystemUnderTest) { + src := filepath.Join(WorkDir, s.nodePath(0), "config", "genesis.json.orig") s.setGenesis(t, src) } // restoreOriginalKeyring replaces test keyring with original -func restoreOriginalKeyring(t *testing.T, s SystemUnderTest) { - dest := filepath.Join(workDir, s.outputDir, "keyring-test") +func restoreOriginalKeyring(t *testing.T, s *SystemUnderTest) { + dest := filepath.Join(WorkDir, s.outputDir, "keyring-test") require.NoError(t, os.RemoveAll(dest)) for i := 0; i < s.initialNodesCount; i++ { - src := filepath.Join(workDir, s.nodePath(i), "keyring-test") + src := filepath.Join(WorkDir, s.nodePath(i), "keyring-test") require.NoError(t, copyFilesInDir(src, dest)) } } diff --git a/tests/system/upgrade_test.go b/tests/system/upgrade_test.go index e4f07d26ce..3ba1067d03 100644 --- a/tests/system/upgrade_test.go +++ b/tests/system/upgrade_test.go @@ -1,4 +1,4 @@ -//go:build system_test +//go:build system_test && linux package system @@ -90,8 +90,8 @@ const cacheDir = "binaries" // FetchExecutable to download and extract tar.gz for linux func FetchExecutable(t *testing.T, version string) string { // use local cache - cacheFolder := filepath.Join(workDir, cacheDir) - err := os.MkdirAll(cacheFolder, 0777) + cacheFolder := filepath.Join(WorkDir, cacheDir) + err := os.MkdirAll(cacheFolder, 0o777) if err != nil && !os.IsExist(err) { panic(err) } From 2a27eac0db977af9844d5370485d898177ba2c0a Mon Sep 17 00:00:00 2001 From: Alex Peters Date: Fri, 29 Sep 2023 16:25:28 +0200 Subject: [PATCH 05/27] Test chain upgrade --- app/upgrades.go | 39 ++++++++++++++++++++++++++++++-- tests/system/system.go | 44 +++++++++++++++++++++++++----------- tests/system/upgrade_test.go | 29 ++++++++++++++++-------- 3 files changed, 88 insertions(+), 24 deletions(-) diff --git a/app/upgrades.go b/app/upgrades.go index 2738c011d3..eaf92b0026 100644 --- a/app/upgrades.go +++ b/app/upgrades.go @@ -3,6 +3,15 @@ package app import ( "context" + circuittypes "cosmossdk.io/x/circuit/types" + paramstypes "github.com/cosmos/cosmos-sdk/x/params/types" + icacontrollertypes "github.com/cosmos/ibc-go/v8/modules/apps/27-interchain-accounts/controller/types" + icahosttypes "github.com/cosmos/ibc-go/v8/modules/apps/27-interchain-accounts/host/types" + ibctransfertypes "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types" + ibcclienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" + ibcconnectiontypes "github.com/cosmos/ibc-go/v8/modules/core/03-connection/types" + ibcexported "github.com/cosmos/ibc-go/v8/modules/core/exported" + storetypes "cosmossdk.io/store/types" upgradetypes "cosmossdk.io/x/upgrade/types" @@ -15,9 +24,33 @@ import ( // NOTE: This upgrade defines a reference implementation of what an upgrade // could look like when an application is migrating from Cosmos SDK version // v0.47.x to v0.50.x. -const UpgradeName = "my chain upgrade" +const UpgradeName = "v0.50.x" func (app WasmApp) RegisterUpgradeHandlers() { + // Set param key table for params module migration + for _, subspace := range app.ParamsKeeper.GetSubspaces() { + + var keyTable paramstypes.KeyTable + switch subspace.Name() { + // ibc types + case ibcexported.ModuleName: + keyTable = ibcclienttypes.ParamKeyTable() + keyTable.RegisterParamSet(&ibcconnectiontypes.Params{}) + case ibctransfertypes.ModuleName: + keyTable = ibctransfertypes.ParamKeyTable() + case icahosttypes.SubModuleName: + keyTable = icahosttypes.ParamKeyTable() + case icacontrollertypes.SubModuleName: + keyTable = icacontrollertypes.ParamKeyTable() + default: + continue + } + + if !subspace.HasKeyTable() { + subspace.WithKeyTable(keyTable) + } + } + app.UpgradeKeeper.SetUpgradeHandler( UpgradeName, func(ctx context.Context, _ upgradetypes.Plan, fromVM module.VersionMap) (module.VersionMap, error) { @@ -31,7 +64,9 @@ func (app WasmApp) RegisterUpgradeHandlers() { } if upgradeInfo.Name == UpgradeName && !app.UpgradeKeeper.IsSkipHeight(upgradeInfo.Height) { - storeUpgrades := storetypes.StoreUpgrades{} + storeUpgrades := storetypes.StoreUpgrades{ + Added: []string{circuittypes.ModuleName}, + } // configure store loader that checks if version == upgradeHeight and applies store upgrades app.SetStoreLoader(upgradetypes.UpgradeStoreLoader(upgradeInfo.Height, &storeUpgrades)) diff --git a/tests/system/system.go b/tests/system/system.go index b41426fcf4..497b9df610 100644 --- a/tests/system/system.go +++ b/tests/system/system.go @@ -234,6 +234,23 @@ func isLogNoise(text string) bool { return false } +// AwaitUpgradeInfo blocks util an upgrade info file is persisted to disk +func (s *SystemUnderTest) AwaitUpgradeInfo(t *testing.T) { + var found bool + for !found { + s.withEachNodeHome(func(i int, home string) { + _, err := os.Stat(filepath.Join(s.nodePath(0), "data", "upgrade-info.json")) + switch { + case err == nil: + found = true + case !os.IsNotExist(err): + t.Fatalf(err.Error()) + } + }) + time.Sleep(s.blockTime) + } +} + func (s *SystemUnderTest) AwaitChainStopped() { for s.anyNodeRunning() { time.Sleep(s.blockTime) @@ -289,23 +306,24 @@ func (s *SystemUnderTest) StopChain() { s.cleanupFn = nil // send SIGTERM s.withEachPid(func(p *os.Process) { - if err := p.Signal(syscall.SIGTERM); err != nil { - s.Logf("failed to stop node with pid %d: %s\n", p.Pid, err) - } + go func() { + if err := p.Signal(syscall.SIGTERM); err != nil { + s.Logf("failed to stop node with pid %d: %s\n", p.Pid, err) + } + }() }) // give some final time to shut down s.withEachPid(func(p *os.Process) { time.Sleep(200 * time.Millisecond) }) // goodbye - s.withEachPid(func(p *os.Process) { - s.Logf("killing node %d\n", p.Pid) - if err := p.Kill(); err != nil { - s.Logf("failed to kill node with pid %d: %s\n", p.Pid, err) - } - }) - for s.anyNodeRunning() { - time.Sleep(100 * time.Millisecond) + for ; s.anyNodeRunning(); time.Sleep(100 * time.Millisecond) { + s.withEachPid(func(p *os.Process) { + s.Logf("killing node %d\n", p.Pid) + if err := p.Kill(); err != nil { + s.Logf("failed to kill node with pid %d: %s\n", p.Pid, err) + } + }) } s.ChainStarted = false } @@ -547,13 +565,13 @@ func (s *SystemUnderTest) startNodesAsync(t *testing.T, xargs ...string) { s.Logf("Node started: %d\n", pid) // cleanup when stopped - go func() { + go func(pid int) { _ = cmd.Wait() // blocks until shutdown s.pidsLock.Lock() delete(s.pids, pid) s.pidsLock.Unlock() s.Logf("Node stopped: %d\n", pid) - }() + }(pid) }) } diff --git a/tests/system/upgrade_test.go b/tests/system/upgrade_test.go index 3ba1067d03..6d9823bfd1 100644 --- a/tests/system/upgrade_test.go +++ b/tests/system/upgrade_test.go @@ -26,14 +26,14 @@ func TestChainUpgrade(t *testing.T) { // todo: this test works only with linux, currently legacyBinary := FetchExecutable(t, "v0.41.0") t.Logf("+++ legacy binary: %s\n", legacyBinary) - targetBinary := sut.ExecBinary + currentBranchBinary := sut.ExecBinary sut.ExecBinary = legacyBinary sut.SetupChain() - votingPeriod := 15 * time.Second + votingPeriod := 10 * time.Second // enough time to vote sut.ModifyGenesisJSON(t, SetGovVotingPeriod(t, votingPeriod)) const upgradeHeight int64 = 20 // - sut.StartChain(t, fmt.Sprintf("--halt-height=%d", upgradeHeight-1)) + sut.StartChain(t, fmt.Sprintf("--halt-height=%d", upgradeHeight)) cli := NewWasmdCLI(t, sut, verbose) @@ -41,7 +41,7 @@ func TestChainUpgrade(t *testing.T) { // submit upgrade proposal // todo: all of this can be moved into the test_cli to make it more readable in the tests - upgradeName := "my chain upgrade" + upgradeName := "v0.50.x" proposal := fmt.Sprintf(` { "messages": [ @@ -70,19 +70,30 @@ func TestChainUpgrade(t *testing.T) { require.NotEmpty(t, proposals, raw) ourProposalID := proposals[len(proposals)-1].String() // last is ours sut.withEachNodeHome(func(n int, _ string) { - t.Logf("Voting: validator %d\n", n) - rsp = cli.CustomCommand("tx", "gov", "vote", ourProposalID, "yes", "--from", cli.GetKeyAddr(fmt.Sprintf("node%d", n))) - RequireTxSuccess(t, rsp) + go func() { // do parallel + t.Logf("Voting: validator %d\n", n) + rsp = cli.CustomCommand("tx", "gov", "vote", ourProposalID, "yes", "--from", cli.GetKeyAddr(fmt.Sprintf("node%d", n))) + RequireTxSuccess(t, rsp) + }() }) + // t.Logf("current_height: %d\n", sut.currentHeight) raw = cli.CustomQuery("q", "gov", "proposal", ourProposalID) t.Log(raw) + sut.AwaitBlockHeight(t, upgradeHeight-1) + t.Logf("current_height: %d\n", sut.currentHeight) + raw = cli.CustomQuery("q", "gov", "proposal", ourProposalID) + t.Log(raw) + + t.Log("waiting for upgrade info") + sut.AwaitUpgradeInfo(t) + sut.StopChain() // just in case - sut.AwaitChainStopped() t.Log("Upgrade height was reached. Upgrading chain") - sut.ExecBinary = targetBinary + sut.ExecBinary = currentBranchBinary sut.StartChain(t) // todo: ensure that state matches expectations + t.Log("Done") } const cacheDir = "binaries" From 46321f81c3d722f103a6b70568c702c0a3653b82 Mon Sep 17 00:00:00 2001 From: Alex Peters Date: Fri, 29 Sep 2023 16:57:09 +0200 Subject: [PATCH 06/27] Set upgrade handler order --- app/app.go | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/app/app.go b/app/app.go index 062d844785..9363e828c1 100644 --- a/app/app.go +++ b/app/app.go @@ -3,6 +3,8 @@ package app import ( "encoding/json" "fmt" + ibcclienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" + ibcconnectiontypes "github.com/cosmos/ibc-go/v8/modules/core/03-connection/types" "io" "os" "path/filepath" @@ -1159,11 +1161,17 @@ func initParamsKeeper(appCodec codec.BinaryCodec, legacyAmino *codec.LegacyAmino paramsKeeper.Subspace(slashingtypes.ModuleName) paramsKeeper.Subspace(govtypes.ModuleName) paramsKeeper.Subspace(crisistypes.ModuleName) - paramsKeeper.Subspace(ibctransfertypes.ModuleName) - paramsKeeper.Subspace(ibcexported.ModuleName) - paramsKeeper.Subspace(icahosttypes.SubModuleName) - paramsKeeper.Subspace(icacontrollertypes.SubModuleName) + //paramsKeeper.Subspace(ibctransfertypes.ModuleName) + //paramsKeeper.Subspace(ibcexported.ModuleName) + //paramsKeeper.Subspace(icahosttypes.SubModuleName) + //paramsKeeper.Subspace(icacontrollertypes.SubModuleName) paramsKeeper.Subspace(wasmtypes.ModuleName) + keyTable := ibcclienttypes.ParamKeyTable() + keyTable.RegisterParamSet(&ibcconnectiontypes.Params{}) + paramsKeeper.Subspace(ibcexported.ModuleName).WithKeyTable(keyTable) + paramsKeeper.Subspace(ibctransfertypes.ModuleName).WithKeyTable(ibctransfertypes.ParamKeyTable()) + paramsKeeper.Subspace(icacontrollertypes.SubModuleName).WithKeyTable(icacontrollertypes.ParamKeyTable()) + paramsKeeper.Subspace(icahosttypes.SubModuleName).WithKeyTable(icahosttypes.ParamKeyTable()) return paramsKeeper } From 540097d78d682aae4abbef75155c170620bb6808 Mon Sep 17 00:00:00 2001 From: Alex Peters Date: Wed, 4 Oct 2023 08:55:03 +0200 Subject: [PATCH 07/27] Fix app for chain upgrade --- app/app.go | 6 ++++++ tests/system/upgrade_test.go | 4 ++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/app/app.go b/app/app.go index 9363e828c1..cf888e0525 100644 --- a/app/app.go +++ b/app/app.go @@ -844,6 +844,7 @@ func NewWasmApp( // initialize BaseApp app.SetInitChainer(app.InitChainer) + app.SetPreBlocker(app.PreBlocker) app.SetBeginBlocker(app.BeginBlocker) app.SetEndBlocker(app.EndBlocker) app.setAnteHandler(txConfig, wasmConfig, keys[wasmtypes.StoreKey]) @@ -951,6 +952,11 @@ func (app *WasmApp) setPostHandler() { // Name returns the name of the App func (app *WasmApp) Name() string { return app.BaseApp.Name() } +// PreBlocker application updates every pre block +func (app *WasmApp) PreBlocker(ctx sdk.Context, _ *abci.RequestFinalizeBlock) (*sdk.ResponsePreBlock, error) { + return app.ModuleManager.PreBlock(ctx) +} + // BeginBlocker application updates every begin block func (app *WasmApp) BeginBlocker(ctx sdk.Context) (sdk.BeginBlock, error) { return app.ModuleManager.BeginBlock(ctx) diff --git a/tests/system/upgrade_test.go b/tests/system/upgrade_test.go index 6d9823bfd1..2e1ea03394 100644 --- a/tests/system/upgrade_test.go +++ b/tests/system/upgrade_test.go @@ -1,4 +1,4 @@ -//go:build system_test && linux +//go:build system_test package system @@ -87,7 +87,7 @@ func TestChainUpgrade(t *testing.T) { t.Log("waiting for upgrade info") sut.AwaitUpgradeInfo(t) - sut.StopChain() // just in case + sut.StopChain() t.Log("Upgrade height was reached. Upgrading chain") sut.ExecBinary = currentBranchBinary From 592b4f0ee4b1d61759a3e0802032e2c0f162a3ed Mon Sep 17 00:00:00 2001 From: Alex Peters Date: Wed, 4 Oct 2023 09:02:03 +0200 Subject: [PATCH 08/27] Minor cleanup --- app/app.go | 17 ++++------------- app/upgrades.go | 4 ++-- 2 files changed, 6 insertions(+), 15 deletions(-) diff --git a/app/app.go b/app/app.go index cf888e0525..b143b01ff6 100644 --- a/app/app.go +++ b/app/app.go @@ -3,8 +3,6 @@ package app import ( "encoding/json" "fmt" - ibcclienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" - ibcconnectiontypes "github.com/cosmos/ibc-go/v8/modules/core/03-connection/types" "io" "os" "path/filepath" @@ -1167,17 +1165,10 @@ func initParamsKeeper(appCodec codec.BinaryCodec, legacyAmino *codec.LegacyAmino paramsKeeper.Subspace(slashingtypes.ModuleName) paramsKeeper.Subspace(govtypes.ModuleName) paramsKeeper.Subspace(crisistypes.ModuleName) - //paramsKeeper.Subspace(ibctransfertypes.ModuleName) - //paramsKeeper.Subspace(ibcexported.ModuleName) - //paramsKeeper.Subspace(icahosttypes.SubModuleName) - //paramsKeeper.Subspace(icacontrollertypes.SubModuleName) + paramsKeeper.Subspace(ibctransfertypes.ModuleName) + paramsKeeper.Subspace(ibcexported.ModuleName) + paramsKeeper.Subspace(icahosttypes.SubModuleName) + paramsKeeper.Subspace(icacontrollertypes.SubModuleName) paramsKeeper.Subspace(wasmtypes.ModuleName) - - keyTable := ibcclienttypes.ParamKeyTable() - keyTable.RegisterParamSet(&ibcconnectiontypes.Params{}) - paramsKeeper.Subspace(ibcexported.ModuleName).WithKeyTable(keyTable) - paramsKeeper.Subspace(ibctransfertypes.ModuleName).WithKeyTable(ibctransfertypes.ParamKeyTable()) - paramsKeeper.Subspace(icacontrollertypes.SubModuleName).WithKeyTable(icacontrollertypes.ParamKeyTable()) - paramsKeeper.Subspace(icahosttypes.SubModuleName).WithKeyTable(icahosttypes.ParamKeyTable()) return paramsKeeper } diff --git a/app/upgrades.go b/app/upgrades.go index eaf92b0026..4094323d38 100644 --- a/app/upgrades.go +++ b/app/upgrades.go @@ -3,8 +3,6 @@ package app import ( "context" - circuittypes "cosmossdk.io/x/circuit/types" - paramstypes "github.com/cosmos/cosmos-sdk/x/params/types" icacontrollertypes "github.com/cosmos/ibc-go/v8/modules/apps/27-interchain-accounts/controller/types" icahosttypes "github.com/cosmos/ibc-go/v8/modules/apps/27-interchain-accounts/host/types" ibctransfertypes "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types" @@ -13,9 +11,11 @@ import ( ibcexported "github.com/cosmos/ibc-go/v8/modules/core/exported" storetypes "cosmossdk.io/store/types" + circuittypes "cosmossdk.io/x/circuit/types" upgradetypes "cosmossdk.io/x/upgrade/types" "github.com/cosmos/cosmos-sdk/types/module" + paramstypes "github.com/cosmos/cosmos-sdk/x/params/types" ) // UpgradeName defines the on-chain upgrade name for the sample SimApp upgrade From 7a3a3e381d17d6d4dceb5767b822453eed102061 Mon Sep 17 00:00:00 2001 From: Alex Peters Date: Wed, 4 Oct 2023 10:02:39 +0200 Subject: [PATCH 09/27] Check contract state --- tests/system/basic_test.go | 9 ++++++--- tests/system/cli.go | 4 ++-- tests/system/upgrade_test.go | 28 +++++++++++++++++++++++----- 3 files changed, 31 insertions(+), 10 deletions(-) diff --git a/tests/system/basic_test.go b/tests/system/basic_test.go index 1fba127648..a6178381f5 100644 --- a/tests/system/basic_test.go +++ b/tests/system/basic_test.go @@ -50,10 +50,13 @@ func TestBasicWasm(t *testing.T) { t.Cleanup(cleanupFn) t.Log("Instantiate wasm code") - initMsg := fmt.Sprintf(`{"verifier":%q, "beneficiary":%q}`, randomBech32Addr(), randomBech32Addr()) + verifierAddr := randomBech32Addr() + initMsg := fmt.Sprintf(`{"verifier":%q, "beneficiary":%q}`, verifierAddr, randomBech32Addr()) newContractAddr := cli.WasmInstantiate(codeID, initMsg, "--admin="+defaultSrcAddr, "--label=label1", "--from="+defaultSrcAddr) - assert.Equal(t, expContractAddr, newContractAddr) - assert.Len(t, done(), 1) + require.Equal(t, expContractAddr, newContractAddr) + require.Len(t, done(), 1) + gotRsp := cli.QuerySmart(newContractAddr, `{"verifier":{}}`) + require.Equal(t, fmt.Sprintf(`{"data":{"verifier":"%s"}}`, verifierAddr), gotRsp) t.Log("Update Instantiate Config") qResult = cli.CustomQuery("q", "wasm", "code-info", fmt.Sprint(codeID)) diff --git a/tests/system/cli.go b/tests/system/cli.go index 7fc419c35b..7fcdf3c047 100644 --- a/tests/system/cli.go +++ b/tests/system/cli.go @@ -216,7 +216,7 @@ func (c WasmdCli) runWithInput(args []string, input io.Reader) (output string, o return cmd.CombinedOutput() }() ok = c.assertErrorFn(c.t, gotErr, string(gotOut)) - return string(gotOut), ok + return strings.TrimSpace(string(gotOut)), ok } func (c WasmdCli) withQueryFlags(args ...string) []string { @@ -302,7 +302,7 @@ func (c WasmdCli) FundAddress(destAddr, amount string) string { // WasmStore uploads a wasm contract to the chain. Returns code id func (c WasmdCli) WasmStore(file string, args ...string) int { if len(args) == 0 { - args = []string{"--from=" + defaultSrcAddr, "--gas=2500000"} + args = []string{"--from=" + defaultSrcAddr, "--gas=2500000", "--fees=3stake"} } cmd := append([]string{"tx", "wasm", "store", file}, args...) rsp := c.CustomCommand(cmd...) diff --git a/tests/system/upgrade_test.go b/tests/system/upgrade_test.go index 2e1ea03394..d19a3d24f5 100644 --- a/tests/system/upgrade_test.go +++ b/tests/system/upgrade_test.go @@ -13,6 +13,8 @@ import ( "testing" "time" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" "github.com/tidwall/gjson" ) @@ -23,7 +25,6 @@ func TestChainUpgrade(t *testing.T) { // when a chain upgrade proposal is executed // then the chain upgrades successfully - // todo: this test works only with linux, currently legacyBinary := FetchExecutable(t, "v0.41.0") t.Logf("+++ legacy binary: %s\n", legacyBinary) currentBranchBinary := sut.ExecBinary @@ -32,12 +33,22 @@ func TestChainUpgrade(t *testing.T) { votingPeriod := 10 * time.Second // enough time to vote sut.ModifyGenesisJSON(t, SetGovVotingPeriod(t, votingPeriod)) - const upgradeHeight int64 = 20 // + const upgradeHeight int64 = 22 sut.StartChain(t, fmt.Sprintf("--halt-height=%d", upgradeHeight)) cli := NewWasmdCLI(t, sut, verbose) - // todo: set some state to ensure that migrations work + // set some state to ensure that migrations work + verifierAddr := cli.AddKey("verifier") + beneficiary := randomBech32Addr() + + t.Log("Launch hackatom contract") + codeID := cli.WasmStore("./testdata/hackatom.wasm.gzip") + initMsg := fmt.Sprintf(`{"verifier":%q, "beneficiary":%q}`, verifierAddr, beneficiary) + contractAddr := cli.WasmInstantiate(codeID, initMsg, "--admin="+defaultSrcAddr, "--label=label1", "--from="+defaultSrcAddr, "--amount=1000000stake") + + gotRsp := cli.QuerySmart(contractAddr, `{"verifier":{}}`) + require.Equal(t, fmt.Sprintf(`{"data":{"verifier":"%s"}}`, verifierAddr), gotRsp) // submit upgrade proposal // todo: all of this can be moved into the test_cli to make it more readable in the tests @@ -84,6 +95,8 @@ func TestChainUpgrade(t *testing.T) { t.Logf("current_height: %d\n", sut.currentHeight) raw = cli.CustomQuery("q", "gov", "proposal", ourProposalID) t.Log(raw) + proposalStatus := gjson.Get(raw, "proposal.status").String() + require.Equal(t, "PROPOSAL_STATUS_PASSED", proposalStatus) t.Log("waiting for upgrade info") sut.AwaitUpgradeInfo(t) @@ -92,8 +105,13 @@ func TestChainUpgrade(t *testing.T) { t.Log("Upgrade height was reached. Upgrading chain") sut.ExecBinary = currentBranchBinary sut.StartChain(t) - // todo: ensure that state matches expectations - t.Log("Done") + + // ensure that state matches expectations + gotRsp = cli.QuerySmart(contractAddr, `{"verifier":{}}`) + require.Equal(t, fmt.Sprintf(`{"data":{"verifier":"%s"}}`, verifierAddr), gotRsp) + // and contract execution works as expected + RequireTxSuccess(t, cli.WasmExecute(contractAddr, verifierAddr, `{"release":{}}`)) + assert.Equal(t, 1_000_000, cli.QueryBalance(beneficiary, "stake")) } const cacheDir = "binaries" From 8083cf4156a79682b5acc90c24129ba83ee6b282 Mon Sep 17 00:00:00 2001 From: Alex Peters Date: Wed, 4 Oct 2023 11:22:22 +0200 Subject: [PATCH 10/27] Updates --- app/upgrades.go | 1 + tests/system/cli.go | 85 +++++++++++++++++++----------------- tests/system/upgrade_test.go | 30 +++---------- 3 files changed, 51 insertions(+), 65 deletions(-) diff --git a/app/upgrades.go b/app/upgrades.go index 4094323d38..b73682f47d 100644 --- a/app/upgrades.go +++ b/app/upgrades.go @@ -54,6 +54,7 @@ func (app WasmApp) RegisterUpgradeHandlers() { app.UpgradeKeeper.SetUpgradeHandler( UpgradeName, func(ctx context.Context, _ upgradetypes.Plan, fromVM module.VersionMap) (module.VersionMap, error) { + app.GovKeeper.Constitution.Set(ctx, "Constitution") // required for genesis export but should go into the SDK instead return app.ModuleManager.RunMigrations(ctx, app.Configurator(), fromVM) }, ) diff --git a/tests/system/cli.go b/tests/system/cli.go index 7fcdf3c047..7171dcc44f 100644 --- a/tests/system/cli.go +++ b/tests/system/cli.go @@ -3,6 +3,7 @@ package system import ( "fmt" "io" + "os" "os/exec" "path/filepath" "strconv" @@ -42,6 +43,7 @@ type WasmdCli struct { awaitNextBlock awaitNextBlock expTXCommitted bool execBinary string + nodesCount int } // NewWasmdCLI constructor @@ -52,6 +54,7 @@ func NewWasmdCLI(t *testing.T, sut *SystemUnderTest, verbose bool) *WasmdCli { sut.rpcAddr, sut.chainID, sut.AwaitNextBlock, + sut.nodesCount, filepath.Join(WorkDir, sut.outputDir), "1"+sdk.DefaultBondDenom, verbose, @@ -67,6 +70,7 @@ func NewWasmdCLIx( nodeAddress string, chainID string, awaiter awaitNextBlock, + nodesCount int, homeDir string, fees string, debug bool, @@ -84,6 +88,7 @@ func NewWasmdCLIx( homeDir: homeDir, Debug: debug, awaitNextBlock: awaiter, + nodesCount: nodesCount, fees: fees, assertErrorFn: assertErrorFn, expTXCommitted: expTXCommitted, @@ -99,48 +104,15 @@ func (c WasmdCli) WithRunErrorsIgnored() WasmdCli { // WithRunErrorMatcher assert function to ensure run command error value func (c WasmdCli) WithRunErrorMatcher(f RunErrorAssert) WasmdCli { - return *NewWasmdCLIx( - c.t, - c.execBinary, - c.nodeAddress, - c.chainID, - c.awaitNextBlock, - c.homeDir, - c.fees, - c.Debug, - f, - c.expTXCommitted, - ) + return *NewWasmdCLIx(c.t, c.execBinary, c.nodeAddress, c.chainID, c.awaitNextBlock, 0, c.homeDir, c.fees, c.Debug, f, c.expTXCommitted) } func (c WasmdCli) WithNodeAddress(nodeAddr string) WasmdCli { - return *NewWasmdCLIx( - c.t, - c.execBinary, - nodeAddr, - c.chainID, - c.awaitNextBlock, - c.homeDir, - c.fees, - c.Debug, - c.assertErrorFn, - c.expTXCommitted, - ) + return *NewWasmdCLIx(c.t, c.execBinary, nodeAddr, c.chainID, c.awaitNextBlock, 0, c.homeDir, c.fees, c.Debug, c.assertErrorFn, c.expTXCommitted) } func (c WasmdCli) WithAssertTXUncommitted() WasmdCli { - return *NewWasmdCLIx( - c.t, - c.execBinary, - c.nodeAddress, - c.chainID, - c.awaitNextBlock, - c.homeDir, - c.fees, - c.Debug, - c.assertErrorFn, - false, - ) + return *NewWasmdCLIx(c.t, c.execBinary, c.nodeAddress, c.chainID, c.awaitNextBlock, 0, c.homeDir, c.fees, c.Debug, c.assertErrorFn, false) } // CustomCommand main entry for executing wasmd cli commands. @@ -354,7 +326,7 @@ func (c WasmdCli) QueryTotalSupply(denom string) int64 { return gjson.Get(raw, fmt.Sprintf("supply.#(denom==%q).amount", denom)).Int() } -func (c WasmdCli) GetTendermintValidatorSet() cmtservice.GetLatestValidatorSetResponse { +func (c WasmdCli) GetCometBFTValidatorSet() cmtservice.GetLatestValidatorSetResponse { args := []string{"q", "comet-validator-set"} got := c.CustomQuery(args...) @@ -368,9 +340,9 @@ func (c WasmdCli) GetTendermintValidatorSet() cmtservice.GetLatestValidatorSetRe return res } -// IsInTendermintValset returns true when the given pub key is in the current active tendermint validator set -func (c WasmdCli) IsInTendermintValset(valPubKey cryptotypes.PubKey) (cmtservice.GetLatestValidatorSetResponse, bool) { - valResult := c.GetTendermintValidatorSet() +// IsInCometBftValset returns true when the given pub key is in the current active tendermint validator set +func (c WasmdCli) IsInCometBftValset(valPubKey cryptotypes.PubKey) (cmtservice.GetLatestValidatorSetResponse, bool) { + valResult := c.GetCometBFTValidatorSet() var found bool for _, v := range valResult.Validators { if v.PubKey.Equal(valPubKey) { @@ -381,6 +353,39 @@ func (c WasmdCli) IsInTendermintValset(valPubKey cryptotypes.PubKey) (cmtservice return valResult, found } +// SubmitUpgradeGovProposal submit a chain upgrade gov v1 proposal + +// SubmitGovProposal submit a gov v1 proposal +func (c WasmdCli) SubmitGovProposal(proposalJson string, args ...string) string { + if len(args) == 0 { + args = []string{"--from=" + defaultSrcAddr} + } + + pathToProposal := filepath.Join(c.t.TempDir(), "proposal.json") + err := os.WriteFile(pathToProposal, []byte(proposalJson), os.FileMode(0o744)) + require.NoError(c.t, err) + c.t.Log("Submit upgrade proposal") + return c.CustomCommand(append([]string{"tx", "gov", "submit-proposal", pathToProposal}, args...)...) +} + +// SubmitAndVoteGovProposal submit proposal, let all validators vote yes and return proposal id +func (c WasmdCli) SubmitAndVoteGovProposal(proposalJson string, args ...string) string { + rsp := c.SubmitGovProposal(proposalJson, args...) + RequireTxSuccess(c.t, rsp) + raw := c.CustomQuery("q", "gov", "proposals", "--depositor", c.GetKeyAddr(defaultSrcAddr)) + proposals := gjson.Get(raw, "proposals.#.id").Array() + require.NotEmpty(c.t, proposals, raw) + ourProposalID := proposals[len(proposals)-1].String() // last is ours + for i := 0; i < c.nodesCount; i++ { + go func(i int) { // do parallel + c.t.Logf("Voting: validator %d\n", i) + rsp = c.CustomCommand("tx", "gov", "vote", ourProposalID, "yes", "--from", c.GetKeyAddr(fmt.Sprintf("node%d", i))) + RequireTxSuccess(c.t, rsp) + }(i) + } + return ourProposalID +} + // RequireTxSuccess require the received response to contain the success code func RequireTxSuccess(t *testing.T, got string) { t.Helper() diff --git a/tests/system/upgrade_test.go b/tests/system/upgrade_test.go index d19a3d24f5..b73ec77994 100644 --- a/tests/system/upgrade_test.go +++ b/tests/system/upgrade_test.go @@ -51,8 +51,6 @@ func TestChainUpgrade(t *testing.T) { require.Equal(t, fmt.Sprintf(`{"data":{"verifier":"%s"}}`, verifierAddr), gotRsp) // submit upgrade proposal - // todo: all of this can be moved into the test_cli to make it more readable in the tests - upgradeName := "v0.50.x" proposal := fmt.Sprintf(` { "messages": [ @@ -69,34 +67,16 @@ func TestChainUpgrade(t *testing.T) { "deposit": "100000000stake", "title": "my upgrade", "summary": "testing" -}`, upgradeName, upgradeHeight) - pathToProposal := filepath.Join(t.TempDir(), "proposal.json") - err := os.WriteFile(pathToProposal, []byte(proposal), os.FileMode(0o744)) - require.NoError(t, err) - t.Log("Submit upgrade proposal") - rsp := cli.CustomCommand("tx", "gov", "submit-proposal", pathToProposal, "--from", cli.GetKeyAddr(defaultSrcAddr)) - RequireTxSuccess(t, rsp) - raw := cli.CustomQuery("q", "gov", "proposals", "--depositor", cli.GetKeyAddr(defaultSrcAddr)) - proposals := gjson.Get(raw, "proposals.#.id").Array() - require.NotEmpty(t, proposals, raw) - ourProposalID := proposals[len(proposals)-1].String() // last is ours - sut.withEachNodeHome(func(n int, _ string) { - go func() { // do parallel - t.Logf("Voting: validator %d\n", n) - rsp = cli.CustomCommand("tx", "gov", "vote", ourProposalID, "yes", "--from", cli.GetKeyAddr(fmt.Sprintf("node%d", n))) - RequireTxSuccess(t, rsp) - }() - }) - // +}`, "v0.50.x", upgradeHeight) + proposalID := cli.SubmitAndVoteGovProposal(proposal) t.Logf("current_height: %d\n", sut.currentHeight) - raw = cli.CustomQuery("q", "gov", "proposal", ourProposalID) + raw := cli.CustomQuery("q", "gov", "proposal", proposalID) t.Log(raw) sut.AwaitBlockHeight(t, upgradeHeight-1) t.Logf("current_height: %d\n", sut.currentHeight) - raw = cli.CustomQuery("q", "gov", "proposal", ourProposalID) - t.Log(raw) + raw = cli.CustomQuery("q", "gov", "proposal", proposalID) proposalStatus := gjson.Get(raw, "proposal.status").String() - require.Equal(t, "PROPOSAL_STATUS_PASSED", proposalStatus) + require.Equal(t, "PROPOSAL_STATUS_PASSED", proposalStatus, raw) t.Log("waiting for upgrade info") sut.AwaitUpgradeInfo(t) From 64b95c3360ec2956d916f440f176d381fe13c943 Mon Sep 17 00:00:00 2001 From: Alex Peters Date: Wed, 4 Oct 2023 12:40:42 +0200 Subject: [PATCH 11/27] Gov constitution migration will be handled by the sdk --- app/upgrades.go | 1 - 1 file changed, 1 deletion(-) diff --git a/app/upgrades.go b/app/upgrades.go index b73682f47d..4094323d38 100644 --- a/app/upgrades.go +++ b/app/upgrades.go @@ -54,7 +54,6 @@ func (app WasmApp) RegisterUpgradeHandlers() { app.UpgradeKeeper.SetUpgradeHandler( UpgradeName, func(ctx context.Context, _ upgradetypes.Plan, fromVM module.VersionMap) (module.VersionMap, error) { - app.GovKeeper.Constitution.Set(ctx, "Constitution") // required for genesis export but should go into the SDK instead return app.ModuleManager.RunMigrations(ctx, app.Configurator(), fromVM) }, ) From 64f6d3904a9e3c6e2d5396f68baf43ad314ad6a2 Mon Sep 17 00:00:00 2001 From: Alex Peters Date: Wed, 4 Oct 2023 12:42:34 +0200 Subject: [PATCH 12/27] Deactivate upgrade test --- tests/system/upgrade_test.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/system/upgrade_test.go b/tests/system/upgrade_test.go index b73ec77994..c8daf48d55 100644 --- a/tests/system/upgrade_test.go +++ b/tests/system/upgrade_test.go @@ -1,4 +1,4 @@ -//go:build system_test +//go:build system_test && linux package system @@ -86,6 +86,7 @@ func TestChainUpgrade(t *testing.T) { sut.ExecBinary = currentBranchBinary sut.StartChain(t) + t.Skip("wasmvm 1.4 upgrade fails, currently. Skipping for now") // ensure that state matches expectations gotRsp = cli.QuerySmart(contractAddr, `{"verifier":{}}`) require.Equal(t, fmt.Sprintf(`{"data":{"verifier":"%s"}}`, verifierAddr), gotRsp) From 059e0e5c1b5d6b2bd655ee149cc456e8b60a5a38 Mon Sep 17 00:00:00 2001 From: Alex Peters Date: Wed, 4 Oct 2023 13:23:11 +0200 Subject: [PATCH 13/27] Helper --- tests/system/cli.go | 42 +++++++++++++++++++++++++++++++++++++++--- 1 file changed, 39 insertions(+), 3 deletions(-) diff --git a/tests/system/cli.go b/tests/system/cli.go index 7171dcc44f..33da0f1378 100644 --- a/tests/system/cli.go +++ b/tests/system/cli.go @@ -104,15 +104,51 @@ func (c WasmdCli) WithRunErrorsIgnored() WasmdCli { // WithRunErrorMatcher assert function to ensure run command error value func (c WasmdCli) WithRunErrorMatcher(f RunErrorAssert) WasmdCli { - return *NewWasmdCLIx(c.t, c.execBinary, c.nodeAddress, c.chainID, c.awaitNextBlock, 0, c.homeDir, c.fees, c.Debug, f, c.expTXCommitted) + return *NewWasmdCLIx( + c.t, + c.execBinary, + c.nodeAddress, + c.chainID, + c.awaitNextBlock, + c.nodesCount, + c.homeDir, + c.fees, + c.Debug, + f, + c.expTXCommitted, + ) } func (c WasmdCli) WithNodeAddress(nodeAddr string) WasmdCli { - return *NewWasmdCLIx(c.t, c.execBinary, nodeAddr, c.chainID, c.awaitNextBlock, 0, c.homeDir, c.fees, c.Debug, c.assertErrorFn, c.expTXCommitted) + return *NewWasmdCLIx( + c.t, + c.execBinary, + nodeAddr, + c.chainID, + c.awaitNextBlock, + c.nodesCount, + c.homeDir, + c.fees, + c.Debug, + c.assertErrorFn, + c.expTXCommitted, + ) } func (c WasmdCli) WithAssertTXUncommitted() WasmdCli { - return *NewWasmdCLIx(c.t, c.execBinary, c.nodeAddress, c.chainID, c.awaitNextBlock, 0, c.homeDir, c.fees, c.Debug, c.assertErrorFn, false) + return *NewWasmdCLIx( + c.t, + c.execBinary, + c.nodeAddress, + c.chainID, + c.awaitNextBlock, + c.nodesCount, + c.homeDir, + c.fees, + c.Debug, + c.assertErrorFn, + false, + ) } // CustomCommand main entry for executing wasmd cli commands. From 6f664751bf20b794dc90cb0e26a0f5502ac3b931 Mon Sep 17 00:00:00 2001 From: Alex Peters Date: Thu, 5 Oct 2023 09:28:43 +0200 Subject: [PATCH 14/27] Better upgrade structure an minor updates (cherry picked from commit 32a01da4563b52df6167929f3535d111ad18a1b7) --- app/upgrades.go | 83 +++++++++++++++++++---------------- app/upgrades/types.go | 25 +++++++++++ app/upgrades/v043/upgrades.go | 31 +++++++++++++ cmd/wasmd/testnet.go | 2 +- tests/system/cli.go | 4 +- tests/system/main_test.go | 4 +- tests/system/system.go | 10 ++--- tests/system/upgrade_test.go | 8 +++- 8 files changed, 117 insertions(+), 50 deletions(-) create mode 100644 app/upgrades/types.go create mode 100644 app/upgrades/v043/upgrades.go diff --git a/app/upgrades.go b/app/upgrades.go index 4094323d38..986e737fa3 100644 --- a/app/upgrades.go +++ b/app/upgrades.go @@ -1,34 +1,62 @@ package app import ( - "context" - + upgradetypes "cosmossdk.io/x/upgrade/types" + "fmt" + "github.com/CosmWasm/wasmd/app/upgrades" + v043 "github.com/CosmWasm/wasmd/app/upgrades/v043" + paramskeeper "github.com/cosmos/cosmos-sdk/x/params/keeper" + paramstypes "github.com/cosmos/cosmos-sdk/x/params/types" icacontrollertypes "github.com/cosmos/ibc-go/v8/modules/apps/27-interchain-accounts/controller/types" icahosttypes "github.com/cosmos/ibc-go/v8/modules/apps/27-interchain-accounts/host/types" ibctransfertypes "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types" ibcclienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" ibcconnectiontypes "github.com/cosmos/ibc-go/v8/modules/core/03-connection/types" ibcexported "github.com/cosmos/ibc-go/v8/modules/core/exported" - - storetypes "cosmossdk.io/store/types" - circuittypes "cosmossdk.io/x/circuit/types" - upgradetypes "cosmossdk.io/x/upgrade/types" - - "github.com/cosmos/cosmos-sdk/types/module" - paramstypes "github.com/cosmos/cosmos-sdk/x/params/types" ) -// UpgradeName defines the on-chain upgrade name for the sample SimApp upgrade -// from v047 to v050. -// -// NOTE: This upgrade defines a reference implementation of what an upgrade -// could look like when an application is migrating from Cosmos SDK version -// v0.47.x to v0.50.x. -const UpgradeName = "v0.50.x" +// Upgrades list of chain upgrades +var Upgrades = []upgrades.Upgrade{v043.Upgrade} +// RegisterUpgradeHandlers registers the chain upgrade handlers func (app WasmApp) RegisterUpgradeHandlers() { + setupLegacyKeyTables(app.ParamsKeeper) + + keepers := upgrades.AppKeepers{AccountKeeper: app.AccountKeeper} + // register all upgrade handlers + for _, upgrade := range Upgrades { + app.UpgradeKeeper.SetUpgradeHandler( + upgrade.UpgradeName, + upgrade.CreateUpgradeHandler( + app.ModuleManager, + app.configurator, + &keepers, + ), + ) + } + + upgradeInfo, err := app.UpgradeKeeper.ReadUpgradeInfoFromDisk() + if err != nil { + panic(fmt.Sprintf("failed to read upgrade info from disk %s", err)) + } + + if app.UpgradeKeeper.IsSkipHeight(upgradeInfo.Height) { + return + } + + // register store loader for current upgrade + for _, upgrade := range Upgrades { + if upgradeInfo.Name == upgrade.UpgradeName { + app.SetStoreLoader(upgradetypes.UpgradeStoreLoader(upgradeInfo.Height, &upgrade.StoreUpgrades)) + break + } + } +} + +func setupLegacyKeyTables(k paramskeeper.Keeper) { // Set param key table for params module migration - for _, subspace := range app.ParamsKeeper.GetSubspaces() { + for _, subspace := range k.GetSubspaces() { + subspace := subspace var keyTable paramstypes.KeyTable switch subspace.Name() { @@ -50,25 +78,4 @@ func (app WasmApp) RegisterUpgradeHandlers() { subspace.WithKeyTable(keyTable) } } - - app.UpgradeKeeper.SetUpgradeHandler( - UpgradeName, - func(ctx context.Context, _ upgradetypes.Plan, fromVM module.VersionMap) (module.VersionMap, error) { - return app.ModuleManager.RunMigrations(ctx, app.Configurator(), fromVM) - }, - ) - - upgradeInfo, err := app.UpgradeKeeper.ReadUpgradeInfoFromDisk() - if err != nil { - panic(err) - } - - if upgradeInfo.Name == UpgradeName && !app.UpgradeKeeper.IsSkipHeight(upgradeInfo.Height) { - storeUpgrades := storetypes.StoreUpgrades{ - Added: []string{circuittypes.ModuleName}, - } - - // configure store loader that checks if version == upgradeHeight and applies store upgrades - app.SetStoreLoader(upgradetypes.UpgradeStoreLoader(upgradeInfo.Height, &storeUpgrades)) - } } diff --git a/app/upgrades/types.go b/app/upgrades/types.go new file mode 100644 index 0000000000..5cfce557f5 --- /dev/null +++ b/app/upgrades/types.go @@ -0,0 +1,25 @@ +package upgrades + +import ( + store "github.com/cosmos/cosmos-sdk/store/types" + "github.com/cosmos/cosmos-sdk/types/module" + authkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper" + upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types" +) + +type AppKeepers struct { + authkeeper.AccountKeeper +} + +// Upgrade defines a struct containing necessary fields that a SoftwareUpgradeProposal +// must have written, in order for the state migration to go smoothly. +// An upgrade must implement this struct, and then set it in the app.go. +// The app.go will then define the handler. +type Upgrade struct { + // Upgrade version name, for the upgrade handler, e.g. `v7` + UpgradeName string + + // CreateUpgradeHandler defines the function that creates an upgrade handler + CreateUpgradeHandler func(*module.Manager, module.Configurator, *AppKeepers) upgradetypes.UpgradeHandler + StoreUpgrades store.StoreUpgrades +} diff --git a/app/upgrades/v043/upgrades.go b/app/upgrades/v043/upgrades.go new file mode 100644 index 0000000000..bca64c425f --- /dev/null +++ b/app/upgrades/v043/upgrades.go @@ -0,0 +1,31 @@ +package v043 + +import ( + "github.com/CosmWasm/wasmd/app/upgrades" + store "github.com/cosmos/cosmos-sdk/store/types" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/module" + upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types" +) + +// UpgradeName defines the on-chain upgrade name +const UpgradeName = "v0.43" + +var Upgrade = upgrades.Upgrade{ + UpgradeName: UpgradeName, + CreateUpgradeHandler: CreateUpgradeHandler, + StoreUpgrades: store.StoreUpgrades{ + Added: []string{}, + Deleted: []string{}, + }, +} + +func CreateUpgradeHandler( + mm *module.Manager, + configurator module.Configurator, + ak *upgrades.AppKeepers, +) upgradetypes.UpgradeHandler { + return func(ctx sdk.Context, plan upgradetypes.Plan, fromVM module.VersionMap) (module.VersionMap, error) { + return mm.RunMigrations(ctx, configurator, fromVM) + } +} diff --git a/cmd/wasmd/testnet.go b/cmd/wasmd/testnet.go index cdfe205a64..f07be8d8bb 100644 --- a/cmd/wasmd/testnet.go +++ b/cmd/wasmd/testnet.go @@ -166,7 +166,7 @@ Example: addTestnetFlagsToCmd(cmd) cmd.Flags().String(flagNodeDirPrefix, "node", "Prefix the directory name for each node with (node results in node0, node1, ...)") - cmd.Flags().String(flagNodeDaemonHome, "wasmd", "Home directory of the node's daemon configuration") + cmd.Flags().String(flagNodeDaemonHome, version.AppName, "Home directory of the node's daemon configuration") cmd.Flags().String(flagStartingIPAddress, "192.168.0.1", "Starting IP address (192.168.0.1 results in persistent peers list ID0@192.168.0.1:46656, ID1@192.168.0.2:46656, ...)") cmd.Flags().String(flags.FlagKeyringBackend, flags.DefaultKeyringBackend, "Select keyring's backend (os|file|test)") cmd.Flags().Duration(flagCommitTimeout, 5*time.Second, "Time to wait after a block commit before starting on the new height") diff --git a/tests/system/cli.go b/tests/system/cli.go index 33da0f1378..5fb915366b 100644 --- a/tests/system/cli.go +++ b/tests/system/cli.go @@ -164,7 +164,7 @@ func (c WasmdCli) CustomCommand(args ...string) string { if !ok { return execOutput } - rsp, committed := c.awaitTxCommitted(execOutput, defaultWaitTime) + rsp, committed := c.awaitTxCommitted(execOutput, DefaultWaitTime) c.t.Logf("tx committed: %v", committed) require.Equal(c.t, c.expTXCommitted, committed, "expected tx committed: %v", c.expTXCommitted) return rsp @@ -218,7 +218,7 @@ func (c WasmdCli) runWithInput(args []string, input io.Reader) (output string, o err = fmt.Errorf("recovered from panic: %v", r) } }() - cmd := exec.Command(locateExecutable("wasmd"), args...) //nolint:gosec + cmd := exec.Command(locateExecutable(c.execBinary), args...) //nolint:gosec cmd.Dir = WorkDir cmd.Stdin = input return cmd.CombinedOutput() diff --git a/tests/system/main_test.go b/tests/system/main_test.go index 85d2e7f483..0467cc2f8f 100644 --- a/tests/system/main_test.go +++ b/tests/system/main_test.go @@ -27,7 +27,7 @@ var ( func TestMain(m *testing.M) { rebuild := flag.Bool("rebuild", false, "rebuild artifacts") - waitTime := flag.Duration("wait-time", defaultWaitTime, "time to wait for chain events") + waitTime := flag.Duration("wait-time", DefaultWaitTime, "time to wait for chain events") nodesCount := flag.Int("nodes-count", 4, "number of nodes in the cluster") blockTime := flag.Duration("block-time", 1000*time.Millisecond, "block creation time") execBinary := flag.String("binary", "wasmd", "executable binary for server/ client side") @@ -48,7 +48,7 @@ func TestMain(m *testing.M) { } initSDKConfig(*bech32Prefix) - defaultWaitTime = *waitTime + DefaultWaitTime = *waitTime if *execBinary == "" { panic("executable binary name must not be empty") } diff --git a/tests/system/system.go b/tests/system/system.go index 497b9df610..e5fc27dbc1 100644 --- a/tests/system/system.go +++ b/tests/system/system.go @@ -261,7 +261,7 @@ func (s *SystemUnderTest) AwaitChainStopped() { func (s *SystemUnderTest) AwaitNodeUp(t *testing.T, rpcAddr string) { t.Helper() t.Logf("Await node is up: %s", rpcAddr) - timeout := defaultWaitTime + timeout := DefaultWaitTime ctx, done := context.WithTimeout(context.Background(), timeout) defer done() @@ -745,7 +745,7 @@ func NewEventListener(t *testing.T, rpcAddr string) *EventListener { return &EventListener{client: httpClient, t: t} } -var defaultWaitTime = 30 * time.Second +var DefaultWaitTime = 30 * time.Second type ( CleanupFn func() @@ -760,7 +760,7 @@ func (l *EventListener) Subscribe(query string, cb EventConsumer) func() { eventsChan, err := l.client.WSEvents.Subscribe(ctx, "testing", query) require.NoError(l.t, err) cleanup := func() { - ctx, _ := context.WithTimeout(ctx, defaultWaitTime) //nolint:govet + ctx, _ := context.WithTimeout(ctx, DefaultWaitTime) //nolint:govet go l.client.WSEvents.Unsubscribe(ctx, "testing", query) //nolint:errcheck done() } @@ -778,7 +778,7 @@ func (l *EventListener) Subscribe(query string, cb EventConsumer) func() { // For query syntax See https://docs.cosmos.network/master/core/events.html#subscribing-to-events func (l *EventListener) AwaitQuery(query string, optMaxWaitTime ...time.Duration) *ctypes.ResultEvent { c, result := CaptureSingleEventConsumer() - maxWaitTime := defaultWaitTime + maxWaitTime := DefaultWaitTime if len(optMaxWaitTime) != 0 { maxWaitTime = optMaxWaitTime[0] } @@ -840,7 +840,7 @@ func CaptureSingleEventConsumer() (EventConsumer, *ctypes.ResultEvent) { // // assert.Len(t, done(), 1) // then verify your assumption func CaptureAllEventsConsumer(t *testing.T, optMaxWaitTime ...time.Duration) (c EventConsumer, done func() []ctypes.ResultEvent) { - maxWaitTime := defaultWaitTime + maxWaitTime := DefaultWaitTime if len(optMaxWaitTime) != 0 { maxWaitTime = optMaxWaitTime[0] } diff --git a/tests/system/upgrade_test.go b/tests/system/upgrade_test.go index c8daf48d55..f48e6dfc73 100644 --- a/tests/system/upgrade_test.go +++ b/tests/system/upgrade_test.go @@ -33,7 +33,11 @@ func TestChainUpgrade(t *testing.T) { votingPeriod := 10 * time.Second // enough time to vote sut.ModifyGenesisJSON(t, SetGovVotingPeriod(t, votingPeriod)) - const upgradeHeight int64 = 22 + const ( + upgradeHeight int64 = 22 + upgradeName = "v0.50" + ) + sut.StartChain(t, fmt.Sprintf("--halt-height=%d", upgradeHeight)) cli := NewWasmdCLI(t, sut, verbose) @@ -67,7 +71,7 @@ func TestChainUpgrade(t *testing.T) { "deposit": "100000000stake", "title": "my upgrade", "summary": "testing" -}`, "v0.50.x", upgradeHeight) +}`, upgradeName, upgradeHeight) proposalID := cli.SubmitAndVoteGovProposal(proposal) t.Logf("current_height: %d\n", sut.currentHeight) raw := cli.CustomQuery("q", "gov", "proposal", proposalID) From 33d4af8a1c9cd58d88d28286b015d92cd01a4dee Mon Sep 17 00:00:00 2001 From: Alex Peters Date: Thu, 5 Oct 2023 09:43:20 +0200 Subject: [PATCH 15/27] Updates --- app/upgrades.go | 14 ++++++++----- app/upgrades/types.go | 6 +++--- app/upgrades/v043/upgrades.go | 14 +++++++------ app/upgrades/v050/upgrades.go | 38 +++++++++++++++++++++++++++++++++++ 4 files changed, 58 insertions(+), 14 deletions(-) create mode 100644 app/upgrades/v050/upgrades.go diff --git a/app/upgrades.go b/app/upgrades.go index 986e737fa3..eca2496a9a 100644 --- a/app/upgrades.go +++ b/app/upgrades.go @@ -1,10 +1,10 @@ package app import ( - upgradetypes "cosmossdk.io/x/upgrade/types" "fmt" - "github.com/CosmWasm/wasmd/app/upgrades" - v043 "github.com/CosmWasm/wasmd/app/upgrades/v043" + + upgradetypes "cosmossdk.io/x/upgrade/types" + paramskeeper "github.com/cosmos/cosmos-sdk/x/params/keeper" paramstypes "github.com/cosmos/cosmos-sdk/x/params/types" icacontrollertypes "github.com/cosmos/ibc-go/v8/modules/apps/27-interchain-accounts/controller/types" @@ -13,10 +13,14 @@ import ( ibcclienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" ibcconnectiontypes "github.com/cosmos/ibc-go/v8/modules/core/03-connection/types" ibcexported "github.com/cosmos/ibc-go/v8/modules/core/exported" + + "github.com/CosmWasm/wasmd/app/upgrades" + v043 "github.com/CosmWasm/wasmd/app/upgrades/v043" + v050 "github.com/CosmWasm/wasmd/app/upgrades/v050" ) // Upgrades list of chain upgrades -var Upgrades = []upgrades.Upgrade{v043.Upgrade} +var Upgrades = []upgrades.Upgrade{v043.Upgrade, v050.Upgrade} // RegisterUpgradeHandlers registers the chain upgrade handlers func (app WasmApp) RegisterUpgradeHandlers() { @@ -47,7 +51,7 @@ func (app WasmApp) RegisterUpgradeHandlers() { // register store loader for current upgrade for _, upgrade := range Upgrades { if upgradeInfo.Name == upgrade.UpgradeName { - app.SetStoreLoader(upgradetypes.UpgradeStoreLoader(upgradeInfo.Height, &upgrade.StoreUpgrades)) + app.SetStoreLoader(upgradetypes.UpgradeStoreLoader(upgradeInfo.Height, &upgrade.StoreUpgrades)) // nolint:gosec break } } diff --git a/app/upgrades/types.go b/app/upgrades/types.go index 5cfce557f5..74808b079f 100644 --- a/app/upgrades/types.go +++ b/app/upgrades/types.go @@ -1,10 +1,10 @@ package upgrades import ( - store "github.com/cosmos/cosmos-sdk/store/types" + storetypes "cosmossdk.io/store/types" + upgradetypes "cosmossdk.io/x/upgrade/types" "github.com/cosmos/cosmos-sdk/types/module" authkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper" - upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types" ) type AppKeepers struct { @@ -21,5 +21,5 @@ type Upgrade struct { // CreateUpgradeHandler defines the function that creates an upgrade handler CreateUpgradeHandler func(*module.Manager, module.Configurator, *AppKeepers) upgradetypes.UpgradeHandler - StoreUpgrades store.StoreUpgrades + StoreUpgrades storetypes.StoreUpgrades } diff --git a/app/upgrades/v043/upgrades.go b/app/upgrades/v043/upgrades.go index bca64c425f..5193a3b658 100644 --- a/app/upgrades/v043/upgrades.go +++ b/app/upgrades/v043/upgrades.go @@ -1,11 +1,13 @@ package v043 import ( - "github.com/CosmWasm/wasmd/app/upgrades" - store "github.com/cosmos/cosmos-sdk/store/types" - sdk "github.com/cosmos/cosmos-sdk/types" + "context" + + storetypes "cosmossdk.io/store/types" + upgradetypes "cosmossdk.io/x/upgrade/types" "github.com/cosmos/cosmos-sdk/types/module" - upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types" + + "github.com/CosmWasm/wasmd/app/upgrades" ) // UpgradeName defines the on-chain upgrade name @@ -14,7 +16,7 @@ const UpgradeName = "v0.43" var Upgrade = upgrades.Upgrade{ UpgradeName: UpgradeName, CreateUpgradeHandler: CreateUpgradeHandler, - StoreUpgrades: store.StoreUpgrades{ + StoreUpgrades: storetypes.StoreUpgrades{ Added: []string{}, Deleted: []string{}, }, @@ -25,7 +27,7 @@ func CreateUpgradeHandler( configurator module.Configurator, ak *upgrades.AppKeepers, ) upgradetypes.UpgradeHandler { - return func(ctx sdk.Context, plan upgradetypes.Plan, fromVM module.VersionMap) (module.VersionMap, error) { + return func(ctx context.Context, plan upgradetypes.Plan, fromVM module.VersionMap) (module.VersionMap, error) { return mm.RunMigrations(ctx, configurator, fromVM) } } diff --git a/app/upgrades/v050/upgrades.go b/app/upgrades/v050/upgrades.go new file mode 100644 index 0000000000..b711a4b82a --- /dev/null +++ b/app/upgrades/v050/upgrades.go @@ -0,0 +1,38 @@ +package v050 + +import ( + "context" + + storetypes "cosmossdk.io/store/types" + upgradetypes "cosmossdk.io/x/upgrade/types" + "github.com/cosmos/cosmos-sdk/types/module" + consensustypes "github.com/cosmos/cosmos-sdk/x/consensus/types" + crisistypes "github.com/cosmos/cosmos-sdk/x/crisis/types" + + "github.com/CosmWasm/wasmd/app/upgrades" +) + +// UpgradeName defines the on-chain upgrade name +const UpgradeName = "v0.50" + +var Upgrade = upgrades.Upgrade{ + UpgradeName: UpgradeName, + CreateUpgradeHandler: CreateUpgradeHandler, + StoreUpgrades: storetypes.StoreUpgrades{ + Added: []string{ + consensustypes.ModuleName, + crisistypes.ModuleName, + }, + Deleted: []string{}, + }, +} + +func CreateUpgradeHandler( + mm *module.Manager, + configurator module.Configurator, + ak *upgrades.AppKeepers, +) upgradetypes.UpgradeHandler { + return func(ctx context.Context, plan upgradetypes.Plan, fromVM module.VersionMap) (module.VersionMap, error) { + return mm.RunMigrations(ctx, configurator, fromVM) + } +} From e720c00764a66d0751c884a85d4f9678262ded40 Mon Sep 17 00:00:00 2001 From: Alex Peters Date: Thu, 5 Oct 2023 09:43:43 +0200 Subject: [PATCH 16/27] Gci formatting --- Makefile | 4 ++-- app/upgrades.go | 9 +++++---- app/upgrades/types.go | 1 + app/upgrades/v043/upgrades.go | 1 + app/upgrades/v050/upgrades.go | 1 + tests/system/Makefile | 3 +-- tests/system/upgrade_test.go | 1 - x/wasm/keeper/keeper_no_cgo.go | 1 + x/wasm/keeper/testdata/contracts.go | 1 + 9 files changed, 13 insertions(+), 9 deletions(-) diff --git a/Makefile b/Makefile index 06ad540ddf..114f56b2be 100644 --- a/Makefile +++ b/Makefile @@ -161,7 +161,7 @@ test-system: install format-tools: go install mvdan.cc/gofumpt@v0.4.0 go install github.com/client9/misspell/cmd/misspell@v0.3.4 - go install golang.org/x/tools/cmd/goimports@latest + go install github.com/daixiang0/gci@v0.11.2 lint: format-tools golangci-lint run --tests=false @@ -170,7 +170,7 @@ lint: format-tools format: format-tools find . -name '*.go' -type f -not -path "./vendor*" -not -path "./tests/system/vendor*" -not -path "*.git*" -not -path "./client/lcd/statik/statik.go" | xargs gofumpt -w find . -name '*.go' -type f -not -path "./vendor*" -not -path "./tests/system/vendor*" -not -path "*.git*" -not -path "./client/lcd/statik/statik.go" | xargs misspell -w - find . -name '*.go' -type f -not -path "./vendor*" -not -path "./tests/system/vendor*" -not -path "*.git*" -not -path "./client/lcd/statik/statik.go" | xargs goimports -w -local github.com/CosmWasm/wasmd + find . -name '*.go' -type f -not -path "./vendor*" -not -path "./tests/system/vendor*" -not -path "*.git*" -not -path "./client/lcd/statik/statik.go" | xargs gci write --skip-generated -s standard -s default -s "prefix(cosmossdk.io)" -s "prefix(github.com/cosmos/cosmos-sdk)" -s "prefix(github.com/CosmWasm/wasmd)" --custom-order ############################################################################### diff --git a/app/upgrades.go b/app/upgrades.go index eca2496a9a..d6458d33d3 100644 --- a/app/upgrades.go +++ b/app/upgrades.go @@ -3,10 +3,6 @@ package app import ( "fmt" - upgradetypes "cosmossdk.io/x/upgrade/types" - - paramskeeper "github.com/cosmos/cosmos-sdk/x/params/keeper" - paramstypes "github.com/cosmos/cosmos-sdk/x/params/types" icacontrollertypes "github.com/cosmos/ibc-go/v8/modules/apps/27-interchain-accounts/controller/types" icahosttypes "github.com/cosmos/ibc-go/v8/modules/apps/27-interchain-accounts/host/types" ibctransfertypes "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types" @@ -14,6 +10,11 @@ import ( ibcconnectiontypes "github.com/cosmos/ibc-go/v8/modules/core/03-connection/types" ibcexported "github.com/cosmos/ibc-go/v8/modules/core/exported" + upgradetypes "cosmossdk.io/x/upgrade/types" + + paramskeeper "github.com/cosmos/cosmos-sdk/x/params/keeper" + paramstypes "github.com/cosmos/cosmos-sdk/x/params/types" + "github.com/CosmWasm/wasmd/app/upgrades" v043 "github.com/CosmWasm/wasmd/app/upgrades/v043" v050 "github.com/CosmWasm/wasmd/app/upgrades/v050" diff --git a/app/upgrades/types.go b/app/upgrades/types.go index 74808b079f..02d31dab73 100644 --- a/app/upgrades/types.go +++ b/app/upgrades/types.go @@ -3,6 +3,7 @@ package upgrades import ( storetypes "cosmossdk.io/store/types" upgradetypes "cosmossdk.io/x/upgrade/types" + "github.com/cosmos/cosmos-sdk/types/module" authkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper" ) diff --git a/app/upgrades/v043/upgrades.go b/app/upgrades/v043/upgrades.go index 5193a3b658..909d01e8c4 100644 --- a/app/upgrades/v043/upgrades.go +++ b/app/upgrades/v043/upgrades.go @@ -5,6 +5,7 @@ import ( storetypes "cosmossdk.io/store/types" upgradetypes "cosmossdk.io/x/upgrade/types" + "github.com/cosmos/cosmos-sdk/types/module" "github.com/CosmWasm/wasmd/app/upgrades" diff --git a/app/upgrades/v050/upgrades.go b/app/upgrades/v050/upgrades.go index b711a4b82a..118ed0e81c 100644 --- a/app/upgrades/v050/upgrades.go +++ b/app/upgrades/v050/upgrades.go @@ -5,6 +5,7 @@ import ( storetypes "cosmossdk.io/store/types" upgradetypes "cosmossdk.io/x/upgrade/types" + "github.com/cosmos/cosmos-sdk/types/module" consensustypes "github.com/cosmos/cosmos-sdk/x/consensus/types" crisistypes "github.com/cosmos/cosmos-sdk/x/crisis/types" diff --git a/tests/system/Makefile b/tests/system/Makefile index 641305df18..b2396fd3fb 100644 --- a/tests/system/Makefile +++ b/tests/system/Makefile @@ -10,7 +10,6 @@ test: format: find . -name '*.go' -type f -not -path "./vendor*" -not -path "*.git*" -not -path "./client/lcd/statik/statik.go" | xargs gofumpt -w find . -name '*.go' -type f -not -path "./vendor*" -not -path "*.git*" -not -path "./client/lcd/statik/statik.go" | xargs misspell -w - find . -name '*.go' -type f -not -path "./vendor*" -not -path "*.git*" -not -path "./client/lcd/statik/statik.go" | xargs goimports -w -local github.com/CosmWasm/wasmd - + find . -name '*.go' -type f -not -path "./vendor*" -not -path "./tests/system/vendor*" -not -path "*.git*" -not -path "./client/lcd/statik/statik.go" | xargs gci write --skip-generated -s standard -s default -s "prefix(cosmossdk.io)" -s "prefix(github.com/cosmos/cosmos-sdk)" -s "prefix(github.com/CosmWasm/wasmd)" --custom-order .PHONY: all test format diff --git a/tests/system/upgrade_test.go b/tests/system/upgrade_test.go index f48e6dfc73..116bb91d15 100644 --- a/tests/system/upgrade_test.go +++ b/tests/system/upgrade_test.go @@ -14,7 +14,6 @@ import ( "time" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" "github.com/tidwall/gjson" ) diff --git a/x/wasm/keeper/keeper_no_cgo.go b/x/wasm/keeper/keeper_no_cgo.go index e0b86812d3..261b2bad2a 100644 --- a/x/wasm/keeper/keeper_no_cgo.go +++ b/x/wasm/keeper/keeper_no_cgo.go @@ -4,6 +4,7 @@ package keeper import ( storetypes "cosmossdk.io/store/types" + "github.com/cosmos/cosmos-sdk/codec" "github.com/CosmWasm/wasmd/x/wasm/types" diff --git a/x/wasm/keeper/testdata/contracts.go b/x/wasm/keeper/testdata/contracts.go index dc81aa23d5..299fc9a324 100644 --- a/x/wasm/keeper/testdata/contracts.go +++ b/x/wasm/keeper/testdata/contracts.go @@ -4,6 +4,7 @@ import ( _ "embed" typwasmvmtypes "github.com/CosmWasm/wasmvm/types" + "github.com/cosmos/cosmos-sdk/types" ) From b803493e7cc172c21473ec2dab91ebe601f51670 Mon Sep 17 00:00:00 2001 From: Alex Peters Date: Fri, 6 Oct 2023 11:11:17 +0200 Subject: [PATCH 17/27] Updates --- tests/system/system.go | 2 +- tests/system/upgrade_test.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/system/system.go b/tests/system/system.go index e5fc27dbc1..f80f52de8c 100644 --- a/tests/system/system.go +++ b/tests/system/system.go @@ -386,7 +386,7 @@ func (s *SystemUnderTest) AwaitBlockHeight(t *testing.T, targetHeight int64, tim t.Fatalf("Timeout - block %d not reached within %s", targetHeight, maxWaitTime) return default: - if current := s.AwaitNextBlock(t); current == targetHeight { + if current := s.AwaitNextBlock(t); current >= targetHeight { return } } diff --git a/tests/system/upgrade_test.go b/tests/system/upgrade_test.go index 116bb91d15..46c2774879 100644 --- a/tests/system/upgrade_test.go +++ b/tests/system/upgrade_test.go @@ -78,7 +78,7 @@ func TestChainUpgrade(t *testing.T) { sut.AwaitBlockHeight(t, upgradeHeight-1) t.Logf("current_height: %d\n", sut.currentHeight) raw = cli.CustomQuery("q", "gov", "proposal", proposalID) - proposalStatus := gjson.Get(raw, "proposal.status").String() + proposalStatus := gjson.Get(raw, "status").String() require.Equal(t, "PROPOSAL_STATUS_PASSED", proposalStatus, raw) t.Log("waiting for upgrade info") From 7a320508ba05652168ccd81589949f4976c0c05d Mon Sep 17 00:00:00 2001 From: Alex Peters Date: Fri, 6 Oct 2023 13:00:04 +0200 Subject: [PATCH 18/27] Testnet commit timeout --- cmd/wasmd/testnet.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cmd/wasmd/testnet.go b/cmd/wasmd/testnet.go index f07be8d8bb..60b9cc1b4f 100644 --- a/cmd/wasmd/testnet.go +++ b/cmd/wasmd/testnet.go @@ -82,6 +82,7 @@ type startArgs struct { outputDir string printMnemonic bool rpcAddress string + timeoutCommit time.Duration } func addTestnetFlagsToCmd(cmd *cobra.Command) { @@ -159,7 +160,6 @@ Example: if err != nil { return err } - return initTestnetFiles(clientCtx, cmd, config, mbm, genBalIterator, clientCtx.TxConfig.SigningContext().ValidatorAddressCodec(), args) }, } @@ -553,6 +553,7 @@ func startTestnet(cmd *cobra.Command, args startArgs) error { networkConfig.APIAddress = args.apiAddress networkConfig.GRPCAddress = args.grpcAddress networkConfig.PrintMnemonic = args.printMnemonic + networkConfig.TimeoutCommit = args.timeoutCommit networkLogger := network.NewCLILogger(cmd) baseDir := fmt.Sprintf("%s/%s", args.outputDir, networkConfig.ChainID) From cb1fc1bb18fba129dc35ee88622dd7aa4c28dd1d Mon Sep 17 00:00:00 2001 From: Alex Peters Date: Mon, 9 Oct 2023 14:40:21 +0200 Subject: [PATCH 19/27] Update --- tests/system/upgrade_test.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/system/upgrade_test.go b/tests/system/upgrade_test.go index 46c2774879..4bcdd63655 100644 --- a/tests/system/upgrade_test.go +++ b/tests/system/upgrade_test.go @@ -29,7 +29,7 @@ func TestChainUpgrade(t *testing.T) { currentBranchBinary := sut.ExecBinary sut.ExecBinary = legacyBinary sut.SetupChain() - votingPeriod := 10 * time.Second // enough time to vote + votingPeriod := 5 * time.Second // enough time to vote sut.ModifyGenesisJSON(t, SetGovVotingPeriod(t, votingPeriod)) const ( @@ -44,6 +44,7 @@ func TestChainUpgrade(t *testing.T) { // set some state to ensure that migrations work verifierAddr := cli.AddKey("verifier") beneficiary := randomBech32Addr() + cli.FundAddress(verifierAddr, "1000stake") t.Log("Launch hackatom contract") codeID := cli.WasmStore("./testdata/hackatom.wasm.gzip") @@ -89,13 +90,12 @@ func TestChainUpgrade(t *testing.T) { sut.ExecBinary = currentBranchBinary sut.StartChain(t) - t.Skip("wasmvm 1.4 upgrade fails, currently. Skipping for now") // ensure that state matches expectations gotRsp = cli.QuerySmart(contractAddr, `{"verifier":{}}`) require.Equal(t, fmt.Sprintf(`{"data":{"verifier":"%s"}}`, verifierAddr), gotRsp) // and contract execution works as expected - RequireTxSuccess(t, cli.WasmExecute(contractAddr, verifierAddr, `{"release":{}}`)) - assert.Equal(t, 1_000_000, cli.QueryBalance(beneficiary, "stake")) + RequireTxSuccess(t, cli.WasmExecute(contractAddr, `{"release":{}}`, verifierAddr)) + assert.Equal(t, int64(1_000_000), cli.QueryBalance(beneficiary, "stake")) } const cacheDir = "binaries" From 00af1759707c28e537259c2551bf4fc6edbbc2e4 Mon Sep 17 00:00:00 2001 From: Alex Peters Date: Mon, 9 Oct 2023 16:01:23 +0200 Subject: [PATCH 20/27] Store artifacts on system test failure --- .circleci/config.yml | 8 ++++++++ app/upgrades.go | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 55547e0640..09897bf8d1 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -112,6 +112,14 @@ jobs: - run: name: Build and run system tests command: make test-system + - run: + when: on_success + name: Clear system test work dir + command: rm -rf /tmp/workspace/tests/system/testnet + - store_artifacts: + path: /tmp/workspace/tests/system/testnet + + benchmark: executor: golang diff --git a/app/upgrades.go b/app/upgrades.go index d6458d33d3..87e8d64bc1 100644 --- a/app/upgrades.go +++ b/app/upgrades.go @@ -6,7 +6,7 @@ import ( icacontrollertypes "github.com/cosmos/ibc-go/v8/modules/apps/27-interchain-accounts/controller/types" icahosttypes "github.com/cosmos/ibc-go/v8/modules/apps/27-interchain-accounts/host/types" ibctransfertypes "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types" - ibcclienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" + ibcclienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" //nolint:staticcheck ibcconnectiontypes "github.com/cosmos/ibc-go/v8/modules/core/03-connection/types" ibcexported "github.com/cosmos/ibc-go/v8/modules/core/exported" From 27b1c9a984efd4abe9caf30f2070c067fdf7e09e Mon Sep 17 00:00:00 2001 From: Alex Peters Date: Mon, 9 Oct 2023 16:04:04 +0200 Subject: [PATCH 21/27] Better circleci setup --- .circleci/config.yml | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 09897bf8d1..9de48baf74 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -113,13 +113,12 @@ jobs: name: Build and run system tests command: make test-system - run: - when: on_success - name: Clear system test work dir - command: rm -rf /tmp/workspace/tests/system/testnet + command: | + mkdir -p /tmp/system-test-workspace + mv /tmp/workspace/tests/system/testnet /tmp/system-test-workspace + when: on_fail - store_artifacts: - path: /tmp/workspace/tests/system/testnet - - + path: /tmp/system-test-workspace benchmark: executor: golang From fb5a8d8cba7e41b4bd246d15ef8946dd68021070 Mon Sep 17 00:00:00 2001 From: Alex Peters Date: Tue, 10 Oct 2023 08:51:06 +0200 Subject: [PATCH 22/27] Artifact path --- .circleci/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 9de48baf74..7a8fcab642 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -115,7 +115,7 @@ jobs: - run: command: | mkdir -p /tmp/system-test-workspace - mv /tmp/workspace/tests/system/testnet /tmp/system-test-workspace + mv /home/circleci/project/tests/system/testnet /tmp/system-test-workspace when: on_fail - store_artifacts: path: /tmp/system-test-workspace From 88f5787ac46b8825182c93d25dd41c7e75bb17db Mon Sep 17 00:00:00 2001 From: Alex Peters Date: Tue, 10 Oct 2023 11:01:47 +0200 Subject: [PATCH 23/27] x --- tests/system/upgrade_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/system/upgrade_test.go b/tests/system/upgrade_test.go index 4bcdd63655..a556a16b16 100644 --- a/tests/system/upgrade_test.go +++ b/tests/system/upgrade_test.go @@ -37,7 +37,7 @@ func TestChainUpgrade(t *testing.T) { upgradeName = "v0.50" ) - sut.StartChain(t, fmt.Sprintf("--halt-height=%d", upgradeHeight)) + sut.StartChain(t, fmt.Sprintf("--halt-height=%d", upgradeHeight+1)) cli := NewWasmdCLI(t, sut, verbose) From d01bb49d4f543b72f7745b21cceeee1d0d672fad Mon Sep 17 00:00:00 2001 From: Alex Peters Date: Tue, 10 Oct 2023 12:31:39 +0200 Subject: [PATCH 24/27] Fix upgrade --- app/upgrades/v050/upgrades.go | 6 ++---- tests/system/system.go | 4 ++-- tests/system/upgrade_test.go | 3 ++- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/app/upgrades/v050/upgrades.go b/app/upgrades/v050/upgrades.go index 118ed0e81c..5ba00e2bbe 100644 --- a/app/upgrades/v050/upgrades.go +++ b/app/upgrades/v050/upgrades.go @@ -4,11 +4,10 @@ import ( "context" storetypes "cosmossdk.io/store/types" + circuittypes "cosmossdk.io/x/circuit/types" upgradetypes "cosmossdk.io/x/upgrade/types" "github.com/cosmos/cosmos-sdk/types/module" - consensustypes "github.com/cosmos/cosmos-sdk/x/consensus/types" - crisistypes "github.com/cosmos/cosmos-sdk/x/crisis/types" "github.com/CosmWasm/wasmd/app/upgrades" ) @@ -21,8 +20,7 @@ var Upgrade = upgrades.Upgrade{ CreateUpgradeHandler: CreateUpgradeHandler, StoreUpgrades: storetypes.StoreUpgrades{ Added: []string{ - consensustypes.ModuleName, - crisistypes.ModuleName, + circuittypes.ModuleName, }, Deleted: []string{}, }, diff --git a/tests/system/system.go b/tests/system/system.go index f80f52de8c..461c85c19b 100644 --- a/tests/system/system.go +++ b/tests/system/system.go @@ -201,7 +201,7 @@ func (s *SystemUnderTest) watchLogs(node int, cmd *exec.Cmd) { go appendToBuf(io.TeeReader(outReader, logfile), s.outBuff, stopRingBuffer) s.cleanupFn = append(s.cleanupFn, func() { close(stopRingBuffer) - logfile.Close() + _ = logfile.Close() }) } @@ -247,7 +247,7 @@ func (s *SystemUnderTest) AwaitUpgradeInfo(t *testing.T) { t.Fatalf(err.Error()) } }) - time.Sleep(s.blockTime) + time.Sleep(s.blockTime / 2) } } diff --git a/tests/system/upgrade_test.go b/tests/system/upgrade_test.go index a556a16b16..9196862756 100644 --- a/tests/system/upgrade_test.go +++ b/tests/system/upgrade_test.go @@ -37,7 +37,7 @@ func TestChainUpgrade(t *testing.T) { upgradeName = "v0.50" ) - sut.StartChain(t, fmt.Sprintf("--halt-height=%d", upgradeHeight+1)) + sut.StartChain(t, fmt.Sprintf("--halt-height=%d", upgradeHeight)) cli := NewWasmdCLI(t, sut, verbose) @@ -89,6 +89,7 @@ func TestChainUpgrade(t *testing.T) { t.Log("Upgrade height was reached. Upgrading chain") sut.ExecBinary = currentBranchBinary sut.StartChain(t) + cli = NewWasmdCLI(t, sut, verbose) // ensure that state matches expectations gotRsp = cli.QuerySmart(contractAddr, `{"verifier":{}}`) From 8f2888bab251228084b41118e66ed3adad2d0680 Mon Sep 17 00:00:00 2001 From: Alex Peters Date: Wed, 11 Oct 2023 10:46:23 +0200 Subject: [PATCH 25/27] Generic upgrade handler --- app/upgrades.go | 8 ++++++-- app/upgrades/noop/upgrades.go | 32 ++++++++++++++++++++++++++++++++ app/upgrades/v043/upgrades.go | 34 ---------------------------------- tests/system/cli.go | 7 +++++++ 4 files changed, 45 insertions(+), 36 deletions(-) create mode 100644 app/upgrades/noop/upgrades.go delete mode 100644 app/upgrades/v043/upgrades.go diff --git a/app/upgrades.go b/app/upgrades.go index 87e8d64bc1..f8634ac0f2 100644 --- a/app/upgrades.go +++ b/app/upgrades.go @@ -16,16 +16,20 @@ import ( paramstypes "github.com/cosmos/cosmos-sdk/x/params/types" "github.com/CosmWasm/wasmd/app/upgrades" - v043 "github.com/CosmWasm/wasmd/app/upgrades/v043" + "github.com/CosmWasm/wasmd/app/upgrades/noop" v050 "github.com/CosmWasm/wasmd/app/upgrades/v050" ) // Upgrades list of chain upgrades -var Upgrades = []upgrades.Upgrade{v043.Upgrade, v050.Upgrade} +var Upgrades = []upgrades.Upgrade{v050.Upgrade} // RegisterUpgradeHandlers registers the chain upgrade handlers func (app WasmApp) RegisterUpgradeHandlers() { setupLegacyKeyTables(app.ParamsKeeper) + if len(Upgrades) == 0 { + // always have a unique upgrade registered for the current version to test in system tests + Upgrades = append(Upgrades, noop.NewUpgrade(app.Version())) + } keepers := upgrades.AppKeepers{AccountKeeper: app.AccountKeeper} // register all upgrade handlers diff --git a/app/upgrades/noop/upgrades.go b/app/upgrades/noop/upgrades.go new file mode 100644 index 0000000000..ffd68b422c --- /dev/null +++ b/app/upgrades/noop/upgrades.go @@ -0,0 +1,32 @@ +package noop + +import ( + store "github.com/cosmos/cosmos-sdk/store/types" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/module" + upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types" + + "github.com/CosmWasm/wasmd/app/upgrades" +) + +// NewUpgrade constructor +func NewUpgrade(semver string) upgrades.Upgrade { + return upgrades.Upgrade{ + UpgradeName: semver, + CreateUpgradeHandler: CreateUpgradeHandler, + StoreUpgrades: store.StoreUpgrades{ + Added: []string{}, + Deleted: []string{}, + }, + } +} + +func CreateUpgradeHandler( + mm *module.Manager, + configurator module.Configurator, + ak *upgrades.AppKeepers, +) upgradetypes.UpgradeHandler { + return func(ctx sdk.Context, plan upgradetypes.Plan, fromVM module.VersionMap) (module.VersionMap, error) { + return mm.RunMigrations(ctx, configurator, fromVM) + } +} diff --git a/app/upgrades/v043/upgrades.go b/app/upgrades/v043/upgrades.go deleted file mode 100644 index 909d01e8c4..0000000000 --- a/app/upgrades/v043/upgrades.go +++ /dev/null @@ -1,34 +0,0 @@ -package v043 - -import ( - "context" - - storetypes "cosmossdk.io/store/types" - upgradetypes "cosmossdk.io/x/upgrade/types" - - "github.com/cosmos/cosmos-sdk/types/module" - - "github.com/CosmWasm/wasmd/app/upgrades" -) - -// UpgradeName defines the on-chain upgrade name -const UpgradeName = "v0.43" - -var Upgrade = upgrades.Upgrade{ - UpgradeName: UpgradeName, - CreateUpgradeHandler: CreateUpgradeHandler, - StoreUpgrades: storetypes.StoreUpgrades{ - Added: []string{}, - Deleted: []string{}, - }, -} - -func CreateUpgradeHandler( - mm *module.Manager, - configurator module.Configurator, - ak *upgrades.AppKeepers, -) upgradetypes.UpgradeHandler { - return func(ctx context.Context, plan upgradetypes.Plan, fromVM module.VersionMap) (module.VersionMap, error) { - return mm.RunMigrations(ctx, configurator, fromVM) - } -} diff --git a/tests/system/cli.go b/tests/system/cli.go index 5fb915366b..40772713ba 100644 --- a/tests/system/cli.go +++ b/tests/system/cli.go @@ -422,6 +422,13 @@ func (c WasmdCli) SubmitAndVoteGovProposal(proposalJson string, args ...string) return ourProposalID } +// Version returns the current version of the client binary +func (c WasmdCli) Version() string { + v, ok := c.run([]string{"version"}) + require.True(c.t, ok) + return v +} + // RequireTxSuccess require the received response to contain the success code func RequireTxSuccess(t *testing.T, got string) { t.Helper() From c0c0f986bed3f6c92f3f001ec88641abaeb50c77 Mon Sep 17 00:00:00 2001 From: Alex Peters Date: Thu, 12 Oct 2023 09:13:26 +0200 Subject: [PATCH 26/27] Fix imports --- app/upgrades/noop/upgrades.go | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/app/upgrades/noop/upgrades.go b/app/upgrades/noop/upgrades.go index ffd68b422c..3458b1385e 100644 --- a/app/upgrades/noop/upgrades.go +++ b/app/upgrades/noop/upgrades.go @@ -1,10 +1,12 @@ package noop import ( - store "github.com/cosmos/cosmos-sdk/store/types" - sdk "github.com/cosmos/cosmos-sdk/types" + "context" + + storetypes "cosmossdk.io/store/types" + upgradetypes "cosmossdk.io/x/upgrade/types" + "github.com/cosmos/cosmos-sdk/types/module" - upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types" "github.com/CosmWasm/wasmd/app/upgrades" ) @@ -14,7 +16,7 @@ func NewUpgrade(semver string) upgrades.Upgrade { return upgrades.Upgrade{ UpgradeName: semver, CreateUpgradeHandler: CreateUpgradeHandler, - StoreUpgrades: store.StoreUpgrades{ + StoreUpgrades: storetypes.StoreUpgrades{ Added: []string{}, Deleted: []string{}, }, @@ -26,7 +28,7 @@ func CreateUpgradeHandler( configurator module.Configurator, ak *upgrades.AppKeepers, ) upgradetypes.UpgradeHandler { - return func(ctx sdk.Context, plan upgradetypes.Plan, fromVM module.VersionMap) (module.VersionMap, error) { + return func(ctx context.Context, plan upgradetypes.Plan, fromVM module.VersionMap) (module.VersionMap, error) { return mm.RunMigrations(ctx, configurator, fromVM) } } From c18d088dbe2919bdd0547c3fe3c607858d889207 Mon Sep 17 00:00:00 2001 From: Alexander Peters Date: Fri, 13 Oct 2023 13:51:12 +0200 Subject: [PATCH 27/27] Update tests/system/cli.go Co-authored-by: pinosu <95283998+pinosu@users.noreply.github.com> --- tests/system/cli.go | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/system/cli.go b/tests/system/cli.go index 40772713ba..600dcf9ee0 100644 --- a/tests/system/cli.go +++ b/tests/system/cli.go @@ -389,7 +389,6 @@ func (c WasmdCli) IsInCometBftValset(valPubKey cryptotypes.PubKey) (cmtservice.G return valResult, found } -// SubmitUpgradeGovProposal submit a chain upgrade gov v1 proposal // SubmitGovProposal submit a gov v1 proposal func (c WasmdCli) SubmitGovProposal(proposalJson string, args ...string) string {