From 2597fdfc785b132629452afc3547747ca9d9cf85 Mon Sep 17 00:00:00 2001 From: GuillemGarciaDev Date: Sun, 19 Jan 2025 15:06:36 +0100 Subject: [PATCH 01/25] feat(tests/e2e): bring evmos e2e upgrade test suite --- go.mod | 22 +- go.sum | 28 +- tests/e2e/README.md | 239 +++++++++++++++ tests/e2e/e2e_suite_test.go | 333 ++++++++++++++++++++ tests/e2e/e2e_test.go | 37 +++ tests/e2e/init-node.sh | 164 ++++++++++ tests/e2e/tx_test.go | 66 ++++ tests/e2e/upgrade/Dockerfile.init | 15 + tests/e2e/upgrade/balances.go | 49 +++ tests/e2e/upgrade/balances_test.go | 70 +++++ tests/e2e/upgrade/constants.go | 24 ++ tests/e2e/upgrade/exec.go | 38 +++ tests/e2e/upgrade/govexec.go | 142 +++++++++ tests/e2e/upgrade/manager.go | 468 +++++++++++++++++++++++++++++ tests/e2e/upgrade/manager_test.go | 25 ++ tests/e2e/upgrade/node.go | 63 ++++ tests/e2e/upgrade/params.go | 152 ++++++++++ tests/e2e/upgrade/params_test.go | 177 +++++++++++ tests/e2e/upgrade/queryexec.go | 61 ++++ tests/e2e/upgrade/utils.go | 129 ++++++++ tests/e2e/upgrade/utils_test.go | 107 +++++++ 21 files changed, 2407 insertions(+), 2 deletions(-) create mode 100644 tests/e2e/README.md create mode 100644 tests/e2e/e2e_suite_test.go create mode 100644 tests/e2e/e2e_test.go create mode 100755 tests/e2e/init-node.sh create mode 100644 tests/e2e/tx_test.go create mode 100644 tests/e2e/upgrade/Dockerfile.init create mode 100644 tests/e2e/upgrade/balances.go create mode 100644 tests/e2e/upgrade/balances_test.go create mode 100644 tests/e2e/upgrade/constants.go create mode 100644 tests/e2e/upgrade/exec.go create mode 100644 tests/e2e/upgrade/govexec.go create mode 100644 tests/e2e/upgrade/manager.go create mode 100644 tests/e2e/upgrade/manager_test.go create mode 100644 tests/e2e/upgrade/node.go create mode 100644 tests/e2e/upgrade/params.go create mode 100644 tests/e2e/upgrade/params_test.go create mode 100644 tests/e2e/upgrade/queryexec.go create mode 100644 tests/e2e/upgrade/utils.go create mode 100644 tests/e2e/upgrade/utils_test.go diff --git a/go.mod b/go.mod index 109650a..bf59b9f 100644 --- a/go.mod +++ b/go.mod @@ -31,6 +31,8 @@ require ( github.com/gorilla/mux v1.8.1 github.com/grpc-ecosystem/grpc-gateway v1.16.0 github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.2 + github.com/hashicorp/go-version v1.7.0 + github.com/ory/dockertest/v3 v3.11.0 github.com/spf13/cast v1.7.0 github.com/spf13/cobra v1.8.1 github.com/spf13/pflag v1.0.5 @@ -53,11 +55,15 @@ require ( cosmossdk.io/depinject v1.0.0 // indirect cosmossdk.io/x/circuit v0.1.1 // indirect cosmossdk.io/x/tx v0.13.4 // indirect + dario.cat/mergo v1.0.0 // indirect filippo.io/edwards25519 v1.1.0 // indirect github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 // indirect github.com/99designs/keyring v1.2.2 // indirect + github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 // indirect github.com/DataDog/datadog-go v3.2.0+incompatible // indirect github.com/DataDog/zstd v1.5.5 // indirect + github.com/Microsoft/go-winio v0.6.2 // indirect + github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 // indirect github.com/PuerkitoBio/purell v1.1.1 // indirect github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect github.com/StackExchange/wmi v1.2.1 // indirect @@ -84,6 +90,7 @@ require ( github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06 // indirect github.com/coinbase/rosetta-sdk-go v0.7.9 // indirect github.com/cometbft/cometbft-db v0.14.1 // indirect + github.com/containerd/continuity v0.4.3 // indirect github.com/cosmos/btcutil v1.0.5 // indirect github.com/cosmos/go-bip39 v1.0.0 // indirect github.com/cosmos/gogogateway v1.2.0 // indirect @@ -105,6 +112,10 @@ require ( github.com/dgraph-io/badger/v4 v4.2.0 // indirect github.com/dgraph-io/ristretto v0.1.1 // indirect github.com/dlclark/regexp2 v1.7.0 // indirect + github.com/docker/cli v26.1.4+incompatible // indirect + github.com/docker/docker v27.1.1+incompatible // indirect + github.com/docker/go-connections v0.5.0 // indirect + github.com/docker/go-units v0.5.0 // indirect github.com/dop251/goja v0.0.0-20230122112309-96b1610dd4f7 // indirect github.com/dustin/go-humanize v1.0.1 // indirect github.com/dvsekhvalnov/jose2go v1.6.0 // indirect @@ -135,6 +146,7 @@ require ( github.com/google/go-cmp v0.6.0 // indirect github.com/google/orderedcode v0.0.1 // indirect github.com/google/s2a-go v0.1.7 // indirect + github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect github.com/google/uuid v1.6.0 // indirect github.com/googleapis/enterprise-certificate-proxy v0.3.2 // indirect github.com/googleapis/gax-go/v2 v2.12.5 // indirect @@ -150,7 +162,6 @@ require ( github.com/hashicorp/go-metrics v0.5.3 // indirect github.com/hashicorp/go-plugin v1.6.0 // indirect github.com/hashicorp/go-safetemp v1.0.0 // indirect - github.com/hashicorp/go-version v1.7.0 // indirect github.com/hashicorp/golang-lru v1.0.2 // indirect github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect github.com/hashicorp/hcl v1.0.0 // indirect @@ -181,11 +192,16 @@ require ( github.com/mitchellh/go-homedir v1.1.0 // indirect github.com/mitchellh/go-testing-interface v1.14.1 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/moby/docker-image-spec v1.3.1 // indirect + github.com/moby/term v0.5.0 // indirect github.com/mtibben/percent v0.2.1 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/oasisprotocol/curve25519-voi v0.0.0-20230904125328-1f23a7beb09a // indirect github.com/oklog/run v1.1.0 // indirect github.com/olekukonko/tablewriter v0.0.5 // indirect + github.com/opencontainers/go-digest v1.0.0 // indirect + github.com/opencontainers/image-spec v1.1.0 // indirect + github.com/opencontainers/runc v1.1.13 // indirect github.com/pelletier/go-toml/v2 v2.2.2 // indirect github.com/petermattis/goid v0.0.0-20240813172612-4fcff4a6cae7 // indirect github.com/pkg/errors v0.9.1 // indirect @@ -205,6 +221,7 @@ require ( github.com/sagikazarmark/slog-shim v0.1.0 // indirect github.com/sasha-s/go-deadlock v0.3.5 // indirect github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible // indirect + github.com/sirupsen/logrus v1.9.3 // indirect github.com/sourcegraph/conc v0.3.0 // indirect github.com/spf13/afero v1.11.0 // indirect github.com/spf13/viper v1.19.0 // indirect @@ -223,6 +240,9 @@ require ( github.com/tklauser/numcpus v0.6.0 // indirect github.com/tyler-smith/go-bip39 v1.1.0 // indirect github.com/ulikunitz/xz v0.5.11 // indirect + github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect + github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect + github.com/xeipuuv/gojsonschema v1.2.0 // indirect github.com/zbiljic/go-filelock v0.0.0-20170914061330-1dbf7103ab7d // indirect github.com/zondax/hid v0.9.2 // indirect github.com/zondax/ledger-go v0.14.3 // indirect diff --git a/go.sum b/go.sum index 81e90c3..95eb0ac 100644 --- a/go.sum +++ b/go.sum @@ -218,6 +218,8 @@ cosmossdk.io/x/tx v0.13.4 h1:Eg0PbJgeO0gM8p5wx6xa0fKR7hIV6+8lC56UrsvSo0Y= cosmossdk.io/x/tx v0.13.4/go.mod h1:BkFqrnGGgW50Y6cwTy+JvgAhiffbGEKW6KF9ufcDpvk= cosmossdk.io/x/upgrade v0.1.4 h1:/BWJim24QHoXde8Bc64/2BSEB6W4eTydq0X/2f8+g38= cosmossdk.io/x/upgrade v0.1.4/go.mod h1:9v0Aj+fs97O+Ztw+tG3/tp5JSlrmT7IcFhAebQHmOPo= +dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk= +dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= filippo.io/edwards25519 v1.0.0-rc.1/go.mod h1:N1IkdkCkiLB6tki+MYJoSx2JTY9NUlxZE7eHn5EwJns= filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= @@ -474,6 +476,8 @@ github.com/creachadair/tomledit v0.0.26 h1:MoDdgHIHZ5PctBVsAZDjxdxreWUEa9ObPKTRk github.com/creachadair/tomledit v0.0.26/go.mod h1:SJi1OxKpMyR141tq1lzsbPtIg3j8TeVPM/ZftfieD7o= github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY= +github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= github.com/crypto-org-chain/cronos/memiavl v0.0.5-0.20240722062311-8384cad72737 h1:9jyWTnpgelwEvTRFkRxDIn/WBuj8pO4WcWYLbh/fi2k= github.com/crypto-org-chain/cronos/memiavl v0.0.5-0.20240722062311-8384cad72737/go.mod h1:gHpd4PhJt1BpjfN3PfChzv+9olZ2yVKDoyiIhMk9VFQ= github.com/crypto-org-chain/cronos/store v0.0.5-0.20240722062311-8384cad72737 h1:KcTmL7lmVr306/7QiBFvgy6mVQuRTdYJc9dP21VuT5s= @@ -520,7 +524,11 @@ github.com/dlclark/regexp2 v1.7.0 h1:7lJfhqlPssTb1WQx4yvTHN0uElPEv52sbaECrAQxjAo github.com/dlclark/regexp2 v1.7.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= github.com/dnaeon/go-vcr v1.1.0/go.mod h1:M7tiix8f0r6mKKJ3Yq/kqU1OYf3MnfmBWVbPx/yU9ko= github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ= +github.com/docker/cli v26.1.4+incompatible h1:I8PHdc0MtxEADqYJZvhBrW9bo8gawKwwenxRM7/rLu8= +github.com/docker/cli v26.1.4+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= github.com/docker/docker v1.6.2/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker v27.1.1+incompatible h1:hO/M4MtV36kzKldqnA37IWhebRA+LnqqcqDja6kVaKY= +github.com/docker/docker v27.1.1+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c= github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc= github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= @@ -635,6 +643,8 @@ github.com/go-sourcemap/sourcemap v2.1.3+incompatible h1:W1iEw64niKVGogNgBN3ePyL github.com/go-sourcemap/sourcemap v2.1.3+incompatible/go.mod h1:F8jJfvm2KbVjc5NqelyYJmf/v5J0dwNLS2mL4sNA1Jg= github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= +github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y= +github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-stack/stack v1.8.1 h1:ntEHSVwIt7PNXNpgPmVfMrNhLtgjlmnZha2kOpuRiDw= github.com/go-stack/stack v1.8.1/go.mod h1:dcoOX6HbPZSZptuspn9bctJ+N/CnF5gGygcUP3XYfe4= @@ -765,6 +775,8 @@ github.com/google/pprof v0.0.0-20240827171923-fa2c70bbbfe5/go.mod h1:vavhavw2zAx github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/s2a-go v0.1.7 h1:60BLSyTrOV4/haCDW4zb1guZItoSq8foHCXrAnjBo/o= github.com/google/s2a-go v0.1.7/go.mod h1:50CgR4k1jNlWBu4UfS4AcfhVe1r6pdZPygJ3R8F0Qdw= +github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4= +github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= @@ -1043,6 +1055,10 @@ github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyua github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/pointerstructure v1.2.0 h1:O+i9nHnXS3l/9Wu7r4NrEdwA2VFTicjUEN1uBnDo34A= github.com/mitchellh/pointerstructure v1.2.0/go.mod h1:BRAsLI5zgXmw97Lf6s25bs8ohIXc3tViBH44KcwB2g4= +github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0= +github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo= +github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0= +github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= @@ -1115,6 +1131,8 @@ github.com/openzipkin/zipkin-go v0.2.1/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnh github.com/openzipkin/zipkin-go v0.2.2/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4= github.com/ory/dockertest v3.3.5+incompatible h1:iLLK6SQwIhcbrG783Dghaaa3WPzGc+4Emza6EbVUUGA= github.com/ory/dockertest v3.3.5+incompatible/go.mod h1:1vX4m9wsvi00u5bseYwXaSnhNrne+V0E6LAcBILJdPs= +github.com/ory/dockertest/v3 v3.11.0 h1:OiHcxKAvSDUwsEVh2BjxQQc/5EHz9n0va9awCtNGuyA= +github.com/ory/dockertest/v3 v3.11.0/go.mod h1:VIPxS1gwT9NpPOrfD3rACs8Y9Z7yhzO4SB194iUDnUI= github.com/pact-foundation/pact-go v1.0.4/go.mod h1:uExwJY4kCzNPcHRj+hCR/HBbOOIwwtUjcrb0b5/5kLM= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= @@ -1205,8 +1223,8 @@ github.com/rs/cors v1.11.1/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= github.com/rs/zerolog v1.33.0 h1:1cU2KZkvPxNyfgEmhHAz/1A9Bz+llsdYzklWFzgp0r8= github.com/rs/zerolog v1.33.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss= -github.com/russross/blackfriday v1.5.2 h1:HyvC0ARfnZBqnXwABFeSZHpKvJHJJfPz81GNueLj0oo= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= +github.com/russross/blackfriday v1.6.0 h1:KqfZb0pUVN2lYqZUYRddxF4OR8ZMURnJIG5Y3VRLtww= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= @@ -1343,6 +1361,13 @@ github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+ github.com/vmihailenco/msgpack/v5 v5.3.5/go.mod h1:7xyJ9e+0+9SaZT0Wt1RGleJXzli6Q/V5KbhBonMG9jc= github.com/vmihailenco/tagparser/v2 v2.0.0/go.mod h1:Wri+At7QHww0WTrCBeu4J6bNtoV6mEfg5OIWRZA9qds= github.com/willf/bitset v1.1.3/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4= +github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= +github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo= +github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= +github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0= +github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= +github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74= +github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xlab/treeprint v0.0.0-20180616005107-d6fb6747feb6/go.mod h1:ce1O1j6UtZfjr22oyGxGLbauSBp2YVXpARAosm7dHBg= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= @@ -1693,6 +1718,7 @@ golang.org/x/sys v0.0.0-20220610221304-9f5ed59c137d/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220615213510-4f61da869c0c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220624220833-87e55d714810/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= diff --git a/tests/e2e/README.md b/tests/e2e/README.md new file mode 100644 index 0000000..5b8f4bc --- /dev/null +++ b/tests/e2e/README.md @@ -0,0 +1,239 @@ +# End-to-End Testing Suite + +The End-to-End (E2E) testing suite provides an environment +for running end-to-end tests on Evmos. +It is used for testing chain upgrades, +as it allows for initializing multiple Evmos chains with different versions. + +- [End-to-End Testing Suite](#end-to-end-testing-suite) + - [Quick Start](#quick-start) + - [Upgrade Process](#upgrade-process) + - [Test Suite Structure](#test-suite-structure) + - [`e2e` Package](#e2e-package) + - [`upgrade` Package](#upgrade-package) + - [Version retrieve](#version-retrieve) + - [Testing Results](#testing-results) + - [Running multiple upgrades](#running-multiple-upgrades) + +### Quick Start + +To run the e2e tests, execute: + +```shell +make test-e2e +``` + +This command runs an upgrade test (upgrading a node from an old version to a newer one), +as well as query and transactions operations against a node with the latest changes. + +This logic utilizes parameters that can be set manually(if necessary): + +```shell +# flag to skip containers cleanup after upgrade +# should be set true with make test-e2e command if you need access to the node +# after upgrading +E2E_SKIP_CLEANUP := false + +# version(s) of initial evmos node(s) that will be upgraded, tag e.g. 'v9.1.0' +# to use multiple upgrades separate the versions with a forward slash, e.g. +# 'v10.0.1/v11.0.0-rc1' +INITIAL_VERSION + +# version of upgraded evmos node that will replace the initial node, tag e.g. +# 'v10.0.0' +TARGET_VERSION + +# mount point for the upgraded node container, to mount new node version to +# previous node state folder. By default this is './build/.evmosd:/root/.evmosd' +# More info at https://docs.docker.com/engine/reference/builder/#volume +MOUNT_PATH + +# '--chain-id' evmos cli parameter, used to start nodes with a specific +# chain-id and submit proposals +# By default this is 'evmos_9000-1' +CHAIN_ID +``` + +To test an upgrade to explicit target version +and continue to run the upgraded node, use: + +```shell +make test-e2e E2E_SKIP_CLEANUP=true INITIAL_VERSION= TARGET_VERSION= +``` + +### Upgrade Process + +Testing a chain upgrade is a multi-step process: + +1. Build a docker image for the evmos target version +(local repo by default, if no explicit `TARGET_VERSION` provided as argument) +(e.g. `v10.0.0`) +2. Run tests +3. The e2e test will first run an `INITIAL_VERSION` node container. +4. The node will submit, deposit and vote for an upgrade proposal +for upgrading to the `TARGET_VERSION`. +5. After block `50` is reached, +the test suite exports `/.evmosd` folder from the docker container +to the local `build/` folder and then purges the container. +6. Suite will mount the node with `TARGET_VERSION` +to the local `build/` dir and start the node. +The node will get upgrade information from `upgrade-info.json` +and will execute the upgrade. + +## Test Suite Structure + +### `e2e` Package + +The `e2e` package defines an integration testing suite +used for full end-to-end testing functionality. +This package is decoupled from depending on the Evmos codebase. +It initializes the chains for testing via Docker. +As a result, the test suite may provide the +desired Evmos version to Docker containers during the initialization. +This design allows for the opportunity of testing chain upgrades +by providing an older Evmos version to the container, +performing the chain upgrade, +and running the latest test suite. +Here's an overview of the files: + +* `e2e_suite_test.go`: defines the testing suite +and contains the core bootstrapping logic +that creates a testing environment via Docker containers. +A testing network is created dynamically with 2 test validators. + +* `e2e_test.go`: contains the actual end-to-end integration tests +that utilize the testing suite. + +* `e2e_utils_test.go`: contains suite upgrade params loading logic. + +### `upgrade` Package + +The `e2e` package defines an upgrade `Manager` abstraction. +Suite will utilize `Manager`'s functions +to run different versions of evmos containers, +propose, vote, delegate and query nodes. + +* `manager.go`: defines core manager logic for running containers, +export state and create networks. + +* `govexec.go`: defines `gov-specific` exec commands to submit/delegate/vote +through nodes `gov` module. + +* `node.go`: defines `Node` structure +responsible for setting node container parameters before run. + +### Version retrieve + +If `INITIAL_VERSION` is provided as an argument, +node container(s) with the corresponding version(s) +will be pulled from [DockerHub](https://hub.docker.com/r/tharsishq/evmos/tags). +If it is not specified, +the test suite retrieves the second-to-last upgrade version +from the local codebase (in the `evmos/app/upgrades` folder) +according to [Semantic Versioning](https://semver.org/). + +If `TARGET_VERSION` is specified, +the corresponding container will also be pulled from DockerHub. +When not specified, the test suite will retrieve the latest upgrade version +from `evmos/app/upgrades`. + +### Testing Results + +The `make test-e2e` script will output the test results +for each testing file. +In case of a successful upgrade, +the script will print the following output (example): + +```log +ok github.com/evmos/evmos/v9/tests/e2e 174.137s. +``` + +If the target node version fails to start, +the logs from the docker container will be printed: + +```log +Error: Received unexpected error: + can't start evmos node, container exit code: 2 + + [error stream]: + + 7:03AM INF Unlocking keyring + 7:03AM INF starting ABCI with Tendermint + panic: invalid minimum gas prices: invalid decimal coin expression: 0... + + goroutine 1 [running]: + github.com/cosmos/cosmos-sdk/baseapp.SetMinGasPrices({0xc0013563e7?, ... + github.com/cosmos/cosmos-sdk@v0.46.5/baseapp/options.go:29 +0xd9 + main.appCreator.newApp({{{0x3399b40, 0xc000ec1db8}, {0x33ac0f8, 0xc00... + github.com/evmos/evmos/v10/cmd/evmosd/root.go:243 +0x2ca + github.com/evmos/ethermint/server.startInProcess(_, {{0x0, 0x0, 0x0},... + github.com/evmos/ethermint@v0.20.0-rc2/server/start.go:304 +0x9c5 + github.com/evmos/ethermint/server.StartCmd.func2(0xc001620600?, {0xc0... + github.com/evmos/ethermint@v0.20.0-rc2/server/start.go:123 +0x1ec + github.com/spf13/cobra.(*Command).execute(0xc001620600, {0xc001745bb0... + github.com/spf13/cobra@v1.6.1/command.go:916 +0x862 + github.com/spf13/cobra.(*Command).ExecuteC(0xc00160e000) + github.com/spf13/cobra@v1.6.1/command.go:1044 +0x3bd + github.com/spf13/cobra.(*Command).Execute(...) + github.com/spf13/cobra@v1.6.1/command.go:968 + github.com/spf13/cobra.(*Command).ExecuteContext(...) + github.com/spf13/cobra@v1.6.1/command.go:961 + github.com/cosmos/cosmos-sdk/server/cmd.Execute(0x2170d50?, {0x26d961... + github.com/cosmos/cosmos-sdk@v0.46.5/server/cmd/execute.go:36 +0x... + main.main() + github.com/evmos/evmos/v10/cmd/evmosd/main.go:20 +0x45 + + + [output stream]: + +Test: TestIntegrationTestSuite/TestUpgrade +Messages: can't mount and run upgraded node container +``` + +To get all containers run: + +```shell +# list containers +docker ps -a +``` + +Container names will be listed as follows: + +```log +CONTAINER ID IMAGE +9307f5485323 evmos:local <-- upgraded node +f41c97d6ca21 evmos:v9.0.0 <-- initial node +``` + +To access containers logs directly, run: + +```shell +docker logs +``` + +To interact with the upgraded node +pass `SKIP_CLEANUP=true` to the make command +and enter the container after the upgrade has finished: + +```shell +docker exec -it bash +``` + +If the cleanup was skipped +the upgraded node container should be removed manually: + +```shell +docker kill +docker rm +``` + +## Running multiple upgrades + +In order to run multiple upgrades, +just combine the versions leading up to the last upgrade +with a forward slash +and pass them as the `INITIAL_VERSION`. + +```bash +make test-e2e INITIAL_VERSION=v10.0.1/v11.0.0-rc1 TARGET_VERSION=v11.0.0-rc3 +``` diff --git a/tests/e2e/e2e_suite_test.go b/tests/e2e/e2e_suite_test.go new file mode 100644 index 0000000..aca75a5 --- /dev/null +++ b/tests/e2e/e2e_suite_test.go @@ -0,0 +1,333 @@ +package e2e + +import ( + "context" + "errors" + "fmt" + "os" + "strings" + "testing" + + "github.com/cosmos/cosmos-sdk/codec" + govtypes "github.com/cosmos/cosmos-sdk/x/gov/types/v1" + "github.com/evmos/evmos/v20/testutil/integration/evmos/network" + "github.com/evmos/evmos/v20/utils" + "github.com/stretchr/testify/suite" + "github.com/xrplevm/node/v5/tests/e2e/upgrade" +) + +const ( + // defaultManagerNetwork defines the network used by the upgrade manager + defaultManagerNetwork = "evmos-local" + + // blocksAfterUpgrade defines how many blocks must be produced after an upgrade is + // considered successful + blocksAfterUpgrade = 5 + + // relatedBuildPath defines the path where the build data is stored + relatedBuildPath = "../../build/" + + // upgradePath defines the relative path from this folder to the upgrade folder + upgradePath = "../../app/upgrades" + + // registryDockerFile builds the image using the docker image registry + registryDockerFile = "./upgrade/Dockerfile.init" +) + +type IntegrationTestSuite struct { + suite.Suite + + upgradeManager *upgrade.Manager + upgradeParams upgrade.Params +} + +func TestIntegrationTestSuite(t *testing.T) { + suite.Run(t, new(IntegrationTestSuite)) +} + +func (s *IntegrationTestSuite) SetupSuite() { + s.T().Log("setting up e2e integration test suite...") + var err error + + s.upgradeParams, err = upgrade.LoadUpgradeParams(upgradePath) + s.Require().NoError(err, "can't load upgrade params") + + s.upgradeManager, err = upgrade.NewManager(defaultManagerNetwork) + s.Require().NoError(err, "upgrade manager creation error") + if _, err := os.Stat(relatedBuildPath); errors.Is(err, os.ErrNotExist) { + err := os.Mkdir(relatedBuildPath, os.ModePerm) + s.Require().NoError(err, "can't create build tmp dir") + } +} + +// runInitialNode builds a docker image capable of running an Evmos node with the given version. +// After a successful build, it runs the container and checks if the node can produce blocks. +func (s *IntegrationTestSuite) runInitialNode(version upgrade.VersionConfig) { + err := s.upgradeManager.BuildImage( + version.ImageName, + version.ImageTag, + registryDockerFile, + ".", + map[string]string{"INITIAL_VERSION": version.ImageTag}, + ) + s.Require().NoError(err, "can't build container with Evmos version: %s", version.ImageTag) + + node := upgrade.NewNode(version.ImageName, version.ImageTag) + node.SetEnvVars([]string{fmt.Sprintf("CHAIN_ID=%s", s.upgradeParams.ChainID)}) + + err = s.upgradeManager.RunNode(node) + s.Require().NoError(err, "can't run node with Evmos version: %s", version) + + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + // wait until node starts and produce some blocks + _, err = s.upgradeManager.WaitForHeight(ctx, s.upgradeManager.HeightBeforeStop+5) + s.Require().NoError(err) + + s.T().Logf("successfully started node with version: [%s]", version.ImageTag) +} + +// proposeUpgrade submits an upgrade proposal to the chain that schedules an upgrade to +// the given target version. +func (s *IntegrationTestSuite) proposeUpgrade(name, target string) { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + // calculate upgrade height for the proposal + upgradeHeight, err := s.upgradeManager.GetUpgradeHeight(ctx, s.upgradeParams.ChainID) + s.Require().NoError(err, "can't get upgrade height") + s.upgradeManager.UpgradeHeight = upgradeHeight + + // if Evmos is lower than v10.x.x no need to use the legacy proposal + currentVersion, err := s.upgradeManager.GetNodeVersion(ctx) + s.Require().NoError(err, "can't get current Evmos version") + proposalVersion := upgrade.CheckUpgradeProposalVersion(currentVersion) + + // create the proposal + exec, err := s.upgradeManager.CreateSubmitProposalExec( + name, + s.upgradeParams.ChainID, + s.upgradeManager.UpgradeHeight, + proposalVersion, + "--fees=10000000000000000aevmos", + "--gas=500000", + ) + s.Require().NoErrorf( + err, + "can't create the proposal to upgrade Evmos to %s at height %d with name %s", + target, s.upgradeManager.UpgradeHeight, name, + ) + + outBuf, errBuf, err := s.upgradeManager.RunExec(ctx, exec) + s.Require().NoErrorf( + err, + "failed to submit proposal to upgrade Evmos to %s at height %d\nstdout: %s,\nstderr: %s", + target, s.upgradeManager.UpgradeHeight, outBuf.String(), errBuf.String(), + ) + + s.Require().Truef( + strings.Contains(outBuf.String(), "code: 0"), + "tx returned non code 0:\nstdout: %s\nstderr: %s", outBuf.String(), errBuf.String(), + ) + + s.T().Logf( + "successfully submitted upgrade proposal: height: %d, name: %s", + s.upgradeManager.UpgradeHeight, + name, + ) +} + +// voteForProposal votes for the upgrade proposal with the given id. +func (s *IntegrationTestSuite) voteForProposal(id int) { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + exec, err := s.upgradeManager.CreateVoteProposalExec(s.upgradeParams.ChainID, id, "--fees=10000000000000000aevmos", "--gas=500000") + s.Require().NoError(err, "can't create vote for proposal exec") + outBuf, errBuf, err := s.upgradeManager.RunExec(ctx, exec) + s.Require().NoErrorf( + err, + "failed to vote for proposal tx;\nstdout: %s,\nstderr: %s", outBuf.String(), errBuf.String(), + ) + + s.Require().Truef( + strings.Contains(outBuf.String(), "code: 0"), + "tx returned non code 0:\nstdout: %s\nstderr: %s", outBuf.String(), errBuf.String(), + ) + + s.T().Logf("successfully voted for upgrade proposal") +} + +// upgrade upgrades the node to the given version using the given repo. The repository +// can either be a local path or a remote repository. +func (s *IntegrationTestSuite) upgrade(targetVersion upgrade.VersionConfig) { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + s.T().Logf("wait for node to reach upgrade height %d...", s.upgradeManager.UpgradeHeight) + // wait for proposed upgrade height + _, err := s.upgradeManager.WaitForHeight(ctx, int(s.upgradeManager.UpgradeHeight)) //#nosec G115 + s.Require().NoError(err, "can't reach upgrade height") + dirs := strings.Split(s.upgradeParams.MountPath, ":") + buildDir := dirs[0] + rootDir := dirs[1] + + // check that the proposal has passed before stopping the node + s.checkProposalPassed(ctx) + + s.T().Log("exporting state to local...") + // export node .evmosd to local build/ + err = s.upgradeManager.ExportState(buildDir) + s.Require().NoError(err, "can't export node container state to local") + + s.T().Log("killing node before upgrade...") + err = s.upgradeManager.KillCurrentNode() + s.Require().NoError(err, "can't kill current node") + + s.T().Logf("starting upgraded node with version: [%s]", targetVersion) + + // NOTE: after the upgrade, the current version needs to be updated to make sure that the correct CLI commands + // for the given version are used. + // + // this is e.g. relevant for retrieving the current node height from the block header + if targetVersion.ImageTag == upgrade.LocalVersionTag { + // NOTE: the upgrade name is the latest version from the app/upgrades folder to upgrade to + s.upgradeManager.CurrentVersion = targetVersion.UpgradeName + } else { + s.upgradeManager.CurrentVersion = targetVersion.ImageTag + } + + node := upgrade.NewNode(targetVersion.ImageName, targetVersion.ImageTag) + node.Mount(s.upgradeParams.MountPath) + node.SetCmd([]string{"evmosd", "start", fmt.Sprintf("--chain-id=%s", s.upgradeParams.ChainID), fmt.Sprintf("--home=%s.evmosd", rootDir)}) + err = s.upgradeManager.RunNode(node) + s.Require().NoError(err, "can't mount and run upgraded node container") + + s.T().Logf("node started! waiting for node to produce %d blocks", blocksAfterUpgrade) + + s.T().Log("executing all module queries") + s.executeQueries() + + s.T().Log("executing sample transactions") + s.executeTransactions() + + // make sure node produce blocks after upgrade + s.T().Logf("height to wait for is %d", int(s.upgradeManager.UpgradeHeight)+blocksAfterUpgrade) // #nosec G115 + // make sure node produces blocks after upgrade + errLogs, err := s.upgradeManager.WaitForHeight(ctx, int(s.upgradeManager.UpgradeHeight)+blocksAfterUpgrade) // #nosec G115 + if err == nil && errLogs != "" { + s.T().Logf( + "even though the node is producing blocks, there are error messages contained in the logs:\n%s", + errLogs, + ) + } + s.Require().NoError(err, "node does not produce blocks after upgrade") + + if targetVersion.ImageTag != upgrade.LocalVersionTag { + s.T().Log("checking node version...") + version, err := s.upgradeManager.GetNodeVersion(ctx) + s.Require().NoError(err, "can't get node version") + + version = strings.TrimSpace(version) + targetVersion.ImageTag = strings.TrimPrefix(targetVersion.ImageTag, "v") + s.Require().Equal(targetVersion, version, + "unexpected node version after upgrade:\nexpected: %s\nactual: %s", + targetVersion, version, + ) + s.T().Logf("node version is correct: %s", version) + } +} + +// checkProposalPassed queries the (most recent) upgrade proposal and checks that it has passed. +// +// NOTE: This was a problem in the past, where the upgrade height was reached before the proposal actually passed. +// This is a safety check to make sure this doesn't happen again, as this was not obvious from the log output. +func (s *IntegrationTestSuite) checkProposalPassed(ctx context.Context) { + exec, err := s.upgradeManager.CreateModuleQueryExec(upgrade.QueryArgs{ + Module: "gov", + SubCommand: "proposals", + ChainID: s.upgradeParams.ChainID, + }) + s.Require().NoError(err, "can't create query proposals exec") + + outBuf, errBuf, err := s.upgradeManager.RunExec(ctx, exec) + s.Require().NoErrorf( + err, + "failed to query proposals;\nstdout: %s,\nstderr: %s", outBuf.String(), errBuf.String(), + ) + + nw := network.New() + encodingConfig := nw.GetEncodingConfig() + protoCodec, ok := encodingConfig.Codec.(*codec.ProtoCodec) + s.Require().True(ok, "encoding config codec is not a proto codec") + + var proposalsRes govtypes.QueryProposalsResponse + err = protoCodec.UnmarshalJSON(outBuf.Bytes(), &proposalsRes) + s.Require().NoError(err, "can't unmarshal proposals response\n%s", outBuf.String()) + s.Require().GreaterOrEqual(len(proposalsRes.Proposals), 1, "no proposals found") + + // check that the most recent proposal has passed + proposal := proposalsRes.Proposals[len(proposalsRes.Proposals)-1] + s.Require().Equal(govtypes.ProposalStatus_PROPOSAL_STATUS_PASSED.String(), proposal.Status.String(), "expected proposal to have passed already") +} + +// executeQueries executes all the module queries to check they are still working after the upgrade. +func (s *IntegrationTestSuite) executeQueries() { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + chainID := utils.TestnetChainID + "-1" + testCases := []struct { + name string + moduleName string + subCommand string + }{ + {"inflation: params", "inflation", "params"}, + {"inflation: circulating-supply", "inflation", "circulating-supply"}, + {"inflation: inflation-rate", "inflation", "inflation-rate"}, + {"inflation: period", "inflation", "period"}, + {"inflation: skipped-epochs", "inflation", "skipped-epochs"}, + {"inflation: epoch-mint-provision", "inflation", "epoch-mint-provision"}, + {"erc20: params", "erc20", "params"}, + {"erc20: token-pairs", "erc20", "token-pairs"}, + {"evm: params", "evm", "params"}, + {"feemarket: params", "feemarket", "params"}, + {"feemarket: base-fee", "feemarket", "base-fee"}, + {"feemarket: block-gas", "feemarket", "block-gas"}, + {"feemarket: block-gas", "feemarket", "block-gas"}, + } + + for _, tc := range testCases { + s.T().Logf("executing %s", tc.name) + exec, err := s.upgradeManager.CreateModuleQueryExec(upgrade.QueryArgs{ + Module: tc.moduleName, + SubCommand: tc.subCommand, + ChainID: chainID, + }) + s.Require().NoError(err) + + _, errBuf, err := s.upgradeManager.RunExec(ctx, exec) + s.Require().NoError(err) + s.Require().Empty(errBuf.String()) + } + s.T().Logf("executed all queries successfully") +} + +// TearDownSuite kills the running container, removes the network and mount path +func (s *IntegrationTestSuite) TearDownSuite() { + if s.upgradeParams.SkipCleanup { + s.T().Logf("skipping cleanup... container %s will be left running", s.upgradeManager.ContainerID()) + return + } + + s.T().Log("tearing down e2e integration test suite...") + s.T().Log("killing node...") + err := s.upgradeManager.KillCurrentNode() + s.Require().NoError(err, "can't kill current node") + + s.T().Log("removing network...") + s.Require().NoError(s.upgradeManager.RemoveNetwork(), "can't remove network") + + s.T().Log("removing mount path...") + s.Require().NoError(os.RemoveAll(strings.Split(s.upgradeParams.MountPath, ":")[0]), "can't remove mount path") +} diff --git a/tests/e2e/e2e_test.go b/tests/e2e/e2e_test.go new file mode 100644 index 0000000..5c5f93c --- /dev/null +++ b/tests/e2e/e2e_test.go @@ -0,0 +1,37 @@ +package e2e + +import ( + "context" +) + +// TestUpgrade tests if an Evmos node can be upgraded from one version to another. +// It iterates through the list of scheduled upgrades, that are defined using the input +// arguments to the make command. The function then submits a proposal to upgrade the chain, +// and finally upgrades the chain. +// If the chain can be restarted after the upgrade(s), the test passes. +func (s *IntegrationTestSuite) TestUpgrade() { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + // NOTE: we initialize the current version, which is then updated in the upgrade function + s.upgradeManager.CurrentVersion = s.upgradeParams.Versions[0].ImageTag + for idx, version := range s.upgradeParams.Versions { + if idx == 0 { + // start initial node + s.runInitialNode(version) + continue + } + + // wait one block to execute the txs + err := s.upgradeManager.WaitNBlocks(ctx, 1) + s.Require().NoError(err) + s.T().Logf("(upgrade %d): UPGRADING TO %s WITH PROPOSAL NAME %s", idx, version.ImageTag, version.UpgradeName) + s.proposeUpgrade(version.UpgradeName, version.ImageTag) + + s.Require().NoError(s.upgradeManager.WaitNBlocks(ctx, 1), "failed to wait for block") + + s.voteForProposal(idx) + s.upgrade(version) + } + s.T().Logf("SUCCESS") +} diff --git a/tests/e2e/init-node.sh b/tests/e2e/init-node.sh new file mode 100755 index 0000000..a5e252c --- /dev/null +++ b/tests/e2e/init-node.sh @@ -0,0 +1,164 @@ +#!/bin/bash + +CHAINID="${CHAIN_ID:-evmos_9000-1}" +MONIKER="localtestnet" +KEYRING="test" # remember to change to other types of keyring like 'file' in-case exposing to outside world, otherwise your balance will be wiped quickly. The keyring test does not require private key to steal tokens from you +KEYALGO="eth_secp256k1" #gitleaks:allow +LOGLEVEL="info" +# to trace evm +#TRACE="--trace" +TRACE="" +PRUNING="default" +#PRUNING="custom" + +CHAINDIR="$HOME/.evmosd" +GENESIS="$CHAINDIR/config/genesis.json" +TMP_GENESIS="$CHAINDIR/config/tmp_genesis.json" +APP_TOML="$CHAINDIR/config/app.toml" +CONFIG_TOML="$CHAINDIR/config/config.toml" + +# feemarket params basefee +BASEFEE=1000000000 + +# myKey address 0x7cb61d4117ae31a12e393a1cfa3bac666481d02e +VAL_KEY="mykey" +VAL_MNEMONIC="gesture inject test cycle original hollow east ridge hen combine junk child bacon zero hope comfort vacuum milk pitch cage oppose unhappy lunar seat" + +# user1 address 0xc6fe5d33615a1c52c08018c47e8bc53646a0e101 +USER1_KEY="user1" +USER1_MNEMONIC="copper push brief egg scan entry inform record adjust fossil boss egg comic alien upon aspect dry avoid interest fury window hint race symptom" + +# user2 address 0x963ebdf2e1f8db8707d05fc75bfeffba1b5bac17 +USER2_KEY="user2" +USER2_MNEMONIC="maximum display century economy unlock van census kite error heart snow filter midnight usage egg venture cash kick motor survey drastic edge muffin visual" + +# user3 address 0x40a0cb1C63e026A81B55EE1308586E21eec1eFa9 +USER3_KEY="user3" +USER3_MNEMONIC="will wear settle write dance topic tape sea glory hotel oppose rebel client problem era video gossip glide during yard balance cancel file rose" + +# user4 address 0x498B5AeC5D439b733dC2F58AB489783A23FB26dA +USER4_KEY="user4" +USER4_MNEMONIC="doll midnight silk carpet brush boring pluck office gown inquiry duck chief aim exit gain never tennis crime fragile ship cloud surface exotic patch" + +# validate dependencies are installed +command -v jq >/dev/null 2>&1 || { + echo >&2 "jq not installed. More info: https://stedolan.github.io/jq/download/" + exit 1 +} + +# used to exit on first error (any non-zero exit code) +set -e + +# Check evmosd version to decide how to set the client configuration +# the older versions of evmosd accept less arguments +sdk_version=$(evmosd version --long | grep 'cosmos_sdk_version' | awk '{print $2}') +if [[ $sdk_version == *v0.4* ]]; then + evmosd config chain-id "$CHAINID" + evmosd config keyring-backend "$KEYRING" +else + evmosd config set client chain-id "$CHAINID" + evmosd config set client keyring-backend "$KEYRING" +fi + +# Import keys from mnemonics +echo "$VAL_MNEMONIC" | evmosd keys add "$VAL_KEY" --recover --keyring-backend "$KEYRING" --algo "$KEYALGO" + +echo "$USER1_MNEMONIC" | evmosd keys add "$USER1_KEY" --recover --keyring-backend "$KEYRING" --algo "$KEYALGO" +echo "$USER2_MNEMONIC" | evmosd keys add "$USER2_KEY" --recover --keyring-backend "$KEYRING" --algo "$KEYALGO" +echo "$USER3_MNEMONIC" | evmosd keys add "$USER3_KEY" --recover --keyring-backend "$KEYRING" --algo "$KEYALGO" +echo "$USER4_MNEMONIC" | evmosd keys add "$USER4_KEY" --recover --keyring-backend "$KEYRING" --algo "$KEYALGO" + +# Set moniker and chain-id for Evmos (Moniker can be anything, chain-id must be an integer) +evmosd init "$MONIKER" --chain-id "$CHAINID" + +# Change parameter token denominations to aevmos +jq '.app_state["staking"]["params"]["bond_denom"]="aevmos"' "$GENESIS" >"$TMP_GENESIS" && mv "$TMP_GENESIS" "$GENESIS" +jq '.app_state["gov"]["deposit_params"]["min_deposit"][0]["denom"]="aevmos"' "$GENESIS" >"$TMP_GENESIS" && mv "$TMP_GENESIS" "$GENESIS" +# When upgrade to cosmos-sdk v0.47, use gov.params to edit the deposit params +jq '.app_state["gov"]["params"]["min_deposit"][0]["denom"]="aevmos"' "$GENESIS" >"$TMP_GENESIS" && mv "$TMP_GENESIS" "$GENESIS" +jq '.app_state["evm"]["params"]["evm_denom"]="aevmos"' "$GENESIS" >"$TMP_GENESIS" && mv "$TMP_GENESIS" "$GENESIS" +jq '.app_state["inflation"]["params"]["mint_denom"]="aevmos"' "$GENESIS" >"$TMP_GENESIS" && mv "$TMP_GENESIS" "$GENESIS" + +# set gov proposing && voting period +jq '.app_state.gov.deposit_params.max_deposit_period="10s"' "$GENESIS" >"$TMP_GENESIS" && mv "$TMP_GENESIS" "$GENESIS" +jq '.app_state.gov.voting_params.voting_period="10s"' "$GENESIS" >"$TMP_GENESIS" && mv "$TMP_GENESIS" "$GENESIS" +sed -i.bak 's/"expedited_voting_period": "86400s"/"expedited_voting_period": "5s"/g' "$GENESIS" + +# When upgrade to cosmos-sdk v0.47, use gov.params to edit the deposit params +# check if the 'params' field exists in the genesis file +if jq '.app_state.gov.params != null' "$GENESIS" | grep -q "true"; then + jq '.app_state.gov.params.min_deposit[0].denom="aevmos"' "$GENESIS" >"$TMP_GENESIS" && mv "$TMP_GENESIS" "$GENESIS" + jq '.app_state.gov.params.max_deposit_period="10s"' "$GENESIS" >"$TMP_GENESIS" && mv "$TMP_GENESIS" "$GENESIS" + jq '.app_state.gov.params.voting_period="10s"' "$GENESIS" >"$TMP_GENESIS" && mv "$TMP_GENESIS" "$GENESIS" +fi + +# Set gas limit in genesis +jq '.consensus_params.block.max_gas="10000000"' "$GENESIS" >"$TMP_GENESIS" && mv "$TMP_GENESIS" "$GENESIS" + +# Set claims start time +current_date=$(date -u +"%Y-%m-%dT%TZ") +jq -r --arg current_date "$current_date" '.app_state.claims.params.airdrop_start_time=$current_date' "$GENESIS" >"$TMP_GENESIS" && mv "$TMP_GENESIS" "$GENESIS" + +# Set base fee in genesis +jq '.app_state["feemarket"]["params"]["base_fee"]="'${BASEFEE}'"' "$GENESIS" >"$TMP_GENESIS" && mv "$TMP_GENESIS" "$GENESIS" + +# disable produce empty block +sed -i.bak 's/create_empty_blocks = true/create_empty_blocks = false/g' "$CONFIG_TOML" + +# Allocate genesis accounts (cosmos formatted addresses) +evmosd add-genesis-account "$(evmosd keys show "$VAL_KEY" -a --keyring-backend "$KEYRING")" 100000000000000000000000000aevmos --keyring-backend "$KEYRING" +evmosd add-genesis-account "$(evmosd keys show "$USER1_KEY" -a --keyring-backend "$KEYRING")" 1000000000000000000000aevmos --keyring-backend "$KEYRING" +evmosd add-genesis-account "$(evmosd keys show "$USER2_KEY" -a --keyring-backend "$KEYRING")" 1000000000000000000000aevmos --keyring-backend "$KEYRING" +evmosd add-genesis-account "$(evmosd keys show "$USER3_KEY" -a --keyring-backend "$KEYRING")" 1000000000000000000000aevmos --keyring-backend "$KEYRING" +evmosd add-genesis-account "$(evmosd keys show "$USER4_KEY" -a --keyring-backend "$KEYRING")" 1000000000000000000000aevmos --keyring-backend "$KEYRING" + +# Update total supply with claim values +# Bc is required to add this big numbers +# total_supply=$(bc <<< "$validators_supply") +total_supply=100004000000000000000000000 +jq -r --arg total_supply "$total_supply" '.app_state.bank.supply[0].amount=$total_supply' "$GENESIS" >"$TMP_GENESIS" && mv "$TMP_GENESIS" "$GENESIS" + +# set custom pruning settings +if [ "$PRUNING" = "custom" ]; then + sed -i.bak 's/pruning = "default"/pruning = "custom"/g' "$APP_TOML" + sed -i.bak 's/pruning-keep-recent = "0"/pruning-keep-recent = "2"/g' "$APP_TOML" + sed -i.bak 's/pruning-interval = "0"/pruning-interval = "10"/g' "$APP_TOML" +fi + +# make sure the localhost IP is 0.0.0.0 +sed -i.bak 's/localhost/0.0.0.0/g' "$CONFIG_TOML" +sed -i.bak 's/127.0.0.1/0.0.0.0/g' "$APP_TOML" + +# use timeout_commit 1s to make test faster +sed -i.bak 's/timeout_commit = "3s"/timeout_commit = "1s"/g' "$CONFIG_TOML" + +# Sign genesis transaction +evmosd gentx "$VAL_KEY" 1000000000000000000000aevmos --gas-prices ${BASEFEE}aevmos --keyring-backend "$KEYRING" --chain-id "$CHAINID" +## In case you want to create multiple validators at genesis +## 1. Back to `evmosd keys add` step, init more keys +## 2. Back to `evmosd add-genesis-account` step, add balance for those +## 3. Clone this ~/.evmosd home directory into some others, let's say `~/.clonedEvmosd` +## 4. Run `gentx` in each of those folders +## 5. Copy the `gentx-*` folders under `~/.clonedEvmosd/config/gentx/` folders into the original `~/.evmosd/config/gentx` + +# Enable the APIs for the tests to be successful +sed -i.bak 's/enable = false/enable = true/g' "$APP_TOML" +# Don't enable Rosetta API by default +grep -q -F '[rosetta]' "$APP_TOML" && sed -i.bak '/\[rosetta\]/,/^\[/ s/enable = true/enable = false/' "$APP_TOML" +# Don't enable memiavl by default +grep -q -F '[memiavl]' "$APP_TOML" && sed -i.bak '/\[memiavl\]/,/^\[/ s/enable = true/enable = false/' "$APP_TOML" +# Don't enable versionDB by default +grep -q -F '[versiondb]' "$APP_TOML" && sed -i.bak '/\[versiondb\]/,/^\[/ s/enable = true/enable = false/' "$APP_TOML" + +# Collect genesis tx +evmosd collect-gentxs + +# Run this to ensure everything worked and that the genesis file is setup correctly +evmosd validate-genesis + +# Start the node +evmosd start "$TRACE" \ + --log_level $LOGLEVEL \ + --minimum-gas-prices=0.0001aevmos \ + --json-rpc.api eth,txpool,personal,net,debug,web3 \ + --chain-id "$CHAINID" diff --git a/tests/e2e/tx_test.go b/tests/e2e/tx_test.go new file mode 100644 index 0000000..d1d8740 --- /dev/null +++ b/tests/e2e/tx_test.go @@ -0,0 +1,66 @@ +// Copyright Tharsis Labs Ltd.(Evmos) +// SPDX-License-Identifier:ENCL-1.0(https://github.com/evmos/evmos/blob/main/LICENSE) + +package e2e + +import ( + "context" + "regexp" + "strings" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/xrplevm/node/v5/tests/e2e/upgrade" +) + +// executeTransactions executes some sample transactions to check they are still working after the upgrade. +func (s *IntegrationTestSuite) executeTransactions() { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + // TODO: Add more transactions in future (e.g. staking precompile) + s.sendBankTransfer(ctx) +} + +// SendBankTransfer sends a bank transfer to check that the transactions are still working after the upgrade. +func (s *IntegrationTestSuite) sendBankTransfer(ctx context.Context) { + receiver := "evmos1jcltmuhplrdcwp7stlr4hlhlhgd4htqh3a79sq" + sentCoins := sdk.Coins{sdk.NewInt64Coin("aevmos", 10000000000)} + + balancePre, err := s.upgradeManager.GetBalance(ctx, s.upgradeParams.ChainID, receiver) + s.Require().NoError(err, "can't get balance of receiver account") + + // send some tokens between accounts to check transactions are still working + exec, err := s.upgradeManager.CreateModuleTxExec(upgrade.E2ETxArgs{ + ModuleName: "bank", + SubCommand: "send", + Args: []string{"mykey", receiver, sentCoins.String()}, + ChainID: s.upgradeParams.ChainID, + From: "mykey", + }) + s.Require().NoError(err, "failed to create bank send tx command") + + outBuf, errBuf, err := s.upgradeManager.RunExec(ctx, exec) + s.Require().NoError(err, "failed to execute bank send tx") + s.Require().Truef( + strings.Contains(outBuf.String(), "code: 0"), + "tx returned non code 0:\nstdout: %s\nstderr: %s", outBuf.String(), errBuf.String(), + ) + // NOTE: The only message in the errBuf that is allowed is `gas estimate: ...` + gasEstimateMatch, err := regexp.MatchString(`^\s*gas estimate: \d+\s*$`, errBuf.String()) + s.Require().NoError(err, "failed to match gas estimate message") + s.Require().True( + gasEstimateMatch, + "expected message in errBuf to be `gas estimate: ...`; got: %q\n", + errBuf.String(), + ) + + // Wait until the transaction has succeeded and is included in the chain + err = s.upgradeManager.WaitNBlocks(ctx, 2) + s.Require().NoError(err, "failed to wait for blocks") + + balancePost, err := s.upgradeManager.GetBalance(ctx, s.upgradeParams.ChainID, receiver) + s.Require().NoError(err, "can't get balance of receiver account") + + diff := balancePost.Sub(balancePre...) + s.Require().Equal(diff.String(), sentCoins.String(), "unexpected difference in bank balance") +} diff --git a/tests/e2e/upgrade/Dockerfile.init b/tests/e2e/upgrade/Dockerfile.init new file mode 100644 index 0000000..fc87806 --- /dev/null +++ b/tests/e2e/upgrade/Dockerfile.init @@ -0,0 +1,15 @@ +# argument to provide specific version of evmos node +ARG INITIAL_VERSION +# checkov:skip=CKV_DOCKER_3:No need to create a user, this is only used on tests +FROM tharsishq/evmos:$INITIAL_VERSION + +WORKDIR /go/src/github.com/evmos/evmos + +COPY ./init-node.sh . + +# JSON-RPC server +EXPOSE 8545 + +HEALTHCHECK CMD curl --fail http://localhost:26657 || exit 1 + +CMD ["sh", "./init-node.sh"] diff --git a/tests/e2e/upgrade/balances.go b/tests/e2e/upgrade/balances.go new file mode 100644 index 0000000..884442f --- /dev/null +++ b/tests/e2e/upgrade/balances.go @@ -0,0 +1,49 @@ +// Copyright Tharsis Labs Ltd.(Evmos) +// SPDX-License-Identifier:ENCL-1.0(https://github.com/evmos/evmos/blob/main/LICENSE) + +package upgrade + +import ( + "context" + "fmt" + + "github.com/cosmos/cosmos-sdk/codec" + sdk "github.com/cosmos/cosmos-sdk/types" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" +) + +// GetBalance returns the account balance for the given address bech32 string through +// the CLI query. +func (m *Manager) GetBalance(ctx context.Context, chainID, address string) (sdk.Coins, error) { + queryArgs := QueryArgs{ + Module: "bank", + SubCommand: "balances", + Args: []string{address}, + ChainID: chainID, + } + + exec, err := m.CreateModuleQueryExec(queryArgs) + if err != nil { + return sdk.Coins{}, fmt.Errorf("create exec error: %w", err) + } + + outBuff, errBuff, err := m.RunExec(ctx, exec) + if err != nil { + return sdk.Coins{}, fmt.Errorf("run exec error: %w", err) + } + if errBuff.String() != "" { + return sdk.Coins{}, fmt.Errorf("evmos query error: %s", errBuff.String()) + } + + return UnpackBalancesResponse(m.ProtoCodec, outBuff.String()) +} + +// UnpackBalancesResponse unpacks the balances response from the given output of the bank balances query. +func UnpackBalancesResponse(cdc *codec.ProtoCodec, out string) (sdk.Coins, error) { + var balances banktypes.QueryAllBalancesResponse + if err := cdc.UnmarshalJSON([]byte(out), &balances); err != nil { + return sdk.Coins{}, fmt.Errorf("failed to unmarshal balances: %w", err) + } + + return balances.Balances, nil +} diff --git a/tests/e2e/upgrade/balances_test.go b/tests/e2e/upgrade/balances_test.go new file mode 100644 index 0000000..1dead10 --- /dev/null +++ b/tests/e2e/upgrade/balances_test.go @@ -0,0 +1,70 @@ +package upgrade_test + +import ( + "fmt" + "testing" + + "cosmossdk.io/math" + "github.com/cosmos/cosmos-sdk/codec" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/evmos/evmos/v20/encoding" + "github.com/evmos/evmos/v20/tests/e2e/upgrade" + "github.com/stretchr/testify/require" +) + +func TestUnpackBalancesResponse(t *testing.T) { + t.Parallel() + + expAmount, ok := math.NewIntFromString("1000000000000000000000") + require.True(t, ok, "failed to convert amount to int") + + encodingConfig := encoding.MakeConfig() + protoCodec, ok := encodingConfig.Codec.(*codec.ProtoCodec) + require.True(t, ok, "failed to cast codec to proto codec") + + testcases := []struct { + name string + output string + want sdk.Coins + expPass bool + errContains string + }{ + { + name: "success", + output: fmt.Sprintf( + `{"balances":[{"denom":"aevmos","amount":"%s"}],`+ + `"pagination":{"next_key":null,"total":"0"}}`, + expAmount, + ), + want: sdk.Coins{sdk.NewCoin("aevmos", expAmount)}, + expPass: true, + }, + { + name: "pass - empty balances", + output: `{"balances":[],"pagination":{"next_key":null,"total":"0"}}`, + want: sdk.Coins{}, + expPass: true, + }, + { + name: "fail - invalid output", + output: `invalid`, + errContains: "failed to unmarshal balances", + }, + } + + for _, tc := range testcases { + tc := tc // Added for parallel testing, check https://pkg.go.dev/testing#hdr-Subtests_and_Sub_benchmarks + t.Run(tc.name, func(t *testing.T) { + t.Parallel() + + got, err := upgrade.UnpackBalancesResponse(protoCodec, tc.output) + if tc.expPass { + require.NoError(t, err, "unexpected error") + require.Equal(t, tc.want, got, "expected different balances") + } else { + require.Error(t, err, "expected error but got none") + require.ErrorContains(t, err, tc.errContains, "expected different error") + } + }) + } +} diff --git a/tests/e2e/upgrade/constants.go b/tests/e2e/upgrade/constants.go new file mode 100644 index 0000000..4221b2b --- /dev/null +++ b/tests/e2e/upgrade/constants.go @@ -0,0 +1,24 @@ +// Copyright Tharsis Labs Ltd.(Evmos) +// SPDX-License-Identifier:ENCL-1.0(https://github.com/evmos/evmos/blob/main/LICENSE) +package upgrade + +// The constants used in the upgrade tests are defined here +const ( + // the defaultChainID used for testing + defaultChainID = "evmos_9000-1" + + // LocalVersionTag defines the docker image ImageTag when building locally + // + // NOTE: For upgrade tests we're using the PebbleDB build + LocalVersionTag = "latest-pebble" + + // tharsisRepo is the docker hub repository that contains the Evmos images pulled during tests + tharsisRepo = "tharsishq/evmos" + + // upgradesPath is the relative path from this folder to the app/upgrades folder + upgradesPath = "../../../app/upgrades" + + // versionSeparator is used to separate versions in the INITIAL_VERSION and TARGET_VERSION + // environment vars + versionSeparator = "/" +) diff --git a/tests/e2e/upgrade/exec.go b/tests/e2e/upgrade/exec.go new file mode 100644 index 0000000..afb4963 --- /dev/null +++ b/tests/e2e/upgrade/exec.go @@ -0,0 +1,38 @@ +// Copyright Tharsis Labs Ltd.(Evmos) +// SPDX-License-Identifier:ENCL-1.0(https://github.com/evmos/evmos/blob/main/LICENSE) + +package upgrade + +import ( + "fmt" +) + +// E2ETxArgs contains the arguments to build a CLI transaction command from. +type E2ETxArgs struct { + ModuleName string + SubCommand string + Args []string + ChainID string + From string +} + +// CreateModuleTxExec creates the execution command for an Evmos transaction. +func (m *Manager) CreateModuleTxExec(txArgs E2ETxArgs) (string, error) { + cmd := []string{ + "evmosd", + "tx", + txArgs.ModuleName, + txArgs.SubCommand, + } + cmd = append(cmd, txArgs.Args...) + cmd = append(cmd, + fmt.Sprintf("--chain-id=%s", txArgs.ChainID), + "--keyring-backend=test", + "--output=text", + "--fees=50000000000000aevmos", + "--gas=auto", + fmt.Sprintf("--from=%s", txArgs.From), + "--yes", + ) + return m.CreateExec(cmd, m.ContainerID()) +} diff --git a/tests/e2e/upgrade/govexec.go b/tests/e2e/upgrade/govexec.go new file mode 100644 index 0000000..bab9be4 --- /dev/null +++ b/tests/e2e/upgrade/govexec.go @@ -0,0 +1,142 @@ +// Copyright Tharsis Labs Ltd.(Evmos) +// SPDX-License-Identifier:ENCL-1.0(https://github.com/evmos/evmos/blob/main/LICENSE) + +package upgrade + +import ( + "bytes" + "context" + "fmt" + + "github.com/ory/dockertest/v3/docker" +) + +// RunExec runs the provided docker exec call +func (m *Manager) RunExec(ctx context.Context, exec string) (outBuf bytes.Buffer, errBuf bytes.Buffer, err error) { + err = m.pool.Client.StartExec(exec, docker.StartExecOptions{ + Context: ctx, + Detach: false, + OutputStream: &outBuf, + ErrorStream: &errBuf, + }) + return +} + +// CreateExec creates docker exec command for specified container +func (m *Manager) CreateExec(cmd []string, containerID string) (string, error) { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + exec, err := m.pool.Client.CreateExec(docker.CreateExecOptions{ + Context: ctx, + AttachStdout: true, + AttachStderr: true, + User: "root", + Container: containerID, + Cmd: cmd, + }) + if err != nil { + return "", err + } + return exec.ID, nil +} + +// CreateSubmitProposalExec creates a gov tx to submit an upgrade proposal to the chain +func (m *Manager) CreateSubmitProposalExec(targetVersion, chainID string, upgradeHeight uint, legacy ProposalVersion, flags ...string) (string, error) { + cmd := getProposalCmd(legacy, targetVersion, upgradeHeight, chainID) + cmd = append(cmd, flags...) + // increment proposal counter to use proposal number for deposit && voting + m.proposalCounter++ + return m.CreateExec(cmd, m.ContainerID()) +} + +func getProposalCmd(legacy ProposalVersion, targetVersion string, upgradeHeight uint, chainID string) []string { + var cmd []string + if legacy == UpgradeProposalV50 { + cmd = []string{ + "evmosd", + "tx", + "upgrade", + "software-upgrade", + targetVersion, + "--summary=\"Test upgrade proposal\"", + "--no-validate", + } + } else { + var upgradeInfo, proposalType string + + switch legacy { + case LegacyProposalPreV50: + upgradeInfo = "--no-validate" + proposalType = "submit-legacy-proposal" + case LegacyProposalPreV46: + upgradeInfo = "--upgrade-info=\"\"" + proposalType = "submit-proposal" + default: + panic(fmt.Sprintf("invalid legacy proposal version: %v", legacy)) + } + + cmd = []string{ + "evmosd", + "tx", + "gov", + proposalType, + "software-upgrade", + targetVersion, + upgradeInfo, + } + } + + cmd = append(cmd, + "--title=\"TEST\"", + "--deposit=10000000aevmos", + "--description=\"Test upgrade proposal\"", + fmt.Sprintf("--upgrade-height=%d", upgradeHeight), + fmt.Sprintf("--chain-id=%s", chainID), + "--from=mykey", + "--yes", + "--keyring-backend=test", + "--output=text", + ) + + return cmd +} + +// CreateDepositProposalExec creates a gov tx to deposit for the proposal with the given id +func (m *Manager) CreateDepositProposalExec(chainID string, id int) (string, error) { + cmd := []string{ + "evmosd", + "tx", + "gov", + "deposit", + fmt.Sprint(id), + "10000000aevmos", + "--from=mykey", + fmt.Sprintf("--chain-id=%s", chainID), + "--yes", + "--keyring-backend=test", + "--output=text", + "--fees=500aevmos", + "--gas=500000", + } + + return m.CreateExec(cmd, m.ContainerID()) +} + +// CreateVoteProposalExec creates gov tx to vote 'yes' on the proposal with the given id +func (m *Manager) CreateVoteProposalExec(chainID string, id int, flags ...string) (string, error) { + cmd := []string{ + "evmosd", + "tx", + "gov", + "vote", + fmt.Sprint(id), + "yes", + "--from=mykey", + fmt.Sprintf("--chain-id=%s", chainID), + "--yes", + "--keyring-backend=test", + "--output=text", + } + cmd = append(cmd, flags...) + return m.CreateExec(cmd, m.ContainerID()) +} diff --git a/tests/e2e/upgrade/manager.go b/tests/e2e/upgrade/manager.go new file mode 100644 index 0000000..ba81ff7 --- /dev/null +++ b/tests/e2e/upgrade/manager.go @@ -0,0 +1,468 @@ +// Copyright Tharsis Labs Ltd.(Evmos) +// SPDX-License-Identifier:ENCL-1.0(https://github.com/evmos/evmos/blob/main/LICENSE) + +package upgrade + +import ( + "bytes" + "context" + "encoding/json" + "fmt" + "io" + "math/big" + "net/http" + "os" + "regexp" + "strconv" + "strings" + "time" + + errorsmod "cosmossdk.io/errors" + "github.com/cosmos/cosmos-sdk/codec" + "github.com/ethereum/go-ethereum/common" + testnetwork "github.com/evmos/evmos/v20/testutil/integration/evmos/network" + "github.com/ory/dockertest/v3" + "github.com/ory/dockertest/v3/docker" +) + +// safetyDelta is the number of blocks that are added to the upgrade height to make sure +// the proposal has concluded when reaching the upgrade height. +const safetyDelta = 2 + +// Manager defines a docker pool instance, used to build, run, interact with and stop docker containers +// running Evmos nodes. +type Manager struct { + pool *dockertest.Pool + network *dockertest.Network + + // CurrentNode stores the currently running docker container + CurrentNode *dockertest.Resource + + // CurrentVersion stores the current version of the running node + CurrentVersion string + + // HeightBeforeStop stores the last block height that was reached before the last running node container + // was stopped + HeightBeforeStop int + + // proposalCounter keeps track of the number of proposals that have been submitted + proposalCounter uint + + // ProtoCodec is the codec used to marshal/unmarshal protobuf messages + ProtoCodec *codec.ProtoCodec + + // UpgradeHeight stores the upgrade height for the latest upgrade proposal that was submitted + UpgradeHeight uint +} + +// NewManager creates new docker pool and network and returns a populated Manager instance +func NewManager(networkName string) (*Manager, error) { + pool, err := dockertest.NewPool("") + if err != nil { + return nil, fmt.Errorf("docker pool creation error: %w", err) + } + + network, err := pool.CreateNetwork(networkName) + if err != nil { + return nil, fmt.Errorf("docker network creation error: %w", err) + } + + nw := testnetwork.New() + encodingConfig := nw.GetEncodingConfig() + protoCodec, ok := encodingConfig.Codec.(*codec.ProtoCodec) + if !ok { + return nil, fmt.Errorf("failed to get proto codec") + } + + return &Manager{ + pool: pool, + network: network, + ProtoCodec: protoCodec, + }, nil +} + +// BuildImage builds a docker image to run in the provided context directory +// with : as the image target +func (m *Manager) BuildImage(name, version, dockerFile, contextDir string, args map[string]string) error { + buildArgs := make([]docker.BuildArg, 0, len(args)) + for k, v := range args { + bArg := docker.BuildArg{ + Name: k, + Value: v, + } + buildArgs = append(buildArgs, bArg) + } + opts := docker.BuildImageOptions{ + // local Dockerfile path + Dockerfile: dockerFile, + BuildArgs: buildArgs, + // rebuild the image every time in case there were changes + // and the image is cached + NoCache: true, + // name with tag, e.g. evmos:v9.0.0 + Name: fmt.Sprintf("%s:%s", name, version), + OutputStream: io.Discard, + ErrorStream: os.Stdout, + ContextDir: contextDir, + } + return m.Client().BuildImage(opts) +} + +// RunNode creates a docker container from the provided node instance and runs it. +// To make sure the node started properly, get requests are sent to the JSON-RPC server repeatedly +// with a timeout of 60 seconds. +// In case the node fails to start, the container logs are returned along with the error. +func (m *Manager) RunNode(node *Node) error { + var resource *dockertest.Resource + var err error + + if node.withRunOptions { + resource, err = m.pool.RunWithOptions(node.RunOptions) + } else { + resource, err = m.pool.Run(node.repository, node.version, []string{}) + } + + if err != nil { + if resource == nil || resource.Container == nil { + return fmt.Errorf( + "can't run container\n[error]: %s", + err.Error(), + ) + } + stdOut, stdErr, _ := m.GetLogs(resource.Container.ID) + return fmt.Errorf( + "can't run container\n\n[error stream]:\n\n%s\n\n[output stream]:\n\n%s", + stdErr, + stdOut, + ) + } + + // trying to get JSON-RPC server, to make sure node started properly + // the last returned error before deadline exceeded will be returned from .Retry() + err = m.pool.Retry( + func() error { + // recreating container instance because resource.Container.State + // does not update properly by default + c, err := m.Client().InspectContainer(resource.Container.ID) + if err != nil { + return fmt.Errorf("can't inspect container: %s", err.Error()) + } + // if node failed to start, i.e. ExitCode != 0, return container logs + if c.State.ExitCode != 0 { + stdOut, stdErr, _ := m.GetLogs(resource.Container.ID) + return fmt.Errorf( + "can't start evmos node, container exit code: %d\n\n[error stream]:\n\n%s\n\n[output stream]:\n\n%s", + c.State.ExitCode, + stdErr, + stdOut, + ) + } + // get host:port for current container in local network + addr := resource.GetHostPort(jrpcPort + "/tcp") + r, err := http.Get("http://" + addr) + if err != nil { + return fmt.Errorf("can't get node json-rpc server: %s", err) + } + defer r.Body.Close() + return nil + }, + ) + if err != nil { + stdOut, stdErr, _ := m.GetLogs(resource.Container.ID) + return fmt.Errorf( + "can't start node: %s\n\n[error stream]:\n\n%s\n\n[output stream]:\n\n%s", + err.Error(), + stdErr, + stdOut, + ) + } + m.CurrentNode = resource + return nil +} + +// GetLogs returns the logs of the container with the provided containerID +func (m *Manager) GetLogs(containerID string) (stdOut, stdErr string, err error) { + var outBuf, errBuf bytes.Buffer + opts := docker.LogsOptions{ + Container: containerID, + OutputStream: &outBuf, + ErrorStream: &errBuf, + Stdout: true, + Stderr: true, + } + err = m.Client().Logs(opts) + if err != nil { + return "", "", fmt.Errorf("can't get logs: %s", err) + } + return outBuf.String(), errBuf.String(), nil +} + +// WaitNBlocks is a helper function to wait the specified number of blocks +func (m *Manager) WaitNBlocks(ctx context.Context, n int) error { + currentHeight, err := m.GetNodeHeight(ctx) + if err != nil { + return err + } + _, err = m.WaitForHeight(ctx, currentHeight+n) + return err +} + +// WaitForHeight queries the Evmos node every second until the node will reach the specified height. +// After 5 minutes this function times out and returns an error +func (m *Manager) WaitForHeight(ctx context.Context, height int) (string, error) { + var currentHeight int + var err error + ticker := time.NewTicker(2 * time.Minute) + for { + select { + case <-ticker.C: + stdOut, stdErr, errLogs := m.GetLogs(m.ContainerID()) + if errLogs != nil { + return "", fmt.Errorf("error while getting logs: %s", errLogs.Error()) + } + return "", fmt.Errorf( + "can't reach height %d, due to: %v\nerror logs: %s\nout logs: %s", + height, err, stdOut, stdErr, + ) + default: + currentHeight, err = m.GetNodeHeight(ctx) + if currentHeight >= height { + if err != nil { + return err.Error(), nil + } + return "", nil + } + time.Sleep(1 * time.Second) + } + } +} + +// GetNodeHeight calls the Evmos CLI in the current node container to get the current block height +func (m *Manager) GetNodeHeight(ctx context.Context) (int, error) { + cmd := []string{"evmosd", "q", "block"} + splitIdx := 0 // split index for the lines in the output - in newer versions the output is in the second line + useV50 := false + + // if the version is higher than v20.0.0, we need to use the json output flag + if !EvmosVersions([]string{m.CurrentVersion, "v20.0.0"}).Less(0, 1) { + cmd = append(cmd, "--output=json") + splitIdx = 1 + useV50 = true + } + + exec, err := m.CreateExec(cmd, m.ContainerID()) + if err != nil { + return 0, fmt.Errorf("create exec error: %w", err) + } + + outBuff, errBuff, err := m.RunExec(ctx, exec) + if err != nil { + return 0, fmt.Errorf("run exec error: %w", err) + } + + if errBuff.String() != "" { + return 0, fmt.Errorf("evmos query error: %s", errBuff.String()) + } + + // NOTE: we're splitting the output because it has the first line saying "falling back to latest height" + splittedOutBuff := strings.Split(outBuff.String(), "\n") + if len(splittedOutBuff) < splitIdx+1 { + return 0, fmt.Errorf("unexpected output format for node height; got: %s", outBuff.String()) + } + + outStr := splittedOutBuff[splitIdx] + var h int + // parse current height number from block info + if outStr != "" && outStr != "" { + if useV50 { + h, err = UnwrapBlockHeightPostV50(outStr) + } else { + h, err = UnwrapBlockHeightPreV50(outStr) + } + + // check if the conversion was possible + if err == nil { + // if conversion was possible but the errBuff is not empty, return the height along with an error + // this is necessary e.g. when the "duplicate proto" errors occur in the logs but the node is still + // producing blocks + if errBuff.String() != "" { + return h, fmt.Errorf("%s", errBuff.String()) + } + return h, nil + } + } + + return h, nil +} + +type BlockHeaderPreV50 struct { + Block struct { + Header struct { + Height string `json:"height"` + } `json:"header"` + } `json:"block"` +} + +type BlockHeaderPostV50 struct { + Header struct { + Height string `json:"height"` + } `json:"header"` +} + +// UnwrapBlockHeightPreV50 unwraps the block height from the output of the evmosd query block command +func UnwrapBlockHeightPreV50(input string) (int, error) { + var blockHeader BlockHeaderPreV50 + err := json.Unmarshal([]byte(input), &blockHeader) + if err != nil { + return 0, fmt.Errorf("failed to unmarshal JSON: %v", err) + } + + return strconv.Atoi(blockHeader.Block.Header.Height) +} + +// UnwrapBlockHeightPostV50 unwraps the block height from the output of the evmosd query block command +func UnwrapBlockHeightPostV50(input string) (int, error) { + var blockHeader BlockHeaderPostV50 + err := json.Unmarshal([]byte(input), &blockHeader) + if err != nil { + return 0, fmt.Errorf("failed to unmarshal JSON: %v", err) + } + + return strconv.Atoi(blockHeader.Header.Height) +} + +// GetNodeVersion calls the Evmos CLI in the current node container to get the +// current node version +func (m *Manager) GetNodeVersion(ctx context.Context) (string, error) { + exec, err := m.CreateExec([]string{"evmosd", "version"}, m.ContainerID()) + if err != nil { + return "", fmt.Errorf("create exec error: %w", err) + } + outBuff, errBuff, err := m.RunExec(ctx, exec) + if err != nil { + return "", fmt.Errorf("run exec error: %w", err) + } + if errBuff.String() != "" { + return "", fmt.Errorf("evmos version error: %s", errBuff.String()) + } + return outBuff.String(), nil +} + +// GetUpgradeHeight calculates the height for the scheduled software upgrade. +// +// It checks the timeout commit that is configured on the node and checks the voting duration. +// From this information, the height at which the upgrade will be scheduled is calculated. +func (m *Manager) GetUpgradeHeight(ctx context.Context, chainID string) (uint, error) { + currentHeight, err := m.GetNodeHeight(ctx) + if err != nil { + return 0, err + } + + timeoutCommit, err := m.getTimeoutCommit(ctx) + if err != nil { + return 0, errorsmod.Wrap(err, "failed to get timeout commit") + } + + votingPeriod, err := m.getVotingPeriod(ctx, chainID) + if err != nil { + return 0, errorsmod.Wrap(err, "failed to get voting period") + } + + heightDelta := new(big.Int).Quo(votingPeriod, timeoutCommit) + upgradeHeight := uint(currentHeight) + uint(heightDelta.Int64()) + safetyDelta // #nosec G115 + + // return the height at which the upgrade will be scheduled + return upgradeHeight, nil +} + +// getTimeoutCommit returns the timeout commit duration for the current node +func (m *Manager) getTimeoutCommit(ctx context.Context) (*big.Int, error) { + exec, err := m.CreateExec([]string{"grep", `\s*timeout_commit =`, "/root/.evmosd/config/config.toml"}, m.ContainerID()) + if err != nil { + return common.Big0, fmt.Errorf("create exec error: %w", err) + } + + outBuff, errBuff, err := m.RunExec(ctx, exec) + if err != nil { + return common.Big0, fmt.Errorf("failed to execute command: %s", err.Error()) + } + + if errBuff.String() != "" { + return common.Big0, fmt.Errorf("evmos version error: %s", errBuff.String()) + } + + re := regexp.MustCompile(`timeout_commit = "(?P\d+)s"`) + match := re.FindStringSubmatch(outBuff.String()) + if len(match) != 2 { + return common.Big0, fmt.Errorf("failed to parse timeout_commit: %s", outBuff.String()) + } + + tc, err := strconv.Atoi(match[1]) + if err != nil { + return common.Big0, err + } + + return big.NewInt(int64(tc)), nil +} + +// getVotingPeriod returns the voting period for the current node +func (m *Manager) getVotingPeriod(ctx context.Context, chainID string) (*big.Int, error) { + exec, err := m.CreateModuleQueryExec(QueryArgs{ + Module: "gov", + SubCommand: "params", + ChainID: chainID, + }) + if err != nil { + return common.Big0, fmt.Errorf("create exec error: %w", err) + } + + outBuff, errBuff, err := m.RunExec(ctx, exec) + if err != nil { + return common.Big0, fmt.Errorf("failed to execute command: %s", err.Error()) + } + + if errBuff.String() != "" { + return common.Big0, fmt.Errorf("evmos version error: %s", errBuff.String()) + } + + re := regexp.MustCompile(`"voting_period":"(?P\d+)s"`) + match := re.FindStringSubmatch(outBuff.String()) + if len(match) != 2 { + return common.Big0, fmt.Errorf("failed to parse voting_period: %s", outBuff.String()) + } + + vp, err := strconv.Atoi(match[1]) + if err != nil { + return common.Big0, err + } + + return big.NewInt(int64(vp)), nil +} + +// ContainerID returns the docker container ID of the currently running Node +func (m *Manager) ContainerID() string { + if m.CurrentNode == nil || m.CurrentNode.Container == nil { + return "" + } + return m.CurrentNode.Container.ID +} + +// The Client method returns the Docker client used by the Manager's pool +func (m *Manager) Client() *docker.Client { + return m.pool.Client +} + +// RemoveNetwork removes the Manager's used network from the pool +func (m *Manager) RemoveNetwork() error { + return m.pool.RemoveNetwork(m.network) +} + +// KillCurrentNode stops the execution of the currently used docker container +func (m *Manager) KillCurrentNode() error { + heightBeforeStop, err := m.GetNodeHeight(context.Background()) + if err != nil && heightBeforeStop == 0 { + return err + } + m.HeightBeforeStop = heightBeforeStop + return m.pool.Client.StopContainer(m.ContainerID(), 5) +} diff --git a/tests/e2e/upgrade/manager_test.go b/tests/e2e/upgrade/manager_test.go new file mode 100644 index 0000000..e7a92fa --- /dev/null +++ b/tests/e2e/upgrade/manager_test.go @@ -0,0 +1,25 @@ +package upgrade_test + +import ( + "testing" + + "github.com/evmos/evmos/v20/tests/e2e/upgrade" + "github.com/stretchr/testify/require" +) + +const ( + blockOutputPreV50 = "{\"block_id\":{\"hash\":\"ECECD69FAF6D6B0722042615CA6B63C3520CE207A03B70A35BC549ECB4101798\",\"parts\":{\"total\":1,\"hash\":\"C433720E863ADA05E015DF78590F13C467FCE3D13B6F8FAD0B4BE94F98093457\"}},\"block\":{\"header\":{\"version\":{\"block\":\"11\"},\"chain_id\":\"evmos_9000-1\",\"height\":\"40\",\"time\":\"2024-08-29T20:59:03.029214545Z\",\"last_block_id\":{\"hash\":\"F5E28BDAAFB6E3769FE15E29256D2D2F265E150D73F6ADC84F76C64A5B668F5C\",\"parts\":{\"total\":1,\"hash\":\"EC6D871E67B5662FB96A696B9E74EA8436B74A5EE1B4F8FDE4007713101CAEB8\"}},\"last_commit_hash\":\"BBE9C89F763E696B189F11C2870893F966FEF5B46085C13D4551FE8F914246E1\",\"data_hash\":\"E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855\",\"validators_hash\":\"3E57E93AFF0EFFA13F92F3F363C4FBB8090D812072035D4D81DA91A1C289562A\",\"next_validators_hash\":\"3E57E93AFF0EFFA13F92F3F363C4FBB8090D812072035D4D81DA91A1C289562A\",\"consensus_hash\":\"7D0B88F8835DB6E92EC4E959CCD9324052C68794BC42567CFA45FB176ED6679A\",\"app_hash\":\"18ADDA9AD92E7C62915702E2A272891FA4EAE006BDD7B117CC2A4A05A262C9B6\",\"last_results_hash\":\"E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855\",\"evidence_hash\":\"E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855\",\"proposer_address\":\"2E33F057457BD6B1374B6776A5A2315CD177E8C8\"},\"data\":{\"txs\":null},\"evidence\":{\"evidence\":null},\"last_commit\":{\"height\":\"39\",\"round\":0,\"block_id\":{\"hash\":\"F5E28BDAAFB6E3769FE15E29256D2D2F265E150D73F6ADC84F76C64A5B668F5C\",\"parts\":{\"total\":1,\"hash\":\"EC6D871E67B5662FB96A696B9E74EA8436B74A5EE1B4F8FDE4007713101CAEB8\"}},\"signatures\":[{\"block_id_flag\":2,\"validator_address\":\"2E33F057457BD6B1374B6776A5A2315CD177E8C8\",\"timestamp\":\"2024-08-29T20:59:03.029214545Z\",\"signature\":\"vcK+Ew9OT/fTGKhxVH/ehKE/7dJ82BSHXNZb/B/saVB+0UhC1qFN/rBQ+FuihNN5J95IG2YdOe+2Fppg7RN1CA==\"}]}}}" + blockOutputPostV50 = "{\"header\":{\"version\":{\"block\":\"11\",\"app\":\"0\"},\"chain_id\":\"evmos_9001-2\",\"height\":\"23136576\",\"time\":\"2024-08-29T21:07:47.173219060Z\",\"last_block_id\":{\"hash\":\"MFoG3Nc8BrfGLBWUtSm3XU/dJG45WZW8MxIo5IAlyho=\",\"part_set_header\":{\"total\":1,\"hash\":\"WlEMTfEcyTyNHzn9FTUZpTWEaOLGOIAYmN0H7gT7Hpk=\"}},\"last_commit_hash\":\"rs55UXNU/Ff/iIdnvf7Uu+OOh+N5nYmI1+jTpY92904=\",\"data_hash\":\"47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=\",\"validators_hash\":\"VFhmtCGzqKtwoK5lewntJwZdn6W7MR0u3tnWTVuWw9g=\",\"next_validators_hash\":\"VFhmtCGzqKtwoK5lewntJwZdn6W7MR0u3tnWTVuWw9g=\",\"consensus_hash\":\"ek5k0qm1ziK3XpVuICUnTcA7aEbM13JRUqa8DQcn4z4=\",\"app_hash\":\"KNmdEQk59wmj0JUCsmpRcXMhVN6Ru3PRpOWj2hykRjg=\",\"last_results_hash\":\"47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=\",\"evidence_hash\":\"47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=\",\"proposer_address\":\"INsp0gYoMX+pxKxyiKFV87qe3zo=\"},\"data\":{\"txs\":[]},\"evidence\":{\"evidence\":[]},\"last_commit\":{\"height\":\"23136575\",\"round\":0,\"block_id\":{\"hash\":\"MFoG3Nc8BrfGLBWUtSm3XU/dJG45WZW8MxIo5IAlyho=\",\"part_set_header\":{\"total\":1,\"hash\":\"WlEMTfEcyTyNHzn9FTUZpTWEaOLGOIAYmN0H7gT7Hpk=\"}},\"signatures\":[{\"block_id_flag\":\"BLOCK_ID_FLAG_COMMIT\",\"validator_address\":\"INsp0gYoMX+pxKxyiKFV87qe3zo=\",\"timestamp\":\"2024-08-29T21:07:47.151689399Z\",\"signature\":\"zTYJQPONiX0fcJMTVJT42XOmxkJC1ycirXQtJ/sQRItJ6ARe5RxdErQiNfbDqh3JApKfshoRMu59RWkUUTI/AA==\"},{\"block_id_flag\":\"BLOCK_ID_FLAG_COMMIT\",\"validator_address\":\"PNbD6+ovTnEkQQAxn4zzqbU0MyI=\",\"timestamp\":\"2024-08-29T21:07:47.190517293Z\",\"signature\":\"okzGvzYOTYRiCXc1YT4an6Oz7EetSwM4Pyj5vqYvJY1BpymD2MfeLp+u+vd0AeIsnimmngyMM35LWfmhOh3VCA==\"},{\"block_id_flag\":\"BLOCK_ID_FLAG_COMMIT\",\"validator_address\":\"gVWhxuhAuZBkUGGIIaRtl972nr4=\",\"timestamp\":\"2024-08-29T21:10:55.258272572Z\",\"signature\":\"gJ5TuPbRt+XwBcBQblcKjmBjIV80XU/SGGhCIMO+0A79XRij9XgIJ+w069ttbkN4KelhWaVcuEIlvOP086mhCg==\"},{\"block_id_flag\":\"BLOCK_ID_FLAG_COMMIT\",\"validator_address\":\"q3gXyrWm5QD0ytQqUiye/bo1naE=\",\"timestamp\":\"2024-08-29T21:07:47.175072852Z\",\"signature\":\"g4tvzy/E6x0s3yIZ3yWktDLycLino3Oj6DDDTnXVyxtnV4iMBtowKbCX0vNc1eiUc684POURtbjtjxP9qWQ/Aw==\"},{\"block_id_flag\":\"BLOCK_ID_FLAG_COMMIT\",\"validator_address\":\"ZyqajL8AeAA5TKmUIvhN+/bLpV4=\",\"timestamp\":\"2024-08-29T21:07:47.176287728Z\",\"signature\":\"EhGb0eIyNeBNWqa24ouhw2MpZTvBXYGk76ipZ+PHzMv8+4zoZ4J+jtTFEDM10Mj6g4/EZfSpdsG6P4bAQihHAw==\"},{\"block_id_flag\":\"BLOCK_ID_FLAG_COMMIT\",\"validator_address\":\"8vf1/A5QX+0NszBqZp2oiOZplZw=\",\"timestamp\":\"2024-08-29T21:07:47.171566330Z\",\"signature\":\"Wm4zmzNVQsrnpTxonEiUpv/I4wnFA6CQSqd5u9T1Gb0jl+5hufmziMnDmxC4R00CTEysXFuTXKz4Pp6Qg90UBg==\"},{\"block_id_flag\":\"BLOCK_ID_FLAG_COMMIT\",\"validator_address\":\"tsPbkG+u8sh1jRiBOG5hXoQyqRw=\",\"timestamp\":\"2024-08-29T21:07:47.160570450Z\",\"signature\":\"LKhUrTphNk1ZWcqsaMvH/NgBy9kWnqql9zs/M8CR8rCcCHi4llZnnqw++0rkCIi0a2bRXtiYmiUEF3e49lgXBg==\"},{\"block_id_flag\":\"BLOCK_ID_FLAG_COMMIT\",\"validator_address\":\"fLQ4DAeE+5p51msU7OucyRAplb8=\",\"timestamp\":\"2024-08-29T21:07:47.189346366Z\",\"signature\":\"jeAFqiq4VUI79rMNkd9NzLrXSyH/Ssra5UK9OmMIyv+9/y4Jx5hWQoTwPutLfseDEdAHnwM9hKc+4rUMRe34CA==\"},{\"block_id_flag\":\"BLOCK_ID_FLAG_COMMIT\",\"validator_address\":\"u5kxpaHBNO8ZZVxHyipibsqAwHE=\",\"timestamp\":\"2024-08-29T21:07:47.178648344Z\",\"signature\":\"68xYCrTjK/SYPn7Fh5QyvjgwvqbOYNvMzUpjCnXpOkPv94z80T4qUrjIh9JHUSXlv25qg6EBmXoi5tJhmGAPBw==\"},{\"block_id_flag\":\"BLOCK_ID_FLAG_COMMIT\",\"validator_address\":\"2gFXnp7Wxh0MboY5hiLSveXcp8M=\",\"timestamp\":\"2024-08-29T21:07:47.152986647Z\",\"signature\":\"MNzh3Ji59ZuANClXJTNl2fRbIQrdctaJDO5ez0UIcsMsGPF5c8HWMKzE4xLM4W9FN7UbZno2e/XDpN2HZk9bAg==\"},{\"block_id_flag\":\"BLOCK_ID_FLAG_COMMIT\",\"validator_address\":\"dmkhFfk65ET6hXx7qWPxJdjC5sY=\",\"timestamp\":\"2024-08-29T21:07:47.165135535Z\",\"signature\":\"V6/DVfD7Ag5oMhsbPw9HfzpNdOv0ojVrVF64M31Blzpsj9yr3CN3AX6dHEV8VLS6oTSNqRe7m3lNlMzlw8vOBg==\"},{\"block_id_flag\":\"BLOCK_ID_FLAG_COMMIT\",\"validator_address\":\"sx94eM3xHLKEE8z5/yxT6GnztlI=\",\"timestamp\":\"2024-08-29T21:07:47.174593472Z\",\"signature\":\"/ELSkgB7Lrr564/e3X8Ijzc5TSCbq5GwRSY7so2003LBvz93Ah0xvcuwtIxIc1cM55brj3iyBmhAyyQGbJJqDQ==\"},{\"block_id_flag\":\"BLOCK_ID_FLAG_COMMIT\",\"validator_address\":\"h+74vYVpLWjBYypK789kLmK010E=\",\"timestamp\":\"2024-08-29T21:07:47.160196561Z\",\"signature\":\"L/abFJLDQbLibh71fu2SLe9l5WJVsP7bsbWMAiyVeSR57hZ+yCUEYbABCgo2ZsiruPp+1ZVlKGf+q1uZjaRkDg==\"},{\"block_id_flag\":\"BLOCK_ID_FLAG_COMMIT\",\"validator_address\":\"fQ8XJW1rIsBOfscAODT1vIo68UQ=\",\"timestamp\":\"2024-08-29T21:07:47.171499902Z\",\"signature\":\"mogIBHuTm/ytCm//lOnXihm6R7eRFkZrijwWkgVfndRZIZreGQyiFqJei8jcV06nAczIPBe3meD3mtC5sXALBg==\"},{\"block_id_flag\":\"BLOCK_ID_FLAG_COMMIT\",\"validator_address\":\"v1/AbjKkFogXoW1paS82yPel2jc=\",\"timestamp\":\"2024-08-29T21:07:47.186492788Z\",\"signature\":\"KJRJuaC1r83O1aCd5pcwZMVSJgBgrt/1z571DkafSYl9E+5WiCcFFUx7F+TJVouXTeOd7leg6eRjdBLvLFlZAQ==\"},{\"block_id_flag\":\"BLOCK_ID_FLAG_COMMIT\",\"validator_address\":\"ktHF8RsGVqD7MJxOx6OtaodeFSs=\",\"timestamp\":\"2024-08-29T21:07:47.164166723Z\",\"signature\":\"XE4IMVZV49CUHGTOI7hpq+DZ6cL6plKv/wq8epzeWnF31DX5mBARWdbWWNjB3ftlZqW244ZMBLK4P0xvv+zzCA==\"},{\"block_id_flag\":\"BLOCK_ID_FLAG_COMMIT\",\"validator_address\":\"4qSeAH8p6atOaURmwC0U7u4S380=\",\"timestamp\":\"2024-08-29T21:07:47.161100379Z\",\"signature\":\"EvvZjNw3fwRAS3ECXuXlCS50hbJKSo9k65MvrbYFwC269ABemdygf0cE8SrF5HfRjAuncywzgqjyrA76QjLNDg==\"},{\"block_id_flag\":\"BLOCK_ID_FLAG_COMMIT\",\"validator_address\":\"B30FDOAwzvoOmN1/DxCyWb6wj28=\",\"timestamp\":\"2024-08-29T21:07:47.154195098Z\",\"signature\":\"Gr0cbNlzG89mV05D+GzP51P2eWdmm4oeaTvyt/n5PzhxDME9KlbZWTPXiu6eQWMrCN7qbqh68/HOHBOvHNc2Aw==\"},{\"block_id_flag\":\"BLOCK_ID_FLAG_COMMIT\",\"validator_address\":\"U7HWxxiQjw09k87HbDM45mZhjTg=\",\"timestamp\":\"2024-08-29T21:07:47.172476499Z\",\"signature\":\"5mwEzHtQyObVJ30zHUayW8a7OiU4lAcSZ/lb0reUP42ZBlIQxqf1OukrmcTUNrZhnzlCE66ujPfwkU+frxyCDQ==\"},{\"block_id_flag\":\"BLOCK_ID_FLAG_COMMIT\",\"validator_address\":\"Xx/1I0Iypa8OrdL2vGqIi90wWn0=\",\"timestamp\":\"2024-08-29T21:07:47.173219060Z\",\"signature\":\"2pPS9qOys5cchdWB4BfT9aFqedXPvMPPSZ1nXYbatMNBNLM3x2rgq78ZiRIm+98UMrGlw7O5C/j+d9sf0WUZAg==\"}]}}" +) + +func TestUnwrapBlockHeight(t *testing.T) { + blockHeight, err := upgrade.UnwrapBlockHeightPreV50(blockOutputPreV50) + require.NoError(t, err, "error unwrapping block height") + require.Equal(t, 40, blockHeight, "block height does not match") +} + +func TestUnwrapBlockHeightPostV50(t *testing.T) { + blockHeight, err := upgrade.UnwrapBlockHeightPostV50(blockOutputPostV50) + require.NoError(t, err, "error unwrapping block height") + require.Equal(t, 23136576, blockHeight, "block height does not match") +} diff --git a/tests/e2e/upgrade/node.go b/tests/e2e/upgrade/node.go new file mode 100644 index 0000000..6a641de --- /dev/null +++ b/tests/e2e/upgrade/node.go @@ -0,0 +1,63 @@ +// Copyright Tharsis Labs Ltd.(Evmos) +// SPDX-License-Identifier:ENCL-1.0(https://github.com/evmos/evmos/blob/main/LICENSE) + +package upgrade + +import "github.com/ory/dockertest/v3" + +const jrpcPort = "8545" + +// Node represents an Evmos node in the context of the upgrade tests. It contains +// fields to store the used repository, version as well as custom run options for +// dockertest. +type Node struct { + repository string + version string + + RunOptions *dockertest.RunOptions + withRunOptions bool +} + +// NewNode creates a new instance of the node with a set of sensible default RunOptions +// for dockertest. +func NewNode(repository, version string) *Node { + return &Node{ + repository: repository, + version: version, + RunOptions: &dockertest.RunOptions{ + User: "0:0", + Repository: repository, + Tag: version, + // exposing JSON-RPC port by default to ping node after start + ExposedPorts: []string{jrpcPort}, + }, + } +} + +// SetEnvVars allows to set additional container environment variables by passing a slice +// of strings that each fit the pattern "VAR_NAME=value". +func (n *Node) SetEnvVars(vars []string) { + n.RunOptions.Env = vars + n.UseRunOptions() +} + +// Mount sets the container mount point, which is used as the value for 'docker run --volume'. +// +// See https://docs.docker.com/engine/reference/builder/#volume +func (n *Node) Mount(mountPath string) { + n.RunOptions.Mounts = []string{mountPath} + n.UseRunOptions() +} + +// SetCmd sets the container entry command and overrides the image CMD instruction. +// +// See https://docs.docker.com/engine/reference/builder/#cmd +func (n *Node) SetCmd(cmd []string) { + n.RunOptions.Cmd = cmd + n.UseRunOptions() +} + +// UseRunOptions sets a flag to allow the node Manager to run the container with additional run options. +func (n *Node) UseRunOptions() { + n.withRunOptions = true +} diff --git a/tests/e2e/upgrade/params.go b/tests/e2e/upgrade/params.go new file mode 100644 index 0000000..429e088 --- /dev/null +++ b/tests/e2e/upgrade/params.go @@ -0,0 +1,152 @@ +// Copyright Tharsis Labs Ltd.(Evmos) +// SPDX-License-Identifier:ENCL-1.0(https://github.com/evmos/evmos/blob/main/LICENSE) + +package upgrade + +import ( + "fmt" + "os" + "regexp" + "strconv" + "strings" +) + +// Params defines the parameters for the upgrade test suite +type Params struct { + // MountPath defines the path where the docker container is mounted + MountPath string + // Versions defines the slice of versions that are run during the upgrade tests + Versions []VersionConfig + // ChainID defines the chain ID used for the upgrade tests + ChainID string + // SkipCleanup defines if the docker containers are removed after the tests + SkipCleanup bool + // WorkDirRoot defines the working directory + WorkDirRoot string +} + +// VersionConfig defines a struct that contains the version and the source repository for an upgrade +type VersionConfig struct { + // UpgradeName defines the upgrade name to use in the proposal + UpgradeName string + // ImageTag defines the version tag to use in the docker image + ImageTag string + // ImageName defines the image name for the docker image + ImageName string +} + +// LoadUpgradeParams loads the upgrade parameters from the environment variables +func LoadUpgradeParams(upgradesFolder string) (Params, error) { + var ( + // allowedVersionPattern defines the regex pattern for a semver version (including release candidates) + allowedVersionPattern = `v*\d+\.\d\.\d(-rc\d+)*` + // allowedVersionSinglePattern defines the regex pattern for a single version + allowedVersionSinglePattern = fmt.Sprintf(`^%s$`, allowedVersionPattern) + // allowedVersionListPattern defines the regex pattern for a list of versions + allowedVersionListPattern = fmt.Sprintf(`^(%s*%s)+$`, versionSeparator, allowedVersionPattern) + // err is the captured error variable + err error + // upgradeName defines the upgrade name to use in the proposal + upgradeName string + // upgradesList contains the available upgrades in the app/upgrades folder + upgradesList []string + // versionTag is a string to store the processed version tags (e.g. v10.0.1) + versionTag string + // versionTags contains the slice of all version tags that are run during the upgrade tests + versionTags []string + ) + + initialV := os.Getenv("INITIAL_VERSION") + if initialV == "" { + upgradesList, err = RetrieveUpgradesList(upgradesFolder) + if err != nil { + return Params{}, fmt.Errorf("failed to retrieve the list of upgrades: %w", err) + } + // set the second-to-last upgrade as initial version + versionTags = []string{upgradesList[len(upgradesList)-2]} + } else { + if !regexp.MustCompile(allowedVersionListPattern).MatchString(initialV) { + return Params{}, fmt.Errorf("invalid initial version: %s", initialV) + } + versionTags = strings.Split(initialV, versionSeparator) + } + + // versions contains the slice of all versions that shall be executed + versions := make([]VersionConfig, 0, len(versionTags)) + + // for all initial versions the docker hub image is used + for _, versionTag = range versionTags { + if !strings.Contains(versionTag, "v") { + versionTag = "v" + versionTag + } + versions = append(versions, VersionConfig{ + UpgradeName: versionTag, + ImageTag: versionTag, + ImageName: tharsisRepo, + }) + } + + // When a target version is specified, it is used and the tharsishq DockerHub repo used. + // If no target version is specified, the last upgrade in the app/upgrades folder is used + // and a name for the local image is assigned. + targetV := os.Getenv("TARGET_VERSION") + if targetV == "" { + if upgradesList == nil { + upgradesList, err = RetrieveUpgradesList(upgradesFolder) + if err != nil { + return Params{}, fmt.Errorf("failed to retrieve the list of upgrades: %w", err) + } + } + upgradeName = upgradesList[len(upgradesList)-1] + versionTag = LocalVersionTag + } else { + if !regexp.MustCompile(allowedVersionSinglePattern).MatchString(targetV) { + return Params{}, fmt.Errorf("invalid target version: %s", targetV) + } + if !strings.Contains(targetV, "v") { + targetV = "v" + targetV + } + upgradeName = targetV + versionTag = targetV + } + + // Add the target version to the versions slice + versions = append(versions, VersionConfig{ + upgradeName, + versionTag, + tharsisRepo, + }) + + // If chain ID is not specified, the default value from the constants file will be used in upgrade-init.sh + chainID := os.Getenv("CHAIN_ID") + if chainID == "" { + chainID = defaultChainID + } + + skipFlag := os.Getenv("E2E_SKIP_CLEANUP") + skipCleanup, err := strconv.ParseBool(skipFlag) + if err != nil { + skipCleanup = false + } + + workDir, err := os.Getwd() + if err != nil { + return Params{}, err + } + workDir = strings.TrimSuffix(workDir, "/tests/e2e") + + mountPath := os.Getenv("MOUNT_PATH") + if mountPath == "" { + mountPath = workDir + "/build/:/root/" + } + + params := Params{ + MountPath: mountPath, + Versions: versions, + ChainID: chainID, + SkipCleanup: skipCleanup, + WorkDirRoot: workDir, + } + + return params, nil +} diff --git a/tests/e2e/upgrade/params_test.go b/tests/e2e/upgrade/params_test.go new file mode 100644 index 0000000..5aa0f05 --- /dev/null +++ b/tests/e2e/upgrade/params_test.go @@ -0,0 +1,177 @@ +package upgrade + +import ( + "os" + "testing" + + "github.com/stretchr/testify/require" +) + +// envVars is a helper struct to define the used environment variables +type envVars struct { + initialVersion string + targetVersion string + chainID string + skipCleanup string + mountPath string +} + +// TestLoadUpgradeParams tests the LoadUpgradeParams function +func TestLoadUpgradeParams(t *testing.T) { + wd, err := os.Getwd() + require.NoError(t, err, "can't get current working directory") + + defaultMountPath := wd + "/build/:/root/" + availableUpgrades, err := RetrieveUpgradesList(upgradesPath) + require.NoError(t, err, "can't retrieve upgrades list") + latestVersionName := availableUpgrades[len(availableUpgrades)-1] + defaultInitialVersion := availableUpgrades[len(availableUpgrades)-2] + + testcases := []struct { + name string + vars envVars + want Params + expPass bool + }{ + { + name: "pass - all params set - one initial version", + vars: envVars{ + initialVersion: "v0.1.0", + targetVersion: "v0.2.0", + chainID: "evmos_9123-1", + skipCleanup: "true", + mountPath: "/tmp/evmos", + }, + want: Params{ + MountPath: "/tmp/evmos", + Versions: []VersionConfig{ + {"v0.1.0", "v0.1.0", tharsisRepo}, + {"v0.2.0", "v0.2.0", tharsisRepo}, + }, + ChainID: "evmos_9123-1", + WorkDirRoot: wd, + }, + expPass: true, + }, + { + name: "pass - multiple initial versions, no target version", + vars: envVars{ + initialVersion: "v0.1.0/v0.2.0", + }, + want: Params{ + MountPath: defaultMountPath, + Versions: []VersionConfig{ + {"v0.1.0", "v0.1.0", tharsisRepo}, + {"v0.2.0", "v0.2.0", tharsisRepo}, + {latestVersionName, LocalVersionTag, tharsisRepo}, + }, + ChainID: defaultChainID, + WorkDirRoot: wd, + }, + expPass: true, + }, + { + name: "pass - no 'v' prefix in version string", + vars: envVars{ + initialVersion: "0.1.0", + targetVersion: "0.2.0", + }, + want: Params{ + MountPath: defaultMountPath, + Versions: []VersionConfig{ + {"v0.1.0", "v0.1.0", tharsisRepo}, + {"v0.2.0", "v0.2.0", tharsisRepo}, + }, + ChainID: defaultChainID, + WorkDirRoot: wd, + }, + expPass: true, + }, + { + name: "pass - release candidate version", + vars: envVars{ + initialVersion: "v0.1.0-rc1", + targetVersion: "v0.2.0-rc2", + }, + want: Params{ + MountPath: defaultMountPath, + Versions: []VersionConfig{ + {"v0.1.0-rc1", "v0.1.0-rc1", tharsisRepo}, + {"v0.2.0-rc2", "v0.2.0-rc2", tharsisRepo}, + }, + ChainID: defaultChainID, + WorkDirRoot: wd, + }, + expPass: true, + }, + { + name: "pass - no initial version", + vars: envVars{}, + want: Params{ + MountPath: defaultMountPath, + Versions: []VersionConfig{ + {defaultInitialVersion, defaultInitialVersion, tharsisRepo}, + {latestVersionName, LocalVersionTag, tharsisRepo}, + }, + ChainID: defaultChainID, + WorkDirRoot: wd, + }, + expPass: true, + }, + { + name: "fail - separator in target version", + vars: envVars{ + initialVersion: "v0.1.0", + targetVersion: "v0.2.0/v0.3.0", + }, + want: Params{}, + expPass: false, + }, + { + name: "fail - wrong version separator", + vars: envVars{ + initialVersion: "v0.1.0|v0.2.0", + }, + want: Params{}, + expPass: false, + }, + { + name: "fail - invalid target version string", + vars: envVars{ + targetVersion: "v@93bca", + }, + want: Params{}, + expPass: false, + }, + { + name: "fail - invalid initial version string", + vars: envVars{ + initialVersion: "v@93bca", + }, + want: Params{}, + expPass: false, + }, + } + + for _, tc := range testcases { + t.Run(tc.name, func(t *testing.T) { + t.Setenv("INITIAL_VERSION", tc.vars.initialVersion) + t.Setenv("TARGET_VERSION", tc.vars.targetVersion) + t.Setenv("CHAIN_ID", tc.vars.chainID) + t.Setenv("SKIP_CLEANUP", tc.vars.skipCleanup) + t.Setenv("MOUNT_PATH", tc.vars.mountPath) + + params, err := LoadUpgradeParams(upgradesPath) + if tc.expPass { + require.NoError(t, err, "LoadUpgradeParams() should not return an error") + } else { + require.Error(t, err, "LoadUpgradeParams() should return an error") + } + require.Equal(t, tc.want.ChainID, params.ChainID, "chain id differs from the expected value") + require.Equal(t, tc.want.MountPath, params.MountPath, "mount path differs from the expected value") + require.Equal(t, tc.want.Versions, params.Versions, "versions differ from the expected values") + require.Equal(t, tc.want.WorkDirRoot, params.WorkDirRoot, "root working directory differs from the expected value") + require.Equal(t, tc.want.SkipCleanup, params.SkipCleanup, "flag to skip cleanup differs from the expected value") + }) + } +} diff --git a/tests/e2e/upgrade/queryexec.go b/tests/e2e/upgrade/queryexec.go new file mode 100644 index 0000000..8f532ce --- /dev/null +++ b/tests/e2e/upgrade/queryexec.go @@ -0,0 +1,61 @@ +// Copyright Tharsis Labs Ltd.(Evmos) +// SPDX-License-Identifier:ENCL-1.0(https://github.com/evmos/evmos/blob/main/LICENSE) + +package upgrade + +import ( + "fmt" +) + +// QueryArgs is a struct to hold the relevant information for the query commands. +type QueryArgs struct { + // Module is the module name to query + Module string + // SubCommand is the subcommand to query + SubCommand string + // Args are the arguments to the query command + Args []string + // ChainID is the chain ID to query + ChainID string +} + +// Validate performs basic validation on the QueryArgs. +func (q QueryArgs) Validate() error { + if q.Module == "" { + return fmt.Errorf("module cannot be empty") + } + if q.SubCommand == "" { + return fmt.Errorf("subcommand cannot be empty") + } + if q.ChainID == "" { + return fmt.Errorf("chain ID cannot be empty") + } + return nil +} + +// CreateModuleQueryExec creates a Evmos module query. +func (m *Manager) CreateModuleQueryExec(args QueryArgs) (string, error) { + // Check that valid args were provided + if err := args.Validate(); err != nil { + return "", err + } + + // Build the query command + cmd := []string{ + "evmosd", + "q", + args.Module, + args.SubCommand, + } + + if len(args.Args) > 0 { + cmd = append(cmd, args.Args...) + } + + cmd = append(cmd, + fmt.Sprintf("--chain-id=%s", args.ChainID), + "--output=json", + ) + + return m.CreateExec(cmd, m.ContainerID()) +} diff --git a/tests/e2e/upgrade/utils.go b/tests/e2e/upgrade/utils.go new file mode 100644 index 0000000..7425e77 --- /dev/null +++ b/tests/e2e/upgrade/utils.go @@ -0,0 +1,129 @@ +// Copyright Tharsis Labs Ltd.(Evmos) +// SPDX-License-Identifier:ENCL-1.0(https://github.com/evmos/evmos/blob/main/LICENSE) + +package upgrade + +import ( + "fmt" + "os" + "os/exec" + "regexp" + "sort" + "strings" + + "github.com/hashicorp/go-version" +) + +// EvmosVersions is a custom comparator for sorting semver version strings. +type EvmosVersions []string + +// Len is the number of stored versions. +func (v EvmosVersions) Len() int { return len(v) } + +// Swap swaps the elements with indexes i and j. It is needed to sort the slice. +func (v EvmosVersions) Swap(i, j int) { v[i], v[j] = v[j], v[i] } + +// Less compares semver versions strings properly +func (v EvmosVersions) Less(i, j int) bool { + v1, err := version.NewVersion(v[i]) + if err != nil { + panic(fmt.Sprintf("couldn't interpret version as SemVer string: %s: %s", v[i], err.Error())) + } + + v2, err := version.NewVersion(v[j]) + if err != nil { + panic(fmt.Sprintf("couldn't interpret version as SemVer string: %s: %s", v[j], err.Error())) + } + + return v1.LessThan(v2) +} + +// ProposalVersion is an enum to represent the type of upgrade proposal to be used +// based on the Evmos version. +// +// This is required since the way to submit an upgrade proposal has changed between +// different SDK versions. +type ProposalVersion uint8 + +const ( + LegacyProposalPreV46 ProposalVersion = iota + LegacyProposalPreV50 + UpgradeProposalV50 +) + +// CheckUpgradeProposalVersion checks if the running node requires a legacy proposal +func CheckUpgradeProposalVersion(version string) ProposalVersion { + version = strings.TrimSpace(version) + if !strings.HasPrefix(version, "v") { + version = "v" + version + } + + // if version is lower than v10.x.x, then it's using SDK v0.46 + cmp := EvmosVersions([]string{version, "v10.0.0", "v20.0.0"}) + var proposalVersion ProposalVersion + switch { + case cmp.Less(0, 1): + proposalVersion = LegacyProposalPreV46 + case cmp.Less(0, 2): + proposalVersion = LegacyProposalPreV50 + default: + proposalVersion = UpgradeProposalV50 + } + + return proposalVersion +} + +// RetrieveUpgradesList parses the app/upgrades folder and returns a slice of semver upgrade versions +// in ascending order, e.g ["v1.0.0", "v1.0.1", "v1.1.0", ... , "v10.0.0"] +func RetrieveUpgradesList(upgradesPath string) ([]string, error) { + dirs, err := os.ReadDir(upgradesPath) + if err != nil { + return nil, err + } + + // preallocate slice to store versions + versions := make([]string, 0, len(dirs)) + + // pattern to find quoted string(upgrade version) in a file e.g. "v10.0.0" + pattern := regexp.MustCompile(`"(.*?)"`) + + for _, d := range dirs { + if !d.IsDir() { + continue + } + + // creating path to upgrade dir file with constant upgrade version + constantsPath := fmt.Sprintf("%s/%s/constants.go", upgradesPath, d.Name()) + if _, err = os.Stat(constantsPath); os.IsNotExist(err) { + continue + } + + f, err := os.ReadFile(constantsPath) + if err != nil { + return nil, err + } + + v := pattern.FindString(string(f)) + // v[1 : len(v)-1] subslice used to remove quotes from version string + versions = append(versions, v[1:len(v)-1]) + } + + sort.Sort(EvmosVersions(versions)) + + return versions, nil +} + +// ExportState executes the 'docker cp' command to copy container .evmosd dir +// to the specified target dir (local) +// +// See https://docs.docker.com/engine/reference/commandline/cp/ +func (m *Manager) ExportState(targetDir string) error { + /* #nosec G204 */ + cmd := exec.Command( + "docker", + "cp", + fmt.Sprintf("%s:/root/.evmosd", m.ContainerID()), + targetDir, + ) + return cmd.Run() +} diff --git a/tests/e2e/upgrade/utils_test.go b/tests/e2e/upgrade/utils_test.go new file mode 100644 index 0000000..73e3836 --- /dev/null +++ b/tests/e2e/upgrade/utils_test.go @@ -0,0 +1,107 @@ +// This file contains unit tests for the e2e package. +package upgrade + +import ( + "testing" + + "github.com/stretchr/testify/require" +) + +func TestCheckUpgradeProposalVersion(t *testing.T) { + testCases := []struct { + Name string + Ver string + Exp ProposalVersion + }{ + { + Name: "legacy proposal pre v0.47 - v10.0.1", + Ver: "v10.0.1", + Exp: LegacyProposalPreV50, + }, + { + Name: "normal proposal pre v0.46 - v9.1.0", + Ver: "v9.1.0", + Exp: LegacyProposalPreV46, + }, + { + Name: "normal proposal - version with whitespace - v9.1.0", + Ver: "\tv9.1.0 ", + Exp: LegacyProposalPreV46, + }, + { + Name: "normal proposal - version without v - 9.1.0", + Ver: "9.1.0", + Exp: LegacyProposalPreV46, + }, + { + Name: "SDK v0.50 proposal - version with whitespace - v20.0.0", + Ver: "\tv20.0.0 ", + Exp: UpgradeProposalV50, + }, + } + + for _, tc := range testCases { + t.Run(tc.Name, func(t *testing.T) { + legacyProposal := CheckUpgradeProposalVersion(tc.Ver) + require.Equal(t, tc.Exp, legacyProposal, "expected: %v, got: %v", tc.Exp, legacyProposal) + }) + } +} + +// TestEvmosVersionsLess tests the EvmosVersions type's Less method with +// different version strings +func TestEvmosVersionsLess(t *testing.T) { + var version EvmosVersions + + testCases := []struct { + Name string + Ver string + Exp bool + }{ + { + Name: "higher - v10.0.1", + Ver: "v10.0.1", + Exp: false, + }, + { + Name: "lower - v9.1.0", + Ver: "v9.1.0", + Exp: true, + }, + } + + for _, tc := range testCases { + t.Run(tc.Name, func(t *testing.T) { + version = []string{tc.Ver, "v10.0.0"} + require.Equal(t, version.Less(0, 1), tc.Exp, "expected: %v, got: %v", tc.Exp, version) + }) + } +} + +// TestEvmosVersionsSwap tests the EvmosVersions type's Swap method +func TestEvmosVersionsSwap(t *testing.T) { + var version EvmosVersions + value := "v9.1.0" + version = []string{value, "v10.0.0"} + version.Swap(0, 1) + require.Equal(t, value, version[1], "expected: %v, got: %v", value, version[1]) +} + +// TestEvmosVersionsLen tests the EvmosVersions type's Len method +func TestEvmosVersionsLen(t *testing.T) { + var version EvmosVersions = []string{"v9.1.0", "v10.0.0"} + require.Equal(t, 2, version.Len(), "expected: %v, got: %v", 2, version.Len()) +} + +// TestRetrieveUpgradesList tests if the list of available upgrades in the codebase +// can be correctly retrieved +func TestRetrieveUpgradesList(t *testing.T) { + upgradeList, err := RetrieveUpgradesList("../../../app/upgrades") + require.NoError(t, err, "expected no error while retrieving upgrade list") + require.NotEmpty(t, upgradeList, "expected upgrade list to be non-empty") + + // check if all entries in the list match a semantic versioning pattern + for _, upgrade := range upgradeList { + require.Regexp(t, `^v\d+\.\d+\.\d+(-rc\d+)*$`, upgrade, "expected upgrade version to be in semantic versioning format") + } +} From 4cc78539da3eb48ec0f1a49efebc6be7e563661b Mon Sep 17 00:00:00 2001 From: GuillemGarciaDev Date: Mon, 20 Jan 2025 13:04:38 +0100 Subject: [PATCH 02/25] fix(tests/e2e): remove e2e docker testsuite --- go.mod | 22 +- go.sum | 28 +- local-node.sh | 2 +- tests/e2e/README.md | 239 --------------- tests/e2e/e2e_suite_test.go | 333 -------------------- tests/e2e/e2e_test.go | 37 --- tests/e2e/init-node.sh | 164 ---------- tests/e2e/tx_test.go | 66 ---- tests/e2e/upgrade/Dockerfile.init | 15 - tests/e2e/upgrade/balances.go | 49 --- tests/e2e/upgrade/balances_test.go | 70 ----- tests/e2e/upgrade/constants.go | 24 -- tests/e2e/upgrade/exec.go | 38 --- tests/e2e/upgrade/govexec.go | 142 --------- tests/e2e/upgrade/manager.go | 468 ----------------------------- tests/e2e/upgrade/manager_test.go | 25 -- tests/e2e/upgrade/node.go | 63 ---- tests/e2e/upgrade/params.go | 152 ---------- tests/e2e/upgrade/params_test.go | 177 ----------- tests/e2e/upgrade/queryexec.go | 61 ---- tests/e2e/upgrade/utils.go | 129 -------- tests/e2e/upgrade/utils_test.go | 107 ------- 22 files changed, 3 insertions(+), 2408 deletions(-) delete mode 100644 tests/e2e/README.md delete mode 100644 tests/e2e/e2e_suite_test.go delete mode 100644 tests/e2e/e2e_test.go delete mode 100755 tests/e2e/init-node.sh delete mode 100644 tests/e2e/tx_test.go delete mode 100644 tests/e2e/upgrade/Dockerfile.init delete mode 100644 tests/e2e/upgrade/balances.go delete mode 100644 tests/e2e/upgrade/balances_test.go delete mode 100644 tests/e2e/upgrade/constants.go delete mode 100644 tests/e2e/upgrade/exec.go delete mode 100644 tests/e2e/upgrade/govexec.go delete mode 100644 tests/e2e/upgrade/manager.go delete mode 100644 tests/e2e/upgrade/manager_test.go delete mode 100644 tests/e2e/upgrade/node.go delete mode 100644 tests/e2e/upgrade/params.go delete mode 100644 tests/e2e/upgrade/params_test.go delete mode 100644 tests/e2e/upgrade/queryexec.go delete mode 100644 tests/e2e/upgrade/utils.go delete mode 100644 tests/e2e/upgrade/utils_test.go diff --git a/go.mod b/go.mod index bf59b9f..109650a 100644 --- a/go.mod +++ b/go.mod @@ -31,8 +31,6 @@ require ( github.com/gorilla/mux v1.8.1 github.com/grpc-ecosystem/grpc-gateway v1.16.0 github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.2 - github.com/hashicorp/go-version v1.7.0 - github.com/ory/dockertest/v3 v3.11.0 github.com/spf13/cast v1.7.0 github.com/spf13/cobra v1.8.1 github.com/spf13/pflag v1.0.5 @@ -55,15 +53,11 @@ require ( cosmossdk.io/depinject v1.0.0 // indirect cosmossdk.io/x/circuit v0.1.1 // indirect cosmossdk.io/x/tx v0.13.4 // indirect - dario.cat/mergo v1.0.0 // indirect filippo.io/edwards25519 v1.1.0 // indirect github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 // indirect github.com/99designs/keyring v1.2.2 // indirect - github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 // indirect github.com/DataDog/datadog-go v3.2.0+incompatible // indirect github.com/DataDog/zstd v1.5.5 // indirect - github.com/Microsoft/go-winio v0.6.2 // indirect - github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 // indirect github.com/PuerkitoBio/purell v1.1.1 // indirect github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect github.com/StackExchange/wmi v1.2.1 // indirect @@ -90,7 +84,6 @@ require ( github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06 // indirect github.com/coinbase/rosetta-sdk-go v0.7.9 // indirect github.com/cometbft/cometbft-db v0.14.1 // indirect - github.com/containerd/continuity v0.4.3 // indirect github.com/cosmos/btcutil v1.0.5 // indirect github.com/cosmos/go-bip39 v1.0.0 // indirect github.com/cosmos/gogogateway v1.2.0 // indirect @@ -112,10 +105,6 @@ require ( github.com/dgraph-io/badger/v4 v4.2.0 // indirect github.com/dgraph-io/ristretto v0.1.1 // indirect github.com/dlclark/regexp2 v1.7.0 // indirect - github.com/docker/cli v26.1.4+incompatible // indirect - github.com/docker/docker v27.1.1+incompatible // indirect - github.com/docker/go-connections v0.5.0 // indirect - github.com/docker/go-units v0.5.0 // indirect github.com/dop251/goja v0.0.0-20230122112309-96b1610dd4f7 // indirect github.com/dustin/go-humanize v1.0.1 // indirect github.com/dvsekhvalnov/jose2go v1.6.0 // indirect @@ -146,7 +135,6 @@ require ( github.com/google/go-cmp v0.6.0 // indirect github.com/google/orderedcode v0.0.1 // indirect github.com/google/s2a-go v0.1.7 // indirect - github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect github.com/google/uuid v1.6.0 // indirect github.com/googleapis/enterprise-certificate-proxy v0.3.2 // indirect github.com/googleapis/gax-go/v2 v2.12.5 // indirect @@ -162,6 +150,7 @@ require ( github.com/hashicorp/go-metrics v0.5.3 // indirect github.com/hashicorp/go-plugin v1.6.0 // indirect github.com/hashicorp/go-safetemp v1.0.0 // indirect + github.com/hashicorp/go-version v1.7.0 // indirect github.com/hashicorp/golang-lru v1.0.2 // indirect github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect github.com/hashicorp/hcl v1.0.0 // indirect @@ -192,16 +181,11 @@ require ( github.com/mitchellh/go-homedir v1.1.0 // indirect github.com/mitchellh/go-testing-interface v1.14.1 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect - github.com/moby/docker-image-spec v1.3.1 // indirect - github.com/moby/term v0.5.0 // indirect github.com/mtibben/percent v0.2.1 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/oasisprotocol/curve25519-voi v0.0.0-20230904125328-1f23a7beb09a // indirect github.com/oklog/run v1.1.0 // indirect github.com/olekukonko/tablewriter v0.0.5 // indirect - github.com/opencontainers/go-digest v1.0.0 // indirect - github.com/opencontainers/image-spec v1.1.0 // indirect - github.com/opencontainers/runc v1.1.13 // indirect github.com/pelletier/go-toml/v2 v2.2.2 // indirect github.com/petermattis/goid v0.0.0-20240813172612-4fcff4a6cae7 // indirect github.com/pkg/errors v0.9.1 // indirect @@ -221,7 +205,6 @@ require ( github.com/sagikazarmark/slog-shim v0.1.0 // indirect github.com/sasha-s/go-deadlock v0.3.5 // indirect github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible // indirect - github.com/sirupsen/logrus v1.9.3 // indirect github.com/sourcegraph/conc v0.3.0 // indirect github.com/spf13/afero v1.11.0 // indirect github.com/spf13/viper v1.19.0 // indirect @@ -240,9 +223,6 @@ require ( github.com/tklauser/numcpus v0.6.0 // indirect github.com/tyler-smith/go-bip39 v1.1.0 // indirect github.com/ulikunitz/xz v0.5.11 // indirect - github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect - github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect - github.com/xeipuuv/gojsonschema v1.2.0 // indirect github.com/zbiljic/go-filelock v0.0.0-20170914061330-1dbf7103ab7d // indirect github.com/zondax/hid v0.9.2 // indirect github.com/zondax/ledger-go v0.14.3 // indirect diff --git a/go.sum b/go.sum index 95eb0ac..81e90c3 100644 --- a/go.sum +++ b/go.sum @@ -218,8 +218,6 @@ cosmossdk.io/x/tx v0.13.4 h1:Eg0PbJgeO0gM8p5wx6xa0fKR7hIV6+8lC56UrsvSo0Y= cosmossdk.io/x/tx v0.13.4/go.mod h1:BkFqrnGGgW50Y6cwTy+JvgAhiffbGEKW6KF9ufcDpvk= cosmossdk.io/x/upgrade v0.1.4 h1:/BWJim24QHoXde8Bc64/2BSEB6W4eTydq0X/2f8+g38= cosmossdk.io/x/upgrade v0.1.4/go.mod h1:9v0Aj+fs97O+Ztw+tG3/tp5JSlrmT7IcFhAebQHmOPo= -dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk= -dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= filippo.io/edwards25519 v1.0.0-rc.1/go.mod h1:N1IkdkCkiLB6tki+MYJoSx2JTY9NUlxZE7eHn5EwJns= filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= @@ -476,8 +474,6 @@ github.com/creachadair/tomledit v0.0.26 h1:MoDdgHIHZ5PctBVsAZDjxdxreWUEa9ObPKTRk github.com/creachadair/tomledit v0.0.26/go.mod h1:SJi1OxKpMyR141tq1lzsbPtIg3j8TeVPM/ZftfieD7o= github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= -github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY= -github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= github.com/crypto-org-chain/cronos/memiavl v0.0.5-0.20240722062311-8384cad72737 h1:9jyWTnpgelwEvTRFkRxDIn/WBuj8pO4WcWYLbh/fi2k= github.com/crypto-org-chain/cronos/memiavl v0.0.5-0.20240722062311-8384cad72737/go.mod h1:gHpd4PhJt1BpjfN3PfChzv+9olZ2yVKDoyiIhMk9VFQ= github.com/crypto-org-chain/cronos/store v0.0.5-0.20240722062311-8384cad72737 h1:KcTmL7lmVr306/7QiBFvgy6mVQuRTdYJc9dP21VuT5s= @@ -524,11 +520,7 @@ github.com/dlclark/regexp2 v1.7.0 h1:7lJfhqlPssTb1WQx4yvTHN0uElPEv52sbaECrAQxjAo github.com/dlclark/regexp2 v1.7.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= github.com/dnaeon/go-vcr v1.1.0/go.mod h1:M7tiix8f0r6mKKJ3Yq/kqU1OYf3MnfmBWVbPx/yU9ko= github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ= -github.com/docker/cli v26.1.4+incompatible h1:I8PHdc0MtxEADqYJZvhBrW9bo8gawKwwenxRM7/rLu8= -github.com/docker/cli v26.1.4+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= github.com/docker/docker v1.6.2/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= -github.com/docker/docker v27.1.1+incompatible h1:hO/M4MtV36kzKldqnA37IWhebRA+LnqqcqDja6kVaKY= -github.com/docker/docker v27.1.1+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c= github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc= github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= @@ -643,8 +635,6 @@ github.com/go-sourcemap/sourcemap v2.1.3+incompatible h1:W1iEw64niKVGogNgBN3ePyL github.com/go-sourcemap/sourcemap v2.1.3+incompatible/go.mod h1:F8jJfvm2KbVjc5NqelyYJmf/v5J0dwNLS2mL4sNA1Jg= github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= -github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y= -github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-stack/stack v1.8.1 h1:ntEHSVwIt7PNXNpgPmVfMrNhLtgjlmnZha2kOpuRiDw= github.com/go-stack/stack v1.8.1/go.mod h1:dcoOX6HbPZSZptuspn9bctJ+N/CnF5gGygcUP3XYfe4= @@ -775,8 +765,6 @@ github.com/google/pprof v0.0.0-20240827171923-fa2c70bbbfe5/go.mod h1:vavhavw2zAx github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/s2a-go v0.1.7 h1:60BLSyTrOV4/haCDW4zb1guZItoSq8foHCXrAnjBo/o= github.com/google/s2a-go v0.1.7/go.mod h1:50CgR4k1jNlWBu4UfS4AcfhVe1r6pdZPygJ3R8F0Qdw= -github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4= -github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= @@ -1055,10 +1043,6 @@ github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyua github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/pointerstructure v1.2.0 h1:O+i9nHnXS3l/9Wu7r4NrEdwA2VFTicjUEN1uBnDo34A= github.com/mitchellh/pointerstructure v1.2.0/go.mod h1:BRAsLI5zgXmw97Lf6s25bs8ohIXc3tViBH44KcwB2g4= -github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0= -github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo= -github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0= -github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= @@ -1131,8 +1115,6 @@ github.com/openzipkin/zipkin-go v0.2.1/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnh github.com/openzipkin/zipkin-go v0.2.2/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4= github.com/ory/dockertest v3.3.5+incompatible h1:iLLK6SQwIhcbrG783Dghaaa3WPzGc+4Emza6EbVUUGA= github.com/ory/dockertest v3.3.5+incompatible/go.mod h1:1vX4m9wsvi00u5bseYwXaSnhNrne+V0E6LAcBILJdPs= -github.com/ory/dockertest/v3 v3.11.0 h1:OiHcxKAvSDUwsEVh2BjxQQc/5EHz9n0va9awCtNGuyA= -github.com/ory/dockertest/v3 v3.11.0/go.mod h1:VIPxS1gwT9NpPOrfD3rACs8Y9Z7yhzO4SB194iUDnUI= github.com/pact-foundation/pact-go v1.0.4/go.mod h1:uExwJY4kCzNPcHRj+hCR/HBbOOIwwtUjcrb0b5/5kLM= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= @@ -1223,8 +1205,8 @@ github.com/rs/cors v1.11.1/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= github.com/rs/zerolog v1.33.0 h1:1cU2KZkvPxNyfgEmhHAz/1A9Bz+llsdYzklWFzgp0r8= github.com/rs/zerolog v1.33.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss= +github.com/russross/blackfriday v1.5.2 h1:HyvC0ARfnZBqnXwABFeSZHpKvJHJJfPz81GNueLj0oo= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= -github.com/russross/blackfriday v1.6.0 h1:KqfZb0pUVN2lYqZUYRddxF4OR8ZMURnJIG5Y3VRLtww= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= @@ -1361,13 +1343,6 @@ github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+ github.com/vmihailenco/msgpack/v5 v5.3.5/go.mod h1:7xyJ9e+0+9SaZT0Wt1RGleJXzli6Q/V5KbhBonMG9jc= github.com/vmihailenco/tagparser/v2 v2.0.0/go.mod h1:Wri+At7QHww0WTrCBeu4J6bNtoV6mEfg5OIWRZA9qds= github.com/willf/bitset v1.1.3/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4= -github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= -github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo= -github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= -github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0= -github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= -github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74= -github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xlab/treeprint v0.0.0-20180616005107-d6fb6747feb6/go.mod h1:ce1O1j6UtZfjr22oyGxGLbauSBp2YVXpARAosm7dHBg= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= @@ -1718,7 +1693,6 @@ golang.org/x/sys v0.0.0-20220610221304-9f5ed59c137d/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220615213510-4f61da869c0c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220624220833-87e55d714810/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= diff --git a/local-node.sh b/local-node.sh index 3144a7b..4fdec5c 100755 --- a/local-node.sh +++ b/local-node.sh @@ -42,7 +42,7 @@ jq '.app_state["evm"]["params"]["evm_denom"]="token"' "$GENESIS" >"$TMP_GENESIS" jq '.app_state["evm"]["params"]["allow_unprotected_txs"]=true' "$GENESIS" >"$TMP_GENESIS" && mv "$TMP_GENESIS" "$GENESIS" jq '.app_state["gov"]["params"]["min_deposit"][0]["denom"]="token"' "$GENESIS" >"$TMP_GENESIS" && mv "$TMP_GENESIS" "$GENESIS" jq '.app_state["gov"]["params"]["min_deposit"][0]["amount"]="1"' "$GENESIS" >"$TMP_GENESIS" && mv "$TMP_GENESIS" "$GENESIS" -jq '.app_state["gov"]["params"]["voting_period"]="10s"' "$GENESIS" >"$TMP_GENESIS" && mv "$TMP_GENESIS" "$GENESIS" +jq '.app_state["gov"]["params"]["voting_period"]="60s"' "$GENESIS" >"$TMP_GENESIS" && mv "$TMP_GENESIS" "$GENESIS" jq '.app_state["gov"]["params"]["expedited_voting_period"]="5s"' "$GENESIS" >"$TMP_GENESIS" && mv "$TMP_GENESIS" "$GENESIS" jq '.app_state["staking"]["params"]["bond_denom"]="apoa"' "$GENESIS" >"$TMP_GENESIS" && mv "$TMP_GENESIS" "$GENESIS" jq '.app_state["staking"]["params"]["unbonding_time"]="60s"' "$GENESIS" >"$TMP_GENESIS" && mv "$TMP_GENESIS" "$GENESIS" diff --git a/tests/e2e/README.md b/tests/e2e/README.md deleted file mode 100644 index 5b8f4bc..0000000 --- a/tests/e2e/README.md +++ /dev/null @@ -1,239 +0,0 @@ -# End-to-End Testing Suite - -The End-to-End (E2E) testing suite provides an environment -for running end-to-end tests on Evmos. -It is used for testing chain upgrades, -as it allows for initializing multiple Evmos chains with different versions. - -- [End-to-End Testing Suite](#end-to-end-testing-suite) - - [Quick Start](#quick-start) - - [Upgrade Process](#upgrade-process) - - [Test Suite Structure](#test-suite-structure) - - [`e2e` Package](#e2e-package) - - [`upgrade` Package](#upgrade-package) - - [Version retrieve](#version-retrieve) - - [Testing Results](#testing-results) - - [Running multiple upgrades](#running-multiple-upgrades) - -### Quick Start - -To run the e2e tests, execute: - -```shell -make test-e2e -``` - -This command runs an upgrade test (upgrading a node from an old version to a newer one), -as well as query and transactions operations against a node with the latest changes. - -This logic utilizes parameters that can be set manually(if necessary): - -```shell -# flag to skip containers cleanup after upgrade -# should be set true with make test-e2e command if you need access to the node -# after upgrading -E2E_SKIP_CLEANUP := false - -# version(s) of initial evmos node(s) that will be upgraded, tag e.g. 'v9.1.0' -# to use multiple upgrades separate the versions with a forward slash, e.g. -# 'v10.0.1/v11.0.0-rc1' -INITIAL_VERSION - -# version of upgraded evmos node that will replace the initial node, tag e.g. -# 'v10.0.0' -TARGET_VERSION - -# mount point for the upgraded node container, to mount new node version to -# previous node state folder. By default this is './build/.evmosd:/root/.evmosd' -# More info at https://docs.docker.com/engine/reference/builder/#volume -MOUNT_PATH - -# '--chain-id' evmos cli parameter, used to start nodes with a specific -# chain-id and submit proposals -# By default this is 'evmos_9000-1' -CHAIN_ID -``` - -To test an upgrade to explicit target version -and continue to run the upgraded node, use: - -```shell -make test-e2e E2E_SKIP_CLEANUP=true INITIAL_VERSION= TARGET_VERSION= -``` - -### Upgrade Process - -Testing a chain upgrade is a multi-step process: - -1. Build a docker image for the evmos target version -(local repo by default, if no explicit `TARGET_VERSION` provided as argument) -(e.g. `v10.0.0`) -2. Run tests -3. The e2e test will first run an `INITIAL_VERSION` node container. -4. The node will submit, deposit and vote for an upgrade proposal -for upgrading to the `TARGET_VERSION`. -5. After block `50` is reached, -the test suite exports `/.evmosd` folder from the docker container -to the local `build/` folder and then purges the container. -6. Suite will mount the node with `TARGET_VERSION` -to the local `build/` dir and start the node. -The node will get upgrade information from `upgrade-info.json` -and will execute the upgrade. - -## Test Suite Structure - -### `e2e` Package - -The `e2e` package defines an integration testing suite -used for full end-to-end testing functionality. -This package is decoupled from depending on the Evmos codebase. -It initializes the chains for testing via Docker. -As a result, the test suite may provide the -desired Evmos version to Docker containers during the initialization. -This design allows for the opportunity of testing chain upgrades -by providing an older Evmos version to the container, -performing the chain upgrade, -and running the latest test suite. -Here's an overview of the files: - -* `e2e_suite_test.go`: defines the testing suite -and contains the core bootstrapping logic -that creates a testing environment via Docker containers. -A testing network is created dynamically with 2 test validators. - -* `e2e_test.go`: contains the actual end-to-end integration tests -that utilize the testing suite. - -* `e2e_utils_test.go`: contains suite upgrade params loading logic. - -### `upgrade` Package - -The `e2e` package defines an upgrade `Manager` abstraction. -Suite will utilize `Manager`'s functions -to run different versions of evmos containers, -propose, vote, delegate and query nodes. - -* `manager.go`: defines core manager logic for running containers, -export state and create networks. - -* `govexec.go`: defines `gov-specific` exec commands to submit/delegate/vote -through nodes `gov` module. - -* `node.go`: defines `Node` structure -responsible for setting node container parameters before run. - -### Version retrieve - -If `INITIAL_VERSION` is provided as an argument, -node container(s) with the corresponding version(s) -will be pulled from [DockerHub](https://hub.docker.com/r/tharsishq/evmos/tags). -If it is not specified, -the test suite retrieves the second-to-last upgrade version -from the local codebase (in the `evmos/app/upgrades` folder) -according to [Semantic Versioning](https://semver.org/). - -If `TARGET_VERSION` is specified, -the corresponding container will also be pulled from DockerHub. -When not specified, the test suite will retrieve the latest upgrade version -from `evmos/app/upgrades`. - -### Testing Results - -The `make test-e2e` script will output the test results -for each testing file. -In case of a successful upgrade, -the script will print the following output (example): - -```log -ok github.com/evmos/evmos/v9/tests/e2e 174.137s. -``` - -If the target node version fails to start, -the logs from the docker container will be printed: - -```log -Error: Received unexpected error: - can't start evmos node, container exit code: 2 - - [error stream]: - - 7:03AM INF Unlocking keyring - 7:03AM INF starting ABCI with Tendermint - panic: invalid minimum gas prices: invalid decimal coin expression: 0... - - goroutine 1 [running]: - github.com/cosmos/cosmos-sdk/baseapp.SetMinGasPrices({0xc0013563e7?, ... - github.com/cosmos/cosmos-sdk@v0.46.5/baseapp/options.go:29 +0xd9 - main.appCreator.newApp({{{0x3399b40, 0xc000ec1db8}, {0x33ac0f8, 0xc00... - github.com/evmos/evmos/v10/cmd/evmosd/root.go:243 +0x2ca - github.com/evmos/ethermint/server.startInProcess(_, {{0x0, 0x0, 0x0},... - github.com/evmos/ethermint@v0.20.0-rc2/server/start.go:304 +0x9c5 - github.com/evmos/ethermint/server.StartCmd.func2(0xc001620600?, {0xc0... - github.com/evmos/ethermint@v0.20.0-rc2/server/start.go:123 +0x1ec - github.com/spf13/cobra.(*Command).execute(0xc001620600, {0xc001745bb0... - github.com/spf13/cobra@v1.6.1/command.go:916 +0x862 - github.com/spf13/cobra.(*Command).ExecuteC(0xc00160e000) - github.com/spf13/cobra@v1.6.1/command.go:1044 +0x3bd - github.com/spf13/cobra.(*Command).Execute(...) - github.com/spf13/cobra@v1.6.1/command.go:968 - github.com/spf13/cobra.(*Command).ExecuteContext(...) - github.com/spf13/cobra@v1.6.1/command.go:961 - github.com/cosmos/cosmos-sdk/server/cmd.Execute(0x2170d50?, {0x26d961... - github.com/cosmos/cosmos-sdk@v0.46.5/server/cmd/execute.go:36 +0x... - main.main() - github.com/evmos/evmos/v10/cmd/evmosd/main.go:20 +0x45 - - - [output stream]: - -Test: TestIntegrationTestSuite/TestUpgrade -Messages: can't mount and run upgraded node container -``` - -To get all containers run: - -```shell -# list containers -docker ps -a -``` - -Container names will be listed as follows: - -```log -CONTAINER ID IMAGE -9307f5485323 evmos:local <-- upgraded node -f41c97d6ca21 evmos:v9.0.0 <-- initial node -``` - -To access containers logs directly, run: - -```shell -docker logs -``` - -To interact with the upgraded node -pass `SKIP_CLEANUP=true` to the make command -and enter the container after the upgrade has finished: - -```shell -docker exec -it bash -``` - -If the cleanup was skipped -the upgraded node container should be removed manually: - -```shell -docker kill -docker rm -``` - -## Running multiple upgrades - -In order to run multiple upgrades, -just combine the versions leading up to the last upgrade -with a forward slash -and pass them as the `INITIAL_VERSION`. - -```bash -make test-e2e INITIAL_VERSION=v10.0.1/v11.0.0-rc1 TARGET_VERSION=v11.0.0-rc3 -``` diff --git a/tests/e2e/e2e_suite_test.go b/tests/e2e/e2e_suite_test.go deleted file mode 100644 index aca75a5..0000000 --- a/tests/e2e/e2e_suite_test.go +++ /dev/null @@ -1,333 +0,0 @@ -package e2e - -import ( - "context" - "errors" - "fmt" - "os" - "strings" - "testing" - - "github.com/cosmos/cosmos-sdk/codec" - govtypes "github.com/cosmos/cosmos-sdk/x/gov/types/v1" - "github.com/evmos/evmos/v20/testutil/integration/evmos/network" - "github.com/evmos/evmos/v20/utils" - "github.com/stretchr/testify/suite" - "github.com/xrplevm/node/v5/tests/e2e/upgrade" -) - -const ( - // defaultManagerNetwork defines the network used by the upgrade manager - defaultManagerNetwork = "evmos-local" - - // blocksAfterUpgrade defines how many blocks must be produced after an upgrade is - // considered successful - blocksAfterUpgrade = 5 - - // relatedBuildPath defines the path where the build data is stored - relatedBuildPath = "../../build/" - - // upgradePath defines the relative path from this folder to the upgrade folder - upgradePath = "../../app/upgrades" - - // registryDockerFile builds the image using the docker image registry - registryDockerFile = "./upgrade/Dockerfile.init" -) - -type IntegrationTestSuite struct { - suite.Suite - - upgradeManager *upgrade.Manager - upgradeParams upgrade.Params -} - -func TestIntegrationTestSuite(t *testing.T) { - suite.Run(t, new(IntegrationTestSuite)) -} - -func (s *IntegrationTestSuite) SetupSuite() { - s.T().Log("setting up e2e integration test suite...") - var err error - - s.upgradeParams, err = upgrade.LoadUpgradeParams(upgradePath) - s.Require().NoError(err, "can't load upgrade params") - - s.upgradeManager, err = upgrade.NewManager(defaultManagerNetwork) - s.Require().NoError(err, "upgrade manager creation error") - if _, err := os.Stat(relatedBuildPath); errors.Is(err, os.ErrNotExist) { - err := os.Mkdir(relatedBuildPath, os.ModePerm) - s.Require().NoError(err, "can't create build tmp dir") - } -} - -// runInitialNode builds a docker image capable of running an Evmos node with the given version. -// After a successful build, it runs the container and checks if the node can produce blocks. -func (s *IntegrationTestSuite) runInitialNode(version upgrade.VersionConfig) { - err := s.upgradeManager.BuildImage( - version.ImageName, - version.ImageTag, - registryDockerFile, - ".", - map[string]string{"INITIAL_VERSION": version.ImageTag}, - ) - s.Require().NoError(err, "can't build container with Evmos version: %s", version.ImageTag) - - node := upgrade.NewNode(version.ImageName, version.ImageTag) - node.SetEnvVars([]string{fmt.Sprintf("CHAIN_ID=%s", s.upgradeParams.ChainID)}) - - err = s.upgradeManager.RunNode(node) - s.Require().NoError(err, "can't run node with Evmos version: %s", version) - - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - - // wait until node starts and produce some blocks - _, err = s.upgradeManager.WaitForHeight(ctx, s.upgradeManager.HeightBeforeStop+5) - s.Require().NoError(err) - - s.T().Logf("successfully started node with version: [%s]", version.ImageTag) -} - -// proposeUpgrade submits an upgrade proposal to the chain that schedules an upgrade to -// the given target version. -func (s *IntegrationTestSuite) proposeUpgrade(name, target string) { - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - - // calculate upgrade height for the proposal - upgradeHeight, err := s.upgradeManager.GetUpgradeHeight(ctx, s.upgradeParams.ChainID) - s.Require().NoError(err, "can't get upgrade height") - s.upgradeManager.UpgradeHeight = upgradeHeight - - // if Evmos is lower than v10.x.x no need to use the legacy proposal - currentVersion, err := s.upgradeManager.GetNodeVersion(ctx) - s.Require().NoError(err, "can't get current Evmos version") - proposalVersion := upgrade.CheckUpgradeProposalVersion(currentVersion) - - // create the proposal - exec, err := s.upgradeManager.CreateSubmitProposalExec( - name, - s.upgradeParams.ChainID, - s.upgradeManager.UpgradeHeight, - proposalVersion, - "--fees=10000000000000000aevmos", - "--gas=500000", - ) - s.Require().NoErrorf( - err, - "can't create the proposal to upgrade Evmos to %s at height %d with name %s", - target, s.upgradeManager.UpgradeHeight, name, - ) - - outBuf, errBuf, err := s.upgradeManager.RunExec(ctx, exec) - s.Require().NoErrorf( - err, - "failed to submit proposal to upgrade Evmos to %s at height %d\nstdout: %s,\nstderr: %s", - target, s.upgradeManager.UpgradeHeight, outBuf.String(), errBuf.String(), - ) - - s.Require().Truef( - strings.Contains(outBuf.String(), "code: 0"), - "tx returned non code 0:\nstdout: %s\nstderr: %s", outBuf.String(), errBuf.String(), - ) - - s.T().Logf( - "successfully submitted upgrade proposal: height: %d, name: %s", - s.upgradeManager.UpgradeHeight, - name, - ) -} - -// voteForProposal votes for the upgrade proposal with the given id. -func (s *IntegrationTestSuite) voteForProposal(id int) { - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - exec, err := s.upgradeManager.CreateVoteProposalExec(s.upgradeParams.ChainID, id, "--fees=10000000000000000aevmos", "--gas=500000") - s.Require().NoError(err, "can't create vote for proposal exec") - outBuf, errBuf, err := s.upgradeManager.RunExec(ctx, exec) - s.Require().NoErrorf( - err, - "failed to vote for proposal tx;\nstdout: %s,\nstderr: %s", outBuf.String(), errBuf.String(), - ) - - s.Require().Truef( - strings.Contains(outBuf.String(), "code: 0"), - "tx returned non code 0:\nstdout: %s\nstderr: %s", outBuf.String(), errBuf.String(), - ) - - s.T().Logf("successfully voted for upgrade proposal") -} - -// upgrade upgrades the node to the given version using the given repo. The repository -// can either be a local path or a remote repository. -func (s *IntegrationTestSuite) upgrade(targetVersion upgrade.VersionConfig) { - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - - s.T().Logf("wait for node to reach upgrade height %d...", s.upgradeManager.UpgradeHeight) - // wait for proposed upgrade height - _, err := s.upgradeManager.WaitForHeight(ctx, int(s.upgradeManager.UpgradeHeight)) //#nosec G115 - s.Require().NoError(err, "can't reach upgrade height") - dirs := strings.Split(s.upgradeParams.MountPath, ":") - buildDir := dirs[0] - rootDir := dirs[1] - - // check that the proposal has passed before stopping the node - s.checkProposalPassed(ctx) - - s.T().Log("exporting state to local...") - // export node .evmosd to local build/ - err = s.upgradeManager.ExportState(buildDir) - s.Require().NoError(err, "can't export node container state to local") - - s.T().Log("killing node before upgrade...") - err = s.upgradeManager.KillCurrentNode() - s.Require().NoError(err, "can't kill current node") - - s.T().Logf("starting upgraded node with version: [%s]", targetVersion) - - // NOTE: after the upgrade, the current version needs to be updated to make sure that the correct CLI commands - // for the given version are used. - // - // this is e.g. relevant for retrieving the current node height from the block header - if targetVersion.ImageTag == upgrade.LocalVersionTag { - // NOTE: the upgrade name is the latest version from the app/upgrades folder to upgrade to - s.upgradeManager.CurrentVersion = targetVersion.UpgradeName - } else { - s.upgradeManager.CurrentVersion = targetVersion.ImageTag - } - - node := upgrade.NewNode(targetVersion.ImageName, targetVersion.ImageTag) - node.Mount(s.upgradeParams.MountPath) - node.SetCmd([]string{"evmosd", "start", fmt.Sprintf("--chain-id=%s", s.upgradeParams.ChainID), fmt.Sprintf("--home=%s.evmosd", rootDir)}) - err = s.upgradeManager.RunNode(node) - s.Require().NoError(err, "can't mount and run upgraded node container") - - s.T().Logf("node started! waiting for node to produce %d blocks", blocksAfterUpgrade) - - s.T().Log("executing all module queries") - s.executeQueries() - - s.T().Log("executing sample transactions") - s.executeTransactions() - - // make sure node produce blocks after upgrade - s.T().Logf("height to wait for is %d", int(s.upgradeManager.UpgradeHeight)+blocksAfterUpgrade) // #nosec G115 - // make sure node produces blocks after upgrade - errLogs, err := s.upgradeManager.WaitForHeight(ctx, int(s.upgradeManager.UpgradeHeight)+blocksAfterUpgrade) // #nosec G115 - if err == nil && errLogs != "" { - s.T().Logf( - "even though the node is producing blocks, there are error messages contained in the logs:\n%s", - errLogs, - ) - } - s.Require().NoError(err, "node does not produce blocks after upgrade") - - if targetVersion.ImageTag != upgrade.LocalVersionTag { - s.T().Log("checking node version...") - version, err := s.upgradeManager.GetNodeVersion(ctx) - s.Require().NoError(err, "can't get node version") - - version = strings.TrimSpace(version) - targetVersion.ImageTag = strings.TrimPrefix(targetVersion.ImageTag, "v") - s.Require().Equal(targetVersion, version, - "unexpected node version after upgrade:\nexpected: %s\nactual: %s", - targetVersion, version, - ) - s.T().Logf("node version is correct: %s", version) - } -} - -// checkProposalPassed queries the (most recent) upgrade proposal and checks that it has passed. -// -// NOTE: This was a problem in the past, where the upgrade height was reached before the proposal actually passed. -// This is a safety check to make sure this doesn't happen again, as this was not obvious from the log output. -func (s *IntegrationTestSuite) checkProposalPassed(ctx context.Context) { - exec, err := s.upgradeManager.CreateModuleQueryExec(upgrade.QueryArgs{ - Module: "gov", - SubCommand: "proposals", - ChainID: s.upgradeParams.ChainID, - }) - s.Require().NoError(err, "can't create query proposals exec") - - outBuf, errBuf, err := s.upgradeManager.RunExec(ctx, exec) - s.Require().NoErrorf( - err, - "failed to query proposals;\nstdout: %s,\nstderr: %s", outBuf.String(), errBuf.String(), - ) - - nw := network.New() - encodingConfig := nw.GetEncodingConfig() - protoCodec, ok := encodingConfig.Codec.(*codec.ProtoCodec) - s.Require().True(ok, "encoding config codec is not a proto codec") - - var proposalsRes govtypes.QueryProposalsResponse - err = protoCodec.UnmarshalJSON(outBuf.Bytes(), &proposalsRes) - s.Require().NoError(err, "can't unmarshal proposals response\n%s", outBuf.String()) - s.Require().GreaterOrEqual(len(proposalsRes.Proposals), 1, "no proposals found") - - // check that the most recent proposal has passed - proposal := proposalsRes.Proposals[len(proposalsRes.Proposals)-1] - s.Require().Equal(govtypes.ProposalStatus_PROPOSAL_STATUS_PASSED.String(), proposal.Status.String(), "expected proposal to have passed already") -} - -// executeQueries executes all the module queries to check they are still working after the upgrade. -func (s *IntegrationTestSuite) executeQueries() { - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - - chainID := utils.TestnetChainID + "-1" - testCases := []struct { - name string - moduleName string - subCommand string - }{ - {"inflation: params", "inflation", "params"}, - {"inflation: circulating-supply", "inflation", "circulating-supply"}, - {"inflation: inflation-rate", "inflation", "inflation-rate"}, - {"inflation: period", "inflation", "period"}, - {"inflation: skipped-epochs", "inflation", "skipped-epochs"}, - {"inflation: epoch-mint-provision", "inflation", "epoch-mint-provision"}, - {"erc20: params", "erc20", "params"}, - {"erc20: token-pairs", "erc20", "token-pairs"}, - {"evm: params", "evm", "params"}, - {"feemarket: params", "feemarket", "params"}, - {"feemarket: base-fee", "feemarket", "base-fee"}, - {"feemarket: block-gas", "feemarket", "block-gas"}, - {"feemarket: block-gas", "feemarket", "block-gas"}, - } - - for _, tc := range testCases { - s.T().Logf("executing %s", tc.name) - exec, err := s.upgradeManager.CreateModuleQueryExec(upgrade.QueryArgs{ - Module: tc.moduleName, - SubCommand: tc.subCommand, - ChainID: chainID, - }) - s.Require().NoError(err) - - _, errBuf, err := s.upgradeManager.RunExec(ctx, exec) - s.Require().NoError(err) - s.Require().Empty(errBuf.String()) - } - s.T().Logf("executed all queries successfully") -} - -// TearDownSuite kills the running container, removes the network and mount path -func (s *IntegrationTestSuite) TearDownSuite() { - if s.upgradeParams.SkipCleanup { - s.T().Logf("skipping cleanup... container %s will be left running", s.upgradeManager.ContainerID()) - return - } - - s.T().Log("tearing down e2e integration test suite...") - s.T().Log("killing node...") - err := s.upgradeManager.KillCurrentNode() - s.Require().NoError(err, "can't kill current node") - - s.T().Log("removing network...") - s.Require().NoError(s.upgradeManager.RemoveNetwork(), "can't remove network") - - s.T().Log("removing mount path...") - s.Require().NoError(os.RemoveAll(strings.Split(s.upgradeParams.MountPath, ":")[0]), "can't remove mount path") -} diff --git a/tests/e2e/e2e_test.go b/tests/e2e/e2e_test.go deleted file mode 100644 index 5c5f93c..0000000 --- a/tests/e2e/e2e_test.go +++ /dev/null @@ -1,37 +0,0 @@ -package e2e - -import ( - "context" -) - -// TestUpgrade tests if an Evmos node can be upgraded from one version to another. -// It iterates through the list of scheduled upgrades, that are defined using the input -// arguments to the make command. The function then submits a proposal to upgrade the chain, -// and finally upgrades the chain. -// If the chain can be restarted after the upgrade(s), the test passes. -func (s *IntegrationTestSuite) TestUpgrade() { - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - - // NOTE: we initialize the current version, which is then updated in the upgrade function - s.upgradeManager.CurrentVersion = s.upgradeParams.Versions[0].ImageTag - for idx, version := range s.upgradeParams.Versions { - if idx == 0 { - // start initial node - s.runInitialNode(version) - continue - } - - // wait one block to execute the txs - err := s.upgradeManager.WaitNBlocks(ctx, 1) - s.Require().NoError(err) - s.T().Logf("(upgrade %d): UPGRADING TO %s WITH PROPOSAL NAME %s", idx, version.ImageTag, version.UpgradeName) - s.proposeUpgrade(version.UpgradeName, version.ImageTag) - - s.Require().NoError(s.upgradeManager.WaitNBlocks(ctx, 1), "failed to wait for block") - - s.voteForProposal(idx) - s.upgrade(version) - } - s.T().Logf("SUCCESS") -} diff --git a/tests/e2e/init-node.sh b/tests/e2e/init-node.sh deleted file mode 100755 index a5e252c..0000000 --- a/tests/e2e/init-node.sh +++ /dev/null @@ -1,164 +0,0 @@ -#!/bin/bash - -CHAINID="${CHAIN_ID:-evmos_9000-1}" -MONIKER="localtestnet" -KEYRING="test" # remember to change to other types of keyring like 'file' in-case exposing to outside world, otherwise your balance will be wiped quickly. The keyring test does not require private key to steal tokens from you -KEYALGO="eth_secp256k1" #gitleaks:allow -LOGLEVEL="info" -# to trace evm -#TRACE="--trace" -TRACE="" -PRUNING="default" -#PRUNING="custom" - -CHAINDIR="$HOME/.evmosd" -GENESIS="$CHAINDIR/config/genesis.json" -TMP_GENESIS="$CHAINDIR/config/tmp_genesis.json" -APP_TOML="$CHAINDIR/config/app.toml" -CONFIG_TOML="$CHAINDIR/config/config.toml" - -# feemarket params basefee -BASEFEE=1000000000 - -# myKey address 0x7cb61d4117ae31a12e393a1cfa3bac666481d02e -VAL_KEY="mykey" -VAL_MNEMONIC="gesture inject test cycle original hollow east ridge hen combine junk child bacon zero hope comfort vacuum milk pitch cage oppose unhappy lunar seat" - -# user1 address 0xc6fe5d33615a1c52c08018c47e8bc53646a0e101 -USER1_KEY="user1" -USER1_MNEMONIC="copper push brief egg scan entry inform record adjust fossil boss egg comic alien upon aspect dry avoid interest fury window hint race symptom" - -# user2 address 0x963ebdf2e1f8db8707d05fc75bfeffba1b5bac17 -USER2_KEY="user2" -USER2_MNEMONIC="maximum display century economy unlock van census kite error heart snow filter midnight usage egg venture cash kick motor survey drastic edge muffin visual" - -# user3 address 0x40a0cb1C63e026A81B55EE1308586E21eec1eFa9 -USER3_KEY="user3" -USER3_MNEMONIC="will wear settle write dance topic tape sea glory hotel oppose rebel client problem era video gossip glide during yard balance cancel file rose" - -# user4 address 0x498B5AeC5D439b733dC2F58AB489783A23FB26dA -USER4_KEY="user4" -USER4_MNEMONIC="doll midnight silk carpet brush boring pluck office gown inquiry duck chief aim exit gain never tennis crime fragile ship cloud surface exotic patch" - -# validate dependencies are installed -command -v jq >/dev/null 2>&1 || { - echo >&2 "jq not installed. More info: https://stedolan.github.io/jq/download/" - exit 1 -} - -# used to exit on first error (any non-zero exit code) -set -e - -# Check evmosd version to decide how to set the client configuration -# the older versions of evmosd accept less arguments -sdk_version=$(evmosd version --long | grep 'cosmos_sdk_version' | awk '{print $2}') -if [[ $sdk_version == *v0.4* ]]; then - evmosd config chain-id "$CHAINID" - evmosd config keyring-backend "$KEYRING" -else - evmosd config set client chain-id "$CHAINID" - evmosd config set client keyring-backend "$KEYRING" -fi - -# Import keys from mnemonics -echo "$VAL_MNEMONIC" | evmosd keys add "$VAL_KEY" --recover --keyring-backend "$KEYRING" --algo "$KEYALGO" - -echo "$USER1_MNEMONIC" | evmosd keys add "$USER1_KEY" --recover --keyring-backend "$KEYRING" --algo "$KEYALGO" -echo "$USER2_MNEMONIC" | evmosd keys add "$USER2_KEY" --recover --keyring-backend "$KEYRING" --algo "$KEYALGO" -echo "$USER3_MNEMONIC" | evmosd keys add "$USER3_KEY" --recover --keyring-backend "$KEYRING" --algo "$KEYALGO" -echo "$USER4_MNEMONIC" | evmosd keys add "$USER4_KEY" --recover --keyring-backend "$KEYRING" --algo "$KEYALGO" - -# Set moniker and chain-id for Evmos (Moniker can be anything, chain-id must be an integer) -evmosd init "$MONIKER" --chain-id "$CHAINID" - -# Change parameter token denominations to aevmos -jq '.app_state["staking"]["params"]["bond_denom"]="aevmos"' "$GENESIS" >"$TMP_GENESIS" && mv "$TMP_GENESIS" "$GENESIS" -jq '.app_state["gov"]["deposit_params"]["min_deposit"][0]["denom"]="aevmos"' "$GENESIS" >"$TMP_GENESIS" && mv "$TMP_GENESIS" "$GENESIS" -# When upgrade to cosmos-sdk v0.47, use gov.params to edit the deposit params -jq '.app_state["gov"]["params"]["min_deposit"][0]["denom"]="aevmos"' "$GENESIS" >"$TMP_GENESIS" && mv "$TMP_GENESIS" "$GENESIS" -jq '.app_state["evm"]["params"]["evm_denom"]="aevmos"' "$GENESIS" >"$TMP_GENESIS" && mv "$TMP_GENESIS" "$GENESIS" -jq '.app_state["inflation"]["params"]["mint_denom"]="aevmos"' "$GENESIS" >"$TMP_GENESIS" && mv "$TMP_GENESIS" "$GENESIS" - -# set gov proposing && voting period -jq '.app_state.gov.deposit_params.max_deposit_period="10s"' "$GENESIS" >"$TMP_GENESIS" && mv "$TMP_GENESIS" "$GENESIS" -jq '.app_state.gov.voting_params.voting_period="10s"' "$GENESIS" >"$TMP_GENESIS" && mv "$TMP_GENESIS" "$GENESIS" -sed -i.bak 's/"expedited_voting_period": "86400s"/"expedited_voting_period": "5s"/g' "$GENESIS" - -# When upgrade to cosmos-sdk v0.47, use gov.params to edit the deposit params -# check if the 'params' field exists in the genesis file -if jq '.app_state.gov.params != null' "$GENESIS" | grep -q "true"; then - jq '.app_state.gov.params.min_deposit[0].denom="aevmos"' "$GENESIS" >"$TMP_GENESIS" && mv "$TMP_GENESIS" "$GENESIS" - jq '.app_state.gov.params.max_deposit_period="10s"' "$GENESIS" >"$TMP_GENESIS" && mv "$TMP_GENESIS" "$GENESIS" - jq '.app_state.gov.params.voting_period="10s"' "$GENESIS" >"$TMP_GENESIS" && mv "$TMP_GENESIS" "$GENESIS" -fi - -# Set gas limit in genesis -jq '.consensus_params.block.max_gas="10000000"' "$GENESIS" >"$TMP_GENESIS" && mv "$TMP_GENESIS" "$GENESIS" - -# Set claims start time -current_date=$(date -u +"%Y-%m-%dT%TZ") -jq -r --arg current_date "$current_date" '.app_state.claims.params.airdrop_start_time=$current_date' "$GENESIS" >"$TMP_GENESIS" && mv "$TMP_GENESIS" "$GENESIS" - -# Set base fee in genesis -jq '.app_state["feemarket"]["params"]["base_fee"]="'${BASEFEE}'"' "$GENESIS" >"$TMP_GENESIS" && mv "$TMP_GENESIS" "$GENESIS" - -# disable produce empty block -sed -i.bak 's/create_empty_blocks = true/create_empty_blocks = false/g' "$CONFIG_TOML" - -# Allocate genesis accounts (cosmos formatted addresses) -evmosd add-genesis-account "$(evmosd keys show "$VAL_KEY" -a --keyring-backend "$KEYRING")" 100000000000000000000000000aevmos --keyring-backend "$KEYRING" -evmosd add-genesis-account "$(evmosd keys show "$USER1_KEY" -a --keyring-backend "$KEYRING")" 1000000000000000000000aevmos --keyring-backend "$KEYRING" -evmosd add-genesis-account "$(evmosd keys show "$USER2_KEY" -a --keyring-backend "$KEYRING")" 1000000000000000000000aevmos --keyring-backend "$KEYRING" -evmosd add-genesis-account "$(evmosd keys show "$USER3_KEY" -a --keyring-backend "$KEYRING")" 1000000000000000000000aevmos --keyring-backend "$KEYRING" -evmosd add-genesis-account "$(evmosd keys show "$USER4_KEY" -a --keyring-backend "$KEYRING")" 1000000000000000000000aevmos --keyring-backend "$KEYRING" - -# Update total supply with claim values -# Bc is required to add this big numbers -# total_supply=$(bc <<< "$validators_supply") -total_supply=100004000000000000000000000 -jq -r --arg total_supply "$total_supply" '.app_state.bank.supply[0].amount=$total_supply' "$GENESIS" >"$TMP_GENESIS" && mv "$TMP_GENESIS" "$GENESIS" - -# set custom pruning settings -if [ "$PRUNING" = "custom" ]; then - sed -i.bak 's/pruning = "default"/pruning = "custom"/g' "$APP_TOML" - sed -i.bak 's/pruning-keep-recent = "0"/pruning-keep-recent = "2"/g' "$APP_TOML" - sed -i.bak 's/pruning-interval = "0"/pruning-interval = "10"/g' "$APP_TOML" -fi - -# make sure the localhost IP is 0.0.0.0 -sed -i.bak 's/localhost/0.0.0.0/g' "$CONFIG_TOML" -sed -i.bak 's/127.0.0.1/0.0.0.0/g' "$APP_TOML" - -# use timeout_commit 1s to make test faster -sed -i.bak 's/timeout_commit = "3s"/timeout_commit = "1s"/g' "$CONFIG_TOML" - -# Sign genesis transaction -evmosd gentx "$VAL_KEY" 1000000000000000000000aevmos --gas-prices ${BASEFEE}aevmos --keyring-backend "$KEYRING" --chain-id "$CHAINID" -## In case you want to create multiple validators at genesis -## 1. Back to `evmosd keys add` step, init more keys -## 2. Back to `evmosd add-genesis-account` step, add balance for those -## 3. Clone this ~/.evmosd home directory into some others, let's say `~/.clonedEvmosd` -## 4. Run `gentx` in each of those folders -## 5. Copy the `gentx-*` folders under `~/.clonedEvmosd/config/gentx/` folders into the original `~/.evmosd/config/gentx` - -# Enable the APIs for the tests to be successful -sed -i.bak 's/enable = false/enable = true/g' "$APP_TOML" -# Don't enable Rosetta API by default -grep -q -F '[rosetta]' "$APP_TOML" && sed -i.bak '/\[rosetta\]/,/^\[/ s/enable = true/enable = false/' "$APP_TOML" -# Don't enable memiavl by default -grep -q -F '[memiavl]' "$APP_TOML" && sed -i.bak '/\[memiavl\]/,/^\[/ s/enable = true/enable = false/' "$APP_TOML" -# Don't enable versionDB by default -grep -q -F '[versiondb]' "$APP_TOML" && sed -i.bak '/\[versiondb\]/,/^\[/ s/enable = true/enable = false/' "$APP_TOML" - -# Collect genesis tx -evmosd collect-gentxs - -# Run this to ensure everything worked and that the genesis file is setup correctly -evmosd validate-genesis - -# Start the node -evmosd start "$TRACE" \ - --log_level $LOGLEVEL \ - --minimum-gas-prices=0.0001aevmos \ - --json-rpc.api eth,txpool,personal,net,debug,web3 \ - --chain-id "$CHAINID" diff --git a/tests/e2e/tx_test.go b/tests/e2e/tx_test.go deleted file mode 100644 index d1d8740..0000000 --- a/tests/e2e/tx_test.go +++ /dev/null @@ -1,66 +0,0 @@ -// Copyright Tharsis Labs Ltd.(Evmos) -// SPDX-License-Identifier:ENCL-1.0(https://github.com/evmos/evmos/blob/main/LICENSE) - -package e2e - -import ( - "context" - "regexp" - "strings" - - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/xrplevm/node/v5/tests/e2e/upgrade" -) - -// executeTransactions executes some sample transactions to check they are still working after the upgrade. -func (s *IntegrationTestSuite) executeTransactions() { - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - - // TODO: Add more transactions in future (e.g. staking precompile) - s.sendBankTransfer(ctx) -} - -// SendBankTransfer sends a bank transfer to check that the transactions are still working after the upgrade. -func (s *IntegrationTestSuite) sendBankTransfer(ctx context.Context) { - receiver := "evmos1jcltmuhplrdcwp7stlr4hlhlhgd4htqh3a79sq" - sentCoins := sdk.Coins{sdk.NewInt64Coin("aevmos", 10000000000)} - - balancePre, err := s.upgradeManager.GetBalance(ctx, s.upgradeParams.ChainID, receiver) - s.Require().NoError(err, "can't get balance of receiver account") - - // send some tokens between accounts to check transactions are still working - exec, err := s.upgradeManager.CreateModuleTxExec(upgrade.E2ETxArgs{ - ModuleName: "bank", - SubCommand: "send", - Args: []string{"mykey", receiver, sentCoins.String()}, - ChainID: s.upgradeParams.ChainID, - From: "mykey", - }) - s.Require().NoError(err, "failed to create bank send tx command") - - outBuf, errBuf, err := s.upgradeManager.RunExec(ctx, exec) - s.Require().NoError(err, "failed to execute bank send tx") - s.Require().Truef( - strings.Contains(outBuf.String(), "code: 0"), - "tx returned non code 0:\nstdout: %s\nstderr: %s", outBuf.String(), errBuf.String(), - ) - // NOTE: The only message in the errBuf that is allowed is `gas estimate: ...` - gasEstimateMatch, err := regexp.MatchString(`^\s*gas estimate: \d+\s*$`, errBuf.String()) - s.Require().NoError(err, "failed to match gas estimate message") - s.Require().True( - gasEstimateMatch, - "expected message in errBuf to be `gas estimate: ...`; got: %q\n", - errBuf.String(), - ) - - // Wait until the transaction has succeeded and is included in the chain - err = s.upgradeManager.WaitNBlocks(ctx, 2) - s.Require().NoError(err, "failed to wait for blocks") - - balancePost, err := s.upgradeManager.GetBalance(ctx, s.upgradeParams.ChainID, receiver) - s.Require().NoError(err, "can't get balance of receiver account") - - diff := balancePost.Sub(balancePre...) - s.Require().Equal(diff.String(), sentCoins.String(), "unexpected difference in bank balance") -} diff --git a/tests/e2e/upgrade/Dockerfile.init b/tests/e2e/upgrade/Dockerfile.init deleted file mode 100644 index fc87806..0000000 --- a/tests/e2e/upgrade/Dockerfile.init +++ /dev/null @@ -1,15 +0,0 @@ -# argument to provide specific version of evmos node -ARG INITIAL_VERSION -# checkov:skip=CKV_DOCKER_3:No need to create a user, this is only used on tests -FROM tharsishq/evmos:$INITIAL_VERSION - -WORKDIR /go/src/github.com/evmos/evmos - -COPY ./init-node.sh . - -# JSON-RPC server -EXPOSE 8545 - -HEALTHCHECK CMD curl --fail http://localhost:26657 || exit 1 - -CMD ["sh", "./init-node.sh"] diff --git a/tests/e2e/upgrade/balances.go b/tests/e2e/upgrade/balances.go deleted file mode 100644 index 884442f..0000000 --- a/tests/e2e/upgrade/balances.go +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright Tharsis Labs Ltd.(Evmos) -// SPDX-License-Identifier:ENCL-1.0(https://github.com/evmos/evmos/blob/main/LICENSE) - -package upgrade - -import ( - "context" - "fmt" - - "github.com/cosmos/cosmos-sdk/codec" - sdk "github.com/cosmos/cosmos-sdk/types" - banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" -) - -// GetBalance returns the account balance for the given address bech32 string through -// the CLI query. -func (m *Manager) GetBalance(ctx context.Context, chainID, address string) (sdk.Coins, error) { - queryArgs := QueryArgs{ - Module: "bank", - SubCommand: "balances", - Args: []string{address}, - ChainID: chainID, - } - - exec, err := m.CreateModuleQueryExec(queryArgs) - if err != nil { - return sdk.Coins{}, fmt.Errorf("create exec error: %w", err) - } - - outBuff, errBuff, err := m.RunExec(ctx, exec) - if err != nil { - return sdk.Coins{}, fmt.Errorf("run exec error: %w", err) - } - if errBuff.String() != "" { - return sdk.Coins{}, fmt.Errorf("evmos query error: %s", errBuff.String()) - } - - return UnpackBalancesResponse(m.ProtoCodec, outBuff.String()) -} - -// UnpackBalancesResponse unpacks the balances response from the given output of the bank balances query. -func UnpackBalancesResponse(cdc *codec.ProtoCodec, out string) (sdk.Coins, error) { - var balances banktypes.QueryAllBalancesResponse - if err := cdc.UnmarshalJSON([]byte(out), &balances); err != nil { - return sdk.Coins{}, fmt.Errorf("failed to unmarshal balances: %w", err) - } - - return balances.Balances, nil -} diff --git a/tests/e2e/upgrade/balances_test.go b/tests/e2e/upgrade/balances_test.go deleted file mode 100644 index 1dead10..0000000 --- a/tests/e2e/upgrade/balances_test.go +++ /dev/null @@ -1,70 +0,0 @@ -package upgrade_test - -import ( - "fmt" - "testing" - - "cosmossdk.io/math" - "github.com/cosmos/cosmos-sdk/codec" - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/evmos/evmos/v20/encoding" - "github.com/evmos/evmos/v20/tests/e2e/upgrade" - "github.com/stretchr/testify/require" -) - -func TestUnpackBalancesResponse(t *testing.T) { - t.Parallel() - - expAmount, ok := math.NewIntFromString("1000000000000000000000") - require.True(t, ok, "failed to convert amount to int") - - encodingConfig := encoding.MakeConfig() - protoCodec, ok := encodingConfig.Codec.(*codec.ProtoCodec) - require.True(t, ok, "failed to cast codec to proto codec") - - testcases := []struct { - name string - output string - want sdk.Coins - expPass bool - errContains string - }{ - { - name: "success", - output: fmt.Sprintf( - `{"balances":[{"denom":"aevmos","amount":"%s"}],`+ - `"pagination":{"next_key":null,"total":"0"}}`, - expAmount, - ), - want: sdk.Coins{sdk.NewCoin("aevmos", expAmount)}, - expPass: true, - }, - { - name: "pass - empty balances", - output: `{"balances":[],"pagination":{"next_key":null,"total":"0"}}`, - want: sdk.Coins{}, - expPass: true, - }, - { - name: "fail - invalid output", - output: `invalid`, - errContains: "failed to unmarshal balances", - }, - } - - for _, tc := range testcases { - tc := tc // Added for parallel testing, check https://pkg.go.dev/testing#hdr-Subtests_and_Sub_benchmarks - t.Run(tc.name, func(t *testing.T) { - t.Parallel() - - got, err := upgrade.UnpackBalancesResponse(protoCodec, tc.output) - if tc.expPass { - require.NoError(t, err, "unexpected error") - require.Equal(t, tc.want, got, "expected different balances") - } else { - require.Error(t, err, "expected error but got none") - require.ErrorContains(t, err, tc.errContains, "expected different error") - } - }) - } -} diff --git a/tests/e2e/upgrade/constants.go b/tests/e2e/upgrade/constants.go deleted file mode 100644 index 4221b2b..0000000 --- a/tests/e2e/upgrade/constants.go +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright Tharsis Labs Ltd.(Evmos) -// SPDX-License-Identifier:ENCL-1.0(https://github.com/evmos/evmos/blob/main/LICENSE) -package upgrade - -// The constants used in the upgrade tests are defined here -const ( - // the defaultChainID used for testing - defaultChainID = "evmos_9000-1" - - // LocalVersionTag defines the docker image ImageTag when building locally - // - // NOTE: For upgrade tests we're using the PebbleDB build - LocalVersionTag = "latest-pebble" - - // tharsisRepo is the docker hub repository that contains the Evmos images pulled during tests - tharsisRepo = "tharsishq/evmos" - - // upgradesPath is the relative path from this folder to the app/upgrades folder - upgradesPath = "../../../app/upgrades" - - // versionSeparator is used to separate versions in the INITIAL_VERSION and TARGET_VERSION - // environment vars - versionSeparator = "/" -) diff --git a/tests/e2e/upgrade/exec.go b/tests/e2e/upgrade/exec.go deleted file mode 100644 index afb4963..0000000 --- a/tests/e2e/upgrade/exec.go +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright Tharsis Labs Ltd.(Evmos) -// SPDX-License-Identifier:ENCL-1.0(https://github.com/evmos/evmos/blob/main/LICENSE) - -package upgrade - -import ( - "fmt" -) - -// E2ETxArgs contains the arguments to build a CLI transaction command from. -type E2ETxArgs struct { - ModuleName string - SubCommand string - Args []string - ChainID string - From string -} - -// CreateModuleTxExec creates the execution command for an Evmos transaction. -func (m *Manager) CreateModuleTxExec(txArgs E2ETxArgs) (string, error) { - cmd := []string{ - "evmosd", - "tx", - txArgs.ModuleName, - txArgs.SubCommand, - } - cmd = append(cmd, txArgs.Args...) - cmd = append(cmd, - fmt.Sprintf("--chain-id=%s", txArgs.ChainID), - "--keyring-backend=test", - "--output=text", - "--fees=50000000000000aevmos", - "--gas=auto", - fmt.Sprintf("--from=%s", txArgs.From), - "--yes", - ) - return m.CreateExec(cmd, m.ContainerID()) -} diff --git a/tests/e2e/upgrade/govexec.go b/tests/e2e/upgrade/govexec.go deleted file mode 100644 index bab9be4..0000000 --- a/tests/e2e/upgrade/govexec.go +++ /dev/null @@ -1,142 +0,0 @@ -// Copyright Tharsis Labs Ltd.(Evmos) -// SPDX-License-Identifier:ENCL-1.0(https://github.com/evmos/evmos/blob/main/LICENSE) - -package upgrade - -import ( - "bytes" - "context" - "fmt" - - "github.com/ory/dockertest/v3/docker" -) - -// RunExec runs the provided docker exec call -func (m *Manager) RunExec(ctx context.Context, exec string) (outBuf bytes.Buffer, errBuf bytes.Buffer, err error) { - err = m.pool.Client.StartExec(exec, docker.StartExecOptions{ - Context: ctx, - Detach: false, - OutputStream: &outBuf, - ErrorStream: &errBuf, - }) - return -} - -// CreateExec creates docker exec command for specified container -func (m *Manager) CreateExec(cmd []string, containerID string) (string, error) { - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - exec, err := m.pool.Client.CreateExec(docker.CreateExecOptions{ - Context: ctx, - AttachStdout: true, - AttachStderr: true, - User: "root", - Container: containerID, - Cmd: cmd, - }) - if err != nil { - return "", err - } - return exec.ID, nil -} - -// CreateSubmitProposalExec creates a gov tx to submit an upgrade proposal to the chain -func (m *Manager) CreateSubmitProposalExec(targetVersion, chainID string, upgradeHeight uint, legacy ProposalVersion, flags ...string) (string, error) { - cmd := getProposalCmd(legacy, targetVersion, upgradeHeight, chainID) - cmd = append(cmd, flags...) - // increment proposal counter to use proposal number for deposit && voting - m.proposalCounter++ - return m.CreateExec(cmd, m.ContainerID()) -} - -func getProposalCmd(legacy ProposalVersion, targetVersion string, upgradeHeight uint, chainID string) []string { - var cmd []string - if legacy == UpgradeProposalV50 { - cmd = []string{ - "evmosd", - "tx", - "upgrade", - "software-upgrade", - targetVersion, - "--summary=\"Test upgrade proposal\"", - "--no-validate", - } - } else { - var upgradeInfo, proposalType string - - switch legacy { - case LegacyProposalPreV50: - upgradeInfo = "--no-validate" - proposalType = "submit-legacy-proposal" - case LegacyProposalPreV46: - upgradeInfo = "--upgrade-info=\"\"" - proposalType = "submit-proposal" - default: - panic(fmt.Sprintf("invalid legacy proposal version: %v", legacy)) - } - - cmd = []string{ - "evmosd", - "tx", - "gov", - proposalType, - "software-upgrade", - targetVersion, - upgradeInfo, - } - } - - cmd = append(cmd, - "--title=\"TEST\"", - "--deposit=10000000aevmos", - "--description=\"Test upgrade proposal\"", - fmt.Sprintf("--upgrade-height=%d", upgradeHeight), - fmt.Sprintf("--chain-id=%s", chainID), - "--from=mykey", - "--yes", - "--keyring-backend=test", - "--output=text", - ) - - return cmd -} - -// CreateDepositProposalExec creates a gov tx to deposit for the proposal with the given id -func (m *Manager) CreateDepositProposalExec(chainID string, id int) (string, error) { - cmd := []string{ - "evmosd", - "tx", - "gov", - "deposit", - fmt.Sprint(id), - "10000000aevmos", - "--from=mykey", - fmt.Sprintf("--chain-id=%s", chainID), - "--yes", - "--keyring-backend=test", - "--output=text", - "--fees=500aevmos", - "--gas=500000", - } - - return m.CreateExec(cmd, m.ContainerID()) -} - -// CreateVoteProposalExec creates gov tx to vote 'yes' on the proposal with the given id -func (m *Manager) CreateVoteProposalExec(chainID string, id int, flags ...string) (string, error) { - cmd := []string{ - "evmosd", - "tx", - "gov", - "vote", - fmt.Sprint(id), - "yes", - "--from=mykey", - fmt.Sprintf("--chain-id=%s", chainID), - "--yes", - "--keyring-backend=test", - "--output=text", - } - cmd = append(cmd, flags...) - return m.CreateExec(cmd, m.ContainerID()) -} diff --git a/tests/e2e/upgrade/manager.go b/tests/e2e/upgrade/manager.go deleted file mode 100644 index ba81ff7..0000000 --- a/tests/e2e/upgrade/manager.go +++ /dev/null @@ -1,468 +0,0 @@ -// Copyright Tharsis Labs Ltd.(Evmos) -// SPDX-License-Identifier:ENCL-1.0(https://github.com/evmos/evmos/blob/main/LICENSE) - -package upgrade - -import ( - "bytes" - "context" - "encoding/json" - "fmt" - "io" - "math/big" - "net/http" - "os" - "regexp" - "strconv" - "strings" - "time" - - errorsmod "cosmossdk.io/errors" - "github.com/cosmos/cosmos-sdk/codec" - "github.com/ethereum/go-ethereum/common" - testnetwork "github.com/evmos/evmos/v20/testutil/integration/evmos/network" - "github.com/ory/dockertest/v3" - "github.com/ory/dockertest/v3/docker" -) - -// safetyDelta is the number of blocks that are added to the upgrade height to make sure -// the proposal has concluded when reaching the upgrade height. -const safetyDelta = 2 - -// Manager defines a docker pool instance, used to build, run, interact with and stop docker containers -// running Evmos nodes. -type Manager struct { - pool *dockertest.Pool - network *dockertest.Network - - // CurrentNode stores the currently running docker container - CurrentNode *dockertest.Resource - - // CurrentVersion stores the current version of the running node - CurrentVersion string - - // HeightBeforeStop stores the last block height that was reached before the last running node container - // was stopped - HeightBeforeStop int - - // proposalCounter keeps track of the number of proposals that have been submitted - proposalCounter uint - - // ProtoCodec is the codec used to marshal/unmarshal protobuf messages - ProtoCodec *codec.ProtoCodec - - // UpgradeHeight stores the upgrade height for the latest upgrade proposal that was submitted - UpgradeHeight uint -} - -// NewManager creates new docker pool and network and returns a populated Manager instance -func NewManager(networkName string) (*Manager, error) { - pool, err := dockertest.NewPool("") - if err != nil { - return nil, fmt.Errorf("docker pool creation error: %w", err) - } - - network, err := pool.CreateNetwork(networkName) - if err != nil { - return nil, fmt.Errorf("docker network creation error: %w", err) - } - - nw := testnetwork.New() - encodingConfig := nw.GetEncodingConfig() - protoCodec, ok := encodingConfig.Codec.(*codec.ProtoCodec) - if !ok { - return nil, fmt.Errorf("failed to get proto codec") - } - - return &Manager{ - pool: pool, - network: network, - ProtoCodec: protoCodec, - }, nil -} - -// BuildImage builds a docker image to run in the provided context directory -// with : as the image target -func (m *Manager) BuildImage(name, version, dockerFile, contextDir string, args map[string]string) error { - buildArgs := make([]docker.BuildArg, 0, len(args)) - for k, v := range args { - bArg := docker.BuildArg{ - Name: k, - Value: v, - } - buildArgs = append(buildArgs, bArg) - } - opts := docker.BuildImageOptions{ - // local Dockerfile path - Dockerfile: dockerFile, - BuildArgs: buildArgs, - // rebuild the image every time in case there were changes - // and the image is cached - NoCache: true, - // name with tag, e.g. evmos:v9.0.0 - Name: fmt.Sprintf("%s:%s", name, version), - OutputStream: io.Discard, - ErrorStream: os.Stdout, - ContextDir: contextDir, - } - return m.Client().BuildImage(opts) -} - -// RunNode creates a docker container from the provided node instance and runs it. -// To make sure the node started properly, get requests are sent to the JSON-RPC server repeatedly -// with a timeout of 60 seconds. -// In case the node fails to start, the container logs are returned along with the error. -func (m *Manager) RunNode(node *Node) error { - var resource *dockertest.Resource - var err error - - if node.withRunOptions { - resource, err = m.pool.RunWithOptions(node.RunOptions) - } else { - resource, err = m.pool.Run(node.repository, node.version, []string{}) - } - - if err != nil { - if resource == nil || resource.Container == nil { - return fmt.Errorf( - "can't run container\n[error]: %s", - err.Error(), - ) - } - stdOut, stdErr, _ := m.GetLogs(resource.Container.ID) - return fmt.Errorf( - "can't run container\n\n[error stream]:\n\n%s\n\n[output stream]:\n\n%s", - stdErr, - stdOut, - ) - } - - // trying to get JSON-RPC server, to make sure node started properly - // the last returned error before deadline exceeded will be returned from .Retry() - err = m.pool.Retry( - func() error { - // recreating container instance because resource.Container.State - // does not update properly by default - c, err := m.Client().InspectContainer(resource.Container.ID) - if err != nil { - return fmt.Errorf("can't inspect container: %s", err.Error()) - } - // if node failed to start, i.e. ExitCode != 0, return container logs - if c.State.ExitCode != 0 { - stdOut, stdErr, _ := m.GetLogs(resource.Container.ID) - return fmt.Errorf( - "can't start evmos node, container exit code: %d\n\n[error stream]:\n\n%s\n\n[output stream]:\n\n%s", - c.State.ExitCode, - stdErr, - stdOut, - ) - } - // get host:port for current container in local network - addr := resource.GetHostPort(jrpcPort + "/tcp") - r, err := http.Get("http://" + addr) - if err != nil { - return fmt.Errorf("can't get node json-rpc server: %s", err) - } - defer r.Body.Close() - return nil - }, - ) - if err != nil { - stdOut, stdErr, _ := m.GetLogs(resource.Container.ID) - return fmt.Errorf( - "can't start node: %s\n\n[error stream]:\n\n%s\n\n[output stream]:\n\n%s", - err.Error(), - stdErr, - stdOut, - ) - } - m.CurrentNode = resource - return nil -} - -// GetLogs returns the logs of the container with the provided containerID -func (m *Manager) GetLogs(containerID string) (stdOut, stdErr string, err error) { - var outBuf, errBuf bytes.Buffer - opts := docker.LogsOptions{ - Container: containerID, - OutputStream: &outBuf, - ErrorStream: &errBuf, - Stdout: true, - Stderr: true, - } - err = m.Client().Logs(opts) - if err != nil { - return "", "", fmt.Errorf("can't get logs: %s", err) - } - return outBuf.String(), errBuf.String(), nil -} - -// WaitNBlocks is a helper function to wait the specified number of blocks -func (m *Manager) WaitNBlocks(ctx context.Context, n int) error { - currentHeight, err := m.GetNodeHeight(ctx) - if err != nil { - return err - } - _, err = m.WaitForHeight(ctx, currentHeight+n) - return err -} - -// WaitForHeight queries the Evmos node every second until the node will reach the specified height. -// After 5 minutes this function times out and returns an error -func (m *Manager) WaitForHeight(ctx context.Context, height int) (string, error) { - var currentHeight int - var err error - ticker := time.NewTicker(2 * time.Minute) - for { - select { - case <-ticker.C: - stdOut, stdErr, errLogs := m.GetLogs(m.ContainerID()) - if errLogs != nil { - return "", fmt.Errorf("error while getting logs: %s", errLogs.Error()) - } - return "", fmt.Errorf( - "can't reach height %d, due to: %v\nerror logs: %s\nout logs: %s", - height, err, stdOut, stdErr, - ) - default: - currentHeight, err = m.GetNodeHeight(ctx) - if currentHeight >= height { - if err != nil { - return err.Error(), nil - } - return "", nil - } - time.Sleep(1 * time.Second) - } - } -} - -// GetNodeHeight calls the Evmos CLI in the current node container to get the current block height -func (m *Manager) GetNodeHeight(ctx context.Context) (int, error) { - cmd := []string{"evmosd", "q", "block"} - splitIdx := 0 // split index for the lines in the output - in newer versions the output is in the second line - useV50 := false - - // if the version is higher than v20.0.0, we need to use the json output flag - if !EvmosVersions([]string{m.CurrentVersion, "v20.0.0"}).Less(0, 1) { - cmd = append(cmd, "--output=json") - splitIdx = 1 - useV50 = true - } - - exec, err := m.CreateExec(cmd, m.ContainerID()) - if err != nil { - return 0, fmt.Errorf("create exec error: %w", err) - } - - outBuff, errBuff, err := m.RunExec(ctx, exec) - if err != nil { - return 0, fmt.Errorf("run exec error: %w", err) - } - - if errBuff.String() != "" { - return 0, fmt.Errorf("evmos query error: %s", errBuff.String()) - } - - // NOTE: we're splitting the output because it has the first line saying "falling back to latest height" - splittedOutBuff := strings.Split(outBuff.String(), "\n") - if len(splittedOutBuff) < splitIdx+1 { - return 0, fmt.Errorf("unexpected output format for node height; got: %s", outBuff.String()) - } - - outStr := splittedOutBuff[splitIdx] - var h int - // parse current height number from block info - if outStr != "" && outStr != "" { - if useV50 { - h, err = UnwrapBlockHeightPostV50(outStr) - } else { - h, err = UnwrapBlockHeightPreV50(outStr) - } - - // check if the conversion was possible - if err == nil { - // if conversion was possible but the errBuff is not empty, return the height along with an error - // this is necessary e.g. when the "duplicate proto" errors occur in the logs but the node is still - // producing blocks - if errBuff.String() != "" { - return h, fmt.Errorf("%s", errBuff.String()) - } - return h, nil - } - } - - return h, nil -} - -type BlockHeaderPreV50 struct { - Block struct { - Header struct { - Height string `json:"height"` - } `json:"header"` - } `json:"block"` -} - -type BlockHeaderPostV50 struct { - Header struct { - Height string `json:"height"` - } `json:"header"` -} - -// UnwrapBlockHeightPreV50 unwraps the block height from the output of the evmosd query block command -func UnwrapBlockHeightPreV50(input string) (int, error) { - var blockHeader BlockHeaderPreV50 - err := json.Unmarshal([]byte(input), &blockHeader) - if err != nil { - return 0, fmt.Errorf("failed to unmarshal JSON: %v", err) - } - - return strconv.Atoi(blockHeader.Block.Header.Height) -} - -// UnwrapBlockHeightPostV50 unwraps the block height from the output of the evmosd query block command -func UnwrapBlockHeightPostV50(input string) (int, error) { - var blockHeader BlockHeaderPostV50 - err := json.Unmarshal([]byte(input), &blockHeader) - if err != nil { - return 0, fmt.Errorf("failed to unmarshal JSON: %v", err) - } - - return strconv.Atoi(blockHeader.Header.Height) -} - -// GetNodeVersion calls the Evmos CLI in the current node container to get the -// current node version -func (m *Manager) GetNodeVersion(ctx context.Context) (string, error) { - exec, err := m.CreateExec([]string{"evmosd", "version"}, m.ContainerID()) - if err != nil { - return "", fmt.Errorf("create exec error: %w", err) - } - outBuff, errBuff, err := m.RunExec(ctx, exec) - if err != nil { - return "", fmt.Errorf("run exec error: %w", err) - } - if errBuff.String() != "" { - return "", fmt.Errorf("evmos version error: %s", errBuff.String()) - } - return outBuff.String(), nil -} - -// GetUpgradeHeight calculates the height for the scheduled software upgrade. -// -// It checks the timeout commit that is configured on the node and checks the voting duration. -// From this information, the height at which the upgrade will be scheduled is calculated. -func (m *Manager) GetUpgradeHeight(ctx context.Context, chainID string) (uint, error) { - currentHeight, err := m.GetNodeHeight(ctx) - if err != nil { - return 0, err - } - - timeoutCommit, err := m.getTimeoutCommit(ctx) - if err != nil { - return 0, errorsmod.Wrap(err, "failed to get timeout commit") - } - - votingPeriod, err := m.getVotingPeriod(ctx, chainID) - if err != nil { - return 0, errorsmod.Wrap(err, "failed to get voting period") - } - - heightDelta := new(big.Int).Quo(votingPeriod, timeoutCommit) - upgradeHeight := uint(currentHeight) + uint(heightDelta.Int64()) + safetyDelta // #nosec G115 - - // return the height at which the upgrade will be scheduled - return upgradeHeight, nil -} - -// getTimeoutCommit returns the timeout commit duration for the current node -func (m *Manager) getTimeoutCommit(ctx context.Context) (*big.Int, error) { - exec, err := m.CreateExec([]string{"grep", `\s*timeout_commit =`, "/root/.evmosd/config/config.toml"}, m.ContainerID()) - if err != nil { - return common.Big0, fmt.Errorf("create exec error: %w", err) - } - - outBuff, errBuff, err := m.RunExec(ctx, exec) - if err != nil { - return common.Big0, fmt.Errorf("failed to execute command: %s", err.Error()) - } - - if errBuff.String() != "" { - return common.Big0, fmt.Errorf("evmos version error: %s", errBuff.String()) - } - - re := regexp.MustCompile(`timeout_commit = "(?P\d+)s"`) - match := re.FindStringSubmatch(outBuff.String()) - if len(match) != 2 { - return common.Big0, fmt.Errorf("failed to parse timeout_commit: %s", outBuff.String()) - } - - tc, err := strconv.Atoi(match[1]) - if err != nil { - return common.Big0, err - } - - return big.NewInt(int64(tc)), nil -} - -// getVotingPeriod returns the voting period for the current node -func (m *Manager) getVotingPeriod(ctx context.Context, chainID string) (*big.Int, error) { - exec, err := m.CreateModuleQueryExec(QueryArgs{ - Module: "gov", - SubCommand: "params", - ChainID: chainID, - }) - if err != nil { - return common.Big0, fmt.Errorf("create exec error: %w", err) - } - - outBuff, errBuff, err := m.RunExec(ctx, exec) - if err != nil { - return common.Big0, fmt.Errorf("failed to execute command: %s", err.Error()) - } - - if errBuff.String() != "" { - return common.Big0, fmt.Errorf("evmos version error: %s", errBuff.String()) - } - - re := regexp.MustCompile(`"voting_period":"(?P\d+)s"`) - match := re.FindStringSubmatch(outBuff.String()) - if len(match) != 2 { - return common.Big0, fmt.Errorf("failed to parse voting_period: %s", outBuff.String()) - } - - vp, err := strconv.Atoi(match[1]) - if err != nil { - return common.Big0, err - } - - return big.NewInt(int64(vp)), nil -} - -// ContainerID returns the docker container ID of the currently running Node -func (m *Manager) ContainerID() string { - if m.CurrentNode == nil || m.CurrentNode.Container == nil { - return "" - } - return m.CurrentNode.Container.ID -} - -// The Client method returns the Docker client used by the Manager's pool -func (m *Manager) Client() *docker.Client { - return m.pool.Client -} - -// RemoveNetwork removes the Manager's used network from the pool -func (m *Manager) RemoveNetwork() error { - return m.pool.RemoveNetwork(m.network) -} - -// KillCurrentNode stops the execution of the currently used docker container -func (m *Manager) KillCurrentNode() error { - heightBeforeStop, err := m.GetNodeHeight(context.Background()) - if err != nil && heightBeforeStop == 0 { - return err - } - m.HeightBeforeStop = heightBeforeStop - return m.pool.Client.StopContainer(m.ContainerID(), 5) -} diff --git a/tests/e2e/upgrade/manager_test.go b/tests/e2e/upgrade/manager_test.go deleted file mode 100644 index e7a92fa..0000000 --- a/tests/e2e/upgrade/manager_test.go +++ /dev/null @@ -1,25 +0,0 @@ -package upgrade_test - -import ( - "testing" - - "github.com/evmos/evmos/v20/tests/e2e/upgrade" - "github.com/stretchr/testify/require" -) - -const ( - blockOutputPreV50 = "{\"block_id\":{\"hash\":\"ECECD69FAF6D6B0722042615CA6B63C3520CE207A03B70A35BC549ECB4101798\",\"parts\":{\"total\":1,\"hash\":\"C433720E863ADA05E015DF78590F13C467FCE3D13B6F8FAD0B4BE94F98093457\"}},\"block\":{\"header\":{\"version\":{\"block\":\"11\"},\"chain_id\":\"evmos_9000-1\",\"height\":\"40\",\"time\":\"2024-08-29T20:59:03.029214545Z\",\"last_block_id\":{\"hash\":\"F5E28BDAAFB6E3769FE15E29256D2D2F265E150D73F6ADC84F76C64A5B668F5C\",\"parts\":{\"total\":1,\"hash\":\"EC6D871E67B5662FB96A696B9E74EA8436B74A5EE1B4F8FDE4007713101CAEB8\"}},\"last_commit_hash\":\"BBE9C89F763E696B189F11C2870893F966FEF5B46085C13D4551FE8F914246E1\",\"data_hash\":\"E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855\",\"validators_hash\":\"3E57E93AFF0EFFA13F92F3F363C4FBB8090D812072035D4D81DA91A1C289562A\",\"next_validators_hash\":\"3E57E93AFF0EFFA13F92F3F363C4FBB8090D812072035D4D81DA91A1C289562A\",\"consensus_hash\":\"7D0B88F8835DB6E92EC4E959CCD9324052C68794BC42567CFA45FB176ED6679A\",\"app_hash\":\"18ADDA9AD92E7C62915702E2A272891FA4EAE006BDD7B117CC2A4A05A262C9B6\",\"last_results_hash\":\"E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855\",\"evidence_hash\":\"E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855\",\"proposer_address\":\"2E33F057457BD6B1374B6776A5A2315CD177E8C8\"},\"data\":{\"txs\":null},\"evidence\":{\"evidence\":null},\"last_commit\":{\"height\":\"39\",\"round\":0,\"block_id\":{\"hash\":\"F5E28BDAAFB6E3769FE15E29256D2D2F265E150D73F6ADC84F76C64A5B668F5C\",\"parts\":{\"total\":1,\"hash\":\"EC6D871E67B5662FB96A696B9E74EA8436B74A5EE1B4F8FDE4007713101CAEB8\"}},\"signatures\":[{\"block_id_flag\":2,\"validator_address\":\"2E33F057457BD6B1374B6776A5A2315CD177E8C8\",\"timestamp\":\"2024-08-29T20:59:03.029214545Z\",\"signature\":\"vcK+Ew9OT/fTGKhxVH/ehKE/7dJ82BSHXNZb/B/saVB+0UhC1qFN/rBQ+FuihNN5J95IG2YdOe+2Fppg7RN1CA==\"}]}}}" - blockOutputPostV50 = "{\"header\":{\"version\":{\"block\":\"11\",\"app\":\"0\"},\"chain_id\":\"evmos_9001-2\",\"height\":\"23136576\",\"time\":\"2024-08-29T21:07:47.173219060Z\",\"last_block_id\":{\"hash\":\"MFoG3Nc8BrfGLBWUtSm3XU/dJG45WZW8MxIo5IAlyho=\",\"part_set_header\":{\"total\":1,\"hash\":\"WlEMTfEcyTyNHzn9FTUZpTWEaOLGOIAYmN0H7gT7Hpk=\"}},\"last_commit_hash\":\"rs55UXNU/Ff/iIdnvf7Uu+OOh+N5nYmI1+jTpY92904=\",\"data_hash\":\"47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=\",\"validators_hash\":\"VFhmtCGzqKtwoK5lewntJwZdn6W7MR0u3tnWTVuWw9g=\",\"next_validators_hash\":\"VFhmtCGzqKtwoK5lewntJwZdn6W7MR0u3tnWTVuWw9g=\",\"consensus_hash\":\"ek5k0qm1ziK3XpVuICUnTcA7aEbM13JRUqa8DQcn4z4=\",\"app_hash\":\"KNmdEQk59wmj0JUCsmpRcXMhVN6Ru3PRpOWj2hykRjg=\",\"last_results_hash\":\"47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=\",\"evidence_hash\":\"47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=\",\"proposer_address\":\"INsp0gYoMX+pxKxyiKFV87qe3zo=\"},\"data\":{\"txs\":[]},\"evidence\":{\"evidence\":[]},\"last_commit\":{\"height\":\"23136575\",\"round\":0,\"block_id\":{\"hash\":\"MFoG3Nc8BrfGLBWUtSm3XU/dJG45WZW8MxIo5IAlyho=\",\"part_set_header\":{\"total\":1,\"hash\":\"WlEMTfEcyTyNHzn9FTUZpTWEaOLGOIAYmN0H7gT7Hpk=\"}},\"signatures\":[{\"block_id_flag\":\"BLOCK_ID_FLAG_COMMIT\",\"validator_address\":\"INsp0gYoMX+pxKxyiKFV87qe3zo=\",\"timestamp\":\"2024-08-29T21:07:47.151689399Z\",\"signature\":\"zTYJQPONiX0fcJMTVJT42XOmxkJC1ycirXQtJ/sQRItJ6ARe5RxdErQiNfbDqh3JApKfshoRMu59RWkUUTI/AA==\"},{\"block_id_flag\":\"BLOCK_ID_FLAG_COMMIT\",\"validator_address\":\"PNbD6+ovTnEkQQAxn4zzqbU0MyI=\",\"timestamp\":\"2024-08-29T21:07:47.190517293Z\",\"signature\":\"okzGvzYOTYRiCXc1YT4an6Oz7EetSwM4Pyj5vqYvJY1BpymD2MfeLp+u+vd0AeIsnimmngyMM35LWfmhOh3VCA==\"},{\"block_id_flag\":\"BLOCK_ID_FLAG_COMMIT\",\"validator_address\":\"gVWhxuhAuZBkUGGIIaRtl972nr4=\",\"timestamp\":\"2024-08-29T21:10:55.258272572Z\",\"signature\":\"gJ5TuPbRt+XwBcBQblcKjmBjIV80XU/SGGhCIMO+0A79XRij9XgIJ+w069ttbkN4KelhWaVcuEIlvOP086mhCg==\"},{\"block_id_flag\":\"BLOCK_ID_FLAG_COMMIT\",\"validator_address\":\"q3gXyrWm5QD0ytQqUiye/bo1naE=\",\"timestamp\":\"2024-08-29T21:07:47.175072852Z\",\"signature\":\"g4tvzy/E6x0s3yIZ3yWktDLycLino3Oj6DDDTnXVyxtnV4iMBtowKbCX0vNc1eiUc684POURtbjtjxP9qWQ/Aw==\"},{\"block_id_flag\":\"BLOCK_ID_FLAG_COMMIT\",\"validator_address\":\"ZyqajL8AeAA5TKmUIvhN+/bLpV4=\",\"timestamp\":\"2024-08-29T21:07:47.176287728Z\",\"signature\":\"EhGb0eIyNeBNWqa24ouhw2MpZTvBXYGk76ipZ+PHzMv8+4zoZ4J+jtTFEDM10Mj6g4/EZfSpdsG6P4bAQihHAw==\"},{\"block_id_flag\":\"BLOCK_ID_FLAG_COMMIT\",\"validator_address\":\"8vf1/A5QX+0NszBqZp2oiOZplZw=\",\"timestamp\":\"2024-08-29T21:07:47.171566330Z\",\"signature\":\"Wm4zmzNVQsrnpTxonEiUpv/I4wnFA6CQSqd5u9T1Gb0jl+5hufmziMnDmxC4R00CTEysXFuTXKz4Pp6Qg90UBg==\"},{\"block_id_flag\":\"BLOCK_ID_FLAG_COMMIT\",\"validator_address\":\"tsPbkG+u8sh1jRiBOG5hXoQyqRw=\",\"timestamp\":\"2024-08-29T21:07:47.160570450Z\",\"signature\":\"LKhUrTphNk1ZWcqsaMvH/NgBy9kWnqql9zs/M8CR8rCcCHi4llZnnqw++0rkCIi0a2bRXtiYmiUEF3e49lgXBg==\"},{\"block_id_flag\":\"BLOCK_ID_FLAG_COMMIT\",\"validator_address\":\"fLQ4DAeE+5p51msU7OucyRAplb8=\",\"timestamp\":\"2024-08-29T21:07:47.189346366Z\",\"signature\":\"jeAFqiq4VUI79rMNkd9NzLrXSyH/Ssra5UK9OmMIyv+9/y4Jx5hWQoTwPutLfseDEdAHnwM9hKc+4rUMRe34CA==\"},{\"block_id_flag\":\"BLOCK_ID_FLAG_COMMIT\",\"validator_address\":\"u5kxpaHBNO8ZZVxHyipibsqAwHE=\",\"timestamp\":\"2024-08-29T21:07:47.178648344Z\",\"signature\":\"68xYCrTjK/SYPn7Fh5QyvjgwvqbOYNvMzUpjCnXpOkPv94z80T4qUrjIh9JHUSXlv25qg6EBmXoi5tJhmGAPBw==\"},{\"block_id_flag\":\"BLOCK_ID_FLAG_COMMIT\",\"validator_address\":\"2gFXnp7Wxh0MboY5hiLSveXcp8M=\",\"timestamp\":\"2024-08-29T21:07:47.152986647Z\",\"signature\":\"MNzh3Ji59ZuANClXJTNl2fRbIQrdctaJDO5ez0UIcsMsGPF5c8HWMKzE4xLM4W9FN7UbZno2e/XDpN2HZk9bAg==\"},{\"block_id_flag\":\"BLOCK_ID_FLAG_COMMIT\",\"validator_address\":\"dmkhFfk65ET6hXx7qWPxJdjC5sY=\",\"timestamp\":\"2024-08-29T21:07:47.165135535Z\",\"signature\":\"V6/DVfD7Ag5oMhsbPw9HfzpNdOv0ojVrVF64M31Blzpsj9yr3CN3AX6dHEV8VLS6oTSNqRe7m3lNlMzlw8vOBg==\"},{\"block_id_flag\":\"BLOCK_ID_FLAG_COMMIT\",\"validator_address\":\"sx94eM3xHLKEE8z5/yxT6GnztlI=\",\"timestamp\":\"2024-08-29T21:07:47.174593472Z\",\"signature\":\"/ELSkgB7Lrr564/e3X8Ijzc5TSCbq5GwRSY7so2003LBvz93Ah0xvcuwtIxIc1cM55brj3iyBmhAyyQGbJJqDQ==\"},{\"block_id_flag\":\"BLOCK_ID_FLAG_COMMIT\",\"validator_address\":\"h+74vYVpLWjBYypK789kLmK010E=\",\"timestamp\":\"2024-08-29T21:07:47.160196561Z\",\"signature\":\"L/abFJLDQbLibh71fu2SLe9l5WJVsP7bsbWMAiyVeSR57hZ+yCUEYbABCgo2ZsiruPp+1ZVlKGf+q1uZjaRkDg==\"},{\"block_id_flag\":\"BLOCK_ID_FLAG_COMMIT\",\"validator_address\":\"fQ8XJW1rIsBOfscAODT1vIo68UQ=\",\"timestamp\":\"2024-08-29T21:07:47.171499902Z\",\"signature\":\"mogIBHuTm/ytCm//lOnXihm6R7eRFkZrijwWkgVfndRZIZreGQyiFqJei8jcV06nAczIPBe3meD3mtC5sXALBg==\"},{\"block_id_flag\":\"BLOCK_ID_FLAG_COMMIT\",\"validator_address\":\"v1/AbjKkFogXoW1paS82yPel2jc=\",\"timestamp\":\"2024-08-29T21:07:47.186492788Z\",\"signature\":\"KJRJuaC1r83O1aCd5pcwZMVSJgBgrt/1z571DkafSYl9E+5WiCcFFUx7F+TJVouXTeOd7leg6eRjdBLvLFlZAQ==\"},{\"block_id_flag\":\"BLOCK_ID_FLAG_COMMIT\",\"validator_address\":\"ktHF8RsGVqD7MJxOx6OtaodeFSs=\",\"timestamp\":\"2024-08-29T21:07:47.164166723Z\",\"signature\":\"XE4IMVZV49CUHGTOI7hpq+DZ6cL6plKv/wq8epzeWnF31DX5mBARWdbWWNjB3ftlZqW244ZMBLK4P0xvv+zzCA==\"},{\"block_id_flag\":\"BLOCK_ID_FLAG_COMMIT\",\"validator_address\":\"4qSeAH8p6atOaURmwC0U7u4S380=\",\"timestamp\":\"2024-08-29T21:07:47.161100379Z\",\"signature\":\"EvvZjNw3fwRAS3ECXuXlCS50hbJKSo9k65MvrbYFwC269ABemdygf0cE8SrF5HfRjAuncywzgqjyrA76QjLNDg==\"},{\"block_id_flag\":\"BLOCK_ID_FLAG_COMMIT\",\"validator_address\":\"B30FDOAwzvoOmN1/DxCyWb6wj28=\",\"timestamp\":\"2024-08-29T21:07:47.154195098Z\",\"signature\":\"Gr0cbNlzG89mV05D+GzP51P2eWdmm4oeaTvyt/n5PzhxDME9KlbZWTPXiu6eQWMrCN7qbqh68/HOHBOvHNc2Aw==\"},{\"block_id_flag\":\"BLOCK_ID_FLAG_COMMIT\",\"validator_address\":\"U7HWxxiQjw09k87HbDM45mZhjTg=\",\"timestamp\":\"2024-08-29T21:07:47.172476499Z\",\"signature\":\"5mwEzHtQyObVJ30zHUayW8a7OiU4lAcSZ/lb0reUP42ZBlIQxqf1OukrmcTUNrZhnzlCE66ujPfwkU+frxyCDQ==\"},{\"block_id_flag\":\"BLOCK_ID_FLAG_COMMIT\",\"validator_address\":\"Xx/1I0Iypa8OrdL2vGqIi90wWn0=\",\"timestamp\":\"2024-08-29T21:07:47.173219060Z\",\"signature\":\"2pPS9qOys5cchdWB4BfT9aFqedXPvMPPSZ1nXYbatMNBNLM3x2rgq78ZiRIm+98UMrGlw7O5C/j+d9sf0WUZAg==\"}]}}" -) - -func TestUnwrapBlockHeight(t *testing.T) { - blockHeight, err := upgrade.UnwrapBlockHeightPreV50(blockOutputPreV50) - require.NoError(t, err, "error unwrapping block height") - require.Equal(t, 40, blockHeight, "block height does not match") -} - -func TestUnwrapBlockHeightPostV50(t *testing.T) { - blockHeight, err := upgrade.UnwrapBlockHeightPostV50(blockOutputPostV50) - require.NoError(t, err, "error unwrapping block height") - require.Equal(t, 23136576, blockHeight, "block height does not match") -} diff --git a/tests/e2e/upgrade/node.go b/tests/e2e/upgrade/node.go deleted file mode 100644 index 6a641de..0000000 --- a/tests/e2e/upgrade/node.go +++ /dev/null @@ -1,63 +0,0 @@ -// Copyright Tharsis Labs Ltd.(Evmos) -// SPDX-License-Identifier:ENCL-1.0(https://github.com/evmos/evmos/blob/main/LICENSE) - -package upgrade - -import "github.com/ory/dockertest/v3" - -const jrpcPort = "8545" - -// Node represents an Evmos node in the context of the upgrade tests. It contains -// fields to store the used repository, version as well as custom run options for -// dockertest. -type Node struct { - repository string - version string - - RunOptions *dockertest.RunOptions - withRunOptions bool -} - -// NewNode creates a new instance of the node with a set of sensible default RunOptions -// for dockertest. -func NewNode(repository, version string) *Node { - return &Node{ - repository: repository, - version: version, - RunOptions: &dockertest.RunOptions{ - User: "0:0", - Repository: repository, - Tag: version, - // exposing JSON-RPC port by default to ping node after start - ExposedPorts: []string{jrpcPort}, - }, - } -} - -// SetEnvVars allows to set additional container environment variables by passing a slice -// of strings that each fit the pattern "VAR_NAME=value". -func (n *Node) SetEnvVars(vars []string) { - n.RunOptions.Env = vars - n.UseRunOptions() -} - -// Mount sets the container mount point, which is used as the value for 'docker run --volume'. -// -// See https://docs.docker.com/engine/reference/builder/#volume -func (n *Node) Mount(mountPath string) { - n.RunOptions.Mounts = []string{mountPath} - n.UseRunOptions() -} - -// SetCmd sets the container entry command and overrides the image CMD instruction. -// -// See https://docs.docker.com/engine/reference/builder/#cmd -func (n *Node) SetCmd(cmd []string) { - n.RunOptions.Cmd = cmd - n.UseRunOptions() -} - -// UseRunOptions sets a flag to allow the node Manager to run the container with additional run options. -func (n *Node) UseRunOptions() { - n.withRunOptions = true -} diff --git a/tests/e2e/upgrade/params.go b/tests/e2e/upgrade/params.go deleted file mode 100644 index 429e088..0000000 --- a/tests/e2e/upgrade/params.go +++ /dev/null @@ -1,152 +0,0 @@ -// Copyright Tharsis Labs Ltd.(Evmos) -// SPDX-License-Identifier:ENCL-1.0(https://github.com/evmos/evmos/blob/main/LICENSE) - -package upgrade - -import ( - "fmt" - "os" - "regexp" - "strconv" - "strings" -) - -// Params defines the parameters for the upgrade test suite -type Params struct { - // MountPath defines the path where the docker container is mounted - MountPath string - // Versions defines the slice of versions that are run during the upgrade tests - Versions []VersionConfig - // ChainID defines the chain ID used for the upgrade tests - ChainID string - // SkipCleanup defines if the docker containers are removed after the tests - SkipCleanup bool - // WorkDirRoot defines the working directory - WorkDirRoot string -} - -// VersionConfig defines a struct that contains the version and the source repository for an upgrade -type VersionConfig struct { - // UpgradeName defines the upgrade name to use in the proposal - UpgradeName string - // ImageTag defines the version tag to use in the docker image - ImageTag string - // ImageName defines the image name for the docker image - ImageName string -} - -// LoadUpgradeParams loads the upgrade parameters from the environment variables -func LoadUpgradeParams(upgradesFolder string) (Params, error) { - var ( - // allowedVersionPattern defines the regex pattern for a semver version (including release candidates) - allowedVersionPattern = `v*\d+\.\d\.\d(-rc\d+)*` - // allowedVersionSinglePattern defines the regex pattern for a single version - allowedVersionSinglePattern = fmt.Sprintf(`^%s$`, allowedVersionPattern) - // allowedVersionListPattern defines the regex pattern for a list of versions - allowedVersionListPattern = fmt.Sprintf(`^(%s*%s)+$`, versionSeparator, allowedVersionPattern) - // err is the captured error variable - err error - // upgradeName defines the upgrade name to use in the proposal - upgradeName string - // upgradesList contains the available upgrades in the app/upgrades folder - upgradesList []string - // versionTag is a string to store the processed version tags (e.g. v10.0.1) - versionTag string - // versionTags contains the slice of all version tags that are run during the upgrade tests - versionTags []string - ) - - initialV := os.Getenv("INITIAL_VERSION") - if initialV == "" { - upgradesList, err = RetrieveUpgradesList(upgradesFolder) - if err != nil { - return Params{}, fmt.Errorf("failed to retrieve the list of upgrades: %w", err) - } - // set the second-to-last upgrade as initial version - versionTags = []string{upgradesList[len(upgradesList)-2]} - } else { - if !regexp.MustCompile(allowedVersionListPattern).MatchString(initialV) { - return Params{}, fmt.Errorf("invalid initial version: %s", initialV) - } - versionTags = strings.Split(initialV, versionSeparator) - } - - // versions contains the slice of all versions that shall be executed - versions := make([]VersionConfig, 0, len(versionTags)) - - // for all initial versions the docker hub image is used - for _, versionTag = range versionTags { - if !strings.Contains(versionTag, "v") { - versionTag = "v" + versionTag - } - versions = append(versions, VersionConfig{ - UpgradeName: versionTag, - ImageTag: versionTag, - ImageName: tharsisRepo, - }) - } - - // When a target version is specified, it is used and the tharsishq DockerHub repo used. - // If no target version is specified, the last upgrade in the app/upgrades folder is used - // and a name for the local image is assigned. - targetV := os.Getenv("TARGET_VERSION") - if targetV == "" { - if upgradesList == nil { - upgradesList, err = RetrieveUpgradesList(upgradesFolder) - if err != nil { - return Params{}, fmt.Errorf("failed to retrieve the list of upgrades: %w", err) - } - } - upgradeName = upgradesList[len(upgradesList)-1] - versionTag = LocalVersionTag - } else { - if !regexp.MustCompile(allowedVersionSinglePattern).MatchString(targetV) { - return Params{}, fmt.Errorf("invalid target version: %s", targetV) - } - if !strings.Contains(targetV, "v") { - targetV = "v" + targetV - } - upgradeName = targetV - versionTag = targetV - } - - // Add the target version to the versions slice - versions = append(versions, VersionConfig{ - upgradeName, - versionTag, - tharsisRepo, - }) - - // If chain ID is not specified, the default value from the constants file will be used in upgrade-init.sh - chainID := os.Getenv("CHAIN_ID") - if chainID == "" { - chainID = defaultChainID - } - - skipFlag := os.Getenv("E2E_SKIP_CLEANUP") - skipCleanup, err := strconv.ParseBool(skipFlag) - if err != nil { - skipCleanup = false - } - - workDir, err := os.Getwd() - if err != nil { - return Params{}, err - } - workDir = strings.TrimSuffix(workDir, "/tests/e2e") - - mountPath := os.Getenv("MOUNT_PATH") - if mountPath == "" { - mountPath = workDir + "/build/:/root/" - } - - params := Params{ - MountPath: mountPath, - Versions: versions, - ChainID: chainID, - SkipCleanup: skipCleanup, - WorkDirRoot: workDir, - } - - return params, nil -} diff --git a/tests/e2e/upgrade/params_test.go b/tests/e2e/upgrade/params_test.go deleted file mode 100644 index 5aa0f05..0000000 --- a/tests/e2e/upgrade/params_test.go +++ /dev/null @@ -1,177 +0,0 @@ -package upgrade - -import ( - "os" - "testing" - - "github.com/stretchr/testify/require" -) - -// envVars is a helper struct to define the used environment variables -type envVars struct { - initialVersion string - targetVersion string - chainID string - skipCleanup string - mountPath string -} - -// TestLoadUpgradeParams tests the LoadUpgradeParams function -func TestLoadUpgradeParams(t *testing.T) { - wd, err := os.Getwd() - require.NoError(t, err, "can't get current working directory") - - defaultMountPath := wd + "/build/:/root/" - availableUpgrades, err := RetrieveUpgradesList(upgradesPath) - require.NoError(t, err, "can't retrieve upgrades list") - latestVersionName := availableUpgrades[len(availableUpgrades)-1] - defaultInitialVersion := availableUpgrades[len(availableUpgrades)-2] - - testcases := []struct { - name string - vars envVars - want Params - expPass bool - }{ - { - name: "pass - all params set - one initial version", - vars: envVars{ - initialVersion: "v0.1.0", - targetVersion: "v0.2.0", - chainID: "evmos_9123-1", - skipCleanup: "true", - mountPath: "/tmp/evmos", - }, - want: Params{ - MountPath: "/tmp/evmos", - Versions: []VersionConfig{ - {"v0.1.0", "v0.1.0", tharsisRepo}, - {"v0.2.0", "v0.2.0", tharsisRepo}, - }, - ChainID: "evmos_9123-1", - WorkDirRoot: wd, - }, - expPass: true, - }, - { - name: "pass - multiple initial versions, no target version", - vars: envVars{ - initialVersion: "v0.1.0/v0.2.0", - }, - want: Params{ - MountPath: defaultMountPath, - Versions: []VersionConfig{ - {"v0.1.0", "v0.1.0", tharsisRepo}, - {"v0.2.0", "v0.2.0", tharsisRepo}, - {latestVersionName, LocalVersionTag, tharsisRepo}, - }, - ChainID: defaultChainID, - WorkDirRoot: wd, - }, - expPass: true, - }, - { - name: "pass - no 'v' prefix in version string", - vars: envVars{ - initialVersion: "0.1.0", - targetVersion: "0.2.0", - }, - want: Params{ - MountPath: defaultMountPath, - Versions: []VersionConfig{ - {"v0.1.0", "v0.1.0", tharsisRepo}, - {"v0.2.0", "v0.2.0", tharsisRepo}, - }, - ChainID: defaultChainID, - WorkDirRoot: wd, - }, - expPass: true, - }, - { - name: "pass - release candidate version", - vars: envVars{ - initialVersion: "v0.1.0-rc1", - targetVersion: "v0.2.0-rc2", - }, - want: Params{ - MountPath: defaultMountPath, - Versions: []VersionConfig{ - {"v0.1.0-rc1", "v0.1.0-rc1", tharsisRepo}, - {"v0.2.0-rc2", "v0.2.0-rc2", tharsisRepo}, - }, - ChainID: defaultChainID, - WorkDirRoot: wd, - }, - expPass: true, - }, - { - name: "pass - no initial version", - vars: envVars{}, - want: Params{ - MountPath: defaultMountPath, - Versions: []VersionConfig{ - {defaultInitialVersion, defaultInitialVersion, tharsisRepo}, - {latestVersionName, LocalVersionTag, tharsisRepo}, - }, - ChainID: defaultChainID, - WorkDirRoot: wd, - }, - expPass: true, - }, - { - name: "fail - separator in target version", - vars: envVars{ - initialVersion: "v0.1.0", - targetVersion: "v0.2.0/v0.3.0", - }, - want: Params{}, - expPass: false, - }, - { - name: "fail - wrong version separator", - vars: envVars{ - initialVersion: "v0.1.0|v0.2.0", - }, - want: Params{}, - expPass: false, - }, - { - name: "fail - invalid target version string", - vars: envVars{ - targetVersion: "v@93bca", - }, - want: Params{}, - expPass: false, - }, - { - name: "fail - invalid initial version string", - vars: envVars{ - initialVersion: "v@93bca", - }, - want: Params{}, - expPass: false, - }, - } - - for _, tc := range testcases { - t.Run(tc.name, func(t *testing.T) { - t.Setenv("INITIAL_VERSION", tc.vars.initialVersion) - t.Setenv("TARGET_VERSION", tc.vars.targetVersion) - t.Setenv("CHAIN_ID", tc.vars.chainID) - t.Setenv("SKIP_CLEANUP", tc.vars.skipCleanup) - t.Setenv("MOUNT_PATH", tc.vars.mountPath) - - params, err := LoadUpgradeParams(upgradesPath) - if tc.expPass { - require.NoError(t, err, "LoadUpgradeParams() should not return an error") - } else { - require.Error(t, err, "LoadUpgradeParams() should return an error") - } - require.Equal(t, tc.want.ChainID, params.ChainID, "chain id differs from the expected value") - require.Equal(t, tc.want.MountPath, params.MountPath, "mount path differs from the expected value") - require.Equal(t, tc.want.Versions, params.Versions, "versions differ from the expected values") - require.Equal(t, tc.want.WorkDirRoot, params.WorkDirRoot, "root working directory differs from the expected value") - require.Equal(t, tc.want.SkipCleanup, params.SkipCleanup, "flag to skip cleanup differs from the expected value") - }) - } -} diff --git a/tests/e2e/upgrade/queryexec.go b/tests/e2e/upgrade/queryexec.go deleted file mode 100644 index 8f532ce..0000000 --- a/tests/e2e/upgrade/queryexec.go +++ /dev/null @@ -1,61 +0,0 @@ -// Copyright Tharsis Labs Ltd.(Evmos) -// SPDX-License-Identifier:ENCL-1.0(https://github.com/evmos/evmos/blob/main/LICENSE) - -package upgrade - -import ( - "fmt" -) - -// QueryArgs is a struct to hold the relevant information for the query commands. -type QueryArgs struct { - // Module is the module name to query - Module string - // SubCommand is the subcommand to query - SubCommand string - // Args are the arguments to the query command - Args []string - // ChainID is the chain ID to query - ChainID string -} - -// Validate performs basic validation on the QueryArgs. -func (q QueryArgs) Validate() error { - if q.Module == "" { - return fmt.Errorf("module cannot be empty") - } - if q.SubCommand == "" { - return fmt.Errorf("subcommand cannot be empty") - } - if q.ChainID == "" { - return fmt.Errorf("chain ID cannot be empty") - } - return nil -} - -// CreateModuleQueryExec creates a Evmos module query. -func (m *Manager) CreateModuleQueryExec(args QueryArgs) (string, error) { - // Check that valid args were provided - if err := args.Validate(); err != nil { - return "", err - } - - // Build the query command - cmd := []string{ - "evmosd", - "q", - args.Module, - args.SubCommand, - } - - if len(args.Args) > 0 { - cmd = append(cmd, args.Args...) - } - - cmd = append(cmd, - fmt.Sprintf("--chain-id=%s", args.ChainID), - "--output=json", - ) - - return m.CreateExec(cmd, m.ContainerID()) -} diff --git a/tests/e2e/upgrade/utils.go b/tests/e2e/upgrade/utils.go deleted file mode 100644 index 7425e77..0000000 --- a/tests/e2e/upgrade/utils.go +++ /dev/null @@ -1,129 +0,0 @@ -// Copyright Tharsis Labs Ltd.(Evmos) -// SPDX-License-Identifier:ENCL-1.0(https://github.com/evmos/evmos/blob/main/LICENSE) - -package upgrade - -import ( - "fmt" - "os" - "os/exec" - "regexp" - "sort" - "strings" - - "github.com/hashicorp/go-version" -) - -// EvmosVersions is a custom comparator for sorting semver version strings. -type EvmosVersions []string - -// Len is the number of stored versions. -func (v EvmosVersions) Len() int { return len(v) } - -// Swap swaps the elements with indexes i and j. It is needed to sort the slice. -func (v EvmosVersions) Swap(i, j int) { v[i], v[j] = v[j], v[i] } - -// Less compares semver versions strings properly -func (v EvmosVersions) Less(i, j int) bool { - v1, err := version.NewVersion(v[i]) - if err != nil { - panic(fmt.Sprintf("couldn't interpret version as SemVer string: %s: %s", v[i], err.Error())) - } - - v2, err := version.NewVersion(v[j]) - if err != nil { - panic(fmt.Sprintf("couldn't interpret version as SemVer string: %s: %s", v[j], err.Error())) - } - - return v1.LessThan(v2) -} - -// ProposalVersion is an enum to represent the type of upgrade proposal to be used -// based on the Evmos version. -// -// This is required since the way to submit an upgrade proposal has changed between -// different SDK versions. -type ProposalVersion uint8 - -const ( - LegacyProposalPreV46 ProposalVersion = iota - LegacyProposalPreV50 - UpgradeProposalV50 -) - -// CheckUpgradeProposalVersion checks if the running node requires a legacy proposal -func CheckUpgradeProposalVersion(version string) ProposalVersion { - version = strings.TrimSpace(version) - if !strings.HasPrefix(version, "v") { - version = "v" + version - } - - // if version is lower than v10.x.x, then it's using SDK v0.46 - cmp := EvmosVersions([]string{version, "v10.0.0", "v20.0.0"}) - var proposalVersion ProposalVersion - switch { - case cmp.Less(0, 1): - proposalVersion = LegacyProposalPreV46 - case cmp.Less(0, 2): - proposalVersion = LegacyProposalPreV50 - default: - proposalVersion = UpgradeProposalV50 - } - - return proposalVersion -} - -// RetrieveUpgradesList parses the app/upgrades folder and returns a slice of semver upgrade versions -// in ascending order, e.g ["v1.0.0", "v1.0.1", "v1.1.0", ... , "v10.0.0"] -func RetrieveUpgradesList(upgradesPath string) ([]string, error) { - dirs, err := os.ReadDir(upgradesPath) - if err != nil { - return nil, err - } - - // preallocate slice to store versions - versions := make([]string, 0, len(dirs)) - - // pattern to find quoted string(upgrade version) in a file e.g. "v10.0.0" - pattern := regexp.MustCompile(`"(.*?)"`) - - for _, d := range dirs { - if !d.IsDir() { - continue - } - - // creating path to upgrade dir file with constant upgrade version - constantsPath := fmt.Sprintf("%s/%s/constants.go", upgradesPath, d.Name()) - if _, err = os.Stat(constantsPath); os.IsNotExist(err) { - continue - } - - f, err := os.ReadFile(constantsPath) - if err != nil { - return nil, err - } - - v := pattern.FindString(string(f)) - // v[1 : len(v)-1] subslice used to remove quotes from version string - versions = append(versions, v[1:len(v)-1]) - } - - sort.Sort(EvmosVersions(versions)) - - return versions, nil -} - -// ExportState executes the 'docker cp' command to copy container .evmosd dir -// to the specified target dir (local) -// -// See https://docs.docker.com/engine/reference/commandline/cp/ -func (m *Manager) ExportState(targetDir string) error { - /* #nosec G204 */ - cmd := exec.Command( - "docker", - "cp", - fmt.Sprintf("%s:/root/.evmosd", m.ContainerID()), - targetDir, - ) - return cmd.Run() -} diff --git a/tests/e2e/upgrade/utils_test.go b/tests/e2e/upgrade/utils_test.go deleted file mode 100644 index 73e3836..0000000 --- a/tests/e2e/upgrade/utils_test.go +++ /dev/null @@ -1,107 +0,0 @@ -// This file contains unit tests for the e2e package. -package upgrade - -import ( - "testing" - - "github.com/stretchr/testify/require" -) - -func TestCheckUpgradeProposalVersion(t *testing.T) { - testCases := []struct { - Name string - Ver string - Exp ProposalVersion - }{ - { - Name: "legacy proposal pre v0.47 - v10.0.1", - Ver: "v10.0.1", - Exp: LegacyProposalPreV50, - }, - { - Name: "normal proposal pre v0.46 - v9.1.0", - Ver: "v9.1.0", - Exp: LegacyProposalPreV46, - }, - { - Name: "normal proposal - version with whitespace - v9.1.0", - Ver: "\tv9.1.0 ", - Exp: LegacyProposalPreV46, - }, - { - Name: "normal proposal - version without v - 9.1.0", - Ver: "9.1.0", - Exp: LegacyProposalPreV46, - }, - { - Name: "SDK v0.50 proposal - version with whitespace - v20.0.0", - Ver: "\tv20.0.0 ", - Exp: UpgradeProposalV50, - }, - } - - for _, tc := range testCases { - t.Run(tc.Name, func(t *testing.T) { - legacyProposal := CheckUpgradeProposalVersion(tc.Ver) - require.Equal(t, tc.Exp, legacyProposal, "expected: %v, got: %v", tc.Exp, legacyProposal) - }) - } -} - -// TestEvmosVersionsLess tests the EvmosVersions type's Less method with -// different version strings -func TestEvmosVersionsLess(t *testing.T) { - var version EvmosVersions - - testCases := []struct { - Name string - Ver string - Exp bool - }{ - { - Name: "higher - v10.0.1", - Ver: "v10.0.1", - Exp: false, - }, - { - Name: "lower - v9.1.0", - Ver: "v9.1.0", - Exp: true, - }, - } - - for _, tc := range testCases { - t.Run(tc.Name, func(t *testing.T) { - version = []string{tc.Ver, "v10.0.0"} - require.Equal(t, version.Less(0, 1), tc.Exp, "expected: %v, got: %v", tc.Exp, version) - }) - } -} - -// TestEvmosVersionsSwap tests the EvmosVersions type's Swap method -func TestEvmosVersionsSwap(t *testing.T) { - var version EvmosVersions - value := "v9.1.0" - version = []string{value, "v10.0.0"} - version.Swap(0, 1) - require.Equal(t, value, version[1], "expected: %v, got: %v", value, version[1]) -} - -// TestEvmosVersionsLen tests the EvmosVersions type's Len method -func TestEvmosVersionsLen(t *testing.T) { - var version EvmosVersions = []string{"v9.1.0", "v10.0.0"} - require.Equal(t, 2, version.Len(), "expected: %v, got: %v", 2, version.Len()) -} - -// TestRetrieveUpgradesList tests if the list of available upgrades in the codebase -// can be correctly retrieved -func TestRetrieveUpgradesList(t *testing.T) { - upgradeList, err := RetrieveUpgradesList("../../../app/upgrades") - require.NoError(t, err, "expected no error while retrieving upgrade list") - require.NotEmpty(t, upgradeList, "expected upgrade list to be non-empty") - - // check if all entries in the list match a semantic versioning pattern - for _, upgrade := range upgradeList { - require.Regexp(t, `^v\d+\.\d+\.\d+(-rc\d+)*$`, upgrade, "expected upgrade version to be in semantic versioning format") - } -} From 1b56800a0f1508cee048a20b1b0b9d802f63881a Mon Sep 17 00:00:00 2001 From: GuillemGarciaDev Date: Mon, 20 Jan 2025 13:05:01 +0100 Subject: [PATCH 03/25] feat(tests/upgrade): setup testsuite with custom db wip --- tests/upgrade/suite.go | 28 +- tests/upgrade/testutil/db.go | 23 ++ tests/upgrade/upgrade-state.json | 656 ------------------------------- 3 files changed, 39 insertions(+), 668 deletions(-) create mode 100644 tests/upgrade/testutil/db.go delete mode 100644 tests/upgrade/upgrade-state.json diff --git a/tests/upgrade/suite.go b/tests/upgrade/suite.go index b95347c..45b9f29 100644 --- a/tests/upgrade/suite.go +++ b/tests/upgrade/suite.go @@ -1,14 +1,18 @@ package testupgrade import ( - "os" - + dbm "github.com/cosmos/cosmos-db" + "github.com/cosmos/cosmos-sdk/baseapp" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/stretchr/testify/suite" - exrpupgrade "github.com/xrplevm/node/v5/testutil/integration/exrp/upgrade" + "github.com/xrplevm/node/v5/tests/upgrade/testutil" + exrpcommon "github.com/xrplevm/node/v5/testutil/integration/exrp/common" ) -const defaultStateFile = "upgrade-state.json" +const ( + DefaultNodeDBName = ".exrp-upgrade" + DefaultNodeDBDir = "exrp-upgrade" +) type UpgradeTestSuite struct { suite.Suite @@ -21,21 +25,21 @@ func (s *UpgradeTestSuite) Network() *UpgradeTestNetwork { } func (s *UpgradeTestSuite) SetupTest() { - // Get the state file from the environment variable, or use the default one - stateFile := os.Getenv("UPGRADE_STATE_FILE") - if stateFile == "" { - stateFile = defaultStateFile - } - s.Require().NotEmpty(stateFile) - // Setup the SDK config s.network.SetupSdkConfig() s.Require().Equal(sdk.GetConfig().GetBech32AccountAddrPrefix(), "ethm") + s.Require().NoError(testutil.CopyNodeDB(DefaultNodeDBDir, DefaultNodeDBDir+"-tmp")) + + db, err := dbm.NewGoLevelDB(DefaultNodeDBName, DefaultNodeDBDir+"-tmp", nil) + s.Require().NoError(err) + // Create the network s.network = NewUpgradeTestNetwork( - exrpupgrade.WithGenesisFile(stateFile), + exrpcommon.WithCustomBaseAppOpts(func(ba *baseapp.BaseApp) { + ba.SetDB(db) + }), ) // Check that the network was created successfully diff --git a/tests/upgrade/testutil/db.go b/tests/upgrade/testutil/db.go new file mode 100644 index 0000000..87d013f --- /dev/null +++ b/tests/upgrade/testutil/db.go @@ -0,0 +1,23 @@ +package testutil + +import ( + "io" + "os" +) + +func CopyNodeDB(from, to string) error { + fromDB, err := os.Open(from) + if err != nil { + return err + } + defer fromDB.Close() + + toDB, err := os.Create(to) + if err != nil { + return err + } + defer toDB.Close() + + _, err = io.Copy(toDB, fromDB) + return err +} diff --git a/tests/upgrade/upgrade-state.json b/tests/upgrade/upgrade-state.json deleted file mode 100644 index af21608..0000000 --- a/tests/upgrade/upgrade-state.json +++ /dev/null @@ -1,656 +0,0 @@ -{ - "app_name": "exrpd", - "app_version": "v4.0.0-7-g40ab899", - "genesis_time": "2024-11-27T17:14:04.871328Z", - "chain_id": "exrp_1440002-1", - "initial_height": 8, - "app_hash": null, - "app_state": { - "auth": { - "params": { - "max_memo_characters": "256", - "tx_sig_limit": "7", - "tx_size_cost_per_byte": "10", - "sig_verify_cost_ed25519": "590", - "sig_verify_cost_secp256k1": "1000" - }, - "accounts": [ - { - "@type": "/cosmos.auth.v1beta1.ModuleAccount", - "base_account": { - "address": "ethm1glht96kr2rseywuvhhay894qw7ekuc4q32ac2y", - "pub_key": null, - "account_number": "7", - "sequence": "0" - }, - "name": "erc20", - "permissions": [ - "minter", - "burner" - ] - }, - { - "@type": "/cosmos.auth.v1beta1.ModuleAccount", - "base_account": { - "address": "ethm1fl48vsnmsdzcv85q5d2q4z5ajdha8yu3w48d64", - "pub_key": null, - "account_number": "3", - "sequence": "0" - }, - "name": "bonded_tokens_pool", - "permissions": [ - "burner", - "staking" - ] - }, - { - "@type": "/cosmos.auth.v1beta1.ModuleAccount", - "base_account": { - "address": "ethm1tygms3xhhs3yv487phx3dw4a95jn7t7l64muvp", - "pub_key": null, - "account_number": "4", - "sequence": "0" - }, - "name": "not_bonded_tokens_pool", - "permissions": [ - "burner", - "staking" - ] - }, - { - "@type": "/cosmos.auth.v1beta1.BaseAccount", - "address": "ethm1dakgyqjulg29m5fmv992g2y66m9g2mjn6hahwg", - "pub_key": { - "@type": "/ethermint.crypto.v1.ethsecp256k1.PubKey", - "key": "AyzS/NPje8oX+4+4uWP9f3060duAFXh3MpNWELtTxPz1" - }, - "account_number": "0", - "sequence": "1" - }, - { - "@type": "/cosmos.auth.v1beta1.ModuleAccount", - "base_account": { - "address": "ethm1wztruvatpslu6ngetc65272cshcnzsxgphqyau", - "pub_key": null, - "account_number": "8", - "sequence": "0" - }, - "name": "poa", - "permissions": [ - "minter", - "burner" - ] - }, - { - "@type": "/cosmos.auth.v1beta1.ModuleAccount", - "base_account": { - "address": "ethm10d07y265gmmuvt4z0w9aw880jnsr700jpva843", - "pub_key": null, - "account_number": "5", - "sequence": "0" - }, - "name": "gov", - "permissions": [ - "burner" - ] - }, - { - "@type": "/cosmos.auth.v1beta1.ModuleAccount", - "base_account": { - "address": "ethm1jv65s3grqf6v6jl3dp4t6c9t9rk99cd8u3272a", - "pub_key": null, - "account_number": "2", - "sequence": "0" - }, - "name": "distribution", - "permissions": [] - }, - { - "@type": "/ethermint.types.v1.EthAccount", - "base_account": { - "address": "ethm16j2fvexdsfnq4t5ehmwqxjsda29qh4gh75fmg2", - "pub_key": null, - "account_number": "6", - "sequence": "0" - }, - "code_hash": "0x7b477c761b4d0469f03f27ba58d0a7eacbfdd62b69b82c6c683ae5f81c67fe80" - }, - { - "@type": "/cosmos.auth.v1beta1.ModuleAccount", - "base_account": { - "address": "ethm17xpfvakm2amg962yls6f84z3kell8c5lthdzgl", - "pub_key": null, - "account_number": "1", - "sequence": "0" - }, - "name": "fee_collector", - "permissions": [] - } - ] - }, - "authz": { - "authorization": [] - }, - "bank": { - "params": { - "send_enabled": [], - "default_send_enabled": true - }, - "balances": [ - { - "address": "ethm1fl48vsnmsdzcv85q5d2q4z5ajdha8yu3w48d64", - "coins": [ - { - "denom": "apoa", - "amount": "1000000" - } - ] - }, - { - "address": "ethm1dakgyqjulg29m5fmv992g2y66m9g2mjn6hahwg", - "coins": [ - { - "denom": "token", - "amount": "1000000000000000000000000000" - } - ] - } - ], - "supply": [ - { - "denom": "apoa", - "amount": "1000000" - }, - { - "denom": "token", - "amount": "1000000000000000000000000000" - } - ], - "denom_metadata": [], - "send_enabled": [] - }, - "capability": { - "index": "3", - "owners": [ - { - "index": "1", - "index_owners": { - "owners": [ - { - "module": "ibc", - "name": "ports/transfer" - }, - { - "module": "transfer", - "name": "ports/transfer" - } - ] - } - }, - { - "index": "2", - "index_owners": { - "owners": [ - { - "module": "ibc", - "name": "ports/icahost" - }, - { - "module": "icahost", - "name": "ports/icahost" - } - ] - } - } - ] - }, - "crisis": { - "constant_fee": { - "denom": "token", - "amount": "1000" - } - }, - "distribution": { - "params": { - "community_tax": "0.020000000000000000", - "base_proposer_reward": "0.000000000000000000", - "bonus_proposer_reward": "0.000000000000000000", - "withdraw_addr_enabled": true - }, - "fee_pool": { - "community_pool": [] - }, - "delegator_withdraw_infos": [], - "previous_proposer": "ethmvalcons123s7tvluhrla7tpj5mwysxqlcgwwzwavxenru7", - "outstanding_rewards": [ - { - "validator_address": "ethmvaloper1dakgyqjulg29m5fmv992g2y66m9g2mjn48hmk4", - "outstanding_rewards": [] - } - ], - "validator_accumulated_commissions": [ - { - "validator_address": "ethmvaloper1dakgyqjulg29m5fmv992g2y66m9g2mjn48hmk4", - "accumulated": { - "commission": [] - } - } - ], - "validator_historical_rewards": [ - { - "validator_address": "ethmvaloper1dakgyqjulg29m5fmv992g2y66m9g2mjn48hmk4", - "period": "1", - "rewards": { - "cumulative_reward_ratio": [], - "reference_count": 2 - } - } - ], - "validator_current_rewards": [ - { - "validator_address": "ethmvaloper1dakgyqjulg29m5fmv992g2y66m9g2mjn48hmk4", - "rewards": { - "rewards": [], - "period": "2" - } - } - ], - "delegator_starting_infos": [ - { - "delegator_address": "ethm1dakgyqjulg29m5fmv992g2y66m9g2mjn6hahwg", - "validator_address": "ethmvaloper1dakgyqjulg29m5fmv992g2y66m9g2mjn48hmk4", - "starting_info": { - "previous_period": "1", - "stake": "1000000.000000000000000000", - "height": "0" - } - } - ], - "validator_slash_events": [] - }, - "erc20": { - "params": { - "enable_erc20": true, - "native_precompiles": [ - "0xD4949664cD82660AaE99bEdc034a0deA8A0bd517" - ], - "dynamic_precompiles": [] - }, - "token_pairs": [ - { - "erc20_address": "0xD4949664cD82660AaE99bEdc034a0deA8A0bd517", - "denom": "token", - "enabled": true, - "contract_owner": "OWNER_MODULE", - "owner_address": "ethm1zrxl239wa6ad5xge3gs68rt98227xgnjq0xyw2" - } - ] - }, - "evidence": { - "evidence": [] - }, - "evm": { - "accounts": [ - { - "address": "0xD4949664cD82660AaE99bEdc034a0deA8A0bd517", - "code": "608060405234801561001057600080fd5b50600436106101da5760003560e01c80635c975abb11610104578063a217fddf116100a2578063d539139311610071578063d53913931461057d578063d547741f1461059b578063dd62ed3e146105b7578063e63ab1e9146105e7576101da565b8063a217fddf146104cf578063a457c2d7146104ed578063a9059cbb1461051d578063ca15c8731461054d576101da565b80638456cb59116100de5780638456cb59146104475780639010d07c1461045157806391d148541461048157806395d89b41146104b1576101da565b80635c975abb146103dd57806370a08231146103fb57806379cc67901461042b576101da565b8063282c51f31161017c578063395093511161014b578063395093511461036b5780633f4ba83a1461039b57806340c10f19146103a557806342966c68146103c1576101da565b8063282c51f3146102f75780632f2ff15d14610315578063313ce5671461033157806336568abe1461034f576101da565b806318160ddd116101b857806318160ddd1461025d5780631cf2c7e21461027b57806323b872dd14610297578063248a9ca3146102c7576101da565b806301ffc9a7146101df57806306fdde031461020f578063095ea7b31461022d575b600080fd5b6101f960048036038101906101f49190612216565b610605565b604051610206919061225e565b60405180910390f35b61021761067f565b6040516102249190612312565b60405180910390f35b610247600480360381019061024291906123c8565b610711565b604051610254919061225e565b60405180910390f35b61026561072f565b6040516102729190612417565b60405180910390f35b610295600480360381019061029091906123c8565b610739565b005b6102b160048036038101906102ac9190612432565b6107b7565b6040516102be919061225e565b60405180910390f35b6102e160048036038101906102dc91906124bb565b6108af565b6040516102ee91906124f7565b60405180910390f35b6102ff6108ce565b60405161030c91906124f7565b60405180910390f35b61032f600480360381019061032a9190612512565b6108f2565b005b61033961091b565b604051610346919061256e565b60405180910390f35b61036960048036038101906103649190612512565b610932565b005b610385600480360381019061038091906123c8565b6109b5565b604051610392919061225e565b60405180910390f35b6103a3610a61565b005b6103bf60048036038101906103ba91906123c8565b610adb565b005b6103db60048036038101906103d69190612589565b610b59565b005b6103e5610b6d565b6040516103f2919061225e565b60405180910390f35b610415600480360381019061041091906125b6565b610b84565b6040516104229190612417565b60405180910390f35b610445600480360381019061044091906123c8565b610bcd565b005b61044f610c48565b005b61046b600480360381019061046691906125e3565b610cc2565b6040516104789190612632565b60405180910390f35b61049b60048036038101906104969190612512565b610cf1565b6040516104a8919061225e565b60405180910390f35b6104b9610d5b565b6040516104c69190612312565b60405180910390f35b6104d7610ded565b6040516104e491906124f7565b60405180910390f35b610507600480360381019061050291906123c8565b610df4565b604051610514919061225e565b60405180910390f35b610537600480360381019061053291906123c8565b610edf565b604051610544919061225e565b60405180910390f35b610567600480360381019061056291906124bb565b610efd565b6040516105749190612417565b60405180910390f35b610585610f21565b60405161059291906124f7565b60405180910390f35b6105b560048036038101906105b09190612512565b610f45565b005b6105d160048036038101906105cc919061264d565b610f6e565b6040516105de9190612417565b60405180910390f35b6105ef610ff5565b6040516105fc91906124f7565b60405180910390f35b60007f5a05180f000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19161480610678575061067782611129565b5b9050919050565b60606005805461068e906126bc565b80601f01602080910402602001604051908101604052809291908181526020018280546106ba906126bc565b80156107075780601f106106dc57610100808354040283529160200191610707565b820191906000526020600020905b8154815290600101906020018083116106ea57829003601f168201915b5050505050905090565b600061072561071e6111a3565b84846111ab565b6001905092915050565b6000600454905090565b61076a7f3c11d16cbaffd01df69ce1c404f6340ee057498f5f00246190ea54220576a8486107656111a3565b610cf1565b6107a9576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016107a090612760565b60405180910390fd5b6107b38282611376565b5050565b60006107c484848461154f565b6000600360008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600061080f6111a3565b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205490508281101561088f576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610886906127f2565b60405180910390fd5b6108a38561089b6111a3565b8584036111ab565b60019150509392505050565b6000806000838152602001908152602001600020600101549050919050565b7f3c11d16cbaffd01df69ce1c404f6340ee057498f5f00246190ea54220576a84881565b6108fb826108af565b61090c816109076111a3565b6117d3565b6109168383611870565b505050565b6000600760019054906101000a900460ff16905090565b61093a6111a3565b73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16146109a7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161099e90612884565b60405180910390fd5b6109b182826118a4565b5050565b6000610a576109c26111a3565b8484600360006109d06111a3565b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054610a5291906128d3565b6111ab565b6001905092915050565b610a927f65d7a28e3265b37a6474929f336521b332c1681b933f6cb9f3376673440d862a610a8d6111a3565b610cf1565b610ad1576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610ac89061299b565b60405180910390fd5b610ad96118d8565b565b610b0c7f9f2df0fed2c77648de5860a4cc508cd0818c85b8b8a1ab4ceeef8d981c8956a6610b076111a3565b610cf1565b610b4b576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610b4290612a2d565b60405180910390fd5b610b55828261197a565b5050565b610b6a610b646111a3565b82611376565b50565b6000600760009054906101000a900460ff16905090565b6000600260008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050919050565b6000610be083610bdb6111a3565b610f6e565b905081811015610c25576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610c1c90612abf565b60405180910390fd5b610c3983610c316111a3565b8484036111ab565b610c438383611376565b505050565b610c797f65d7a28e3265b37a6474929f336521b332c1681b933f6cb9f3376673440d862a610c746111a3565b610cf1565b610cb8576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610caf90612b51565b60405180910390fd5b610cc0611adb565b565b6000610ce98260016000868152602001908152602001600020611b7e90919063ffffffff16565b905092915050565b600080600084815260200190815260200160002060000160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16905092915050565b606060068054610d6a906126bc565b80601f0160208091040260200160405190810160405280929190818152602001828054610d96906126bc565b8015610de35780601f10610db857610100808354040283529160200191610de3565b820191906000526020600020905b815481529060010190602001808311610dc657829003601f168201915b5050505050905090565b6000801b81565b60008060036000610e036111a3565b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054905082811015610ec0576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610eb790612be3565b60405180910390fd5b610ed4610ecb6111a3565b858584036111ab565b600191505092915050565b6000610ef3610eec6111a3565b848461154f565b6001905092915050565b6000610f1a60016000848152602001908152602001600020611b98565b9050919050565b7f9f2df0fed2c77648de5860a4cc508cd0818c85b8b8a1ab4ceeef8d981c8956a681565b610f4e826108af565b610f5f81610f5a6111a3565b6117d3565b610f6983836118a4565b505050565b6000600360008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054905092915050565b7f65d7a28e3265b37a6474929f336521b332c1681b933f6cb9f3376673440d862a81565b6110238282610cf1565b6110f557600160008084815260200190815260200160002060000160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff02191690831515021790555061109a6111a3565b73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45b5050565b6000611121836000018373ffffffffffffffffffffffffffffffffffffffff1660001b611bad565b905092915050565b60007f7965db0b000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916148061119c575061119b82611c1d565b5b9050919050565b600033905090565b600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16141561121b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161121290612c75565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16141561128b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161128290612d07565b60405180910390fd5b80600360008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925836040516113699190612417565b60405180910390a3505050565b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614156113e6576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016113dd90612d99565b60405180910390fd5b6113f282600083611c87565b6000600260008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054905081811015611479576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161147090612e2b565b60405180910390fd5b818103600260008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190555081600460008282546114d19190612e4b565b92505081905550600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef846040516115369190612417565b60405180910390a361154a83600084611c97565b505050565b600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1614156115bf576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016115b690612ef1565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16141561162f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161162690612f83565b60405180910390fd5b61163a838383611c87565b6000600260008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050818110156116c1576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016116b890613015565b60405180910390fd5b818103600260008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190555081600260008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825461175691906128d3565b925050819055508273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef846040516117ba9190612417565b60405180910390a36117cd848484611c97565b50505050565b6117dd8282610cf1565b61186c576118028173ffffffffffffffffffffffffffffffffffffffff166014611c9c565b6118108360001c6020611c9c565b604051602001611821929190613109565b6040516020818303038152906040526040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016118639190612312565b60405180910390fd5b5050565b61187a8282611019565b61189f81600160008581526020019081526020016000206110f990919063ffffffff16565b505050565b6118ae8282611ed8565b6118d38160016000858152602001908152602001600020611fb990919063ffffffff16565b505050565b6118e0610b6d565b61191f576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016119169061318f565b60405180910390fd5b6000600760006101000a81548160ff0219169083151502179055507f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa6119636111a3565b6040516119709190612632565b60405180910390a1565b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614156119ea576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016119e1906131fb565b60405180910390fd5b6119f660008383611c87565b8060046000828254611a0891906128d3565b9250508190555080600260008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254611a5e91906128d3565b925050819055508173ffffffffffffffffffffffffffffffffffffffff16600073ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef83604051611ac39190612417565b60405180910390a3611ad760008383611c97565b5050565b611ae3610b6d565b15611b23576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611b1a90613267565b60405180910390fd5b6001600760006101000a81548160ff0219169083151502179055507f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258611b676111a3565b604051611b749190612632565b60405180910390a1565b6000611b8d8360000183611fe9565b60001c905092915050565b6000611ba682600001612014565b9050919050565b6000611bb98383612025565b611c12578260000182908060018154018082558091505060019003906000526020600020016000909190919091505582600001805490508360010160008481526020019081526020016000208190555060019050611c17565b600090505b92915050565b60007f01ffc9a7000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916149050919050565b611c92838383612048565b505050565b505050565b606060006002836002611caf9190613287565b611cb991906128d3565b67ffffffffffffffff811115611cd257611cd16132e1565b5b6040519080825280601f01601f191660200182016040528015611d045781602001600182028036833780820191505090505b5090507f300000000000000000000000000000000000000000000000000000000000000081600081518110611d3c57611d3b613310565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053507f780000000000000000000000000000000000000000000000000000000000000081600181518110611da057611d9f613310565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a90535060006001846002611de09190613287565b611dea91906128d3565b90505b6001811115611e8a577f3031323334353637383961626364656600000000000000000000000000000000600f861660108110611e2c57611e2b613310565b5b1a60f81b828281518110611e4357611e42613310565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a905350600485901c945080611e839061333f565b9050611ded565b5060008414611ece576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611ec5906133b5565b60405180910390fd5b8091505092915050565b611ee28282610cf1565b15611fb557600080600084815260200190815260200160002060000160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff021916908315150217905550611f5a6111a3565b73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16837ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b60405160405180910390a45b5050565b6000611fe1836000018373ffffffffffffffffffffffffffffffffffffffff1660001b6120a0565b905092915050565b600082600001828154811061200157612000613310565b5b9060005260206000200154905092915050565b600081600001805490509050919050565b600080836001016000848152602001908152602001600020541415905092915050565b6120538383836121b4565b61205b610b6d565b1561209b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161209290613447565b60405180910390fd5b505050565b600080836001016000848152602001908152602001600020549050600081146121a85760006001826120d29190612e4b565b90506000600186600001805490506120ea9190612e4b565b905081811461215957600086600001828154811061210b5761210a613310565b5b906000526020600020015490508087600001848154811061212f5761212e613310565b5b90600052602060002001819055508387600101600083815260200190815260200160002081905550505b8560000180548061216d5761216c613467565b5b6001900381819060005260206000200160009055905585600101600086815260200190815260200160002060009055600193505050506121ae565b60009150505b92915050565b505050565b600080fd5b60007fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b6121f3816121be565b81146121fe57600080fd5b50565b600081359050612210816121ea565b92915050565b60006020828403121561222c5761222b6121b9565b5b600061223a84828501612201565b91505092915050565b60008115159050919050565b61225881612243565b82525050565b6000602082019050612273600083018461224f565b92915050565b600081519050919050565b600082825260208201905092915050565b60005b838110156122b3578082015181840152602081019050612298565b838111156122c2576000848401525b50505050565b6000601f19601f8301169050919050565b60006122e482612279565b6122ee8185612284565b93506122fe818560208601612295565b612307816122c8565b840191505092915050565b6000602082019050818103600083015261232c81846122d9565b905092915050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b600061235f82612334565b9050919050565b61236f81612354565b811461237a57600080fd5b50565b60008135905061238c81612366565b92915050565b6000819050919050565b6123a581612392565b81146123b057600080fd5b50565b6000813590506123c28161239c565b92915050565b600080604083850312156123df576123de6121b9565b5b60006123ed8582860161237d565b92505060206123fe858286016123b3565b9150509250929050565b61241181612392565b82525050565b600060208201905061242c6000830184612408565b92915050565b60008060006060848603121561244b5761244a6121b9565b5b60006124598682870161237d565b935050602061246a8682870161237d565b925050604061247b868287016123b3565b9150509250925092565b6000819050919050565b61249881612485565b81146124a357600080fd5b50565b6000813590506124b58161248f565b92915050565b6000602082840312156124d1576124d06121b9565b5b60006124df848285016124a6565b91505092915050565b6124f181612485565b82525050565b600060208201905061250c60008301846124e8565b92915050565b60008060408385031215612529576125286121b9565b5b6000612537858286016124a6565b92505060206125488582860161237d565b9150509250929050565b600060ff82169050919050565b61256881612552565b82525050565b6000602082019050612583600083018461255f565b92915050565b60006020828403121561259f5761259e6121b9565b5b60006125ad848285016123b3565b91505092915050565b6000602082840312156125cc576125cb6121b9565b5b60006125da8482850161237d565b91505092915050565b600080604083850312156125fa576125f96121b9565b5b6000612608858286016124a6565b9250506020612619858286016123b3565b9150509250929050565b61262c81612354565b82525050565b60006020820190506126476000830184612623565b92915050565b60008060408385031215612664576126636121b9565b5b60006126728582860161237d565b92505060206126838582860161237d565b9150509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b600060028204905060018216806126d457607f821691505b602082108114156126e8576126e761268d565b5b50919050565b7f45524332304d696e7465724275726e6572446563696d616c733a206d7573742060008201527f68617665206275726e657220726f6c6520746f206275726e0000000000000000602082015250565b600061274a603883612284565b9150612755826126ee565b604082019050919050565b600060208201905081810360008301526127798161273d565b9050919050565b7f45524332303a207472616e7366657220616d6f756e742065786365656473206160008201527f6c6c6f77616e6365000000000000000000000000000000000000000000000000602082015250565b60006127dc602883612284565b91506127e782612780565b604082019050919050565b6000602082019050818103600083015261280b816127cf565b9050919050565b7f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560008201527f20726f6c657320666f722073656c660000000000000000000000000000000000602082015250565b600061286e602f83612284565b915061287982612812565b604082019050919050565b6000602082019050818103600083015261289d81612861565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60006128de82612392565b91506128e983612392565b9250827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0382111561291e5761291d6128a4565b5b828201905092915050565b7f45524332304d696e7465724275726e6572446563696d616c733a206d7573742060008201527f686176652070617573657220726f6c6520746f20756e70617573650000000000602082015250565b6000612985603b83612284565b915061299082612929565b604082019050919050565b600060208201905081810360008301526129b481612978565b9050919050565b7f45524332304d696e7465724275726e6572446563696d616c733a206d7573742060008201527f68617665206d696e74657220726f6c6520746f206d696e740000000000000000602082015250565b6000612a17603883612284565b9150612a22826129bb565b604082019050919050565b60006020820190508181036000830152612a4681612a0a565b9050919050565b7f45524332303a206275726e20616d6f756e74206578636565647320616c6c6f7760008201527f616e636500000000000000000000000000000000000000000000000000000000602082015250565b6000612aa9602483612284565b9150612ab482612a4d565b604082019050919050565b60006020820190508181036000830152612ad881612a9c565b9050919050565b7f45524332304d696e7465724275726e6572446563696d616c733a206d7573742060008201527f686176652070617573657220726f6c6520746f20706175736500000000000000602082015250565b6000612b3b603983612284565b9150612b4682612adf565b604082019050919050565b60006020820190508181036000830152612b6a81612b2e565b9050919050565b7f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f7760008201527f207a65726f000000000000000000000000000000000000000000000000000000602082015250565b6000612bcd602583612284565b9150612bd882612b71565b604082019050919050565b60006020820190508181036000830152612bfc81612bc0565b9050919050565b7f45524332303a20617070726f76652066726f6d20746865207a65726f2061646460008201527f7265737300000000000000000000000000000000000000000000000000000000602082015250565b6000612c5f602483612284565b9150612c6a82612c03565b604082019050919050565b60006020820190508181036000830152612c8e81612c52565b9050919050565b7f45524332303a20617070726f766520746f20746865207a65726f20616464726560008201527f7373000000000000000000000000000000000000000000000000000000000000602082015250565b6000612cf1602283612284565b9150612cfc82612c95565b604082019050919050565b60006020820190508181036000830152612d2081612ce4565b9050919050565b7f45524332303a206275726e2066726f6d20746865207a65726f2061646472657360008201527f7300000000000000000000000000000000000000000000000000000000000000602082015250565b6000612d83602183612284565b9150612d8e82612d27565b604082019050919050565b60006020820190508181036000830152612db281612d76565b9050919050565b7f45524332303a206275726e20616d6f756e7420657863656564732062616c616e60008201527f6365000000000000000000000000000000000000000000000000000000000000602082015250565b6000612e15602283612284565b9150612e2082612db9565b604082019050919050565b60006020820190508181036000830152612e4481612e08565b9050919050565b6000612e5682612392565b9150612e6183612392565b925082821015612e7457612e736128a4565b5b828203905092915050565b7f45524332303a207472616e736665722066726f6d20746865207a65726f20616460008201527f6472657373000000000000000000000000000000000000000000000000000000602082015250565b6000612edb602583612284565b9150612ee682612e7f565b604082019050919050565b60006020820190508181036000830152612f0a81612ece565b9050919050565b7f45524332303a207472616e7366657220746f20746865207a65726f206164647260008201527f6573730000000000000000000000000000000000000000000000000000000000602082015250565b6000612f6d602383612284565b9150612f7882612f11565b604082019050919050565b60006020820190508181036000830152612f9c81612f60565b9050919050565b7f45524332303a207472616e7366657220616d6f756e742065786365656473206260008201527f616c616e63650000000000000000000000000000000000000000000000000000602082015250565b6000612fff602683612284565b915061300a82612fa3565b604082019050919050565b6000602082019050818103600083015261302e81612ff2565b9050919050565b600081905092915050565b7f416363657373436f6e74726f6c3a206163636f756e7420000000000000000000600082015250565b6000613076601783613035565b915061308182613040565b601782019050919050565b600061309782612279565b6130a18185613035565b93506130b1818560208601612295565b80840191505092915050565b7f206973206d697373696e6720726f6c6520000000000000000000000000000000600082015250565b60006130f3601183613035565b91506130fe826130bd565b601182019050919050565b600061311482613069565b9150613120828561308c565b915061312b826130e6565b9150613137828461308c565b91508190509392505050565b7f5061757361626c653a206e6f7420706175736564000000000000000000000000600082015250565b6000613179601483612284565b915061318482613143565b602082019050919050565b600060208201905081810360008301526131a88161316c565b9050919050565b7f45524332303a206d696e7420746f20746865207a65726f206164647265737300600082015250565b60006131e5601f83612284565b91506131f0826131af565b602082019050919050565b60006020820190508181036000830152613214816131d8565b9050919050565b7f5061757361626c653a2070617573656400000000000000000000000000000000600082015250565b6000613251601083612284565b915061325c8261321b565b602082019050919050565b6000602082019050818103600083015261328081613244565b9050919050565b600061329282612392565b915061329d83612392565b9250817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04831182151516156132d6576132d56128a4565b5b828202905092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600061334a82612392565b9150600082141561335e5761335d6128a4565b5b600182039050919050565b7f537472696e67733a20686578206c656e67746820696e73756666696369656e74600082015250565b600061339f602083612284565b91506133aa82613369565b602082019050919050565b600060208201905081810360008301526133ce81613392565b9050919050565b7f45524332305061757361626c653a20746f6b656e207472616e7366657220776860008201527f696c652070617573656400000000000000000000000000000000000000000000602082015250565b6000613431602a83612284565b915061343c826133d5565b604082019050919050565b6000602082019050818103600083015261346081613424565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fdfea2646970667358221220c3d4a4231a6c94cfb03623ea4b77df2c9ccfa487132bebf43620219e3dc2f4cf64736f6c63430008090033", - "storage": [] - } - ], - "params": { - "evm_denom": "token", - "extra_eips": [ - "ethereum_3855" - ], - "chain_config": { - "homestead_block": "0", - "dao_fork_block": "0", - "dao_fork_support": true, - "eip150_block": "0", - "eip150_hash": "0x0000000000000000000000000000000000000000000000000000000000000000", - "eip155_block": "0", - "eip158_block": "0", - "byzantium_block": "0", - "constantinople_block": "0", - "petersburg_block": "0", - "istanbul_block": "0", - "muir_glacier_block": "0", - "berlin_block": "0", - "london_block": "0", - "arrow_glacier_block": "0", - "gray_glacier_block": "0", - "merge_netsplit_block": "0", - "shanghai_block": "0", - "cancun_block": "0" - }, - "allow_unprotected_txs": true, - "evm_channels": [ - "channel-10", - "channel-31", - "channel-83" - ], - "access_control": { - "create": { - "access_type": "ACCESS_TYPE_PERMISSIONLESS", - "access_control_list": [] - }, - "call": { - "access_type": "ACCESS_TYPE_PERMISSIONLESS", - "access_control_list": [] - } - }, - "active_static_precompiles": [ - "0x0000000000000000000000000000000000000100", - "0x0000000000000000000000000000000000000400", - "0x0000000000000000000000000000000000000800", - "0x0000000000000000000000000000000000000801", - "0x0000000000000000000000000000000000000802", - "0x0000000000000000000000000000000000000803", - "0x0000000000000000000000000000000000000804", - "0x0000000000000000000000000000000000000805" - ] - } - }, - "feegrant": { - "allowances": [] - }, - "feemarket": { - "params": { - "no_base_fee": false, - "base_fee_change_denominator": 8, - "elasticity_multiplier": 2, - "enable_height": "0", - "base_fee": "0", - "min_gas_price": "0.000000000000000000", - "min_gas_multiplier": "0.500000000000000000" - }, - "block_gas": "0" - }, - "genutil": { - "gen_txs": [] - }, - "gov": { - "starting_proposal_id": "1", - "deposits": [], - "votes": [], - "proposals": [], - "deposit_params": null, - "voting_params": null, - "tally_params": null, - "params": { - "min_deposit": [ - { - "denom": "token", - "amount": "1" - } - ], - "max_deposit_period": "172800s", - "voting_period": "10s", - "quorum": "0.334000000000000000", - "threshold": "0.500000000000000000", - "veto_threshold": "0.334000000000000000", - "min_initial_deposit_ratio": "0.000000000000000000", - "proposal_cancel_ratio": "0.500000000000000000", - "proposal_cancel_dest": "", - "expedited_voting_period": "5s", - "expedited_threshold": "0.667000000000000000", - "expedited_min_deposit": [ - { - "denom": "stake", - "amount": "50000000" - } - ], - "burn_vote_quorum": false, - "burn_proposal_deposit_prevote": false, - "burn_vote_veto": true, - "min_deposit_ratio": "0.010000000000000000" - }, - "constitution": "" - }, - "ibc": { - "client_genesis": { - "clients": [ - { - "client_id": "09-localhost", - "client_state": { - "@type": "/ibc.lightclients.localhost.v2.ClientState", - "latest_height": { - "revision_number": "1", - "revision_height": "7" - } - } - } - ], - "clients_consensus": [], - "clients_metadata": [], - "params": { - "allowed_clients": [ - "*" - ] - }, - "create_localhost": false, - "next_client_sequence": "0" - }, - "connection_genesis": { - "connections": [ - { - "id": "connection-localhost", - "client_id": "09-localhost", - "versions": [ - { - "identifier": "1", - "features": [ - "ORDER_ORDERED", - "ORDER_UNORDERED" - ] - } - ], - "state": "STATE_OPEN", - "counterparty": { - "client_id": "09-localhost", - "connection_id": "connection-localhost", - "prefix": { - "key_prefix": "aWJj" - } - }, - "delay_period": "0" - } - ], - "client_connection_paths": [], - "next_connection_sequence": "0", - "params": { - "max_expected_time_per_block": "30000000000" - } - }, - "channel_genesis": { - "channels": [], - "acknowledgements": [], - "commitments": [], - "receipts": [], - "send_sequences": [], - "recv_sequences": [], - "ack_sequences": [], - "next_channel_sequence": "0", - "params": { - "upgrade_timeout": { - "height": { - "revision_number": "0", - "revision_height": "0" - }, - "timestamp": "600000000000" - } - } - } - }, - "interchainaccounts": { - "controller_genesis_state": { - "active_channels": [], - "interchain_accounts": [], - "ports": [], - "params": { - "controller_enabled": true - } - }, - "host_genesis_state": { - "active_channels": [], - "interchain_accounts": [], - "port": "icahost", - "params": { - "host_enabled": true, - "allow_messages": [ - "*" - ] - } - } - }, - "poa": { - "params": {} - }, - "ratelimit": { - "params": {}, - "rate_limits": [], - "whitelisted_address_pairs": [], - "blacklisted_denoms": [], - "pending_send_packet_sequence_numbers": [], - "hour_epoch": { - "epoch_number": "17", - "duration": "3600s", - "epoch_start_time": "2024-11-27T17:00:00Z", - "epoch_start_height": "0" - } - }, - "slashing": { - "params": { - "signed_blocks_window": "100", - "min_signed_per_window": "0.500000000000000000", - "downtime_jail_duration": "600s", - "slash_fraction_double_sign": "0.000000000000000000", - "slash_fraction_downtime": "0.000000000000000000" - }, - "signing_infos": [ - { - "address": "ethmvalcons123s7tvluhrla7tpj5mwysxqlcgwwzwavxenru7", - "validator_signing_info": { - "address": "ethmvalcons123s7tvluhrla7tpj5mwysxqlcgwwzwavxenru7", - "start_height": "0", - "index_offset": "6", - "jailed_until": "1970-01-01T00:00:00Z", - "tombstoned": false, - "missed_blocks_counter": "0" - } - } - ], - "missed_blocks": [ - { - "address": "ethmvalcons123s7tvluhrla7tpj5mwysxqlcgwwzwavxenru7", - "missed_blocks": [] - } - ] - }, - "staking": { - "params": { - "unbonding_time": "60s", - "max_validators": 100, - "max_entries": 7, - "historical_entries": 10000, - "bond_denom": "apoa", - "min_commission_rate": "0.000000000000000000" - }, - "last_total_power": "1", - "last_validator_powers": [ - { - "address": "ethmvaloper1dakgyqjulg29m5fmv992g2y66m9g2mjn48hmk4", - "power": "1" - } - ], - "validators": [ - { - "operator_address": "ethmvaloper1dakgyqjulg29m5fmv992g2y66m9g2mjn48hmk4", - "consensus_pubkey": { - "@type": "/cosmos.crypto.ed25519.PubKey", - "key": "x39TSSHGypcFLoD91nkVBQTiRT/KcVnnvyJrnXn0Bps=" - }, - "jailed": false, - "status": "BOND_STATUS_BONDED", - "tokens": "1000000", - "delegator_shares": "1000000.000000000000000000", - "description": { - "moniker": "localnet", - "identity": "", - "website": "", - "security_contact": "", - "details": "" - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "0.100000000000000000", - "max_rate": "0.200000000000000000", - "max_change_rate": "0.010000000000000000" - }, - "update_time": "2024-11-27T17:14:04.871328Z" - }, - "min_self_delegation": "1", - "unbonding_on_hold_ref_count": "0", - "unbonding_ids": [] - } - ], - "delegations": [ - { - "delegator_address": "ethm1dakgyqjulg29m5fmv992g2y66m9g2mjn6hahwg", - "validator_address": "ethmvaloper1dakgyqjulg29m5fmv992g2y66m9g2mjn48hmk4", - "shares": "1000000.000000000000000000" - } - ], - "unbonding_delegations": [], - "redelegations": [], - "exported": true - }, - "transfer": { - "port_id": "transfer", - "denom_traces": [], - "params": { - "send_enabled": true, - "receive_enabled": true - }, - "total_escrowed": [] - }, - "upgrade": {} - }, - "consensus": { - "validators": [ - { - "address": "5461E5B3FCB8FFDF2C32A6DC48181FC21CE13BAC", - "pub_key": { - "type": "tendermint/PubKeyEd25519", - "value": "x39TSSHGypcFLoD91nkVBQTiRT/KcVnnvyJrnXn0Bps=" - }, - "power": "1", - "name": "localnet" - } - ], - "params": { - "block": { - "max_bytes": 22020096, - "max_gas": 10500000 - }, - "evidence": { - "max_age_num_blocks": 100000, - "max_age_duration": 172800000000000, - "max_bytes": 1048576 - }, - "validator": { - "pub_key_types": [ - "ed25519" - ] - }, - "version": { - "app": 0 - }, - "abci": { - "vote_extensions_enable_height": 0 - } - } - } -} \ No newline at end of file From b2ae9095c5ff88083f3b0faab40fb949973bb423 Mon Sep 17 00:00:00 2001 From: GuillemGarciaDev Date: Tue, 28 Jan 2025 19:04:58 +0000 Subject: [PATCH 04/25] feat(tests): upgrade integration testutil --- app/upgrades/vtest/constants.go | 5 + app/upgrades/vtest/upgrades.go | 21 ++++ tests/upgrade/suite.go | 13 +-- tests/upgrade/suite_test.go | 18 ---- tests/upgrade/testutil/db.go | 23 ----- testutil/integration/exrp/common/clients.go | 12 ++- testutil/integration/exrp/common/config.go | 1 + testutil/integration/exrp/common/setup.go | 10 +- .../integration/exrp/integration/keepers.go | 5 + testutil/integration/exrp/upgrade/config.go | 7 ++ testutil/integration/exrp/upgrade/keepers.go | 5 + testutil/integration/exrp/upgrade/network.go | 95 +++++++------------ testutil/integration/exrp/upgrade/setup.go | 44 +++++++++ 13 files changed, 141 insertions(+), 118 deletions(-) create mode 100644 app/upgrades/vtest/constants.go create mode 100644 app/upgrades/vtest/upgrades.go delete mode 100644 tests/upgrade/testutil/db.go create mode 100644 testutil/integration/exrp/upgrade/setup.go diff --git a/app/upgrades/vtest/constants.go b/app/upgrades/vtest/constants.go new file mode 100644 index 0000000..9052900 --- /dev/null +++ b/app/upgrades/vtest/constants.go @@ -0,0 +1,5 @@ +package v6 + +const ( + UpgradeName = "v6.0.0" +) diff --git a/app/upgrades/vtest/upgrades.go b/app/upgrades/vtest/upgrades.go new file mode 100644 index 0000000..c2a6e27 --- /dev/null +++ b/app/upgrades/vtest/upgrades.go @@ -0,0 +1,21 @@ +package v6 + +import ( + "context" + + upgradetypes "cosmossdk.io/x/upgrade/types" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/module" +) + +func CreateUpgradeHandler( + mm *module.Manager, + configurator module.Configurator, +) upgradetypes.UpgradeHandler { + return func(c context.Context, _ upgradetypes.Plan, vm module.VersionMap) (module.VersionMap, error) { + ctx := sdk.UnwrapSDKContext(c) + logger := ctx.Logger().With("upgrade", UpgradeName) + logger.Info("Running v6 upgrade handler...") + return mm.RunMigrations(ctx, configurator, vm) + } +} diff --git a/tests/upgrade/suite.go b/tests/upgrade/suite.go index 45b9f29..dfded14 100644 --- a/tests/upgrade/suite.go +++ b/tests/upgrade/suite.go @@ -1,12 +1,9 @@ package testupgrade import ( - dbm "github.com/cosmos/cosmos-db" - "github.com/cosmos/cosmos-sdk/baseapp" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/stretchr/testify/suite" - "github.com/xrplevm/node/v5/tests/upgrade/testutil" - exrpcommon "github.com/xrplevm/node/v5/testutil/integration/exrp/common" + exrpupgrade "github.com/xrplevm/node/v5/testutil/integration/exrp/upgrade" ) const ( @@ -30,16 +27,10 @@ func (s *UpgradeTestSuite) SetupTest() { s.Require().Equal(sdk.GetConfig().GetBech32AccountAddrPrefix(), "ethm") - s.Require().NoError(testutil.CopyNodeDB(DefaultNodeDBDir, DefaultNodeDBDir+"-tmp")) - - db, err := dbm.NewGoLevelDB(DefaultNodeDBName, DefaultNodeDBDir+"-tmp", nil) - s.Require().NoError(err) // Create the network s.network = NewUpgradeTestNetwork( - exrpcommon.WithCustomBaseAppOpts(func(ba *baseapp.BaseApp) { - ba.SetDB(db) - }), + exrpupgrade.WithUpgradePlanName("v6.0.0"), ) // Check that the network was created successfully diff --git a/tests/upgrade/suite_test.go b/tests/upgrade/suite_test.go index 4de919c..ad1634f 100644 --- a/tests/upgrade/suite_test.go +++ b/tests/upgrade/suite_test.go @@ -3,8 +3,6 @@ package testupgrade import ( "testing" - banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" - stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" "github.com/stretchr/testify/suite" "github.com/xrplevm/node/v5/app" ) @@ -17,20 +15,4 @@ func (s *UpgradeTestSuite) TestUpgrade() { denom := s.network.GetDenom() s.Require().NotEmpty(denom) s.Require().Equal(denom, app.BaseDenom) - - balances, err := s.Network().GetBankClient().AllBalances(s.network.GetContext(), &banktypes.QueryAllBalancesRequest{ - Address: "ethm1fl48vsnmsdzcv85q5d2q4z5ajdha8yu3w48d64", - }) - - s.T().Log("balances", balances) - s.Require().NoError(err) - - err = s.network.NextBlock() - s.Require().NoError(err) - - res, err := s.Network().GetStakingClient().Validators(s.network.GetContext(), &stakingtypes.QueryValidatorsRequest{}) - s.Require().NoError(err) - - s.T().Log("validators", len(res.Validators)) - s.Require().Equal(len(res.Validators), 1) } diff --git a/tests/upgrade/testutil/db.go b/tests/upgrade/testutil/db.go deleted file mode 100644 index 87d013f..0000000 --- a/tests/upgrade/testutil/db.go +++ /dev/null @@ -1,23 +0,0 @@ -package testutil - -import ( - "io" - "os" -) - -func CopyNodeDB(from, to string) error { - fromDB, err := os.Open(from) - if err != nil { - return err - } - defer fromDB.Close() - - toDB, err := os.Create(to) - if err != nil { - return err - } - defer toDB.Close() - - _, err = io.Copy(toDB, fromDB) - return err -} diff --git a/testutil/integration/exrp/common/clients.go b/testutil/integration/exrp/common/clients.go index d1e2086..ec7e083 100644 --- a/testutil/integration/exrp/common/clients.go +++ b/testutil/integration/exrp/common/clients.go @@ -21,6 +21,8 @@ import ( stakingkeeper "github.com/cosmos/cosmos-sdk/x/staking/keeper" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" + upgradekeeper "cosmossdk.io/x/upgrade/keeper" + upgradetypes "cosmossdk.io/x/upgrade/types" erc20keeper "github.com/evmos/evmos/v20/x/erc20/keeper" erc20types "github.com/evmos/evmos/v20/x/erc20/types" evmkeeper "github.com/evmos/evmos/v20/x/evm/keeper" @@ -46,14 +48,14 @@ type NetworkKeepers interface { AuthzKeeper() authzkeeper.Keeper FeeMarketKeeper() feemarketkeeper.Keeper PoaKeeper() poakeeper.Keeper + UpgradeKeeper() upgradekeeper.Keeper } func getQueryHelper(ctx sdktypes.Context, encCfg testutil.TestEncodingConfig) *baseapp.QueryServiceTestHelper { interfaceRegistry := encCfg.InterfaceRegistry // This is needed so that state changes are not committed in precompiles // simulations. - cacheCtx, _ := ctx.CacheContext() - return baseapp.NewQueryServerTestHelper(cacheCtx, interfaceRegistry) + return baseapp.NewQueryServerTestHelper(ctx, interfaceRegistry) } func GetERC20Client(n NetworkKeepers) erc20types.QueryClient { @@ -121,3 +123,9 @@ func GetPoaClient(n NetworkKeepers) poatypes.QueryClient { poatypes.RegisterQueryServer(queryHelper, poakeeper.Querier{Keeper: n.PoaKeeper()}) return poatypes.NewQueryClient(queryHelper) } + +func GetUpgradeClient(n NetworkKeepers) upgradetypes.QueryClient { + queryHelper := getQueryHelper(n.GetContext(), n.GetEncodingConfig()) + upgradetypes.RegisterQueryServer(queryHelper, n.UpgradeKeeper()) + return upgradetypes.NewQueryClient(queryHelper) +} diff --git a/testutil/integration/exrp/common/config.go b/testutil/integration/exrp/common/config.go index 4a2ae7f..85efe75 100644 --- a/testutil/integration/exrp/common/config.go +++ b/testutil/integration/exrp/common/config.go @@ -34,6 +34,7 @@ type Config struct { CustomBaseAppOpts []func(*baseapp.BaseApp) MinDepositAmt sdkmath.Int Quorum string + UpgradePlanName string } type CustomGenesisState map[string]interface{} diff --git a/testutil/integration/exrp/common/setup.go b/testutil/integration/exrp/common/setup.go index 38bf227..b54fe16 100644 --- a/testutil/integration/exrp/common/setup.go +++ b/testutil/integration/exrp/common/setup.go @@ -25,6 +25,11 @@ import ( feemarkettypes "github.com/evmos/evmos/v20/x/feemarket/types" ) +const ( + DefaultNodeDBName = "application" + DefaultNodeDBDir = ".exrpd/data" +) + // GenSetupFn is the type for the module genesis setup functions type GenSetupFn func(exrpApp *app.App, genesisState app.GenesisState, customGenesis interface{}) (app.GenesisState, error) @@ -100,7 +105,10 @@ func MustGetIntegrationTestNodeHome() string { func CreateExrpApp(chainID string, customBaseAppOptions ...func(*baseapp.BaseApp)) *app.App { testNodeHome := MustGetIntegrationTestNodeHome() // Create exrp app - db := dbm.NewMemDB() + db, err := dbm.NewGoLevelDB(DefaultNodeDBName, DefaultNodeDBDir, nil) + if err != nil { + panic(err) + } logger := log.NewNopLogger() loadLatest := true skipUpgradeHeights := map[int64]bool{} diff --git a/testutil/integration/exrp/integration/keepers.go b/testutil/integration/exrp/integration/keepers.go index 2cab201..bc2500f 100644 --- a/testutil/integration/exrp/integration/keepers.go +++ b/testutil/integration/exrp/integration/keepers.go @@ -9,6 +9,7 @@ import ( slashingkeeper "github.com/cosmos/cosmos-sdk/x/slashing/keeper" stakingkeeper "github.com/cosmos/cosmos-sdk/x/staking/keeper" + upgradekeeper "cosmossdk.io/x/upgrade/keeper" erc20keeper "github.com/evmos/evmos/v20/x/erc20/keeper" evmkeeper "github.com/evmos/evmos/v20/x/evm/keeper" feemarketkeeper "github.com/evmos/evmos/v20/x/feemarket/keeper" @@ -58,3 +59,7 @@ func (n *IntegrationNetwork) FeeMarketKeeper() feemarketkeeper.Keeper { func (n *IntegrationNetwork) PoaKeeper() poakeeper.Keeper { return n.app.PoaKeeper } + +func (n *IntegrationNetwork) UpgradeKeeper() upgradekeeper.Keeper { + return *n.app.UpgradeKeeper +} diff --git a/testutil/integration/exrp/upgrade/config.go b/testutil/integration/exrp/upgrade/config.go index d05ddff..2ad59c0 100644 --- a/testutil/integration/exrp/upgrade/config.go +++ b/testutil/integration/exrp/upgrade/config.go @@ -23,3 +23,10 @@ func WithGenesisFile(genesisFile string) exrpcommon.ConfigOption { cfg.GenesisBytes = genesisBytes } } + +// WithUpgradePlanName sets the upgrade plan name for the network. +func WithUpgradePlanName(name string) exrpcommon.ConfigOption { + return func(cfg *exrpcommon.Config) { + cfg.UpgradePlanName = name + } +} diff --git a/testutil/integration/exrp/upgrade/keepers.go b/testutil/integration/exrp/upgrade/keepers.go index 3bfd973..92895b4 100644 --- a/testutil/integration/exrp/upgrade/keepers.go +++ b/testutil/integration/exrp/upgrade/keepers.go @@ -9,6 +9,7 @@ import ( slashingkeeper "github.com/cosmos/cosmos-sdk/x/slashing/keeper" stakingkeeper "github.com/cosmos/cosmos-sdk/x/staking/keeper" + upgradekeeper "cosmossdk.io/x/upgrade/keeper" erc20keeper "github.com/evmos/evmos/v20/x/erc20/keeper" evmkeeper "github.com/evmos/evmos/v20/x/evm/keeper" feemarketkeeper "github.com/evmos/evmos/v20/x/feemarket/keeper" @@ -58,3 +59,7 @@ func (n *UpgradeIntegrationNetwork) FeeMarketKeeper() feemarketkeeper.Keeper { func (n *UpgradeIntegrationNetwork) PoaKeeper() poakeeper.Keeper { return n.app.PoaKeeper } + +func (n *UpgradeIntegrationNetwork) UpgradeKeeper() upgradekeeper.Keeper { + return *n.app.UpgradeKeeper +} diff --git a/testutil/integration/exrp/upgrade/network.go b/testutil/integration/exrp/upgrade/network.go index 3a64756..2cd7643 100644 --- a/testutil/integration/exrp/upgrade/network.go +++ b/testutil/integration/exrp/upgrade/network.go @@ -4,9 +4,7 @@ package exrpupgrade import ( - "encoding/json" "fmt" - "math" "math/big" "time" @@ -14,18 +12,18 @@ import ( "github.com/xrplevm/node/v5/app" exrpcommon "github.com/xrplevm/node/v5/testutil/integration/exrp/common" + upgradetypes "cosmossdk.io/x/upgrade/types" abcitypes "github.com/cometbft/cometbft/abci/types" ed25519 "github.com/cometbft/cometbft/crypto/ed25519" cmtproto "github.com/cometbft/cometbft/proto/tendermint/types" tmversion "github.com/cometbft/cometbft/proto/tendermint/version" cmttypes "github.com/cometbft/cometbft/types" "github.com/cometbft/cometbft/version" + "github.com/cosmos/cosmos-sdk/runtime" sdktypes "github.com/cosmos/cosmos-sdk/types" sdktestutil "github.com/cosmos/cosmos-sdk/types/module/testutil" txtypes "github.com/cosmos/cosmos-sdk/types/tx" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" - - "github.com/evmos/evmos/v20/types" ) // Network is the interface that wraps the methods to interact with integration test network. @@ -117,75 +115,41 @@ func getValidatorsAndSignersFromCustomGenesisState( // It creates the genesis state and starts the network. func (n *UpgradeIntegrationNetwork) configureAndInitChain() error { // Create a new EvmosApp with the following params - exrpApp := exrpcommon.CreateExrpApp(n.cfg.ChainID, n.cfg.CustomBaseAppOpts...) - - var genesisState app.GenesisState - err := json.Unmarshal(n.cfg.GenesisBytes, &genesisState) - if err != nil { - return fmt.Errorf("error unmarshalling genesis state: %w", err) - } + exrpApp := CreateExrpApp(n.cfg.ChainID, n.cfg.CustomBaseAppOpts...) - stateBytes, ok := genesisState["app_state"] - if !ok { - return fmt.Errorf("app_state not found in genesis state") - } - - var appState map[string]json.RawMessage - err = json.Unmarshal(genesisState["app_state"], &appState) - if err != nil { - return fmt.Errorf("error unmarshalling app state: %w", err) + upgradePlan := upgradetypes.Plan{ + Name: "v1", + Height: exrpApp.LastBlockHeight() + 1, } - var stakingState stakingtypes.GenesisState - err = exrpApp.AppCodec().UnmarshalJSON(appState["staking"], &stakingState) + bz, err := exrpApp.AppCodec().Marshal(&upgradePlan) if err != nil { - return fmt.Errorf("error unmarshalling staking state: %w", err) + return err } - valSet, valSigners, _, err := getValidatorsAndSignersFromCustomGenesisState(stakingState) + upgradeKey := exrpApp.GetKey(upgradetypes.StoreKey) + upgradeStoreService := runtime.NewKVStoreService(upgradeKey) + upgradeStore := upgradeStoreService.OpenKVStore(exrpApp.NewContext(true)) + err = upgradeStore.Set(upgradetypes.PlanKey(), bz) if err != nil { - return fmt.Errorf("error getting validators and signers from custom genesis state: %w", err) + return err } - // Consensus module does not have a genesis state on the app, - // but can customize the consensus parameters of the chain on initialization - - var consensusState map[string]json.RawMessage - err = json.Unmarshal(genesisState["consensus"], &consensusState) + validators, err := exrpApp.StakingKeeper.GetBondedValidatorsByPower(exrpApp.NewContext(true)) if err != nil { - return fmt.Errorf("error unmarshalling consensus state: %w", err) + return err } - var consensusParams *cmtproto.ConsensusParams - err = json.Unmarshal(consensusState["params"], &consensusParams) + valSet, err := createStakingValidators(validators) if err != nil { - return fmt.Errorf("error unmarshalling consensus params: %w", err) - } - - var initialHeight int64 - if err := json.Unmarshal(genesisState["initial_height"], &initialHeight); err != nil { - return fmt.Errorf("initial_height is not an int64") - } - - now := time.Now().UTC() - if _, err := exrpApp.InitChain( - &abcitypes.RequestInitChain{ - Time: now, - ChainId: n.cfg.ChainID, - Validators: []abcitypes.ValidatorUpdate{}, - ConsensusParams: consensusParams, - AppStateBytes: stateBytes, - InitialHeight: initialHeight, - }, - ); err != nil { return err } header := cmtproto.Header{ ChainID: n.cfg.ChainID, - Height: initialHeight, + Height: exrpApp.LastBlockHeight() + 1, AppHash: exrpApp.LastCommitID().Hash, - Time: now, + Time: time.Now().UTC(), ValidatorsHash: valSet.Hash(), NextValidatorsHash: valSet.Hash(), ProposerAddress: valSet.Proposer.Address, @@ -207,19 +171,10 @@ func (n *UpgradeIntegrationNetwork) configureAndInitChain() error { return err } - // Set networks global parameters - var blockMaxGas uint64 = math.MaxUint64 - if consensusParams.Block != nil && consensusParams.Block.MaxGas > 0 { - blockMaxGas = uint64(consensusParams.Block.MaxGas) //nolint:gosec // G115 - } n.app = exrpApp - n.ctx = n.ctx.WithConsensusParams(*consensusParams) - n.ctx = n.ctx.WithBlockGasMeter(types.NewInfiniteGasMeterWithLimit(blockMaxGas)) - n.validators = stakingState.Validators n.valSet = valSet - n.valSigners = valSigners return nil } @@ -330,3 +285,17 @@ func (n *UpgradeIntegrationNetwork) CheckTx(txBytes []byte) (*abcitypes.Response } return res, nil } + +func createStakingValidators(validators []stakingtypes.Validator) (*cmttypes.ValidatorSet, error) { + tmValidators := make([]*cmttypes.Validator, 0, len(validators)) + for _, val := range validators { + pb, err := val.CmtConsPublicKey() + if err != nil { + return nil, err + } + pubKey := ed25519.PubKey(pb.GetEd25519()) + validator := cmttypes.NewValidator(pubKey, val.GetConsensusPower(val.Tokens)) + tmValidators = append(tmValidators, validator) + } + return cmttypes.NewValidatorSet(tmValidators), nil +} diff --git a/testutil/integration/exrp/upgrade/setup.go b/testutil/integration/exrp/upgrade/setup.go new file mode 100644 index 0000000..fc854e7 --- /dev/null +++ b/testutil/integration/exrp/upgrade/setup.go @@ -0,0 +1,44 @@ +package exrpupgrade + +import ( + "cosmossdk.io/log" + dbm "github.com/cosmos/cosmos-db" + "github.com/cosmos/cosmos-sdk/baseapp" + simutils "github.com/cosmos/cosmos-sdk/testutil/sims" + "github.com/xrplevm/node/v5/app" + exrpcommon "github.com/xrplevm/node/v5/testutil/integration/exrp/common" +) + +const ( + DefaultNodeDBName = "application" + DefaultNodeDBDir = ".exrpd/data" +) + +// createExrpApp creates an exrp app +func CreateExrpApp(chainID string, customBaseAppOptions ...func(*baseapp.BaseApp)) *app.App { + testNodeHome := exrpcommon.MustGetIntegrationTestNodeHome() + // Create exrp app + db, err := dbm.NewGoLevelDB(DefaultNodeDBName, DefaultNodeDBDir, nil) + if err != nil { + panic(err) + } + logger := log.NewNopLogger() + loadLatest := false + skipUpgradeHeights := map[int64]bool{} + homePath := testNodeHome + invCheckPeriod := uint(5) + appOptions := simutils.NewAppOptionsWithFlagHome(homePath) + baseAppOptions := append(customBaseAppOptions, baseapp.SetChainID(chainID)) //nolint:gocritic + + return app.New( + logger, + db, + nil, + loadLatest, + skipUpgradeHeights, + homePath, + invCheckPeriod, + appOptions, + baseAppOptions..., + ) +} From e3d60cbc0dd0989ee030a2c5c57a33b3ce5f5f55 Mon Sep 17 00:00:00 2001 From: GuillemGarciaDev Date: Tue, 28 Jan 2025 19:31:05 +0000 Subject: [PATCH 05/25] feat: upgrade integration base --- app/upgrades.go | 10 +++++++++- tests/upgrade/network.go | 5 +++++ testutil/integration/exrp/upgrade/network.go | 9 ++++----- testutil/integration/exrp/upgrade/setup.go | 2 +- 4 files changed, 19 insertions(+), 7 deletions(-) diff --git a/app/upgrades.go b/app/upgrades.go index 97f4ce1..95386a3 100644 --- a/app/upgrades.go +++ b/app/upgrades.go @@ -11,6 +11,7 @@ import ( icahosttypes "github.com/cosmos/ibc-go/v8/modules/apps/27-interchain-accounts/host/types" v4 "github.com/xrplevm/node/v5/app/upgrades/v4" v5 "github.com/xrplevm/node/v5/app/upgrades/v5" + v6 "github.com/xrplevm/node/v5/app/upgrades/vtest" ) func (app *App) setupUpgradeHandlers() { @@ -36,6 +37,13 @@ func (app *App) setupUpgradeHandlers() { app.configurator, ), ) + app.UpgradeKeeper.SetUpgradeHandler( + v6.UpgradeName, + v6.CreateUpgradeHandler( + app.mm, + app.configurator, + ), + ) // When a planned update height is reached, the old binary will panic // writing on disk the height and name of the update that triggered it @@ -60,7 +68,7 @@ func (app *App) setupUpgradeHandlers() { }, Deleted: []string{}, } - case v5.UpgradeName: + case v5.UpgradeName, v6.UpgradeName: // No store upgrades for v5 storeUpgrades = &storetypes.StoreUpgrades{} } diff --git a/tests/upgrade/network.go b/tests/upgrade/network.go index a71a2d1..ad02afb 100644 --- a/tests/upgrade/network.go +++ b/tests/upgrade/network.go @@ -1,6 +1,7 @@ package testupgrade import ( + upgradetypes "cosmossdk.io/x/upgrade/types" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" "github.com/cosmos/cosmos-sdk/x/authz" banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" @@ -72,3 +73,7 @@ func (n *UpgradeTestNetwork) GetDistrClient() distrtypes.QueryClient { func (n *UpgradeTestNetwork) GetPoaClient() poatypes.QueryClient { return exrpcommon.GetPoaClient(n) } + +func (n *UpgradeTestNetwork) GetUpgradeClient() upgradetypes.QueryClient { + return exrpcommon.GetUpgradeClient(n) +} diff --git a/testutil/integration/exrp/upgrade/network.go b/testutil/integration/exrp/upgrade/network.go index 2cd7643..c0732fb 100644 --- a/testutil/integration/exrp/upgrade/network.go +++ b/testutil/integration/exrp/upgrade/network.go @@ -69,9 +69,6 @@ func New(opts ...exrpcommon.ConfigOption) *UpgradeIntegrationNetwork { validators: []stakingtypes.Validator{}, } - if cfg.GenesisBytes == nil { - panic("GenesisBytes is nil") - } err := network.configureAndInitChain() if err != nil { panic(err) @@ -118,7 +115,7 @@ func (n *UpgradeIntegrationNetwork) configureAndInitChain() error { exrpApp := CreateExrpApp(n.cfg.ChainID, n.cfg.CustomBaseAppOpts...) upgradePlan := upgradetypes.Plan{ - Name: "v1", + Name: n.cfg.UpgradePlanName, Height: exrpApp.LastBlockHeight() + 1, } @@ -131,6 +128,9 @@ func (n *UpgradeIntegrationNetwork) configureAndInitChain() error { upgradeStoreService := runtime.NewKVStoreService(upgradeKey) upgradeStore := upgradeStoreService.OpenKVStore(exrpApp.NewContext(true)) err = upgradeStore.Set(upgradetypes.PlanKey(), bz) + + exrpApp.CommitMultiStore().Commit() + if err != nil { return err } @@ -171,7 +171,6 @@ func (n *UpgradeIntegrationNetwork) configureAndInitChain() error { return err } - n.app = exrpApp n.valSet = valSet diff --git a/testutil/integration/exrp/upgrade/setup.go b/testutil/integration/exrp/upgrade/setup.go index fc854e7..7d2dcd9 100644 --- a/testutil/integration/exrp/upgrade/setup.go +++ b/testutil/integration/exrp/upgrade/setup.go @@ -23,7 +23,7 @@ func CreateExrpApp(chainID string, customBaseAppOptions ...func(*baseapp.BaseApp panic(err) } logger := log.NewNopLogger() - loadLatest := false + loadLatest := true skipUpgradeHeights := map[int64]bool{} homePath := testNodeHome invCheckPeriod := uint(5) From 22e2a621e79f64ac3339cb596442097b23d2cbc1 Mon Sep 17 00:00:00 2001 From: GuillemGarciaDev Date: Wed, 29 Jan 2025 17:33:09 +0000 Subject: [PATCH 06/25] feat(tests): upgrade integration testsuite with `ApplyUpgrade` call --- Makefile | 2 + app/upgrades.go | 1 + app/upgrades/vtest/upgrades.go | 15 ++++++ tests/upgrade/README.md | 14 ----- tests/upgrade/suite.go | 8 +-- tests/upgrade/suite_test.go | 26 +++++++++ testutil/integration/exrp/common/config.go | 2 + testutil/integration/exrp/upgrade/config.go | 12 +++++ testutil/integration/exrp/upgrade/network.go | 57 ++++++++++++-------- testutil/integration/exrp/upgrade/setup.go | 9 +--- 10 files changed, 98 insertions(+), 48 deletions(-) delete mode 100644 tests/upgrade/README.md diff --git a/Makefile b/Makefile index c15620f..5f06915 100644 --- a/Makefile +++ b/Makefile @@ -128,6 +128,8 @@ mocks: test-upgrade: @echo "--> Running upgrade testsuite" + @rm -rf ./tests/upgrade/.exrpd + @cp -r ./tests/upgrade/.exrpd-backup ./tests/upgrade/.exrpd @go test -mod=readonly -v ./tests/upgrade test-integration: diff --git a/app/upgrades.go b/app/upgrades.go index 95386a3..fc9a7e5 100644 --- a/app/upgrades.go +++ b/app/upgrades.go @@ -42,6 +42,7 @@ func (app *App) setupUpgradeHandlers() { v6.CreateUpgradeHandler( app.mm, app.configurator, + app.StakingKeeper, ), ) diff --git a/app/upgrades/vtest/upgrades.go b/app/upgrades/vtest/upgrades.go index c2a6e27..1f2e5fd 100644 --- a/app/upgrades/vtest/upgrades.go +++ b/app/upgrades/vtest/upgrades.go @@ -2,20 +2,35 @@ package v6 import ( "context" + "time" upgradetypes "cosmossdk.io/x/upgrade/types" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/module" + stakingkeeper "github.com/evmos/evmos/v20/x/staking/keeper" ) func CreateUpgradeHandler( mm *module.Manager, configurator module.Configurator, + sk *stakingkeeper.Keeper, + ) upgradetypes.UpgradeHandler { return func(c context.Context, _ upgradetypes.Plan, vm module.VersionMap) (module.VersionMap, error) { ctx := sdk.UnwrapSDKContext(c) logger := ctx.Logger().With("upgrade", UpgradeName) logger.Info("Running v6 upgrade handler...") + + params, err := sk.GetParams(ctx) + if err != nil { + return vm, err + } + params.UnbondingTime = 100 * time.Second + err = sk.SetParams(ctx, params) + if err != nil { + return vm, err + } + return mm.RunMigrations(ctx, configurator, vm) } } diff --git a/tests/upgrade/README.md b/tests/upgrade/README.md deleted file mode 100644 index 0a05141..0000000 --- a/tests/upgrade/README.md +++ /dev/null @@ -1,14 +0,0 @@ -# Upgrade testsuite - -## Download exported state - -```bash - -``` - -## Setup - -Set the `UPGRADE_STATE_FILE` environment variable to the path to the exported state file. -```bash -UPGRADE_STATE_FILE="path/to/exported-state.json" -``` \ No newline at end of file diff --git a/tests/upgrade/suite.go b/tests/upgrade/suite.go index dfded14..420714d 100644 --- a/tests/upgrade/suite.go +++ b/tests/upgrade/suite.go @@ -6,11 +6,6 @@ import ( exrpupgrade "github.com/xrplevm/node/v5/testutil/integration/exrp/upgrade" ) -const ( - DefaultNodeDBName = ".exrp-upgrade" - DefaultNodeDBDir = "exrp-upgrade" -) - type UpgradeTestSuite struct { suite.Suite @@ -27,10 +22,11 @@ func (s *UpgradeTestSuite) SetupTest() { s.Require().Equal(sdk.GetConfig().GetBech32AccountAddrPrefix(), "ethm") - // Create the network s.network = NewUpgradeTestNetwork( exrpupgrade.WithUpgradePlanName("v6.0.0"), + exrpupgrade.WithDataDir(".exrpd/data"), + exrpupgrade.WithNodeDBName("application"), ) // Check that the network was created successfully diff --git a/tests/upgrade/suite_test.go b/tests/upgrade/suite_test.go index ad1634f..56fe662 100644 --- a/tests/upgrade/suite_test.go +++ b/tests/upgrade/suite_test.go @@ -2,7 +2,10 @@ package testupgrade import ( "testing" + "time" + upgradetypes "cosmossdk.io/x/upgrade/types" + stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" "github.com/stretchr/testify/suite" "github.com/xrplevm/node/v5/app" ) @@ -15,4 +18,27 @@ func (s *UpgradeTestSuite) TestUpgrade() { denom := s.network.GetDenom() s.Require().NotEmpty(denom) s.Require().Equal(denom, app.BaseDenom) + + res, err := s.network.GetUpgradeClient().CurrentPlan( + s.network.GetContext(), + &upgradetypes.QueryCurrentPlanRequest{}, + ) + s.Require().NoError(err) + s.Require().Equal("v6.0.0", res.Plan.Name) + + s.Require().True(s.Network().UpgradeKeeper().HasHandler("v6.0.0")) + + err = s.network.UpgradeKeeper().ApplyUpgrade( + s.Network().GetContext(), + *res.Plan, + ) + + s.Require().NoError(err) + + resParams, err := s.network.GetStakingClient().Params( + s.network.GetContext(), + &stakingtypes.QueryParamsRequest{}, + ) + + s.Require().Equal(100 * time.Second, resParams.Params.UnbondingTime) } diff --git a/testutil/integration/exrp/common/config.go b/testutil/integration/exrp/common/config.go index 85efe75..4b43c6a 100644 --- a/testutil/integration/exrp/common/config.go +++ b/testutil/integration/exrp/common/config.go @@ -35,6 +35,8 @@ type Config struct { MinDepositAmt sdkmath.Int Quorum string UpgradePlanName string + DataDir string + NodeDBName string } type CustomGenesisState map[string]interface{} diff --git a/testutil/integration/exrp/upgrade/config.go b/testutil/integration/exrp/upgrade/config.go index 2ad59c0..15cd275 100644 --- a/testutil/integration/exrp/upgrade/config.go +++ b/testutil/integration/exrp/upgrade/config.go @@ -30,3 +30,15 @@ func WithUpgradePlanName(name string) exrpcommon.ConfigOption { cfg.UpgradePlanName = name } } + +func WithDataDir(dataDir string) exrpcommon.ConfigOption { + return func(cfg *exrpcommon.Config) { + cfg.DataDir = dataDir + } +} + +func WithNodeDBName(nodeDBName string) exrpcommon.ConfigOption { + return func(cfg *exrpcommon.Config) { + cfg.NodeDBName = nodeDBName + } +} diff --git a/testutil/integration/exrp/upgrade/network.go b/testutil/integration/exrp/upgrade/network.go index c0732fb..8be19a6 100644 --- a/testutil/integration/exrp/upgrade/network.go +++ b/testutil/integration/exrp/upgrade/network.go @@ -112,28 +112,9 @@ func getValidatorsAndSignersFromCustomGenesisState( // It creates the genesis state and starts the network. func (n *UpgradeIntegrationNetwork) configureAndInitChain() error { // Create a new EvmosApp with the following params - exrpApp := CreateExrpApp(n.cfg.ChainID, n.cfg.CustomBaseAppOpts...) + exrpApp := CreateExrpApp(n.cfg.ChainID, n.cfg.DataDir, n.cfg.NodeDBName, n.cfg.CustomBaseAppOpts...) - upgradePlan := upgradetypes.Plan{ - Name: n.cfg.UpgradePlanName, - Height: exrpApp.LastBlockHeight() + 1, - } - - bz, err := exrpApp.AppCodec().Marshal(&upgradePlan) - if err != nil { - return err - } - - upgradeKey := exrpApp.GetKey(upgradetypes.StoreKey) - upgradeStoreService := runtime.NewKVStoreService(upgradeKey) - upgradeStore := upgradeStoreService.OpenKVStore(exrpApp.NewContext(true)) - err = upgradeStore.Set(upgradetypes.PlanKey(), bz) - - exrpApp.CommitMultiStore().Commit() - - if err != nil { - return err - } + fmt.Println("pre commit last block height", exrpApp.LastBlockHeight()) validators, err := exrpApp.StakingKeeper.GetBondedValidatorsByPower(exrpApp.NewContext(true)) if err != nil { @@ -145,6 +126,8 @@ func (n *UpgradeIntegrationNetwork) configureAndInitChain() error { return err } + fmt.Println("post commit last block height", exrpApp.LastBlockHeight()) + header := cmtproto.Header{ ChainID: n.cfg.ChainID, Height: exrpApp.LastBlockHeight() + 1, @@ -158,19 +141,51 @@ func (n *UpgradeIntegrationNetwork) configureAndInitChain() error { }, } + fmt.Println("before finalize block") + req := BuildFinalizeBlockReq(header, valSet.Validators, nil, nil) if _, err := exrpApp.FinalizeBlock(req); err != nil { return err } + fmt.Println("after finalize block") + + // Store upgrade plan on finalizeblock + upgradePlan := upgradetypes.Plan{ + Name: n.cfg.UpgradePlanName, + Height: exrpApp.LastBlockHeight() + 1, + } + + bz, err := exrpApp.AppCodec().Marshal(&upgradePlan) + if err != nil { + return err + } + + upgradeKey := exrpApp.GetKey(upgradetypes.StoreKey) + upgradeStoreService := runtime.NewKVStoreService(upgradeKey) + upgradeStore := upgradeStoreService.OpenKVStore(exrpApp.NewContext(false)) + err = upgradeStore.Set(upgradetypes.PlanKey(), bz) + + plan, err := exrpApp.UpgradeKeeper.CurrentPlan( + exrpApp.NewContext(true), + &upgradetypes.QueryCurrentPlanRequest{}, + ) + if err != nil { + return err + } + fmt.Println("plan", plan) // TODO - this might not be the best way to initilize the context n.ctx = exrpApp.BaseApp.NewContextLegacy(false, header) + fmt.Println("before last commit") + // Commit genesis changes if _, err := exrpApp.Commit(); err != nil { return err } + fmt.Println("after last commit") + n.app = exrpApp n.valSet = valSet diff --git a/testutil/integration/exrp/upgrade/setup.go b/testutil/integration/exrp/upgrade/setup.go index 7d2dcd9..f1dc7e1 100644 --- a/testutil/integration/exrp/upgrade/setup.go +++ b/testutil/integration/exrp/upgrade/setup.go @@ -9,16 +9,11 @@ import ( exrpcommon "github.com/xrplevm/node/v5/testutil/integration/exrp/common" ) -const ( - DefaultNodeDBName = "application" - DefaultNodeDBDir = ".exrpd/data" -) - // createExrpApp creates an exrp app -func CreateExrpApp(chainID string, customBaseAppOptions ...func(*baseapp.BaseApp)) *app.App { +func CreateExrpApp(chainID string, dataDir string, nodeDBName string, customBaseAppOptions ...func(*baseapp.BaseApp)) *app.App { testNodeHome := exrpcommon.MustGetIntegrationTestNodeHome() // Create exrp app - db, err := dbm.NewGoLevelDB(DefaultNodeDBName, DefaultNodeDBDir, nil) + db, err := dbm.NewGoLevelDB(nodeDBName, dataDir, nil) if err != nil { panic(err) } From 42aefc2312a42f4a0a81d5646026bb7c8077897f Mon Sep 17 00:00:00 2001 From: GuillemGarciaDev Date: Thu, 30 Jan 2025 09:32:01 +0100 Subject: [PATCH 07/25] poc(tests): testing temporal v6 upgrade with upgrade integration testsuite --- Makefile | 9 +-- app/upgrades.go | 2 +- app/upgrades/{vtest => v6}/constants.go | 0 .../upgrades/v6/tests}/network.go | 2 +- .../upgrades/v6/tests}/suite.go | 2 +- .../upgrades/v6/tests}/suite_test.go | 14 ++--- app/upgrades/{vtest => v6}/upgrades.go | 1 - testutil/integration/exrp/upgrade/network.go | 59 ++----------------- testutil/integration/exrp/upgrade/setup.go | 2 +- 9 files changed, 19 insertions(+), 72 deletions(-) rename app/upgrades/{vtest => v6}/constants.go (100%) rename {tests/upgrade => app/upgrades/v6/tests}/network.go (99%) rename {tests/upgrade => app/upgrades/v6/tests}/suite.go (97%) rename {tests/upgrade => app/upgrades/v6/tests}/suite_test.go (74%) rename app/upgrades/{vtest => v6}/upgrades.go (99%) diff --git a/Makefile b/Makefile index 5f06915..a26658a 100644 --- a/Makefile +++ b/Makefile @@ -4,6 +4,7 @@ BRANCH := $(shell git rev-parse --abbrev-ref HEAD) COMMIT := $(shell git log -1 --format='%H') BINDIR ?= $(GOPATH)/bin APP = ./app +LATEST_UPGRADE = $(shell ls -d ./app/upgrades/* | sort -r | head -n 1) # don't override user values ifeq (,$(VERSION)) @@ -126,11 +127,11 @@ mocks: @echo "--> Generating mocks" @./scripts/mockgen.sh -test-upgrade: +test-latest-upgrade: @echo "--> Running upgrade testsuite" - @rm -rf ./tests/upgrade/.exrpd - @cp -r ./tests/upgrade/.exrpd-backup ./tests/upgrade/.exrpd - @go test -mod=readonly -v ./tests/upgrade + @rm -rf $(LATEST_UPGRADE)/tests/.exrpd + @cp -r ./.exrpd $(LATEST_UPGRADE)/tests/.exrpd + @go test -mod=readonly -v $(LATEST_UPGRADE)/tests test-integration: @echo "--> Running integration testsuite" diff --git a/app/upgrades.go b/app/upgrades.go index fc9a7e5..d318434 100644 --- a/app/upgrades.go +++ b/app/upgrades.go @@ -11,7 +11,7 @@ import ( icahosttypes "github.com/cosmos/ibc-go/v8/modules/apps/27-interchain-accounts/host/types" v4 "github.com/xrplevm/node/v5/app/upgrades/v4" v5 "github.com/xrplevm/node/v5/app/upgrades/v5" - v6 "github.com/xrplevm/node/v5/app/upgrades/vtest" + v6 "github.com/xrplevm/node/v5/app/upgrades/v6" ) func (app *App) setupUpgradeHandlers() { diff --git a/app/upgrades/vtest/constants.go b/app/upgrades/v6/constants.go similarity index 100% rename from app/upgrades/vtest/constants.go rename to app/upgrades/v6/constants.go diff --git a/tests/upgrade/network.go b/app/upgrades/v6/tests/network.go similarity index 99% rename from tests/upgrade/network.go rename to app/upgrades/v6/tests/network.go index ad02afb..c8607e4 100644 --- a/tests/upgrade/network.go +++ b/app/upgrades/v6/tests/network.go @@ -1,4 +1,4 @@ -package testupgrade +package tests import ( upgradetypes "cosmossdk.io/x/upgrade/types" diff --git a/tests/upgrade/suite.go b/app/upgrades/v6/tests/suite.go similarity index 97% rename from tests/upgrade/suite.go rename to app/upgrades/v6/tests/suite.go index 420714d..f50e710 100644 --- a/tests/upgrade/suite.go +++ b/app/upgrades/v6/tests/suite.go @@ -1,4 +1,4 @@ -package testupgrade +package tests import ( sdk "github.com/cosmos/cosmos-sdk/types" diff --git a/tests/upgrade/suite_test.go b/app/upgrades/v6/tests/suite_test.go similarity index 74% rename from tests/upgrade/suite_test.go rename to app/upgrades/v6/tests/suite_test.go index 56fe662..66bb223 100644 --- a/tests/upgrade/suite_test.go +++ b/app/upgrades/v6/tests/suite_test.go @@ -1,4 +1,4 @@ -package testupgrade +package tests import ( "testing" @@ -7,25 +7,20 @@ import ( upgradetypes "cosmossdk.io/x/upgrade/types" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" "github.com/stretchr/testify/suite" - "github.com/xrplevm/node/v5/app" ) func TestUpgradeTestSuite(t *testing.T) { suite.Run(t, new(UpgradeTestSuite)) } -func (s *UpgradeTestSuite) TestUpgrade() { - denom := s.network.GetDenom() - s.Require().NotEmpty(denom) - s.Require().Equal(denom, app.BaseDenom) - +func (s *UpgradeTestSuite) TestUpgradeV6() { res, err := s.network.GetUpgradeClient().CurrentPlan( s.network.GetContext(), &upgradetypes.QueryCurrentPlanRequest{}, ) s.Require().NoError(err) s.Require().Equal("v6.0.0", res.Plan.Name) - + s.Require().True(s.Network().UpgradeKeeper().HasHandler("v6.0.0")) err = s.network.UpgradeKeeper().ApplyUpgrade( @@ -40,5 +35,6 @@ func (s *UpgradeTestSuite) TestUpgrade() { &stakingtypes.QueryParamsRequest{}, ) - s.Require().Equal(100 * time.Second, resParams.Params.UnbondingTime) + s.Require().NoError(err) + s.Require().Equal(100*time.Second, resParams.Params.UnbondingTime) } diff --git a/app/upgrades/vtest/upgrades.go b/app/upgrades/v6/upgrades.go similarity index 99% rename from app/upgrades/vtest/upgrades.go rename to app/upgrades/v6/upgrades.go index 1f2e5fd..221a34a 100644 --- a/app/upgrades/vtest/upgrades.go +++ b/app/upgrades/v6/upgrades.go @@ -14,7 +14,6 @@ func CreateUpgradeHandler( mm *module.Manager, configurator module.Configurator, sk *stakingkeeper.Keeper, - ) upgradetypes.UpgradeHandler { return func(c context.Context, _ upgradetypes.Plan, vm module.VersionMap) (module.VersionMap, error) { ctx := sdk.UnwrapSDKContext(c) diff --git a/testutil/integration/exrp/upgrade/network.go b/testutil/integration/exrp/upgrade/network.go index 8be19a6..8448371 100644 --- a/testutil/integration/exrp/upgrade/network.go +++ b/testutil/integration/exrp/upgrade/network.go @@ -76,46 +76,12 @@ func New(opts ...exrpcommon.ConfigOption) *UpgradeIntegrationNetwork { return network } -func getValidatorsAndSignersFromCustomGenesisState( - stakingState stakingtypes.GenesisState, -) ( - *cmttypes.ValidatorSet, - map[string]cmttypes.PrivValidator, - []abcitypes.ValidatorUpdate, error, -) { - genesisValidators := stakingState.Validators - - tmValidators := make([]*cmttypes.Validator, 0, len(genesisValidators)) - validatorsUpdates := make([]abcitypes.ValidatorUpdate, 0, len(genesisValidators)) - valSigners := make(map[string]cmttypes.PrivValidator, len(genesisValidators)) - - // For each validator, we need to get the pubkey and create a new validator - for _, val := range genesisValidators { - pb, err := val.CmtConsPublicKey() - if err != nil { - return nil, nil, nil, err - } - pubKey := ed25519.PubKey(pb.GetEd25519()) - - validator := cmttypes.NewValidator(pubKey, 10000000) - tmValidators = append(tmValidators, validator) - validatorsUpdates = append(validatorsUpdates, abcitypes.ValidatorUpdate{ - PubKey: pb, - Power: val.GetConsensusPower(val.Tokens), - }) - } - - return cmttypes.NewValidatorSet(tmValidators), valSigners, validatorsUpdates, nil -} - // configureAndInitChain initializes the network with the given configuration. // It creates the genesis state and starts the network. func (n *UpgradeIntegrationNetwork) configureAndInitChain() error { // Create a new EvmosApp with the following params exrpApp := CreateExrpApp(n.cfg.ChainID, n.cfg.DataDir, n.cfg.NodeDBName, n.cfg.CustomBaseAppOpts...) - fmt.Println("pre commit last block height", exrpApp.LastBlockHeight()) - validators, err := exrpApp.StakingKeeper.GetBondedValidatorsByPower(exrpApp.NewContext(true)) if err != nil { return err @@ -126,8 +92,6 @@ func (n *UpgradeIntegrationNetwork) configureAndInitChain() error { return err } - fmt.Println("post commit last block height", exrpApp.LastBlockHeight()) - header := cmtproto.Header{ ChainID: n.cfg.ChainID, Height: exrpApp.LastBlockHeight() + 1, @@ -141,15 +105,12 @@ func (n *UpgradeIntegrationNetwork) configureAndInitChain() error { }, } - fmt.Println("before finalize block") - req := BuildFinalizeBlockReq(header, valSet.Validators, nil, nil) if _, err := exrpApp.FinalizeBlock(req); err != nil { return err } - fmt.Println("after finalize block") - // Store upgrade plan on finalizeblock + // Store upgrade plan on finalizeblock state. upgradePlan := upgradetypes.Plan{ Name: n.cfg.UpgradePlanName, Height: exrpApp.LastBlockHeight() + 1, @@ -160,32 +121,22 @@ func (n *UpgradeIntegrationNetwork) configureAndInitChain() error { return err } + // TODO - this might not be the best way to initilize the context + n.ctx = exrpApp.BaseApp.NewContextLegacy(false, header) + upgradeKey := exrpApp.GetKey(upgradetypes.StoreKey) upgradeStoreService := runtime.NewKVStoreService(upgradeKey) - upgradeStore := upgradeStoreService.OpenKVStore(exrpApp.NewContext(false)) + upgradeStore := upgradeStoreService.OpenKVStore(n.ctx) err = upgradeStore.Set(upgradetypes.PlanKey(), bz) - - plan, err := exrpApp.UpgradeKeeper.CurrentPlan( - exrpApp.NewContext(true), - &upgradetypes.QueryCurrentPlanRequest{}, - ) if err != nil { return err } - fmt.Println("plan", plan) - - // TODO - this might not be the best way to initilize the context - n.ctx = exrpApp.BaseApp.NewContextLegacy(false, header) - - fmt.Println("before last commit") // Commit genesis changes if _, err := exrpApp.Commit(); err != nil { return err } - fmt.Println("after last commit") - n.app = exrpApp n.valSet = valSet diff --git a/testutil/integration/exrp/upgrade/setup.go b/testutil/integration/exrp/upgrade/setup.go index f1dc7e1..a737466 100644 --- a/testutil/integration/exrp/upgrade/setup.go +++ b/testutil/integration/exrp/upgrade/setup.go @@ -18,7 +18,7 @@ func CreateExrpApp(chainID string, dataDir string, nodeDBName string, customBase panic(err) } logger := log.NewNopLogger() - loadLatest := true + loadLatest := true skipUpgradeHeights := map[int64]bool{} homePath := testNodeHome invCheckPeriod := uint(5) From 9d3a1c6e47eccac258339662636caa65438b3da0 Mon Sep 17 00:00:00 2001 From: GuillemGarciaDev Date: Thu, 30 Jan 2025 09:32:35 +0100 Subject: [PATCH 08/25] fix: rename `tests` package to `integration` --- app/upgrades/v6/{tests => integration}/network.go | 0 app/upgrades/v6/{tests => integration}/suite.go | 0 app/upgrades/v6/{tests => integration}/suite_test.go | 0 3 files changed, 0 insertions(+), 0 deletions(-) rename app/upgrades/v6/{tests => integration}/network.go (100%) rename app/upgrades/v6/{tests => integration}/suite.go (100%) rename app/upgrades/v6/{tests => integration}/suite_test.go (100%) diff --git a/app/upgrades/v6/tests/network.go b/app/upgrades/v6/integration/network.go similarity index 100% rename from app/upgrades/v6/tests/network.go rename to app/upgrades/v6/integration/network.go diff --git a/app/upgrades/v6/tests/suite.go b/app/upgrades/v6/integration/suite.go similarity index 100% rename from app/upgrades/v6/tests/suite.go rename to app/upgrades/v6/integration/suite.go diff --git a/app/upgrades/v6/tests/suite_test.go b/app/upgrades/v6/integration/suite_test.go similarity index 100% rename from app/upgrades/v6/tests/suite_test.go rename to app/upgrades/v6/integration/suite_test.go From 76638a1fff2e1cee5e907d783bebb2559687f7ff Mon Sep 17 00:00:00 2001 From: GuillemGarciaDev Date: Thu, 30 Jan 2025 09:34:22 +0100 Subject: [PATCH 09/25] fix(testutil): restore `MemDB` for exrp integration app --- testutil/integration/exrp/common/setup.go | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/testutil/integration/exrp/common/setup.go b/testutil/integration/exrp/common/setup.go index b54fe16..38bf227 100644 --- a/testutil/integration/exrp/common/setup.go +++ b/testutil/integration/exrp/common/setup.go @@ -25,11 +25,6 @@ import ( feemarkettypes "github.com/evmos/evmos/v20/x/feemarket/types" ) -const ( - DefaultNodeDBName = "application" - DefaultNodeDBDir = ".exrpd/data" -) - // GenSetupFn is the type for the module genesis setup functions type GenSetupFn func(exrpApp *app.App, genesisState app.GenesisState, customGenesis interface{}) (app.GenesisState, error) @@ -105,10 +100,7 @@ func MustGetIntegrationTestNodeHome() string { func CreateExrpApp(chainID string, customBaseAppOptions ...func(*baseapp.BaseApp)) *app.App { testNodeHome := MustGetIntegrationTestNodeHome() // Create exrp app - db, err := dbm.NewGoLevelDB(DefaultNodeDBName, DefaultNodeDBDir, nil) - if err != nil { - panic(err) - } + db := dbm.NewMemDB() logger := log.NewNopLogger() loadLatest := true skipUpgradeHeights := map[int64]bool{} From 800bea17a321c9e311b819ea96678cda577588e1 Mon Sep 17 00:00:00 2001 From: GuillemGarciaDev Date: Thu, 30 Jan 2025 09:44:58 +0100 Subject: [PATCH 10/25] refactor(poc): replace current version `v6` with testing version `v7` --- Makefile | 6 +- app/upgrades.go | 11 ++- app/upgrades/v7/constants.go | 5 ++ app/upgrades/v7/integration/network.go | 79 ++++++++++++++++++++++ app/upgrades/v7/integration/suite.go | 34 ++++++++++ app/upgrades/v7/integration/suite_test.go | 40 +++++++++++ app/upgrades/v7/upgrades.go | 35 ++++++++++ testutil/integration/exrp/upgrade/setup.go | 4 +- 8 files changed, 208 insertions(+), 6 deletions(-) create mode 100644 app/upgrades/v7/constants.go create mode 100644 app/upgrades/v7/integration/network.go create mode 100644 app/upgrades/v7/integration/suite.go create mode 100644 app/upgrades/v7/integration/suite_test.go create mode 100644 app/upgrades/v7/upgrades.go diff --git a/Makefile b/Makefile index 6ed42b4..9e2b386 100644 --- a/Makefile +++ b/Makefile @@ -131,9 +131,9 @@ test: test-poa test-integration test-sim-benchmark-simulation test-sim-full-app- test-latest-upgrade: @echo "--> Running upgrade testsuite" - @rm -rf $(LATEST_UPGRADE)/tests/.exrpd - @cp -r ./.exrpd $(LATEST_UPGRADE)/tests/.exrpd - @go test -mod=readonly -v $(LATEST_UPGRADE)/tests + @rm -rf $(LATEST_UPGRADE)/integration/.exrpd + @cp -r ./.exrpd $(LATEST_UPGRADE)/integration/.exrpd + @go test -mod=readonly -v $(LATEST_UPGRADE)/integration test-integration: @echo "--> Running integration testsuite" diff --git a/app/upgrades.go b/app/upgrades.go index efeb33c..5a9db19 100644 --- a/app/upgrades.go +++ b/app/upgrades.go @@ -12,6 +12,7 @@ import ( v4 "github.com/xrplevm/node/v6/app/upgrades/v4" v5 "github.com/xrplevm/node/v6/app/upgrades/v5" v6 "github.com/xrplevm/node/v6/app/upgrades/v6" + v7 "github.com/xrplevm/node/v6/app/upgrades/v7" ) func (app *App) setupUpgradeHandlers() { @@ -44,6 +45,14 @@ func (app *App) setupUpgradeHandlers() { app.configurator, ), ) + app.UpgradeKeeper.SetUpgradeHandler( + v7.UpgradeName, + v7.CreateUpgradeHandler( + app.mm, + app.configurator, + app.StakingKeeper, + ), + ) // When a planned update height is reached, the old binary will panic // writing on disk the height and name of the update that triggered it @@ -68,7 +77,7 @@ func (app *App) setupUpgradeHandlers() { }, Deleted: []string{}, } - case v5.UpgradeName, v6.UpgradeName: + case v5.UpgradeName, v6.UpgradeName, v7.UpgradeName: // No store upgrades for v5 storeUpgrades = &storetypes.StoreUpgrades{} } diff --git a/app/upgrades/v7/constants.go b/app/upgrades/v7/constants.go new file mode 100644 index 0000000..ab8f7f4 --- /dev/null +++ b/app/upgrades/v7/constants.go @@ -0,0 +1,5 @@ +package v7 + +const ( + UpgradeName = "v7.0.0" +) diff --git a/app/upgrades/v7/integration/network.go b/app/upgrades/v7/integration/network.go new file mode 100644 index 0000000..644c11a --- /dev/null +++ b/app/upgrades/v7/integration/network.go @@ -0,0 +1,79 @@ +package tests + +import ( + upgradetypes "cosmossdk.io/x/upgrade/types" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + "github.com/cosmos/cosmos-sdk/x/authz" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + distrtypes "github.com/cosmos/cosmos-sdk/x/distribution/types" + govtypes "github.com/cosmos/cosmos-sdk/x/gov/types/v1" + stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" + erc20types "github.com/evmos/evmos/v20/x/erc20/types" + evmtypes "github.com/evmos/evmos/v20/x/evm/types" + feemarkettypes "github.com/evmos/evmos/v20/x/feemarket/types" + commonnetwork "github.com/xrplevm/node/v6/testutil/integration/common/network" + exrpcommon "github.com/xrplevm/node/v6/testutil/integration/exrp/common" + upgradenetwork "github.com/xrplevm/node/v6/testutil/integration/exrp/upgrade" + poatypes "github.com/xrplevm/node/v6/x/poa/types" +) + +var _ commonnetwork.Network = (*UpgradeTestNetwork)(nil) + +type UpgradeTestNetwork struct { + upgradenetwork.UpgradeIntegrationNetwork +} + +func NewUpgradeTestNetwork(opts ...exrpcommon.ConfigOption) *UpgradeTestNetwork { + network := upgradenetwork.New(opts...) + return &UpgradeTestNetwork{ + UpgradeIntegrationNetwork: *network, + } +} + +func (n *UpgradeTestNetwork) SetupSdkConfig() { + exrpcommon.SetupSdkConfig() +} + +func (n *UpgradeTestNetwork) GetERC20Client() erc20types.QueryClient { + return exrpcommon.GetERC20Client(n) +} + +func (n *UpgradeTestNetwork) GetEvmClient() evmtypes.QueryClient { + return exrpcommon.GetEvmClient(n) +} + +func (n *UpgradeTestNetwork) GetGovClient() govtypes.QueryClient { + return exrpcommon.GetGovClient(n) +} + +func (n *UpgradeTestNetwork) GetBankClient() banktypes.QueryClient { + return exrpcommon.GetBankClient(n) +} + +func (n *UpgradeTestNetwork) GetFeeMarketClient() feemarkettypes.QueryClient { + return exrpcommon.GetFeeMarketClient(n) +} + +func (n *UpgradeTestNetwork) GetAuthClient() authtypes.QueryClient { + return exrpcommon.GetAuthClient(n) +} + +func (n *UpgradeTestNetwork) GetAuthzClient() authz.QueryClient { + return exrpcommon.GetAuthzClient(n) +} + +func (n *UpgradeTestNetwork) GetStakingClient() stakingtypes.QueryClient { + return exrpcommon.GetStakingClient(n) +} + +func (n *UpgradeTestNetwork) GetDistrClient() distrtypes.QueryClient { + return exrpcommon.GetDistrClient(n) +} + +func (n *UpgradeTestNetwork) GetPoaClient() poatypes.QueryClient { + return exrpcommon.GetPoaClient(n) +} + +func (n *UpgradeTestNetwork) GetUpgradeClient() upgradetypes.QueryClient { + return exrpcommon.GetUpgradeClient(n) +} diff --git a/app/upgrades/v7/integration/suite.go b/app/upgrades/v7/integration/suite.go new file mode 100644 index 0000000..d08cebb --- /dev/null +++ b/app/upgrades/v7/integration/suite.go @@ -0,0 +1,34 @@ +package tests + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/stretchr/testify/suite" + exrpupgrade "github.com/xrplevm/node/v6/testutil/integration/exrp/upgrade" +) + +type UpgradeTestSuite struct { + suite.Suite + + network *UpgradeTestNetwork +} + +func (s *UpgradeTestSuite) Network() *UpgradeTestNetwork { + return s.network +} + +func (s *UpgradeTestSuite) SetupTest() { + // Setup the SDK config + s.network.SetupSdkConfig() + + s.Require().Equal(sdk.GetConfig().GetBech32AccountAddrPrefix(), "ethm") + + // Create the network + s.network = NewUpgradeTestNetwork( + exrpupgrade.WithUpgradePlanName("v6.0.0"), + exrpupgrade.WithDataDir(".exrpd/data"), + exrpupgrade.WithNodeDBName("application"), + ) + + // Check that the network was created successfully + s.Require().NotNil(s.network) +} diff --git a/app/upgrades/v7/integration/suite_test.go b/app/upgrades/v7/integration/suite_test.go new file mode 100644 index 0000000..c7a85c8 --- /dev/null +++ b/app/upgrades/v7/integration/suite_test.go @@ -0,0 +1,40 @@ +package tests + +import ( + "testing" + "time" + + upgradetypes "cosmossdk.io/x/upgrade/types" + stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" + "github.com/stretchr/testify/suite" +) + +func TestUpgradeTestSuite(t *testing.T) { + suite.Run(t, new(UpgradeTestSuite)) +} + +func (s *UpgradeTestSuite) TestUpgradeV7() { + res, err := s.network.GetUpgradeClient().CurrentPlan( + s.network.GetContext(), + &upgradetypes.QueryCurrentPlanRequest{}, + ) + s.Require().NoError(err) + s.Require().Equal("v7.0.0", res.Plan.Name) + + s.Require().True(s.Network().UpgradeKeeper().HasHandler("v7.0.0")) + + err = s.network.UpgradeKeeper().ApplyUpgrade( + s.Network().GetContext(), + *res.Plan, + ) + + s.Require().NoError(err) + + resParams, err := s.network.GetStakingClient().Params( + s.network.GetContext(), + &stakingtypes.QueryParamsRequest{}, + ) + + s.Require().NoError(err) + s.Require().Equal(100*time.Second, resParams.Params.UnbondingTime) +} diff --git a/app/upgrades/v7/upgrades.go b/app/upgrades/v7/upgrades.go new file mode 100644 index 0000000..484c63d --- /dev/null +++ b/app/upgrades/v7/upgrades.go @@ -0,0 +1,35 @@ +package v7 + +import ( + "context" + "time" + + upgradetypes "cosmossdk.io/x/upgrade/types" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/module" + stakingkeeper "github.com/evmos/evmos/v20/x/staking/keeper" +) + +func CreateUpgradeHandler( + mm *module.Manager, + configurator module.Configurator, + sk *stakingkeeper.Keeper, +) upgradetypes.UpgradeHandler { + return func(c context.Context, _ upgradetypes.Plan, vm module.VersionMap) (module.VersionMap, error) { + ctx := sdk.UnwrapSDKContext(c) + logger := ctx.Logger().With("upgrade", UpgradeName) + logger.Info("Running v7 upgrade handler...") + + params, err := sk.GetParams(ctx) + if err != nil { + return vm, err + } + params.UnbondingTime = 100 * time.Second + err = sk.SetParams(ctx, params) + if err != nil { + return vm, err + } + + return mm.RunMigrations(ctx, configurator, vm) + } +} diff --git a/testutil/integration/exrp/upgrade/setup.go b/testutil/integration/exrp/upgrade/setup.go index a737466..d60bf74 100644 --- a/testutil/integration/exrp/upgrade/setup.go +++ b/testutil/integration/exrp/upgrade/setup.go @@ -5,8 +5,8 @@ import ( dbm "github.com/cosmos/cosmos-db" "github.com/cosmos/cosmos-sdk/baseapp" simutils "github.com/cosmos/cosmos-sdk/testutil/sims" - "github.com/xrplevm/node/v5/app" - exrpcommon "github.com/xrplevm/node/v5/testutil/integration/exrp/common" + "github.com/xrplevm/node/v6/app" + exrpcommon "github.com/xrplevm/node/v6/testutil/integration/exrp/common" ) // createExrpApp creates an exrp app From 7a2aefa74661e2ee6d7e6a73bf3a08a919865863 Mon Sep 17 00:00:00 2001 From: GuillemGarciaDev Date: Thu, 30 Jan 2025 09:45:32 +0100 Subject: [PATCH 11/25] fix(tests): replace upgrade plan name with v7 --- app/upgrades/v7/integration/suite.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/upgrades/v7/integration/suite.go b/app/upgrades/v7/integration/suite.go index d08cebb..871ed86 100644 --- a/app/upgrades/v7/integration/suite.go +++ b/app/upgrades/v7/integration/suite.go @@ -24,7 +24,7 @@ func (s *UpgradeTestSuite) SetupTest() { // Create the network s.network = NewUpgradeTestNetwork( - exrpupgrade.WithUpgradePlanName("v6.0.0"), + exrpupgrade.WithUpgradePlanName("v7.0.0"), exrpupgrade.WithDataDir(".exrpd/data"), exrpupgrade.WithNodeDBName("application"), ) From 596829d0eb7db676be18e1bc3c6d7baf26120e24 Mon Sep 17 00:00:00 2001 From: GuillemGarciaDev Date: Thu, 30 Jan 2025 16:13:48 +0100 Subject: [PATCH 12/25] feat(tests): upgrade auth module tests --- app/upgrades/v7/integration/auth_test.go | 44 ++++++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 app/upgrades/v7/integration/auth_test.go diff --git a/app/upgrades/v7/integration/auth_test.go b/app/upgrades/v7/integration/auth_test.go new file mode 100644 index 0000000..64f965d --- /dev/null +++ b/app/upgrades/v7/integration/auth_test.go @@ -0,0 +1,44 @@ +//nolint:dupl +package integration + +import ( + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" +) + +func (s *UpgradeTestSuite) TestUpgrade_Auth_Params() { + prevParams, err := s.network.GetAuthClient().Params( + s.network.GetContext(), + &authtypes.QueryParamsRequest{}, + ) + s.Require().NoError(err) + + s.RunUpgrade(upgradeName) + + postParams, err := s.network.GetAuthClient().Params( + s.network.GetContext(), + &authtypes.QueryParamsRequest{}, + ) + s.Require().NoError(err) + + // Check that not modified params are the same + s.Require().Equal(prevParams.Params, postParams.Params) +} + +func (s *UpgradeTestSuite) TestUpgrade_Auth_Accounts() { + res, err := s.network.GetAuthClient().Accounts( + s.network.GetContext(), + &authtypes.QueryAccountsRequest{}, + ) + s.Require().NoError(err) + + s.RunUpgrade(upgradeName) + + postRes, err := s.network.GetAuthClient().Accounts( + s.network.GetContext(), + &authtypes.QueryAccountsRequest{}, + ) + s.Require().NoError(err) + + // Check that not modified accounts are the same + s.Require().Equal(res.Accounts, postRes.Accounts) +} From 99fbf0698a26e393a16d20a9f30db0c14aa9bfc0 Mon Sep 17 00:00:00 2001 From: GuillemGarciaDev Date: Thu, 30 Jan 2025 16:13:54 +0100 Subject: [PATCH 13/25] feat(tests): upgrade bank module tests --- app/upgrades/v7/integration/bank_test.go | 44 ++++++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 app/upgrades/v7/integration/bank_test.go diff --git a/app/upgrades/v7/integration/bank_test.go b/app/upgrades/v7/integration/bank_test.go new file mode 100644 index 0000000..f54ca8f --- /dev/null +++ b/app/upgrades/v7/integration/bank_test.go @@ -0,0 +1,44 @@ +//nolint:dupl +package integration + +import ( + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" +) + +func (s *UpgradeTestSuite) TestUpgrade_Bank_Params() { + prevParams, err := s.network.GetBankClient().Params( + s.network.GetContext(), + &banktypes.QueryParamsRequest{}, + ) + s.Require().NoError(err) + + s.RunUpgrade(upgradeName) + + postParams, err := s.network.GetBankClient().Params( + s.network.GetContext(), + &banktypes.QueryParamsRequest{}, + ) + s.Require().NoError(err) + + // Check that not modified params are the same + s.Require().Equal(prevParams.Params, postParams.Params) +} + +func (s *UpgradeTestSuite) TestUpgrade_Bank_TotalSupply() { + res, err := s.network.GetBankClient().TotalSupply( + s.network.GetContext(), + &banktypes.QueryTotalSupplyRequest{}, + ) + s.Require().NoError(err) + + s.RunUpgrade(upgradeName) + + postRes, err := s.network.GetBankClient().TotalSupply( + s.network.GetContext(), + &banktypes.QueryTotalSupplyRequest{}, + ) + s.Require().NoError(err) + + // Check that not modified balances are the same + s.Require().Equal(res.Supply, postRes.Supply) +} From a51bc65847bffea6057e0fbdd7b77627c32e72bf Mon Sep 17 00:00:00 2001 From: GuillemGarciaDev Date: Thu, 30 Jan 2025 16:14:02 +0100 Subject: [PATCH 14/25] feat(tests): upgrade distribution module tests --- .../v7/integration/distribution_test.go | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 app/upgrades/v7/integration/distribution_test.go diff --git a/app/upgrades/v7/integration/distribution_test.go b/app/upgrades/v7/integration/distribution_test.go new file mode 100644 index 0000000..ab3240a --- /dev/null +++ b/app/upgrades/v7/integration/distribution_test.go @@ -0,0 +1,24 @@ +package integration + +import ( + distributiontypes "github.com/cosmos/cosmos-sdk/x/distribution/types" +) + +func (s *UpgradeTestSuite) TestUpgrade_DistributionParams() { + prevParams, err := s.network.GetDistrClient().Params( + s.network.GetContext(), + &distributiontypes.QueryParamsRequest{}, + ) + s.Require().NoError(err) + + s.RunUpgrade(upgradeName) + + postParams, err := s.network.GetDistrClient().Params( + s.network.GetContext(), + &distributiontypes.QueryParamsRequest{}, + ) + s.Require().NoError(err) + + // Check that not modified params are the same + s.Require().Equal(prevParams.Params, postParams.Params) +} From 7701cecf7c8de79f7a9f3bfe2c53e71034d9c20f Mon Sep 17 00:00:00 2001 From: GuillemGarciaDev Date: Thu, 30 Jan 2025 16:14:09 +0100 Subject: [PATCH 15/25] feat(tests): upgrade erc20 module tests --- app/upgrades/v7/integration/erc20_test.go | 44 +++++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 app/upgrades/v7/integration/erc20_test.go diff --git a/app/upgrades/v7/integration/erc20_test.go b/app/upgrades/v7/integration/erc20_test.go new file mode 100644 index 0000000..7f6c629 --- /dev/null +++ b/app/upgrades/v7/integration/erc20_test.go @@ -0,0 +1,44 @@ +//nolint:dupl +package integration + +import ( + erc20types "github.com/evmos/evmos/v20/x/erc20/types" +) + +func (s *UpgradeTestSuite) TestUpgrade_ERC20Params() { + prevParams, err := s.network.GetERC20Client().Params( + s.network.GetContext(), + &erc20types.QueryParamsRequest{}, + ) + s.Require().NoError(err) + + s.RunUpgrade(upgradeName) + + postParams, err := s.network.GetERC20Client().Params( + s.network.GetContext(), + &erc20types.QueryParamsRequest{}, + ) + s.Require().NoError(err) + + // Check that not modified params are the same + s.Require().Equal(prevParams.Params, postParams.Params) +} + +func (s *UpgradeTestSuite) TestUpgrade_ERC20_TokenPairs() { + prevTokenPairs, err := s.network.GetERC20Client().TokenPairs( + s.network.GetContext(), + &erc20types.QueryTokenPairsRequest{}, + ) + s.Require().NoError(err) + + s.RunUpgrade(upgradeName) + + postTokenPairs, err := s.network.GetERC20Client().TokenPairs( + s.network.GetContext(), + &erc20types.QueryTokenPairsRequest{}, + ) + s.Require().NoError(err) + + // Check that not modified token pairs are the same + s.Require().Equal(prevTokenPairs.TokenPairs, postTokenPairs.TokenPairs) +} From 4a7c5b730340a47e7649205b3c4ecf614f3caa97 Mon Sep 17 00:00:00 2001 From: GuillemGarciaDev Date: Thu, 30 Jan 2025 16:14:14 +0100 Subject: [PATCH 16/25] feat(tests): upgrade evm module tests --- app/upgrades/v7/integration/evm_test.go | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 app/upgrades/v7/integration/evm_test.go diff --git a/app/upgrades/v7/integration/evm_test.go b/app/upgrades/v7/integration/evm_test.go new file mode 100644 index 0000000..a56fb3c --- /dev/null +++ b/app/upgrades/v7/integration/evm_test.go @@ -0,0 +1,24 @@ +package integration + +import ( + evmtypes "github.com/evmos/evmos/v20/x/evm/types" +) + +func (s *UpgradeTestSuite) TestUpgrade_EvmParams() { + prevParams, err := s.network.GetEvmClient().Params( + s.network.GetContext(), + &evmtypes.QueryParamsRequest{}, + ) + s.Require().NoError(err) + + s.RunUpgrade(upgradeName) + + postParams, err := s.network.GetEvmClient().Params( + s.network.GetContext(), + &evmtypes.QueryParamsRequest{}, + ) + s.Require().NoError(err) + + // Check that not modified params are the same + s.Require().Equal(prevParams.Params, postParams.Params) +} From cd101b4227e59fb194e99957936bb409c9d1b8df Mon Sep 17 00:00:00 2001 From: GuillemGarciaDev Date: Thu, 30 Jan 2025 16:14:20 +0100 Subject: [PATCH 17/25] feat(tests): upgrade feemarket module tests --- app/upgrades/v7/integration/feemarket_test.go | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 app/upgrades/v7/integration/feemarket_test.go diff --git a/app/upgrades/v7/integration/feemarket_test.go b/app/upgrades/v7/integration/feemarket_test.go new file mode 100644 index 0000000..8af75d5 --- /dev/null +++ b/app/upgrades/v7/integration/feemarket_test.go @@ -0,0 +1,24 @@ +package integration + +import ( + feemarkettypes "github.com/evmos/evmos/v20/x/feemarket/types" +) + +func (s *UpgradeTestSuite) TestUpgrade_FeeMarketParams() { + prevParams, err := s.network.GetFeeMarketClient().Params( + s.network.GetContext(), + &feemarkettypes.QueryParamsRequest{}, + ) + s.Require().NoError(err) + + s.RunUpgrade(upgradeName) + + postParams, err := s.network.GetFeeMarketClient().Params( + s.network.GetContext(), + &feemarkettypes.QueryParamsRequest{}, + ) + s.Require().NoError(err) + + // Check that not modified params are the same + s.Require().Equal(prevParams.Params, postParams.Params) +} From 56edca6d56849b280f202e57ab35f93c77a55e5b Mon Sep 17 00:00:00 2001 From: GuillemGarciaDev Date: Thu, 30 Jan 2025 16:14:26 +0100 Subject: [PATCH 18/25] feat(tests): upgrade gov module tests --- app/upgrades/v7/integration/gov_test.go | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 app/upgrades/v7/integration/gov_test.go diff --git a/app/upgrades/v7/integration/gov_test.go b/app/upgrades/v7/integration/gov_test.go new file mode 100644 index 0000000..3790d9c --- /dev/null +++ b/app/upgrades/v7/integration/gov_test.go @@ -0,0 +1,24 @@ +package integration + +import ( + govtypes "github.com/cosmos/cosmos-sdk/x/gov/types/v1" +) + +func (s *UpgradeTestSuite) TestUpgrade_GovParams() { + prevParams, err := s.network.GetGovClient().Params( + s.network.GetContext(), + &govtypes.QueryParamsRequest{}, + ) + s.Require().NoError(err) + + s.RunUpgrade(upgradeName) + + postParams, err := s.network.GetGovClient().Params( + s.network.GetContext(), + &govtypes.QueryParamsRequest{}, + ) + s.Require().NoError(err) + + // Check that not modified params are the same + s.Require().Equal(prevParams.Params, postParams.Params) +} From fc20391c8c24eebe9d91582fcff2277d24ac32fa Mon Sep 17 00:00:00 2001 From: GuillemGarciaDev Date: Thu, 30 Jan 2025 16:14:41 +0100 Subject: [PATCH 19/25] feat(tests): upgrade slashing module tests --- app/upgrades/v7/integration/slashing_test.go | 44 ++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 app/upgrades/v7/integration/slashing_test.go diff --git a/app/upgrades/v7/integration/slashing_test.go b/app/upgrades/v7/integration/slashing_test.go new file mode 100644 index 0000000..ee0d4cd --- /dev/null +++ b/app/upgrades/v7/integration/slashing_test.go @@ -0,0 +1,44 @@ +//nolint:dupl +package integration + +import ( + slashingtypes "github.com/cosmos/cosmos-sdk/x/slashing/types" +) + +func (s *UpgradeTestSuite) TestUpgrade_SlashingParams() { + prevParams, err := s.network.GetSlashingClient().Params( + s.network.GetContext(), + &slashingtypes.QueryParamsRequest{}, + ) + s.Require().NoError(err) + + s.RunUpgrade(upgradeName) + + postParams, err := s.network.GetSlashingClient().Params( + s.network.GetContext(), + &slashingtypes.QueryParamsRequest{}, + ) + s.Require().NoError(err) + + // Check that not modified params are the same + s.Require().Equal(prevParams.Params, postParams.Params) +} + +func (s *UpgradeTestSuite) TestUpgrade_Slashing_SigningInfos() { + prevSigningInfos, err := s.network.GetSlashingClient().SigningInfos( + s.network.GetContext(), + &slashingtypes.QuerySigningInfosRequest{}, + ) + s.Require().NoError(err) + + s.RunUpgrade(upgradeName) + + postSigningInfos, err := s.network.GetSlashingClient().SigningInfos( + s.network.GetContext(), + &slashingtypes.QuerySigningInfosRequest{}, + ) + s.Require().NoError(err) + + // Check that not modified signing infos are the same + s.Require().Equal(prevSigningInfos.Info, postSigningInfos.Info) +} From dd1c4a6fba2bfc04bf4612f9df9c60ceee125f53 Mon Sep 17 00:00:00 2001 From: GuillemGarciaDev Date: Thu, 30 Jan 2025 16:14:49 +0100 Subject: [PATCH 20/25] feat(tests): upgrade staking module tests --- app/upgrades/v7/integration/staking_test.go | 69 +++++++++++++++++++++ 1 file changed, 69 insertions(+) create mode 100644 app/upgrades/v7/integration/staking_test.go diff --git a/app/upgrades/v7/integration/staking_test.go b/app/upgrades/v7/integration/staking_test.go new file mode 100644 index 0000000..bce9650 --- /dev/null +++ b/app/upgrades/v7/integration/staking_test.go @@ -0,0 +1,69 @@ +package integration + +import ( + "time" + + stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" +) + +func (s *UpgradeTestSuite) TestUpgrade_Staking_Params() { + prevParams, err := s.network.GetStakingClient().Params( + s.network.GetContext(), + &stakingtypes.QueryParamsRequest{}, + ) + s.Require().NoError(err) + + s.RunUpgrade(upgradeName) + + postParams, err := s.network.GetStakingClient().Params( + s.network.GetContext(), + &stakingtypes.QueryParamsRequest{}, + ) + s.Require().NoError(err) + + // Check that not modified params are the same + s.Require().Equal(prevParams.Params.BondDenom, postParams.Params.BondDenom) + s.Require().Equal(prevParams.Params.MaxValidators, postParams.Params.MaxValidators) + s.Require().Equal(prevParams.Params.MinCommissionRate, postParams.Params.MinCommissionRate) + s.Require().Equal(prevParams.Params.MaxEntries, postParams.Params.MaxEntries) + s.Require().Equal(prevParams.Params.HistoricalEntries, postParams.Params.HistoricalEntries) + + // Check that unbonding time was modified + s.Require().Equal(postParams.Params.UnbondingTime, 100*time.Second) +} + +func (s *UpgradeTestSuite) TestUpgrade_Staking_Validators() { + res, err := s.network.GetStakingClient().Validators( + s.network.GetContext(), + &stakingtypes.QueryValidatorsRequest{}, + ) + s.Require().NoError(err) + + s.RunUpgrade(upgradeName) + + postRes, err := s.network.GetStakingClient().Validators( + s.network.GetContext(), + &stakingtypes.QueryValidatorsRequest{}, + ) + s.Require().NoError(err) + + // Check that not modified validators are the same + s.Require().Equal(res.Validators, postRes.Validators) +} + +func (s *UpgradeTestSuite) TestUpgrade_Staking_Delegations() { + prevDelegations, err := s.network.StakingKeeper().GetAllDelegations( + s.network.GetContext(), + ) + s.Require().NoError(err) + + s.RunUpgrade(upgradeName) + + postDelegations, err := s.network.StakingKeeper().GetAllDelegations( + s.network.GetContext(), + ) + s.Require().NoError(err) + + // Check that not modified delegations are the same + s.Require().Equal(prevDelegations, postDelegations) +} From c2ce5b4607e092fd8425bfb1ac2a8322f3184247 Mon Sep 17 00:00:00 2001 From: GuillemGarciaDev Date: Thu, 30 Jan 2025 16:15:10 +0100 Subject: [PATCH 21/25] refactor(tests): upgrade test suite --- app/upgrades/v7/integration/network.go | 7 +++- app/upgrades/v7/integration/suite.go | 42 ++++++++++++++++--- app/upgrades/v7/integration/suite_test.go | 31 +------------- .../integration/common/network/network.go | 1 - 4 files changed, 43 insertions(+), 38 deletions(-) diff --git a/app/upgrades/v7/integration/network.go b/app/upgrades/v7/integration/network.go index 644c11a..f82507b 100644 --- a/app/upgrades/v7/integration/network.go +++ b/app/upgrades/v7/integration/network.go @@ -1,4 +1,4 @@ -package tests +package integration import ( upgradetypes "cosmossdk.io/x/upgrade/types" @@ -7,6 +7,7 @@ import ( banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" distrtypes "github.com/cosmos/cosmos-sdk/x/distribution/types" govtypes "github.com/cosmos/cosmos-sdk/x/gov/types/v1" + slashingtypes "github.com/cosmos/cosmos-sdk/x/slashing/types" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" erc20types "github.com/evmos/evmos/v20/x/erc20/types" evmtypes "github.com/evmos/evmos/v20/x/evm/types" @@ -66,6 +67,10 @@ func (n *UpgradeTestNetwork) GetStakingClient() stakingtypes.QueryClient { return exrpcommon.GetStakingClient(n) } +func (n *UpgradeTestNetwork) GetSlashingClient() slashingtypes.QueryClient { + return exrpcommon.GetSlashingClient(n) +} + func (n *UpgradeTestNetwork) GetDistrClient() distrtypes.QueryClient { return exrpcommon.GetDistrClient(n) } diff --git a/app/upgrades/v7/integration/suite.go b/app/upgrades/v7/integration/suite.go index 871ed86..56eaf08 100644 --- a/app/upgrades/v7/integration/suite.go +++ b/app/upgrades/v7/integration/suite.go @@ -1,11 +1,18 @@ -package tests +package integration import ( + "os/exec" + + upgradetypes "cosmossdk.io/x/upgrade/types" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/stretchr/testify/suite" exrpupgrade "github.com/xrplevm/node/v6/testutil/integration/exrp/upgrade" ) +const ( + upgradeName = "v7.0.0" +) + type UpgradeTestSuite struct { suite.Suite @@ -16,19 +23,42 @@ func (s *UpgradeTestSuite) Network() *UpgradeTestNetwork { return s.network } -func (s *UpgradeTestSuite) SetupTest() { +func (s *UpgradeTestSuite) SetupSuite() { // Setup the SDK config s.network.SetupSdkConfig() s.Require().Equal(sdk.GetConfig().GetBech32AccountAddrPrefix(), "ethm") +} + +func (s *UpgradeTestSuite) SetupTest() { + s.Require().NoError(exec.Command("cp", "-r", ".exrpd", ".exrpd-v7").Run()) // Create the network s.network = NewUpgradeTestNetwork( - exrpupgrade.WithUpgradePlanName("v7.0.0"), - exrpupgrade.WithDataDir(".exrpd/data"), + exrpupgrade.WithUpgradePlanName(upgradeName), + exrpupgrade.WithDataDir(".exrpd-v7/data"), exrpupgrade.WithNodeDBName("application"), ) +} + +func (s *UpgradeTestSuite) TearDownTest() { + s.Require().NoError(exec.Command("rm", "-rf", ".exrpd-v7").Run()) +} + +func (s *UpgradeTestSuite) RunUpgrade(name string) { + res, err := s.network.GetUpgradeClient().CurrentPlan( + s.network.GetContext(), + &upgradetypes.QueryCurrentPlanRequest{}, + ) + s.Require().NoError(err) + s.Require().Equal(name, res.Plan.Name) + + s.Require().True(s.Network().UpgradeKeeper().HasHandler(name)) + + err = s.network.UpgradeKeeper().ApplyUpgrade( + s.Network().GetContext(), + *res.Plan, + ) - // Check that the network was created successfully - s.Require().NotNil(s.network) + s.Require().NoError(err) } diff --git a/app/upgrades/v7/integration/suite_test.go b/app/upgrades/v7/integration/suite_test.go index c7a85c8..dd3fe6f 100644 --- a/app/upgrades/v7/integration/suite_test.go +++ b/app/upgrades/v7/integration/suite_test.go @@ -1,40 +1,11 @@ -package tests +package integration import ( "testing" - "time" - upgradetypes "cosmossdk.io/x/upgrade/types" - stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" "github.com/stretchr/testify/suite" ) func TestUpgradeTestSuite(t *testing.T) { suite.Run(t, new(UpgradeTestSuite)) } - -func (s *UpgradeTestSuite) TestUpgradeV7() { - res, err := s.network.GetUpgradeClient().CurrentPlan( - s.network.GetContext(), - &upgradetypes.QueryCurrentPlanRequest{}, - ) - s.Require().NoError(err) - s.Require().Equal("v7.0.0", res.Plan.Name) - - s.Require().True(s.Network().UpgradeKeeper().HasHandler("v7.0.0")) - - err = s.network.UpgradeKeeper().ApplyUpgrade( - s.Network().GetContext(), - *res.Plan, - ) - - s.Require().NoError(err) - - resParams, err := s.network.GetStakingClient().Params( - s.network.GetContext(), - &stakingtypes.QueryParamsRequest{}, - ) - - s.Require().NoError(err) - s.Require().Equal(100*time.Second, resParams.Params.UnbondingTime) -} diff --git a/testutil/integration/common/network/network.go b/testutil/integration/common/network/network.go index bb98e18..993f4f6 100644 --- a/testutil/integration/common/network/network.go +++ b/testutil/integration/common/network/network.go @@ -45,7 +45,6 @@ type Network interface { GetDistrClient() distrtypes.QueryClient GetFeeMarketClient() feemarkettypes.QueryClient GetGovClient() govtypes.QueryClient - BroadcastTxSync(txBytes []byte) (abcitypes.ExecTxResult, error) Simulate(txBytes []byte) (*txtypes.SimulateResponse, error) CheckTx(txBytes []byte) (*abcitypes.ResponseCheckTx, error) From 6c581f7e4bc8e8b74e6081bf4a1b220ae44a51e7 Mon Sep 17 00:00:00 2001 From: GuillemGarciaDev Date: Fri, 31 Jan 2025 13:36:46 +0100 Subject: [PATCH 22/25] feat(tests): add poa upgrade tests --- app/upgrades/v7/integration/bank_test.go | 59 +++++++++ app/upgrades/v7/integration/erc20_test.go | 123 +++++++++++++++++++ app/upgrades/v7/integration/poa_test.go | 98 +++++++++++++++ app/upgrades/v7/integration/staking_test.go | 36 ++++++ app/upgrades/v7/integration/suite.go | 17 +++ testutil/integration/exrp/upgrade/keepers.go | 5 + 6 files changed, 338 insertions(+) create mode 100644 app/upgrades/v7/integration/poa_test.go diff --git a/app/upgrades/v7/integration/bank_test.go b/app/upgrades/v7/integration/bank_test.go index f54ca8f..7bf1f1f 100644 --- a/app/upgrades/v7/integration/bank_test.go +++ b/app/upgrades/v7/integration/bank_test.go @@ -2,6 +2,7 @@ package integration import ( + sdktypes "github.com/cosmos/cosmos-sdk/types" banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" ) @@ -42,3 +43,61 @@ func (s *UpgradeTestSuite) TestUpgrade_Bank_TotalSupply() { // Check that not modified balances are the same s.Require().Equal(res.Supply, postRes.Supply) } + +func (s *UpgradeTestSuite) TestUpgrade_Bank_Send() { + // Replace with the desired addresses + sender, err := sdktypes.AccAddressFromBech32("ethm1dakgyqjulg29m5fmv992g2y66m9g2mjn6hahwg") + s.Require().NoError(err) + receiver, err := sdktypes.AccAddressFromBech32("ethm1nqvn2hmte72e3z0xyqmh06hdwd9qu6hgdcavhh") + s.Require().NoError(err) + amount := sdktypes.NewInt64Coin(s.network.GetDenom(), 100) + + prevBalancesSender, err := s.network.GetBankClient().Balance( + s.network.GetContext(), + &banktypes.QueryBalanceRequest{ + Address: sender.String(), + Denom: s.network.GetDenom(), + }, + ) + s.Require().NoError(err) + + prevBalancesReceiver, err := s.network.GetBankClient().Balance( + s.network.GetContext(), + &banktypes.QueryBalanceRequest{ + Address: receiver.String(), + Denom: s.network.GetDenom(), + }, + ) + s.Require().NoError(err) + + s.RunUpgrade(upgradeName) + + err = s.network.BankKeeper().SendCoins( + s.network.GetContext(), + sender, + receiver, + sdktypes.NewCoins(amount), + ) + s.Require().NoError(err) + + postBalancesSender, err := s.network.GetBankClient().Balance( + s.network.GetContext(), + &banktypes.QueryBalanceRequest{ + Address: sender.String(), + Denom: s.network.GetDenom(), + }, + ) + s.Require().NoError(err) + + postBalancesReceiver, err := s.network.GetBankClient().Balance( + s.network.GetContext(), + &banktypes.QueryBalanceRequest{ + Address: receiver.String(), + Denom: s.network.GetDenom(), + }, + ) + s.Require().NoError(err) + + s.Require().Equal(prevBalancesSender.Balance.Amount.Sub(amount.Amount).String(), postBalancesSender.Balance.Amount.String()) + s.Require().Equal(prevBalancesReceiver.Balance.Amount.Add(amount.Amount).String(), postBalancesReceiver.Balance.Amount.String()) +} diff --git a/app/upgrades/v7/integration/erc20_test.go b/app/upgrades/v7/integration/erc20_test.go index 7f6c629..48f526c 100644 --- a/app/upgrades/v7/integration/erc20_test.go +++ b/app/upgrades/v7/integration/erc20_test.go @@ -2,6 +2,8 @@ package integration import ( + sdktypes "github.com/cosmos/cosmos-sdk/types" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" erc20types "github.com/evmos/evmos/v20/x/erc20/types" ) @@ -42,3 +44,124 @@ func (s *UpgradeTestSuite) TestUpgrade_ERC20_TokenPairs() { // Check that not modified token pairs are the same s.Require().Equal(prevTokenPairs.TokenPairs, postTokenPairs.TokenPairs) } + +func (s *UpgradeTestSuite) TestUpgrade_ERC20_MintCoins() { + tokenPairs, err := s.network.GetERC20Client().TokenPairs( + s.network.GetContext(), + &erc20types.QueryTokenPairsRequest{}, + ) + s.Require().NoError(err) + s.Require().Equal(len(tokenPairs.TokenPairs), 1) + + tokenPair := tokenPairs.TokenPairs[0] + + sender, err := sdktypes.AccAddressFromBech32(tokenPair.OwnerAddress) + s.Require().NoError(err) + + receiver, err := sdktypes.AccAddressFromBech32("ethm1dakgyqjulg29m5fmv992g2y66m9g2mjn6hahwg") + s.Require().NoError(err) + + amount := sdktypes.NewInt64Coin(s.network.GetDenom(), 100) + + prevBalancesReceiver, err := s.network.GetBankClient().Balance( + s.network.GetContext(), + &banktypes.QueryBalanceRequest{ + Address: receiver.String(), + Denom: s.network.GetDenom(), + }, + ) + + s.RunUpgrade(upgradeName) + + err = s.network.ERC20Keeper().MintCoins( + s.network.GetContext(), + sender, + receiver, + amount.Amount, + s.network.GetDenom(), + ) + s.Require().NoError(err) + + postBalancesReceiver, err := s.network.GetBankClient().Balance( + s.network.GetContext(), + &banktypes.QueryBalanceRequest{ + Address: receiver.String(), + Denom: s.network.GetDenom(), + }, + ) + s.Require().NoError(err) + + s.Require().Equal(prevBalancesReceiver.Balance.Amount.Add(amount.Amount).String(), postBalancesReceiver.Balance.Amount.String()) +} + +func (s *UpgradeTestSuite) TestUpgrade_ERC20_BurnCoins() { + sender, err := sdktypes.AccAddressFromBech32("ethm1dakgyqjulg29m5fmv992g2y66m9g2mjn6hahwg") + s.Require().NoError(err) + + amount := sdktypes.NewInt64Coin(s.network.GetDenom(), 100) + + prevBalancesSender, err := s.network.GetBankClient().Balance( + s.network.GetContext(), + &banktypes.QueryBalanceRequest{ + Address: sender.String(), + Denom: s.network.GetDenom(), + }, + ) + s.Require().NoError(err) + + s.RunUpgrade(upgradeName) + + err = s.network.ERC20Keeper().BurnCoins( + s.network.GetContext(), + sender, + amount.Amount, + s.network.GetDenom(), + ) + s.Require().NoError(err) + + postBalancesSender, err := s.network.GetBankClient().Balance( + s.network.GetContext(), + &banktypes.QueryBalanceRequest{ + Address: sender.String(), + Denom: s.network.GetDenom(), + }, + ) + s.Require().NoError(err) + + s.Require().Equal(prevBalancesSender.Balance.Amount.Sub(amount.Amount).String(), postBalancesSender.Balance.Amount.String()) +} + +func (s *UpgradeTestSuite) TestUpgrade_ERC20_TransferOwnership() { + tokenPairs, err := s.network.GetERC20Client().TokenPairs( + s.network.GetContext(), + &erc20types.QueryTokenPairsRequest{}, + ) + s.Require().NoError(err) + s.Require().Equal(len(tokenPairs.TokenPairs), 1) + + tokenPair := tokenPairs.TokenPairs[0] + + sender, err := sdktypes.AccAddressFromBech32(tokenPair.OwnerAddress) + s.Require().NoError(err) + + newOwner, err := sdktypes.AccAddressFromBech32("ethm1nqvn2hmte72e3z0xyqmh06hdwd9qu6hgdcavhh") + s.Require().NoError(err) + + s.network.ERC20Keeper().TransferOwnership( + s.network.GetContext(), + sender, + newOwner, + tokenPair.Denom, + ) + s.Require().NoError(err) + + postTokenPair, err := s.network.GetERC20Client().TokenPair( + s.network.GetContext(), + &erc20types.QueryTokenPairRequest{ + Token: tokenPair.Denom, + }, + ) + s.Require().NoError(err) + + s.Require().Equal(newOwner.String(), postTokenPair.TokenPair.OwnerAddress) +} \ No newline at end of file diff --git a/app/upgrades/v7/integration/poa_test.go b/app/upgrades/v7/integration/poa_test.go new file mode 100644 index 0000000..9c99935 --- /dev/null +++ b/app/upgrades/v7/integration/poa_test.go @@ -0,0 +1,98 @@ +package integration + +import ( + "time" + + "math/rand" + + sdktypes "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/address" + simtypes "github.com/cosmos/cosmos-sdk/types/simulation" + stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" + poatypes "github.com/xrplevm/node/v6/x/poa/types" +) + +func (s *UpgradeTestSuite) TestUpgrade_Poa_ExecuteRemoveValidator() { + validators, err := s.network.GetStakingClient().Validators( + s.network.GetContext(), + &stakingtypes.QueryValidatorsRequest{}, + ) + s.Require().NoError(err) + s.Require().Greater(len(validators.Validators), 0) + + validator := validators.Validators[0] + valAddr, err := sdktypes.ValAddressFromBech32(validator.OperatorAddress) + s.Require().NoError(err) + valAccAddr := sdktypes.AccAddress(valAddr) + + _, err = s.network.GetStakingClient().Validator( + s.network.GetContext(), + &stakingtypes.QueryValidatorRequest{ + ValidatorAddr: validator.OperatorAddress, + }, + ) + s.Require().NoError(err) + + s.RunUpgrade(upgradeName) + + s.network.PoaKeeper().ExecuteRemoveValidator( + s.network.GetContext(), + valAccAddr.String(), + ) + s.Require().NoError(err) + + + postValidator, err := s.network.GetStakingClient().Validator( + s.network.GetContext(), + &stakingtypes.QueryValidatorRequest{ + ValidatorAddr: validator.OperatorAddress, + }, + ) + + s.Require().NoError(err) + s.Require().True(postValidator.Validator.Tokens.IsZero(), "validator tokens should be zero") + s.Require().True(postValidator.Validator.DelegatorShares.RoundInt().IsZero(), "validator delegator shares should be zero") +} + +func (s *UpgradeTestSuite) TestUpgrade_Poa_ExecuteAddValidator() { + randomAccs := simtypes.RandomAccounts(rand.New(rand.NewSource(time.Now().UnixNano())), 1) //nolint:gosec + randomAcc := randomAccs[0] + randomValAddr := sdktypes.ValAddress(randomAcc.Address.Bytes()) + + authority := sdktypes.AccAddress(address.Module("gov")) + msg, err := poatypes.NewMsgAddValidator( + authority.String(), + randomAcc.Address.String(), + randomAcc.ConsKey.PubKey(), + stakingtypes.Description{ + Moniker: "test", + }, + ) + + _, err = s.network.GetStakingClient().Validator( + s.network.GetContext(), + &stakingtypes.QueryValidatorRequest{ + ValidatorAddr: randomValAddr.String(), + }, + ) + s.Require().Error(err) + + s.RunUpgrade(upgradeName) + + err = s.network.PoaKeeper().ExecuteAddValidator( + s.network.GetContext(), + msg, + ) + s.Require().NoError(err) + + val, err := s.network.GetStakingClient().Validator( + s.network.GetContext(), + &stakingtypes.QueryValidatorRequest{ + ValidatorAddr: randomValAddr.String(), + }, + ) + s.Require().NoError(err) + s.Require().Equal(val.Validator.Status, stakingtypes.Unbonded) + s.Require().Equal(val.Validator.Tokens, sdktypes.DefaultPowerReduction) + s.Require().Equal(val.Validator.DelegatorShares, sdktypes.DefaultPowerReduction.ToLegacyDec()) +} diff --git a/app/upgrades/v7/integration/staking_test.go b/app/upgrades/v7/integration/staking_test.go index bce9650..0ac3760 100644 --- a/app/upgrades/v7/integration/staking_test.go +++ b/app/upgrades/v7/integration/staking_test.go @@ -67,3 +67,39 @@ func (s *UpgradeTestSuite) TestUpgrade_Staking_Delegations() { // Check that not modified delegations are the same s.Require().Equal(prevDelegations, postDelegations) } + +func (s *UpgradeTestSuite) TestUpgrade_Staking_UnbondingDelegations() { + prevValidators, err := s.network.StakingKeeper().GetAllValidators( + s.network.GetContext(), + ) + s.Require().NoError(err) + + unbondingDelegations := make(map[string][]stakingtypes.UnbondingDelegation, len(prevValidators)) + for _, validator := range prevValidators { + res, err := s.network.GetStakingClient().ValidatorUnbondingDelegations( + s.network.GetContext(), + &stakingtypes.QueryValidatorUnbondingDelegationsRequest{ + ValidatorAddr: validator.OperatorAddress, + }, + ) + s.Require().NoError(err) + unbondingDelegations[validator.OperatorAddress] = res.UnbondingResponses + } + + s.RunUpgrade(upgradeName) + + postUnbondingDelegations := make(map[string][]stakingtypes.UnbondingDelegation, len(prevValidators)) + for _, validator := range prevValidators { + res, err := s.network.GetStakingClient().ValidatorUnbondingDelegations( + s.network.GetContext(), + &stakingtypes.QueryValidatorUnbondingDelegationsRequest{ + ValidatorAddr: validator.OperatorAddress, + }, + ) + s.Require().NoError(err) + postUnbondingDelegations[validator.OperatorAddress] = res.UnbondingResponses + } + + // Check that not modified unbonding delegations are the same + s.Require().Equal(unbondingDelegations, postUnbondingDelegations) +} diff --git a/app/upgrades/v7/integration/suite.go b/app/upgrades/v7/integration/suite.go index 56eaf08..3178d44 100644 --- a/app/upgrades/v7/integration/suite.go +++ b/app/upgrades/v7/integration/suite.go @@ -6,6 +6,9 @@ import ( upgradetypes "cosmossdk.io/x/upgrade/types" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/stretchr/testify/suite" + "github.com/xrplevm/node/v6/testutil/integration/common/grpc" + "github.com/xrplevm/node/v6/testutil/integration/common/keyring" + exrpcommon "github.com/xrplevm/node/v6/testutil/integration/exrp/common" exrpupgrade "github.com/xrplevm/node/v6/testutil/integration/exrp/upgrade" ) @@ -17,6 +20,8 @@ type UpgradeTestSuite struct { suite.Suite network *UpgradeTestNetwork + keyring keyring.Keyring + grpcHandler grpc.Handler } func (s *UpgradeTestSuite) Network() *UpgradeTestNetwork { @@ -31,6 +36,9 @@ func (s *UpgradeTestSuite) SetupSuite() { } func (s *UpgradeTestSuite) SetupTest() { + // Check that the network was created successfully + kr := keyring.New(5) + s.Require().NoError(exec.Command("cp", "-r", ".exrpd", ".exrpd-v7").Run()) // Create the network @@ -38,7 +46,14 @@ func (s *UpgradeTestSuite) SetupTest() { exrpupgrade.WithUpgradePlanName(upgradeName), exrpupgrade.WithDataDir(".exrpd-v7/data"), exrpupgrade.WithNodeDBName("application"), + exrpcommon.WithBondDenom("apoa"), + exrpcommon.WithDenom("token"), ) + + rpcHandler := grpc.NewIntegrationHandler(s.network) + + s.grpcHandler = rpcHandler + s.keyring = kr } func (s *UpgradeTestSuite) TearDownTest() { @@ -61,4 +76,6 @@ func (s *UpgradeTestSuite) RunUpgrade(name string) { ) s.Require().NoError(err) + + } diff --git a/testutil/integration/exrp/upgrade/keepers.go b/testutil/integration/exrp/upgrade/keepers.go index 70fd1b8..cd34b9a 100644 --- a/testutil/integration/exrp/upgrade/keepers.go +++ b/testutil/integration/exrp/upgrade/keepers.go @@ -10,6 +10,7 @@ import ( stakingkeeper "github.com/cosmos/cosmos-sdk/x/staking/keeper" upgradekeeper "cosmossdk.io/x/upgrade/keeper" + paramskeeper "github.com/cosmos/cosmos-sdk/x/params/keeper" erc20keeper "github.com/evmos/evmos/v20/x/erc20/keeper" evmkeeper "github.com/evmos/evmos/v20/x/evm/keeper" feemarketkeeper "github.com/evmos/evmos/v20/x/feemarket/keeper" @@ -63,3 +64,7 @@ func (n *UpgradeIntegrationNetwork) PoaKeeper() poakeeper.Keeper { func (n *UpgradeIntegrationNetwork) UpgradeKeeper() upgradekeeper.Keeper { return *n.app.UpgradeKeeper } + +func (n *UpgradeIntegrationNetwork) ParamsKeeper() paramskeeper.Keeper { + return n.app.ParamsKeeper +} From ee31df21b05ea7818a80cd1a46c4e69cf4b0a731 Mon Sep 17 00:00:00 2001 From: GuillemGarciaDev Date: Fri, 31 Jan 2025 13:42:47 +0100 Subject: [PATCH 23/25] chore: remove `test-upgrade` rule from dockerfile --- Dockerfile | 1 - 1 file changed, 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 9aff88a..7e83bd8 100644 --- a/Dockerfile +++ b/Dockerfile @@ -20,7 +20,6 @@ RUN make lint RUN make test-poa # Integration tests RUN make test-integration -RUN make test-upgrade # Simulation tests RUN make test-sim-benchmark-simulation RUN make test-sim-full-app-fast From 94cd5f853818cb026dc7d37d6efa9a34a76b1f6a Mon Sep 17 00:00:00 2001 From: GuillemGarciaDev Date: Fri, 31 Jan 2025 15:37:49 +0100 Subject: [PATCH 24/25] fix(tests): linting --- app/upgrades/v7/integration/bank_test.go | 1 - app/upgrades/v7/integration/erc20_test.go | 7 +++---- app/upgrades/v7/integration/poa_test.go | 13 ++++++------- app/upgrades/v7/integration/suite.go | 6 ++---- 4 files changed, 11 insertions(+), 16 deletions(-) diff --git a/app/upgrades/v7/integration/bank_test.go b/app/upgrades/v7/integration/bank_test.go index 7bf1f1f..17f6b04 100644 --- a/app/upgrades/v7/integration/bank_test.go +++ b/app/upgrades/v7/integration/bank_test.go @@ -1,4 +1,3 @@ -//nolint:dupl package integration import ( diff --git a/app/upgrades/v7/integration/erc20_test.go b/app/upgrades/v7/integration/erc20_test.go index 48f526c..5435ec2 100644 --- a/app/upgrades/v7/integration/erc20_test.go +++ b/app/upgrades/v7/integration/erc20_test.go @@ -1,4 +1,3 @@ -//nolint:dupl package integration import ( @@ -70,7 +69,7 @@ func (s *UpgradeTestSuite) TestUpgrade_ERC20_MintCoins() { Denom: s.network.GetDenom(), }, ) - + s.Require().NoError(err) s.RunUpgrade(upgradeName) err = s.network.ERC20Keeper().MintCoins( @@ -147,7 +146,7 @@ func (s *UpgradeTestSuite) TestUpgrade_ERC20_TransferOwnership() { newOwner, err := sdktypes.AccAddressFromBech32("ethm1nqvn2hmte72e3z0xyqmh06hdwd9qu6hgdcavhh") s.Require().NoError(err) - s.network.ERC20Keeper().TransferOwnership( + err = s.network.ERC20Keeper().TransferOwnership( s.network.GetContext(), sender, newOwner, @@ -164,4 +163,4 @@ func (s *UpgradeTestSuite) TestUpgrade_ERC20_TransferOwnership() { s.Require().NoError(err) s.Require().Equal(newOwner.String(), postTokenPair.TokenPair.OwnerAddress) -} \ No newline at end of file +} diff --git a/app/upgrades/v7/integration/poa_test.go b/app/upgrades/v7/integration/poa_test.go index 9c99935..e95e182 100644 --- a/app/upgrades/v7/integration/poa_test.go +++ b/app/upgrades/v7/integration/poa_test.go @@ -1,9 +1,8 @@ package integration import ( - "time" - "math/rand" + "time" sdktypes "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/address" @@ -35,12 +34,11 @@ func (s *UpgradeTestSuite) TestUpgrade_Poa_ExecuteRemoveValidator() { s.RunUpgrade(upgradeName) - s.network.PoaKeeper().ExecuteRemoveValidator( + err = s.network.PoaKeeper().ExecuteRemoveValidator( s.network.GetContext(), valAccAddr.String(), ) s.Require().NoError(err) - postValidator, err := s.network.GetStakingClient().Validator( s.network.GetContext(), @@ -54,10 +52,10 @@ func (s *UpgradeTestSuite) TestUpgrade_Poa_ExecuteRemoveValidator() { s.Require().True(postValidator.Validator.DelegatorShares.RoundInt().IsZero(), "validator delegator shares should be zero") } -func (s *UpgradeTestSuite) TestUpgrade_Poa_ExecuteAddValidator() { +func (s *UpgradeTestSuite) TestUpgrade_Poa_ExecuteAddValidator() { randomAccs := simtypes.RandomAccounts(rand.New(rand.NewSource(time.Now().UnixNano())), 1) //nolint:gosec randomAcc := randomAccs[0] - randomValAddr := sdktypes.ValAddress(randomAcc.Address.Bytes()) + randomValAddr := sdktypes.ValAddress(randomAcc.Address.Bytes()) authority := sdktypes.AccAddress(address.Module("gov")) msg, err := poatypes.NewMsgAddValidator( @@ -68,6 +66,7 @@ func (s *UpgradeTestSuite) TestUpgrade_Poa_ExecuteAddValidator() { Moniker: "test", }, ) + s.Require().NoError(err) _, err = s.network.GetStakingClient().Validator( s.network.GetContext(), @@ -84,7 +83,7 @@ func (s *UpgradeTestSuite) TestUpgrade_Poa_ExecuteAddValidator() { msg, ) s.Require().NoError(err) - + val, err := s.network.GetStakingClient().Validator( s.network.GetContext(), &stakingtypes.QueryValidatorRequest{ diff --git a/app/upgrades/v7/integration/suite.go b/app/upgrades/v7/integration/suite.go index 3178d44..ad53443 100644 --- a/app/upgrades/v7/integration/suite.go +++ b/app/upgrades/v7/integration/suite.go @@ -19,8 +19,8 @@ const ( type UpgradeTestSuite struct { suite.Suite - network *UpgradeTestNetwork - keyring keyring.Keyring + network *UpgradeTestNetwork + keyring keyring.Keyring grpcHandler grpc.Handler } @@ -76,6 +76,4 @@ func (s *UpgradeTestSuite) RunUpgrade(name string) { ) s.Require().NoError(err) - - } From 66099e9b09a623d5d08b9ebaabb4c3179f1a3588 Mon Sep 17 00:00:00 2001 From: GuillemGarciaDev Date: Fri, 31 Jan 2025 16:13:06 +0100 Subject: [PATCH 25/25] feat: customize `test-upgrade` Makefile rule to accept custom options --- Makefile | 10 +-- app/upgrades/v6/integration/network.go | 79 ----------------------- app/upgrades/v6/integration/suite.go | 34 ---------- app/upgrades/v6/integration/suite_test.go | 40 ------------ app/upgrades/v7/integration/suite.go | 9 +-- 5 files changed, 11 insertions(+), 161 deletions(-) delete mode 100644 app/upgrades/v6/integration/network.go delete mode 100644 app/upgrades/v6/integration/suite.go delete mode 100644 app/upgrades/v6/integration/suite_test.go diff --git a/Makefile b/Makefile index 9e2b386..3855b3c 100644 --- a/Makefile +++ b/Makefile @@ -4,8 +4,10 @@ BRANCH := $(shell git rev-parse --abbrev-ref HEAD) COMMIT := $(shell git log -1 --format='%H') BINDIR ?= $(GOPATH)/bin APP = ./app -LATEST_UPGRADE = $(shell ls -d ./app/upgrades/* | sort -r | head -n 1) +# Upgrade testsuite values +LATEST_UPGRADE ?= $(shell ls -d ./app/upgrades/* | sort -r | head -n 1) +SNAPSHOT_DIR ?= .exrpd # don't override user values ifeq (,$(VERSION)) VERSION := $(shell git describe --tags) @@ -129,10 +131,10 @@ mocks: test: test-poa test-integration test-sim-benchmark-simulation test-sim-full-app-fast -test-latest-upgrade: - @echo "--> Running upgrade testsuite" +test-upgrade: + @echo "--> Running upgrade testsuite from snapshot: $(SNAPSHOT_DIR), into $(LATEST_UPGRADE)" @rm -rf $(LATEST_UPGRADE)/integration/.exrpd - @cp -r ./.exrpd $(LATEST_UPGRADE)/integration/.exrpd + @cp -r $(SNAPSHOT_DIR) $(LATEST_UPGRADE)/integration/.exrpd @go test -mod=readonly -v $(LATEST_UPGRADE)/integration test-integration: diff --git a/app/upgrades/v6/integration/network.go b/app/upgrades/v6/integration/network.go deleted file mode 100644 index 644c11a..0000000 --- a/app/upgrades/v6/integration/network.go +++ /dev/null @@ -1,79 +0,0 @@ -package tests - -import ( - upgradetypes "cosmossdk.io/x/upgrade/types" - authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" - "github.com/cosmos/cosmos-sdk/x/authz" - banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" - distrtypes "github.com/cosmos/cosmos-sdk/x/distribution/types" - govtypes "github.com/cosmos/cosmos-sdk/x/gov/types/v1" - stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" - erc20types "github.com/evmos/evmos/v20/x/erc20/types" - evmtypes "github.com/evmos/evmos/v20/x/evm/types" - feemarkettypes "github.com/evmos/evmos/v20/x/feemarket/types" - commonnetwork "github.com/xrplevm/node/v6/testutil/integration/common/network" - exrpcommon "github.com/xrplevm/node/v6/testutil/integration/exrp/common" - upgradenetwork "github.com/xrplevm/node/v6/testutil/integration/exrp/upgrade" - poatypes "github.com/xrplevm/node/v6/x/poa/types" -) - -var _ commonnetwork.Network = (*UpgradeTestNetwork)(nil) - -type UpgradeTestNetwork struct { - upgradenetwork.UpgradeIntegrationNetwork -} - -func NewUpgradeTestNetwork(opts ...exrpcommon.ConfigOption) *UpgradeTestNetwork { - network := upgradenetwork.New(opts...) - return &UpgradeTestNetwork{ - UpgradeIntegrationNetwork: *network, - } -} - -func (n *UpgradeTestNetwork) SetupSdkConfig() { - exrpcommon.SetupSdkConfig() -} - -func (n *UpgradeTestNetwork) GetERC20Client() erc20types.QueryClient { - return exrpcommon.GetERC20Client(n) -} - -func (n *UpgradeTestNetwork) GetEvmClient() evmtypes.QueryClient { - return exrpcommon.GetEvmClient(n) -} - -func (n *UpgradeTestNetwork) GetGovClient() govtypes.QueryClient { - return exrpcommon.GetGovClient(n) -} - -func (n *UpgradeTestNetwork) GetBankClient() banktypes.QueryClient { - return exrpcommon.GetBankClient(n) -} - -func (n *UpgradeTestNetwork) GetFeeMarketClient() feemarkettypes.QueryClient { - return exrpcommon.GetFeeMarketClient(n) -} - -func (n *UpgradeTestNetwork) GetAuthClient() authtypes.QueryClient { - return exrpcommon.GetAuthClient(n) -} - -func (n *UpgradeTestNetwork) GetAuthzClient() authz.QueryClient { - return exrpcommon.GetAuthzClient(n) -} - -func (n *UpgradeTestNetwork) GetStakingClient() stakingtypes.QueryClient { - return exrpcommon.GetStakingClient(n) -} - -func (n *UpgradeTestNetwork) GetDistrClient() distrtypes.QueryClient { - return exrpcommon.GetDistrClient(n) -} - -func (n *UpgradeTestNetwork) GetPoaClient() poatypes.QueryClient { - return exrpcommon.GetPoaClient(n) -} - -func (n *UpgradeTestNetwork) GetUpgradeClient() upgradetypes.QueryClient { - return exrpcommon.GetUpgradeClient(n) -} diff --git a/app/upgrades/v6/integration/suite.go b/app/upgrades/v6/integration/suite.go deleted file mode 100644 index d08cebb..0000000 --- a/app/upgrades/v6/integration/suite.go +++ /dev/null @@ -1,34 +0,0 @@ -package tests - -import ( - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/stretchr/testify/suite" - exrpupgrade "github.com/xrplevm/node/v6/testutil/integration/exrp/upgrade" -) - -type UpgradeTestSuite struct { - suite.Suite - - network *UpgradeTestNetwork -} - -func (s *UpgradeTestSuite) Network() *UpgradeTestNetwork { - return s.network -} - -func (s *UpgradeTestSuite) SetupTest() { - // Setup the SDK config - s.network.SetupSdkConfig() - - s.Require().Equal(sdk.GetConfig().GetBech32AccountAddrPrefix(), "ethm") - - // Create the network - s.network = NewUpgradeTestNetwork( - exrpupgrade.WithUpgradePlanName("v6.0.0"), - exrpupgrade.WithDataDir(".exrpd/data"), - exrpupgrade.WithNodeDBName("application"), - ) - - // Check that the network was created successfully - s.Require().NotNil(s.network) -} diff --git a/app/upgrades/v6/integration/suite_test.go b/app/upgrades/v6/integration/suite_test.go deleted file mode 100644 index 66bb223..0000000 --- a/app/upgrades/v6/integration/suite_test.go +++ /dev/null @@ -1,40 +0,0 @@ -package tests - -import ( - "testing" - "time" - - upgradetypes "cosmossdk.io/x/upgrade/types" - stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" - "github.com/stretchr/testify/suite" -) - -func TestUpgradeTestSuite(t *testing.T) { - suite.Run(t, new(UpgradeTestSuite)) -} - -func (s *UpgradeTestSuite) TestUpgradeV6() { - res, err := s.network.GetUpgradeClient().CurrentPlan( - s.network.GetContext(), - &upgradetypes.QueryCurrentPlanRequest{}, - ) - s.Require().NoError(err) - s.Require().Equal("v6.0.0", res.Plan.Name) - - s.Require().True(s.Network().UpgradeKeeper().HasHandler("v6.0.0")) - - err = s.network.UpgradeKeeper().ApplyUpgrade( - s.Network().GetContext(), - *res.Plan, - ) - - s.Require().NoError(err) - - resParams, err := s.network.GetStakingClient().Params( - s.network.GetContext(), - &stakingtypes.QueryParamsRequest{}, - ) - - s.Require().NoError(err) - s.Require().Equal(100*time.Second, resParams.Params.UnbondingTime) -} diff --git a/app/upgrades/v7/integration/suite.go b/app/upgrades/v7/integration/suite.go index ad53443..718a5e3 100644 --- a/app/upgrades/v7/integration/suite.go +++ b/app/upgrades/v7/integration/suite.go @@ -13,7 +13,8 @@ import ( ) const ( - upgradeName = "v7.0.0" + upgradeName = "v7.0.0" + testSnapshotDir = ".exrpd" ) type UpgradeTestSuite struct { @@ -39,12 +40,12 @@ func (s *UpgradeTestSuite) SetupTest() { // Check that the network was created successfully kr := keyring.New(5) - s.Require().NoError(exec.Command("cp", "-r", ".exrpd", ".exrpd-v7").Run()) + s.Require().NoError(exec.Command("cp", "-r", testSnapshotDir, testSnapshotDir+"-"+upgradeName).Run()) // Create the network s.network = NewUpgradeTestNetwork( exrpupgrade.WithUpgradePlanName(upgradeName), - exrpupgrade.WithDataDir(".exrpd-v7/data"), + exrpupgrade.WithDataDir(testSnapshotDir+"-"+upgradeName+"/data"), exrpupgrade.WithNodeDBName("application"), exrpcommon.WithBondDenom("apoa"), exrpcommon.WithDenom("token"), @@ -57,7 +58,7 @@ func (s *UpgradeTestSuite) SetupTest() { } func (s *UpgradeTestSuite) TearDownTest() { - s.Require().NoError(exec.Command("rm", "-rf", ".exrpd-v7").Run()) + s.Require().NoError(exec.Command("rm", "-rf", testSnapshotDir+"-"+upgradeName).Run()) } func (s *UpgradeTestSuite) RunUpgrade(name string) {