From a5f9c0e771ea9c9a152aa3d4bfc035f7da6d8f9a Mon Sep 17 00:00:00 2001 From: beer-1 <147697694+beer-1@users.noreply.github.com> Date: Sun, 19 Nov 2023 12:01:49 +0900 Subject: [PATCH 1/5] prevent returning stopping workers --- crates/relayer/src/worker/map.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/crates/relayer/src/worker/map.rs b/crates/relayer/src/worker/map.rs index 65d80d1af1..c1f3568304 100644 --- a/crates/relayer/src/worker/map.rs +++ b/crates/relayer/src/worker/map.rs @@ -124,6 +124,10 @@ impl WorkerMap { dst: Chain, config: &Config, ) -> &WorkerHandle { + + // Clear workers, to prevent returning stopping workers. + self.clean_stopped_workers(); + if self.workers.contains_key(&object) { &self.workers[&object] } else { From d020489737d1b5e738bf2aadd2fdfdcf6460ae88 Mon Sep 17 00:00:00 2001 From: beer-1 <147697694+beer-1@users.noreply.github.com> Date: Thu, 23 Nov 2023 13:50:14 +0900 Subject: [PATCH 2/5] clear only the specific worker --- crates/relayer/src/worker/map.rs | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/crates/relayer/src/worker/map.rs b/crates/relayer/src/worker/map.rs index c1f3568304..c5305f52cb 100644 --- a/crates/relayer/src/worker/map.rs +++ b/crates/relayer/src/worker/map.rs @@ -124,12 +124,18 @@ impl WorkerMap { dst: Chain, config: &Config, ) -> &WorkerHandle { - - // Clear workers, to prevent returning stopping workers. - self.clean_stopped_workers(); - if self.workers.contains_key(&object) { - &self.workers[&object] + if self.workers[&object].shutdown_stopped_tasks() { + self.remove_stopped( + self.workers[&object].id(), + self.workers[&object].object().clone(), + ); + + let worker = self.spawn_worker(src, dst, &object, config); + self.workers.entry(object).or_insert(worker) + } else { + &self.workers[&object] + } } else { let worker = self.spawn_worker(src, dst, &object, config); self.workers.entry(object).or_insert(worker) From fb7773051f0f404ba9fda3e27c2a5d96f71ddb18 Mon Sep 17 00:00:00 2001 From: Luca Joss <43531661+ljoss17@users.noreply.github.com> Date: Thu, 16 Nov 2023 16:57:58 +0100 Subject: [PATCH 3/5] Add ibc-go v8 to integration tests (#3694) * Add simapp v8 to CI jobs * Add simapp v8 to nix flake * Handle CLI breaking changes of Cosmos SDK v0.50 in test bootstrap * Handle genesis config 'voting_perdiod' and CLI 'query txs' changes for Cosmos SDK v0.50.1 * Use 'MsgSubmitProposal' instead of deprecated 'UpgradeProposal' to initiate a chain upgrade * Update 'tx upgrade-chain' CLI template * Fix 'tx chain-upgrade' tests * Update chain upgrade for compatibility between different ibc-go versions * Improve assertion for client upgrade tests * Update ibc-proto-rs to v0.39.0 * Add changelog entry * Fix and improve guide section for client upgrade * Wait before querying client state for client upgrade tests * Apply suggestions from code review Co-authored-by: Romain Ruetschi Signed-off-by: Luca Joss <43531661+ljoss17@users.noreply.github.com> * Rename method 'ibc_version()' to 'version_specs' * Extract the verification of legacy version in a method * Implement 'FromStr' instead of 'TryFrom' for 'ProposalStatus' * Fix cargo-doc warning * Add changelog entry for CLI * Change the '--gov-account' flag as optional but will fail if trying to upgrade a chain with ibc-go v8+ * Update guide * Move and update changelog entry for CLI * Return a 'Specs' struct in 'version_specs()' method * Fix clippy errors --------- Signed-off-by: Luca Joss <43531661+ljoss17@users.noreply.github.com> Co-authored-by: Romain Ruetschi --- .../3696-new-chain-upgrade-flag.md | 3 + .../ibc-relayer/3696-new-upgrade-proposal.md | 3 + .github/workflows/integration.yaml | 9 + .github/workflows/multi-chains.yaml | 3 + Cargo.lock | 105 ++++--- crates/chain-registry/Cargo.toml | 2 +- crates/relayer-cli/src/commands/tx/upgrade.rs | 79 ++++- crates/relayer-types/Cargo.toml | 2 +- crates/relayer/Cargo.toml | 2 +- crates/relayer/src/chain/cosmos.rs | 5 +- .../src/chain/cosmos/types/events/channel.rs | 2 +- crates/relayer/src/chain/endpoint.rs | 3 +- crates/relayer/src/chain/handle.rs | 7 +- crates/relayer/src/chain/handle/base.rs | 9 +- crates/relayer/src/chain/handle/cache.rs | 5 +- crates/relayer/src/chain/handle/counting.rs | 5 +- crates/relayer/src/chain/runtime.rs | 9 +- crates/relayer/src/upgrade_chain.rs | 161 ++++++++++- flake.lock | 20 +- flake.nix | 1 + .../src/documentation/commands/tx/upgrade.md | 22 +- .../documentation/commands/upgrade/test.md | 14 + .../templates/commands/hermes/evidence_1.md | 2 +- .../help_templates/tx/upgrade-chain.md | 4 + tools/check-guide/Cargo.lock | 32 +-- .../src/tests/client_upgrade.rs | 272 +++++++++++------- tools/integration-test/src/tests/ics31.rs | 2 +- .../src/tests/interchain_security/icq.rs | 2 +- tools/test-framework/Cargo.toml | 2 +- .../test-framework/src/chain/cli/bootstrap.rs | 75 ++++- .../test-framework/src/chain/cli/provider.rs | 5 +- tools/test-framework/src/chain/cli/query.rs | 202 ++++++++++++- tools/test-framework/src/chain/config.rs | 32 ++- .../test-framework/src/chain/ext/bootstrap.rs | 113 ++++---- .../test-framework/src/chain/ext/proposal.rs | 39 ++- tools/test-framework/src/chain/tagged.rs | 21 +- tools/test-framework/src/error.rs | 2 +- .../src/framework/binary/ics.rs | 21 +- tools/test-framework/src/relayer/chain.rs | 5 +- .../src/util/interchain_security.rs | 2 +- tools/test-framework/src/util/mod.rs | 1 + .../src/util/proposal_status.rs | 80 ++++++ 42 files changed, 1038 insertions(+), 347 deletions(-) create mode 100644 .changelog/unreleased/features/ibc-relayer-cli/3696-new-chain-upgrade-flag.md create mode 100644 .changelog/unreleased/features/ibc-relayer/3696-new-upgrade-proposal.md create mode 100644 tools/test-framework/src/util/proposal_status.rs diff --git a/.changelog/unreleased/features/ibc-relayer-cli/3696-new-chain-upgrade-flag.md b/.changelog/unreleased/features/ibc-relayer-cli/3696-new-chain-upgrade-flag.md new file mode 100644 index 0000000000..125422b3d5 --- /dev/null +++ b/.changelog/unreleased/features/ibc-relayer-cli/3696-new-chain-upgrade-flag.md @@ -0,0 +1,3 @@ +- Add a `--gov-account` option to `hermes tx upgrade-chain` to specify the + authority account used to sign upgrade proposal for chains running IBC-Go v8+. + ([\#3696](https://github.com/informalsystems/hermes/issues/3696)) \ No newline at end of file diff --git a/.changelog/unreleased/features/ibc-relayer/3696-new-upgrade-proposal.md b/.changelog/unreleased/features/ibc-relayer/3696-new-upgrade-proposal.md new file mode 100644 index 0000000000..8ba9c4c22f --- /dev/null +++ b/.changelog/unreleased/features/ibc-relayer/3696-new-upgrade-proposal.md @@ -0,0 +1,3 @@ +- Use legacy `UpgradeProposal` or newer `MsgIbcSoftwareUpgrade` message when upgrading + a chain depending on whether the chain is running IBC-Go v8 or older. + ([\#3696](https://github.com/informalsystems/hermes/issues/3696)) \ No newline at end of file diff --git a/.github/workflows/integration.yaml b/.github/workflows/integration.yaml index 598b3937ec..7643796859 100644 --- a/.github/workflows/integration.yaml +++ b/.github/workflows/integration.yaml @@ -60,6 +60,9 @@ jobs: - package: ibc-go-v7-simapp command: simd account_prefix: cosmos + - package: ibc-go-v8-simapp + command: simd + account_prefix: cosmos - package: wasmd command: wasmd account_prefix: wasm @@ -157,6 +160,9 @@ jobs: - package: ibc-go-v7-simapp command: simd account_prefix: cosmos + - package: ibc-go-v8-simapp + command: simd + account_prefix: cosmos steps: - uses: actions/checkout@v4 - uses: cachix/install-nix-action@v22 @@ -206,6 +212,9 @@ jobs: - package: ibc-go-v7-simapp command: simd account_prefix: cosmos + - package: ibc-go-v8-simapp + command: simd + account_prefix: cosmos - package: migaloo command: migalood account_prefix: migaloo diff --git a/.github/workflows/multi-chains.yaml b/.github/workflows/multi-chains.yaml index 8aab31647d..681eaada4f 100644 --- a/.github/workflows/multi-chains.yaml +++ b/.github/workflows/multi-chains.yaml @@ -64,6 +64,9 @@ jobs: - package: ibc-go-v7-simapp command: simd account_prefix: cosmos + - package: ibc-go-v8-simapp + command: simd + account_prefix: cosmos - package: wasmd command: wasmd account_prefix: wasm diff --git a/Cargo.lock b/Cargo.lock index c85b113fcd..35214e2558 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -23,7 +23,7 @@ dependencies = [ "termcolor", "toml 0.5.11", "tracing", - "tracing-log", + "tracing-log 0.1.4", "tracing-subscriber", "wait-timeout", ] @@ -592,9 +592,9 @@ checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" [[package]] name = "crypto-bigint" -version = "0.5.3" +version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "740fe28e594155f10cfc383984cbefd529d7396050557148f79cb0f621204124" +checksum = "28f85c3514d2a6e64160359b45a3918c3b4178bcbf4ae5d03ab2d02e521c479a" dependencies = [ "generic-array", "rand_core", @@ -802,15 +802,16 @@ dependencies = [ [[package]] name = "ed25519-dalek" -version = "2.0.0" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7277392b266383ef8396db7fdeb1e77b6c52fed775f5df15bb24f35b72156980" +checksum = "1f628eaec48bfd21b865dc2950cfa014450c01d2fa2b69a86c2fd5844ec523c0" dependencies = [ "curve25519-dalek", "ed25519", "rand_core", "serde", "sha2 0.10.8", + "subtle", "zeroize", ] @@ -834,9 +835,9 @@ checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" [[package]] name = "elliptic-curve" -version = "0.13.6" +version = "0.13.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d97ca172ae9dc9f9b779a6e3a65d308f2af74e5b8c921299075bdb4a0370e914" +checksum = "e9775b22bc152ad86a0cf23f0f348b884b26add12bf741e7ffc4d4ab2ab4d205" dependencies = [ "base16ct", "crypto-bigint", @@ -868,9 +869,9 @@ dependencies = [ [[package]] name = "env_logger" -version = "0.10.0" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85cdab6a89accf66733ad5a1693a4dcced6aeff64602b634530dd73c1f3ee9f0" +checksum = "95b3f3e67048839cb0d0781f445682a35113da7121f7c949db0e2be96a4fbece" dependencies = [ "humantime", "is-terminal", @@ -887,9 +888,9 @@ checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] name = "errno" -version = "0.3.5" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3e13f66a2f95e32a39eaa81f6b95d42878ca0e1db0c7543723dfe12557e860" +checksum = "f258a7194e7f7c2a7837a8913aeab7fd8c383457034fa20ce4dd3dcb813e8eb8" dependencies = [ "libc", "windows-sys 0.48.0", @@ -932,9 +933,9 @@ dependencies = [ [[package]] name = "fiat-crypto" -version = "0.2.2" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a481586acf778f1b1455424c343f71124b048ffa5f4fc3f8f6ae9dc432dcb3c7" +checksum = "53a56f0780318174bad1c127063fd0c5fdfb35398e3cd79ffaab931a6c79df80" [[package]] name = "fixed-hash" @@ -973,9 +974,12 @@ dependencies = [ [[package]] name = "fs-err" -version = "2.9.0" +version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0845fa252299212f0389d64ba26f34fa32cfe41588355f21ed507c59a0f64541" +checksum = "fb5fd9bcbe8b1087cbd395b51498c01bc997cef73e778a80b77a811af5e2d29f" +dependencies = [ + "autocfg", +] [[package]] name = "futures" @@ -1079,9 +1083,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.10" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" +checksum = "fe9006bed769170c11f845cf00c7c1e9092aeb3f268e007c3e760ac68008070f" dependencies = [ "cfg-if 1.0.0", "js-sys", @@ -1135,9 +1139,9 @@ dependencies = [ [[package]] name = "h2" -version = "0.3.21" +version = "0.3.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91fc23aa11be92976ef4729127f1a74adf36d8436f7816b185d18df956790833" +checksum = "4d6250322ef6e60f93f9a2162799302cd6f68f79f6e5d85c8c16f14d1d958178" dependencies = [ "bytes", "fnv", @@ -1145,7 +1149,7 @@ dependencies = [ "futures-sink", "futures-util", "http", - "indexmap 1.9.3", + "indexmap 2.1.0", "slab", "tokio", "tokio-util", @@ -1223,9 +1227,9 @@ dependencies = [ [[package]] name = "http" -version = "0.2.9" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd6effc99afb63425aff9b05836f029929e345a6148a14b7ecd5ab67af944482" +checksum = "8947b1a6fad4393052c7ba1f4cd97bed3e953a95c79c92ad9b051a04611d9fbb" dependencies = [ "bytes", "fnv", @@ -1359,9 +1363,9 @@ dependencies = [ [[package]] name = "ibc-proto" -version = "0.38.0" +version = "0.39.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93cbf4cbe9e5113cc7c70f3208a7029b2205c629502cbb2ae7ea0a09a97d3005" +checksum = "32b5aca9ca863246a2b358e0a1845759780860673e54c0a76335faccc504981c" dependencies = [ "base64 0.21.5", "bytes", @@ -1711,9 +1715,9 @@ dependencies = [ [[package]] name = "k256" -version = "0.13.1" +version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cadb76004ed8e97623117f3df85b17aaa6626ab0b0831e6573f104df16cd1bcc" +checksum = "3f01b677d82ef7a676aa37e099defd83a28e15687112cafdd112d60236b6115b" dependencies = [ "cfg-if 1.0.0", "ecdsa", @@ -1755,9 +1759,9 @@ dependencies = [ [[package]] name = "linux-raw-sys" -version = "0.4.10" +version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da2479e8c062e40bf0066ffa0bc823de0a9368974af99c9f6df941d2c231e03f" +checksum = "969488b55f8ac402214f3f5fd243ebb7206cf82de60d3172994707a4bcc2b829" [[package]] name = "lock_api" @@ -2523,9 +2527,9 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.21" +version = "0.38.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b426b0506e5d50a7d8dafcf2e81471400deb602392c7dd110815afb4eaf02a3" +checksum = "9ad981d6c340a49cdc40a1028d9c6084ec7e9fa33fcb839cab656a267071e234" dependencies = [ "bitflags 2.4.1", "errno", @@ -2560,9 +2564,9 @@ dependencies = [ [[package]] name = "rustls-pemfile" -version = "1.0.3" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d3987094b1d07b653b7dfdc3f70ce9a1da9c51ac18c1b06b662e4f9a0e9f4b2" +checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" dependencies = [ "base64 0.21.5", ] @@ -2951,9 +2955,9 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.11.1" +version = "1.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "942b4a808e05215192e39f4ab80813e599068285906cc91aa64f923db842bd5a" +checksum = "4dccd0940a2dcdf68d092b8cbab7dc0ad8fa938bf95787e1b916b0e3d0e8e970" [[package]] name = "socket2" @@ -3302,9 +3306,9 @@ dependencies = [ [[package]] name = "termcolor" -version = "1.3.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6093bad37da69aab9d123a8091e4be0aa4a03e4d601ec641c327398315f62b64" +checksum = "ff1bc3d3f05aff0403e8ac0d92ced918ec05b666a43f83297ccef5bea8a3d449" dependencies = [ "winapi-util", ] @@ -3429,9 +3433,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.33.0" +version = "1.34.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f38200e3ef7995e5ef13baec2f432a6da0aa9ac495b2c0e8f3b7eec2c92d653" +checksum = "d0c014766411e834f7af5b8f4cf46257aab4036ca95e9d2c144a10f59ad6f5b9" dependencies = [ "backtrace", "bytes", @@ -3458,9 +3462,9 @@ dependencies = [ [[package]] name = "tokio-macros" -version = "2.1.0" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" +checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" dependencies = [ "proc-macro2", "quote", @@ -3662,6 +3666,17 @@ dependencies = [ "tracing-core", ] +[[package]] +name = "tracing-log" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" +dependencies = [ + "log", + "once_cell", + "tracing-core", +] + [[package]] name = "tracing-serde" version = "0.1.3" @@ -3674,9 +3689,9 @@ dependencies = [ [[package]] name = "tracing-subscriber" -version = "0.3.17" +version = "0.3.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30a651bc37f915e81f087d86e62a18eec5f79550c7faff886f7090b4ea757c77" +checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" dependencies = [ "matchers", "nu-ansi-term", @@ -3689,7 +3704,7 @@ dependencies = [ "thread_local", "tracing", "tracing-core", - "tracing-log", + "tracing-log 0.2.0", "tracing-serde", ] @@ -4153,9 +4168,9 @@ dependencies = [ [[package]] name = "zeroize" -version = "1.6.0" +version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a0956f1ba7c7909bfb66c2e9e4124ab6f6482560f6628b5aaeba39207c9aad9" +checksum = "12a3946ecfc929b583800f4629b6c25b88ac6e92a40ea5670f77112a85d40a8b" dependencies = [ "zeroize_derive", ] diff --git a/crates/chain-registry/Cargo.toml b/crates/chain-registry/Cargo.toml index 99893f6955..4ece1e4fc6 100644 --- a/crates/chain-registry/Cargo.toml +++ b/crates/chain-registry/Cargo.toml @@ -13,7 +13,7 @@ description = """ [dependencies] ibc-relayer-types = { version = "0.26.1", path = "../relayer-types" } -ibc-proto = { version = "0.38.0", features = ["serde"] } +ibc-proto = { version = "0.39.0", features = ["serde"] } tendermint-rpc = { version = "0.34.0", features = ["http-client", "websocket-client"] } async-trait = "0.1.72" diff --git a/crates/relayer-cli/src/commands/tx/upgrade.rs b/crates/relayer-cli/src/commands/tx/upgrade.rs index e3ff636cbd..c56a60832c 100644 --- a/crates/relayer-cli/src/commands/tx/upgrade.rs +++ b/crates/relayer-cli/src/commands/tx/upgrade.rs @@ -3,6 +3,7 @@ use core::time::Duration; use abscissa_core::clap::Parser; use abscissa_core::{Command, Runnable}; +use ibc_relayer::upgrade_chain::requires_legacy_upgrade_proposal; use ibc_relayer::upgrade_chain::{build_and_send_ibc_upgrade_proposal, UpgradePlanOptions}; use ibc_relayer_types::core::ics24_host::identifier::{ChainId, ClientId}; @@ -58,6 +59,13 @@ pub struct TxIbcUpgradeChainCmd { )] height_offset: u64, + #[clap( + long = "gov-account", + value_name = "GOV_ACCOUNT", + help = "Authority account used to sign upgrade proposal. Note: This is only used for chains with ibc-go version v8.0.0 or higher" + )] + gov_account: Option, + #[clap( long = "new-chain", value_name = "CHAIN_ID", @@ -88,7 +96,7 @@ pub struct TxIbcUpgradeChainCmd { } impl TxIbcUpgradeChainCmd { - fn validate_options(&self) -> Result { + fn validate_options(&self, gov_account: String) -> Result { let opts = UpgradePlanOptions { src_client_id: self.host_client_id.clone(), amount: self.amount, @@ -103,6 +111,7 @@ impl TxIbcUpgradeChainCmd { .upgrade_name .clone() .unwrap_or_else(|| "plan".to_string()), + gov_account, }; Ok(opts) @@ -113,17 +122,25 @@ impl Runnable for TxIbcUpgradeChainCmd { fn run(&self) { let config = app_config(); - let opts = match self.validate_options() { - Err(err) => Output::error(err).exit(), - Ok(result) => result, - }; - let host_chain = spawn_chain_runtime(&config, &self.host_chain_id) .unwrap_or_else(exit_with_unrecoverable_error); let reference_chain = spawn_chain_runtime(&config, &self.reference_chain_id) .unwrap_or_else(exit_with_unrecoverable_error); + let gov_account = if requires_legacy_upgrade_proposal(reference_chain.clone()) { + "".to_string() + } else if let Some(gov_account) = &self.gov_account { + gov_account.clone() + } else { + Output::error("The chain being upgraded uses an ibc-go version v8.0.0 or higher, which requires the governance module account to be specified using the flag `--gov-account`".to_owned()).exit(); + }; + + let opts = match self.validate_options(gov_account) { + Err(err) => Output::error(err).exit(), + Ok(result) => result, + }; + let res = build_and_send_ibc_upgrade_proposal(reference_chain, host_chain, &opts) .map_err(Error::upgrade_chain); @@ -151,6 +168,7 @@ mod tests { host_client_id: ClientId::from_str("client_sender").unwrap(), amount: 42, height_offset: 21, + gov_account: None, new_chain_id: None, new_unbonding: None, upgrade_name: None, @@ -167,7 +185,7 @@ mod tests { "--amount", "42", "--height-offset", - "21" + "21", ]) ) } @@ -181,6 +199,7 @@ mod tests { host_client_id: ClientId::from_str("client_sender").unwrap(), amount: 42, height_offset: 21, + gov_account: None, new_chain_id: None, new_unbonding: None, upgrade_name: None, @@ -213,6 +232,7 @@ mod tests { host_client_id: ClientId::from_str("client_sender").unwrap(), amount: 42, height_offset: 21, + gov_account: None, new_chain_id: Some(ChainId::from_string("new_chain")), new_unbonding: None, upgrade_name: None, @@ -245,6 +265,7 @@ mod tests { host_client_id: ClientId::from_str("client_sender").unwrap(), amount: 42, height_offset: 21, + gov_account: None, new_chain_id: None, new_unbonding: Some(17), upgrade_name: None, @@ -277,6 +298,7 @@ mod tests { host_client_id: ClientId::from_str("client_sender").unwrap(), amount: 42, height_offset: 21, + gov_account: None, new_chain_id: None, new_unbonding: None, upgrade_name: Some("upgrade_name".to_owned()), @@ -300,6 +322,39 @@ mod tests { ) } + #[test] + fn test_upgrade_chain_gov_account() { + assert_eq!( + TxIbcUpgradeChainCmd { + reference_chain_id: ChainId::from_string("chain_receiver"), + host_chain_id: ChainId::from_string("chain_sender"), + host_client_id: ClientId::from_str("client_sender").unwrap(), + amount: 42, + height_offset: 21, + gov_account: Some("gov_account".to_owned()), + new_chain_id: None, + new_unbonding: None, + upgrade_name: None, + denom: None + }, + TxIbcUpgradeChainCmd::parse_from([ + "test", + "--reference-chain", + "chain_receiver", + "--host-chain", + "chain_sender", + "--host-client", + "client_sender", + "--amount", + "42", + "--height-offset", + "21", + "--gov-account", + "gov_account" + ]) + ) + } + #[test] fn test_upgrade_chain_no_height_offset() { assert!(TxIbcUpgradeChainCmd::try_parse_from([ @@ -311,7 +366,7 @@ mod tests { "--host-client", "client_sender", "--amount", - "42" + "42", ]) .is_err()) } @@ -327,7 +382,7 @@ mod tests { "--host-client", "client_sender", "--height-offset", - "21" + "21", ]) .is_err()) } @@ -343,7 +398,7 @@ mod tests { "--amount", "42", "--height-offset", - "21" + "21", ]) .is_err()) } @@ -359,7 +414,7 @@ mod tests { "--amount", "42", "--height-offset", - "21" + "21", ]) .is_err()) } @@ -375,7 +430,7 @@ mod tests { "--amount", "42", "--height-offset", - "21" + "21", ]) .is_err()) } diff --git a/crates/relayer-types/Cargo.toml b/crates/relayer-types/Cargo.toml index 63a9dd3974..3accdc1878 100644 --- a/crates/relayer-types/Cargo.toml +++ b/crates/relayer-types/Cargo.toml @@ -24,7 +24,7 @@ mocks = ["tendermint-testgen", "clock"] [dependencies] # Proto definitions for all IBC-related interfaces, e.g., connections or channels. -ibc-proto = { version = "0.38.0", features = ["serde"] } +ibc-proto = { version = "0.39.0", features = ["serde"] } ics23 = { version = "0.11.0", features = ["std", "host-functions"] } time = { version = "0.3" } serde_derive = { version = "1.0.104" } diff --git a/crates/relayer/Cargo.toml b/crates/relayer/Cargo.toml index 6e0082f7e5..04e3832ad8 100644 --- a/crates/relayer/Cargo.toml +++ b/crates/relayer/Cargo.toml @@ -20,7 +20,7 @@ default = ["flex-error/std", "flex-error/eyre_tracer"] telemetry = ["ibc-telemetry"] [dependencies] -ibc-proto = { version = "0.38.0", features = ["serde"] } +ibc-proto = { version = "0.39.0", features = ["serde"] } ibc-telemetry = { version = "0.26.1", path = "../telemetry", optional = true } ibc-relayer-types = { version = "0.26.1", path = "../relayer-types", features = ["mocks"] } diff --git a/crates/relayer/src/chain/cosmos.rs b/crates/relayer/src/chain/cosmos.rs index 31f0349aae..e8d41f6975 100644 --- a/crates/relayer/src/chain/cosmos.rs +++ b/crates/relayer/src/chain/cosmos.rs @@ -106,6 +106,7 @@ use crate::util::pretty::{ use crate::{chain::client::ClientSettings, config::Error as ConfigError}; use self::types::app_state::GenesisAppState; +use self::version::Specs; pub mod batch; pub mod client; @@ -1078,9 +1079,9 @@ impl ChainEndpoint for CosmosSdkChain { ChainConfig::CosmosSdk(self.config.clone()) } - fn ibc_version(&self) -> Result, Error> { + fn version_specs(&self) -> Result { let version_specs = self.block_on(fetch_version_specs(self.id(), &self.grpc_addr))?; - Ok(version_specs.ibc_go) + Ok(version_specs) } fn query_balance(&self, key_name: Option<&str>, denom: Option<&str>) -> Result { diff --git a/crates/relayer/src/chain/cosmos/types/events/channel.rs b/crates/relayer/src/chain/cosmos/types/events/channel.rs index 29730e3669..fa09493913 100644 --- a/crates/relayer/src/chain/cosmos/types/events/channel.rs +++ b/crates/relayer/src/chain/cosmos/types/events/channel.rs @@ -95,7 +95,7 @@ impl TryFrom> for WriteAcknowledgement { .into_bytes(); let mut packet = Packet::try_from(obj)?; - packet.data = Vec::from(data_str.as_str().as_bytes()); + packet.data = Vec::from(data_str.as_bytes()); Ok(Self { packet, ack }) } diff --git a/crates/relayer/src/chain/endpoint.rs b/crates/relayer/src/chain/endpoint.rs index d47367a6b2..02b1d342cb 100644 --- a/crates/relayer/src/chain/endpoint.rs +++ b/crates/relayer/src/chain/endpoint.rs @@ -33,6 +33,7 @@ use tendermint_rpc::endpoint::broadcast::tx_sync::Response as TxResponse; use crate::account::Balance; use crate::chain::client::ClientSettings; +use crate::chain::cosmos::version::Specs; use crate::chain::handle::Subscription; use crate::chain::requests::*; use crate::chain::tracking::TrackedMsgs; @@ -124,7 +125,7 @@ pub trait ChainEndpoint: Sized { // Versioning /// Return the version of the IBC protocol that this chain is running, if known. - fn ibc_version(&self) -> Result, Error>; + fn version_specs(&self) -> Result; // Send transactions diff --git a/crates/relayer/src/chain/handle.rs b/crates/relayer/src/chain/handle.rs index af6cb7e1ef..1ff6aae63f 100644 --- a/crates/relayer/src/chain/handle.rs +++ b/crates/relayer/src/chain/handle.rs @@ -45,6 +45,7 @@ use crate::{ use super::{ client::ClientSettings, + cosmos::version::Specs, endpoint::{ChainStatus, HealthCheck}, requests::*, tracking::TrackedMsgs, @@ -140,8 +141,8 @@ pub enum ChainRequest { reply_to: ReplyTo<()>, }, - IbcVersion { - reply_to: ReplyTo>, + VersionSpecs { + reply_to: ReplyTo, }, QueryBalance { @@ -412,7 +413,7 @@ pub trait ChainHandle: Clone + Display + Send + Sync + Debug + 'static { fn add_key(&self, key_name: String, key: AnySigningKeyPair) -> Result<(), Error>; /// Return the version of the IBC protocol that this chain is running, if known. - fn ibc_version(&self) -> Result, Error>; + fn version_specs(&self) -> Result; /// Query the balance of the given account for the given denom. /// If no account is given, behavior must be specified, e.g. retrieve it from configuration file. diff --git a/crates/relayer/src/chain/handle/base.rs b/crates/relayer/src/chain/handle/base.rs index fccfd383f8..220c9ce7a3 100644 --- a/crates/relayer/src/chain/handle/base.rs +++ b/crates/relayer/src/chain/handle/base.rs @@ -26,7 +26,10 @@ use ibc_relayer_types::{ use crate::{ account::Balance, - chain::{client::ClientSettings, endpoint::ChainStatus, requests::*, tracking::TrackedMsgs}, + chain::{ + client::ClientSettings, cosmos::version::Specs, endpoint::ChainStatus, requests::*, + tracking::TrackedMsgs, + }, client_state::{AnyClientState, IdentifiedAnyClientState}, config::ChainConfig, connection::ConnectionMsgType, @@ -144,8 +147,8 @@ impl ChainHandle for BaseChainHandle { }) } - fn ibc_version(&self) -> Result, Error> { - self.send(|reply_to| ChainRequest::IbcVersion { reply_to }) + fn version_specs(&self) -> Result { + self.send(|reply_to| ChainRequest::VersionSpecs { reply_to }) } fn query_balance( diff --git a/crates/relayer/src/chain/handle/cache.rs b/crates/relayer/src/chain/handle/cache.rs index edec29b7fb..3c4762b3ae 100644 --- a/crates/relayer/src/chain/handle/cache.rs +++ b/crates/relayer/src/chain/handle/cache.rs @@ -25,6 +25,7 @@ use ibc_relayer_types::Height; use crate::account::Balance; use crate::cache::{Cache, CacheStatus}; use crate::chain::client::ClientSettings; +use crate::chain::cosmos::version::Specs; use crate::chain::endpoint::{ChainStatus, HealthCheck}; use crate::chain::handle::{ChainHandle, ChainRequest, Subscription}; use crate::chain::requests::*; @@ -122,8 +123,8 @@ impl ChainHandle for CachingChainHandle { self.inner().add_key(key_name, key) } - fn ibc_version(&self) -> Result, Error> { - self.inner().ibc_version() + fn version_specs(&self) -> Result { + self.inner().version_specs() } fn query_balance( diff --git a/crates/relayer/src/chain/handle/counting.rs b/crates/relayer/src/chain/handle/counting.rs index d08662bdc0..2211cc3551 100644 --- a/crates/relayer/src/chain/handle/counting.rs +++ b/crates/relayer/src/chain/handle/counting.rs @@ -28,6 +28,7 @@ use ibc_relayer_types::Height; use crate::account::Balance; use crate::chain::client::ClientSettings; +use crate::chain::cosmos::version::Specs; use crate::chain::endpoint::{ChainStatus, HealthCheck}; use crate::chain::handle::{ChainHandle, ChainRequest, Subscription}; use crate::chain::requests::*; @@ -150,9 +151,9 @@ impl ChainHandle for CountingChainHandle { self.inner().add_key(key_name, key) } - fn ibc_version(&self) -> Result, Error> { + fn version_specs(&self) -> Result { self.inc_metric("ibc_version"); - self.inner().ibc_version() + self.inner().version_specs() } fn query_balance( diff --git a/crates/relayer/src/chain/runtime.rs b/crates/relayer/src/chain/runtime.rs index 1c700a6978..d19fbd9cfe 100644 --- a/crates/relayer/src/chain/runtime.rs +++ b/crates/relayer/src/chain/runtime.rs @@ -45,6 +45,7 @@ use crate::{ use super::{ client::ClientSettings, + cosmos::version::Specs, endpoint::{ChainEndpoint, ChainStatus, HealthCheck}, handle::{ChainHandle, ChainRequest, ReplyTo, Subscription}, requests::*, @@ -186,8 +187,8 @@ where self.add_key(key_name, key, reply_to)? }, - ChainRequest::IbcVersion { reply_to } => { - self.ibc_version(reply_to)? + ChainRequest::VersionSpecs { reply_to } => { + self.version_specs(reply_to)? }, ChainRequest::BuildHeader { trusted_height, target_height, client_state, reply_to } => { @@ -449,8 +450,8 @@ where reply_to.send(result).map_err(Error::send) } - fn ibc_version(&mut self, reply_to: ReplyTo>) -> Result<(), Error> { - let result = self.chain.ibc_version(); + fn version_specs(&mut self, reply_to: ReplyTo) -> Result<(), Error> { + let result = self.chain.version_specs(); reply_to.send(result).map_err(Error::send) } diff --git a/crates/relayer/src/upgrade_chain.rs b/crates/relayer/src/upgrade_chain.rs index 8da417e8e0..3c6b407f5c 100644 --- a/crates/relayer/src/upgrade_chain.rs +++ b/crates/relayer/src/upgrade_chain.rs @@ -8,10 +8,11 @@ use flex_error::define_error; use tendermint::Hash as TxHash; -use ibc_proto::cosmos::gov::v1beta1::MsgSubmitProposal; +use ibc_proto::cosmos::gov::v1::MsgSubmitProposal; +use ibc_proto::cosmos::gov::v1beta1::MsgSubmitProposal as LegacyMsgSubmitProposal; use ibc_proto::cosmos::upgrade::v1beta1::Plan; use ibc_proto::google::protobuf::Any; -use ibc_proto::ibc::core::client::v1::UpgradeProposal; +use ibc_proto::ibc::core::client::v1::{MsgIbcSoftwareUpgrade, UpgradeProposal}; use ibc_relayer_types::clients::ics07_tendermint::client_state::UpgradeOptions; use ibc_relayer_types::core::ics02_client::client_state::ClientState; use ibc_relayer_types::core::ics24_host::identifier::{ChainId, ClientId}; @@ -66,6 +67,7 @@ pub struct UpgradePlanOptions { pub upgraded_chain_id: ChainId, pub upgraded_unbonding_period: Option, pub upgrade_plan_name: String, + pub gov_account: String, } pub fn build_and_send_ibc_upgrade_proposal( @@ -73,6 +75,52 @@ pub fn build_and_send_ibc_upgrade_proposal( src_chain: impl ChainHandle, // the source chain; supplies a client state for building the upgrade plan opts: &UpgradePlanOptions, ) -> Result { + let any_msg = if requires_legacy_upgrade_proposal(dst_chain.clone()) { + build_legacy_upgrade_proposal(dst_chain.clone(), src_chain, opts) + } else { + build_upgrade_proposal(dst_chain.clone(), src_chain, opts) + }?; + + // Can't use send_messages_and_wait_commit because no IBC events + // corresponding to the transaction can be recognized to confirm the + // upgrade. + // https://github.com/informalsystems/hermes/issues/1288#issuecomment-1066884163 + + let responses = dst_chain + .send_messages_and_wait_check_tx(TrackedMsgs::new_single(any_msg, "upgrade")) + .map_err(|e| UpgradeChainError::submit(dst_chain.id(), e))?; + + Ok(responses[0].hash) +} + +/// Looks at the ibc-go version to determine if the legacy `UpgradeProposal` message +/// or if the newer `MsgIBCSoftwareUpdate` message should be used to upgrade the chain. +/// If the ibc-go version returned isn't reliable, a deprecated version, then the version +/// of Cosmos SDK is used. +pub fn requires_legacy_upgrade_proposal(dst_chain: impl ChainHandle) -> bool { + let version_specs = dst_chain.version_specs().unwrap(); + match version_specs.ibc_go { + Some(ibc_version) => { + // Some ibc-go simapps return unreliable ibc-go versions, such as simapp v8.0.0 + // returns version v1.0.0. So if the ibc-go version matches which is not maintained + // anymore, use the Cosmos SDK version to determine if the legacy upgrade proposal + // has to be used + if ibc_version.major < 4 { + version_specs.cosmos_sdk.minor < 50 + } else { + ibc_version.major < 8 + } + } + None => version_specs.cosmos_sdk.minor < 50, + } +} + +/// Ibc-go versions up to v7.x.x use the deprecated `UpgradeProposal` to upgrade a chain +fn build_legacy_upgrade_proposal( + dst_chain: impl ChainHandle, // the chain which will undergo an upgrade + src_chain: impl ChainHandle, // the source chain; supplies a client state for building the upgrade plan + opts: &UpgradePlanOptions, +) -> Result { let plan_height = dst_chain .query_latest_height() // FIXME(romac): Use query_chain_latest_height once added to ChainHandle .map_err(UpgradeChainError::query)? @@ -125,7 +173,7 @@ pub fn build_and_send_ibc_upgrade_proposal( }), }; - let proposal = Proposal::Default(proposal); + let proposal = Proposal::Legacy(proposal); let mut buf_proposal = Vec::new(); proposal.encode(&mut buf_proposal); @@ -142,7 +190,7 @@ pub fn build_and_send_ibc_upgrade_proposal( amount: opts.amount.to_string(), }; - let msg = MsgSubmitProposal { + let msg = LegacyMsgSubmitProposal { content: Some(any_proposal), initial_deposit: vec![coins], proposer: proposer.to_string(), @@ -150,38 +198,121 @@ pub fn build_and_send_ibc_upgrade_proposal( let mut buf_msg = Vec::new(); prost::Message::encode(&msg, &mut buf_msg).unwrap(); - let any_msg = Any { + Ok(Any { type_url: "/cosmos.gov.v1beta1.MsgSubmitProposal".to_string(), value: buf_msg, + }) +} + +/// Since ibc-go version to v8.x.x `MsgIbcSoftwareUpgrade` is used to upgrade a chain +fn build_upgrade_proposal( + dst_chain: impl ChainHandle, // the chain which will undergo an upgrade + src_chain: impl ChainHandle, // the source chain; supplies a client state for building the upgrade plan + opts: &UpgradePlanOptions, +) -> Result { + let plan_height = dst_chain + .query_latest_height() // FIXME(romac): Use query_chain_latest_height once added to ChainHandle + .map_err(UpgradeChainError::query)? + .add(opts.height_offset); + + let upgraded_client_latest_height = + if dst_chain.id().version() == opts.upgraded_chain_id.version() { + plan_height.increment() + } else { + Height::new(opts.upgraded_chain_id.version(), 1).map_err(|_| { + UpgradeChainError::upgrade_height_revision(opts.upgraded_chain_id.version()) + })? + }; + + let (client_state, _) = src_chain + .query_client_state( + QueryClientStateRequest { + client_id: opts.src_client_id.clone(), + height: QueryHeight::Latest, + }, + IncludeProof::No, + ) + .map_err(UpgradeChainError::query)?; + + let mut client_state = downcast!(client_state => AnyClientState::Tendermint) + .ok_or_else(UpgradeChainError::tendermint_only)?; + + // Retain the old unbonding period in case the user did not specify a new one + let upgrade_options = UpgradeOptions { + unbonding_period: opts + .upgraded_unbonding_period + .unwrap_or(client_state.unbonding_period), }; - // Can't use send_messages_and_wait_commit because no IBC events - // corresponding to the transaction can be recognized to confirm the - // upgrade. - // https://github.com/informalsystems/hermes/issues/1288#issuecomment-1066884163 + client_state.upgrade( + upgraded_client_latest_height, + upgrade_options, + opts.upgraded_chain_id.clone(), + ); - let responses = dst_chain - .send_messages_and_wait_check_tx(TrackedMsgs::new_single(any_msg, "upgrade")) - .map_err(|e| UpgradeChainError::submit(dst_chain.id(), e))?; + let proposal = MsgIbcSoftwareUpgrade { + plan: Some(Plan { + name: opts.upgrade_plan_name.clone(), + height: plan_height.revision_height() as i64, + info: "".to_string(), + ..Default::default() // deprecated fields - time & upgraded_client_state + }), + upgraded_client_state: Some(Any::from(AnyClientState::from(client_state))), + signer: opts.gov_account.clone(), + }; - Ok(responses[0].hash) + let proposal = Proposal::Default(proposal); + + let mut buf_proposal = Vec::new(); + proposal.encode(&mut buf_proposal); + let any_proposal = Any { + type_url: proposal.type_url(), + value: buf_proposal, + }; + + // build the msg submit proposal + let proposer = dst_chain.get_signer().map_err(UpgradeChainError::key)?; + + let coins = ibc_proto::cosmos::base::v1beta1::Coin { + denom: opts.denom.clone(), + amount: opts.amount.to_string(), + }; + + let msg = MsgSubmitProposal { + messages: vec![any_proposal], + initial_deposit: vec![coins], + proposer: proposer.to_string(), + metadata: "".to_string(), + title: "proposal 0".to_string(), + summary: "upgrade the chain software and unbonding period".to_string(), + }; + + let mut buf_msg = Vec::new(); + prost::Message::encode(&msg, &mut buf_msg).unwrap(); + Ok(Any { + type_url: "/cosmos.gov.v1.MsgSubmitProposal".to_string(), + value: buf_msg, + }) } enum Proposal { - Default(UpgradeProposal), + Default(MsgIbcSoftwareUpgrade), + Legacy(UpgradeProposal), } impl Proposal { fn encode(&self, buf: &mut impl BufMut) { match self { Proposal::Default(p) => prost::Message::encode(p, buf), + Proposal::Legacy(p) => prost::Message::encode(p, buf), } .unwrap() } fn type_url(&self) -> String { match self { - Proposal::Default(_) => "/ibc.core.client.v1.UpgradeProposal", + Proposal::Default(_) => "/ibc.core.client.v1.MsgIBCSoftwareUpgrade", + Proposal::Legacy(_) => "/ibc.core.client.v1.UpgradeProposal", } .to_owned() } diff --git a/flake.lock b/flake.lock index bc3eaafb13..f80edd5878 100644 --- a/flake.lock +++ b/flake.lock @@ -172,11 +172,11 @@ "wasmvm_1_beta7-src": "wasmvm_1_beta7-src" }, "locked": { - "lastModified": 1698864415, - "narHash": "sha256-v1Vx4Xt3O8aFoUuEUlZ6HZGKPkKJjOQ4rVLP/JCl6Cg=", + "lastModified": 1699655934, + "narHash": "sha256-nLJQMsH8TaGAGBEZRzSNQugzZGclkDqVffb7oVP974Y=", "owner": "informalsystems", "repo": "cosmos.nix", - "rev": "2e06a0e9d985db778cf416c6d460a275cc39c43b", + "rev": "6d54d90c8d8c26a188ef76dd288d08192aa3532d", "type": "github" }, "original": { @@ -685,16 +685,16 @@ "ibc-go-v8-src": { "flake": false, "locked": { - "lastModified": 1695930850, - "narHash": "sha256-BHmsnnqB+SoS8UdfGbEk07EXGZJG9ELo4+2gAbP8LdM=", + "lastModified": 1699602904, + "narHash": "sha256-BcP3y874QviVsV+04p9CioolyvmWH82ORbb5EB2GyRI=", "owner": "cosmos", "repo": "ibc-go", - "rev": "9c7212198d0ef82b8219ea66cee9c96b40e7981d", + "rev": "2551dea41cd3c512845007ca895c8402afa9b79f", "type": "github" }, "original": { "owner": "cosmos", - "ref": "v8.0.0-beta.1", + "ref": "v8.0.0", "repo": "ibc-go", "type": "github" } @@ -932,11 +932,11 @@ }, "nixpkgs_4": { "locked": { - "lastModified": 1698890957, - "narHash": "sha256-DJ+SppjpPBoJr0Aro9TAcP3sxApCSieY6BYBCoWGUX8=", + "lastModified": 1699725108, + "narHash": "sha256-NTiPW4jRC+9puakU4Vi8WpFEirhp92kTOSThuZke+FA=", "owner": "nixos", "repo": "nixpkgs", - "rev": "c082856b850ec60cda9f0a0db2bc7bd8900d708c", + "rev": "911ad1e67f458b6bcf0278fa85e33bb9924fed7e", "type": "github" }, "original": { diff --git a/flake.nix b/flake.nix index b27f451e29..3d316b9a49 100644 --- a/flake.nix +++ b/flake.nix @@ -38,6 +38,7 @@ ibc-go-v5-simapp ibc-go-v6-simapp ibc-go-v7-simapp + ibc-go-v8-simapp interchain-security apalache evmos diff --git a/guide/src/documentation/commands/tx/upgrade.md b/guide/src/documentation/commands/tx/upgrade.md index 950e53a3a8..07fbaa15ea 100644 --- a/guide/src/documentation/commands/tx/upgrade.md +++ b/guide/src/documentation/commands/tx/upgrade.md @@ -16,8 +16,28 @@ __Example__ An upgrade proposal is made for `ibc-0`, for height `300` blocks from the latest height, with `10000000stake` deposited. The proposal will include the upgraded client state constructed from the state of `07-tendermint-0` client on `ibc-1`. +If the chain is using ibc-go version `v8.0.0` or higher, the authority account for the governance module needs to be used. To query the account use: + +```shell + query auth module-account gov +``` + +or + +```shell + query auth module-accounts +``` + +And then + +```shell +{{#template ../../../templates/commands/hermes/tx/upgrade-chain_1.md REFERENCE_CHAIN_ID=ibc-0 HOST_CHAIN_ID=ibc-1 HOST_CLIENT_ID=07-tendermint-0 AMOUNT=10000000 HEIGHT_OFFSET=60 OPTIONS= --gov-account }} +``` + +If the ibc-go version used is lower than `v8.0.0` you can ignore the `--gov-account` flag as it will not be used. + ```shell -{{#template ../../../templates/commands/hermes/tx/upgrade-chain_1.md REFERENCE_CHAIN_ID=ibc-0 HOST_CHAIN_ID=ibc-1 HOST_CLIENT_ID=07-tendermint-0 AMOUNT=10000000 HEIGHT_OFFSET=300}} +{{#template ../../../templates/commands/hermes/tx/upgrade-chain_1.md REFERENCE_CHAIN_ID=ibc-0 HOST_CHAIN_ID=ibc-1 HOST_CLIENT_ID=07-tendermint-0 AMOUNT=10000000 HEIGHT_OFFSET=60}} ``` ``` diff --git a/guide/src/documentation/commands/upgrade/test.md b/guide/src/documentation/commands/upgrade/test.md index 47804b9dbb..65093de03a 100644 --- a/guide/src/documentation/commands/upgrade/test.md +++ b/guide/src/documentation/commands/upgrade/test.md @@ -70,10 +70,24 @@ gaiad version --log_level error --long | head -n4 Use test command to make an upgrade proposal. In the example below a software upgrade proposal is made for `ibc-0`, for the height `300` blocks from the latest height. `10000000stake` is deposited. The proposal includes the upgraded client state constructed from the state of `07-tendermint-0` client on `ibc-1` that was created in the previous step. + If the chain is using ibc-go version `v8.0.0` or higher, the authority account for the governance module needs to be used. To query the account use: + + ```shell + gaiad --node tcp://localhost:27000 --home $HOME/.gm/ibc-0/ query auth module-account gov + ``` + + ```shell + {{#template ../../../templates/commands/hermes/tx/upgrade-chain_1.md REFERENCE_CHAIN_ID=ibc-0 HOST_CHAIN_ID=ibc-1 HOST_CLIENT_ID=07-tendermint-0 AMOUNT=10000000 HEIGHT_OFFSET=60 OPTIONS= --gov-account }} + ``` + + If the ibc-go version used is lower than `v8.0.0` you can ignore the `--gov-account` flag as it will not be used. + ```shell {{#template ../../../templates/commands/hermes/tx/upgrade-chain_1.md REFERENCE_CHAIN_ID=ibc-0 HOST_CHAIN_ID=ibc-1 HOST_CLIENT_ID=07-tendermint-0 AMOUNT=10000000 HEIGHT_OFFSET=60}} ``` + For this test, the `--gov-account` can be ignored. + ```text Success: transaction::Hash(CE98D8D98091BA8016BD852D18056E54C4CB3C4525E7F40DD3C40B4FD0F2482B) ``` diff --git a/guide/src/templates/commands/hermes/evidence_1.md b/guide/src/templates/commands/hermes/evidence_1.md index 4db7cc285b..5a08ef4c71 100644 --- a/guide/src/templates/commands/hermes/evidence_1.md +++ b/guide/src/templates/commands/hermes/evidence_1.md @@ -1 +1 @@ -[[#BINARY hermes]][[#GLOBALOPTIONS]] evidence[[#OPTIONS]] --chain [[#CHAIN_ID]] \ No newline at end of file +[[#BINARY hermes]][[#GLOBALOPTIONS]] evidence[[#OPTIONS]] --chain [[#CHAIN_ID]] diff --git a/guide/src/templates/help_templates/tx/upgrade-chain.md b/guide/src/templates/help_templates/tx/upgrade-chain.md index ed5dc6ac29..444afc3fdf 100644 --- a/guide/src/templates/help_templates/tx/upgrade-chain.md +++ b/guide/src/templates/help_templates/tx/upgrade-chain.md @@ -8,6 +8,10 @@ OPTIONS: --denom Denomination for the deposit (default: 'stake') + --gov-account + Authority account used to sign upgrade proposal. Note: This is only used for chains with + ibc-go version v8.0.0 or higher + -h, --help Print help information diff --git a/tools/check-guide/Cargo.lock b/tools/check-guide/Cargo.lock index b5ddef7a45..735f88c9a3 100644 --- a/tools/check-guide/Cargo.lock +++ b/tools/check-guide/Cargo.lock @@ -1654,7 +1654,7 @@ dependencies = [ [[package]] name = "ibc-chain-registry" -version = "0.25.0" +version = "0.26.1" dependencies = [ "async-trait", "flex-error", @@ -1673,9 +1673,9 @@ dependencies = [ [[package]] name = "ibc-proto" -version = "0.38.0" +version = "0.39.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93cbf4cbe9e5113cc7c70f3208a7029b2205c629502cbb2ae7ea0a09a97d3005" +checksum = "32b5aca9ca863246a2b358e0a1845759780860673e54c0a76335faccc504981c" dependencies = [ "base64 0.21.4", "bytes", @@ -1690,7 +1690,7 @@ dependencies = [ [[package]] name = "ibc-relayer" -version = "0.25.0" +version = "0.26.1" dependencies = [ "anyhow", "async-stream", @@ -1737,6 +1737,7 @@ dependencies = [ "tendermint", "tendermint-light-client", "tendermint-light-client-detector", + "tendermint-light-client-verifier", "tendermint-proto", "tendermint-rpc", "thiserror", @@ -1747,12 +1748,13 @@ dependencies = [ "toml 0.7.8", "tonic", "tracing", + "tracing-subscriber", "uuid 1.4.1", ] [[package]] name = "ibc-relayer-cli" -version = "1.6.0" +version = "1.7.1" dependencies = [ "abscissa_core", "clap 3.2.25", @@ -1791,7 +1793,7 @@ dependencies = [ [[package]] name = "ibc-relayer-rest" -version = "0.25.0" +version = "0.26.1" dependencies = [ "axum", "crossbeam-channel 0.5.8", @@ -1804,7 +1806,7 @@ dependencies = [ [[package]] name = "ibc-relayer-types" -version = "0.25.0" +version = "0.26.1" dependencies = [ "bytes", "derive_more", @@ -1830,7 +1832,7 @@ dependencies = [ [[package]] name = "ibc-telemetry" -version = "0.25.0" +version = "0.26.1" dependencies = [ "axum", "dashmap", @@ -2248,9 +2250,9 @@ dependencies = [ [[package]] name = "moka" -version = "0.11.3" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa6e72583bf6830c956235bff0d5afec8cf2952f579ebad18ae7821a917d950f" +checksum = "d8017ec3548ffe7d4cef7ac0e12b044c01164a74c0f3119420faeaf13490ad8b" dependencies = [ "crossbeam-channel 0.5.8", "crossbeam-epoch", @@ -2259,7 +2261,6 @@ dependencies = [ "parking_lot", "quanta", "rustc_version", - "scheduled-thread-pool", "skeptic", "smallvec", "tagptr", @@ -3156,15 +3157,6 @@ dependencies = [ "windows-sys 0.48.0", ] -[[package]] -name = "scheduled-thread-pool" -version = "0.2.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3cbc66816425a074528352f5789333ecff06ca41b36b0b0efdfbb29edc391a19" -dependencies = [ - "parking_lot", -] - [[package]] name = "scoped-tls" version = "1.0.1" diff --git a/tools/integration-test/src/tests/client_upgrade.rs b/tools/integration-test/src/tests/client_upgrade.rs index 9f6ceff850..c45426fd9e 100644 --- a/tools/integration-test/src/tests/client_upgrade.rs +++ b/tools/integration-test/src/tests/client_upgrade.rs @@ -15,21 +15,21 @@ use http::Uri; use std::str::FromStr; +use ibc_relayer::chain::requests::IncludeProof; +use ibc_relayer::chain::requests::QueryClientStateRequest; +use ibc_relayer::chain::requests::QueryHeight; +use ibc_relayer::client_state::AnyClientState; use ibc_relayer::upgrade_chain::{build_and_send_ibc_upgrade_proposal, UpgradePlanOptions}; use ibc_relayer_types::core::ics02_client::height::Height; -use ibc_test_framework::{ - chain::{ - config::{set_max_deposit_period, set_voting_period}, - ext::wait_chain::wait_for_chain_height, - }, - prelude::*, -}; +use ibc_test_framework::chain::config::{set_max_deposit_period, set_voting_period}; +use ibc_test_framework::chain::ext::bootstrap::ChainBootstrapMethodsExt; +use ibc_test_framework::prelude::*; +use ibc_test_framework::util::proposal_status::ProposalStatus; const MAX_DEPOSIT_PERIOD: &str = "10s"; -const VOTING_PERIOD: &str = "10s"; +const VOTING_PERIOD: u64 = 10; const DELTA_HEIGHT: u64 = 15; const WAIT_CHAIN_UPGRADE: Duration = Duration::from_secs(4); -const MAX_WAIT_FOR_CHAIN_HEIGHT: Duration = Duration::from_secs(60); #[test] fn test_client_upgrade() -> Result<(), Error> { @@ -74,24 +74,13 @@ impl BinaryChainTest for ClientUpgradeTest { _relayer: ibc_test_framework::prelude::RelayerDriver, chains: ibc_test_framework::prelude::ConnectedChains, ) -> Result<(), ibc_test_framework::prelude::Error> { + let upgraded_chain_id = ChainId::new("upgradedibc".to_owned(), 1); let fee_denom_a: MonoTagged = MonoTagged::new(Denom::base(&config.native_tokens[0])); let foreign_clients = chains.clone().foreign_clients; - let upgraded_chain_id = chains.chain_id_a().0.clone(); - - let src_client_id = foreign_clients.client_id_b().0.clone(); - // Create and send an chain upgrade proposal - let opts = UpgradePlanOptions { - src_client_id, - amount: 10000000u64, - denom: fee_denom_a.to_string(), - height_offset: DELTA_HEIGHT, - upgraded_chain_id, - upgraded_unbonding_period: None, - upgrade_plan_name: "plan".to_string(), - }; + let opts = create_upgrade_plan(config, &chains, &upgraded_chain_id)?; build_and_send_ibc_upgrade_proposal( chains.handle_a().clone(), @@ -100,14 +89,22 @@ impl BinaryChainTest for ClientUpgradeTest { ) .map_err(Error::upgrade_chain)?; - // Wait for the proposal to be processed - std::thread::sleep(Duration::from_secs(2)); + info!("Assert that the chain upgrade proposal is eventually in voting period"); let driver = chains.node_a.chain_driver(); + driver.value().assert_proposal_status( + driver.value().chain_id.as_str(), + &driver.value().command_path, + &driver.value().home_path, + &driver.value().rpc_listen_address(), + ProposalStatus::VotingPeriod, + "1", + )?; + // Retrieve the height which should be used to upgrade the client let upgrade_height = driver.query_upgrade_proposal_height( - &Uri::from_str(&driver.0.grpc_address()).map_err(handle_generic_error)?, + &Uri::from_str(&driver.value().grpc_address()).map_err(handle_generic_error)?, 1, )?; @@ -120,27 +117,41 @@ impl BinaryChainTest for ClientUpgradeTest { // Vote on the proposal so the chain will upgrade driver.vote_proposal(&fee_denom_a.with_amount(1200u64).to_string())?; - // The application height reports a height of 1 less than the height according to Tendermint - let target_reference_application_height = client_upgrade_height - .decrement() - .expect("Upgrade height cannot be 1"); + info!("Assert that the chain upgrade proposal is eventually passed"); - assert!(wait_for_chain_height( - &foreign_clients, - target_reference_application_height, - MAX_WAIT_FOR_CHAIN_HEIGHT - ) - .is_ok()); + driver.value().assert_proposal_status( + driver.value().chain_id.as_str(), + &driver.value().command_path, + &driver.value().home_path, + &driver.value().rpc_listen_address(), + ProposalStatus::Passed, + "1", + )?; // Wait for the chain to upgrade std::thread::sleep(WAIT_CHAIN_UPGRADE); // Trigger the client upgrade - let outcome = foreign_clients.client_a_to_b.upgrade(client_upgrade_height); + // The error is ignored as the client state will be asserted afterwards. + let _ = foreign_clients.client_a_to_b.upgrade(client_upgrade_height); - assert!(outcome.is_ok(), "{outcome:?}"); + // Wait to seconds before querying the client state + std::thread::sleep(Duration::from_secs(2)); - Ok(()) + let (state, _) = chains.handle_b().query_client_state( + QueryClientStateRequest { + client_id: foreign_clients.client_a_to_b.id().clone(), + height: QueryHeight::Latest, + }, + IncludeProof::No, + )?; + + match state { + AnyClientState::Tendermint(client_state) => { + assert_eq!(client_state.chain_id, upgraded_chain_id); + Ok(()) + } + } } } @@ -161,7 +172,7 @@ impl BinaryChainTest for InvalidClientUpgradeTest { chains: ibc_test_framework::prelude::ConnectedChains, ) -> Result<(), ibc_test_framework::prelude::Error> { let arbitrary_height = 5u64; - let foreign_clients = chains.foreign_clients; + let foreign_clients = &chains.foreign_clients; // Wait for the chain to reach a given height let client_upgrade_height = Height::new( @@ -174,11 +185,26 @@ impl BinaryChainTest for InvalidClientUpgradeTest { std::thread::sleep(Duration::from_secs(2)); // Trigger the client upgrade - let outcome = foreign_clients.client_a_to_b.upgrade(client_upgrade_height); + // The error is ignored as the client state will be asserted afterwards. + let _ = foreign_clients.client_a_to_b.upgrade(client_upgrade_height); + + // Wait to seconds before querying the client state + std::thread::sleep(Duration::from_secs(2)); - assert!(outcome.is_err(), "{outcome:?}"); + let (state, _) = chains.handle_b().query_client_state( + QueryClientStateRequest { + client_id: foreign_clients.client_a_to_b.id().clone(), + height: QueryHeight::Latest, + }, + IncludeProof::No, + )?; - Ok(()) + match state { + AnyClientState::Tendermint(client_state) => { + assert_eq!(client_state.chain_id, chains.handle_a().id()); + Ok(()) + } + } } } @@ -194,24 +220,13 @@ impl BinaryChainTest for HeightTooHighClientUpgradeTest { _relayer: ibc_test_framework::prelude::RelayerDriver, chains: ibc_test_framework::prelude::ConnectedChains, ) -> Result<(), ibc_test_framework::prelude::Error> { + let upgraded_chain_id = ChainId::new("upgradedibc".to_owned(), 1); let fee_denom_a: MonoTagged = MonoTagged::new(Denom::base(&config.native_tokens[0])); let foreign_clients = chains.clone().foreign_clients; - let upgraded_chain_id = chains.chain_id_a().0.clone(); - - let src_client_id = foreign_clients.client_id_b().0.clone(); - // Create and send an chain upgrade proposal - let opts = UpgradePlanOptions { - src_client_id, - amount: 10000000u64, - denom: fee_denom_a.to_string(), - height_offset: DELTA_HEIGHT, - upgraded_chain_id, - upgraded_unbonding_period: None, - upgrade_plan_name: "plan".to_string(), - }; + let opts = create_upgrade_plan(config, &chains, &upgraded_chain_id)?; build_and_send_ibc_upgrade_proposal( chains.handle_a().clone(), @@ -220,11 +235,19 @@ impl BinaryChainTest for HeightTooHighClientUpgradeTest { ) .map_err(Error::upgrade_chain)?; - // Wait for the proposal to be processed - std::thread::sleep(Duration::from_secs(2)); + info!("Assert that the chain upgrade proposal is eventually in voting period"); let driver = chains.node_a.chain_driver(); + driver.value().assert_proposal_status( + driver.value().chain_id.as_str(), + &driver.value().command_path, + &driver.value().home_path, + &driver.value().rpc_listen_address(), + ProposalStatus::VotingPeriod, + "1", + )?; + // Retrieve the height which should be used to upgrade the client let upgrade_height = driver.query_upgrade_proposal_height( &Uri::from_str(&driver.0.grpc_address()).map_err(handle_generic_error)?, @@ -241,28 +264,45 @@ impl BinaryChainTest for HeightTooHighClientUpgradeTest { driver.vote_proposal(&fee_denom_a.with_amount(1200u64).to_string())?; // The application height reports a height of 1 less than the height according to Tendermint - let target_reference_application_height = client_upgrade_height - .decrement() - .expect("Upgrade height cannot be 1"); + client_upgrade_height.increment(); - assert!(wait_for_chain_height( - &foreign_clients, - target_reference_application_height, - MAX_WAIT_FOR_CHAIN_HEIGHT - ) - .is_ok()); + info!("Assert that the chain upgrade proposal is eventually passed"); + + driver.value().assert_proposal_status( + driver.value().chain_id.as_str(), + &driver.value().command_path, + &driver.value().home_path, + &driver.value().rpc_listen_address(), + ProposalStatus::Passed, + "1", + )?; // Wait for the chain to upgrade std::thread::sleep(WAIT_CHAIN_UPGRADE); // Trigger the client upgrade using client_upgrade_height + 1. - let outcome = foreign_clients + // The error is ignored as the client state will be asserted afterwards. + let _ = foreign_clients .client_a_to_b .upgrade(client_upgrade_height.increment()); - assert!(outcome.is_err(), "{outcome:?}"); + // Wait to seconds before querying the client state + std::thread::sleep(Duration::from_secs(2)); - Ok(()) + let (state, _) = chains.handle_b().query_client_state( + QueryClientStateRequest { + client_id: foreign_clients.client_a_to_b.id().clone(), + height: QueryHeight::Latest, + }, + IncludeProof::No, + )?; + + match state { + AnyClientState::Tendermint(client_state) => { + assert_eq!(client_state.chain_id, chains.handle_a().id()); + Ok(()) + } + } } } @@ -278,24 +318,12 @@ impl BinaryChainTest for HeightTooLowClientUpgradeTest { _relayer: ibc_test_framework::prelude::RelayerDriver, chains: ibc_test_framework::prelude::ConnectedChains, ) -> Result<(), ibc_test_framework::prelude::Error> { + let upgraded_chain_id = ChainId::new("upgradedibc".to_owned(), 1); let fee_denom_a: MonoTagged = MonoTagged::new(Denom::base(&config.native_tokens[0])); let foreign_clients = chains.clone().foreign_clients; - let upgraded_chain_id = chains.chain_id_a().0.clone(); - - let src_client_id = foreign_clients.client_id_b().0.clone(); - - // Create and send an chain upgrade proposal - let opts = UpgradePlanOptions { - src_client_id, - amount: 10000000u64, - denom: fee_denom_a.to_string(), - height_offset: DELTA_HEIGHT, - upgraded_chain_id, - upgraded_unbonding_period: None, - upgrade_plan_name: "plan".to_string(), - }; + let opts = create_upgrade_plan(config, &chains, &upgraded_chain_id)?; build_and_send_ibc_upgrade_proposal( chains.handle_a().clone(), @@ -304,14 +332,22 @@ impl BinaryChainTest for HeightTooLowClientUpgradeTest { ) .map_err(Error::upgrade_chain)?; - // Wait for the proposal to be processed - std::thread::sleep(Duration::from_secs(2)); + info!("Assert that the chain upgrade proposal is eventually in voting period"); let driver = chains.node_a.chain_driver(); + driver.value().assert_proposal_status( + driver.value().chain_id.as_str(), + &driver.value().command_path, + &driver.value().home_path, + &driver.value().rpc_listen_address(), + ProposalStatus::VotingPeriod, + "1", + )?; + // Retrieve the height which should be used to upgrade the client let upgrade_height = driver.query_upgrade_proposal_height( - &Uri::from_str(&driver.0.grpc_address()).map_err(handle_generic_error)?, + &Uri::from_str(&driver.value().grpc_address()).map_err(handle_generic_error)?, 1, )?; @@ -325,33 +361,77 @@ impl BinaryChainTest for HeightTooLowClientUpgradeTest { driver.vote_proposal(&fee_denom_a.with_amount(1200u64).to_string())?; // The application height reports a height of 1 less than the height according to Tendermint - let target_reference_application_height = client_upgrade_height + client_upgrade_height .decrement() .expect("Upgrade height cannot be 1"); - assert!(wait_for_chain_height( - &foreign_clients, - target_reference_application_height, - MAX_WAIT_FOR_CHAIN_HEIGHT - ) - .is_ok()); + info!("Assert that the chain upgrade proposal is eventually passed"); + + driver.value().assert_proposal_status( + driver.value().chain_id.as_str(), + &driver.value().command_path, + &driver.value().home_path, + &driver.value().rpc_listen_address(), + ProposalStatus::Passed, + "1", + )?; // Wait for the chain to upgrade std::thread::sleep(WAIT_CHAIN_UPGRADE); // Trigger the client upgrade using client_upgrade_height - 1. - let outcome = foreign_clients.client_a_to_b.upgrade( + // The error is ignored as the client state will be asserted afterwards. + let _ = foreign_clients.client_a_to_b.upgrade( client_upgrade_height .decrement() .map_err(handle_generic_error)?, ); - assert!(outcome.is_err(), "{outcome:?}"); + // Wait to seconds before querying the client state + std::thread::sleep(Duration::from_secs(2)); - Ok(()) + let (state, _) = chains.handle_b().query_client_state( + QueryClientStateRequest { + client_id: foreign_clients.client_a_to_b.id().clone(), + height: QueryHeight::Latest, + }, + IncludeProof::No, + )?; + + match state { + AnyClientState::Tendermint(client_state) => { + assert_eq!(client_state.chain_id, chains.handle_a().id()); + Ok(()) + } + } } } +fn create_upgrade_plan( + config: &ibc_test_framework::prelude::TestConfig, + chains: &ibc_test_framework::prelude::ConnectedChains, + upgraded_chain_id: &ChainId, +) -> Result { + let fee_denom_a: MonoTagged = + MonoTagged::new(Denom::base(&config.native_tokens[0])); + let foreign_clients = chains.clone().foreign_clients; + + let src_client_id = foreign_clients.client_id_b().0.clone(); + + let gov_account = chains.node_a.chain_driver().query_auth_module("gov")?; + // Create and send an chain upgrade proposal + Ok(UpgradePlanOptions { + src_client_id, + amount: 10000000u64, + denom: fee_denom_a.to_string(), + height_offset: DELTA_HEIGHT, + upgraded_chain_id: upgraded_chain_id.clone(), + upgraded_unbonding_period: None, + upgrade_plan_name: "plan".to_string(), + gov_account, + }) +} + impl HasOverrides for ClientUpgradeTest { type Overrides = ClientUpgradeTestOverrides; diff --git a/tools/integration-test/src/tests/ics31.rs b/tools/integration-test/src/tests/ics31.rs index 93454b0820..33065dc091 100644 --- a/tools/integration-test/src/tests/ics31.rs +++ b/tools/integration-test/src/tests/ics31.rs @@ -51,7 +51,7 @@ impl TestOverrides for ICS31Test { *duration = serde_json::Value::String("20s".to_owned()); } } - set_voting_period(genesis, "20s")?; + set_voting_period(genesis, 20)?; set_staking_max_entries(genesis, "10")?; set_staking_bond_denom(genesis, "stake")?; set_mint_mint_denom(genesis, "stake")?; diff --git a/tools/integration-test/src/tests/interchain_security/icq.rs b/tools/integration-test/src/tests/interchain_security/icq.rs index 8b305f92e2..d1fde8a0c9 100644 --- a/tools/integration-test/src/tests/interchain_security/icq.rs +++ b/tools/integration-test/src/tests/interchain_security/icq.rs @@ -57,7 +57,7 @@ impl TestOverrides for InterchainSecurityIcqTest { *duration = serde_json::Value::String("20s".to_owned()); } } - set_voting_period(genesis, "10s")?; + set_voting_period(genesis, 10)?; set_staking_max_entries(genesis, "10")?; set_staking_bond_denom(genesis, "stake")?; set_mint_mint_denom(genesis, "stake")?; diff --git a/tools/test-framework/Cargo.toml b/tools/test-framework/Cargo.toml index 39764e7c2b..e88ecefa68 100644 --- a/tools/test-framework/Cargo.toml +++ b/tools/test-framework/Cargo.toml @@ -17,7 +17,7 @@ description = """ ibc-relayer-types = { version = "=0.26.1", path = "../../crates/relayer-types" } ibc-relayer = { version = "=0.26.1", path = "../../crates/relayer" } ibc-relayer-cli = { version = "=1.7.1", path = "../../crates/relayer-cli" } -ibc-proto = { version = "0.38.0", features = ["serde"] } +ibc-proto = { version = "0.39.0", features = ["serde"] } tendermint-rpc = { version = "0.34.0", features = ["http-client", "websocket-client"] } http = "0.2.9" diff --git a/tools/test-framework/src/chain/cli/bootstrap.rs b/tools/test-framework/src/chain/cli/bootstrap.rs index 15d7f9f71d..65dc1e9ed4 100644 --- a/tools/test-framework/src/chain/cli/bootstrap.rs +++ b/tools/test-framework/src/chain/cli/bootstrap.rs @@ -64,20 +64,36 @@ pub fn add_genesis_account( amounts: &[String], ) -> Result<(), Error> { let amounts_str = itertools::join(amounts, ","); - - simple_exec( + // Cosmos SDK v0.47.0 introduced the `genesis` subcommand, this match is required to + // support pre and post SDK v0.47.0. https://github.com/cosmos/cosmos-sdk/pull/14149 + match simple_exec( chain_id, command_path, &[ "--home", home_path, + "genesis", "add-genesis-account", wallet_address, &amounts_str, ], - )?; - - Ok(()) + ) { + Ok(_) => Ok(()), + Err(_) => { + simple_exec( + chain_id, + command_path, + &[ + "--home", + home_path, + "add-genesis-account", + wallet_address, + &amounts_str, + ], + )?; + Ok(()) + } + } } pub fn add_genesis_validator( @@ -87,12 +103,15 @@ pub fn add_genesis_validator( wallet_id: &str, amount: &str, ) -> Result<(), Error> { - simple_exec( + // Cosmos SDK v0.47.0 introduced the `genesis` subcommand, this match is required to + // support pre and post SDK v0.47.0. https://github.com/cosmos/cosmos-sdk/pull/14149 + match simple_exec( chain_id, command_path, &[ "--home", home_path, + "genesis", "gentx", wallet_id, "--keyring-backend", @@ -101,19 +120,47 @@ pub fn add_genesis_validator( chain_id, amount, ], - )?; - - Ok(()) + ) { + Ok(_) => Ok(()), + Err(_) => { + simple_exec( + chain_id, + command_path, + &[ + "--home", + home_path, + "gentx", + wallet_id, + "--keyring-backend", + "test", + "--chain-id", + chain_id, + amount, + ], + )?; + Ok(()) + } + } } pub fn collect_gen_txs(chain_id: &str, command_path: &str, home_path: &str) -> Result<(), Error> { - simple_exec( + // Cosmos SDK v0.47.0 introduced the `genesis` subcommand, this match is required to + // support pre and post SDK v0.47.0. https://github.com/cosmos/cosmos-sdk/pull/14149 + match simple_exec( chain_id, command_path, - &["--home", home_path, "collect-gentxs"], - )?; - - Ok(()) + &["--home", home_path, "genesis", "collect-gentxs"], + ) { + Ok(_) => Ok(()), + Err(_) => { + simple_exec( + chain_id, + command_path, + &["--home", home_path, "collect-gentxs"], + )?; + Ok(()) + } + } } pub fn start_chain( diff --git a/tools/test-framework/src/chain/cli/provider.rs b/tools/test-framework/src/chain/cli/provider.rs index e7f0a15522..6a1c7c34f3 100644 --- a/tools/test-framework/src/chain/cli/provider.rs +++ b/tools/test-framework/src/chain/cli/provider.rs @@ -41,11 +41,12 @@ pub fn submit_consumer_chain_proposal( Ok(()) } -pub fn query_consumer_proposal( +pub fn query_gov_proposal( chain_id: &str, command_path: &str, home_path: &str, rpc_listen_address: &str, + proposal_id: &str, ) -> Result { simple_exec( chain_id, @@ -58,7 +59,7 @@ pub fn query_consumer_proposal( "query", "gov", "proposal", - "1", + proposal_id, "--output", "json", ], diff --git a/tools/test-framework/src/chain/cli/query.rs b/tools/test-framework/src/chain/cli/query.rs index 8029d23929..5bfb0801b5 100644 --- a/tools/test-framework/src/chain/cli/query.rs +++ b/tools/test-framework/src/chain/cli/query.rs @@ -3,6 +3,8 @@ use eyre::eyre; use ibc_relayer_types::applications::transfer::amount::Amount; use serde_json as json; use serde_yaml as yaml; +use std::collections::HashMap; +use tracing::debug; use crate::chain::exec::simple_exec; use crate::error::{handle_generic_error, Error}; @@ -14,7 +16,9 @@ pub fn query_balance( wallet_id: &str, denom: &str, ) -> Result { - let res = simple_exec( + // SDK v0.50 has removed the `--denom` flag from the `query bank balances` CLI. + // It also changed the JSON output. + match simple_exec( chain_id, command_path, &[ @@ -29,20 +33,73 @@ pub fn query_balance( "--output", "json", ], - )? - .stdout; + ) { + Ok(output) => { + let amount_str = json::from_str::(&output.stdout) + .map_err(handle_generic_error)? + .get("amount") + .ok_or_else(|| eyre!("expected amount field"))? + .as_str() + .ok_or_else(|| eyre!("expected string field"))? + .to_string(); - let amount_str = json::from_str::(&res) - .map_err(handle_generic_error)? - .get("amount") - .ok_or_else(|| eyre!("expected amount field"))? - .as_str() - .ok_or_else(|| eyre!("expected string field"))? - .to_string(); + let amount = Amount::from_str(&amount_str).map_err(handle_generic_error)?; + + Ok(amount) + } + Err(_) => { + let res = simple_exec( + chain_id, + command_path, + &[ + "--node", + rpc_listen_address, + "query", + "bank", + "balances", + wallet_id, + "--output", + "json", + ], + )? + .stdout; + let amounts_array = + json::from_str::(&res).map_err(handle_generic_error)?; - let amount = Amount::from_str(&amount_str).map_err(handle_generic_error)?; + let balances = amounts_array + .get("balances") + .ok_or_else(|| eyre!("expected balances field"))? + .as_array() + .ok_or_else(|| eyre!("expected array field"))?; - Ok(amount) + let amount_str = balances.iter().find(|a| { + a.get("denom") + .ok_or_else(|| eyre!("expected denom field")) + .unwrap() + == denom + }); + + match amount_str { + Some(amount_str) => { + let amount_str = amount_str + .get("amount") + .ok_or_else(|| eyre!("expected amount field"))? + .as_str() + .ok_or_else(|| eyre!("expected amount to be in string format"))?; + + let amount = Amount::from_str(amount_str).map_err(handle_generic_error)?; + + Ok(amount) + } + None => { + debug!( + "Denom `{denom}` not found when querying for balance, will return 0{denom}" + ); + Ok(Amount::from_str("0").map_err(handle_generic_error)?) + } + } + } + } } /** @@ -55,7 +112,7 @@ pub fn query_recipient_transactions( rpc_listen_address: &str, recipient_address: &str, ) -> Result { - let res = simple_exec( + let res = match simple_exec( chain_id, command_path, &[ @@ -66,8 +123,25 @@ pub fn query_recipient_transactions( "--events", &format!("transfer.recipient={recipient_address}"), ], - )? - .stdout; + ) { + Ok(output) => output.stdout, + // Cosmos SDK v0.50.1 changed the `query txs` CLI flag from `--events` to `--query` + Err(_) => { + simple_exec( + chain_id, + command_path, + &[ + "--node", + rpc_listen_address, + "query", + "txs", + "--query", + &format!("transfer.recipient='{recipient_address}'"), + ], + )? + .stdout + } + }; tracing::debug!("parsing tx result: {}", res); @@ -120,3 +194,101 @@ pub fn query_cross_chain_query( Ok(res) } + +/// Query authority account for a specific module +pub fn query_auth_module( + chain_id: &str, + command_path: &str, + home_path: &str, + rpc_listen_address: &str, + module_name: &str, +) -> Result { + let account = match simple_exec( + chain_id, + command_path, + &[ + "--home", + home_path, + "--node", + rpc_listen_address, + "query", + "auth", + "module-account", + module_name, + "--output", + "json", + ], + ) { + Ok(output) => { + let json_res: HashMap = + serde_json::from_str(&output.stdout).map_err(handle_generic_error)?; + + json_res + .get("account") + .ok_or_else(|| eyre!("expect `account` string field to be present in json result"))? + .clone() + } + Err(e) => { + debug!("CLI `query auth module-account` failed, will try with `query auth module-accounts`: {e}"); + let output = simple_exec( + chain_id, + command_path, + &[ + "--home", + home_path, + "--node", + rpc_listen_address, + "query", + "auth", + "module-accounts", + "--output", + "json", + ], + )? + .stdout; + let json_res: HashMap = + serde_json::from_str(&output).map_err(handle_generic_error)?; + + let accounts = json_res + .get("accounts") + .ok_or_else(|| { + eyre!("expect `accounts` string field to be present in json result") + })? + .as_array() + .ok_or_else(|| eyre!("expected `accounts` to be an array"))?; + + accounts + .iter() + .find(|&account| { + if let Some(name) = account.get("name") { + name == module_name + } else { + false + } + }) + .ok_or_else(|| { + eyre!("expected to find the account for the `{module_name}` module") + })? + .clone() + } + }; + + // Depending on the version used the CLI `query auth module-account` will have a field `base_account` or + // or a field `value` containing the address. + let res = match account.get("base_account") { + Some(base_account) => base_account + .get("address") + .ok_or_else(|| eyre!("expect `address` string field to be present in json result"))? + .as_str() + .ok_or_else(|| eyre!("failed to convert value to &str"))?, + None => account + .get("value") + .ok_or_else(|| eyre!("expect `value` string field to be present in json result"))? + .get("address") + .ok_or_else(|| eyre!("expect `address` string field to be present in json result"))? + .as_str() + .ok_or_else(|| eyre!("failed to convert value to &str"))?, + }; + + Ok(res.to_owned()) +} diff --git a/tools/test-framework/src/chain/config.rs b/tools/test-framework/src/chain/config.rs index a8133dd048..4c74ea3b11 100644 --- a/tools/test-framework/src/chain/config.rs +++ b/tools/test-framework/src/chain/config.rs @@ -9,6 +9,7 @@ use core::time::Duration; use eyre::{eyre, Report as Error}; use toml::Value; +use tracing::debug; /// Set the `rpc` field in the full node config. pub fn set_rpc_port(config: &mut Value, port: u16) -> Result<(), Error> { @@ -253,7 +254,10 @@ pub fn set_crisis_denom(genesis: &mut serde_json::Value, crisis_denom: &str) -> Ok(()) } -pub fn set_voting_period(genesis: &mut serde_json::Value, period: &str) -> Result<(), Error> { +pub fn set_voting_period(genesis: &mut serde_json::Value, period: u64) -> Result<(), Error> { + // Expedited voting period must be strictly less that the regular voting period + let regular_period = format!("{period}s"); + let expedited_period = format!("{}s", period - 1); let voting_period = genesis .get_mut("app_state") .and_then(|app_state| app_state.get_mut("gov")) @@ -264,10 +268,34 @@ pub fn set_voting_period(genesis: &mut serde_json::Value, period: &str) -> Resul voting_period .insert( "voting_period".to_owned(), - serde_json::Value::String(period.to_string()), + serde_json::Value::String(regular_period), ) .ok_or_else(|| eyre!("failed to update voting_period in genesis file"))?; + let maybe_expedited_voting_period = genesis + .get_mut("app_state") + .and_then(|app_state| app_state.get_mut("gov")) + .and_then(|gov| get_mut_with_fallback(gov, "params", "expedited_voting_period")); + + if let Some(expedited_voting_period) = maybe_expedited_voting_period { + let expedited_voting_period = expedited_voting_period + .as_object_mut() + .ok_or_else(|| eyre!("failed to get voting_params in genesis file"))?; + + // Only insert `expedited_voting_period` if it already exists in order to avoid adding an unknown configuration in + // chains using Cosmos SDK pre v0.50 + match expedited_voting_period.get("expedited_voting_period") { + Some(_) => { + expedited_voting_period + .insert( + "expedited_voting_period".to_owned(), + serde_json::Value::String(expedited_period), + ).ok_or_else(|| eyre!("failed to update expedited_voting_period in genesis file"))?; + }, + None => debug!("`expedited_voting_period` was not updated, this configuration was introduced in Cosmos SDK v0.50"), + } + } + Ok(()) } diff --git a/tools/test-framework/src/chain/ext/bootstrap.rs b/tools/test-framework/src/chain/ext/bootstrap.rs index 72fc668e38..37f7818d75 100644 --- a/tools/test-framework/src/chain/ext/bootstrap.rs +++ b/tools/test-framework/src/chain/ext/bootstrap.rs @@ -16,8 +16,8 @@ use crate::chain::cli::bootstrap::{ start_chain, }; use crate::chain::cli::provider::{ - copy_validator_key_pair, query_consumer_genesis, query_consumer_proposal, - replace_genesis_state, submit_consumer_chain_proposal, + copy_validator_key_pair, query_consumer_genesis, query_gov_proposal, replace_genesis_state, + submit_consumer_chain_proposal, }; use crate::chain::driver::ChainDriver; use crate::chain::exec::simple_exec; @@ -26,6 +26,7 @@ use crate::ibc::token::Token; use crate::prelude::assert_eventually_succeed; use crate::types::process::ChildProcess; use crate::types::wallet::{Wallet, WalletAddress, WalletId}; +use crate::util::proposal_status::ProposalStatus; pub trait ChainBootstrapMethodsExt { /** @@ -110,25 +111,16 @@ pub trait ChainBootstrapMethodsExt { ) -> Result<(), Error>; /** - Assert that the consumer chain proposal is eventually submitted. + Assert that the proposal is eventually in the desired state. */ - fn assert_consumer_chain_proposal_submitted( - &self, - chain_id: &str, - command_path: &str, - home_path: &str, - rpc_listen_address: &str, - ) -> Result<(), Error>; - - /** - Assert that the consumer chain proposal eventually passes. - */ - fn assert_consumer_chain_proposal_passed( + fn assert_proposal_status( &self, chain_id: &str, command_path: &str, home_path: &str, rpc_listen_address: &str, + status: ProposalStatus, + proposal_id: &str, ) -> Result<(), Error>; /** @@ -330,66 +322,59 @@ impl ChainBootstrapMethodsExt for ChainDriver { ) } - fn assert_consumer_chain_proposal_submitted( + fn assert_proposal_status( &self, chain_id: &str, command_path: &str, home_path: &str, rpc_listen_address: &str, + status: ProposalStatus, + proposal_id: &str, ) -> Result<(), Error> { assert_eventually_succeed( - "consumer chain proposal submitted", + &format!("proposal `{}` status: {}", proposal_id, status.as_str()), 10, - Duration::from_secs(1), - || { - match query_consumer_proposal(chain_id, command_path, home_path, rpc_listen_address) { - Ok(exec_output) => { - let json_res = json::from_str::(&exec_output.stdout).map_err(handle_generic_error)?; - let proposal_status = json_res.get("status") + Duration::from_secs(2), + || match query_gov_proposal( + chain_id, + command_path, + home_path, + rpc_listen_address, + proposal_id, + ) { + Ok(exec_output) => { + let json_res = json::from_str::(&exec_output.stdout) + .map_err(handle_generic_error)?; + // Cosmos SDK v0.50.1 outputs the status of the proposal using an integer code + let proposal_status: ProposalStatus = match json_res.get("proposal") { + Some(proposal_status) => proposal_status + .get("status") + .ok_or_else(|| eyre!("expected `status` field"))? + .try_into()?, + None => json_res + .get("status") .ok_or_else(|| eyre!("expected `status` field"))? - .as_str() - .ok_or_else(|| eyre!("expected string field"))?; - if proposal_status == "PROPOSAL_STATUS_VOTING_PERIOD" { - Ok(()) - } else { - Err(Error::generic(eyre!("consumer chain proposal is not in voting period. Proposal status: {proposal_status}"))) - } - }, - Err(e) => Err(Error::generic(eyre!("Error querying the consumer chain proposal. Potential issues could be due to not using enough gas or the proposal submitted is invalid. Error: {e}"))), + .try_into()?, + }; + + if proposal_status == status { + Ok(()) + } else { + Err(Error::generic(eyre!( + "proposal is not in `{}`. Proposal status: {}", + status.as_str(), + proposal_status.as_str() + ))) + } } - }, - )?; - Ok(()) - } - - fn assert_consumer_chain_proposal_passed( - &self, - chain_id: &str, - command_path: &str, - home_path: &str, - rpc_listen_address: &str, - ) -> Result<(), Error> { - assert_eventually_succeed( - "consumer chain proposal passed", - 10, - Duration::from_secs(5), - || { - match query_consumer_proposal(chain_id, command_path, home_path, rpc_listen_address) { - Ok(exec_output) => { - let json_res = json::from_str::(&exec_output.stdout).map_err(handle_generic_error)?; - let proposal_status = json_res.get("status") - .ok_or_else(|| eyre!("expected `status` field"))? - .as_str() - .ok_or_else(|| eyre!("expected string field"))?; - - if proposal_status == "PROPOSAL_STATUS_PASSED" { - Ok(()) - } else { - Err(Error::generic(eyre!("consumer chain proposal has not passed. Proposal status: {proposal_status}"))) - } - }, - Err(e) => Err(Error::generic(eyre!("Error querying the consumer chain proposal. Potential issues could be due to not using enough gas or the proposal submitted is invalid. Error: {e}"))), + Err(e) => { + let msg = e.to_string(); + if msg.contains(&format!("status:{}", status.as_str())) { + Ok(()) + } else { + Err(Error::generic(eyre!("Error querying proposal `{proposal_id}`. Potential issues could be due to not using enough gas or the proposal submitted is invalid. Error: {e}"))) } + } }, )?; Ok(()) diff --git a/tools/test-framework/src/chain/ext/proposal.rs b/tools/test-framework/src/chain/ext/proposal.rs index 46321a5447..e15e9a93ce 100644 --- a/tools/test-framework/src/chain/ext/proposal.rs +++ b/tools/test-framework/src/chain/ext/proposal.rs @@ -4,7 +4,7 @@ use ibc_relayer::config::default::max_grpc_decoding_size; use prost::Message; use ibc_proto::cosmos::gov::v1beta1::{query_client::QueryClient, QueryProposalRequest}; -use ibc_proto::ibc::core::client::v1::UpgradeProposal; +use ibc_proto::ibc::core::client::v1::{MsgIbcSoftwareUpgrade, UpgradeProposal}; use ibc_relayer::error::Error as RelayerError; use crate::chain::cli::upgrade::vote_proposal; @@ -79,18 +79,33 @@ pub async fn query_upgrade_proposal_height( .content .ok_or_else(|| eyre!("failed to retrieve content of Proposal"))?; - if proposal_content.type_url != *"/ibc.core.client.v1.UpgradeProposal" { - return Err(Error::incorrect_proposal_type_url( - proposal_content.type_url, - )); - } + let height = match proposal_content.type_url.as_str() { + "/ibc.core.client.v1.MsgIBCSoftwareUpgrade" => { + let upgrade_plan = MsgIbcSoftwareUpgrade::decode(&proposal_content.value as &[u8]) + .map_err(handle_generic_error)?; + + let plan = upgrade_plan + .plan + .ok_or_else(|| eyre!("failed to plan from MsgIbcSoftwareUpgrade"))?; + + plan.height as u64 + } + "/ibc.core.client.v1.UpgradeProposal" => { + let upgrade_plan = UpgradeProposal::decode(&proposal_content.value as &[u8]) + .map_err(handle_generic_error)?; - let upgrade_plan = - UpgradeProposal::decode(&proposal_content.value as &[u8]).map_err(handle_generic_error)?; + let plan = upgrade_plan + .plan + .ok_or_else(|| eyre!("failed to plan from MsgIbcSoftwareUpgrade"))?; - let plan = upgrade_plan - .plan - .ok_or_else(|| eyre!("failed to plan from UpgradeProposal"))?; + plan.height as u64 + } + _ => { + return Err(Error::incorrect_proposal_type_url( + proposal_content.type_url, + )) + } + }; - Ok(plan.height as u64) + Ok(height) } diff --git a/tools/test-framework/src/chain/tagged.rs b/tools/test-framework/src/chain/tagged.rs index 7ef47a1431..64b73ef171 100644 --- a/tools/test-framework/src/chain/tagged.rs +++ b/tools/test-framework/src/chain/tagged.rs @@ -10,6 +10,7 @@ use ibc_relayer::util::compat_mode::compat_mode_from_version; use serde_json as json; use tendermint_rpc::client::{Client, HttpClient}; +use crate::chain::cli::query::query_auth_module; use crate::chain::cli::query::query_recipient_transactions; use crate::chain::driver::ChainDriver; use crate::error::{handle_generic_error, Error}; @@ -71,7 +72,7 @@ pub trait TaggedChainDriverExt { ) -> Result<(), Error>; /** - Taggged version of [`query_recipient_transactions`]. + Tagged version of [`query_recipient_transactions`]. Query for the transactions related to a wallet on `Chain` receiving token transfer from others. @@ -80,6 +81,13 @@ pub trait TaggedChainDriverExt { &self, recipient_address: &MonoTagged, ) -> Result; + + /** + Tagged version of [`query_auth_module`]. + + Query for the authority account for a specific module. + */ + fn query_auth_module(&self, module_name: &str) -> Result; } impl<'a, Chain: Send> TaggedChainDriverExt for MonoTagged { @@ -155,4 +163,15 @@ impl<'a, Chain: Send> TaggedChainDriverExt for MonoTagged Result { + let driver = *self.value(); + query_auth_module( + driver.chain_id.as_str(), + &driver.command_path, + &driver.home_path, + &driver.rpc_listen_address(), + module_name, + ) + } } diff --git a/tools/test-framework/src/error.rs b/tools/test-framework/src/error.rs index 8a0fb932e1..cc4c24b29c 100644 --- a/tools/test-framework/src/error.rs +++ b/tools/test-framework/src/error.rs @@ -87,7 +87,7 @@ define_error! { IncorrectProposalTypeUrl { type_url: String } - | e | format_args!("expected /ibc.core.client.v1.UpgradeProposal but got {}", e.type_url), + | e | format_args!("expected /ibc.core.client.v1.UpgradeProposal or /ibc.core.client.v1.MsgIBCSoftwareUpgrade but got {}", e.type_url), EmptyProposal | _ | { "the Proposal content is empty" }, diff --git a/tools/test-framework/src/framework/binary/ics.rs b/tools/test-framework/src/framework/binary/ics.rs index 85dc113a0a..8125a541f9 100644 --- a/tools/test-framework/src/framework/binary/ics.rs +++ b/tools/test-framework/src/framework/binary/ics.rs @@ -11,6 +11,7 @@ use crate::framework::base::{run_basic_test, BasicTest, HasOverrides, TestConfig use crate::framework::binary::node::{NodeConfigOverride, NodeGenesisOverride}; use crate::prelude::FullNode; use crate::types::config::TestConfig; +use crate::util::proposal_status::ProposalStatus; /** Runs a test case that implements [`InterchainSecurityChainTest`]. @@ -74,14 +75,14 @@ where .chain_driver .submit_consumer_chain_proposal(chain_id.as_str(), "2023-05-31T12:09:47.048227Z")?; - node_a - .chain_driver - .assert_consumer_chain_proposal_submitted( - node_a.chain_driver.chain_id.as_str(), - &node_a.chain_driver.command_path, - &node_a.chain_driver.home_path, - &node_a.chain_driver.rpc_listen_address(), - )?; + node_a.chain_driver.assert_proposal_status( + node_a.chain_driver.chain_id.as_str(), + &node_a.chain_driver.command_path, + &node_a.chain_driver.home_path, + &node_a.chain_driver.rpc_listen_address(), + ProposalStatus::VotingPeriod, + "1", + )?; vote_proposal( node_a.chain_driver.chain_id.as_str(), @@ -91,11 +92,13 @@ where &provider_fee, )?; - node_a.chain_driver.assert_consumer_chain_proposal_passed( + node_a.chain_driver.assert_proposal_status( node_a.chain_driver.chain_id.as_str(), &node_a.chain_driver.command_path, &node_a.chain_driver.home_path, &node_a.chain_driver.rpc_listen_address(), + ProposalStatus::Passed, + "1", )?; let node_b = bootstrap_consumer_node( diff --git a/tools/test-framework/src/relayer/chain.rs b/tools/test-framework/src/relayer/chain.rs index bf095d57d9..c4d70fe466 100644 --- a/tools/test-framework/src/relayer/chain.rs +++ b/tools/test-framework/src/relayer/chain.rs @@ -21,6 +21,7 @@ */ use crossbeam_channel as channel; +use ibc_relayer::chain::cosmos::version::Specs; use tracing::Span; use ibc_proto::ibc::apps::fee::v1::{ @@ -121,8 +122,8 @@ where self.value().add_key(key_name, key) } - fn ibc_version(&self) -> Result, Error> { - self.value().ibc_version() + fn version_specs(&self) -> Result { + self.value().version_specs() } fn query_application_status(&self) -> Result { diff --git a/tools/test-framework/src/util/interchain_security.rs b/tools/test-framework/src/util/interchain_security.rs index ec808a539c..035efb3c84 100644 --- a/tools/test-framework/src/util/interchain_security.rs +++ b/tools/test-framework/src/util/interchain_security.rs @@ -10,7 +10,7 @@ pub fn update_genesis_for_consumer_chain(genesis: &mut serde_json::Value) -> Res .and_then(|app_state| app_state.get("gov")) .is_some() { - set_voting_period(genesis, "10s")?; + set_voting_period(genesis, 10)?; } Ok(()) } diff --git a/tools/test-framework/src/util/mod.rs b/tools/test-framework/src/util/mod.rs index bb1d92e67e..8fcd82a5dc 100644 --- a/tools/test-framework/src/util/mod.rs +++ b/tools/test-framework/src/util/mod.rs @@ -6,6 +6,7 @@ pub mod array; pub mod assert; pub mod file; pub mod interchain_security; +pub mod proposal_status; pub mod random; pub mod retry; pub mod suspend; diff --git a/tools/test-framework/src/util/proposal_status.rs b/tools/test-framework/src/util/proposal_status.rs new file mode 100644 index 0000000000..5c1e63df5e --- /dev/null +++ b/tools/test-framework/src/util/proposal_status.rs @@ -0,0 +1,80 @@ +use serde_json::Value; +use std::str::FromStr; + +use crate::prelude::*; + +#[derive(Clone, Debug, PartialEq, Eq)] +pub enum ProposalStatus { + Unspecified = 0, + DepositPeriod = 1, + VotingPeriod = 2, + Passed = 3, + Rejected = 4, + Failed = 5, +} + +impl TryFrom for ProposalStatus { + type Error = Error; + + fn try_from(value: i64) -> Result { + match value { + 0 => Ok(Self::Unspecified), + 1 => Ok(Self::DepositPeriod), + 2 => Ok(Self::VotingPeriod), + 3 => Ok(Self::Passed), + 4 => Ok(Self::Rejected), + 5 => Ok(Self::Failed), + _ => Err(Error::generic(eyre!( + "unknown value for proposal status: `{value}`" + ))), + } + } +} + +impl FromStr for ProposalStatus { + type Err = Error; + + fn from_str(s: &str) -> Result { + match s { + "PROPOSAL_STATUS_UNSPECIFIED" => Ok(Self::Unspecified), + "PROPOSAL_STATUS_DEPOSIT_PERIOD" => Ok(Self::DepositPeriod), + "PROPOSAL_STATUS_VOTING_PERIOD" => Ok(Self::VotingPeriod), + "PROPOSAL_STATUS_PASSED" => Ok(Self::Passed), + "PROPOSAL_STATUS_REJECTED" => Ok(Self::Rejected), + "PROPOSAL_STATUS_FAILED" => Ok(Self::Failed), + _ => Err(Error::generic(eyre!( + "unknown value for proposal status: `{s}`" + ))), + } + } +} + +impl ProposalStatus { + pub fn as_str(&self) -> &'static str { + match self { + Self::Unspecified => "PROPOSAL_STATUS_UNSPECIFIED", + Self::DepositPeriod => "PROPOSAL_STATUS_DEPOSIT_PERIOD", + Self::VotingPeriod => "PROPOSAL_STATUS_VOTING_PERIOD", + Self::Passed => "PROPOSAL_STATUS_PASSED", + Self::Rejected => "PROPOSAL_STATUS_REJECTED", + Self::Failed => "PROPOSAL_STATUS_FAILED", + } + } +} + +impl TryFrom<&Value> for ProposalStatus { + type Error = Error; + + fn try_from(value: &Value) -> Result { + if let Some(numeric_value) = value.as_i64() { + ProposalStatus::try_from(numeric_value) + } else { + // If .to_string() is used directly on a serde_json::Value the double quotes are kept in the string. + // Example: would result in `\"PROPOSAL_STATUS_VOTING_PERIOD\"` instead of `PROPOSAL_STATUS_VOTING_PERIOD` + let str_value = value + .as_str() + .ok_or_else(|| eyre!("error converting value to str: `{value}`"))?; + ProposalStatus::from_str(str_value) + } + } +} From 90e7fd7b67ca89db9fc382e988aa8a2e3f93e6da Mon Sep 17 00:00:00 2001 From: Luca Joss <43531661+ljoss17@users.noreply.github.com> Date: Thu, 16 Nov 2023 18:17:02 +0100 Subject: [PATCH 4/5] Update Gaia used in tests from v12 to v13 & v14 (#3700) * Update Gaia v12 to v13 and v14 in tests * Fix Celestia CI job --- .github/workflows/integration.yaml | 86 +++++++++++++++++---------- .github/workflows/misbehaviour.yml | 2 +- flake.lock | 94 +++++++++++++++++++++++------- flake.nix | 3 +- 4 files changed, 133 insertions(+), 52 deletions(-) diff --git a/.github/workflows/integration.yaml b/.github/workflows/integration.yaml index 7643796859..80ced67502 100644 --- a/.github/workflows/integration.yaml +++ b/.github/workflows/integration.yaml @@ -45,7 +45,10 @@ jobs: fail-fast: false matrix: chain: - - package: gaia12 + - package: gaia13 + command: gaiad + account_prefix: cosmos + - package: gaia14 command: gaiad account_prefix: cosmos - package: ibc-go-v4-simapp @@ -258,7 +261,10 @@ jobs: fail-fast: false matrix: chain: - - package: gaia12 + - package: gaia13 + command: gaiad + account_prefix: cosmos + - package: gaia14 command: gaiad account_prefix: cosmos - package: juno @@ -304,7 +310,10 @@ jobs: fail-fast: false matrix: chain: - - package: .#gaia12 .#stride-no-admin + - package: .#gaia13 .#stride-no-admin + command: gaiad,strided + account_prefix: cosmos,stride + - package: .#gaia14 .#stride-no-admin command: gaiad,strided account_prefix: cosmos,stride steps: @@ -340,6 +349,7 @@ jobs: nix shell ${{ matrix.chain.package }} -c \ cargo nextest run -p ibc-integration-test --no-fail-fast --failure-output final --test-threads=2 \ --features ics31 ics31:: + fee-grant: runs-on: ubuntu-20.04 strategy: @@ -391,7 +401,10 @@ jobs: fail-fast: false matrix: chain: - - package: gaia12 + - package: gaia13 + command: gaiad + account_prefix: cosmos + - package: gaia14 command: gaiad account_prefix: cosmos steps: @@ -434,9 +447,12 @@ jobs: fail-fast: false matrix: chain: - - package: neutron - command: neutrond - account_prefix: neutron + - package: .#gaia13 .#neutron + command: gaiad,neutrond + account_prefix: cosmos,neutron + - package: .#gaia14 .#neutron + command: gaiad,neutrond + account_prefix: cosmos,neutron steps: - uses: actions/checkout@v4 - uses: cachix/install-nix-action@v22 @@ -464,10 +480,10 @@ jobs: RUST_BACKTRACE: 1 NO_COLOR_LOG: 1 NEXTEST_RETRIES: 2 - CHAIN_COMMAND_PATHS: gaiad,${{ matrix.chain.command }} - ACCOUNT_PREFIXES: cosmos,${{ matrix.chain.account_prefix }} + CHAIN_COMMAND_PATHS: ${{ matrix.chain.command }} + ACCOUNT_PREFIXES: ${{ matrix.chain.account_prefix }} run: | - nix shell .#gaia12 .#${{ matrix.chain.package }} -c \ + nix shell ${{ matrix.chain.package }} -c \ cargo nextest run -p ibc-integration-test --no-fail-fast --failure-output final --test-threads=2 \ --features interchain-security interchain_security:: @@ -477,9 +493,12 @@ jobs: fail-fast: false matrix: chain: - - package: stride-consumer - command: strided - account_prefix: stride + - package: .#gaia13 .#stride-consumer + command: gaiad,strided + account_prefix: cosmos,stride + - package: .#gaia14 .#stride-consumer + command: gaiad,strided + account_prefix: cosmos,stride steps: - uses: actions/checkout@v4 - uses: cachix/install-nix-action@v22 @@ -507,10 +526,10 @@ jobs: RUST_BACKTRACE: 1 NO_COLOR_LOG: 1 NEXTEST_RETRIES: 2 - CHAIN_COMMAND_PATHS: gaiad,${{ matrix.chain.command }} - ACCOUNT_PREFIXES: cosmos,${{ matrix.chain.account_prefix }} + CHAIN_COMMAND_PATHS: ${{ matrix.chain.command }} + ACCOUNT_PREFIXES: ${{ matrix.chain.account_prefix }} run: | - nix shell .#gaia12 .#${{ matrix.chain.package }} -c \ + nix shell ${{ matrix.chain.package }} -c \ cargo nextest run -p ibc-integration-test --no-fail-fast --failure-output final --test-threads=2 \ --features interchain-security,ica interchain_security:: @@ -520,9 +539,12 @@ jobs: fail-fast: false matrix: chain: - - package: stride-consumer-no-admin - command: strided - account_prefix: stride + - package: .#gaia13 .#stride-consumer-no-admin + command: gaiad,strided + account_prefix: cosmos,stride + - package: .#gaia14 .#stride-consumer-no-admin + command: gaiad,strided + account_prefix: cosmos,stride steps: - uses: actions/checkout@v4 - uses: cachix/install-nix-action@v22 @@ -549,10 +571,10 @@ jobs: RUST_LOG: info RUST_BACKTRACE: 1 NO_COLOR_LOG: 1 - CHAIN_COMMAND_PATHS: gaiad,${{ matrix.chain.command }} - ACCOUNT_PREFIXES: cosmos,${{ matrix.chain.account_prefix }} + CHAIN_COMMAND_PATHS: ${{ matrix.chain.command }} + ACCOUNT_PREFIXES: ${{ matrix.chain.account_prefix }} run: | - nix shell .#gaia12 .#${{ matrix.chain.package }} -c \ + nix shell ${{ matrix.chain.package }} -c \ cargo nextest run -p ibc-integration-test --no-fail-fast --failure-output final --test-threads=2 \ --features interchain-security,ics31 interchain_security:: @@ -562,10 +584,14 @@ jobs: fail-fast: false matrix: chain: - - package: celestia - command: celestia-appd - account_prefix: celestia - native_token: utia + - package: .#celestia .#gaia13 + command: celestia-appd,gaiad + account_prefix: celestia,cosmos + native_token: utia,stake + - package: .#celestia .#gaia14 + command: celestia-appd,gaiad + account_prefix: celestia,cosmos + native_token: utia,stake steps: - uses: actions/checkout@v4 - uses: cachix/install-nix-action@v22 @@ -593,11 +619,11 @@ jobs: RUST_BACKTRACE: 1 NO_COLOR_LOG: 1 COMPAT_MODES: 0.34 - CHAIN_COMMAND_PATHS: ${{ matrix.chain.command }},gaiad - ACCOUNT_PREFIXES: ${{ matrix.chain.account_prefix }},cosmos - NATIVE_TOKENS: ${{ matrix.chain.native_token }},stake + CHAIN_COMMAND_PATHS: ${{ matrix.chain.command }} + ACCOUNT_PREFIXES: ${{ matrix.chain.account_prefix }} + NATIVE_TOKENS: ${{ matrix.chain.native_token }} run: | - nix shell .#python .#gaia12 .#${{ matrix.chain.package }} -c \ + nix shell .#python ${{ matrix.chain.package }} -c \ cargo nextest run -p ibc-integration-test --no-fail-fast --failure-output final --test-threads=2 \ --features celestia diff --git a/.github/workflows/misbehaviour.yml b/.github/workflows/misbehaviour.yml index 577455c35c..edba7b3824 100644 --- a/.github/workflows/misbehaviour.yml +++ b/.github/workflows/misbehaviour.yml @@ -43,7 +43,7 @@ jobs: fail-fast: false matrix: chain: - - package: gaia12 + - package: gaia14 command: gaiad account_prefix: cosmos steps: diff --git a/flake.lock b/flake.lock index f80edd5878..9db2166d6c 100644 --- a/flake.lock +++ b/flake.lock @@ -71,17 +71,17 @@ "centauri-src": { "flake": false, "locked": { - "lastModified": 1697027127, - "narHash": "sha256-zdEJr4VfwKq20rGx7JZYV7cnz5APwnPSMJrjX9S/bT8=", + "lastModified": 1699873949, + "narHash": "sha256-oJNkzBM0pD6+KkIH8ICVcl8yp94R2EoIsvb/i+t5c8c=", "owner": "dzmitry-lahoda-forks", "repo": "composable-centauri", - "rev": "9a296e3dcca3ff390dd5622ab3cfbdfa0b68d2e9", + "rev": "c6736b946c3bc6c7c23788d499b2dff94ffd39f5", "type": "github" }, "original": { "owner": "dzmitry-lahoda-forks", "repo": "composable-centauri", - "rev": "9a296e3dcca3ff390dd5622ab3cfbdfa0b68d2e9", + "rev": "c6736b946c3bc6c7c23788d499b2dff94ffd39f5", "type": "github" } }, @@ -119,6 +119,8 @@ "gaia10-src": "gaia10-src", "gaia11-src": "gaia11-src", "gaia12-src": "gaia12-src", + "gaia13-src": "gaia13-src", + "gaia14-src": "gaia14-src", "gaia5-src": "gaia5-src", "gaia6-ordered-src": "gaia6-ordered-src", "gaia6-src": "gaia6-src", @@ -172,11 +174,11 @@ "wasmvm_1_beta7-src": "wasmvm_1_beta7-src" }, "locked": { - "lastModified": 1699655934, - "narHash": "sha256-nLJQMsH8TaGAGBEZRzSNQugzZGclkDqVffb7oVP974Y=", + "lastModified": 1700133562, + "narHash": "sha256-ItMoSAOJq2yKXeeyqXB+Aei+qlmwmmPz9HgnGAfDJNs=", "owner": "informalsystems", "repo": "cosmos.nix", - "rev": "6d54d90c8d8c26a188ef76dd288d08192aa3532d", + "rev": "f93ee05ad75196fa48ec025b1632cd12ba322e5c", "type": "github" }, "original": { @@ -306,12 +308,15 @@ } }, "flake-utils_3": { + "inputs": { + "systems": "systems_3" + }, "locked": { - "lastModified": 1667395993, - "narHash": "sha256-nuEHfE/LcWyuSWnS8t12N1wc105Qtau+/OdUAjtQ0rA=", + "lastModified": 1694529238, + "narHash": "sha256-zsNZZGTGnMOf9YpHKJqMSsa0dXbfmxeoJ7xHlrt+xmY=", "owner": "numtide", "repo": "flake-utils", - "rev": "5aed5285a952e0b949eb3ba02c12fa4fcfef535f", + "rev": "ff7b65b44d01cf9ba6a71320833626af21126384", "type": "github" }, "original": { @@ -322,7 +327,7 @@ }, "flake-utils_4": { "inputs": { - "systems": "systems_3" + "systems": "systems_4" }, "locked": { "lastModified": 1694529238, @@ -405,6 +410,40 @@ "type": "github" } }, + "gaia13-src": { + "flake": false, + "locked": { + "lastModified": 1699370179, + "narHash": "sha256-bvJ33JL1Fr7ilnnYEjrjnbS/dbFkyhZ2uq6u39CeTa0=", + "owner": "cosmos", + "repo": "gaia", + "rev": "2406abb61856b61904ff06c7be2a355babcc3dfc", + "type": "github" + }, + "original": { + "owner": "cosmos", + "ref": "v13.0.2", + "repo": "gaia", + "type": "github" + } + }, + "gaia14-src": { + "flake": false, + "locked": { + "lastModified": 1700067649, + "narHash": "sha256-7AnaIy/SElf/Uj2xTbHzLSgPY68SgQqqJZ2BPmt6czo=", + "owner": "cosmos", + "repo": "gaia", + "rev": "189b57be735d64d0dbf0945717b49017a1beb11e", + "type": "github" + }, + "original": { + "owner": "cosmos", + "ref": "v14.0.0", + "repo": "gaia", + "type": "github" + } + }, "gaia5-src": { "flake": false, "locked": { @@ -868,11 +907,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1698553279, - "narHash": "sha256-T/9P8yBSLcqo/v+FTOBK+0rjzjPMctVymZydbvR/Fak=", + "lastModified": 1699725108, + "narHash": "sha256-NTiPW4jRC+9puakU4Vi8WpFEirhp92kTOSThuZke+FA=", "owner": "nixos", "repo": "nixpkgs", - "rev": "90e85bc7c1a6fc0760a94ace129d3a1c61c3d035", + "rev": "911ad1e67f458b6bcf0278fa85e33bb9924fed7e", "type": "github" }, "original": { @@ -916,11 +955,11 @@ }, "nixpkgs_3": { "locked": { - "lastModified": 1674990008, - "narHash": "sha256-4zOyp+hFW2Y7imxIpZqZGT8CEqKmDjwgfD6BzRUE0mQ=", + "lastModified": 1699343069, + "narHash": "sha256-s7BBhyLA6MI6FuJgs4F/SgpntHBzz40/qV0xLPW6A1Q=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "d2bbcbe6c626d339b25a4995711f07625b508214", + "rev": "ec750fd01963ab6b20ee1f0cb488754e8036d89d", "type": "github" }, "original": { @@ -932,11 +971,11 @@ }, "nixpkgs_4": { "locked": { - "lastModified": 1699725108, - "narHash": "sha256-NTiPW4jRC+9puakU4Vi8WpFEirhp92kTOSThuZke+FA=", + "lastModified": 1700108881, + "narHash": "sha256-+Lqybl8kj0+nD/IlAWPPG/RDTa47gff9nbei0u7BntE=", "owner": "nixos", "repo": "nixpkgs", - "rev": "911ad1e67f458b6bcf0278fa85e33bb9924fed7e", + "rev": "7414e9ee0b3e9903c24d3379f577a417f0aae5f1", "type": "github" }, "original": { @@ -1233,6 +1272,21 @@ "type": "github" } }, + "systems_4": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + }, "ts-relayer-src": { "flake": false, "locked": { diff --git a/flake.nix b/flake.nix index 3d316b9a49..9defb85611 100644 --- a/flake.nix +++ b/flake.nix @@ -29,7 +29,8 @@ (cosmos-nix) cometbft gaia6-ordered - gaia12 + gaia13 + gaia14 osmosis wasmd ibc-go-v2-simapp From 94a0208d0fd50bbf33f8ebd0f6b7ba39ede5a725 Mon Sep 17 00:00:00 2001 From: Luca Joss <43531661+ljoss17@users.noreply.github.com> Date: Fri, 17 Nov 2023 13:03:47 +0100 Subject: [PATCH 5/5] Replace Gaia v12 with v13 and v14 in multi-chain tests (#3701) --- .github/workflows/multi-chains.yaml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/multi-chains.yaml b/.github/workflows/multi-chains.yaml index 681eaada4f..cecbd156ad 100644 --- a/.github/workflows/multi-chains.yaml +++ b/.github/workflows/multi-chains.yaml @@ -58,7 +58,10 @@ jobs: fail-fast: false matrix: first-package: - - package: gaia12 + - package: gaia13 + command: gaiad + account_prefix: cosmos + - package: gaia14 command: gaiad account_prefix: cosmos - package: ibc-go-v7-simapp