From 47adda35b3656559c4ecd2666bc3ce63484ac9c6 Mon Sep 17 00:00:00 2001 From: Luca Joss Date: Wed, 18 Oct 2023 12:01:51 +0200 Subject: [PATCH 1/7] Update test bootstrap to work with Celestia chain --- crates/relayer-cli/src/chain_registry.rs | 1 + crates/relayer-cli/src/commands/listen.rs | 7 +-- crates/relayer/src/chain/cosmos.rs | 6 +- crates/relayer/src/config.rs | 61 ++++++++++++++++++- crates/relayer/src/config/error.rs | 4 ++ crates/relayer/src/error.rs | 4 ++ crates/relayer/src/util.rs | 1 + crates/relayer/src/util/compat_mode.rs | 27 ++++++++ tools/integration-test/Cargo.toml | 1 + .../src/tests/clear_packet.rs | 4 +- .../src/tests/client_refresh.rs | 4 +- .../src/tests/client_upgrade.rs | 24 +++++--- tools/integration-test/src/tests/mod.rs | 2 + .../integration-test/src/tests/supervisor.rs | 4 +- tools/integration-test/src/tests/transfer.rs | 3 + .../src/bootstrap/binary/chain.rs | 12 ++-- tools/test-framework/src/bootstrap/init.rs | 8 +++ .../src/bootstrap/nary/chain.rs | 4 +- tools/test-framework/src/bootstrap/single.rs | 25 +++++--- tools/test-framework/src/chain/builder.rs | 25 ++++++++ .../test-framework/src/chain/cli/transfer.rs | 3 +- tools/test-framework/src/chain/config.rs | 11 ++++ tools/test-framework/src/chain/driver.rs | 7 +++ .../test-framework/src/chain/ext/transfer.rs | 3 + tools/test-framework/src/chain/tagged.rs | 5 +- .../src/framework/binary/ics.rs | 4 +- tools/test-framework/src/relayer/tx.rs | 7 ++- tools/test-framework/src/types/config.rs | 4 ++ tools/test-framework/src/types/single/node.rs | 14 ++++- 29 files changed, 239 insertions(+), 46 deletions(-) create mode 100644 crates/relayer/src/util/compat_mode.rs diff --git a/crates/relayer-cli/src/chain_registry.rs b/crates/relayer-cli/src/chain_registry.rs index 305a8d615a..480d64dc7d 100644 --- a/crates/relayer-cli/src/chain_registry.rs +++ b/crates/relayer-cli/src/chain_registry.rs @@ -160,6 +160,7 @@ where address_type: AddressType::default(), sequential_batch_tx: false, extension_options: Vec::new(), + compat_mode: None, }) } diff --git a/crates/relayer-cli/src/commands/listen.rs b/crates/relayer-cli/src/commands/listen.rs index 1806fc310d..366e8a8f78 100644 --- a/crates/relayer-cli/src/commands/listen.rs +++ b/crates/relayer-cli/src/commands/listen.rs @@ -17,6 +17,7 @@ use ibc_relayer::{ chain::handle::Subscription, config::{ChainConfig, EventSourceMode}, event::source::EventSource, + util::compat_mode::compat_mode_from_version, }; use ibc_relayer_types::{core::ics24_host::identifier::ChainId, events::IbcEvent}; @@ -171,10 +172,8 @@ fn detect_compatibility_mode( ) -> eyre::Result { let client = HttpClient::new(config.rpc_addr.clone())?; let status = rt.block_on(client.status())?; - let compat_mode = CompatMode::from_version(status.node_info.version).unwrap_or_else(|e| { - warn!("Unsupported tendermint version, will use v0.37 compatibility mode but relaying might not work as desired: {e}"); - CompatMode::V0_37 - }); + let compat_mode = + compat_mode_from_version(&config.compat_mode, status.node_info.version)?.into(); Ok(compat_mode) } diff --git a/crates/relayer/src/chain/cosmos.rs b/crates/relayer/src/chain/cosmos.rs index b2f71a1c37..9db2b81265 100644 --- a/crates/relayer/src/chain/cosmos.rs +++ b/crates/relayer/src/chain/cosmos.rs @@ -103,6 +103,7 @@ use crate::keyring::{KeyRing, Secp256k1KeyPair, SigningKeyPair}; use crate::light_client::tendermint::LightClient as TmLightClient; use crate::light_client::{LightClient, Verified}; use crate::misbehaviour::MisbehaviourEvidence; +use crate::util::compat_mode::compat_mode_from_version; use crate::util::pretty::{ PrettyIdentifiedChannel, PrettyIdentifiedClientState, PrettyIdentifiedConnection, }; @@ -878,10 +879,7 @@ impl ChainEndpoint for CosmosSdkChain { let node_info = rt.block_on(fetch_node_info(&rpc_client, &config))?; - let compat_mode = CompatMode::from_version(node_info.version).unwrap_or_else(|e| { - warn!("Unsupported tendermint version, will use v0.37 compatibility mode but relaying might not work as desired: {e}"); - CompatMode::V0_37 - }); + let compat_mode = compat_mode_from_version(&config.compat_mode, node_info.version)?.into(); rpc_client.set_compat_mode(compat_mode); let light_client = TmLightClient::from_config(&config, node_info.id)?; diff --git a/crates/relayer/src/config.rs b/crates/relayer/src/config.rs index 8fe656dcb3..7abaeb6e58 100644 --- a/crates/relayer/src/config.rs +++ b/crates/relayer/src/config.rs @@ -24,7 +24,9 @@ use std::{ }; use tendermint::block::Height as BlockHeight; use tendermint_light_client::verifier::types::TrustThreshold; -use tendermint_rpc::{Url, WebSocketClientUrl}; +use tendermint_rpc::client::CompatMode as TmCompatMode; +use tendermint_rpc::Url; +use tendermint_rpc::WebSocketClientUrl; use ibc_proto::google::protobuf::Any; use ibc_relayer_types::core::ics23_commitment::specs::ProofSpecs; @@ -146,6 +148,62 @@ impl Display for ExtensionOption { } } +#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] +pub enum CompatMode { + /// Use version 0.34 of the protocol. + V0_34, + /// Use version 0.37 of the protocol. + V0_37, +} + +impl Display for CompatMode { + fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> { + match self { + Self::V0_34 => write!(f, "v0.34"), + Self::V0_37 => write!(f, "v0.37"), + } + } +} + +impl FromStr for CompatMode { + type Err = Error; + + fn from_str(s: &str) -> Result { + match s { + "V0_34" => Ok(Self::V0_34), + "V0_37" => Ok(Self::V0_37), + _ => Err(Error::invalid_compat_mode(s.to_owned())), + } + } +} + +impl From for CompatMode { + fn from(value: TmCompatMode) -> Self { + match value { + TmCompatMode::V0_34 => Self::V0_34, + TmCompatMode::V0_37 => Self::V0_37, + } + } +} + +impl From for TmCompatMode { + fn from(value: CompatMode) -> Self { + match value { + CompatMode::V0_34 => Self::V0_34, + CompatMode::V0_37 => Self::V0_37, + } + } +} + +impl CompatMode { + pub fn equal_to_tm_compat_mode(&self, tm_compat_mode: TmCompatMode) -> bool { + match self { + Self::V0_34 => tm_compat_mode == TmCompatMode::V0_34, + Self::V0_37 => tm_compat_mode == TmCompatMode::V0_37, + } + } +} + /// Defaults for various fields pub mod default { use super::*; @@ -663,6 +721,7 @@ pub struct ChainConfig { pub address_type: AddressType, #[serde(default = "Vec::new", skip_serializing_if = "Vec::is_empty")] pub extension_options: Vec, + pub compat_mode: Option, } /// Attempt to load and parse the TOML config file as a `Config`. diff --git a/crates/relayer/src/config/error.rs b/crates/relayer/src/config/error.rs index 9889e553ad..1aac124d26 100644 --- a/crates/relayer/src/config/error.rs +++ b/crates/relayer/src/config/error.rs @@ -10,6 +10,10 @@ define_error! { [ TraceError ] |_| { "invalid configuration" }, + InvalidCompatMode + { compat_mode: String } + |e| { format!("invalid compat mode: {}", e.compat_mode) }, + Encode [ TraceError ] |_| { "invalid configuration" }, diff --git a/crates/relayer/src/error.rs b/crates/relayer/src/error.rs index 10e97c08b7..3f75da8aec 100644 --- a/crates/relayer/src/error.rs +++ b/crates/relayer/src/error.rs @@ -591,6 +591,10 @@ define_error! { { address: String } [ TendermintRpcError ] |e| { format!("invalid archive node address {}", e.address) }, + + InvalidCompatMode + [ TendermintRpcError ] + |_| { "Invalid CompatMode queried from chain and no `compat_mode` configured in Hermes. This can be fixed by specifying a `compat_mode` in Hermes config.toml" }, } } diff --git a/crates/relayer/src/util.rs b/crates/relayer/src/util.rs index 589b2f5ff4..e944c2023a 100644 --- a/crates/relayer/src/util.rs +++ b/crates/relayer/src/util.rs @@ -2,6 +2,7 @@ mod block_on; pub use block_on::{block_on, spawn_blocking}; pub mod collate; +pub mod compat_mode; pub mod debug_section; pub mod diff; pub mod iter; diff --git a/crates/relayer/src/util/compat_mode.rs b/crates/relayer/src/util/compat_mode.rs new file mode 100644 index 0000000000..e8964832b8 --- /dev/null +++ b/crates/relayer/src/util/compat_mode.rs @@ -0,0 +1,27 @@ +use tracing::warn; + +use tendermint::Version; +use tendermint_rpc::client::CompatMode as TmCompatMode; + +use crate::config::CompatMode; +use crate::error::Error; + +/// This is a wrapper around tendermint-rs CompatMode::from_version() method. +/// +pub fn compat_mode_from_version( + configured_version: &Option, + version: Version, +) -> Result { + let queried_version = TmCompatMode::from_version(version); + + // This will prioritize the use of the CompatMode specified in Hermes configuration file + match (configured_version, queried_version) { + (Some(configured), Ok(queried)) if !configured.equal_to_tm_compat_mode(queried) => { + warn!("Be wary of potential CompatMode version misconfiguration. Configured version: {}, Version output from chain: {}. Hermes will use the configured CompatMode version `{}`. If this configuration is done on purpose this message can be ignored.", configured, queried, configured); + Ok(configured.clone()) + } + (Some(configured), _) => Ok(configured.clone()), + (_, Ok(queried)) => Ok(queried.into()), + (_, Err(e)) => Err(Error::invalid_compat_mode(e)), + } +} diff --git a/tools/integration-test/Cargo.toml b/tools/integration-test/Cargo.toml index f5d69d9132..fbac3486da 100644 --- a/tools/integration-test/Cargo.toml +++ b/tools/integration-test/Cargo.toml @@ -39,6 +39,7 @@ ics31 = [] clean-workers = [] fee-grant = [] interchain-security = [] +celestia = [] [[bin]] name = "test_setup_with_binary_channel" diff --git a/tools/integration-test/src/tests/clear_packet.rs b/tools/integration-test/src/tests/clear_packet.rs index 9eef3f6c26..562dbe398c 100644 --- a/tools/integration-test/src/tests/clear_packet.rs +++ b/tools/integration-test/src/tests/clear_packet.rs @@ -204,12 +204,13 @@ impl TestOverrides for ClearPacketNoScanTest { impl BinaryChannelTest for ClearPacketNoScanTest { fn run( &self, - _config: &TestConfig, + config: &TestConfig, relayer: RelayerDriver, chains: ConnectedChains, channel: ConnectedChannel, ) -> Result<(), Error> { let denom_a = chains.node_a.denom(); + let fee_denom_a = MonoTagged::new(Denom::base(&config.native_tokens[0])); let wallet_a = chains.node_a.wallets().user1().cloned(); let wallet_b = chains.node_b.wallets().user1().cloned(); @@ -272,6 +273,7 @@ impl BinaryChannelTest for ClearPacketNoScanTest { &channel.port_a.0, &channel.channel_id_a.0, &denom_a.with_amount(amount1).as_ref(), + &fee_denom_a.with_amount(1200u64).as_ref(), &dst_height, )?; diff --git a/tools/integration-test/src/tests/client_refresh.rs b/tools/integration-test/src/tests/client_refresh.rs index c5e79c2e71..a650d44c96 100644 --- a/tools/integration-test/src/tests/client_refresh.rs +++ b/tools/integration-test/src/tests/client_refresh.rs @@ -168,8 +168,8 @@ where { let mut config = Config::default(); - add_chain_config(&mut config, chains.node_a.value(), test_config)?; - add_chain_config(&mut config, chains.node_b.value(), test_config)?; + add_chain_config(&mut config, chains.node_a.value(), test_config, 0)?; + add_chain_config(&mut config, chains.node_b.value(), test_config, 1)?; config_modifier(&mut config); diff --git a/tools/integration-test/src/tests/client_upgrade.rs b/tools/integration-test/src/tests/client_upgrade.rs index 588e9992d5..9f6ceff850 100644 --- a/tools/integration-test/src/tests/client_upgrade.rs +++ b/tools/integration-test/src/tests/client_upgrade.rs @@ -70,10 +70,12 @@ impl BinaryChainTest for ClientUpgradeTest { ChainB: ibc_test_framework::prelude::ChainHandle, >( &self, - _config: &ibc_test_framework::prelude::TestConfig, + config: &ibc_test_framework::prelude::TestConfig, _relayer: ibc_test_framework::prelude::RelayerDriver, chains: ibc_test_framework::prelude::ConnectedChains, ) -> Result<(), ibc_test_framework::prelude::Error> { + 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(); @@ -84,7 +86,7 @@ impl BinaryChainTest for ClientUpgradeTest { let opts = UpgradePlanOptions { src_client_id, amount: 10000000u64, - denom: "stake".to_string(), + denom: fee_denom_a.to_string(), height_offset: DELTA_HEIGHT, upgraded_chain_id, upgraded_unbonding_period: None, @@ -116,7 +118,7 @@ impl BinaryChainTest for ClientUpgradeTest { .map_err(handle_generic_error)?; // Vote on the proposal so the chain will upgrade - driver.vote_proposal("1200stake")?; + 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 @@ -188,10 +190,12 @@ impl BinaryChainTest for HeightTooHighClientUpgradeTest { ChainB: ibc_test_framework::prelude::ChainHandle, >( &self, - _config: &ibc_test_framework::prelude::TestConfig, + config: &ibc_test_framework::prelude::TestConfig, _relayer: ibc_test_framework::prelude::RelayerDriver, chains: ibc_test_framework::prelude::ConnectedChains, ) -> Result<(), ibc_test_framework::prelude::Error> { + 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(); @@ -202,7 +206,7 @@ impl BinaryChainTest for HeightTooHighClientUpgradeTest { let opts = UpgradePlanOptions { src_client_id, amount: 10000000u64, - denom: "stake".to_string(), + denom: fee_denom_a.to_string(), height_offset: DELTA_HEIGHT, upgraded_chain_id, upgraded_unbonding_period: None, @@ -234,7 +238,7 @@ impl BinaryChainTest for HeightTooHighClientUpgradeTest { .map_err(handle_generic_error)?; // Vote on the proposal so the chain will upgrade - driver.vote_proposal("1200stake")?; + 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 @@ -270,10 +274,12 @@ impl BinaryChainTest for HeightTooLowClientUpgradeTest { ChainB: ibc_test_framework::prelude::ChainHandle, >( &self, - _config: &ibc_test_framework::prelude::TestConfig, + config: &ibc_test_framework::prelude::TestConfig, _relayer: ibc_test_framework::prelude::RelayerDriver, chains: ibc_test_framework::prelude::ConnectedChains, ) -> Result<(), ibc_test_framework::prelude::Error> { + 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(); @@ -284,7 +290,7 @@ impl BinaryChainTest for HeightTooLowClientUpgradeTest { let opts = UpgradePlanOptions { src_client_id, amount: 10000000u64, - denom: "stake".to_string(), + denom: fee_denom_a.to_string(), height_offset: DELTA_HEIGHT, upgraded_chain_id, upgraded_unbonding_period: None, @@ -316,7 +322,7 @@ impl BinaryChainTest for HeightTooLowClientUpgradeTest { .map_err(handle_generic_error)?; // Vote on the proposal so the chain will upgrade - driver.vote_proposal("1200stake")?; + 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 diff --git a/tools/integration-test/src/tests/mod.rs b/tools/integration-test/src/tests/mod.rs index 57526ac08b..2badc7caae 100644 --- a/tools/integration-test/src/tests/mod.rs +++ b/tools/integration-test/src/tests/mod.rs @@ -10,6 +10,7 @@ pub mod client_expiration; pub mod client_filter; pub mod client_refresh; pub mod client_settings; +#[cfg(not(feature = "celestia"))] pub mod client_upgrade; pub mod connection_delay; pub mod consensus_states; @@ -22,6 +23,7 @@ pub mod python; pub mod query_packet; pub mod supervisor; pub mod tendermint; +#[cfg(not(feature = "celestia"))] pub mod ternary_transfer; pub mod transfer; diff --git a/tools/integration-test/src/tests/supervisor.rs b/tools/integration-test/src/tests/supervisor.rs index c934d7a659..31b236d07b 100644 --- a/tools/integration-test/src/tests/supervisor.rs +++ b/tools/integration-test/src/tests/supervisor.rs @@ -188,12 +188,13 @@ impl TestOverrides for SupervisorScanTest { impl BinaryChannelTest for SupervisorScanTest { fn run( &self, - _config: &TestConfig, + config: &TestConfig, _relayer: RelayerDriver, chains: ConnectedChains, channels: ConnectedChannel, ) -> Result<(), Error> { let denom_a = chains.node_a.denom(); + let fee_denom_a = MonoTagged::new(Denom::base(&config.native_tokens[0])); let denom_b = derive_ibc_denom( &channels.port_b.as_ref(), @@ -229,6 +230,7 @@ impl BinaryChannelTest for SupervisorScanTest { &channels.port_a.0, &channels.channel_id_a.0, &denom_a.with_amount(1000u64).as_ref(), + &fee_denom_a.with_amount(1200u64).as_ref(), &dst_height, )?; diff --git a/tools/integration-test/src/tests/transfer.rs b/tools/integration-test/src/tests/transfer.rs index d51e3be616..f117dc742f 100644 --- a/tools/integration-test/src/tests/transfer.rs +++ b/tools/integration-test/src/tests/transfer.rs @@ -10,6 +10,7 @@ fn test_ibc_transfer() -> Result<(), Error> { Test that IBC token transfer can still work with a single chain that is connected to itself. */ +#[cfg(not(feature = "celestia"))] #[test] fn test_self_connected_ibc_transfer() -> Result<(), Error> { run_self_connected_binary_chain_test(&RunBinaryConnectionTest::new(&RunBinaryChannelTest::new( @@ -24,11 +25,13 @@ fn test_self_connected_ibc_transfer() -> Result<(), Error> { this behind the "experimental" feature flag so that normal developers are not obligated to understand how this test works yet. */ +#[cfg(not(feature = "celestia"))] #[test] fn test_nary_ibc_transfer() -> Result<(), Error> { run_binary_as_nary_channel_test(&IbcTransferTest) } +#[cfg(not(feature = "celestia"))] #[test] fn test_self_connected_nary_ibc_transfer() -> Result<(), Error> { run_self_connected_nary_chain_test(&RunNaryConnectionTest::new(&RunNaryChannelTest::new( diff --git a/tools/test-framework/src/bootstrap/binary/chain.rs b/tools/test-framework/src/bootstrap/binary/chain.rs index 386e743b28..1e5e461266 100644 --- a/tools/test-framework/src/bootstrap/binary/chain.rs +++ b/tools/test-framework/src/bootstrap/binary/chain.rs @@ -56,8 +56,8 @@ pub fn bootstrap_chains_with_full_nodes( > { let mut config = Config::default(); - add_chain_config(&mut config, &node_a, test_config)?; - add_chain_config(&mut config, &node_b, test_config)?; + add_chain_config(&mut config, &node_a, test_config, 0)?; + add_chain_config(&mut config, &node_b, test_config, 1)?; config_modifier(&mut config); @@ -257,9 +257,13 @@ pub fn add_chain_config( config: &mut Config, running_node: &FullNode, test_config: &TestConfig, + chain_number: usize, ) -> Result<(), Error> { - let chain_config = - running_node.generate_chain_config(&running_node.chain_driver.chain_type, test_config)?; + let chain_config = running_node.generate_chain_config( + &running_node.chain_driver.chain_type, + test_config, + chain_number, + )?; config.chains.push(chain_config); Ok(()) diff --git a/tools/test-framework/src/bootstrap/init.rs b/tools/test-framework/src/bootstrap/init.rs index 45a102127f..795f19787c 100644 --- a/tools/test-framework/src/bootstrap/init.rs +++ b/tools/test-framework/src/bootstrap/init.rs @@ -46,8 +46,14 @@ pub fn init_test() -> Result { let account_prefix = env::var("ACCOUNT_PREFIXES").unwrap_or_else(|_| "cosmos".to_string()); + let native_token = env::var("NATIVE_TOKENS").unwrap_or_else(|_| "stake".to_string()); + + let compat_modes = env::var("COMPAT_MODES").ok().map(parse_chain_command_paths); + let account_prefixes = parse_chain_command_paths(account_prefix); + let native_tokens = parse_chain_command_paths(native_token); + let chain_store_dir = format!("{}/test-{}", base_chain_store_dir, random_u32()); fs::create_dir_all(&chain_store_dir)?; @@ -65,6 +71,8 @@ pub fn init_test() -> Result { account_prefixes, hang_on_fail, bootstrap_with_random_ids: false, + native_tokens, + compat_modes, }) } diff --git a/tools/test-framework/src/bootstrap/nary/chain.rs b/tools/test-framework/src/bootstrap/nary/chain.rs index b0233ecdf5..795ec74e69 100644 --- a/tools/test-framework/src/bootstrap/nary/chain.rs +++ b/tools/test-framework/src/bootstrap/nary/chain.rs @@ -59,8 +59,8 @@ pub fn boostrap_chains_with_any_nodes( ) -> Result<(RelayerDriver, DynamicConnectedChains), Error> { let mut config = Config::default(); - for node in full_nodes.iter() { - add_chain_config(&mut config, node, test_config)?; + for (i, node) in full_nodes.iter().enumerate() { + add_chain_config(&mut config, node, test_config, i)?; } config_modifier(&mut config); diff --git a/tools/test-framework/src/bootstrap/single.rs b/tools/test-framework/src/bootstrap/single.rs index 2e341b9de2..2f4c1dd645 100644 --- a/tools/test-framework/src/bootstrap/single.rs +++ b/tools/test-framework/src/bootstrap/single.rs @@ -45,7 +45,9 @@ pub fn bootstrap_single_node( genesis_modifier: impl FnOnce(&mut serde_json::Value) -> Result<(), Error>, chain_number: usize, ) -> Result { - let stake_denom = Denom::base("stake"); + let native_token_number = chain_number % builder.native_tokens.len(); + let native_token = &builder.native_tokens[native_token_number]; + let native_denom = Denom::base(native_token); let denom = if use_random_id { Denom::base(&format!("coin{:x}", random_u32())) @@ -58,12 +60,13 @@ pub fn bootstrap_single_node( // when running `evmosd start`. let initial_amount = random_u128_range(1_000_000_000_000_000_000, 2_000_000_000_000_000_000); - let initial_stake = Token::new(stake_denom, initial_amount); - let additional_initial_stake = initial_stake + let initial_native_token = Token::new(native_denom, initial_amount); + let additional_native_token = initial_native_token .clone() .checked_add(1_000_000_000_000u64) .ok_or(Error::generic(eyre!( - "error creating initial stake with additional amount" + "error creating initial {} with additional amount", + native_token )))?; let initial_coin = Token::new(denom.clone(), initial_amount); @@ -79,15 +82,15 @@ pub fn bootstrap_single_node( let user2 = add_wallet(&chain_driver, "user2", use_random_id)?; // Validator is given more tokens as they are required to vote on upgrade chain - chain_driver.add_genesis_account(&validator.address, &[&additional_initial_stake])?; + chain_driver.add_genesis_account(&validator.address, &[&additional_native_token])?; - chain_driver.add_genesis_validator(&validator.id, &initial_stake)?; + chain_driver.add_genesis_validator(&validator.id, &initial_native_token)?; - chain_driver.add_genesis_account(&user1.address, &[&initial_stake, &initial_coin])?; + chain_driver.add_genesis_account(&user1.address, &[&initial_native_token, &initial_coin])?; - chain_driver.add_genesis_account(&user2.address, &[&initial_stake, &initial_coin])?; + chain_driver.add_genesis_account(&user2.address, &[&initial_native_token, &initial_coin])?; - chain_driver.add_genesis_account(&relayer.address, &[&initial_stake, &initial_coin])?; + chain_driver.add_genesis_account(&relayer.address, &[&initial_native_token, &initial_coin])?; chain_driver.collect_gen_txs()?; @@ -101,17 +104,19 @@ pub fn bootstrap_single_node( config::set_timeout_commit(config, Duration::from_secs(1))?; config::set_timeout_propose(config, Duration::from_secs(1))?; config::set_mode(config, "validator")?; + config::set_indexer(config, "kv")?; config_modifier(config)?; Ok(()) })?; + let minimum_gas = format!("0{}", native_token); chain_driver.update_chain_config("app.toml", |config| { config::set_grpc_port(config, chain_driver.grpc_port)?; config::disable_grpc_web(config)?; config::disable_api(config)?; - config::set_minimum_gas_price(config, "0stake")?; + config::set_minimum_gas_price(config, &minimum_gas)?; Ok(()) })?; diff --git a/tools/test-framework/src/chain/builder.rs b/tools/test-framework/src/chain/builder.rs index d78fe390ac..ba4d2eae8e 100644 --- a/tools/test-framework/src/chain/builder.rs +++ b/tools/test-framework/src/chain/builder.rs @@ -2,9 +2,11 @@ Builder construct that spawn new chains with some common parameters. */ +use eyre::eyre; use std::str::FromStr; use alloc::sync::Arc; +use ibc_relayer::config::CompatMode; use tokio::runtime::Runtime; use crate::chain::driver::ChainDriver; @@ -39,6 +41,10 @@ pub struct ChainBuilder { pub account_prefixes: Vec, + pub native_tokens: Vec, + + pub compat_modes: Option>, + pub runtime: Arc, } @@ -50,12 +56,16 @@ impl ChainBuilder { command_paths: Vec, base_store_dir: &str, account_prefixes: Vec, + native_tokens: Vec, + compat_modes: Option>, runtime: Arc, ) -> Self { Self { command_paths, base_store_dir: base_store_dir.to_string(), account_prefixes, + native_tokens, + compat_modes, runtime, } } @@ -68,6 +78,8 @@ impl ChainBuilder { config.chain_command_paths.clone(), &format!("{}", config.chain_store_dir.display()), config.account_prefixes.clone(), + config.native_tokens.clone(), + config.compat_modes.clone(), runtime, ) } @@ -96,6 +108,17 @@ impl ChainBuilder { // the number of chain binaries given. Same for account prefix. let chain_number = chain_number % self.command_paths.len(); let account_number = chain_number % self.account_prefixes.len(); + let native_token_number = chain_number % self.native_tokens.len(); + let compat_mode = if let Some(modes) = &self.compat_modes { + let mode_str = &modes[chain_number % modes.len()]; + Some(CompatMode::from_str(mode_str).map_err(|e| { + Error::generic(eyre!( + "Invalid CompatMode environment variable `{mode_str}`: {e}" + )) + })?) + } else { + None + }; let chain_type = ChainType::from_str(&self.command_paths[chain_number])?; @@ -121,6 +144,8 @@ impl ChainBuilder { p2p_port, pprof_port, self.runtime.clone(), + self.native_tokens[native_token_number].clone(), + compat_mode, )?; Ok(driver) diff --git a/tools/test-framework/src/chain/cli/transfer.rs b/tools/test-framework/src/chain/cli/transfer.rs index b91297db12..53457c04ab 100644 --- a/tools/test-framework/src/chain/cli/transfer.rs +++ b/tools/test-framework/src/chain/cli/transfer.rs @@ -49,6 +49,7 @@ pub fn transfer_from_chain( src_channel: &str, recipient: &str, token: &str, + fees: &str, timeout_height: &str, ) -> Result<(), Error> { simple_exec( @@ -73,7 +74,7 @@ pub fn transfer_from_chain( "--keyring-backend", "test", "--fees", - "1200stake", + fees, "--timeout-height", timeout_height, "--yes", diff --git a/tools/test-framework/src/chain/config.rs b/tools/test-framework/src/chain/config.rs index 617485e04a..a8133dd048 100644 --- a/tools/test-framework/src/chain/config.rs +++ b/tools/test-framework/src/chain/config.rs @@ -149,6 +149,17 @@ pub fn set_mode(config: &mut Value, mode: &str) -> Result<(), Error> { Ok(()) } +pub fn set_indexer(config: &mut Value, mode: &str) -> Result<(), Error> { + config + .get_mut("tx_index") + .ok_or_else(|| eyre!("expect tx_index section"))? + .as_table_mut() + .ok_or_else(|| eyre!("expect object"))? + .insert("indexer".to_string(), mode.into()); + + Ok(()) +} + pub fn set_max_deposit_period(genesis: &mut serde_json::Value, period: &str) -> Result<(), Error> { let max_deposit_period = genesis .get_mut("app_state") diff --git a/tools/test-framework/src/chain/driver.rs b/tools/test-framework/src/chain/driver.rs index f853ad10b9..0d35e6f09f 100644 --- a/tools/test-framework/src/chain/driver.rs +++ b/tools/test-framework/src/chain/driver.rs @@ -6,6 +6,7 @@ use core::time::Duration; use alloc::sync::Arc; use eyre::eyre; +use ibc_relayer::config::CompatMode; use tokio::runtime::Runtime; use ibc_relayer::chain::cosmos::types::config::TxConfig; @@ -95,6 +96,8 @@ pub struct ChainDriver { pub tx_config: TxConfig, pub runtime: Arc, + + pub compat_mode: Option, } impl ExportEnv for ChainDriver { @@ -120,12 +123,15 @@ impl ChainDriver { p2p_port: u16, pprof_port: u16, runtime: Arc, + native_token: String, + compat_mode: Option, ) -> Result { let tx_config = new_tx_config_for_test( chain_id.clone(), format!("http://localhost:{rpc_port}"), format!("http://localhost:{grpc_port}"), chain_type.address_type(), + native_token, )?; Ok(Self { @@ -141,6 +147,7 @@ impl ChainDriver { pprof_port, tx_config, runtime, + compat_mode, }) } diff --git a/tools/test-framework/src/chain/ext/transfer.rs b/tools/test-framework/src/chain/ext/transfer.rs index 58b85ccc46..94707ff8da 100644 --- a/tools/test-framework/src/chain/ext/transfer.rs +++ b/tools/test-framework/src/chain/ext/transfer.rs @@ -80,6 +80,7 @@ pub trait ChainTransferMethodsExt { port: &PortId, channel: &ChannelId, token: &TaggedTokenRef, + fees: &TaggedTokenRef, timeout_height: &Height, ) -> Result<(), Error>; } @@ -180,6 +181,7 @@ impl<'a, Chain: Send> ChainTransferMethodsExt for MonoTagged, + fees: &TaggedTokenRef, timeout_height: &Height, ) -> Result<(), Error> { let driver = *self.value(); @@ -194,6 +196,7 @@ impl<'a, Chain: Send> ChainTransferMethodsExt for MonoTagged TaggedChainDriverExt for MonoTagged GasConfig { +pub fn gas_config_for_test(native_token: String) -> GasConfig { let max_gas = 3000000; let gas_multiplier = 1.1; - let gas_price = GasPrice::new(0.003, "stake".to_string()); + let gas_price = GasPrice::new(0.003, native_token); let default_gas = max_gas; let fee_granter = "".to_string(); @@ -43,10 +43,11 @@ pub fn new_tx_config_for_test( raw_rpc_address: String, raw_grpc_address: String, address_type: AddressType, + native_token: String, ) -> Result { let rpc_address = Url::from_str(&raw_rpc_address).map_err(handle_generic_error)?; let grpc_address = Uri::from_str(&raw_grpc_address).map_err(handle_generic_error)?; - let gas_config = gas_config_for_test(); + let gas_config = gas_config_for_test(native_token); let rpc_timeout = Duration::from_secs(30); let max_msg_num = Default::default(); let max_tx_size = Default::default(); diff --git a/tools/test-framework/src/types/config.rs b/tools/test-framework/src/types/config.rs index ec11607bee..ea3944b3f5 100644 --- a/tools/test-framework/src/types/config.rs +++ b/tools/test-framework/src/types/config.rs @@ -30,6 +30,10 @@ pub struct TestConfig { pub account_prefixes: Vec, + pub native_tokens: Vec, + + pub compat_modes: Option>, + /** The directory path for storing the chain and relayer files. Defaults to `"data"`. This can be overridden with the `$CHAIN_STORE_DIR` diff --git a/tools/test-framework/src/types/single/node.rs b/tools/test-framework/src/types/single/node.rs index 5aeced1f4b..a9f00c8e02 100644 --- a/tools/test-framework/src/types/single/node.rs +++ b/tools/test-framework/src/types/single/node.rs @@ -9,6 +9,7 @@ use eyre::Report as Error; use ibc_relayer::chain::ChainType; use ibc_relayer::config; use ibc_relayer::config::gas_multiplier::GasMultiplier; +use ibc_relayer::config::CompatMode; use ibc_relayer::keyring::Store; use ibc_relayer_types::core::ics24_host::identifier::ChainId; use std::sync::{Arc, RwLock}; @@ -126,7 +127,9 @@ impl FullNode { &self, chain_type: &TestedChainType, test_config: &TestConfig, + chain_number: usize, ) -> Result { + let native_token_number = chain_number % test_config.native_tokens.len(); let hermes_keystore_dir = test_config .chain_store_dir .join("hermes_keyring") @@ -134,6 +137,11 @@ impl FullNode { .display() .to_string(); + let compat_mode = test_config.compat_modes.as_ref().map(|modes| { + let mode = &modes[chain_number % modes.len()]; + CompatMode::from_str(mode).unwrap() + }); + Ok(config::ChainConfig { id: self.chain_driver.chain_id.clone(), r#type: ChainType::CosmosSdk, @@ -164,13 +172,17 @@ impl FullNode { trusting_period: Some(Duration::from_secs(14 * 24 * 3600)), ccv_consumer_chain: false, trust_threshold: Default::default(), - gas_price: config::GasPrice::new(0.003, "stake".to_string()), + gas_price: config::GasPrice::new( + 0.003, + test_config.native_tokens[native_token_number].clone(), + ), packet_filter: Default::default(), address_type: chain_type.address_type(), memo_prefix: Default::default(), proof_specs: Default::default(), extension_options: Default::default(), sequential_batch_tx: false, + compat_mode, }) } From 5769296c313b859b05808de209f136e6057cc52a Mon Sep 17 00:00:00 2001 From: Luca Joss Date: Thu, 19 Oct 2023 09:50:41 +0200 Subject: [PATCH 2/7] Update Nix flake and add Celestia CI job --- .github/workflows/integration.yaml | 45 ++++++++++++++ flake.lock | 94 +++++++++++++++++++++--------- flake.nix | 1 + 3 files changed, 111 insertions(+), 29 deletions(-) diff --git a/.github/workflows/integration.yaml b/.github/workflows/integration.yaml index 0b6b60bc41..07cd72a4e7 100644 --- a/.github/workflows/integration.yaml +++ b/.github/workflows/integration.yaml @@ -547,6 +547,51 @@ jobs: cargo nextest run -p ibc-integration-test --no-fail-fast --failure-output final --test-threads=2 \ --features interchain-security,ics31 interchain_security:: + celestia-to-gaia: + runs-on: ubuntu-20.04 + strategy: + fail-fast: false + matrix: + chain: + - package: celestia + command: celestia-appd + account_prefix: celestia + native_token: utia + steps: + - uses: actions/checkout@v4 + - uses: cachix/install-nix-action@v22 + with: + install_url: https://nixos-nix-install-tests.cachix.org/serve/vij683ly7sl95nnhb67bdjjfabclr85m/install + install_options: '--tarball-url-prefix https://nixos-nix-install-tests.cachix.org/serve' + extra_nix_config: | + experimental-features = nix-command flakes + - uses: cachix/cachix-action@v12 + with: + name: cosmos + - uses: actions-rs/toolchain@v1 + with: + toolchain: stable + override: true + - uses: Swatinem/rust-cache@v2 + - uses: actions-rs/cargo@v1 + with: + command: test + args: -p ibc-integration-test --features interchain-security --no-fail-fast --no-run + - name: Install cargo-nextest + run: curl -LsSf https://get.nexte.st/latest/linux | tar zxf - -C ${CARGO_HOME:-~/.cargo}/bin + - env: + RUST_LOG: info + RUST_BACKTRACE: 1 + NO_COLOR_LOG: 1 + COMPAT_MODES: V0_34 + CHAIN_COMMAND_PATHS: ${{ matrix.chain.command }},gaiad + ACCOUNT_PREFIXES: ${{ matrix.chain.account_prefix }},cosmos + NATIVE_TOKENS: ${{ matrix.chain.native_token }},stake + run: | + nix shell .#python .#gaia12 .#${{ matrix.chain.package }} -c \ + cargo nextest run -p ibc-integration-test --no-fail-fast --failure-output final --test-threads=2 \ + --features celestia + model-based-test: runs-on: ubuntu-20.04 timeout-minutes: 60 diff --git a/flake.lock b/flake.lock index 6c1750e11d..ccdad80ec7 100644 --- a/flake.lock +++ b/flake.lock @@ -51,20 +51,54 @@ "type": "github" } }, + "celestia-src": { + "flake": false, + "locked": { + "lastModified": 1697229641, + "narHash": "sha256-1HvYCZEcB7BCY5q9ykEZuCMzqcbA3JoDMwoHVJ0+SaY=", + "owner": "celestiaorg", + "repo": "celestia-app", + "rev": "2b8cc9e23826ccb658b7dd5aa6cd51a0921a0c29", + "type": "github" + }, + "original": { + "owner": "celestiaorg", + "ref": "v1.1.0", + "repo": "celestia-app", + "type": "github" + } + }, "centauri-src": { "flake": false, "locked": { - "lastModified": 1692209286, - "narHash": "sha256-fabsZyaSCnWnhvG9nO8y39t85u+MZNyEKzU+0fSueLM=", + "lastModified": 1697027127, + "narHash": "sha256-zdEJr4VfwKq20rGx7JZYV7cnz5APwnPSMJrjX9S/bT8=", "owner": "dzmitry-lahoda-forks", "repo": "composable-centauri", - "rev": "9fa53d8b47d17219d1270146a146e4e386bc2a29", + "rev": "9a296e3dcca3ff390dd5622ab3cfbdfa0b68d2e9", "type": "github" }, "original": { "owner": "dzmitry-lahoda-forks", "repo": "composable-centauri", - "rev": "9fa53d8b47d17219d1270146a146e4e386bc2a29", + "rev": "9a296e3dcca3ff390dd5622ab3cfbdfa0b68d2e9", + "type": "github" + } + }, + "cometbft-src": { + "flake": false, + "locked": { + "lastModified": 1694550324, + "narHash": "sha256-G5gchJMn/BFzwYx8/ikPDL5fS/TuFIBF4DKJbkalp/M=", + "owner": "cometbft", + "repo": "cometbft", + "rev": "66a5a9da9f7a3306f382eb9142ccb9c9f7997d3f", + "type": "github" + }, + "original": { + "owner": "cometbft", + "ref": "v0.38.0", + "repo": "cometbft", "type": "github" } }, @@ -73,7 +107,9 @@ "akash-src": "akash-src", "apalache-src": "apalache-src", "beaker-src": "beaker-src", + "celestia-src": "celestia-src", "centauri-src": "centauri-src", + "cometbft-src": "cometbft-src", "cosmos-sdk-src": "cosmos-sdk-src", "cosmwasm-src": "cosmwasm-src", "crescent-src": "crescent-src", @@ -136,11 +172,11 @@ "wasmvm_1_beta7-src": "wasmvm_1_beta7-src" }, "locked": { - "lastModified": 1697035289, - "narHash": "sha256-2yPPi/n4IrKZ0Y0BwPSmHGP5UJoY5u5XY6BnKxsuGnc=", + "lastModified": 1697663750, + "narHash": "sha256-Fe0FGqhseN2LnlqXIVcjbqTrQWnhrcsyu2QKBZcxsZQ=", "owner": "informalsystems", "repo": "cosmos.nix", - "rev": "e26774d7889a508ad3ac021a886bc6b8cf11cf7e", + "rev": "999d7978f52046107fcf50c57294ccd7444ae027", "type": "github" }, "original": { @@ -238,11 +274,11 @@ "systems": "systems" }, "locked": { - "lastModified": 1692792214, - "narHash": "sha256-voZDQOvqHsaReipVd3zTKSBwN7LZcUwi3/ThMxRZToU=", + "lastModified": 1694529238, + "narHash": "sha256-zsNZZGTGnMOf9YpHKJqMSsa0dXbfmxeoJ7xHlrt+xmY=", "owner": "numtide", "repo": "flake-utils", - "rev": "1721b3e7c882f75f2301b00d48a2884af8c448ae", + "rev": "ff7b65b44d01cf9ba6a71320833626af21126384", "type": "github" }, "original": { @@ -305,11 +341,11 @@ "gaia-main-src": { "flake": false, "locked": { - "lastModified": 1692777545, - "narHash": "sha256-Gg6pqITR+aqq4FBE0h/HvXpG+whtli2gJXw+dsyoKEE=", + "lastModified": 1697456548, + "narHash": "sha256-iXcwU0/kDAGzQKYrHKTMX6/ayB6Ns0KBYMOpi5uNYJk=", "owner": "cosmos", "repo": "gaia", - "rev": "97d0a1359716c5c534053a6a15a007b740d34780", + "rev": "e6da2cc3d1602a6c64fc50c90ea60651177d911b", "type": "github" }, "original": { @@ -683,11 +719,11 @@ "ica-src": { "flake": false, "locked": { - "lastModified": 1679480012, - "narHash": "sha256-LFyInZT7z/8/d3RYepYf95ryxA7Pbg3TMQhHrHUvlCA=", + "lastModified": 1695202199, + "narHash": "sha256-8RwZSnqqZzVjQsSMTckNhmTy3VYyubVmgE/hU6ntq9M=", "owner": "cosmos", "repo": "interchain-accounts-demo", - "rev": "fe07f304731161055cecec120e0d2de01e84bad4", + "rev": "9d9ec3f4f7e37e9d2a1c7f4a199e7d18c17e14db", "type": "github" }, "original": { @@ -832,11 +868,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1692684269, - "narHash": "sha256-zJk2pyF4Cuhtor0khtPlf+hfJIh22rzAUC+KU3Ob31Q=", + "lastModified": 1697379843, + "narHash": "sha256-RcnGuJgC2K/UpTy+d32piEoBXq2M+nVFzM3ah/ZdJzg=", "owner": "nixos", "repo": "nixpkgs", - "rev": "9d757ec498666cc1dcc6f2be26db4fd3e1e9ab37", + "rev": "12bdeb01ff9e2d3917e6a44037ed7df6e6c3df9d", "type": "github" }, "original": { @@ -896,11 +932,11 @@ }, "nixpkgs_4": { "locked": { - "lastModified": 1696757521, - "narHash": "sha256-cfgtLNCBLFx2qOzRLI6DHfqTdfWI+UbvsKYa3b3fvaA=", + "lastModified": 1697379843, + "narHash": "sha256-RcnGuJgC2K/UpTy+d32piEoBXq2M+nVFzM3ah/ZdJzg=", "owner": "nixos", "repo": "nixpkgs", - "rev": "2646b294a146df2781b1ca49092450e8a32814e1", + "rev": "12bdeb01ff9e2d3917e6a44037ed7df6e6c3df9d", "type": "github" }, "original": { @@ -913,16 +949,16 @@ "osmosis-src": { "flake": false, "locked": { - "lastModified": 1692886846, - "narHash": "sha256-VdM6hGqcDyCNx7AR8s7SxE3pEMxHiIhCJ7592sDp3uc=", + "lastModified": 1695859760, + "narHash": "sha256-Ad2Z4rzD0HQtnj2aQ4GD6ic5sxOHVPsaW4iNKZEDTiw=", "owner": "osmosis-labs", "repo": "osmosis", - "rev": "1c5f25d04f19d6302e0bdd585ba1d7a2cc96e397", + "rev": "38d1d2b748d161fd23f966d88b23b66a63c9a284", "type": "github" }, "original": { "owner": "osmosis-labs", - "ref": "v18.0.0", + "ref": "v19.2.0", "repo": "osmosis", "type": "github" } @@ -942,11 +978,11 @@ "nixpkgs-stable": "nixpkgs-stable" }, "locked": { - "lastModified": 1692274144, - "narHash": "sha256-BxTQuRUANQ81u8DJznQyPmRsg63t4Yc+0kcyq6OLz8s=", + "lastModified": 1696846637, + "narHash": "sha256-0hv4kbXxci2+pxhuXlVgftj/Jq79VSmtAyvfabCCtYk=", "owner": "cachix", "repo": "pre-commit-hooks.nix", - "rev": "7e3517c03d46159fdbf8c0e5c97f82d5d4b0c8fa", + "rev": "42e1b6095ef80a51f79595d9951eb38e91c4e6ca", "type": "github" }, "original": { diff --git a/flake.nix b/flake.nix index 7cadfe5970..01750a70b1 100644 --- a/flake.nix +++ b/flake.nix @@ -46,6 +46,7 @@ stride-consumer migaloo neutron + celestia ; python = nixpkgs.python3.withPackages (p: [ From 5e9d37dc0ad5b54ba80243b2afc05aa6c26c7ce5 Mon Sep 17 00:00:00 2001 From: Luca Joss Date: Thu, 19 Oct 2023 10:21:08 +0200 Subject: [PATCH 3/7] Add changelog entry --- .../features/ibc-relayer/3623-compat-mode-configurability.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .changelog/unreleased/features/ibc-relayer/3623-compat-mode-configurability.md diff --git a/.changelog/unreleased/features/ibc-relayer/3623-compat-mode-configurability.md b/.changelog/unreleased/features/ibc-relayer/3623-compat-mode-configurability.md new file mode 100644 index 0000000000..a4fa83a82e --- /dev/null +++ b/.changelog/unreleased/features/ibc-relayer/3623-compat-mode-configurability.md @@ -0,0 +1,3 @@ +- Add the optional configuration `compat_mode` which can be + used to specify which CometBFT compatibility mode is used. + ([\#3623](https://github.com/informalsystems/hermes/issues/3623)) \ No newline at end of file From 2116dc19bb8cac608a8f2588cc15530bac3007c9 Mon Sep 17 00:00:00 2001 From: Luca Joss Date: Thu, 19 Oct 2023 11:57:14 +0200 Subject: [PATCH 4/7] Add guide section for 'compat_mode' configuration --- config.toml | 9 +++++++ guide/src/SUMMARY.md | 1 + .../configuration/comet-compat-mode.md | 24 +++++++++++++++++++ .../src/documentation/configuration/index.md | 5 +++- 4 files changed, 38 insertions(+), 1 deletion(-) create mode 100644 guide/src/documentation/configuration/comet-compat-mode.md diff --git a/config.toml b/config.toml index d4a30dbcee..4a07081d4b 100644 --- a/config.toml +++ b/config.toml @@ -372,6 +372,15 @@ memo_prefix = '' # submitted to this chain. # fee_granter = '' +# Specify the CometBFT compatibility mode to use. +# The following behaviours are applied whether the `compat_mode` is configured or not: +# * compat_mode is specified and the version queried from /status is the same as the one configured: Use that version without log output +# * compat_mode is specified but the version queried from /status differs: The CompatMode configured is used, but a warning log is outputted +# * compat_mode is not specified but /status returns a correct version: The CompatMode retrieved from the endpoint is used +# * compat_mode is not specified and /status does not return a valid version: Hermes stops and outputs an error informing the user a compat_mode needs to be configured +# Possible values: [`V0_34`, `V0_37`] +# compat_mode = 'V0_34' + [[chains]] id = 'ibc-1' rpc_addr = 'http://127.0.0.1:26557' diff --git a/guide/src/SUMMARY.md b/guide/src/SUMMARY.md index 3264a2214f..d27e8a4fae 100644 --- a/guide/src/SUMMARY.md +++ b/guide/src/SUMMARY.md @@ -32,6 +32,7 @@ - [Description of the parameters](./documentation/configuration/description.md) - [Filter incentivized packets](./documentation/configuration/filter-incentivized.md) - [Performance tuning](./documentation/configuration/performance.md) + - [CometBFT Compatibility modes](./documentation/configuration/comet-compat-mode.md) - [Telemetry](./documentation/telemetry/index.md) - [Operators guide](./documentation/telemetry/operators.md) diff --git a/guide/src/documentation/configuration/comet-compat-mode.md b/guide/src/documentation/configuration/comet-compat-mode.md new file mode 100644 index 0000000000..666593ec98 --- /dev/null +++ b/guide/src/documentation/configuration/comet-compat-mode.md @@ -0,0 +1,24 @@ +# CometBFT Compatibility modes + +## Overview + +There are two different compatibility modes for CometBFT, one for version v0.34 and one for versions v0.37 and v0.38. In order to verify the compatiblity used Hermes queries the node's `/status` endpoint, which contains the CometBFT version used. This can be an issue if a chain uses a custom version which does not output the version string Hermes expects. To still be able to relay for these chains a configuration can be set in Hermes. + +## Configuration + +The configuration is set per chain and can take two values `V0_34` and `V0_37`, other values will be invalid: + +```toml +[[chains]] +... +compat_mode = 'V0_34' +``` + +Hermes will act in the following way whether or not the configuration is set: + +* `compat_mode` is specified and the version queried from `/status` is the same as the one configured: Use that version without log output +* `compat_mode` is specified but the version queried from `/status` differs: The compatibility mode configured is used, but a warning log is outputted +* `compat_mode` is not specified but /status returns a correct version: The compatibility mode retrieved from the endpoint is used +* `compat_mode` is not specified and /status does not return a valid version: Hermes stops and outputs an error informing the user that the `compat_mode` needs to be configured + +The configuration can also be found in the example [config.toml](https://github.com/informalsystems/hermes/blob/{{#include ../../templates/hermes-version.md}}/config.toml#382) \ No newline at end of file diff --git a/guide/src/documentation/configuration/index.md b/guide/src/documentation/configuration/index.md index e8f8e04e40..7b43841ce1 100644 --- a/guide/src/documentation/configuration/index.md +++ b/guide/src/documentation/configuration/index.md @@ -16,4 +16,7 @@ This section includes everything you need to know to configure Hermes. * Examples on how to configure Hermes in order to filter incentivized packets - **[Performance Tuning](./performance.md)** - * Learn about configurations allowing more refined performance tuning. \ No newline at end of file + * Learn about configurations allowing more refined performance tuning. + +- **[CometBFT Compatibility modes](./comet-compat-mode.md)** + * Handle different CometBFT compatibility modes. \ No newline at end of file From 1cea24050e5f057daa877e4471a9ea95a545ad98 Mon Sep 17 00:00:00 2001 From: Luca Joss <43531661+ljoss17@users.noreply.github.com> Date: Thu, 19 Oct 2023 13:43:18 +0200 Subject: [PATCH 5/7] Apply suggestions from code review Co-authored-by: Romain Ruetschi Signed-off-by: Luca Joss <43531661+ljoss17@users.noreply.github.com> --- .../features/ibc-relayer/3623-compat-mode-configurability.md | 4 ++-- crates/relayer/src/config.rs | 4 ++++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/.changelog/unreleased/features/ibc-relayer/3623-compat-mode-configurability.md b/.changelog/unreleased/features/ibc-relayer/3623-compat-mode-configurability.md index a4fa83a82e..ca2601a602 100644 --- a/.changelog/unreleased/features/ibc-relayer/3623-compat-mode-configurability.md +++ b/.changelog/unreleased/features/ibc-relayer/3623-compat-mode-configurability.md @@ -1,3 +1,3 @@ -- Add the optional configuration `compat_mode` which can be - used to specify which CometBFT compatibility mode is used. +- Add an optional per-chain setting `compat_mode`, which can be + used to specify which CometBFT compatibility mode is used for interacting with the node over RPC. ([\#3623](https://github.com/informalsystems/hermes/issues/3623)) \ No newline at end of file diff --git a/crates/relayer/src/config.rs b/crates/relayer/src/config.rs index 7abaeb6e58..e964d27c9f 100644 --- a/crates/relayer/src/config.rs +++ b/crates/relayer/src/config.rs @@ -148,6 +148,10 @@ impl Display for ExtensionOption { } } +/// CometBFT RPC compatibility mode +/// +/// Can be removed in favor of the one in tendermint-rs, once +/// is merged. #[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] pub enum CompatMode { /// Use version 0.34 of the protocol. From c31cdae15e2e6028f75d67f11a92371d5f3347e4 Mon Sep 17 00:00:00 2001 From: Luca Joss Date: Thu, 19 Oct 2023 14:04:26 +0200 Subject: [PATCH 6/7] Implement serialization and deserialization for CompatMode --- .github/workflows/integration.yaml | 2 +- config.toml | 4 +- crates/relayer/src/config.rs | 38 ++++++++++++++++--- crates/relayer/src/config/error.rs | 4 +- .../configuration/comet-compat-mode.md | 4 +- 5 files changed, 40 insertions(+), 12 deletions(-) diff --git a/.github/workflows/integration.yaml b/.github/workflows/integration.yaml index 07cd72a4e7..598b3937ec 100644 --- a/.github/workflows/integration.yaml +++ b/.github/workflows/integration.yaml @@ -583,7 +583,7 @@ jobs: RUST_LOG: info RUST_BACKTRACE: 1 NO_COLOR_LOG: 1 - COMPAT_MODES: V0_34 + 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 diff --git a/config.toml b/config.toml index 4a07081d4b..0028418559 100644 --- a/config.toml +++ b/config.toml @@ -378,8 +378,8 @@ memo_prefix = '' # * compat_mode is specified but the version queried from /status differs: The CompatMode configured is used, but a warning log is outputted # * compat_mode is not specified but /status returns a correct version: The CompatMode retrieved from the endpoint is used # * compat_mode is not specified and /status does not return a valid version: Hermes stops and outputs an error informing the user a compat_mode needs to be configured -# Possible values: [`V0_34`, `V0_37`] -# compat_mode = 'V0_34' +# Possible values: [`0.34`, `0.37`] +# compat_mode = '0.34' [[chains]] id = 'ibc-1' diff --git a/crates/relayer/src/config.rs b/crates/relayer/src/config.rs index e964d27c9f..fd763ed72e 100644 --- a/crates/relayer/src/config.rs +++ b/crates/relayer/src/config.rs @@ -14,6 +14,7 @@ use core::{ str::FromStr, time::Duration, }; +use serde::{Deserialize as IDeserialize, Deserializer, Serialize as ISerialize, Serializer}; use serde_derive::{Deserialize, Serialize}; use std::{ fs, @@ -152,7 +153,7 @@ impl Display for ExtensionOption { /// /// Can be removed in favor of the one in tendermint-rs, once /// is merged. -#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] +#[derive(Clone, Debug, Eq, PartialEq)] pub enum CompatMode { /// Use version 0.34 of the protocol. V0_34, @@ -173,14 +174,41 @@ impl FromStr for CompatMode { type Err = Error; fn from_str(s: &str) -> Result { - match s { - "V0_34" => Ok(Self::V0_34), - "V0_37" => Ok(Self::V0_37), - _ => Err(Error::invalid_compat_mode(s.to_owned())), + const VALID_COMPAT_MODES: &str = "0.34, 0.37"; + + // Trim leading 'v', if present + match s.trim_start_matches('v') { + "0.34" => Ok(CompatMode::V0_34), + "0.37" => Ok(CompatMode::V0_37), + _ => Err(Error::invalid_compat_mode( + s.to_string(), + VALID_COMPAT_MODES, + )), } } } +impl<'de> IDeserialize<'de> for CompatMode { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + use serde::de; + + let s = String::deserialize(deserializer)?; + FromStr::from_str(&s).map_err(de::Error::custom) + } +} + +impl ISerialize for CompatMode { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + self.to_string().serialize(serializer) + } +} + impl From for CompatMode { fn from(value: TmCompatMode) -> Self { match value { diff --git a/crates/relayer/src/config/error.rs b/crates/relayer/src/config/error.rs index 1aac124d26..3d131e795d 100644 --- a/crates/relayer/src/config/error.rs +++ b/crates/relayer/src/config/error.rs @@ -11,8 +11,8 @@ define_error! { |_| { "invalid configuration" }, InvalidCompatMode - { compat_mode: String } - |e| { format!("invalid compat mode: {}", e.compat_mode) }, + { compat_mode: String, valide_modes: &'static str } + |e| { format!("invalid compatibility mode: '{}' (supported: {})", e.compat_mode, e.valide_modes) }, Encode [ TraceError ] diff --git a/guide/src/documentation/configuration/comet-compat-mode.md b/guide/src/documentation/configuration/comet-compat-mode.md index 666593ec98..caf581102b 100644 --- a/guide/src/documentation/configuration/comet-compat-mode.md +++ b/guide/src/documentation/configuration/comet-compat-mode.md @@ -6,12 +6,12 @@ There are two different compatibility modes for CometBFT, one for version v0.34 ## Configuration -The configuration is set per chain and can take two values `V0_34` and `V0_37`, other values will be invalid: +The configuration is set per chain and can take two values `0.34` and `0.37`, other values will be invalid: ```toml [[chains]] ... -compat_mode = 'V0_34' +compat_mode = '0.34' ``` Hermes will act in the following way whether or not the configuration is set: From 576ea19210422f0fab4e5addae356ff99c1b19ee Mon Sep 17 00:00:00 2001 From: Luca Joss <43531661+ljoss17@users.noreply.github.com> Date: Thu, 2 Nov 2023 11:47:49 +0100 Subject: [PATCH 7/7] Update crates/relayer/src/util/compat_mode.rs Co-authored-by: Romain Ruetschi Signed-off-by: Luca Joss <43531661+ljoss17@users.noreply.github.com> --- crates/relayer/src/util/compat_mode.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/relayer/src/util/compat_mode.rs b/crates/relayer/src/util/compat_mode.rs index ba9516e643..fd4bc1ed1a 100644 --- a/crates/relayer/src/util/compat_mode.rs +++ b/crates/relayer/src/util/compat_mode.rs @@ -17,7 +17,7 @@ pub fn compat_mode_from_version( // This will prioritize the use of the CompatMode specified in Hermes configuration file match (configured_version, queried_version) { (Some(configured), Ok(queried)) if !configured.equal_to_tm_compat_mode(queried) => { - warn!("Be wary of potential CompatMode version misconfiguration. Configured version: {}, Version output from chain: {}. Hermes will use the configured CompatMode version `{}`. If this configuration is done on purpose this message can be ignored.", configured, queried, configured); + warn!("be wary of potential `compat_mode` misconfiguration. Configured version: {}, chain version: {}. Hermes will use the configured `compat_mode` version `{}`. If this configuration is done on purpose this message can be ignored.", configured, queried, configured); Ok(configured.clone()) } (Some(configured), _) => Ok(configured.clone()),