From 6b4ba992779ae205b00e9d149aec9641661533a2 Mon Sep 17 00:00:00 2001 From: Luca Joss Date: Mon, 9 Dec 2024 16:27:14 +0100 Subject: [PATCH 1/8] Add packet clearing and no packet clearing tests --- .../tests/packet_clear.rs | 147 ++++++++++++++++++ 1 file changed, 147 insertions(+) create mode 100644 crates/cosmos/cosmos-integration-tests/tests/packet_clear.rs diff --git a/crates/cosmos/cosmos-integration-tests/tests/packet_clear.rs b/crates/cosmos/cosmos-integration-tests/tests/packet_clear.rs new file mode 100644 index 000000000..db937e789 --- /dev/null +++ b/crates/cosmos/cosmos-integration-tests/tests/packet_clear.rs @@ -0,0 +1,147 @@ +#![recursion_limit = "256"] + +use hermes_cosmos_integration_tests::contexts::binary_channel::setup::CosmosBinaryChannelSetup; +use hermes_cosmos_integration_tests::contexts::binary_channel::test_driver::CosmosBinaryChannelTestDriver; +use hermes_cosmos_integration_tests::contexts::bootstrap::CosmosBootstrap; +use hermes_cosmos_integration_tests::init::{ + build_tracing_subscriber, init_preset_bootstraps, init_test_runtime, +}; +use hermes_cosmos_relayer::contexts::chain::CosmosChain; +use hermes_cosmos_test_components::chain::types::amount::Amount; +use hermes_error::types::Error; +use hermes_relayer_components::relay::traits::packet_clearer::CanClearPackets; +use hermes_test_components::chain::traits::assert::eventual_amount::CanAssertEventualAmount; +use hermes_test_components::chain::traits::queries::balance::CanQueryBalance; +use hermes_test_components::chain::traits::transfer::amount::CanConvertIbcTransferredAmount; +use hermes_test_components::chain::traits::transfer::ibc_transfer::CanIbcTransferToken; +use hermes_test_components::chain::traits::types::memo::HasDefaultMemo; +use hermes_test_components::chain_driver::traits::fields::amount::CanGenerateRandomAmount; + +#[test] +fn clear_packet_test() -> Result<(), Error> { + let subscriber = build_tracing_subscriber(); + let _ = tracing::subscriber::set_default(subscriber); + + let runtime = init_test_runtime(); + + runtime.runtime.clone().block_on(async move { + let setup: CosmosBinaryChannelTestDriver = init_preset_bootstraps::< + CosmosBinaryChannelSetup, + >(&runtime) + .await?; + + let balance_a1 = setup + .chain_driver_a + .chain + .query_balance( + &setup.chain_driver_a.user_wallet_a.address, + &setup.chain_driver_a.genesis_config.transfer_denom, + ) + .await?; + + let a_to_b_amount = setup.chain_driver_a.random_amount(1000, &balance_a1).await; + + let balance_b1 = + >::ibc_transfer_amount_from( + &a_to_b_amount, + &setup.channel_id_b, + &setup.port_id_b, + )?; + + >::ibc_transfer_token( + &setup.chain_driver_a.chain, + &setup.channel_id_a, + &setup.port_id_a, + &setup.chain_driver_a.user_wallet_a, + &setup.chain_driver_b.user_wallet_b.address, + &a_to_b_amount, + &setup.chain_driver_a.chain.default_memo(), + ) + .await?; + + setup + .relay_driver + .birelay + .relay_a_to_b + .clear_packets( + &setup.channel_id_a, + &setup.port_id_a, + &setup.channel_id_b, + &setup.port_id_b, + ) + .await?; + + // Wait a bit before asserting packets are cleared + tokio::time::sleep(core::time::Duration::from_secs(5)).await; + + setup + .chain_driver_b + .chain + .assert_eventual_amount(&setup.chain_driver_b.user_wallet_b.address, &balance_b1) + .await?; + + >::Ok(()) + })?; + + Ok(()) +} + +#[test] +fn no_clear_packet_test() -> Result<(), Error> { + let subscriber = build_tracing_subscriber(); + let _ = tracing::subscriber::set_default(subscriber); + + let runtime = init_test_runtime(); + + runtime.runtime.clone().block_on(async move { + let setup: CosmosBinaryChannelTestDriver = init_preset_bootstraps::< + CosmosBinaryChannelSetup, + >(&runtime) + .await?; + + let balance_a1 = setup + .chain_driver_a + .chain + .query_balance( + &setup.chain_driver_a.user_wallet_a.address, + &setup.chain_driver_a.genesis_config.transfer_denom, + ) + .await?; + + let a_to_b_amount = setup.chain_driver_a.random_amount(1000, &balance_a1).await; + + let balance_b1 = + >::ibc_transfer_amount_from( + &Amount::new( + 0, + setup.chain_driver_a.genesis_config.transfer_denom.clone(), + ), + &setup.channel_id_b, + &setup.port_id_b, + )?; + + >::ibc_transfer_token( + &setup.chain_driver_a.chain, + &setup.channel_id_a, + &setup.port_id_a, + &setup.chain_driver_a.user_wallet_a, + &setup.chain_driver_b.user_wallet_b.address, + &a_to_b_amount, + &setup.chain_driver_a.chain.default_memo(), + ) + .await?; + + // Wait a bit before asserting packets are not cleared + tokio::time::sleep(core::time::Duration::from_secs(5)).await; + + setup + .chain_driver_b + .chain + .assert_eventual_amount(&setup.chain_driver_b.user_wallet_b.address, &balance_b1) + .await?; + + >::Ok(()) + })?; + + Ok(()) +} From 680c74c6fcbf953c1042e12371aa5711c91bc0a5 Mon Sep 17 00:00:00 2001 From: Luca Joss Date: Mon, 9 Dec 2024 16:27:33 +0100 Subject: [PATCH 2/8] Update tracing subscriber initialisation to avoid crashing in tests --- .../cosmos/cosmos-integration-tests/src/init.rs | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/crates/cosmos/cosmos-integration-tests/src/init.rs b/crates/cosmos/cosmos-integration-tests/src/init.rs index eae66ef5b..b721c64e4 100644 --- a/crates/cosmos/cosmos-integration-tests/src/init.rs +++ b/crates/cosmos/cosmos-integration-tests/src/init.rs @@ -12,8 +12,8 @@ use ibc::core::host::types::identifiers::PortId; use serde_json::Value as JsonValue; use tokio::runtime::Builder; use toml::Value as TomlValue; -use tracing::info; use tracing::level_filters::LevelFilter; +use tracing::{info, Subscriber}; use tracing_subscriber::prelude::__tracing_subscriber_SubscriberExt; use tracing_subscriber::util::SubscriberInitExt; use tracing_subscriber::{fmt, EnvFilter}; @@ -42,9 +42,7 @@ impl FromStr for TestPreset { } } -pub fn init_test_runtime() -> HermesRuntime { - let _ = stable_eyre::install(); - +pub fn build_tracing_subscriber() -> impl Subscriber + Send + Sync { let env_filter = EnvFilter::builder() .with_default_directive(LevelFilter::INFO.into()) .from_env_lossy(); @@ -52,7 +50,14 @@ pub fn init_test_runtime() -> HermesRuntime { tracing_subscriber::registry() .with(fmt::layer()) .with(env_filter) - .init(); +} + +pub fn init_test_runtime() -> HermesRuntime { + let _ = stable_eyre::install(); + + let subscriber = build_tracing_subscriber(); + // Avoid crashing if already initialised + let _ = subscriber.try_init(); let tokio_runtime = Arc::new(Builder::new_multi_thread().enable_all().build().unwrap()); From b0847d08bb072a35fe3a43175d441cefd750083f Mon Sep 17 00:00:00 2001 From: Luca Joss Date: Mon, 9 Dec 2024 17:11:59 +0100 Subject: [PATCH 3/8] Remove unnecessary generic Setup in init_preset_bootstraps --- crates/cosmos/cosmos-integration-tests/src/init.rs | 9 +++------ .../tests/cosmos_integration_tests.rs | 7 +------ .../cosmos-integration-tests/tests/packet_clear.rs | 12 ++---------- 3 files changed, 6 insertions(+), 22 deletions(-) diff --git a/crates/cosmos/cosmos-integration-tests/src/init.rs b/crates/cosmos/cosmos-integration-tests/src/init.rs index b721c64e4..0a7799eda 100644 --- a/crates/cosmos/cosmos-integration-tests/src/init.rs +++ b/crates/cosmos/cosmos-integration-tests/src/init.rs @@ -7,7 +7,7 @@ use hermes_cosmos_chain_components::types::config::gas::dynamic_gas_config::Dyna use hermes_cosmos_relayer::contexts::build::CosmosBuilder; use hermes_error::types::Error; use hermes_runtime::types::runtime::HermesRuntime; -use hermes_test_components::setup::traits::driver::{CanBuildTestDriver, HasTestDriverType}; +use hermes_test_components::setup::traits::driver::CanBuildTestDriver; use ibc::core::host::types::identifiers::PortId; use serde_json::Value as JsonValue; use tokio::runtime::Builder; @@ -231,12 +231,9 @@ async fn setup_osmosis_to_gaia( setup.build_driver().await } -pub async fn init_preset_bootstraps( +pub async fn init_preset_bootstraps( runtime: &HermesRuntime, -) -> Result -where - Setup: HasTestDriverType, -{ +) -> Result { let test_preset = env::var("TEST_PRESET") .unwrap_or_else(|_| "GaiaToGaia".to_string()) .parse::()?; diff --git a/crates/cosmos/cosmos-integration-tests/tests/cosmos_integration_tests.rs b/crates/cosmos/cosmos-integration-tests/tests/cosmos_integration_tests.rs index ba2526368..64d9a5957 100644 --- a/crates/cosmos/cosmos-integration-tests/tests/cosmos_integration_tests.rs +++ b/crates/cosmos/cosmos-integration-tests/tests/cosmos_integration_tests.rs @@ -1,8 +1,6 @@ #![recursion_limit = "256"] -use hermes_cosmos_integration_tests::contexts::binary_channel::setup::CosmosBinaryChannelSetup; use hermes_cosmos_integration_tests::contexts::binary_channel::test_driver::CosmosBinaryChannelTestDriver; -use hermes_cosmos_integration_tests::contexts::bootstrap::CosmosBootstrap; use hermes_cosmos_integration_tests::init::{init_preset_bootstraps, init_test_runtime}; use hermes_error::types::Error; use hermes_ibc_test_suite::tests::transfer::TestIbcTransfer; @@ -14,10 +12,7 @@ fn cosmos_integration_tests() -> Result<(), Error> { // TODO: Use a test suite entry point for running multiple tests runtime.runtime.clone().block_on(async move { - let setup: CosmosBinaryChannelTestDriver = init_preset_bootstraps::< - CosmosBinaryChannelSetup, - >(&runtime) - .await?; + let setup: CosmosBinaryChannelTestDriver = init_preset_bootstraps(&runtime).await?; TestIbcTransfer::run_test(&TestIbcTransfer, &setup).await?; >::Ok(()) diff --git a/crates/cosmos/cosmos-integration-tests/tests/packet_clear.rs b/crates/cosmos/cosmos-integration-tests/tests/packet_clear.rs index db937e789..049ed0639 100644 --- a/crates/cosmos/cosmos-integration-tests/tests/packet_clear.rs +++ b/crates/cosmos/cosmos-integration-tests/tests/packet_clear.rs @@ -1,8 +1,6 @@ #![recursion_limit = "256"] -use hermes_cosmos_integration_tests::contexts::binary_channel::setup::CosmosBinaryChannelSetup; use hermes_cosmos_integration_tests::contexts::binary_channel::test_driver::CosmosBinaryChannelTestDriver; -use hermes_cosmos_integration_tests::contexts::bootstrap::CosmosBootstrap; use hermes_cosmos_integration_tests::init::{ build_tracing_subscriber, init_preset_bootstraps, init_test_runtime, }; @@ -25,10 +23,7 @@ fn clear_packet_test() -> Result<(), Error> { let runtime = init_test_runtime(); runtime.runtime.clone().block_on(async move { - let setup: CosmosBinaryChannelTestDriver = init_preset_bootstraps::< - CosmosBinaryChannelSetup, - >(&runtime) - .await?; + let setup: CosmosBinaryChannelTestDriver = init_preset_bootstraps(&runtime).await?; let balance_a1 = setup .chain_driver_a @@ -94,10 +89,7 @@ fn no_clear_packet_test() -> Result<(), Error> { let runtime = init_test_runtime(); runtime.runtime.clone().block_on(async move { - let setup: CosmosBinaryChannelTestDriver = init_preset_bootstraps::< - CosmosBinaryChannelSetup, - >(&runtime) - .await?; + let setup: CosmosBinaryChannelTestDriver = init_preset_bootstraps(&runtime).await?; let balance_a1 = setup .chain_driver_a From 7fcc6bf51002767cdaa33468ccc6be61408b826a Mon Sep 17 00:00:00 2001 From: Luca Joss Date: Tue, 10 Dec 2024 13:39:10 +0100 Subject: [PATCH 4/8] Migrate packet timeout test --- .../tests/timeout_transfer.rs | 91 +++++++++++++++++++ 1 file changed, 91 insertions(+) create mode 100644 crates/cosmos/cosmos-integration-tests/tests/timeout_transfer.rs diff --git a/crates/cosmos/cosmos-integration-tests/tests/timeout_transfer.rs b/crates/cosmos/cosmos-integration-tests/tests/timeout_transfer.rs new file mode 100644 index 000000000..df362cbb2 --- /dev/null +++ b/crates/cosmos/cosmos-integration-tests/tests/timeout_transfer.rs @@ -0,0 +1,91 @@ +#![recursion_limit = "256"] + +use hermes_cosmos_integration_tests::contexts::binary_channel::test_driver::CosmosBinaryChannelTestDriver; +use hermes_cosmos_integration_tests::init::{ + build_tracing_subscriber, init_preset_bootstraps, init_test_runtime, +}; +use hermes_cosmos_relayer::contexts::chain::CosmosChain; +use hermes_cosmos_test_components::chain::types::amount::Amount; +use hermes_error::types::Error; +use hermes_relayer_components::relay::traits::packet_clearer::CanClearPackets; +use hermes_test_components::chain::traits::assert::eventual_amount::CanAssertEventualAmount; +use hermes_test_components::chain::traits::queries::balance::CanQueryBalance; +use hermes_test_components::chain::traits::transfer::ibc_transfer::CanIbcTransferToken; +use hermes_test_components::chain::traits::types::memo::HasDefaultMemo; +use hermes_test_components::chain_driver::traits::fields::amount::CanGenerateRandomAmount; + +#[test] +fn timeout_transfer_test() -> Result<(), Error> { + let subscriber = build_tracing_subscriber(); + let _ = tracing::subscriber::set_default(subscriber); + + let runtime = init_test_runtime(); + + runtime.runtime.clone().block_on(async move { + let setup: CosmosBinaryChannelTestDriver = init_preset_bootstraps(&runtime).await?; + + let balance_a = setup + .chain_driver_a + .chain + .query_balance( + &setup.chain_driver_a.user_wallet_a.address, + &setup.chain_driver_a.genesis_config.transfer_denom, + ) + .await?; + + let a_to_b_amount = setup.chain_driver_a.random_amount(1000, &balance_a).await; + + let balance_after_escrow = Amount::new( + balance_a.quantity - a_to_b_amount.quantity, + balance_a.denom.clone(), + ); + + >::ibc_transfer_token( + &setup.chain_driver_a.chain, + &setup.channel_id_a, + &setup.port_id_a, + &setup.chain_driver_a.user_wallet_a, + &setup.chain_driver_b.user_wallet_b.address, + &a_to_b_amount, + &setup.chain_driver_a.chain.default_memo(), + ) + .await?; + + // Assert tokens have been escrowed + setup + .chain_driver_a + .chain + .assert_eventual_amount( + &setup.chain_driver_a.user_wallet_a.address, + &balance_after_escrow, + ) + .await?; + + // Wait for timeout before asserting packets are cleared + // Timeout for tests is set it crates/cosmos/cosmos-test-components/src/chain/components.rs + tokio::time::sleep(core::time::Duration::from_secs(95)).await; + + setup + .relay_driver + .birelay + .relay_a_to_b + .clear_packets( + &setup.channel_id_a, + &setup.port_id_a, + &setup.channel_id_b, + &setup.port_id_b, + ) + .await?; + + // Assert tokens have been unescrowed after relaying timeout + setup + .chain_driver_a + .chain + .assert_eventual_amount(&setup.chain_driver_a.user_wallet_a.address, &balance_a) + .await?; + + >::Ok(()) + })?; + + Ok(()) +} From 15e57947d7d7bbdd1d56883ef2c94794a5924cf5 Mon Sep 17 00:00:00 2001 From: Luca Joss Date: Tue, 10 Dec 2024 15:03:44 +0100 Subject: [PATCH 5/8] Add packet filtering test --- .../types/messages/packet/packet_filter.rs | 20 +- .../cosmos-integration-tests/src/init.rs | 50 ++++- .../tests/bootstrap.rs | 2 + .../tests/cosmos_integration_tests.rs | 3 +- .../cosmos-integration-tests/tests/filter.rs | 195 ++++++++++++++++++ .../tests/packet_clear.rs | 6 +- .../tests/timeout_transfer.rs | 3 +- 7 files changed, 264 insertions(+), 15 deletions(-) create mode 100644 crates/cosmos/cosmos-integration-tests/tests/filter.rs diff --git a/crates/cosmos/cosmos-chain-components/src/types/messages/packet/packet_filter.rs b/crates/cosmos/cosmos-chain-components/src/types/messages/packet/packet_filter.rs index 2324d1150..01d505944 100644 --- a/crates/cosmos/cosmos-chain-components/src/types/messages/packet/packet_filter.rs +++ b/crates/cosmos/cosmos-chain-components/src/types/messages/packet/packet_filter.rs @@ -1,11 +1,23 @@ +use std::collections::HashMap; + use ibc::core::host::types::identifiers::{ChannelId, PortId}; #[derive(Clone, Default)] -pub struct PacketFilterConfig; +pub struct PacketFilterConfig { + pub filter_map: HashMap<(ChannelId, PortId), bool>, +} + +impl PacketFilterConfig { + pub fn new(filter_map: HashMap<(ChannelId, PortId), bool>) -> Self { + Self { filter_map } + } +} impl PacketFilterConfig { - /// TODO: Use proper packet filtering - pub fn is_allowed(&self, _port_id: &PortId, _channel_id: &ChannelId) -> bool { - true + pub fn is_allowed(&self, port_id: &PortId, channel_id: &ChannelId) -> bool { + *self + .filter_map + .get(&(channel_id.clone(), port_id.clone())) + .unwrap_or(&true) } } diff --git a/crates/cosmos/cosmos-integration-tests/src/init.rs b/crates/cosmos/cosmos-integration-tests/src/init.rs index 0a7799eda..2f4e4a4f7 100644 --- a/crates/cosmos/cosmos-integration-tests/src/init.rs +++ b/crates/cosmos/cosmos-integration-tests/src/init.rs @@ -4,6 +4,7 @@ use std::str::FromStr; use eyre::Report; use hermes_cosmos_chain_components::types::config::gas::dynamic_gas_config::DynamicGasConfig; +use hermes_cosmos_chain_components::types::messages::packet::packet_filter::PacketFilterConfig; use hermes_cosmos_relayer::contexts::build::CosmosBuilder; use hermes_error::types::Error; use hermes_runtime::types::runtime::HermesRuntime; @@ -75,10 +76,17 @@ pub fn build_osmosis_bootstrap( transfer_denom_prefix: String, genesis_modifier: impl Fn(&mut JsonValue) -> Result<(), Error> + Send + Sync + 'static, comet_config_modifier: impl Fn(&mut TomlValue) -> Result<(), Error> + Send + Sync + 'static, + packet_filter: PacketFilterConfig, ) -> LegacyCosmosBootstrap { let dynamic_gas_config = Some(DynamicGasConfig::new(1.1, 1.6, "osmosis", "stake")); - - let cosmos_builder = CosmosBuilder::new_with_default(runtime.clone()); + let cosmos_builder = CosmosBuilder::new( + Default::default(), + runtime.clone(), + Default::default(), + packet_filter, + Default::default(), + Default::default(), + ); LegacyCosmosBootstrap { fields: Arc::new(LegacyCosmosBootstrapFields { @@ -105,9 +113,17 @@ pub fn build_gaia_bootstrap( transfer_denom_prefix: String, genesis_modifier: impl Fn(&mut JsonValue) -> Result<(), Error> + Send + Sync + 'static, comet_config_modifier: impl Fn(&mut TomlValue) -> Result<(), Error> + Send + Sync + 'static, + packet_filter: PacketFilterConfig, ) -> CosmosBootstrap { let dynamic_gas_config = Some(DynamicGasConfig::default()); - let cosmos_builder = CosmosBuilder::new_with_default(runtime.clone()); + let cosmos_builder = CosmosBuilder::new( + Default::default(), + runtime.clone(), + Default::default(), + packet_filter, + Default::default(), + Default::default(), + ); CosmosBootstrap { fields: Arc::new(CosmosBootstrapFields { @@ -129,6 +145,7 @@ pub fn build_gaia_bootstrap( async fn setup_gaia_to_gaia( runtime: &HermesRuntime, builder: CosmosBuilder, + packet_filter: PacketFilterConfig, ) -> Result { let bootstrap_chain_0 = build_gaia_bootstrap( runtime.clone(), @@ -137,6 +154,7 @@ async fn setup_gaia_to_gaia( "coin".into(), |_| Ok(()), |_| Ok(()), + packet_filter.clone(), ); let bootstrap_chain_1 = build_gaia_bootstrap( @@ -146,6 +164,7 @@ async fn setup_gaia_to_gaia( "coin".into(), |_| Ok(()), |_| Ok(()), + packet_filter, ); let setup = CosmosBinaryChannelSetup { @@ -164,6 +183,7 @@ async fn setup_gaia_to_gaia( async fn setup_osmosis_to_osmosis( runtime: &HermesRuntime, builder: CosmosBuilder, + packet_filter: PacketFilterConfig, ) -> Result { let bootstrap_chain_0 = build_osmosis_bootstrap( runtime.clone(), @@ -172,6 +192,7 @@ async fn setup_osmosis_to_osmosis( "coin".into(), |_| Ok(()), |_| Ok(()), + packet_filter.clone(), ); let bootstrap_chain_1 = build_osmosis_bootstrap( @@ -181,6 +202,7 @@ async fn setup_osmosis_to_osmosis( "coin".into(), |_| Ok(()), |_| Ok(()), + packet_filter, ); let setup = CosmosBinaryChannelSetup { @@ -199,6 +221,7 @@ async fn setup_osmosis_to_osmosis( async fn setup_osmosis_to_gaia( runtime: &HermesRuntime, builder: CosmosBuilder, + packet_filter: PacketFilterConfig, ) -> Result { let bootstrap_chain_0 = build_osmosis_bootstrap( runtime.clone(), @@ -207,6 +230,7 @@ async fn setup_osmosis_to_gaia( "coin".into(), |_| Ok(()), |_| Ok(()), + packet_filter.clone(), ); let bootstrap_chain_1 = build_gaia_bootstrap( @@ -216,6 +240,7 @@ async fn setup_osmosis_to_gaia( "coin".into(), |_| Ok(()), |_| Ok(()), + packet_filter, ); let setup = CosmosBinaryChannelSetup { @@ -233,15 +258,26 @@ async fn setup_osmosis_to_gaia( pub async fn init_preset_bootstraps( runtime: &HermesRuntime, + packet_filter: PacketFilterConfig, ) -> Result { let test_preset = env::var("TEST_PRESET") .unwrap_or_else(|_| "GaiaToGaia".to_string()) .parse::()?; - let builder = CosmosBuilder::new_with_default(runtime.clone()); + + let builder = CosmosBuilder::new( + Default::default(), + runtime.clone(), + Default::default(), + packet_filter.clone(), + Default::default(), + Default::default(), + ); match test_preset { - TestPreset::GaiaToGaia => setup_gaia_to_gaia(runtime, builder).await, - TestPreset::OsmosisToOsmosis => setup_osmosis_to_osmosis(runtime, builder).await, - TestPreset::OsmosisToGaia => setup_osmosis_to_gaia(runtime, builder).await, + TestPreset::GaiaToGaia => setup_gaia_to_gaia(runtime, builder, packet_filter).await, + TestPreset::OsmosisToOsmosis => { + setup_osmosis_to_osmosis(runtime, builder, packet_filter).await + } + TestPreset::OsmosisToGaia => setup_osmosis_to_gaia(runtime, builder, packet_filter).await, } } diff --git a/crates/cosmos/cosmos-integration-tests/tests/bootstrap.rs b/crates/cosmos/cosmos-integration-tests/tests/bootstrap.rs index aff9ec0ed..8c3e6c237 100644 --- a/crates/cosmos/cosmos-integration-tests/tests/bootstrap.rs +++ b/crates/cosmos/cosmos-integration-tests/tests/bootstrap.rs @@ -17,6 +17,7 @@ fn test_cosmos_bootstrap() -> Result<(), Error> { "coin".into(), |_| Ok(()), |_| Ok(()), + Default::default(), )); let bootstrap_legacy = Arc::new(build_osmosis_bootstrap( @@ -26,6 +27,7 @@ fn test_cosmos_bootstrap() -> Result<(), Error> { "coin".into(), |_| Ok(()), |_| Ok(()), + Default::default(), )); runtime.runtime.clone().block_on(async move { diff --git a/crates/cosmos/cosmos-integration-tests/tests/cosmos_integration_tests.rs b/crates/cosmos/cosmos-integration-tests/tests/cosmos_integration_tests.rs index 64d9a5957..b7276257e 100644 --- a/crates/cosmos/cosmos-integration-tests/tests/cosmos_integration_tests.rs +++ b/crates/cosmos/cosmos-integration-tests/tests/cosmos_integration_tests.rs @@ -12,7 +12,8 @@ fn cosmos_integration_tests() -> Result<(), Error> { // TODO: Use a test suite entry point for running multiple tests runtime.runtime.clone().block_on(async move { - let setup: CosmosBinaryChannelTestDriver = init_preset_bootstraps(&runtime).await?; + let setup: CosmosBinaryChannelTestDriver = + init_preset_bootstraps(&runtime, Default::default()).await?; TestIbcTransfer::run_test(&TestIbcTransfer, &setup).await?; >::Ok(()) diff --git a/crates/cosmos/cosmos-integration-tests/tests/filter.rs b/crates/cosmos/cosmos-integration-tests/tests/filter.rs new file mode 100644 index 000000000..d3e6b6391 --- /dev/null +++ b/crates/cosmos/cosmos-integration-tests/tests/filter.rs @@ -0,0 +1,195 @@ +#![recursion_limit = "256"] + +use std::collections::HashMap; + +use hermes_cosmos_chain_components::types::messages::packet::packet_filter::PacketFilterConfig; +use hermes_cosmos_integration_tests::contexts::binary_channel::test_driver::CosmosBinaryChannelTestDriver; +use hermes_cosmos_integration_tests::init::{ + build_tracing_subscriber, init_preset_bootstraps, init_test_runtime, +}; +use hermes_cosmos_relayer::contexts::chain::CosmosChain; +use hermes_cosmos_test_components::chain::types::amount::Amount; +use hermes_error::types::Error; +use hermes_relayer_components::chain::traits::queries::packet_commitments::CanQueryPacketCommitments; +use hermes_relayer_components::chain::traits::queries::unreceived_packet_sequences::CanQueryUnreceivedPacketSequences; +use hermes_test_components::chain::traits::assert::eventual_amount::CanAssertEventualAmount; +use hermes_test_components::chain::traits::queries::balance::CanQueryBalance; +use hermes_test_components::chain::traits::transfer::amount::CanConvertIbcTransferredAmount; +use hermes_test_components::chain::traits::transfer::ibc_transfer::CanIbcTransferToken; +use hermes_test_components::chain::traits::types::memo::HasDefaultMemo; +use hermes_test_components::chain_driver::traits::fields::amount::CanGenerateRandomAmount; +use hermes_test_components::relay_driver::run::CanRunRelayerInBackground; +use ibc::core::host::types::identifiers::{ChannelId, PortId}; + +#[test] +fn packet_filter_test() -> Result<(), Error> { + let subscriber = build_tracing_subscriber(); + let _ = tracing::subscriber::set_default(subscriber); + + let runtime = init_test_runtime(); + + runtime.runtime.clone().block_on(async move { + let mut filter_map = HashMap::new(); + filter_map.insert((ChannelId::new(0), PortId::transfer()), false); + let packet_filter = PacketFilterConfig::new(filter_map); + let setup: CosmosBinaryChannelTestDriver = + init_preset_bootstraps(&runtime, packet_filter).await?; + + let balance_a = setup + .chain_driver_a + .chain + .query_balance( + &setup.chain_driver_a.user_wallet_a.address, + &setup.chain_driver_a.genesis_config.transfer_denom, + ) + .await?; + + let a_to_b_amount = setup.chain_driver_a.random_amount(1000, &balance_a).await; + + let balance_after_escrow = Amount::new( + balance_a.quantity - a_to_b_amount.quantity, + balance_a.denom.clone(), + ); + + setup.relay_driver.run_relayer_in_background().await?; + + >::ibc_transfer_token( + &setup.chain_driver_a.chain, + &setup.channel_id_a, + &setup.port_id_a, + &setup.chain_driver_a.user_wallet_a, + &setup.chain_driver_b.user_wallet_b.address, + &a_to_b_amount, + &setup.chain_driver_a.chain.default_memo(), + ) + .await?; + + // Assert tokens have been escrowed + setup + .chain_driver_a + .chain + .assert_eventual_amount( + &setup.chain_driver_a.user_wallet_a.address, + &balance_after_escrow, + ) + .await?; + + // Wait for a bit + tokio::time::sleep(core::time::Duration::from_secs(5)).await; + + let (commitment_sequences, _) = + >::query_packet_commitments( + &setup.chain_driver_a.chain, + &setup.channel_id_a, + &setup.port_id_a, + ) + .await?; + + let unreceived_sequences = >::query_unreceived_packet_sequences( + &setup.chain_driver_b.chain, + &setup.channel_id_b, + &setup.port_id_b, + &commitment_sequences, + ) + .await?; + + // Assert packets have not been relayed + assert!(!unreceived_sequences.is_empty()); + + >::Ok(()) + })?; + + Ok(()) +} + +#[test] +fn no_packet_filter_test() -> Result<(), Error> { + let subscriber = build_tracing_subscriber(); + let _ = tracing::subscriber::set_default(subscriber); + + let runtime = init_test_runtime(); + + runtime.runtime.clone().block_on(async move { + let setup: CosmosBinaryChannelTestDriver = + init_preset_bootstraps(&runtime, Default::default()).await?; + + setup.relay_driver.run_relayer_in_background().await?; + + let balance_a = setup + .chain_driver_a + .chain + .query_balance( + &setup.chain_driver_a.user_wallet_a.address, + &setup.chain_driver_a.genesis_config.transfer_denom, + ) + .await?; + + let a_to_b_amount = setup.chain_driver_a.random_amount(1000, &balance_a).await; + + let balance_b = + >::ibc_transfer_amount_from( + &a_to_b_amount, + &setup.channel_id_b, + &setup.port_id_b, + )?; + + let balance_after_escrow = Amount::new( + balance_a.quantity - a_to_b_amount.quantity, + balance_a.denom.clone(), + ); + + >::ibc_transfer_token( + &setup.chain_driver_a.chain, + &setup.channel_id_a, + &setup.port_id_a, + &setup.chain_driver_a.user_wallet_a, + &setup.chain_driver_b.user_wallet_b.address, + &a_to_b_amount, + &setup.chain_driver_a.chain.default_memo(), + ) + .await?; + + // Assert tokens have been escrowed + setup + .chain_driver_a + .chain + .assert_eventual_amount( + &setup.chain_driver_a.user_wallet_a.address, + &balance_after_escrow, + ) + .await?; + + setup + .chain_driver_b + .chain + .assert_eventual_amount(&setup.chain_driver_b.user_wallet_b.address, &balance_b) + .await?; + + let (commitment_sequences, _) = + >::query_packet_commitments( + &setup.chain_driver_a.chain, + &setup.channel_id_a, + &setup.port_id_a, + ) + .await?; + + let unreceived_sequences = >::query_unreceived_packet_sequences( + &setup.chain_driver_b.chain, + &setup.channel_id_b, + &setup.port_id_b, + &commitment_sequences, + ) + .await?; + + // Assert there are no pending packets and tokens have been transferred + assert!(unreceived_sequences.is_empty()); + + >::Ok(()) + })?; + + Ok(()) +} diff --git a/crates/cosmos/cosmos-integration-tests/tests/packet_clear.rs b/crates/cosmos/cosmos-integration-tests/tests/packet_clear.rs index 049ed0639..d5f6af384 100644 --- a/crates/cosmos/cosmos-integration-tests/tests/packet_clear.rs +++ b/crates/cosmos/cosmos-integration-tests/tests/packet_clear.rs @@ -23,7 +23,8 @@ fn clear_packet_test() -> Result<(), Error> { let runtime = init_test_runtime(); runtime.runtime.clone().block_on(async move { - let setup: CosmosBinaryChannelTestDriver = init_preset_bootstraps(&runtime).await?; + let setup: CosmosBinaryChannelTestDriver = + init_preset_bootstraps(&runtime, Default::default()).await?; let balance_a1 = setup .chain_driver_a @@ -89,7 +90,8 @@ fn no_clear_packet_test() -> Result<(), Error> { let runtime = init_test_runtime(); runtime.runtime.clone().block_on(async move { - let setup: CosmosBinaryChannelTestDriver = init_preset_bootstraps(&runtime).await?; + let setup: CosmosBinaryChannelTestDriver = + init_preset_bootstraps(&runtime, Default::default()).await?; let balance_a1 = setup .chain_driver_a diff --git a/crates/cosmos/cosmos-integration-tests/tests/timeout_transfer.rs b/crates/cosmos/cosmos-integration-tests/tests/timeout_transfer.rs index df362cbb2..a46f41d99 100644 --- a/crates/cosmos/cosmos-integration-tests/tests/timeout_transfer.rs +++ b/crates/cosmos/cosmos-integration-tests/tests/timeout_transfer.rs @@ -22,7 +22,8 @@ fn timeout_transfer_test() -> Result<(), Error> { let runtime = init_test_runtime(); runtime.runtime.clone().block_on(async move { - let setup: CosmosBinaryChannelTestDriver = init_preset_bootstraps(&runtime).await?; + let setup: CosmosBinaryChannelTestDriver = + init_preset_bootstraps(&runtime, Default::default()).await?; let balance_a = setup .chain_driver_a From f1e2bb088ffec803c5d22ee064577d84bd6a8c46 Mon Sep 17 00:00:00 2001 From: Luca Joss Date: Wed, 11 Dec 2024 09:06:02 +0100 Subject: [PATCH 6/8] Add test for acknowledgment relaying and fix acknowledgment relaying for cosmos chains --- .../src/impls/events.rs | 2 +- .../tests/packet_ack.rs | 133 ++++++++++++++++++ 2 files changed, 134 insertions(+), 1 deletion(-) create mode 100644 crates/cosmos/cosmos-integration-tests/tests/packet_ack.rs diff --git a/crates/cosmos/cosmos-chain-components/src/impls/events.rs b/crates/cosmos/cosmos-chain-components/src/impls/events.rs index cab719019..71c766bc3 100644 --- a/crates/cosmos/cosmos-chain-components/src/impls/events.rs +++ b/crates/cosmos/cosmos-chain-components/src/impls/events.rs @@ -195,6 +195,6 @@ where } fn write_acknowledgement(event: &WriteAckEvent) -> &Vec { - &event.packet.data + &event.acknowledgment } } diff --git a/crates/cosmos/cosmos-integration-tests/tests/packet_ack.rs b/crates/cosmos/cosmos-integration-tests/tests/packet_ack.rs new file mode 100644 index 000000000..88f927a4f --- /dev/null +++ b/crates/cosmos/cosmos-integration-tests/tests/packet_ack.rs @@ -0,0 +1,133 @@ +#![recursion_limit = "256"] + +use hermes_cosmos_integration_tests::contexts::binary_channel::test_driver::CosmosBinaryChannelTestDriver; +use hermes_cosmos_integration_tests::init::{ + build_tracing_subscriber, init_preset_bootstraps, init_test_runtime, +}; +use hermes_cosmos_relayer::contexts::chain::CosmosChain; +use hermes_cosmos_test_components::chain::types::amount::Amount; +use hermes_error::types::Error; +use hermes_relayer_components::chain::traits::queries::packet_acknowledgements::CanQueryPacketAcknowledgements; +use hermes_relayer_components::chain::traits::queries::packet_commitments::CanQueryPacketCommitments; +use hermes_relayer_components::chain::traits::queries::unreceived_packet_sequences::CanQueryUnreceivedPacketSequences; +use hermes_test_components::chain::traits::assert::eventual_amount::CanAssertEventualAmount; +use hermes_test_components::chain::traits::queries::balance::CanQueryBalance; +use hermes_test_components::chain::traits::transfer::amount::CanConvertIbcTransferredAmount; +use hermes_test_components::chain::traits::transfer::ibc_transfer::CanIbcTransferToken; +use hermes_test_components::chain::traits::types::memo::HasDefaultMemo; +use hermes_test_components::chain_driver::traits::fields::amount::CanGenerateRandomAmount; +use hermes_test_components::relay_driver::run::CanRunRelayerInBackground; + +#[test] +fn packet_ack_test() -> Result<(), Error> { + let subscriber = build_tracing_subscriber(); + let _ = tracing::subscriber::set_default(subscriber); + + let runtime = init_test_runtime(); + + runtime.runtime.clone().block_on(async move { + let setup: CosmosBinaryChannelTestDriver = + init_preset_bootstraps(&runtime, Default::default()).await?; + + setup.relay_driver.run_relayer_in_background().await?; + + let balance_a = setup + .chain_driver_a + .chain + .query_balance( + &setup.chain_driver_a.user_wallet_a.address, + &setup.chain_driver_a.genesis_config.transfer_denom, + ) + .await?; + + let a_to_b_amount = setup.chain_driver_a.random_amount(1000, &balance_a).await; + + let balance_b = + >::ibc_transfer_amount_from( + &a_to_b_amount, + &setup.channel_id_b, + &setup.port_id_b, + )?; + + let balance_after_escrow = Amount::new( + balance_a.quantity - a_to_b_amount.quantity, + balance_a.denom.clone(), + ); + + >::ibc_transfer_token( + &setup.chain_driver_a.chain, + &setup.channel_id_a, + &setup.port_id_a, + &setup.chain_driver_a.user_wallet_a, + &setup.chain_driver_b.user_wallet_b.address, + &a_to_b_amount, + &setup.chain_driver_a.chain.default_memo(), + ) + .await?; + + // Assert tokens have been escrowed + setup + .chain_driver_a + .chain + .assert_eventual_amount( + &setup.chain_driver_a.user_wallet_a.address, + &balance_after_escrow, + ) + .await?; + + setup + .chain_driver_b + .chain + .assert_eventual_amount(&setup.chain_driver_b.user_wallet_b.address, &balance_b) + .await?; + + let (commitment_sequences, _) = + >::query_packet_commitments( + &setup.chain_driver_a.chain, + &setup.channel_id_a, + &setup.port_id_a, + ) + .await?; + + let unreceived_sequences = >::query_unreceived_packet_sequences( + &setup.chain_driver_b.chain, + &setup.channel_id_b, + &setup.port_id_b, + &commitment_sequences, + ) + .await?; + + // Assert there are no pending packets and tokens have been transferred + assert!(unreceived_sequences.is_empty()); + + // Wait for acknowledgments to be relayed + tokio::time::sleep(core::time::Duration::from_secs(15)).await; + + let (commitment_sequences, _) = + >::query_packet_commitments( + &setup.chain_driver_a.chain, + &setup.channel_id_a, + &setup.port_id_a, + ) + .await?; + + let acks_and_height_on_counterparty = >::query_packet_acknowlegements( + &setup.chain_driver_b.chain, + &setup.channel_id_b, + &setup.port_id_b, + &commitment_sequences, + ) + .await?; + + assert!(acks_and_height_on_counterparty.is_some()); + assert!(acks_and_height_on_counterparty.unwrap().0.is_empty()); + + >::Ok(()) + })?; + + Ok(()) +} From 80598989e09843571197f5325471806ef45e0905 Mon Sep 17 00:00:00 2001 From: Luca Joss Date: Wed, 11 Dec 2024 09:13:42 +0100 Subject: [PATCH 7/8] Cleanup comments --- crates/cosmos/cosmos-integration-tests/tests/filter.rs | 2 +- crates/cosmos/cosmos-integration-tests/tests/packet_ack.rs | 2 +- .../cosmos/cosmos-integration-tests/tests/timeout_transfer.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/crates/cosmos/cosmos-integration-tests/tests/filter.rs b/crates/cosmos/cosmos-integration-tests/tests/filter.rs index d3e6b6391..f55b3abf5 100644 --- a/crates/cosmos/cosmos-integration-tests/tests/filter.rs +++ b/crates/cosmos/cosmos-integration-tests/tests/filter.rs @@ -161,6 +161,7 @@ fn no_packet_filter_test() -> Result<(), Error> { ) .await?; + // Assert there are no pending packets and tokens have been transferred setup .chain_driver_b .chain @@ -185,7 +186,6 @@ fn no_packet_filter_test() -> Result<(), Error> { ) .await?; - // Assert there are no pending packets and tokens have been transferred assert!(unreceived_sequences.is_empty()); >::Ok(()) diff --git a/crates/cosmos/cosmos-integration-tests/tests/packet_ack.rs b/crates/cosmos/cosmos-integration-tests/tests/packet_ack.rs index 88f927a4f..a0d7ab994 100644 --- a/crates/cosmos/cosmos-integration-tests/tests/packet_ack.rs +++ b/crates/cosmos/cosmos-integration-tests/tests/packet_ack.rs @@ -75,6 +75,7 @@ fn packet_ack_test() -> Result<(), Error> { ) .await?; + // Assert there are no pending packets and tokens have been transferred setup .chain_driver_b .chain @@ -99,7 +100,6 @@ fn packet_ack_test() -> Result<(), Error> { ) .await?; - // Assert there are no pending packets and tokens have been transferred assert!(unreceived_sequences.is_empty()); // Wait for acknowledgments to be relayed diff --git a/crates/cosmos/cosmos-integration-tests/tests/timeout_transfer.rs b/crates/cosmos/cosmos-integration-tests/tests/timeout_transfer.rs index a46f41d99..51496311f 100644 --- a/crates/cosmos/cosmos-integration-tests/tests/timeout_transfer.rs +++ b/crates/cosmos/cosmos-integration-tests/tests/timeout_transfer.rs @@ -63,7 +63,7 @@ fn timeout_transfer_test() -> Result<(), Error> { .await?; // Wait for timeout before asserting packets are cleared - // Timeout for tests is set it crates/cosmos/cosmos-test-components/src/chain/components.rs + // Timeout for tests is set in crates/cosmos/cosmos-test-components/src/chain/components.rs tokio::time::sleep(core::time::Duration::from_secs(95)).await; setup From d6d302156afc2c02969e0530d57b813e4bf53a3b Mon Sep 17 00:00:00 2001 From: Luca Joss Date: Wed, 11 Dec 2024 09:59:07 +0100 Subject: [PATCH 8/8] Remove tools crate and anything related to legacy tests --- .../workflows/integration-tests-legacy.yaml | 62 --- Cargo.toml | 5 - tools/integration-test/Cargo.toml | 36 -- tools/integration-test/spec/.gitignore | 3 - tools/integration-test/spec/MC_Transfer.cfg | 2 - tools/integration-test/spec/MC_Transfer.tla | 49 -- tools/integration-test/spec/README.md | 23 - tools/integration-test/spec/Transfer.tla | 398 --------------- .../spec/Transfer_typedefs.tla | 45 -- tools/integration-test/src/lib.rs | 5 - .../integration-test/src/tests/connection.rs | 91 ---- tools/integration-test/src/tests/context.rs | 78 --- tools/integration-test/src/tests/filter.rs | 112 ----- tools/integration-test/src/tests/mod.rs | 9 - .../src/tests/packet_clear.rs | 458 ----------------- .../src/tests/solomachine/connection.rs | 110 ---- .../src/tests/solomachine/mod.rs | 1 - .../src/tests/timeout_transfer.rs | 102 ---- tools/integration-test/src/tests/transfer.rs | 145 ------ tools/test-framework/.gitignore | 1 - tools/test-framework/Cargo.toml | 49 -- tools/test-framework/README.md | 27 - .../src/bootstrap/binary/chain.rs | 311 ------------ .../src/bootstrap/binary/channel.rs | 233 --------- .../src/bootstrap/binary/connection.rs | 153 ------ .../src/bootstrap/binary/mod.rs | 7 - .../test-framework/src/bootstrap/consumer.rs | 137 ----- tools/test-framework/src/bootstrap/init.rs | 94 ---- tools/test-framework/src/bootstrap/mod.rs | 18 - .../src/bootstrap/nary/chain.rs | 120 ----- .../src/bootstrap/nary/channel.rs | 150 ------ .../src/bootstrap/nary/connection.rs | 76 --- .../test-framework/src/bootstrap/nary/mod.rs | 13 - tools/test-framework/src/bootstrap/single.rs | 168 ------- tools/test-framework/src/chain/builder.rs | 127 ----- tools/test-framework/src/chain/chain_type.rs | 76 --- .../test-framework/src/chain/cli/bootstrap.rs | 187 ------- .../test-framework/src/chain/cli/fee_grant.rs | 34 -- .../test-framework/src/chain/cli/host_zone.rs | 46 -- tools/test-framework/src/chain/cli/ica.rs | 103 ---- tools/test-framework/src/chain/cli/mod.rs | 9 - .../test-framework/src/chain/cli/provider.rs | 97 ---- tools/test-framework/src/chain/cli/query.rs | 122 ----- .../test-framework/src/chain/cli/transfer.rs | 84 ---- tools/test-framework/src/chain/cli/upgrade.rs | 40 -- tools/test-framework/src/chain/cli/version.rs | 17 - tools/test-framework/src/chain/config.rs | 309 ------------ tools/test-framework/src/chain/driver.rs | 227 --------- tools/test-framework/src/chain/exec.rs | 52 -- .../test-framework/src/chain/ext/bootstrap.rs | 338 ------------- .../src/chain/ext/crosschainquery.rs | 95 ---- tools/test-framework/src/chain/ext/fee.rs | 185 ------- .../test-framework/src/chain/ext/fee_grant.rs | 20 - tools/test-framework/src/chain/ext/forward.rs | 28 -- tools/test-framework/src/chain/ext/ica.rs | 110 ---- tools/test-framework/src/chain/ext/mod.rs | 10 - .../test-framework/src/chain/ext/proposal.rs | 96 ---- .../test-framework/src/chain/ext/transfer.rs | 200 -------- tools/test-framework/src/chain/ext/version.rs | 14 - .../src/chain/ext/wait_chain.rs | 43 -- tools/test-framework/src/chain/mod.rs | 25 - tools/test-framework/src/chain/tagged.rs | 157 ------ tools/test-framework/src/chain/version.rs | 29 -- tools/test-framework/src/docs/mod.rs | 3 - .../src/docs/walkthroughs/memo.rs | 130 ----- .../src/docs/walkthroughs/mod.rs | 8 - .../src/docs/walkthroughs/ordered_channel.rs | 152 ------ .../src/docs/walkthroughs/simple.rs | 66 --- tools/test-framework/src/error.rs | 156 ------ tools/test-framework/src/framework/base.rs | 109 ---- .../src/framework/binary/chain.rs | 350 ------------- .../src/framework/binary/channel.rs | 348 ------------- .../src/framework/binary/connection.rs | 256 ---------- .../src/framework/binary/ics.rs | 117 ----- .../src/framework/binary/mod.rs | 10 - .../src/framework/binary/next.rs | 407 --------------- .../src/framework/binary/node.rs | 183 ------- tools/test-framework/src/framework/mod.rs | 40 -- .../src/framework/nary/chain.rs | 247 --------- .../src/framework/nary/channel.rs | 262 ---------- .../src/framework/nary/connection.rs | 188 ------- .../test-framework/src/framework/nary/mod.rs | 8 - .../test-framework/src/framework/nary/node.rs | 86 ---- .../src/framework/next/chain.rs | 56 --- .../src/framework/next/context.rs | 32 -- .../test-framework/src/framework/next/mod.rs | 2 - .../test-framework/src/framework/overrides.rs | 233 --------- .../src/framework/supervisor.rs | 58 --- tools/test-framework/src/ibc/denom.rs | 160 ------ tools/test-framework/src/ibc/mod.rs | 7 - tools/test-framework/src/ibc/token.rs | 118 ----- tools/test-framework/src/lib.rs | 83 ---- tools/test-framework/src/prelude.rs | 77 --- tools/test-framework/src/relayer/chain.rs | 462 ----------------- tools/test-framework/src/relayer/channel.rs | 209 -------- .../test-framework/src/relayer/connection.rs | 196 -------- tools/test-framework/src/relayer/driver.rs | 90 ---- tools/test-framework/src/relayer/fee.rs | 213 -------- .../src/relayer/foreign_client.rs | 47 -- tools/test-framework/src/relayer/mod.rs | 29 -- tools/test-framework/src/relayer/refresh.rs | 19 - tools/test-framework/src/relayer/transfer.rs | 157 ------ tools/test-framework/src/relayer/tx.rs | 66 --- .../test-framework/src/types/binary/chains.rs | 175 ------- .../src/types/binary/channel.rs | 98 ---- .../test-framework/src/types/binary/client.rs | 51 -- .../src/types/binary/connection.rs | 95 ---- .../src/types/binary/foreign_client.rs | 63 --- tools/test-framework/src/types/binary/mod.rs | 9 - tools/test-framework/src/types/config.rs | 61 --- tools/test-framework/src/types/env.rs | 119 ----- tools/test-framework/src/types/id.rs | 77 --- tools/test-framework/src/types/mod.rs | 19 - .../test-framework/src/types/nary/aliases.rs | 34 -- tools/test-framework/src/types/nary/chains.rs | 256 ---------- .../test-framework/src/types/nary/channel.rs | 159 ------ .../src/types/nary/connection.rs | 136 ----- .../src/types/nary/foreign_client.rs | 89 ---- tools/test-framework/src/types/nary/mod.rs | 66 --- tools/test-framework/src/types/process.rs | 53 -- tools/test-framework/src/types/single/mod.rs | 5 - tools/test-framework/src/types/single/node.rs | 205 -------- tools/test-framework/src/types/tagged/dual.rs | 470 ------------------ tools/test-framework/src/types/tagged/mod.rs | 130 ----- tools/test-framework/src/types/tagged/mono.rs | 411 --------------- tools/test-framework/src/types/wallet.rs | 218 -------- tools/test-framework/src/util/array.rs | 88 ---- tools/test-framework/src/util/assert.rs | 43 -- tools/test-framework/src/util/file.rs | 30 -- .../src/util/interchain_security.rs | 31 -- tools/test-framework/src/util/mod.rs | 11 - tools/test-framework/src/util/random.rs | 69 --- tools/test-framework/src/util/retry.rs | 39 -- tools/test-framework/src/util/suspend.rs | 69 --- 134 files changed, 14990 deletions(-) delete mode 100644 .github/workflows/integration-tests-legacy.yaml delete mode 100644 tools/integration-test/Cargo.toml delete mode 100644 tools/integration-test/spec/.gitignore delete mode 100644 tools/integration-test/spec/MC_Transfer.cfg delete mode 100644 tools/integration-test/spec/MC_Transfer.tla delete mode 100644 tools/integration-test/spec/README.md delete mode 100644 tools/integration-test/spec/Transfer.tla delete mode 100644 tools/integration-test/spec/Transfer_typedefs.tla delete mode 100644 tools/integration-test/src/lib.rs delete mode 100644 tools/integration-test/src/tests/connection.rs delete mode 100644 tools/integration-test/src/tests/context.rs delete mode 100644 tools/integration-test/src/tests/filter.rs delete mode 100644 tools/integration-test/src/tests/mod.rs delete mode 100644 tools/integration-test/src/tests/packet_clear.rs delete mode 100644 tools/integration-test/src/tests/solomachine/connection.rs delete mode 100644 tools/integration-test/src/tests/solomachine/mod.rs delete mode 100644 tools/integration-test/src/tests/timeout_transfer.rs delete mode 100644 tools/integration-test/src/tests/transfer.rs delete mode 100644 tools/test-framework/.gitignore delete mode 100644 tools/test-framework/Cargo.toml delete mode 100644 tools/test-framework/README.md delete mode 100644 tools/test-framework/src/bootstrap/binary/chain.rs delete mode 100644 tools/test-framework/src/bootstrap/binary/channel.rs delete mode 100644 tools/test-framework/src/bootstrap/binary/connection.rs delete mode 100644 tools/test-framework/src/bootstrap/binary/mod.rs delete mode 100644 tools/test-framework/src/bootstrap/consumer.rs delete mode 100644 tools/test-framework/src/bootstrap/init.rs delete mode 100644 tools/test-framework/src/bootstrap/mod.rs delete mode 100644 tools/test-framework/src/bootstrap/nary/chain.rs delete mode 100644 tools/test-framework/src/bootstrap/nary/channel.rs delete mode 100644 tools/test-framework/src/bootstrap/nary/connection.rs delete mode 100644 tools/test-framework/src/bootstrap/nary/mod.rs delete mode 100644 tools/test-framework/src/bootstrap/single.rs delete mode 100644 tools/test-framework/src/chain/builder.rs delete mode 100644 tools/test-framework/src/chain/chain_type.rs delete mode 100644 tools/test-framework/src/chain/cli/bootstrap.rs delete mode 100644 tools/test-framework/src/chain/cli/fee_grant.rs delete mode 100644 tools/test-framework/src/chain/cli/host_zone.rs delete mode 100644 tools/test-framework/src/chain/cli/ica.rs delete mode 100644 tools/test-framework/src/chain/cli/mod.rs delete mode 100644 tools/test-framework/src/chain/cli/provider.rs delete mode 100644 tools/test-framework/src/chain/cli/query.rs delete mode 100644 tools/test-framework/src/chain/cli/transfer.rs delete mode 100644 tools/test-framework/src/chain/cli/upgrade.rs delete mode 100644 tools/test-framework/src/chain/cli/version.rs delete mode 100644 tools/test-framework/src/chain/config.rs delete mode 100644 tools/test-framework/src/chain/driver.rs delete mode 100644 tools/test-framework/src/chain/exec.rs delete mode 100644 tools/test-framework/src/chain/ext/bootstrap.rs delete mode 100644 tools/test-framework/src/chain/ext/crosschainquery.rs delete mode 100644 tools/test-framework/src/chain/ext/fee.rs delete mode 100644 tools/test-framework/src/chain/ext/fee_grant.rs delete mode 100644 tools/test-framework/src/chain/ext/forward.rs delete mode 100644 tools/test-framework/src/chain/ext/ica.rs delete mode 100644 tools/test-framework/src/chain/ext/mod.rs delete mode 100644 tools/test-framework/src/chain/ext/proposal.rs delete mode 100644 tools/test-framework/src/chain/ext/transfer.rs delete mode 100644 tools/test-framework/src/chain/ext/version.rs delete mode 100644 tools/test-framework/src/chain/ext/wait_chain.rs delete mode 100644 tools/test-framework/src/chain/mod.rs delete mode 100644 tools/test-framework/src/chain/tagged.rs delete mode 100644 tools/test-framework/src/chain/version.rs delete mode 100644 tools/test-framework/src/docs/mod.rs delete mode 100644 tools/test-framework/src/docs/walkthroughs/memo.rs delete mode 100644 tools/test-framework/src/docs/walkthroughs/mod.rs delete mode 100644 tools/test-framework/src/docs/walkthroughs/ordered_channel.rs delete mode 100644 tools/test-framework/src/docs/walkthroughs/simple.rs delete mode 100644 tools/test-framework/src/error.rs delete mode 100644 tools/test-framework/src/framework/base.rs delete mode 100644 tools/test-framework/src/framework/binary/chain.rs delete mode 100644 tools/test-framework/src/framework/binary/channel.rs delete mode 100644 tools/test-framework/src/framework/binary/connection.rs delete mode 100644 tools/test-framework/src/framework/binary/ics.rs delete mode 100644 tools/test-framework/src/framework/binary/mod.rs delete mode 100644 tools/test-framework/src/framework/binary/next.rs delete mode 100644 tools/test-framework/src/framework/binary/node.rs delete mode 100644 tools/test-framework/src/framework/mod.rs delete mode 100644 tools/test-framework/src/framework/nary/chain.rs delete mode 100644 tools/test-framework/src/framework/nary/channel.rs delete mode 100644 tools/test-framework/src/framework/nary/connection.rs delete mode 100644 tools/test-framework/src/framework/nary/mod.rs delete mode 100644 tools/test-framework/src/framework/nary/node.rs delete mode 100644 tools/test-framework/src/framework/next/chain.rs delete mode 100644 tools/test-framework/src/framework/next/context.rs delete mode 100644 tools/test-framework/src/framework/next/mod.rs delete mode 100644 tools/test-framework/src/framework/overrides.rs delete mode 100644 tools/test-framework/src/framework/supervisor.rs delete mode 100644 tools/test-framework/src/ibc/denom.rs delete mode 100644 tools/test-framework/src/ibc/mod.rs delete mode 100644 tools/test-framework/src/ibc/token.rs delete mode 100644 tools/test-framework/src/lib.rs delete mode 100644 tools/test-framework/src/prelude.rs delete mode 100644 tools/test-framework/src/relayer/chain.rs delete mode 100644 tools/test-framework/src/relayer/channel.rs delete mode 100644 tools/test-framework/src/relayer/connection.rs delete mode 100644 tools/test-framework/src/relayer/driver.rs delete mode 100644 tools/test-framework/src/relayer/fee.rs delete mode 100644 tools/test-framework/src/relayer/foreign_client.rs delete mode 100644 tools/test-framework/src/relayer/mod.rs delete mode 100644 tools/test-framework/src/relayer/refresh.rs delete mode 100644 tools/test-framework/src/relayer/transfer.rs delete mode 100644 tools/test-framework/src/relayer/tx.rs delete mode 100644 tools/test-framework/src/types/binary/chains.rs delete mode 100644 tools/test-framework/src/types/binary/channel.rs delete mode 100644 tools/test-framework/src/types/binary/client.rs delete mode 100644 tools/test-framework/src/types/binary/connection.rs delete mode 100644 tools/test-framework/src/types/binary/foreign_client.rs delete mode 100644 tools/test-framework/src/types/binary/mod.rs delete mode 100644 tools/test-framework/src/types/config.rs delete mode 100644 tools/test-framework/src/types/env.rs delete mode 100644 tools/test-framework/src/types/id.rs delete mode 100644 tools/test-framework/src/types/mod.rs delete mode 100644 tools/test-framework/src/types/nary/aliases.rs delete mode 100644 tools/test-framework/src/types/nary/chains.rs delete mode 100644 tools/test-framework/src/types/nary/channel.rs delete mode 100644 tools/test-framework/src/types/nary/connection.rs delete mode 100644 tools/test-framework/src/types/nary/foreign_client.rs delete mode 100644 tools/test-framework/src/types/nary/mod.rs delete mode 100644 tools/test-framework/src/types/process.rs delete mode 100644 tools/test-framework/src/types/single/mod.rs delete mode 100644 tools/test-framework/src/types/single/node.rs delete mode 100644 tools/test-framework/src/types/tagged/dual.rs delete mode 100644 tools/test-framework/src/types/tagged/mod.rs delete mode 100644 tools/test-framework/src/types/tagged/mono.rs delete mode 100644 tools/test-framework/src/types/wallet.rs delete mode 100644 tools/test-framework/src/util/array.rs delete mode 100644 tools/test-framework/src/util/assert.rs delete mode 100644 tools/test-framework/src/util/file.rs delete mode 100644 tools/test-framework/src/util/interchain_security.rs delete mode 100644 tools/test-framework/src/util/mod.rs delete mode 100644 tools/test-framework/src/util/random.rs delete mode 100644 tools/test-framework/src/util/retry.rs delete mode 100644 tools/test-framework/src/util/suspend.rs diff --git a/.github/workflows/integration-tests-legacy.yaml b/.github/workflows/integration-tests-legacy.yaml deleted file mode 100644 index 079451d0c..000000000 --- a/.github/workflows/integration-tests-legacy.yaml +++ /dev/null @@ -1,62 +0,0 @@ -name: Integration Tests (Legacy) -on: - pull_request: {} - push: - branches: main - -# Cancel previous runs of this workflow when a new commit is added to the PR, branch or tag -concurrency: - group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} - cancel-in-progress: true - -jobs: - integration-test: - if: false # Disable legacy tests as they depend on ibc-relayer-types - runs-on: ubuntu-20.04 - timeout-minutes: 60 - strategy: - fail-fast: false - matrix: - chain: - - package: gaia14 - command: gaiad - account_prefix: cosmos - features: '' - - package: ibc-go-v7-simapp - command: simd - account_prefix: cosmos - features: solomachine - steps: - - uses: actions/checkout@v4 - - uses: cachix/install-nix-action@v30 - with: - extra_nix_config: | - experimental-features = nix-command flakes - - uses: cachix/cachix-action@v15 - with: - name: hermes-sdk - extraPullNames: cosmos-nix - authToken: ${{ secrets.CACHIX_AUTH_TOKEN }} - - 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 --no-run --features=${{ matrix.chain.features }} - - name: run integration tests - env: - RUST_LOG: info,ibc_relayer_runtime=trace - RUST_BACKTRACE: 1 - NO_COLOR_LOG: 1 - CHAIN_COMMAND_PATHS: ${{ matrix.chain.command }} - ACCOUNT_PREFIXES: ${{ matrix.chain.account_prefix }} - run: | - nix shell .#cargo-nextest .#protobuf .#${{ matrix.chain.package }} -c \ - cargo nextest run \ - -p ibc-integration-test \ - --features=${{ matrix.chain.features }} \ - --test-threads=2 \ - --failure-output final diff --git a/Cargo.toml b/Cargo.toml index 98e9df0e0..1436b0ee6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -54,9 +54,6 @@ members = [ "crates/mock/mock-relayer", - #"tools/integration-test", - #"tools/test-framework", - "crates/ibc/ibc-components", "crates/ibc/ibc-token-transfer-components", "crates/ibc/ibc-mock-chain", @@ -81,7 +78,6 @@ ibc = { version = "0.56.0", default-features = false ibc-client-tendermint = { version = "0.56.0", default-features = false } ibc-proto = { version = "0.51.1", default-features = false } ibc-relayer = { version = "0.29.3" } -ibc-relayer-types = { version = "0.29.3" } ibc-telemetry = { version = "0.29.3" } tendermint = { version = "0.40" } tendermint-proto = { version = "0.40" } @@ -193,7 +189,6 @@ hermes-ibc-mock-chain = { version = "0.1.0" } # cgp-inner = { git = "https://github.com/contextgeneric/cgp.git" } ibc-relayer = { git = "https://github.com/informalsystems/hermes.git" } -ibc-relayer-types = { git = "https://github.com/informalsystems/hermes.git" } ibc-telemetry = { git = "https://github.com/informalsystems/hermes.git" } hermes-chain-components = { path = "./crates/chain/chain-components" } diff --git a/tools/integration-test/Cargo.toml b/tools/integration-test/Cargo.toml deleted file mode 100644 index a2cb3c0f1..000000000 --- a/tools/integration-test/Cargo.toml +++ /dev/null @@ -1,36 +0,0 @@ -[package] -name = "ibc-integration-test" -version = { workspace = true } -edition = { workspace = true } -license = { workspace = true } -keywords = { workspace = true } -repository = { workspace = true } -authors = { workspace = true } -rust-version = { workspace = true } -readme = "README.md" -description = "Integration tests for Hermes" -publish = false - -[dependencies] -cgp = { workspace = true } -ibc-relayer-types = { workspace = true } -ibc-relayer = { workspace = true } -hermes-relayer-components = { workspace = true } -hermes-relayer-components-extra = { workspace = true } -hermes-error = { workspace = true } -hermes-runtime = { workspace = true } -hermes-cosmos-relayer = { workspace = true } -hermes-cosmos-chain-components = { workspace = true } -hermes-solomachine-relayer = { workspace = true } -ibc-test-framework = { path = "../test-framework" } - -http = { workspace = true } -prost = { workspace = true } -serde_json = { workspace = true } -tokio = { workspace = true, features = ["rt"] } -time = "0.3" -toml = "0.8" - -[features] -default = [] -solomachine = [] diff --git a/tools/integration-test/spec/.gitignore b/tools/integration-test/spec/.gitignore deleted file mode 100644 index 86ee00110..000000000 --- a/tools/integration-test/spec/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -states/ -_apalache-out/ -run/ diff --git a/tools/integration-test/spec/MC_Transfer.cfg b/tools/integration-test/spec/MC_Transfer.cfg deleted file mode 100644 index e3e8c3d25..000000000 --- a/tools/integration-test/spec/MC_Transfer.cfg +++ /dev/null @@ -1,2 +0,0 @@ -INIT Init -NEXT Next diff --git a/tools/integration-test/spec/MC_Transfer.tla b/tools/integration-test/spec/MC_Transfer.tla deleted file mode 100644 index 3af3909d5..000000000 --- a/tools/integration-test/spec/MC_Transfer.tla +++ /dev/null @@ -1,49 +0,0 @@ ----- MODULE MC_Transfer ---- -EXTENDS Transfer_typedefs - -CHAIN_IDS == {1, 2} -N_INITIAL_ACCOUNTS == 2 -GENESIS_AMOUNT == 3 - -VARIABLES - \* Interchain state - \* @type: CHAIN_ID -> CHAIN; - chains, - \* @type: Bool; - relayerRunning, - \* Action performed at current step - \* @type: [ name: Str ]; - action, - \* Outcome after action performed at current step - \* @type: [ name: Str ]; - outcome - -INSTANCE Transfer - -\* Trace with a LocalTransfer action -LocalTransferTest == action.name = LocalTransferAction - -\* Trace with a RestoreRelay action -RestoreRelayTest == action.name = RestoreRelayAction -\* Trace with an InterruptRelay action -InterruptRelayTest == action.name = InterruptRelayAction - -\* Trace with an IBCTransferSendPacket action -IBCTransferSendPacketTest == action.name = IBCTransferSendPacketAction -\* Trace with an IBCTransferReceivePacket action -IBCTransferReceivePacketTest == action.name = IBCTransferReceivePacketAction -\* Trace with an IBCTransferAcknowledgePacket action -IBCTransferAcknowledgePacketTest == action.name = IBCTransferAcknowledgePacketAction -\* Trace with an IBCTransferTimeoutPacket action -IBCTransferTimeoutPacketTest == action.name = IBCTransferTimeoutPacketAction - -\* Negate the trace predicate to find counter-example -LocalTransferInv == ~LocalTransferTest -RestoreRelayInv == ~RestoreRelayTest -InterruptRelayInv == ~InterruptRelayTest -IBCTransferSendPacketInv == ~IBCTransferSendPacketTest -IBCTransferReceivePacketInv == ~IBCTransferReceivePacketTest -IBCTransferAcknowledgePacketInv == ~IBCTransferAcknowledgePacketTest -IBCTransferTimeoutPacketInv == ~IBCTransferTimeoutPacketTest - -==== diff --git a/tools/integration-test/spec/README.md b/tools/integration-test/spec/README.md deleted file mode 100644 index 8d9466915..000000000 --- a/tools/integration-test/spec/README.md +++ /dev/null @@ -1,23 +0,0 @@ -# ICS20 Specification - -Add desired `Invariant` predicate in `MC_Transfer.tla`. Then execute, - -```sh -apalache check --inv=Invariant --run-dir=run MC_Transfer.tla -``` - -Provided invariants to pass, - -``` -LocalTransferInv -RestoreRelayInv -InterruptRelayInv -IBCTransferSendPacketInv -IBCTransferReceivePacketInv -IBCTransferAcknowledgePacketInv -IBCTransferTimeoutPacketInv -``` - -```sh -apalache check --inv=IBCTransferAcknowledgePacketInv --run-dir=run MC_Transfer.tla -``` diff --git a/tools/integration-test/spec/Transfer.tla b/tools/integration-test/spec/Transfer.tla deleted file mode 100644 index bb9067868..000000000 --- a/tools/integration-test/spec/Transfer.tla +++ /dev/null @@ -1,398 +0,0 @@ ----- MODULE Transfer ---- -EXTENDS Apalache, Sequences, Integers, Transfer_typedefs - -CONSTANTS - \* Set of blockchain names - \* @type: Set(CHAIN_ID); - CHAIN_IDS, - \* Number of accounts per blockchain - \* @type: ACCOUNT_ID; - N_INITIAL_ACCOUNTS, - \* Genesis balance per account - \* @type: Int; - GENESIS_AMOUNT - -VARIABLES - \* Interchain state - \* @type: CHAIN_ID -> CHAIN; - chains, - \* @type: Bool; - relayerRunning, - \* Action performed at current step - \* @type: [ name: Str ]; - action, - \* Outcome after action performed at current step - \* @type: [ name: Str ]; - outcome - -\* Account IDs starts from 1 -\* @type: () => Set(ACCOUNT_ID); -ACCOUNT_IDS == 1..N_INITIAL_ACCOUNTS - -\* Actions -NullAction == "Null" -LocalTransferAction == "LocalTransfer" -RestoreRelayAction == "RestoreRelay" -InterruptRelayAction == "InterruptRelay" -IBCTransferSendPacketAction == "IBCTransferSendPacket" -IBCTransferReceivePacketAction == "IBCTransferReceivePacket" -IBCTransferAcknowledgePacketAction == "IBCTransferAcknowledgePacket" -IBCTransferTimeoutPacketAction == "IBCTransferTimeoutPacket" - -\* Outcomes -SuccessOutcome == "Success" -ErrorOutcome == "Error" - -\* @type: (CHAIN_ID) => CHAIN; -Genesis(chainId) == - LET nativeDenom == chainId IN [ - \* Name of the chain - id |-> chainId, - - \* Bank data for this chain - \* To support different cross-chain(ibc) denoms, it is a 2D map. - \* `accountId` has `bank[accountId][denomId]` many `denomId`. - bank |-> [accountId \in ACCOUNT_IDS |-> [denom \in {nativeDenom} |-> GENESIS_AMOUNT]], - \* Record of circulating native and cross-chain(ibc) token sourced at this chain - supply |-> [denom \in {nativeDenom} |-> GENESIS_AMOUNT * N_INITIAL_ACCOUNTS ], - - \* Record of packets originated from this chain - localPackets |-> [ - \* A table of packets with packetId - list |-> SetAsFun({}), - \* Set of packetIds of packets which are not yet acknowledged by destination chain - pending |-> {}, - \* Set of packetIds of packets which are not delivered to destrination chain within timeout block height - expired |-> {}, - \* Set of packetIds of packets which are acknowledged by destination chain - success |-> {} - ], - - \* Escrow balance per chain - escrow |-> [cId \in CHAIN_IDS \ {chainId} |-> SetAsFun({})], - - \* Record of packets receiveed from other chains - \* Packets are maintained using the channelId, it was received at. - \* Note: A pair of chain may have multiple channels in the past. - remotePackets |-> SetAsFun({}), - - nextPacketId |-> 0 -] - -\* Get balance of denom in a bank -\* @type: (BANK, DENOM_ID) => Int; -GetDenomFromBank(bank, denom) == - IF denom \in DOMAIN bank THEN bank[denom] - ELSE 0 - -\* Add an entry to a map if its key does not exists -\* Else update the existing entry -\* @type: (k -> v, k, v) => (k -> v); -AddOrUpdateEntry(func, key, value) == - IF key \in DOMAIN func THEN [func EXCEPT ![key] = value] - ELSE [x \in {key} \union DOMAIN func |-> IF x = key THEN value ELSE func[x]] - - -(* -We will model TokenTransfer using following actions. - -LocalTransfer : on-chain transfer - -InterruptRelay : Interrupt relaying -RestoreRelay : Restore relaying - -IBCTransferSendPacket : account in source chain tries to send denom to an account in target chain -IBCTransferReceivePacket : account in target chain receives the denom sent from account in source chain -IBCTransferAcknowledgePacket : the transaction is acknowledged. source chain completes the transaction. -IBCTransferTimeoutPacket : the transfer is timed-out. balance is refunded to source account. -*) - -\* Checks if the source account has enough balance -\* @type: (CHAIN, ACCOUNT_ID, DENOM_ID, Int) => Bool; -HasEnoughBalance(chain, source, denom, amount) == - /\ source \in DOMAIN chain.bank - /\ denom \in DOMAIN chain.bank[source] - /\ chain.bank[source][denom] >= amount - -\* Updated bank after local transfer -\* @type: (CHAIN, ACCOUNT_ID, ACCOUNT_ID, DENOM_ID, Int) => CHAIN; -LocalTransfer(chain, source, target, denom, amount) == - [ - chain EXCEPT - !.bank = [ - @ EXCEPT - ![source] = AddOrUpdateEntry(@, denom, GetDenomFromBank(@, denom) - amount), - ![target] = AddOrUpdateEntry(@, denom, GetDenomFromBank(@, denom) + amount) - ] - ] - -\* Next operator for LocalTransfer -\* @type: () => Bool; -LocalTransferNext == - \E chainId \in CHAIN_IDS: - \E source, target \in ACCOUNT_IDS: - source /= target /\ - \E amount \in 1..10: - LET - chain == chains[chainId] - denom == chain.id IN - /\ HasEnoughBalance(chain, source, denom, amount) - /\ chains' = [ - chains EXCEPT - ![chainId] = LocalTransfer(@, source, target, chain.id, amount) - ] - /\ action' = [ - name |-> LocalTransferAction, - chainId |-> chainId, - source |-> source, - target |-> target, - denom |-> denom, - amount |-> amount - ] - /\ outcome' = [ name |-> SuccessOutcome ] - /\ UNCHANGED relayerRunning - -\* Next operator for RestoreRelay -\* @type: () => Bool; -RestoreRelayNext == - /\ relayerRunning = FALSE - /\ relayerRunning' = TRUE - /\ UNCHANGED chains - /\ action' = [name |-> RestoreRelayAction] - /\ outcome' = [name |-> SuccessOutcome] - -\* Next operator for InterruptRelay -\* @type: () => Bool; -InterruptRelayNext == - /\ relayerRunning = TRUE - /\ relayerRunning' = FALSE - /\ UNCHANGED chains - /\ action' = [name |-> InterruptRelayAction] - /\ outcome' = [name |-> SuccessOutcome] - -\* Checks if there exists a channel between two chains -\* @type: () => Bool; -IBCTransferSendPacketCondition == - relayerRunning - -\* Creates an IBCPacket with the necessary information and adds it to pending packets -\* @type: (CHAIN, ACCOUNT_ID, CHAIN, ACCOUNT_ID, DENOM_ID, Int) => CHAIN; -IBCTransferSendPacket(sourceChain, source, targetChain, target, denom, amount) == - [ - sourceChain EXCEPT - !.bank = [@ EXCEPT - ![source] = AddOrUpdateEntry(@, denom, GetDenomFromBank(@, denom) - amount) - ], - !.escrow = [@ EXCEPT - ![targetChain.id] = AddOrUpdateEntry(@, denom, GetDenomFromBank(@, denom) + amount) - ], - !.localPackets = [@ EXCEPT - !.list = AddOrUpdateEntry(@, - sourceChain.nextPacketId, - [ - id |-> sourceChain.nextPacketId, - from |-> source, - sourceChainId |-> sourceChain.id, - to |-> target, - targetChainId |-> targetChain.id, - denom |-> denom, - amount |-> amount - ] - ), - !.pending = @ \union {sourceChain.nextPacketId} - ], - !.nextPacketId = @ + 1 - ] - -\* Next operator for IBCTransferSendPacket -IBCTransferSendPacketNext == - \E chainId1, chainId2 \in CHAIN_IDS: - chainId1 /= chainId2 /\ - \E acc1, acc2 \in ACCOUNT_IDS: - \E denom \in DOMAIN chains[chainId1].supply: - \E amount \in 1..10: - /\ IBCTransferSendPacketCondition - /\ HasEnoughBalance(chains[chainId1], acc1, denom, amount) - /\ chains' = [chains EXCEPT - ![chainId1] = IBCTransferSendPacket(chains[chainId1], acc1, chains[chainId2], acc2, denom, amount) - ] - /\ action' = [ - name |-> IBCTransferSendPacketAction, - packet |-> chains'[chainId1].localPackets.list[chains[chainId1].nextPacketId] - ] - /\ outcome' = [name |-> SuccessOutcome] - /\ UNCHANGED relayerRunning - -\* TODO: -\* append CHANNEL_ID/PORT_ID for source zone -\* trim CHANNEL_ID/PORT_ID for sink zone -\* @type: (DENOM_ID, CHAIN_ID) => DENOM_ID; -TransformDenom(denom, targetChainId) == - denom - -\* Process an IBC packet at targetChain -\* @type: (PACKET) => CHAIN; -IBCTransferReceivePacket(packet) == - LET - targetChainId == packet.targetChainId - sourceChainId == packet.sourceChainId - destination == packet.to - denom == TransformDenom(packet.denom, targetChainId) - amount == packet.amount - targetChain == chains[targetChainId] - IN - [ - targetChain EXCEPT - !.bank = [@ EXCEPT - ![destination] = AddOrUpdateEntry(@, denom, GetDenomFromBank(@, denom) + amount) - ], - !.supply = AddOrUpdateEntry(@, denom, GetDenomFromBank(@, denom) + amount), - !.remotePackets = AddOrUpdateEntry( - @, - sourceChainId, - AddOrUpdateEntry( - IF sourceChainId \in DOMAIN @ THEN @[sourceChainId] ELSE SetAsFun({}), - packet.id, - packet - ) - ) - ] - -\* Checks if the packet is not processed by the targetChain -\* @type: (PACKET, CHAIN) => Bool; -IBCTransferReceivePacketCondition(packet, targetChain) == - /\ relayerRunning - /\ \/ packet.sourceChainId \notin DOMAIN targetChain.remotePackets - \/ packet.id \notin DOMAIN targetChain.remotePackets[packet.sourceChainId] - -\* Next operator for IBCTransferReceivePacket -IBCTransferReceivePacketNext == - \E chainId \in CHAIN_IDS: - \E packetId \in chains[chainId].localPackets.pending: - LET - packet == chains[chainId].localPackets.list[packetId] - targetChain == chains[packet.targetChainId] - IN - /\ IBCTransferReceivePacketCondition(packet, targetChain) - /\ chains' = [chains EXCEPT - ![packet.targetChainId] = IBCTransferReceivePacket(packet) - ] - /\ action' = [ - name |-> IBCTransferReceivePacketAction, - packet |-> packet - ] - /\ outcome' = [name |-> SuccessOutcome] - /\ UNCHANGED relayerRunning - - -\* Picks an IBCPacket from sourceChain to timeout -\* Refunds balance to source account -\* Moves the packet from pending to expired -\* @type: (PACKET) => CHAIN; -IBCTransferTimeoutPacket(packet) == - LET - from == packet.from - denom == packet.denom - amount == packet.amount - sourceChain == chains[packet.sourceChainId] - targetChain == chains[packet.targetChainId] - escrowAccount == sourceChain.escrow[packet.targetChainId] - IN - [ - sourceChain EXCEPT - !.bank = [@ EXCEPT - ![from] = AddOrUpdateEntry(@, denom, GetDenomFromBank(@, denom) + amount) - ], - !.escrow = [@ EXCEPT - ![packet.targetChainId] = AddOrUpdateEntry(@, denom, GetDenomFromBank(@, denom) - amount) - ], - !.localPackets = [@ EXCEPT - !.pending = @ \ {packet.id}, - !.expired = @ \union {packet.id} - ] - ] - -\* Checks if the packet is not processed by the targetChain -\* @type: (PACKET, CHAIN) => Bool; -IBCTransferTimeoutPacketCondition(packet, targetChain) == - /\ ~relayerRunning - /\ packet.id \notin DOMAIN targetChain.remotePackets[packet.sourceChainId] - -\* Next operator for IBCTransferTimeoutPacket -IBCTransferTimeoutPacketNext == - \E chainId \in CHAIN_IDS: - \E packetId \in chains[chainId].localPackets.pending: - LET - packet == chains[chainId].localPackets.list[packetId] - sourceChain == chains[packet.sourceChainId] - targetChain == chains[packet.targetChainId] - IN - /\ IBCTransferTimeoutPacketCondition(packet, targetChain) - /\ chains' = [chains EXCEPT - ![sourceChain.id] = IBCTransferTimeoutPacket(packet) - ] - /\ action' = [ - name |-> IBCTransferTimeoutPacketAction, - packet |-> packet - ] - /\ outcome' = [name |-> SuccessOutcome] - /\ UNCHANGED relayerRunning - - -\* Mark an IBC packet at sourceChain as success which is processed at targetChain -\* @type: (PACKET) => CHAIN; -IBCTransferAcknowledgePacket(packet) == - LET sourceChain == chains[packet.sourceChainId] IN - [ - sourceChain EXCEPT - !.localPackets = [@ EXCEPT - !.pending = @ \ {packet.id}, - !.success = @ \union {packet.id} - ] - ] - -\* Checks if the packet is already processed by the targetChain -\* @type: (PACKET, CHAIN) => Bool; -IBCTransferAcknowledgePacketCondition(packet, targetChain) == - /\ relayerRunning - /\ packet.sourceChainId \in DOMAIN targetChain.remotePackets - /\ packet.id \in DOMAIN targetChain.remotePackets[packet.sourceChainId] - -\* Next operator for IBCTransferAcknowledgePacket -IBCTransferAcknowledgePacketNext == - \E chainId \in CHAIN_IDS: - \E packetId \in chains[chainId].localPackets.pending: - LET - packet == chains[chainId].localPackets.list[packetId] - sourceChain == chains[packet.sourceChainId] - targetChain == chains[packet.targetChainId] - IN - /\ IBCTransferAcknowledgePacketCondition(packet, targetChain) - /\ chains' = [chains EXCEPT - ![sourceChain.id] = IBCTransferAcknowledgePacket(packet) - ] - /\ action' = [ - name |-> IBCTransferAcknowledgePacketAction, - packet |-> packet - ] - /\ outcome' = [name |-> SuccessOutcome] - /\ UNCHANGED relayerRunning - -\* Init predicate -Init == - /\ chains = [chainId \in CHAIN_IDS |-> Genesis(chainId)] - /\ relayerRunning = TRUE - /\ action = [ name |-> NullAction ] - /\ outcome = [ name |-> SuccessOutcome ] - -\* Complete Next predicate -Next == - \/ LocalTransferNext - \/ InterruptRelayNext - \/ RestoreRelayNext - \/ IBCTransferSendPacketNext - \/ IBCTransferReceivePacketNext - \/ IBCTransferTimeoutPacketNext - \/ IBCTransferAcknowledgePacketNext - -==== diff --git a/tools/integration-test/spec/Transfer_typedefs.tla b/tools/integration-test/spec/Transfer_typedefs.tla deleted file mode 100644 index f352ccfb7..000000000 --- a/tools/integration-test/spec/Transfer_typedefs.tla +++ /dev/null @@ -1,45 +0,0 @@ ----- MODULE Transfer_typedefs ---- - -(* - @typeAlias: ACCOUNT_ID = Int; - @typeAlias: CHAIN_ID = Int; - @typeAlias: PACKET_ID = Int; - - TODO: Fix when to transfer back money to sink zone - @typeAlias: DENOM_ID = CHAIN_ID; - - @typeAlias: PACKET = [ - id: PACKET_ID, - from: ACCOUNT_ID, - sourceChainId: CHAIN_ID, - to: ACCOUNT_ID, - targetChainId: CHAIN_ID, - denom: DENOM_ID, - amount: Int - ]; - - @typeAlias: BANK = DENOM_ID -> Int; - - @typeAlias: CHAIN = [ - id: CHAIN_ID, - - bank: ACCOUNT_ID -> BANK, - supply: BANK, - - localPackets: [ - list: PACKET_ID -> PACKET, - pending: Set(PACKET_ID), - expired: Set(PACKET_ID), - success: Set(PACKET_ID) - ], - - remotePackets: CHAIN_ID -> PACKET_ID -> PACKET, - - escrow: CHAIN_ID -> BANK, - - nextPacketId: PACKET_ID - ]; -*) -typedefs == TRUE - -==== diff --git a/tools/integration-test/src/lib.rs b/tools/integration-test/src/lib.rs deleted file mode 100644 index 1a1c6f690..000000000 --- a/tools/integration-test/src/lib.rs +++ /dev/null @@ -1,5 +0,0 @@ -#![recursion_limit = "256"] -#![allow(clippy::too_many_arguments)] - -#[cfg(test)] -pub mod tests; diff --git a/tools/integration-test/src/tests/connection.rs b/tools/integration-test/src/tests/connection.rs deleted file mode 100644 index b0b5dd35d..000000000 --- a/tools/integration-test/src/tests/connection.rs +++ /dev/null @@ -1,91 +0,0 @@ -use hermes_cosmos_chain_components::types::channel::CosmosInitChannelOptions; -use hermes_error::types::HermesError; -use hermes_relayer_components::birelay::traits::two_way::HasTwoWayRelay; -use hermes_relayer_components::build::impls::bootstrap::birelay::CanBootstrapBiRelay; -use hermes_relayer_components::relay::impls::channel::bootstrap::CanBootstrapChannel; -use hermes_relayer_components::relay::impls::connection::bootstrap::CanBootstrapConnection; -use ibc_relayer::channel::version::Version; -use ibc_relayer::config::PacketFilter; -use ibc_test_framework::prelude::*; - -use crate::tests::context::new_cosmos_builder; - -#[test] -fn test_connection_and_channel_handshake_next() -> Result<(), Error> { - run_binary_chain_test(&ConnectionAndChannelHandshakeTest) -} - -pub struct ConnectionAndChannelHandshakeTest; - -impl TestOverrides for ConnectionAndChannelHandshakeTest { - fn should_spawn_supervisor(&self) -> bool { - false - } -} - -impl BinaryChainTest for ConnectionAndChannelHandshakeTest { - fn run( - &self, - _config: &TestConfig, - relayer: RelayerDriver, - chains: ConnectedChains, - ) -> Result<(), Error> { - let pf: PacketFilter = PacketFilter::default(); - - let runtime = chains.node_a.value().chain_driver.runtime.as_ref(); - - let builder = new_cosmos_builder(&relayer.config, &chains, pf)?; - - let chain_id_a = chains.chain_id_a().cloned_value(); - let chain_id_b = chains.chain_id_b().cloned_value(); - - runtime - .block_on(async move { - let birelay = builder - .bootstrap_birelay( - &chain_id_a, - &chain_id_b, - &Default::default(), - &Default::default(), - &(), - &(), - ) - .await?; - - let (connection_id_a, connection_id_b) = birelay - .relay_a_to_b() - .bootstrap_connection(&Default::default()) - .await?; - - info!( - "bootstrapped new IBC connections with ID {} and {}", - connection_id_a, connection_id_b - ); - - let channel_init_options = CosmosInitChannelOptions { - ordering: Ordering::Unordered, - connection_hops: vec![connection_id_a], - channel_version: Version::ics20(), - }; - - let (channel_id_a, channel_id_b) = birelay - .relay_a_to_b() - .bootstrap_channel( - &PortId::transfer(), - &PortId::transfer(), - &channel_init_options, - ) - .await?; - - info!( - "bootstrapped new IBC channel with ID {} and {}", - channel_id_a, channel_id_b - ); - - >::Ok(()) - }) - .unwrap(); - - Ok(()) - } -} diff --git a/tools/integration-test/src/tests/context.rs b/tools/integration-test/src/tests/context.rs deleted file mode 100644 index 0f0c0c83c..000000000 --- a/tools/integration-test/src/tests/context.rs +++ /dev/null @@ -1,78 +0,0 @@ -use std::collections::HashMap; - -use hermes_cosmos_chain_components::impls::types::config::CosmosChainConfig; -use hermes_cosmos_relayer::contexts::birelay::CosmosBiRelay; -use hermes_cosmos_relayer::contexts::build::CosmosBuilder; -use hermes_relayer_components::build::traits::builders::birelay_builder::CanBuildBiRelay; -use hermes_runtime::types::runtime::HermesRuntime; -use ibc_relayer::chain::handle::ChainHandle; -use ibc_relayer::config::filter::PacketFilter; -use ibc_relayer::config::{ChainConfig, Config}; -use ibc_test_framework::error::{handle_generic_error, Error}; -use ibc_test_framework::prelude::TaggedFullNodeExt; -use ibc_test_framework::types::binary::chains::ConnectedChains; - -pub fn new_cosmos_builder( - config: &Config, - chains: &ConnectedChains, - packet_filter: PacketFilter, -) -> Result -where - ChainA: ChainHandle, - ChainB: ChainHandle, -{ - let runtime = chains.node_a.value().chain_driver.runtime.clone(); - - let key_a = chains.node_a.wallets().value().relayer.key.clone(); - - let key_b = chains.node_b.wallets().value().relayer.key.clone(); - - let key_map = HashMap::from([ - (chains.chain_id_a().cloned_value(), key_a), - (chains.chain_id_b().cloned_value(), key_b), - ]); - - let chain_configs = config - .chains - .iter() - .map(|config| { - let ChainConfig::CosmosSdk(config) = config; - CosmosChainConfig::from(config.clone()) - }) - .collect(); - - let builder = CosmosBuilder::new( - chain_configs, - HermesRuntime::new(runtime), - Default::default(), - packet_filter, - Default::default(), - key_map, - ); - - Ok(builder) -} - -pub fn build_cosmos_relay_context( - config: &Config, - chains: &ConnectedChains, - packet_filter: PacketFilter, -) -> Result -where - ChainA: ChainHandle, - ChainB: ChainHandle, -{ - let runtime = chains.node_a.value().chain_driver.runtime.clone(); - let builder = new_cosmos_builder(config, chains, packet_filter)?; - - let birelay = runtime - .block_on(builder.build_birelay( - chains.chain_id_a().value(), - chains.chain_id_b().value(), - chains.client_id_a().value(), - chains.client_id_b().value(), - )) - .map_err(handle_generic_error)?; - - Ok(birelay) -} diff --git a/tools/integration-test/src/tests/filter.rs b/tools/integration-test/src/tests/filter.rs deleted file mode 100644 index 516e7622a..000000000 --- a/tools/integration-test/src/tests/filter.rs +++ /dev/null @@ -1,112 +0,0 @@ -use hermes_relayer_components::birelay::traits::two_way::HasTwoWayRelay; -use hermes_relayer_components::relay::traits::packet_relayer::CanRelayPacket; -use ibc_relayer::config::filter::PacketFilter; -use ibc_test_framework::framework::next::chain::{HasTwoChains, HasTwoChannels}; -use ibc_test_framework::ibc::denom::derive_ibc_denom; -use ibc_test_framework::prelude::*; -use ibc_test_framework::util::random::random_u64_range; - -use crate::tests::context::build_cosmos_relay_context; - -#[test] -fn test_ibc_filter_next() -> Result<(), Error> { - run_binary_channel_test(&ChannelFilterTest) -} - -pub struct ChannelFilterTest; - -impl TestOverrides for ChannelFilterTest { - fn should_spawn_supervisor(&self) -> bool { - false - } -} - -impl BinaryChannelTest for ChannelFilterTest { - fn run(&self, relayer: RelayerDriver, context: &Context) -> Result<(), Error> - where - Context: HasTwoChains + HasTwoChannels, - { - let chains = context.chains(); - let channel = context.channel(); - let toml_content = r#" - policy = 'deny' - list = [ - ['transfer', 'channel-*'], - ] - "#; - let pf: PacketFilter = toml::from_str(toml_content).expect("could not parse filter policy"); - - let relay_context = build_cosmos_relay_context(&relayer.config, chains, pf)?; - - let runtime = chains.node_a.value().chain_driver.runtime.as_ref(); - - let denom_a = chains.node_a.denom(); - - let wallet_a = chains.node_a.wallets().user1().cloned(); - let wallet_b = chains.node_b.wallets().user1().cloned(); - - let balance_a = chains - .node_a - .chain_driver() - .query_balance(&wallet_a.address(), &denom_a)?; - - let a_to_b_amount = random_u64_range(1000, 5000); - - info!( - "Sending IBC transfer from chain {} to chain {} with amount of {} {}", - chains.chain_id_a(), - chains.chain_id_b(), - a_to_b_amount, - denom_a - ); - - let packet = chains.node_a.chain_driver().ibc_transfer_token( - &channel.port_a.as_ref(), - &channel.channel_id_a.as_ref(), - &wallet_a.as_ref(), - &wallet_b.address(), - &denom_a.with_amount(a_to_b_amount).as_ref(), - )?; - - info!("running relayer"); - - runtime.block_on(async { - relay_context - .relay_a_to_b() - .relay_packet(&packet) - .await - .unwrap() - }); - - info!("finished running relayer"); - - let denom_b = derive_ibc_denom( - &channel.port_b.as_ref(), - &channel.channel_id_b.as_ref(), - &denom_a, - )?; - - info!( - "User on chain B should not receive the transfer of {} {}", - a_to_b_amount, &denom_b - ); - - chains.node_a.chain_driver().assert_eventual_wallet_amount( - &wallet_a.address(), - &(balance_a - a_to_b_amount).as_ref(), - )?; - - chains.node_b.chain_driver().assert_eventual_wallet_amount( - &wallet_b.address(), - &denom_b.with_amount(0u64).as_ref(), - )?; - - info!( - "successfully filtered IBC transfer from chain {} to chain {}", - chains.chain_id_a(), - chains.chain_id_b(), - ); - - Ok(()) - } -} diff --git a/tools/integration-test/src/tests/mod.rs b/tools/integration-test/src/tests/mod.rs deleted file mode 100644 index 6e7825f47..000000000 --- a/tools/integration-test/src/tests/mod.rs +++ /dev/null @@ -1,9 +0,0 @@ -pub mod connection; -pub mod context; -pub mod filter; -pub mod packet_clear; -pub mod timeout_transfer; -pub mod transfer; - -#[cfg(feature = "solomachine")] -pub mod solomachine; diff --git a/tools/integration-test/src/tests/packet_clear.rs b/tools/integration-test/src/tests/packet_clear.rs deleted file mode 100644 index 540745660..000000000 --- a/tools/integration-test/src/tests/packet_clear.rs +++ /dev/null @@ -1,458 +0,0 @@ -use hermes_cosmos_relayer::contexts::chain::CosmosChain; -use hermes_relayer_components::birelay::traits::two_way::HasTwoWayRelay; -use hermes_relayer_components::chain::traits::queries::chain_status::CanQueryChainStatus; -use hermes_relayer_components::chain::traits::queries::packet_acknowledgements::CanQueryPacketAcknowledgements; -use hermes_relayer_components::chain::traits::queries::packet_commitments::CanQueryPacketCommitments; -use hermes_relayer_components::chain::traits::queries::send_packets::CanQuerySendPackets; -use hermes_relayer_components::chain::traits::queries::unreceived_acks_sequences::CanQueryUnreceivedAcksSequences; -use hermes_relayer_components::chain::traits::queries::unreceived_packet_sequences::CanQueryUnreceivedPacketSequences; -use hermes_relayer_components::chain::traits::types::status::HasChainStatusType; -use hermes_relayer_components::relay::traits::chains::{HasDstChain, HasSrcChain}; -use hermes_relayer_components::relay::traits::packet_clearer::CanClearPackets; -use hermes_relayer_components::relay::traits::packet_relayers::receive_packet::CanRelayReceivePacket; -use ibc_relayer::config::PacketFilter; -use ibc_relayer_types::core::ics04_channel::packet::Sequence; -use ibc_relayer_types::Height; -use ibc_test_framework::framework::next::chain::{HasTwoChains, HasTwoChannels}; -use ibc_test_framework::prelude::*; -use ibc_test_framework::util::random::random_u64_range; - -use crate::tests::context::build_cosmos_relay_context; - -#[test] -fn test_ibc_clear_packet_next() -> Result<(), Error> { - run_binary_channel_test(&IbcClearPacketTest) -} - -#[test] -fn test_ibc_clear_ack_next() -> Result<(), Error> { - run_binary_channel_test(&IbcClearAckTest) -} - -pub struct IbcClearPacketTest; - -impl TestOverrides for IbcClearPacketTest { - fn should_spawn_supervisor(&self) -> bool { - false - } -} - -impl BinaryChannelTest for IbcClearPacketTest { - fn run(&self, relayer: RelayerDriver, context: &Context) -> Result<(), Error> - where - Context: HasTwoChains + HasTwoChannels, - { - let chains = context.chains(); - let cloned_channel = context.channel().clone(); - let channel = context.channel().clone(); - let pf: PacketFilter = PacketFilter::default(); - - let relay_context = build_cosmos_relay_context(&relayer.config, chains, pf)?; - - let relay_a_to_b = relay_context.relay_a_to_b(); - let relay_b_to_a = relay_context.relay_b_to_a(); - let chain_a = relay_a_to_b.src_chain(); - let chain_b = relay_a_to_b.dst_chain(); - - let runtime = chains.node_a.value().chain_driver.runtime.as_ref(); - - let denom_a = chains.node_a.denom(); - - let wallet_a = chains.node_a.wallets().user1().cloned(); - let wallet_b = chains.node_b.wallets().user1().cloned(); - - let balance_a = chains - .node_a - .chain_driver() - .query_balance(&wallet_a.address(), &denom_a)?; - - let a_to_b_amount = random_u64_range(1000, 5000); - - info!( - "Sending IBC transfer from chain {} to chain {} with amount of {} {}", - chains.chain_id_a(), - chains.chain_id_b(), - a_to_b_amount, - denom_a - ); - - chains.node_a.chain_driver().ibc_transfer_token( - &channel.port_a.as_ref(), - &channel.channel_id_a.as_ref(), - &wallet_a.as_ref(), - &wallet_b.address(), - &denom_a.with_amount(a_to_b_amount).as_ref(), - )?; - - let denom_b = derive_ibc_denom( - &channel.port_b.as_ref(), - &channel.channel_id_b.as_ref(), - &denom_a, - )?; - - runtime.block_on(async { - info!("Assert query packet commitments works as expected"); - - let (src_commitments, src_height): (Vec, Height) = - >::query_packet_commitments( - chain_a, - channel.channel_id_a.value(), - channel.port_a.value(), - ) - .await - .unwrap(); - - assert_eq!(src_commitments, vec!(Sequence::from(1))); - - let (dst_commitments, dst_height): (Vec, Height) = - >::query_packet_commitments( - chain_b, - channel.channel_id_b.value(), - channel.port_b.value(), - ) - .await - .unwrap(); - - assert_eq!(dst_commitments, vec!()); - - info!("Assert query unreceived packet sequences works as expected"); - - let unreceived_packet_sequences: Vec = - >::query_unreceived_packet_sequences( - chain_a, - channel.channel_id_a.value(), - channel.port_a.value(), - &src_commitments, - ) - .await - .unwrap(); - - assert_eq!(unreceived_packet_sequences, vec!(Sequence::from(1))); - - let unreceived_packet_sequences: Vec = - >::query_unreceived_packet_sequences( - chain_b, - channel.channel_id_b.value(), - channel.port_b.value(), - &src_commitments, - ) - .await - .unwrap(); - - assert_eq!(unreceived_packet_sequences, vec!(Sequence::from(1))); - - info!("Assert query unreceived packets works as expected"); - - let send_packets = >::query_send_packets_from_sequences( - chain_a, - channel.channel_id_a.value(), - channel.port_a.value(), - channel.channel_id_b.value(), - channel.port_b.value(), - &unreceived_packet_sequences, - &src_height, - ) - .await - .unwrap(); - - assert_eq!(send_packets.len(), 1); - - let send_packets = >::query_send_packets_from_sequences( - chain_b, - channel.channel_id_b.value(), - channel.port_b.value(), - channel.channel_id_a.value(), - channel.port_a.value(), - &unreceived_packet_sequences, - &dst_height, - ) - .await; - - assert!( - send_packets.is_err(), - "There should be no send packets from Chain B" - ); - - let _ = relay_b_to_a - .clear_packets( - channel.channel_id_b.value(), - channel.port_b.value(), - channel.channel_id_a.value(), - channel.port_a.value(), - ) - .await; - - info!("Clear packets from B to A should not clear the pending packet from A to B"); - - let amount = chains - .node_a - .chain_driver() - .query_balance(&wallet_a.address(), &balance_a.denom()) - .unwrap(); - - assert_eq!( - amount.value().amount, - (balance_a.clone() - a_to_b_amount).amount() - ); - - let amount = chains - .node_b - .chain_driver() - .query_balance(&wallet_b.address(), &denom_b.as_ref()) - .unwrap(); - - assert_eq!(amount.value().amount, denom_b.with_amount(0u64).amount()); - - let _ = relay_a_to_b - .clear_packets( - cloned_channel.channel_id_a.value(), - cloned_channel.port_a.value(), - cloned_channel.channel_id_b.value(), - cloned_channel.port_b.value(), - ) - .await; - - info!("Clear packet from A to B should clear the pending packet"); - - let amount = chains - .node_a - .chain_driver() - .query_balance(&wallet_a.address(), &balance_a.denom()) - .unwrap(); - - assert_eq!( - amount.value().amount, - (balance_a.clone() - a_to_b_amount).amount() - ); - - let amount = chains - .node_b - .chain_driver() - .query_balance(&wallet_b.address(), &denom_b.as_ref()) - .unwrap(); - - assert_eq!( - amount.value().amount, - denom_b.with_amount(a_to_b_amount).amount() - ); - }); - - Ok(()) - } -} - -pub struct IbcClearAckTest; - -impl TestOverrides for IbcClearAckTest { - fn should_spawn_supervisor(&self) -> bool { - false - } -} - -impl BinaryChannelTest for IbcClearAckTest { - fn run(&self, relayer: RelayerDriver, context: &Context) -> Result<(), Error> - where - Context: HasTwoChains + HasTwoChannels, - { - let chains = context.chains(); - let cloned_channel = context.channel().clone(); - let channel = context.channel().clone(); - let pf: PacketFilter = PacketFilter::default(); - - let relay_context = build_cosmos_relay_context(&relayer.config, chains, pf)?; - - let relay_a_to_b = relay_context.relay_a_to_b(); - let chain_a = relay_a_to_b.src_chain(); - let chain_b = relay_a_to_b.dst_chain(); - - let runtime = chains.node_a.value().chain_driver.runtime.as_ref(); - - let denom_a = chains.node_a.denom(); - - let wallet_a = chains.node_a.wallets().user1().cloned(); - let wallet_b = chains.node_b.wallets().user1().cloned(); - - let balance_a = chains - .node_a - .chain_driver() - .query_balance(&wallet_a.address(), &denom_a)?; - - let a_to_b_amount = random_u64_range(1000, 5000); - - info!( - "Sending IBC transfer from chain {} to chain {} with amount of {} {}", - chains.chain_id_a(), - chains.chain_id_b(), - a_to_b_amount, - denom_a - ); - - chains.node_a.chain_driver().ibc_transfer_token( - &channel.port_a.as_ref(), - &channel.channel_id_a.as_ref(), - &wallet_a.as_ref(), - &wallet_b.address(), - &denom_a.with_amount(a_to_b_amount).as_ref(), - )?; - - let denom_b = derive_ibc_denom( - &channel.port_b.as_ref(), - &channel.channel_id_b.as_ref(), - &denom_a, - )?; - - runtime.block_on(async { - // Will only clear the receive packet - let (src_commitments, src_height): (Vec, Height) = - >::query_packet_commitments( - chain_a, - channel.channel_id_a.value(), - channel.port_a.value(), - ) - .await - .unwrap(); - - let unreceived_packet_sequences: Vec = - >::query_unreceived_packet_sequences( - chain_b, - channel.channel_id_b.value(), - channel.port_b.value(), - &src_commitments, - ) - .await - .unwrap(); - - let send_packets =>::query_send_packets_from_sequences( - chain_a, - channel.channel_id_a.value(), - channel.port_a.value(), - channel.channel_id_b.value(), - channel.port_b.value(), - &unreceived_packet_sequences, - &src_height, - ) - .await - .unwrap(); - - let src_chain_status = chain_a - .query_chain_status() - .await - .unwrap(); - - for packet in send_packets.iter() { - let _write_ack = relay_a_to_b - .relay_receive_packet( - ::chain_status_height(&src_chain_status), - packet, - ) - .await.unwrap(); - } - - info!("The receive packet relaying should have escrowed the tokens"); - - let amount = chains - .node_a - .chain_driver() - .query_balance(&wallet_a.address(), &balance_a.denom()) - .unwrap(); - - assert_eq!( - amount.value().amount, - (balance_a.clone() - a_to_b_amount).amount() - ); - - let amount = chains - .node_b - .chain_driver() - .query_balance(&wallet_b.address(), &denom_b.as_ref()) - .unwrap(); - - assert_eq!( - amount.value().amount, - denom_b.with_amount(a_to_b_amount).amount() - ); - - info!("Assert query packet commitments works as expected"); - - let (src_commitments, _): (Vec, Height) = - >::query_packet_commitments( - chain_a, - channel.channel_id_a.value(), - channel.port_a.value(), - ) - .await - .unwrap(); - - assert_eq!(src_commitments, vec!(Sequence::from(1))); - - info!("Assert packet clearing clear the pending acks"); - - let acks_and_height_on_counterparty = >::query_packet_acknowlegements( - chain_b, - channel.channel_id_b.value(), - channel.port_b.value(), - &src_commitments - ).await.unwrap(); - - assert!(acks_and_height_on_counterparty.is_some()); - - info!("Assert query unreceived acknowledgment sequences works as expected"); - - let unreceived_ack_sequences = - >::query_unreceived_acknowledgments_sequences( - chain_a, - channel.channel_id_a.value(), - channel.port_a.value(), - &acks_and_height_on_counterparty.clone().unwrap().0, - ) - .await - .unwrap(); - - assert_eq!(unreceived_ack_sequences, vec!(Sequence::from(1))); - - let _ = relay_a_to_b - .clear_packets( - cloned_channel.channel_id_a.value(), - cloned_channel.port_a.value(), - cloned_channel.channel_id_b.value(), - cloned_channel.port_b.value(), - ) - .await; - - let acks_and_height_on_counterparty = >::query_packet_acknowlegements( - chain_b, - channel.channel_id_b.value(), - channel.port_b.value(), - &src_commitments - ).await.unwrap(); - - let unreceived_ack_sequences = - >::query_unreceived_acknowledgments_sequences( - chain_a, - channel.channel_id_a.value(), - channel.port_a.value(), - &acks_and_height_on_counterparty.clone().unwrap().0, - ) - .await - .unwrap(); - - assert_eq!(unreceived_ack_sequences, vec!()); - }); - - Ok(()) - } -} diff --git a/tools/integration-test/src/tests/solomachine/connection.rs b/tools/integration-test/src/tests/solomachine/connection.rs deleted file mode 100644 index 00d5f2d87..000000000 --- a/tools/integration-test/src/tests/solomachine/connection.rs +++ /dev/null @@ -1,110 +0,0 @@ -use hermes_cosmos_relayer::types::telemetry::CosmosTelemetry; -use hermes_error::types::HermesError; -use hermes_relayer_components::relay::traits::client_creator::CanCreateClient; -use hermes_relayer_components::relay::traits::connection::open_init::CanInitConnection; -use hermes_relayer_components::relay::traits::target::{DestinationTarget, SourceTarget}; -use hermes_runtime::types::runtime::HermesRuntime; -use hermes_solomachine_relayer::contexts::chain::MockSolomachine; -use hermes_solomachine_relayer::contexts::relay::SolomachineRelay; -use ibc_relayer::config::PacketFilter; -use ibc_test_framework::prelude::*; - -use crate::tests::context::new_cosmos_builder; - -#[test] -fn test_solomachine_to_cosmos_next() -> Result<(), Error> { - run_binary_chain_test(&SolomachineToCosmosTest) -} - -pub struct SolomachineToCosmosTest; - -impl TestOverrides for SolomachineToCosmosTest { - fn should_spawn_supervisor(&self) -> bool { - false - } -} - -impl BinaryChainTest for SolomachineToCosmosTest { - fn run( - &self, - _config: &TestConfig, - relayer: RelayerDriver, - chains: ConnectedChains, - ) -> Result<(), Error> { - let pf: PacketFilter = PacketFilter::default(); - - let runtime = chains.node_a.value().chain_driver.runtime.as_ref(); - - let builder = new_cosmos_builder(&relayer.config, &chains, pf)?; - - let chain_id_a = chains.chain_id_a().cloned_value(); - - let solomachine_runtime = - HermesRuntime::new(chains.node_b.value().chain_driver.runtime.clone()); - - let solomachine_chain = solomachine_chain_context(solomachine_runtime, Default::default()); - - runtime - .block_on(async move { - let cosmos_chain = builder.build_chain(&chain_id_a).await?; - - let src_client_id = SolomachineRelay::create_client( - SourceTarget, - &solomachine_chain, - &cosmos_chain, - &Default::default(), - &(), - ) - .await - .unwrap(); - - let dst_client_id = SolomachineRelay::create_client( - DestinationTarget, - &cosmos_chain, - &solomachine_chain, - &(), - &(), - ) - .await - .unwrap(); - - info!("src_client_id: {src_client_id:#?}"); - info!("dst_client_id: {dst_client_id:#?}"); - - let relay = SolomachineRelay { - runtime: solomachine_chain.runtime.clone(), - src_chain: solomachine_chain, - dst_chain: cosmos_chain, - src_client_id, - dst_client_id, - }; - - let src_connection_id = relay.init_connection(&Default::default()).await.unwrap(); - - info!("src_connection_id: {src_connection_id:#?}"); - - // FIXME: The test currently fails here - - // let dst_connection_id = relay - // .relay_connection_open_handshake(&src_connection_id) - // .await - // .unwrap(); - - // info!("dst_connection_id: {dst_connection_id:#?}"); - - >::Ok(()) - }) - .unwrap(); - - Ok(()) - } -} - -pub fn solomachine_chain_context( - runtime: HermesRuntime, - telemetry: CosmosTelemetry, -) -> MockSolomachine { - let commitment_prefix = "solomachine".to_owned(); - - MockSolomachine::new("solomachine1", commitment_prefix, runtime, telemetry) -} diff --git a/tools/integration-test/src/tests/solomachine/mod.rs b/tools/integration-test/src/tests/solomachine/mod.rs deleted file mode 100644 index b3b606b40..000000000 --- a/tools/integration-test/src/tests/solomachine/mod.rs +++ /dev/null @@ -1 +0,0 @@ -pub mod connection; diff --git a/tools/integration-test/src/tests/timeout_transfer.rs b/tools/integration-test/src/tests/timeout_transfer.rs deleted file mode 100644 index f1cf3edf3..000000000 --- a/tools/integration-test/src/tests/timeout_transfer.rs +++ /dev/null @@ -1,102 +0,0 @@ -//! Tests the capability of a full relayer instance to relay a timeout packet. -//! -//! This test ensures that a source chain that initiates an IBC transfer is -//! refunded the tokens that it sent in response to receiving a timeout packet -//! relayed by a full relayer. - -use hermes_relayer_components::birelay::traits::two_way::HasTwoWayRelay; -use hermes_relayer_components::relay::traits::packet_relayer::CanRelayPacket; -use ibc_relayer::config::PacketFilter; -use ibc_test_framework::framework::next::chain::{HasTwoChains, HasTwoChannels}; -use ibc_test_framework::prelude::*; -use ibc_test_framework::util::random::random_u64_range; - -use crate::tests::context::build_cosmos_relay_context; - -#[test] -fn test_ibc_transfer_timeout_next() -> Result<(), Error> { - run_binary_channel_test(&IbcTransferTest) -} - -pub struct IbcTransferTest; - -impl TestOverrides for IbcTransferTest { - fn should_spawn_supervisor(&self) -> bool { - false - } -} - -impl BinaryChannelTest for IbcTransferTest { - fn run(&self, relayer: RelayerDriver, context: &Context) -> Result<(), Error> - where - Context: HasTwoChains + HasTwoChannels, - { - let chains = context.chains(); - let channel = context.channel(); - let pf: PacketFilter = PacketFilter::default(); - - let relay_context = build_cosmos_relay_context(&relayer.config, chains, pf)?; - - let runtime = chains.node_a.value().chain_driver.runtime.as_ref(); - - let denom_a = chains.node_a.denom(); - - let wallet_a = chains.node_a.wallets().user1().cloned(); - let wallet_b = chains.node_b.wallets().user1().cloned(); - - let balance_a = chains - .node_a - .chain_driver() - .query_balance(&wallet_a.address(), &denom_a)?; - - let a_to_b_amount = random_u64_range(1000, 5000); - - info!( - "Sending IBC timeout from chain {} to chain {} with amount of {} {}", - chains.chain_id_a(), - chains.chain_id_b(), - a_to_b_amount, - denom_a - ); - - let packet = chains - .node_a - .chain_driver() - .ibc_transfer_token_with_memo_and_timeout( - &channel.port_a.as_ref(), - &channel.channel_id_a.as_ref(), - &wallet_a.as_ref(), - &wallet_b.address(), - &denom_a.with_amount(a_to_b_amount).as_ref(), - None, - Some(Duration::from_secs(1)), - )?; - - info!("running relayer"); - - sleep(Duration::from_secs(5)); - - runtime.block_on(async { - relay_context - .relay_a_to_b() - .relay_packet(&packet) - .await - .unwrap() - }); - - info!("finished running relayer"); - - chains - .node_a - .chain_driver() - .assert_eventual_wallet_amount(&wallet_a.address(), &balance_a.as_ref())?; - - info!( - "successfully refunded IBC transfer back to chain {} from chain {}", - chains.chain_id_a(), - chains.chain_id_b(), - ); - - Ok(()) - } -} diff --git a/tools/integration-test/src/tests/transfer.rs b/tools/integration-test/src/tests/transfer.rs deleted file mode 100644 index 864d79152..000000000 --- a/tools/integration-test/src/tests/transfer.rs +++ /dev/null @@ -1,145 +0,0 @@ -use std::thread::sleep; - -use cgp::extra::run::CanRun; -use ibc_relayer::config::PacketFilter; -use ibc_test_framework::framework::next::chain::{HasTwoChains, HasTwoChannels}; -use ibc_test_framework::ibc::denom::derive_ibc_denom; -use ibc_test_framework::prelude::*; -use ibc_test_framework::util::random::random_u64_range; - -use crate::tests::context::build_cosmos_relay_context; - -#[test] -fn test_ibc_transfer_next() -> Result<(), Error> { - run_binary_channel_test(&IbcTransferTest) -} - -pub struct IbcTransferTest; - -impl TestOverrides for IbcTransferTest { - fn should_spawn_supervisor(&self) -> bool { - false - } -} - -impl BinaryChannelTest for IbcTransferTest { - fn run(&self, relayer: RelayerDriver, context: &Context) -> Result<(), Error> - where - Context: HasTwoChains + HasTwoChannels, - { - let chains = context.chains(); - let channel = context.channel(); - let pf: PacketFilter = PacketFilter::default(); - - let relay_context = build_cosmos_relay_context(&relayer.config, chains, pf)?; - - let runtime = chains.node_a.value().chain_driver.runtime.as_ref(); - - runtime.spawn(async move { - let _ = relay_context.run().await; - }); - - let denom_a = chains.node_a.denom(); - - let wallet_a = chains.node_a.wallets().user1().cloned(); - let wallet_b = chains.node_b.wallets().user1().cloned(); - let wallet_c = chains.node_a.wallets().user2().cloned(); - - let balance_a = chains - .node_a - .chain_driver() - .query_balance(&wallet_a.address(), &denom_a)?; - - let a_to_b_amount = random_u64_range(1000, 5000); - - info!( - "Sending IBC transfer from chain {} to chain {} with amount of {} {}", - chains.chain_id_a(), - chains.chain_id_b(), - a_to_b_amount, - denom_a - ); - - chains.node_a.chain_driver().ibc_transfer_token( - &channel.port_a.as_ref(), - &channel.channel_id_a.as_ref(), - &wallet_a.as_ref(), - &wallet_b.address(), - &denom_a.with_amount(a_to_b_amount).as_ref(), - )?; - - let denom_b = derive_ibc_denom( - &channel.port_b.as_ref(), - &channel.channel_id_b.as_ref(), - &denom_a, - )?; - - info!( - "Waiting for user on chain B to receive IBC transferred amount of {} {}", - a_to_b_amount, denom_b - ); - - chains.node_a.chain_driver().assert_eventual_wallet_amount( - &wallet_a.address(), - &(balance_a - a_to_b_amount).as_ref(), - )?; - - chains.node_b.chain_driver().assert_eventual_wallet_amount( - &wallet_b.address(), - &denom_b.with_amount(a_to_b_amount).as_ref(), - )?; - - info!( - "successfully performed IBC transfer from chain {} to chain {}", - chains.chain_id_a(), - chains.chain_id_b(), - ); - - let balance_c = chains - .node_a - .chain_driver() - .query_balance(&wallet_c.address(), &denom_a)?; - - let b_to_a_amount = random_u64_range(500, a_to_b_amount); - - info!( - "Sending IBC transfer from chain {} to chain {} with amount of {}", - chains.chain_id_b(), - chains.chain_id_a(), - b_to_a_amount, - ); - - chains.node_b.chain_driver().ibc_transfer_token( - &channel.port_b.as_ref(), - &channel.channel_id_b.as_ref(), - &wallet_b.as_ref(), - &wallet_c.address(), - &denom_b.with_amount(b_to_a_amount).as_ref(), - )?; - - info!( - "Waiting for user on chain A to receive IBC transferred amount of {} {}", - b_to_a_amount, denom_a - ); - - chains.node_b.chain_driver().assert_eventual_wallet_amount( - &wallet_b.address(), - &denom_b.with_amount(a_to_b_amount - b_to_a_amount).as_ref(), - )?; - - chains.node_a.chain_driver().assert_eventual_wallet_amount( - &wallet_c.address(), - &(balance_c + b_to_a_amount).as_ref(), - )?; - - info!( - "successfully performed reverse IBC transfer from chain {} back to chain {}", - chains.chain_id_b(), - chains.chain_id_a(), - ); - - sleep(Duration::from_secs(2)); - - Ok(()) - } -} diff --git a/tools/test-framework/.gitignore b/tools/test-framework/.gitignore deleted file mode 100644 index 8fce60300..000000000 --- a/tools/test-framework/.gitignore +++ /dev/null @@ -1 +0,0 @@ -data/ diff --git a/tools/test-framework/Cargo.toml b/tools/test-framework/Cargo.toml deleted file mode 100644 index 6eabe06b4..000000000 --- a/tools/test-framework/Cargo.toml +++ /dev/null @@ -1,49 +0,0 @@ -[package] -name = "ibc-test-framework" -version = { workspace = true } -edition = { workspace = true } -license = { workspace = true } -keywords = { workspace = true } -repository = { workspace = true } -authors = { workspace = true } -rust-version = { workspace = true } -readme = "README.md" -description = """ - Framework for writing integration tests for IBC relayers -""" - -[dependencies] -cgp = { workspace = true } -hermes-runtime-components = { workspace = true } -hermes-relayer-components = { workspace = true } -hermes-cosmos-relayer = { workspace = true } - -ibc-relayer-types = { workspace = true } -ibc-relayer = { workspace = true } -ibc-proto = { workspace = true, features = ["serde"] } -tendermint-rpc = { workspace = true, features = ["http-client", "websocket-client"] } - -http = { workspace = true } -tokio = { workspace = true, features = ["full"] } -tracing = { workspace = true } -eyre = { workspace = true } -flex-error = { workspace = true } -itertools = { workspace = true } -prost = { workspace = true } -serde = { workspace = true } -serde_json = { workspace = true } -tonic = { workspace = true, features = ["tls", "tls-roots"] } - -color-eyre = "0.6" -cfg-if = "1.0.0" -rand = "0.8.5" -hex = "0.4.3" -serde_yaml = "0.9.34" -toml = "0.8" -subtle-encoding = "0.5.1" -sha2 = "0.10.6" -crossbeam-channel = "0.5.13" -semver = "1.0.21" -tracing-subscriber = { version = "0.3.17", features = [ "env-filter" ] } -hdpath = "0.6.3" -once_cell = "1.20.2" diff --git a/tools/test-framework/README.md b/tools/test-framework/README.md deleted file mode 100644 index 32ac79cd2..000000000 --- a/tools/test-framework/README.md +++ /dev/null @@ -1,27 +0,0 @@ -# IBC Relayer Integration Test Framework - -## Overview - -The `ibc-test-framework` crate provides the infrastructure and framework for writing end-to-end (E2E) tests that include the spawning of the relayer together with Cosmos full nodes running as child processes inside the tests. - -## Installation - -Other than Rust, the test suite assumes the `gaiad` binary is present in `$PATH`. You can install Gaia by either [building from source](https://github.com/cosmos/gaia), or load it using [Cosmos.nix](https://github.com/informalsystems/cosmos.nix/): - -```text -nix shell github:informalsystems/cosmos.nix#gaia11 -``` - -Alternatively, you can use `$CHAIN_COMMAND_PATH` to override with a different executable that is compatible with `gaiad`. - -## Examples - -Example tests written using `ibc-test-framework` can be found in the [`ibc-rs` project repository](https://github.com/informalsystems/hermes/tree/master/tools/integration-test) - -## Diagrams - -Some diagrams have been prepared to ease the understanding of the test framework: - -- [Tagged Identifiers and Data Structures](https://app.excalidraw.com/l/4XqkU6POmGI/7za2eSTChuT) -- [Test Data Structures](https://app.excalidraw.com/l/4XqkU6POmGI/5y6i0NKqiEv) -- [Test Framework Traits](https://app.excalidraw.com/l/4XqkU6POmGI/80KAnVZ6cu4) diff --git a/tools/test-framework/src/bootstrap/binary/chain.rs b/tools/test-framework/src/bootstrap/binary/chain.rs deleted file mode 100644 index 8e62eab5f..000000000 --- a/tools/test-framework/src/bootstrap/binary/chain.rs +++ /dev/null @@ -1,311 +0,0 @@ -/*! - Helper functions for bootstrapping two relayer chain handles - with connected foreign clients. -*/ - -use std::path::Path; -use std::time::Duration; -use std::{fs, thread}; - -use eyre::Report as Error; -use ibc_relayer::chain::handle::{ChainHandle, CountingAndCachingChainHandle}; -use ibc_relayer::config::Config; -use ibc_relayer::error::ErrorDetail as RelayerErrorDetail; -use ibc_relayer::foreign_client::{ - extract_client_id, CreateOptions as ClientOptions, ForeignClient, -}; -use ibc_relayer::keyring::errors::ErrorDetail as KeyringErrorDetail; -use ibc_relayer::registry::SharedRegistry; -use ibc_relayer_types::core::ics24_host::identifier::ClientId; -use tracing::{debug, info}; - -use crate::relayer::driver::RelayerDriver; -use crate::types::binary::chains::ConnectedChains; -use crate::types::binary::foreign_client::ForeignClientPair; -use crate::types::config::TestConfig; -use crate::types::single::node::FullNode; -use crate::types::tagged::*; -use crate::types::wallet::{TestWallets, Wallet}; -use crate::util::random::random_u64_range; - -#[derive(Default)] -pub struct BootstrapClientOptions { - pub client_options_a_to_b: ClientOptions, - pub client_options_b_to_a: ClientOptions, - pub pad_client_id_a_to_b: u64, - pub pad_client_id_b_to_a: u64, -} - -/// Bootstraps two relayer chain handles with connected foreign clients. -/// -/// Returns a tuple consisting of the [`RelayerDriver`] and a -/// [`ConnectedChains`] object that contains the given -/// full nodes together with the corresponding two [`ChainHandle`]s and -/// [`ForeignClient`]s. -pub fn bootstrap_chains_with_full_nodes( - test_config: &TestConfig, - node_a: FullNode, - node_b: FullNode, - options: BootstrapClientOptions, - config_modifier: impl FnOnce(&mut Config), -) -> Result< - ( - RelayerDriver, - ConnectedChains, - ), - Error, -> { - let mut config = Config::default(); - - add_chain_config(&mut config, &node_a, test_config)?; - add_chain_config(&mut config, &node_b, test_config)?; - - config_modifier(&mut config); - - let config_path = test_config.chain_store_dir.join("relayer-config.toml"); - - save_relayer_config(&config, &config_path)?; - - let registry = new_registry(config.clone()); - - // Pass in unique closure expressions `||{}` as the first argument so that - // the returned chains are considered different types by Rust. - // See [`spawn_chain_handle`] for more details. - let handle_a = spawn_chain_handle(|| {}, ®istry, &node_a)?; - let handle_b = spawn_chain_handle(|| {}, ®istry, &node_b)?; - - // Wait for the chain handles to be spawned - thread::sleep(Duration::from_secs(10)); - - pad_client_ids(&handle_a, &handle_b, options.pad_client_id_a_to_b)?; - pad_client_ids(&handle_b, &handle_a, options.pad_client_id_b_to_a)?; - - let foreign_clients = bootstrap_foreign_client_pair(&handle_a, &handle_b, options)?; - - let relayer = RelayerDriver { - config_path, - config, - registry, - hang_on_fail: test_config.hang_on_fail, - }; - - let chains = ConnectedChains::new( - handle_a, - handle_b, - MonoTagged::new(node_a), - MonoTagged::new(node_b), - foreign_clients, - ); - - Ok((relayer, chains)) -} - -/// Bootstraps two relayer chain handles with connected foreign clients. -/// -/// Returns a tuple consisting of the [`RelayerDriver`] and a -/// [`ConnectedChains`] object that contains the given -/// full nodes together with the corresponding two [`ChainHandle`]s and -/// [`ForeignClient`]s. -/// -/// This method gives the caller a way to modify the relayer configuration -/// that is pre-generated from the configurations of the full nodes. -pub fn bootstrap_foreign_client_pair( - chain_a: &ChainA, - chain_b: &ChainB, - options: BootstrapClientOptions, -) -> Result, Error> { - let client_a_to_b = bootstrap_foreign_client(chain_a, chain_b, options.client_options_a_to_b)?; - let client_b_to_a = bootstrap_foreign_client(chain_b, chain_a, options.client_options_b_to_a)?; - Ok(ForeignClientPair::new(client_a_to_b, client_b_to_a)) -} - -pub fn bootstrap_foreign_client( - chain_a: &ChainA, - chain_b: &ChainB, - client_options: ClientOptions, -) -> Result, Error> { - let foreign_client = - ForeignClient::restore(ClientId::default(), chain_b.clone(), chain_a.clone()); - - let event = foreign_client.build_create_client_and_send(client_options)?; - let client_id = extract_client_id(&event.event)?.clone(); - - info!( - "created foreign client from chain {} to chain {} with client id {} on chain {}", - chain_a.id(), - chain_b.id(), - client_id, - chain_b.id() - ); - - Ok(ForeignClient::restore( - client_id, - chain_b.clone(), - chain_a.clone(), - )) -} - -pub fn pad_client_ids( - chain_a: &ChainA, - chain_b: &ChainB, - pad_count: u64, -) -> Result<(), Error> { - let foreign_client = - ForeignClient::restore(ClientId::default(), chain_b.clone(), chain_a.clone()); - - for i in 0..pad_count { - debug!("creating new client id {} on chain {}", i + 1, chain_b.id()); - foreign_client.build_create_client_and_send(Default::default())?; - } - - Ok(()) -} - -/** - Spawn a new chain handle using the given [`SharedRegistry`] and - [`FullNode`]. - - The function accepts a proxy type `Seed` that should be unique - accross multiple calls so that the returned [`ChainHandle`] - have a unique type. - - For example, the following test should fail to compile: - - ```rust,compile_fail - # use ibc_test_framework::bootstrap::binary::chain::spawn_chain_handle; - fn same(_: T, _: T) {} - - let chain_a = spawn_chain_handle(|| {}, todo!(), todo!()).unwrap(); - let chain_b = spawn_chain_handle(|| {}, todo!(), todo!()).unwrap(); - same(chain_a, chain_b); // error: chain_a and chain_b have different types - ``` - - The reason is that Rust would give each closure expression `||{}` a - [unique anonymous type](https://doc.rust-lang.org/reference/types/closure.html). - When we instantiate two chains with different closure types, - the resulting values would be considered by Rust to have different types. - - With this we can treat `chain_a` and `chain_b` having different types - so that we do not accidentally mix them up later in the code. -*/ -pub fn spawn_chain_handle( - _: Seed, - registry: &SharedRegistry, - node: &FullNode, -) -> Result { - let chain_id = &node.chain_driver.chain_id; - let handle = registry.get_or_spawn(chain_id)?; - - add_keys_to_chain_handle(&handle, &node.wallets)?; - - Ok(handle) -} - -/** - Add a wallet key to a [`ChainHandle`]'s key store. - - Note that if the [`ChainConfig`](ibc_relayer::config::ChainConfig) is - configured to use in-memory store only, the added key would not be - accessible through external CLI. -*/ -pub fn add_key_to_chain_handle( - chain: &Chain, - wallet: &Wallet, -) -> Result<(), Error> { - let res = chain.add_key(wallet.id.0.clone(), wallet.key.clone().into()); - - // Ignore error if chain handle already have the given key - match res { - Err(e) => match e.detail() { - RelayerErrorDetail::KeyBase(e2) => match e2.source { - KeyringErrorDetail::KeyAlreadyExist(_) => Ok(()), - _ => Err(e.into()), - }, - _ => Err(e.into()), - }, - Ok(()) => Ok(()), - } -} - -/** - Add multiple wallets provided in [`TestWallets`] into the - [`ChainHandle`]'s key store. -*/ -pub fn add_keys_to_chain_handle( - chain: &Chain, - wallets: &TestWallets, -) -> Result<(), Error> { - add_key_to_chain_handle(chain, &wallets.relayer)?; - add_key_to_chain_handle(chain, &wallets.user1)?; - add_key_to_chain_handle(chain, &wallets.user2)?; - - Ok(()) -} - -/** - Create a new [`SharedRegistry`] that uses [`CountingAndCachingChainHandle`] - as the [`ChainHandle`] implementation. -*/ -pub fn new_registry(config: Config) -> SharedRegistry { - >::new(config) -} - -/** - Generate [`ChainConfig`](ibc_relayer::config::ChainConfig) from a running - [`FullNode`] and add it to the relayer's [`Config`]. -*/ -pub fn add_chain_config( - config: &mut Config, - running_node: &FullNode, - test_config: &TestConfig, -) -> Result<(), Error> { - let chain_config = - running_node.generate_chain_config(&running_node.chain_driver.chain_type, test_config)?; - - config.chains.push(chain_config); - Ok(()) -} - -/** - Save a relayer's [`Config`] to the filesystem to make it accessible - through external CLI. -*/ -pub fn save_relayer_config(config: &Config, config_path: &Path) -> Result<(), Error> { - let config_str = toml::to_string_pretty(&config)?; - - fs::write(config_path, &config_str)?; - - info!( - "written hermes config.toml to {}:\n{}", - config_path.display(), - config_str - ); - - Ok(()) -} - -impl BootstrapClientOptions { - /// Overrides options for the foreign client connecting chain A to chain B. - pub fn client_options_a_to_b(mut self, options: ClientOptions) -> Self { - self.client_options_a_to_b = options; - self - } - - /// Overrides options for the foreign client connecting chain B to chain A. - pub fn client_options_b_to_a(mut self, options: ClientOptions) -> Self { - self.client_options_b_to_a = options; - self - } - - pub fn bootstrap_with_random_ids(mut self, bootstrap_with_random_ids: bool) -> Self { - if bootstrap_with_random_ids { - self.pad_client_id_b_to_a = random_u64_range(1, 6); - self.pad_client_id_a_to_b = random_u64_range(1, 6); - } else { - self.pad_client_id_b_to_a = 0; - self.pad_client_id_a_to_b = 1; - } - - self - } -} diff --git a/tools/test-framework/src/bootstrap/binary/channel.rs b/tools/test-framework/src/bootstrap/binary/channel.rs deleted file mode 100644 index 4b1439568..000000000 --- a/tools/test-framework/src/bootstrap/binary/channel.rs +++ /dev/null @@ -1,233 +0,0 @@ -/*! - Helper functions for bootstrapping a channel between two chains. -*/ - -use eyre::{eyre, Report as Error}; -use ibc_relayer::chain::handle::ChainHandle; -use ibc_relayer::channel::{Channel, ChannelSide}; -use ibc_relayer_types::core::ics04_channel::channel::Ordering; -use ibc_relayer_types::core::ics04_channel::version::Version; -use ibc_relayer_types::core::ics24_host::identifier::PortId; -use tracing::{debug, info}; - -use super::connection::{bootstrap_connection, BootstrapConnectionOptions}; -use crate::types::binary::chains::ConnectedChains; -use crate::types::binary::channel::ConnectedChannel; -use crate::types::binary::connection::ConnectedConnection; -use crate::types::binary::foreign_client::ForeignClientPair; -use crate::types::id::TaggedPortIdRef; -use crate::types::tagged::*; -use crate::util::random::random_u64_range; - -pub struct BootstrapChannelOptions { - pub order: Ordering, - pub version: Version, - pub pad_channel_id_a: u64, - pub pad_channel_id_b: u64, -} - -/** - Create a new [`ConnectedChannel`] based on the provided [`ConnectedChains`]. - - Also accepts the [`PortId`] that should be used for the two sides of the - channel. -*/ -pub fn bootstrap_channel_with_chains( - chains: &ConnectedChains, - port_a: &PortId, - port_b: &PortId, - connection_options: BootstrapConnectionOptions, - channel_options: BootstrapChannelOptions, -) -> Result, Error> { - let channel = bootstrap_channel( - &chains.foreign_clients, - &DualTagged::new(port_a), - &DualTagged::new(port_b), - connection_options, - channel_options, - )?; - - Ok(channel) -} - -/** - Create a new [`ConnectedChannel`] between two chains using foreign clients - with initialized client IDs. -*/ -pub fn bootstrap_channel( - foreign_clients: &ForeignClientPair, - port_a: &TaggedPortIdRef, - port_b: &TaggedPortIdRef, - connection_options: BootstrapConnectionOptions, - channel_options: BootstrapChannelOptions, -) -> Result, Error> { - let connection = bootstrap_connection(foreign_clients, connection_options)?; - - bootstrap_channel_with_connection( - &foreign_clients.handle_a(), - &foreign_clients.handle_b(), - connection, - port_a, - port_b, - channel_options, - ) -} - -/** - Create a new [`ConnectedChannel`] using existing [`ConnectedConnection`]. -*/ -pub fn bootstrap_channel_with_connection( - chain_a: &ChainA, - chain_b: &ChainB, - connection: ConnectedConnection, - port_a: &TaggedPortIdRef, - port_b: &TaggedPortIdRef, - options: BootstrapChannelOptions, -) -> Result, Error> { - pad_channel_id( - chain_a, - chain_b, - &connection, - port_a, - options.pad_channel_id_a, - )?; - pad_channel_id( - chain_b, - chain_a, - &connection.clone().flip(), - port_b, - options.pad_channel_id_b, - )?; - - let channel = Channel::new( - connection.connection.clone(), - options.order, - port_a.0.clone(), - port_b.0.clone(), - Some(options.version), - )?; - - let channel_id_a = channel - .a_side - .channel_id() - .ok_or_else(|| eyre!("expect channel id"))? - .clone(); - - let channel_id_b = channel - .b_side - .channel_id() - .ok_or_else(|| eyre!("expect channel id"))? - .clone(); - - info!( - "created new chain/client/connection/channel from {}/{}/{}/{} to {}/{}/{}/{}", - chain_a.id(), - connection.client_ids.client_id_a, - connection.connection_id_a, - channel_id_a, - chain_b.id(), - connection.client_ids.client_id_b, - connection.connection_id_b, - channel_id_b, - ); - - let res = ConnectedChannel { - connection, - channel, - channel_id_a: DualTagged::new(channel_id_a), - channel_id_b: DualTagged::new(channel_id_b), - port_a: port_a.cloned(), - port_b: port_b.cloned(), - }; - - Ok(res) -} - -/** - Create a random number of dummy channel IDs so that the bootstrapped - channel ID is random instead of being always `channel-0`. - - This would help us catch bugs where the channel IDs are used at - the wrong side of the chain, but still got accepted because the - channel IDs on both sides are the same. -*/ -pub fn pad_channel_id( - chain_a: &ChainA, - chain_b: &ChainB, - connection: &ConnectedConnection, - port_id: &TaggedPortIdRef, - pad_count: u64, -) -> Result<(), Error> { - let client_id_a = &connection.client_ids.client_id_a; - let client_id_b = &connection.client_ids.client_id_b; - - for i in 0..pad_count { - debug!( - "creating new channel id {} on chain/connection/client {}/{}/{}", - i + 1, - chain_a.id(), - connection.connection_id_a, - client_id_a, - ); - - let channel: Channel = Channel { - ordering: Ordering::Unordered, - a_side: ChannelSide::new( - chain_b.clone(), - client_id_b.value().clone(), - connection.connection_id_b.value().clone(), - port_id.cloned().into_value(), - None, - None, - ), - b_side: ChannelSide::new( - chain_a.clone(), - client_id_a.value().clone(), - connection.connection_id_a.value().clone(), - port_id.cloned().into_value(), - None, - None, - ), - connection_delay: connection.connection.delay_period, - }; - - channel.build_chan_open_init_and_send()?; - } - - Ok(()) -} - -impl Default for BootstrapChannelOptions { - fn default() -> Self { - Self { - order: Ordering::Unordered, - version: Version::ics20(), - pad_channel_id_a: 0, - pad_channel_id_b: 1, - } - } -} - -impl BootstrapChannelOptions { - pub fn order(mut self, order: Ordering) -> Self { - self.order = order; - self - } - - pub fn version(mut self, version: Version) -> Self { - self.version = version; - self - } - - pub fn bootstrap_with_random_ids(mut self, bootstrap_with_random_ids: bool) -> Self { - if bootstrap_with_random_ids { - self.pad_channel_id_a = random_u64_range(0, 6); - self.pad_channel_id_b = random_u64_range(0, 6); - } else { - self.pad_channel_id_a = 0; - self.pad_channel_id_b = 1; - } - - self - } -} diff --git a/tools/test-framework/src/bootstrap/binary/connection.rs b/tools/test-framework/src/bootstrap/binary/connection.rs deleted file mode 100644 index c287cd50e..000000000 --- a/tools/test-framework/src/bootstrap/binary/connection.rs +++ /dev/null @@ -1,153 +0,0 @@ -/*! - Helper functions for bootstrapping a connection between two chains. -*/ - -use core::time::Duration; - -use eyre::{eyre, Report as Error}; -use ibc_relayer::chain::handle::ChainHandle; -use ibc_relayer::config::default::connection_delay as default_connection_delay; -use ibc_relayer::connection::{Connection, ConnectionSide}; -use ibc_relayer_types::timestamp::ZERO_DURATION; -use tracing::{debug, info}; - -use crate::relayer::connection::TaggedConnectionExt; -use crate::types::binary::client::ClientIdPair; -use crate::types::binary::connection::ConnectedConnection; -use crate::types::binary::foreign_client::ForeignClientPair; -use crate::types::id::TaggedClientIdRef; -use crate::util::random::random_u64_range; - -pub struct BootstrapConnectionOptions { - pub connection_delay: Duration, - pub pad_connection_id_a: u64, - pub pad_connection_id_b: u64, -} - -/** - Create a new [`ConnectedConnection`] using the foreign clients with - initialized client IDs. -*/ -pub fn bootstrap_connection( - foreign_clients: &ForeignClientPair, - options: BootstrapConnectionOptions, -) -> Result, Error> { - let chain_a = foreign_clients.handle_a(); - let chain_b = foreign_clients.handle_b(); - - let client_id_a = foreign_clients.client_id_a(); - let client_id_b = foreign_clients.client_id_b(); - - pad_connection_id( - &chain_a, - &chain_b, - &client_id_a, - &client_id_b, - options.pad_connection_id_a, - )?; - pad_connection_id( - &chain_b, - &chain_a, - &client_id_b, - &client_id_a, - options.pad_connection_id_b, - )?; - - let connection = Connection::new( - foreign_clients.client_b_to_a.clone(), - foreign_clients.client_a_to_b.clone(), - options.connection_delay, - )?; - - let connection_id_a = connection - .tagged_connection_id_a() - .ok_or_else(|| eyre!("expected connection id to present"))? - .cloned(); - - let connection_id_b = connection - .tagged_connection_id_b() - .ok_or_else(|| eyre!("expected connection id to present"))? - .cloned(); - - info!( - "created new chain/client/connection from {}/{}/{} to {}/{}/{}", - chain_a.id(), - client_id_a, - connection_id_a, - chain_b.id(), - client_id_b, - connection_id_b, - ); - - let connected_connection = ConnectedConnection::new( - ClientIdPair::new(client_id_a.cloned(), client_id_b.cloned()), - connection, - connection_id_a, - connection_id_b, - ); - - Ok(connected_connection) -} - -/** - Create a random number of dummy connection IDs so that the bootstrapped - connection ID is random instead of being always `connection-0`. - - This would help us catch bugs where the connection IDs are used at - the wrong side of the chain, but still got accepted because the - connection IDs on both sides are the same. -*/ -pub fn pad_connection_id( - chain_a: &ChainA, - chain_b: &ChainB, - client_id_a: &TaggedClientIdRef, - client_id_b: &TaggedClientIdRef, - pad_count: u64, -) -> Result<(), Error> { - for i in 0..pad_count { - debug!( - "creating new connection id {} on chain {}", - i + 1, - chain_a.id() - ); - - let connection: Connection = Connection { - delay_period: ZERO_DURATION, - a_side: ConnectionSide::new(chain_b.clone(), client_id_b.cloned().into_value(), None), - b_side: ConnectionSide::new(chain_a.clone(), client_id_a.cloned().into_value(), None), - }; - - connection.build_conn_init_and_send()?; - } - - Ok(()) -} - -impl Default for BootstrapConnectionOptions { - fn default() -> Self { - Self { - connection_delay: default_connection_delay(), - pad_connection_id_a: 0, - pad_connection_id_b: 0, - } - } -} - -impl BootstrapConnectionOptions { - pub fn connection_delay(mut self, connection_delay: Duration) -> Self { - self.connection_delay = connection_delay; - self - } - - pub fn bootstrap_with_random_ids(mut self, bootstrap_with_random_ids: bool) -> Self { - if bootstrap_with_random_ids { - self.pad_connection_id_a = random_u64_range(0, 6); - self.pad_connection_id_b = random_u64_range(0, 6); - } else { - self.pad_connection_id_a = 0; - self.pad_connection_id_b = 1; - } - - self - } -} diff --git a/tools/test-framework/src/bootstrap/binary/mod.rs b/tools/test-framework/src/bootstrap/binary/mod.rs deleted file mode 100644 index 5cf48e941..000000000 --- a/tools/test-framework/src/bootstrap/binary/mod.rs +++ /dev/null @@ -1,7 +0,0 @@ -/*! - Helper functions for bootstrapping constructs that involve two chains. -*/ - -pub mod chain; -pub mod channel; -pub mod connection; diff --git a/tools/test-framework/src/bootstrap/consumer.rs b/tools/test-framework/src/bootstrap/consumer.rs deleted file mode 100644 index 39cc9748a..000000000 --- a/tools/test-framework/src/bootstrap/consumer.rs +++ /dev/null @@ -1,137 +0,0 @@ -/*! -Helper functions for bootstrapping a consumer full node. -*/ -use std::sync::{Arc, RwLock}; -use std::thread; -use std::time::Duration; - -use eyre::eyre; -use toml; -use tracing::info; - -use crate::chain::builder::ChainBuilder; -use crate::chain::config; -use crate::chain::ext::bootstrap::ChainBootstrapMethodsExt; -use crate::error::Error; -use crate::prelude::{ChainDriver, Denom, FullNode, TestWallets, Token}; -use crate::util::random::random_u128_range; - -pub fn bootstrap_consumer_node( - builder: &ChainBuilder, - prefix: &str, - node_a: &FullNode, - config_modifier: impl FnOnce(&mut toml::Value) -> Result<(), Error>, - genesis_modifier: impl FnOnce(&mut serde_json::Value) -> Result<(), Error>, - chain_number: usize, - provider_chain_driver: &ChainDriver, -) -> Result { - let stake_denom = Denom::base("stake"); - - let denom = Denom::base("samoleans"); - - 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 - .clone() - .checked_add(1_000_000_000_000u64) - .ok_or(Error::generic(eyre!( - "error creating initial stake with additional amount" - )))?; - - let initial_coin = Token::new(denom.clone(), initial_amount); - let chain_driver = builder.new_chain(prefix, false, chain_number)?; - - chain_driver.initialize()?; - - let validator = chain_driver.add_wallet("validator")?; - let relayer = chain_driver.add_wallet("relayer")?; - let user1 = chain_driver.add_wallet("user1")?; - let user2 = chain_driver.add_wallet("user2")?; - - chain_driver.add_genesis_account(&validator.address, &[&additional_initial_stake])?; - chain_driver.add_genesis_account(&relayer.address, &[&initial_stake, &initial_coin])?; - chain_driver.add_genesis_account(&user1.address, &[&initial_stake, &initial_coin])?; - chain_driver.add_genesis_account(&user2.address, &[&initial_stake, &initial_coin])?; - - // Wait for the consumer chain to be initialized before querying the genesis - thread::sleep(Duration::from_secs(30)); - - node_a - .chain_driver - .query_consumer_genesis(&chain_driver, chain_driver.chain_id.as_str())?; - - chain_driver.replace_genesis_state()?; - - chain_driver.update_genesis_file("genesis.json", genesis_modifier)?; - // The configuration `soft_opt_out_threshold` might be missing and is required - // for chains such as Neutron - chain_driver.update_genesis_file("genesis.json", |genesis| { - config::set_soft_opt_out_threshold(genesis, "0.05")?; - Ok(()) - })?; - - let log_level = std::env::var("CHAIN_LOG_LEVEL").unwrap_or_else(|_| "info".to_string()); - - chain_driver.update_chain_config("config.toml", |config| { - config::set_log_level(config, &log_level)?; - config::set_rpc_port(config, chain_driver.rpc_port)?; - config::set_p2p_port(config, chain_driver.p2p_port)?; - config::set_pprof_port(config, chain_driver.pprof_port)?; - config::set_timeout_commit(config, Duration::from_secs(1))?; - config::set_timeout_propose(config, Duration::from_secs(1))?; - config::set_mode(config, "validator")?; - - config_modifier(config)?; - - Ok(()) - })?; - - 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")?; - - Ok(()) - })?; - - chain_driver.copy_validator_key_pair(provider_chain_driver)?; - - let process = chain_driver.start()?; - - info!( - "started new chain {} at with home path {} and RPC address {}.", - chain_driver.chain_id, - chain_driver.home_path, - chain_driver.rpc_address(), - ); - - info!( - "user wallet for chain {} - id: {}, address: {}", - chain_driver.chain_id, user1.id.0, user1.address.0, - ); - - info!( - "you can manually interact with the chain using commands starting with:\n{} --home '{}' --node {}", - chain_driver.command_path, - chain_driver.home_path, - chain_driver.rpc_address(), - ); - - let wallets = TestWallets { - validator, - relayer, - user1, - user2, - }; - - let node = FullNode { - chain_driver, - denom, - wallets, - process: Arc::new(RwLock::new(process)), - }; - - Ok(node) -} diff --git a/tools/test-framework/src/bootstrap/init.rs b/tools/test-framework/src/bootstrap/init.rs deleted file mode 100644 index 4179549d8..000000000 --- a/tools/test-framework/src/bootstrap/init.rs +++ /dev/null @@ -1,94 +0,0 @@ -/*! - Functions for initializing each test at the beginning of a Rust test - session. -*/ - -use std::sync::Once; -use std::{env, fs}; - -use eyre::Report as Error; -use tracing_subscriber::filter::{EnvFilter, LevelFilter}; -use tracing_subscriber::layer::SubscriberExt; -use tracing_subscriber::util::SubscriberInitExt; -use tracing_subscriber::{self as ts}; - -use crate::types::config::TestConfig; -use crate::util::random::random_u32; - -static INIT: Once = Once::new(); - -/** - Initialize the test with a global logger and error handlers, - read the environment variables and return a [`TestConfig`]. -*/ -pub fn init_test() -> Result { - let no_color_log = env::var("NO_COLOR_LOG") - .ok() - .map(|val| val == "1") - .unwrap_or(false); - - INIT.call_once(|| { - if enable_ansi() && !no_color_log { - color_eyre::install().unwrap(); - } - install_logger(!no_color_log); - }); - - let chain_command_path = - env::var("CHAIN_COMMAND_PATHS").unwrap_or_else(|_| "gaiad".to_string()); - - let chain_command_paths = parse_chain_command_paths(chain_command_path); - - let base_chain_store_dir = env::var("CHAIN_STORE_DIR").unwrap_or_else(|_| "data".to_string()); - - let account_prefix = env::var("ACCOUNT_PREFIXES").unwrap_or_else(|_| "cosmos".to_string()); - - let account_prefixes = parse_chain_command_paths(account_prefix); - - let chain_store_dir = format!("{}/test-{}", base_chain_store_dir, random_u32()); - - fs::create_dir_all(&chain_store_dir)?; - - let chain_store_dir = fs::canonicalize(chain_store_dir)?; - - let hang_on_fail = env::var("HANG_ON_FAIL") - .ok() - .map(|val| val == "1") - .unwrap_or(false); - - Ok(TestConfig { - chain_command_paths, - chain_store_dir, - account_prefixes, - hang_on_fail, - bootstrap_with_random_ids: false, - }) -} - -fn parse_chain_command_paths(chain_command_path: String) -> Vec { - let patterns: Vec = chain_command_path - .split(',') - .map(|chain_binary| chain_binary.to_string()) - .collect(); - patterns -} - -/** - Install the [`tracing_subscriber`] logger handlers so that logs will - be displayed during test. -*/ -pub fn install_logger(with_color: bool) { - // Use log level INFO by default if RUST_LOG is not set. - let env_filter = EnvFilter::builder() - .with_default_directive(LevelFilter::INFO.into()) - .from_env_lossy(); - - let layer = ts::fmt::layer().with_ansi(with_color); - - ts::registry().with(env_filter).with(layer).init(); -} - -pub fn enable_ansi() -> bool { - use std::io::IsTerminal; - std::io::stdout().is_terminal() && std::io::stderr().is_terminal() -} diff --git a/tools/test-framework/src/bootstrap/mod.rs b/tools/test-framework/src/bootstrap/mod.rs deleted file mode 100644 index 17216d945..000000000 --- a/tools/test-framework/src/bootstrap/mod.rs +++ /dev/null @@ -1,18 +0,0 @@ -/*! - Helper functions for setting up test cases in an imperative way. - - Normal test authors should have no need to call functions provided - by the `bootstrap` module, as they are implicitly called by the - [`framework`](crate::framework) constructs. - - Advanced test authors with needs for more flexibility can call - functions in the `bootstrap` module directly, so that they have - more control of when exactly new chains and relayers should - be spawned. -*/ - -pub mod binary; -pub mod consumer; -pub mod init; -pub mod nary; -pub mod single; diff --git a/tools/test-framework/src/bootstrap/nary/chain.rs b/tools/test-framework/src/bootstrap/nary/chain.rs deleted file mode 100644 index 1f812c780..000000000 --- a/tools/test-framework/src/bootstrap/nary/chain.rs +++ /dev/null @@ -1,120 +0,0 @@ -/*! - Functions for bootstrapping N-ary number of chains. -*/ - -use core::convert::TryInto; - -use ibc_relayer::chain::handle::ChainHandle; -use ibc_relayer::config::Config; -use ibc_relayer::foreign_client::ForeignClient; -use ibc_relayer::registry::SharedRegistry; - -use crate::bootstrap::binary::chain::{ - add_chain_config, add_keys_to_chain_handle, bootstrap_foreign_client, new_registry, - save_relayer_config, -}; -use crate::error::{handle_generic_error, Error}; -use crate::relayer::driver::RelayerDriver; -use crate::types::config::TestConfig; -use crate::types::nary::chains::{DynamicConnectedChains, NaryConnectedChains}; -use crate::types::single::node::FullNode; - -/** - Bootstrap a fixed number of chains specified by `SIZE`. -*/ -pub fn boostrap_chains_with_nodes( - test_config: &TestConfig, - full_nodes: [FullNode; SIZE], - config_modifier: impl FnOnce(&mut Config), -) -> Result<(RelayerDriver, NaryConnectedChains), Error> { - let (relayer, chains) = - boostrap_chains_with_any_nodes(test_config, full_nodes.into(), config_modifier)?; - - Ok((relayer, chains.try_into()?)) -} - -/** - Bootstrap a fixed number of chains that are actually - backed by the same underlying full node. -*/ -pub fn boostrap_chains_with_self_connected_node( - test_config: &TestConfig, - full_node: FullNode, - config_modifier: impl FnOnce(&mut Config), -) -> Result<(RelayerDriver, NaryConnectedChains), Error> { - let full_nodes = vec![full_node; SIZE]; - let (relayer, chains) = - boostrap_chains_with_any_nodes(test_config, full_nodes, config_modifier)?; - - Ok((relayer, chains.try_into()?)) -} - -/** - Bootstrap a dynamic number of chains, according to the number of full nodes - in the `Vec`. -*/ -pub fn boostrap_chains_with_any_nodes( - test_config: &TestConfig, - full_nodes: Vec, - config_modifier: impl FnOnce(&mut Config), -) -> Result<(RelayerDriver, DynamicConnectedChains), Error> { - let mut config = Config::default(); - - for node in full_nodes.iter() { - add_chain_config(&mut config, node, test_config)?; - } - - config_modifier(&mut config); - - let config_path = test_config.chain_store_dir.join("relayer-config.toml"); - - save_relayer_config(&config, &config_path)?; - - let registry = new_registry(config.clone()); - - let mut chain_handles = Vec::new(); - - for node in full_nodes.iter() { - let handle = spawn_chain_handle(®istry, node)?; - chain_handles.push(handle); - } - - let mut foreign_clients: Vec>> = Vec::new(); - - for handle_a in chain_handles.iter() { - let mut foreign_clients_b = Vec::new(); - - for handle_b in chain_handles.iter() { - let foreign_client = bootstrap_foreign_client(handle_a, handle_b, Default::default())?; - - foreign_clients_b.push(foreign_client); - } - - foreign_clients.push(foreign_clients_b); - } - - let relayer = RelayerDriver { - config_path, - config, - registry, - hang_on_fail: test_config.hang_on_fail, - }; - - let connected_chains = DynamicConnectedChains::new(chain_handles, full_nodes, foreign_clients); - - Ok((relayer, connected_chains)) -} - -fn spawn_chain_handle( - registry: &SharedRegistry, - node: &FullNode, -) -> Result { - let chain_id = &node.chain_driver.chain_id; - let handle = registry - .get_or_spawn(chain_id) - .map_err(handle_generic_error)?; - - add_keys_to_chain_handle(&handle, &node.wallets)?; - - Ok(handle) -} diff --git a/tools/test-framework/src/bootstrap/nary/channel.rs b/tools/test-framework/src/bootstrap/nary/channel.rs deleted file mode 100644 index c1d76875b..000000000 --- a/tools/test-framework/src/bootstrap/nary/channel.rs +++ /dev/null @@ -1,150 +0,0 @@ -/*! - Functions for bootstrapping N-ary number of chanels. -*/ - -use core::convert::TryInto; -use core::time::Duration; - -use ibc_relayer::chain::handle::ChainHandle; -use ibc_relayer_types::core::ics04_channel::channel::Ordering; -use ibc_relayer_types::core::ics24_host::identifier::PortId; - -use crate::bootstrap::binary::channel::{ - bootstrap_channel_with_connection, BootstrapChannelOptions, -}; -use crate::bootstrap::nary::connection::bootstrap_connections_dynamic; -use crate::error::{handle_generic_error, Error}; -use crate::types::binary::channel::ConnectedChannel; -use crate::types::nary::chains::{DynamicConnectedChains, NaryConnectedChains}; -use crate::types::nary::channel::{ConnectedChannels, DynamicConnectedChannels}; -use crate::types::nary::connection::{ConnectedConnections, DynamicConnectedConnections}; -use crate::types::tagged::*; -use crate::util::array::{assert_same_dimension, into_nested_vec}; - -/** - Bootstrap a dynamic number of channels based on the number of - connections in `DynamicConnectedConnections`. -*/ -pub fn bootstrap_channels_with_connections_dynamic( - connections: DynamicConnectedConnections, - chains: &Vec, - ports: &Vec>, - order: Ordering, - bootstrap_with_random_ids: bool, -) -> Result, Error> { - let size = chains.len(); - - assert_same_dimension(size, connections.connections())?; - assert_same_dimension(size, ports)?; - - let mut channels: Vec>> = Vec::new(); - - for (i, connections_b) in connections.connections().iter().enumerate() { - let mut channels_b: Vec> = Vec::new(); - - for (j, connection) in connections_b.iter().enumerate() { - if i <= j { - let chain_a = &chains[i]; - let chain_b = &chains[j]; - - let port_a = &ports[i][j]; - let port_b = &ports[j][i]; - - let bootstrap_options = BootstrapChannelOptions::default() - .order(order) - .bootstrap_with_random_ids(bootstrap_with_random_ids); - - let channel = bootstrap_channel_with_connection( - chain_a, - chain_b, - connection.clone(), - &DualTagged::new(port_a), - &DualTagged::new(port_b), - bootstrap_options, - )?; - - channels_b.push(channel); - } else { - let counter_channel = &channels[j][i]; - let channel = counter_channel.clone().flip(); - - channels_b.push(channel); - } - } - - channels.push(channels_b); - } - - Ok(DynamicConnectedChannels::new(channels)) -} - -/** - Bootstrap a fixed number of connections with the same `SIZE` - as in `ConnectedConnections`. -*/ -pub fn bootstrap_channels_with_connections( - connections: ConnectedConnections, - chains: [Handle; SIZE], - ports: [[PortId; SIZE]; SIZE], - order: Ordering, - bootstrap_with_random_ids: bool, -) -> Result, Error> { - let channels = bootstrap_channels_with_connections_dynamic( - connections.into(), - &chains.into(), - &into_nested_vec(ports), - order, - bootstrap_with_random_ids, - )?; - - channels.try_into().map_err(handle_generic_error) -} - -/** - Boostrap a dynamic number of channels together with the - underlying connections based on the number of chain handles - in `DynamicConnectedChains`. -*/ -pub fn bootstrap_channels_and_connections_dynamic( - chains: &DynamicConnectedChains, - ports: &Vec>, - connection_delay: Duration, - order: Ordering, - bootstrap_with_random_ids: bool, -) -> Result, Error> { - let connections = bootstrap_connections_dynamic( - chains.foreign_clients(), - connection_delay, - bootstrap_with_random_ids, - )?; - - bootstrap_channels_with_connections_dynamic( - connections, - chains.chain_handles(), - ports, - order, - bootstrap_with_random_ids, - ) -} - -/** - Bootstrap a fixed number of channels as specified by `SIZE`, - together with bootstrapping the underlying connections. -*/ -pub fn bootstrap_channels_and_connections( - chains: &NaryConnectedChains, - ports: [[PortId; SIZE]; SIZE], - connection_delay: Duration, - order: Ordering, - bootstrap_with_random_ids: bool, -) -> Result, Error> { - let channels = bootstrap_channels_and_connections_dynamic( - &chains.clone().into(), - &into_nested_vec(ports), - connection_delay, - order, - bootstrap_with_random_ids, - )?; - - channels.try_into() -} diff --git a/tools/test-framework/src/bootstrap/nary/connection.rs b/tools/test-framework/src/bootstrap/nary/connection.rs deleted file mode 100644 index 0e7e670f3..000000000 --- a/tools/test-framework/src/bootstrap/nary/connection.rs +++ /dev/null @@ -1,76 +0,0 @@ -/*! - Functions for bootstrapping N-ary number of connections. -*/ - -use core::convert::TryInto; -use core::time::Duration; - -use ibc_relayer::chain::handle::ChainHandle; -use ibc_relayer::foreign_client::ForeignClient; - -use crate::bootstrap::binary::connection::{bootstrap_connection, BootstrapConnectionOptions}; -use crate::error::Error; -use crate::types::binary::connection::ConnectedConnection; -use crate::types::binary::foreign_client::ForeignClientPair; -use crate::types::nary::connection::{ConnectedConnections, DynamicConnectedConnections}; -use crate::types::nary::foreign_client::ForeignClientPairs; -use crate::util::array::assert_same_dimension; - -/** - Bootstrap a dynamic number of connections based on the - given foreign client NxN matrix. -*/ -pub fn bootstrap_connections_dynamic( - foreign_clients: &Vec>>, - connection_delay: Duration, - bootstrap_with_random_ids: bool, -) -> Result, Error> { - let size = foreign_clients.len(); - - assert_same_dimension(size, foreign_clients)?; - - let mut connections: Vec>> = Vec::new(); - - for (i, foreign_clients_b) in foreign_clients.iter().enumerate() { - let mut connections_b: Vec> = Vec::new(); - - for (j, foreign_client) in foreign_clients_b.iter().enumerate() { - if i <= j { - let counter_foreign_client = &foreign_clients[j][i]; - let foreign_clients = - ForeignClientPair::new(foreign_client.clone(), counter_foreign_client.clone()); - - let bootstrap_options = BootstrapConnectionOptions::default() - .connection_delay(connection_delay) - .bootstrap_with_random_ids(bootstrap_with_random_ids); - - let connection = bootstrap_connection(&foreign_clients, bootstrap_options)?; - - connections_b.push(connection); - } else { - let counter_connection = &connections[j][i]; - let connection = counter_connection.clone().flip(); - - connections_b.push(connection); - } - } - - connections.push(connections_b); - } - - Ok(DynamicConnectedConnections::new(connections)) -} - -pub fn bootstrap_connections( - foreign_clients: ForeignClientPairs, - connection_delay: Duration, - bootstrap_with_random_ids: bool, -) -> Result, Error> { - let connections = bootstrap_connections_dynamic( - &foreign_clients.into_nested_vec(), - connection_delay, - bootstrap_with_random_ids, - )?; - - connections.try_into() -} diff --git a/tools/test-framework/src/bootstrap/nary/mod.rs b/tools/test-framework/src/bootstrap/nary/mod.rs deleted file mode 100644 index d7d0b0076..000000000 --- a/tools/test-framework/src/bootstrap/nary/mod.rs +++ /dev/null @@ -1,13 +0,0 @@ -/*! - Experimental work to bootstrap N-ary chains for testing. - - This is a work in progress and although it works, is currently - lack of documentation. We put this behind the "experimental" - feature flag so that developers who do not need this feature - are not obligated to go though the code and understand what - is happening under the hood. -*/ - -pub mod chain; -pub mod channel; -pub mod connection; diff --git a/tools/test-framework/src/bootstrap/single.rs b/tools/test-framework/src/bootstrap/single.rs deleted file mode 100644 index 2e181b2bb..000000000 --- a/tools/test-framework/src/bootstrap/single.rs +++ /dev/null @@ -1,168 +0,0 @@ -/*! - Helper functions for bootstrapping a single full node. -*/ -use core::time::Duration; -use std::sync::{Arc, RwLock}; - -use eyre::eyre; -use toml; -use tracing::info; - -use crate::chain::builder::ChainBuilder; -use crate::chain::config; -use crate::chain::driver::ChainDriver; -use crate::chain::ext::bootstrap::ChainBootstrapMethodsExt; -use crate::error::Error; -use crate::ibc::denom::Denom; -use crate::ibc::token::Token; -use crate::types::single::node::FullNode; -use crate::types::wallet::{TestWallets, Wallet}; -use crate::util::random::{random_u128_range, random_u32}; - -/** - Bootstrap a single full node with the provided [`ChainBuilder`] and - a prefix for the chain ID. - - The function would generate random postfix attached to the end of - a chain ID. So for example having a prefix `"alpha"` may generate - a chain with an ID like `"ibc-alpha-f5a2a988"` - - The bootstrap function also tries to use as many random parameters - when intitializing the chain, such as using random denomination - and wallets. This is to help ensure that the test is written to - only work with specific hardcoded parameters. - - TODO: Due to the limitation of the `gaiad` command, currently - parameters such as the stake denomination (`stake`) and the wallet - address prefix (`cosmos`) cannot be overridden. It would be - great to be able to randomize these parameters in the future - as well. -*/ -pub fn bootstrap_single_node( - builder: &ChainBuilder, - prefix: &str, - use_random_id: bool, - config_modifier: impl FnOnce(&mut toml::Value) -> Result<(), Error>, - genesis_modifier: impl FnOnce(&mut serde_json::Value) -> Result<(), Error>, - chain_number: usize, -) -> Result { - let stake_denom = Denom::base("stake"); - - let denom = if use_random_id { - Denom::base(&format!("coin{:x}", random_u32())) - } else { - Denom::base("samoleans") - }; - - // Evmos requires of at least 1_000_000_000_000_000_000 or else there will be the - // error `error during handshake: error on replay: validator set is nil in genesis and still empty after InitChain` - // 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 - .clone() - .checked_add(1_000_000_000_000u64) - .ok_or(Error::generic(eyre!( - "error creating initial stake with additional amount" - )))?; - let initial_coin = Token::new(denom.clone(), initial_amount); - - let chain_driver = builder.new_chain(prefix, use_random_id, chain_number)?; - - chain_driver.initialize()?; - - chain_driver.update_genesis_file("genesis.json", genesis_modifier)?; - - let validator = add_wallet(&chain_driver, "validator", use_random_id)?; - let relayer = add_wallet(&chain_driver, "relayer", use_random_id)?; - let user1 = add_wallet(&chain_driver, "user1", use_random_id)?; - 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_validator(&validator.id, &initial_stake)?; - - chain_driver.add_genesis_account(&user1.address, &[&initial_stake, &initial_coin])?; - - chain_driver.add_genesis_account(&user2.address, &[&initial_stake, &initial_coin])?; - - chain_driver.add_genesis_account(&relayer.address, &[&initial_stake, &initial_coin])?; - - chain_driver.collect_gen_txs()?; - - let log_level = std::env::var("CHAIN_LOG_LEVEL").unwrap_or_else(|_| "info".to_string()); - - chain_driver.update_chain_config("config.toml", |config| { - config::set_log_level(config, &log_level)?; - config::set_rpc_port(config, chain_driver.rpc_port)?; - config::set_p2p_port(config, chain_driver.p2p_port)?; - config::set_pprof_port(config, chain_driver.pprof_port)?; - config::set_timeout_commit(config, Duration::from_secs(1))?; - config::set_timeout_propose(config, Duration::from_secs(1))?; - config::set_mode(config, "validator")?; - - config_modifier(config)?; - - Ok(()) - })?; - - 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")?; - - Ok(()) - })?; - - let process = chain_driver.start()?; - - chain_driver.assert_eventual_wallet_amount(&relayer.address, &initial_coin)?; - - info!( - "started new chain {} at with home path {} and RPC address {}.", - chain_driver.chain_id, - chain_driver.home_path, - chain_driver.rpc_address(), - ); - - info!( - "user wallet for chain {} - id: {}, address: {}", - chain_driver.chain_id, user1.id.0, user1.address.0, - ); - - info!( - "you can manually interact with the chain using commands starting with:\n{} --home '{}' --node {}", - chain_driver.command_path, - chain_driver.home_path, - chain_driver.rpc_address(), - ); - - let wallets = TestWallets { - validator, - relayer, - user1, - user2, - }; - - let node = FullNode { - chain_driver, - denom, - wallets, - process: Arc::new(RwLock::new(process)), - }; - - Ok(node) -} - -fn add_wallet(driver: &ChainDriver, prefix: &str, use_random_id: bool) -> Result { - if use_random_id { - let num = random_u32(); - let wallet_id = format!("{prefix}-{num:x}"); - driver.add_wallet(&wallet_id) - } else { - driver.add_wallet(prefix) - } -} diff --git a/tools/test-framework/src/chain/builder.rs b/tools/test-framework/src/chain/builder.rs deleted file mode 100644 index 464f8dcdd..000000000 --- a/tools/test-framework/src/chain/builder.rs +++ /dev/null @@ -1,127 +0,0 @@ -/*! - Builder construct that spawn new chains with some common parameters. -*/ - -use alloc::sync::Arc; -use std::str::FromStr; - -use tokio::runtime::Runtime; - -use super::chain_type::ChainType; -use crate::chain::driver::ChainDriver; -use crate::error::Error; -use crate::types::config::TestConfig; -use crate::util::random::random_unused_tcp_port; - -/** - Used for holding common configuration needed to create new `ChainDriver`s. - - Currently this is hardcoded to support only a single version of Gaia chain. - We may want to turn this into a trait in the future to support different - chain implementations. -*/ -#[derive(Debug)] -pub struct ChainBuilder { - /** - The CLI executable used for the chain commands. Defaults to `gaiad`. - - TODO: Have a mutable list of command paths so that the `ChainBuilder` - may return [`ChainDriver`]s bound to different chain commands - for testing with multiple chain implementations. - */ - pub command_paths: Vec, - - /** - The filesystem path to store the data files used by the chain. - */ - pub base_store_dir: String, - - pub account_prefixes: Vec, - - pub runtime: Arc, -} - -impl ChainBuilder { - /** - Create a new `ChainBuilder`. - */ - pub fn new( - command_paths: Vec, - base_store_dir: &str, - account_prefixes: Vec, - runtime: Arc, - ) -> Self { - Self { - command_paths, - base_store_dir: base_store_dir.to_string(), - account_prefixes, - runtime, - } - } - - /** - Create a `ChainBuilder` based on the provided [`TestConfig`]. - */ - pub fn new_with_config(config: &TestConfig, runtime: Arc) -> Self { - Self::new( - config.chain_command_paths.clone(), - &format!("{}", config.chain_store_dir.display()), - config.account_prefixes.clone(), - runtime, - ) - } - - /** - Create a new [`ChainDriver`] with the chain ID containing the - given prefix. - - Note that this only configures the [`ChainDriver`] without - the actual chain being intitialized or spawned. - - The `ChainBuilder` will configure the [`ChainDriver`] with random - unused ports, and add a random suffix to the chain ID. - - For example, calling this with a prefix `"alpha"` will return - a [`ChainDriver`] configured with a chain ID like - `"ibc-alpha-f5a2a988"`. - */ - pub fn new_chain( - &self, - prefix: &str, - use_random_id: bool, - chain_number: usize, - ) -> Result { - // If there are more spawned chains than given chain binaries, take the N-th position modulo - // 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 chain_type = ChainType::from_str(&self.command_paths[chain_number])?; - - let chain_id = chain_type.chain_id(prefix, use_random_id); - - let rpc_port = random_unused_tcp_port(); - let grpc_port = random_unused_tcp_port(); - let grpc_web_port = random_unused_tcp_port(); - let p2p_port = random_unused_tcp_port(); - let pprof_port = random_unused_tcp_port(); - - let home_path = format!("{}/{}", self.base_store_dir, chain_id); - - let driver = ChainDriver::create( - chain_type, - self.command_paths[chain_number].clone(), - chain_id, - home_path, - self.account_prefixes[account_number].clone(), - rpc_port, - grpc_port, - grpc_web_port, - p2p_port, - pprof_port, - self.runtime.clone(), - )?; - - Ok(driver) - } -} diff --git a/tools/test-framework/src/chain/chain_type.rs b/tools/test-framework/src/chain/chain_type.rs deleted file mode 100644 index 0b9f9c01d..000000000 --- a/tools/test-framework/src/chain/chain_type.rs +++ /dev/null @@ -1,76 +0,0 @@ -use core::str::FromStr; - -use ibc_relayer::config::AddressType; -use ibc_relayer_types::core::ics24_host::identifier::ChainId; - -use crate::error::Error; -use crate::util::random::{random_u32, random_unused_tcp_port}; - -const COSMOS_HD_PATH: &str = "m/44'/118'/0'/0/0"; -const EVMOS_HD_PATH: &str = "m/44'/60'/0'/0/0"; - -#[derive(Clone, Debug)] -pub enum ChainType { - Cosmos, - Evmos, -} - -impl ChainType { - pub fn hd_path(&self) -> &str { - match self { - Self::Cosmos => COSMOS_HD_PATH, - Self::Evmos => EVMOS_HD_PATH, - } - } - - pub fn chain_id(&self, prefix: &str, use_random_id: bool) -> ChainId { - match self { - Self::Cosmos => { - if use_random_id { - ChainId::from_string(&format!("ibc-{}-{:x}", prefix, random_u32())) - } else { - ChainId::from_string(&format!("ibc{prefix}")) - } - } - Self::Evmos => ChainId::from_string(&format!("evmos_9000-{prefix}")), - } - } - - // Extra arguments required to run ` start` - pub fn extra_start_args(&self) -> Vec { - let mut res = vec![]; - let json_rpc_port = random_unused_tcp_port(); - match self { - Self::Cosmos => {} - Self::Evmos => { - res.push("--json-rpc.address".to_owned()); - res.push(format!("localhost:{json_rpc_port}")); - } - } - res - } - - pub fn address_type(&self) -> AddressType { - match self { - Self::Cosmos => AddressType::default(), - Self::Evmos => AddressType::Ethermint { - pk_type: "/ethermint.crypto.v1.ethsecp256k1.PubKey".to_string(), - }, - } - } -} - -impl FromStr for ChainType { - type Err = Error; - - fn from_str(s: &str) -> Result { - match s { - name if name.contains("gaiad") => Ok(ChainType::Cosmos), - name if name.contains("simd") => Ok(ChainType::Cosmos), - name if name.contains("wasmd") => Ok(ChainType::Cosmos), - name if name.contains("icad") => Ok(ChainType::Cosmos), - name if name.contains("evmosd") => Ok(ChainType::Evmos), - _ => Ok(ChainType::Cosmos), - } - } -} diff --git a/tools/test-framework/src/chain/cli/bootstrap.rs b/tools/test-framework/src/chain/cli/bootstrap.rs deleted file mode 100644 index 41d402a44..000000000 --- a/tools/test-framework/src/chain/cli/bootstrap.rs +++ /dev/null @@ -1,187 +0,0 @@ -use core::time::Duration; -use std::process::{Command, Stdio}; -use std::thread::sleep; -use std::{fs, str}; - -use eyre::eyre; - -use crate::chain::exec::simple_exec; -use crate::error::Error; -use crate::types::process::ChildProcess; -use crate::util::file::pipe_to_file; - -pub fn initialize(chain_id: &str, command_path: &str, home_path: &str) -> Result<(), Error> { - simple_exec( - chain_id, - command_path, - &[ - "--home", - home_path, - "--chain-id", - chain_id, - "init", - chain_id, - ], - )?; - - Ok(()) -} -pub fn add_wallet( - chain_id: &str, - command_path: &str, - home_path: &str, - wallet_id: &str, -) -> Result { - let output = simple_exec( - chain_id, - command_path, - &[ - "--home", - home_path, - "keys", - "add", - wallet_id, - "--keyring-backend", - "test", - "--output", - "json", - ], - )?; - - // gaia6 somehow displays result in stderr instead of stdout - if output.stdout.is_empty() { - Ok(output.stderr) - } else { - Ok(output.stdout) - } -} - -pub fn add_genesis_account( - chain_id: &str, - command_path: &str, - home_path: &str, - wallet_address: &str, - amounts: &[String], -) -> Result<(), Error> { - let amounts_str = itertools::join(amounts, ","); - - simple_exec( - chain_id, - command_path, - &[ - "--home", - home_path, - "add-genesis-account", - wallet_address, - &amounts_str, - ], - )?; - - Ok(()) -} - -pub fn add_genesis_validator( - chain_id: &str, - command_path: &str, - home_path: &str, - wallet_id: &str, - amount: &str, -) -> Result<(), Error> { - 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( - chain_id, - command_path, - &["--home", home_path, "collect-gentxs"], - )?; - - Ok(()) -} - -pub fn start_chain( - command_path: &str, - home_path: &str, - rpc_listen_address: &str, - grpc_listen_address: &str, - extra_start_args: &[&str], -) -> Result { - let base_args = [ - "--home", - home_path, - "start", - "--pruning", - "nothing", - "--grpc.address", - grpc_listen_address, - "--rpc.laddr", - rpc_listen_address, - ]; - - let mut args: Vec<&str> = base_args.to_vec(); - args.extend(extra_start_args.iter()); - - let mut child = Command::new(command_path) - .args(&args) - .stdin(Stdio::null()) - .stdout(Stdio::piped()) - .stderr(Stdio::piped()) - .spawn()?; - - let stdout = child - .stdout - .take() - .ok_or_else(|| eyre!("expected stdout to be present in child process"))?; - - let stderr = child - .stderr - .take() - .ok_or_else(|| eyre!("expected stderr to be present in child process"))?; - - let stderr_path = format!("{home_path}/stdout.log"); - let stdout_path = format!("{home_path}/stderr.log"); - - pipe_to_file(stdout, &stdout_path)?; - pipe_to_file(stderr, &stderr_path)?; - - // Wait for a while and check if the child process exited immediately. - // If so, return error since we expect the full node to be running in the background. - - sleep(Duration::from_millis(1000)); - - let status = child - .try_wait() - .map_err(|e| eyre!("error try waiting for child status: {}", e))?; - - match status { - None => Ok(ChildProcess::new(child)), - Some(status) => { - let stdout_output = fs::read_to_string(stdout_path)?; - let stderr_output = fs::read_to_string(stderr_path)?; - - Err(eyre!( - "expected full node process to be running, but it exited immediately with exit status {} and output: {}\n{}", - status, - stdout_output, - stderr_output, - ).into()) - } - } -} diff --git a/tools/test-framework/src/chain/cli/fee_grant.rs b/tools/test-framework/src/chain/cli/fee_grant.rs deleted file mode 100644 index 3fe484aca..000000000 --- a/tools/test-framework/src/chain/cli/fee_grant.rs +++ /dev/null @@ -1,34 +0,0 @@ -use crate::chain::exec::simple_exec; -use crate::error::Error; - -pub fn feegrant_grant( - chain_id: &str, - command_path: &str, - home_path: &str, - rpc_listen_address: &str, - granter: &str, - grantee: &str, -) -> Result<(), Error> { - simple_exec( - chain_id, - command_path, - &[ - "--home", - home_path, - "--chain-id", - chain_id, - "--node", - rpc_listen_address, - "--keyring-backend", - "test", - "tx", - "feegrant", - "grant", - granter, - grantee, - "--yes", - ], - )?; - - Ok(()) -} diff --git a/tools/test-framework/src/chain/cli/host_zone.rs b/tools/test-framework/src/chain/cli/host_zone.rs deleted file mode 100644 index 5ffb53ad7..000000000 --- a/tools/test-framework/src/chain/cli/host_zone.rs +++ /dev/null @@ -1,46 +0,0 @@ -use crate::chain::exec::simple_exec; -use crate::error::Error; - -pub fn register_host_zone( - chain_id: &str, - command_path: &str, - home_path: &str, - rpc_listen_address: &str, - connection_id: &str, - host_denom: &str, - bech32_prefix: &str, - ibc_denom: &str, - channel_id: &str, - sender: &str, -) -> Result<(), Error> { - simple_exec( - chain_id, - command_path, - &[ - "--home", - home_path, - "--node", - rpc_listen_address, - "--keyring-backend", - "test", - "tx", - "stakeibc", - "register-host-zone", - connection_id, - host_denom, - bech32_prefix, - ibc_denom, - channel_id, - "1", - "--from", - sender, - "--chain-id", - chain_id, - "--gas", - "auto", - "--yes", - ], - )?; - - Ok(()) -} diff --git a/tools/test-framework/src/chain/cli/ica.rs b/tools/test-framework/src/chain/cli/ica.rs deleted file mode 100644 index 552454374..000000000 --- a/tools/test-framework/src/chain/cli/ica.rs +++ /dev/null @@ -1,103 +0,0 @@ -use eyre::eyre; -use serde_json as json; - -use crate::chain::exec::simple_exec; -use crate::error::{handle_generic_error, Error}; - -/// Register a new interchain account controlled by the given account -/// over the given connection. -pub fn register_interchain_account_cli( - chain_id: &str, - command_path: &str, - home_path: &str, - rpc_listen_address: &str, - from: &str, - connection_id: &str, -) -> Result<(), Error> { - let args = &[ - "--home", - home_path, - "--node", - rpc_listen_address, - "--output", - "json", - "tx", - "intertx", - "register", - "--from", - from, - "--connection-id", - connection_id, - "--chain-id", - chain_id, - "--keyring-backend", - "test", - "-y", - ]; - - let res = simple_exec(chain_id, command_path, args)?.stdout; - check_result_code(&res)?; - - Ok(()) -} - -/// Query the address of the interchain account -/// corresponding to the given controller account. -pub fn query_interchain_account( - chain_id: &str, - command_path: &str, - home_path: &str, - rpc_listen_address: &str, - account: &str, - connection_id: &str, -) -> Result { - let args = &[ - "--home", - home_path, - "--node", - rpc_listen_address, - "--output", - "json", - "query", - "interchain-accounts", - "controller", - "interchain-account", - account, - connection_id, - ]; - - let res = simple_exec(chain_id, command_path, args)?.stdout; - let json_res = json::from_str::(&res).map_err(handle_generic_error)?; - - let address = json_res - .get("address") - .ok_or_else(|| eyre!("expected `address` field"))? - .as_str() - .ok_or_else(|| eyre!("expected string field"))?; - - Ok(address.to_string()) -} - -/// Check that a command succeeded, by ensuring that the JSON emitted -/// contains a `code` integer field set to 0. -fn check_result_code(res: &str) -> Result<(), Error> { - let json_res = json::from_str::(res).map_err(handle_generic_error)?; - - let code = json_res - .get("code") - .ok_or_else(|| eyre!("expected `code` field"))? - .as_i64() - .ok_or_else(|| eyre!("expected integer field"))?; - - if code == 0 { - Ok(()) - } else { - let raw_log = json_res - .get("raw_log") - .ok_or_else(|| eyre!("expected `raw_log` field"))? - .as_str() - .ok_or_else(|| eyre!("expected string field"))?; - - Err(Error::generic(eyre!("{}", raw_log))) - } -} diff --git a/tools/test-framework/src/chain/cli/mod.rs b/tools/test-framework/src/chain/cli/mod.rs deleted file mode 100644 index 88ac42bf9..000000000 --- a/tools/test-framework/src/chain/cli/mod.rs +++ /dev/null @@ -1,9 +0,0 @@ -pub mod bootstrap; -pub mod fee_grant; -pub mod host_zone; -pub mod ica; -pub mod provider; -pub mod query; -pub mod transfer; -pub mod upgrade; -pub mod version; diff --git a/tools/test-framework/src/chain/cli/provider.rs b/tools/test-framework/src/chain/cli/provider.rs deleted file mode 100644 index b4c44dd67..000000000 --- a/tools/test-framework/src/chain/cli/provider.rs +++ /dev/null @@ -1,97 +0,0 @@ -use std::str; - -use crate::chain::exec::simple_exec; -use crate::error::Error; - -pub fn submit_consumer_chain_proposal( - chain_id: &str, - command_path: &str, - home_path: &str, - rpc_listen_address: &str, -) -> Result<(), Error> { - let proposal_file = format!("{}/consumer_proposal.json", home_path); - - simple_exec( - chain_id, - command_path, - &[ - "tx", - "gov", - "submit-proposal", - "consumer-addition", - &proposal_file, - "--chain-id", - chain_id, - "--from", - "validator", - "--home", - home_path, - "--node", - rpc_listen_address, - "--keyring-backend", - "test", - "--yes", - ], - )?; - - Ok(()) -} - -pub fn query_consumer_genesis( - chain_id: &str, - command_path: &str, - home_path: &str, - rpc_listen_address: &str, - consumer_chain_id: &str, -) -> Result { - let exec_output = simple_exec( - chain_id, - command_path, - &[ - "--home", - home_path, - "--node", - rpc_listen_address, - "query", - "provider", - "consumer-genesis", - consumer_chain_id, - "--output", - "json", - ], - )?; - - Ok(exec_output.stdout) -} - -pub fn replace_genesis_state(chain_id: &str, home_path: &str) -> Result { - let exec_output = simple_exec( - chain_id, - "jq", - &[ - "-s", - ".[0].app_state.ccvconsumer = .[1] | .[0]", - &format!("{}/config/genesis.json", home_path), - &format!("{}/config/consumer_genesis.json", home_path), - ], - )?; - - Ok(exec_output.stdout) -} - -pub fn copy_validator_key_pair( - chain_id: &str, - provider_home_path: &str, - consumer_home_path: &str, -) -> Result<(), Error> { - simple_exec( - chain_id, - "cp", - &[ - &format!("{}/config/priv_validator_key.json", provider_home_path), - &format!("{}/config/priv_validator_key.json", consumer_home_path), - ], - )?; - - Ok(()) -} diff --git a/tools/test-framework/src/chain/cli/query.rs b/tools/test-framework/src/chain/cli/query.rs deleted file mode 100644 index dabb6cb8f..000000000 --- a/tools/test-framework/src/chain/cli/query.rs +++ /dev/null @@ -1,122 +0,0 @@ -use core::str::FromStr; - -use eyre::eyre; -use ibc_relayer_types::applications::transfer::amount::Amount; -use {serde_json as json, serde_yaml as yaml}; - -use crate::chain::exec::simple_exec; -use crate::error::{handle_generic_error, Error}; - -pub fn query_balance( - chain_id: &str, - command_path: &str, - rpc_listen_address: &str, - wallet_id: &str, - denom: &str, -) -> Result { - let res = simple_exec( - chain_id, - command_path, - &[ - "--node", - rpc_listen_address, - "query", - "bank", - "balances", - wallet_id, - "--denom", - denom, - "--output", - "json", - ], - )? - .stdout; - - 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) -} - -/** - Query for the transactions related to a wallet on `Chain` - receiving token transfer from others. -*/ -pub fn query_recipient_transactions( - chain_id: &str, - command_path: &str, - rpc_listen_address: &str, - recipient_address: &str, -) -> Result { - let res = simple_exec( - chain_id, - command_path, - &[ - "--node", - rpc_listen_address, - "query", - "txs", - "--events", - &format!("transfer.recipient={recipient_address}"), - ], - )? - .stdout; - - tracing::debug!("parsing tx result: {}", res); - - match json::from_str(&res) { - Ok(res) => Ok(res), - _ => { - let value: yaml::Value = yaml::from_str(&res).map_err(handle_generic_error)?; - Ok(yaml_to_json_value(value)?) - } - } -} - -// Hack to convert yaml::Value to json::Value. Unfortunately there is -// no builtin conversion provided even though both Value types are -// essentially the same. We just convert the two types to and from -// strings as a shortcut. -// -// TODO: properly implement a common trait that is implemented by -// dynamic types like json::Value, yaml::Value, and toml::Value. -// That way we can write generic functions that work with any of -// the dynamic value types for testing purposes. -fn yaml_to_json_value(value: yaml::Value) -> Result { - let json_str = json::to_string(&value).map_err(handle_generic_error)?; - - let parsed = json::from_str(&json_str).map_err(handle_generic_error)?; - - Ok(parsed) -} - -/// Query pending Cross Chain Queries -pub fn query_cross_chain_query( - chain_id: &str, - command_path: &str, - rpc_listen_address: &str, -) -> Result { - let res = simple_exec( - chain_id, - command_path, - &[ - "--node", - rpc_listen_address, - "query", - "interchainquery", - "list-pending-queries", - "--output", - "json", - ], - )? - .stdout; - - Ok(res) -} diff --git a/tools/test-framework/src/chain/cli/transfer.rs b/tools/test-framework/src/chain/cli/transfer.rs deleted file mode 100644 index b91297db1..000000000 --- a/tools/test-framework/src/chain/cli/transfer.rs +++ /dev/null @@ -1,84 +0,0 @@ -/*! - Methods for performing IBC token transfer on a chain. -*/ - -use crate::chain::exec::simple_exec; -use crate::error::Error; - -pub fn local_transfer_token( - chain_id: &str, - command_path: &str, - home_path: &str, - rpc_listen_address: &str, - sender: &str, - recipient: &str, - token: &str, -) -> Result<(), Error> { - simple_exec( - chain_id, - command_path, - &[ - "--node", - rpc_listen_address, - "tx", - "bank", - "send", - sender, - recipient, - token, - "--chain-id", - chain_id, - "--home", - home_path, - "--keyring-backend", - "test", - "--yes", - ], - )?; - - Ok(()) -} - -pub fn transfer_from_chain( - chain_id: &str, - command_path: &str, - home_path: &str, - rpc_listen_address: &str, - sender: &str, - src_port: &str, - src_channel: &str, - recipient: &str, - token: &str, - timeout_height: &str, -) -> Result<(), Error> { - simple_exec( - chain_id, - command_path, - &[ - "--node", - rpc_listen_address, - "tx", - "ibc-transfer", - "transfer", - src_port, - src_channel, - recipient, - token, - "--from", - sender, - "--chain-id", - chain_id, - "--home", - home_path, - "--keyring-backend", - "test", - "--fees", - "1200stake", - "--timeout-height", - timeout_height, - "--yes", - ], - )?; - - Ok(()) -} diff --git a/tools/test-framework/src/chain/cli/upgrade.rs b/tools/test-framework/src/chain/cli/upgrade.rs deleted file mode 100644 index ffb66f50b..000000000 --- a/tools/test-framework/src/chain/cli/upgrade.rs +++ /dev/null @@ -1,40 +0,0 @@ -/*! - Methods for voting on a proposal. -*/ -use crate::chain::exec::simple_exec; -use crate::error::Error; - -pub fn vote_proposal( - chain_id: &str, - command_path: &str, - home_path: &str, - rpc_listen_address: &str, - fees: &str, -) -> Result<(), Error> { - simple_exec( - chain_id, - command_path, - &[ - "--node", - rpc_listen_address, - "tx", - "gov", - "vote", - "1", - "yes", - "--chain-id", - chain_id, - "--home", - home_path, - "--keyring-backend", - "test", - "--from", - "validator", - "--fees", - fees, - "--yes", - ], - )?; - - Ok(()) -} diff --git a/tools/test-framework/src/chain/cli/version.rs b/tools/test-framework/src/chain/cli/version.rs deleted file mode 100644 index d48a61f01..000000000 --- a/tools/test-framework/src/chain/cli/version.rs +++ /dev/null @@ -1,17 +0,0 @@ -use crate::chain::exec::simple_exec; -use crate::error::Error; -use crate::prelude::handle_generic_error; - -pub fn major_version(command_path: &str) -> Result { - let output = simple_exec("version", command_path, &["version"])?; - - // The command output is returned in stderr: - // https://github.com/cosmos/cosmos-sdk/issues/8498#issuecomment-1160576936 - match output.stderr.chars().nth(1) { - Some(major_version) => major_version - .to_string() - .parse::() - .map_err(handle_generic_error), - None => Ok(0), - } -} diff --git a/tools/test-framework/src/chain/config.rs b/tools/test-framework/src/chain/config.rs deleted file mode 100644 index 0b417638f..000000000 --- a/tools/test-framework/src/chain/config.rs +++ /dev/null @@ -1,309 +0,0 @@ -/*! - Helper functions for modifying the Gaia chain config in TOML. - - Since we do not need to understand the full structure of the - CosmosSDK config, we are updating the config as dynamic TOML - values instead of serializing them into proper types. -*/ - -use core::time::Duration; - -use eyre::{eyre, Report as Error}; -use toml::Value; - -/// Set the `rpc` field in the full node config. -pub fn set_rpc_port(config: &mut Value, port: u16) -> Result<(), Error> { - config - .get_mut("rpc") - .ok_or_else(|| eyre!("expect rpc section"))? - .as_table_mut() - .ok_or_else(|| eyre!("expect object"))? - .insert("laddr".to_string(), format!("tcp://0.0.0.0:{port}").into()); - - Ok(()) -} - -pub fn set_grpc_port(config: &mut Value, port: u16) -> Result<(), Error> { - config - .get_mut("grpc") - .ok_or_else(|| eyre!("expect grpc section"))? - .as_table_mut() - .ok_or_else(|| eyre!("expect object"))? - .insert("address".to_string(), format!("0.0.0.0:{port}").into()); - - Ok(()) -} - -pub fn disable_grpc_web(config: &mut Value) -> Result<(), Error> { - if let Some(field) = config.get_mut("grpc-web") { - field - .as_table_mut() - .ok_or_else(|| eyre!("expect object"))? - .insert("enable".to_string(), false.into()); - } - - Ok(()) -} - -pub fn disable_api(config: &mut Value) -> Result<(), Error> { - if let Some(field) = config.get_mut("api") { - field - .as_table_mut() - .ok_or_else(|| eyre!("expect object"))? - .insert("enable".to_string(), false.into()); - } - - Ok(()) -} - -/// Set the `p2p` field in the full node config. -pub fn set_p2p_port(config: &mut Value, port: u16) -> Result<(), Error> { - config - .get_mut("p2p") - .ok_or_else(|| eyre!("expect p2p section"))? - .as_table_mut() - .ok_or_else(|| eyre!("expect object"))? - .insert("laddr".to_string(), format!("tcp://0.0.0.0:{port}").into()); - - Ok(()) -} - -/// Set the `pprof_laddr` field in the full node config. -pub fn set_pprof_port(config: &mut Value, port: u16) -> Result<(), Error> { - config - .as_table_mut() - .ok_or_else(|| eyre!("expect object"))? - .insert( - "pprof_laddr".to_string(), - format!("tcp://0.0.0.0:{port}").into(), - ); - - Ok(()) -} - -pub fn set_mempool_version(config: &mut Value, version: &str) -> Result<(), Error> { - config - .get_mut("mempool") - .ok_or_else(|| eyre!("expect mempool section"))? - .as_table_mut() - .ok_or_else(|| eyre!("expect object"))? - .insert("version".to_string(), version.into()); - - Ok(()) -} - -/// Set the `consensus.timeout_commit` field in the full node config. -pub fn set_timeout_commit(config: &mut Value, duration: Duration) -> Result<(), Error> { - config - .get_mut("consensus") - .ok_or_else(|| eyre!("expect consensus section"))? - .as_table_mut() - .ok_or_else(|| eyre!("expect object"))? - .insert( - "timeout_commit".to_string(), - format!("{}ms", duration.as_millis()).into(), - ); - - Ok(()) -} - -/// Set the `consensus.timeout_propose` field in the full node config. -pub fn set_timeout_propose(config: &mut Value, duration: Duration) -> Result<(), Error> { - config - .get_mut("consensus") - .ok_or_else(|| eyre!("expect consensus section"))? - .as_table_mut() - .ok_or_else(|| eyre!("expect object"))? - .insert( - "timeout_propose".to_string(), - format!("{}ms", duration.as_millis()).into(), - ); - - Ok(()) -} - -/// Set the `log_level` field in the full node config. -pub fn set_log_level(config: &mut Value, log_level: &str) -> Result<(), Error> { - config - .as_table_mut() - .ok_or_else(|| eyre!("expect object"))? - .insert("log_level".to_string(), log_level.into()); - - Ok(()) -} - -pub fn set_minimum_gas_price(config: &mut Value, price: &str) -> Result<(), Error> { - config - .as_table_mut() - .ok_or_else(|| eyre!("expect object"))? - .insert("minimum-gas-prices".to_string(), price.into()); - - Ok(()) -} - -pub fn set_mode(config: &mut Value, mode: &str) -> Result<(), Error> { - config - .as_table_mut() - .ok_or_else(|| eyre!("expect object"))? - .insert("mode".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") - .and_then(|app_state| app_state.get_mut("gov")) - .and_then(|gov| get_mut_with_fallback(gov, "params", "deposit_params")) - .and_then(|deposit_params| deposit_params.as_object_mut()) - .ok_or_else(|| eyre!("failed to update max_deposit_period in genesis file"))?; - - max_deposit_period - .insert( - "max_deposit_period".to_owned(), - serde_json::Value::String(period.to_string()), - ) - .ok_or_else(|| eyre!("failed to update max_deposit_period in genesis file"))?; - - Ok(()) -} - -pub fn set_staking_bond_denom(genesis: &mut serde_json::Value, denom: &str) -> Result<(), Error> { - let bond_denom = genesis - .get_mut("app_state") - .and_then(|app_state| app_state.get_mut("staking")) - .and_then(|staking| staking.get_mut("params")) - .and_then(|params| params.as_object_mut()) - .ok_or_else(|| eyre!("failed to update bond_denom in genesis file"))?; - - bond_denom - .insert( - "bond_denom".to_owned(), - serde_json::Value::String(denom.to_string()), - ) - .ok_or_else(|| eyre!("failed to update bond_denom in genesis file"))?; - - Ok(()) -} - -pub fn set_staking_max_entries( - genesis: &mut serde_json::Value, - entries: &str, -) -> Result<(), Error> { - let max_entries = genesis - .get_mut("app_state") - .and_then(|app_state| app_state.get_mut("staking")) - .and_then(|staking| staking.get_mut("params")) - .and_then(|params| params.as_object_mut()) - .ok_or_else(|| eyre!("failed to update max_entries in genesis file"))?; - - max_entries - .insert( - "max_entries".to_owned(), - serde_json::Value::String(entries.to_string()), - ) - .ok_or_else(|| eyre!("failed to update max_entries in genesis file"))?; - - Ok(()) -} - -pub fn set_mint_mint_denom(genesis: &mut serde_json::Value, denom: &str) -> Result<(), Error> { - let mint_denom = genesis - .get_mut("app_state") - .and_then(|app_state| app_state.get_mut("mint")) - .and_then(|mint| mint.get_mut("params")) - .and_then(|params| params.as_object_mut()) - .ok_or_else(|| eyre!("failed to update mint_denom in genesis file"))?; - - mint_denom - .insert( - "mint_denom".to_owned(), - serde_json::Value::String(denom.to_string()), - ) - .ok_or_else(|| eyre!("failed to update mint_denom in genesis file"))?; - - Ok(()) -} - -pub fn set_crisis_denom(genesis: &mut serde_json::Value, crisis_denom: &str) -> Result<(), Error> { - let denom = genesis - .get_mut("app_state") - .and_then(|app_state| app_state.get_mut("crisis")) - .and_then(|crisis| crisis.get_mut("constant_fee")) - .and_then(|constant_fee| constant_fee.as_object_mut()) - .ok_or_else(|| eyre!("failed to update denom in genesis file"))?; - - denom - .insert( - "denom".to_owned(), - serde_json::Value::String(crisis_denom.to_string()), - ) - .ok_or_else(|| eyre!("failed to update denom in genesis file"))?; - - Ok(()) -} - -pub fn set_voting_period(genesis: &mut serde_json::Value, period: &str) -> Result<(), Error> { - let 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", "voting_params")) - .and_then(|voting_params| voting_params.as_object_mut()) - .ok_or_else(|| eyre!("failed to get voting_params in genesis file"))?; - - voting_period - .insert( - "voting_period".to_owned(), - serde_json::Value::String(period.to_string()), - ) - .ok_or_else(|| eyre!("failed to update voting_period in genesis file"))?; - - Ok(()) -} - -pub fn set_soft_opt_out_threshold( - genesis: &mut serde_json::Value, - threshold: &str, -) -> Result<(), Error> { - let params = genesis - .get_mut("app_state") - .and_then(|app_state| app_state.get_mut("ccvconsumer")) - .and_then(|ccvconsumer| ccvconsumer.get_mut("params")) - .and_then(|params| params.as_object_mut()) - .ok_or_else(|| eyre!("failed to get ccvconsumer params in genesis file"))?; - - // Might be none if the entry `soft_opt_out_threshold` didn't exist - params.insert( - "soft_opt_out_threshold".to_owned(), - serde_json::Value::String(threshold.to_string()), - ); - - Ok(()) -} - -/// Look up a key in a JSON object, falling back to the second key if the first one cannot be found. -/// -/// This lets us support both Tendermint 0.34 and 0.37, which sometimes use different keys for the -/// same configuration object in the genesis file. -/// -/// Eg. in 0.34, the voting params are at `app_state.gov.voting_params`, -/// but in 0.37 they are at `app_state.gov.params`. -/// -/// Note: This function is needed to avoid having to inline its code every time we need it. -/// The more obvious way to write it inline would be: -/// -/// value.get_mut(key_034).or_else(|| value.get_mut(key_037)) -/// -/// but that does not work because of the first `get_mut` borrows `value` mutably, which -/// prevents the second `get_mut` from borrowing it again. -fn get_mut_with_fallback<'a>( - value: &'a mut serde_json::Value, - key: &str, - fallback_key: &str, -) -> Option<&'a mut serde_json::Value> { - let key = match value.get(key) { - Some(value) if !value.is_null() => key, - _ => fallback_key, - }; - value.get_mut(key) -} diff --git a/tools/test-framework/src/chain/driver.rs b/tools/test-framework/src/chain/driver.rs deleted file mode 100644 index a5b77ec27..000000000 --- a/tools/test-framework/src/chain/driver.rs +++ /dev/null @@ -1,227 +0,0 @@ -/*! - Implementation of [`ChainDriver`]. -*/ - -use alloc::sync::Arc; -use core::time::Duration; - -use eyre::eyre; -use ibc_relayer::chain::cosmos::types::config::TxConfig; -use ibc_relayer_types::applications::transfer::amount::Amount; -use ibc_relayer_types::core::ics24_host::identifier::ChainId; -use tokio::runtime::Runtime; - -use crate::chain::chain_type::ChainType; -use crate::chain::cli::query::query_balance; -use crate::error::Error; -use crate::ibc::denom::Denom; -use crate::ibc::token::Token; -use crate::relayer::tx::new_tx_config_for_test; -use crate::types::env::{EnvWriter, ExportEnv}; -use crate::types::wallet::WalletAddress; -use crate::util::retry::assert_eventually_succeed; - -/** - Number of times (seconds) to try and query a wallet to reach the - target amount, as used by [`assert_eventual_wallet_amount`]. - - We set this to around 60 seconds to make sure that the tests still - pass in slower environments like the CI. - - If you encounter retry error, try increasing this constant. If the - test is taking much longer to reach eventual consistency, it might - be indication of some underlying performance issues. -*/ -const WAIT_WALLET_AMOUNT_ATTEMPTS: u16 = 90; - -/** - A driver for interacting with a chain full nodes through command line. - - The name `ChainDriver` is inspired by - [WebDriver](https://developer.mozilla.org/en-US/docs/Web/WebDriver), - which is the term used to describe programs that control spawning of the - web browsers. In our case, the ChainDriver is used to spawn and manage - chain full nodes. - - Currently the `ChainDriver` is hardcoded to support only a single version - of Gaia chain. In the future, we will want to turn this into one or more - `ChainDriver` traits so that they can be used to spawn multiple chain - implementations other than a single version of Gaia. -*/ - -#[derive(Debug, Clone)] -pub struct ChainDriver { - pub chain_type: ChainType, - /** - The filesystem path to the Gaia CLI. Defaults to `gaiad`. - */ - pub command_path: String, - - /** - The ID of the chain. - */ - pub chain_id: ChainId, - - /** - The home directory for the full node to store data files. - */ - pub home_path: String, - - pub account_prefix: String, - - /** - The port used for RPC. - */ - pub rpc_port: u16, - - /** - The port used for GRPC. - */ - pub grpc_port: u16, - - pub grpc_web_port: u16, - - /** - The port used for P2P. (Currently unused other than for setup) - */ - pub p2p_port: u16, - - /** - The port used for pprof. (Currently unused other than for setup) - */ - pub pprof_port: u16, - - pub tx_config: TxConfig, - - pub runtime: Arc, -} - -impl ExportEnv for ChainDriver { - fn export_env(&self, writer: &mut impl EnvWriter) { - writer.write_env("CMD", &self.command_path); - writer.write_env("HOME", &self.home_path); - writer.write_env("RPC_ADDR", &self.rpc_address()); - writer.write_env("GRPC_ADDR", &self.grpc_address()); - } -} - -impl ChainDriver { - /// Create a new [`ChainDriver`] - pub fn create( - chain_type: ChainType, - command_path: String, - chain_id: ChainId, - home_path: String, - account_prefix: String, - rpc_port: u16, - grpc_port: u16, - grpc_web_port: u16, - p2p_port: u16, - pprof_port: u16, - runtime: Arc, - ) -> 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(), - )?; - - Ok(Self { - chain_type, - command_path, - chain_id, - home_path, - account_prefix, - rpc_port, - grpc_port, - grpc_web_port, - p2p_port, - pprof_port, - tx_config, - runtime, - }) - } - - /// Returns the full URL for the RPC address. - pub fn rpc_address(&self) -> String { - format!("http://localhost:{}", self.rpc_port) - } - - /// Returns the full URL for the WebSocket address. - pub fn websocket_address(&self) -> String { - format!("ws://localhost:{}/websocket", self.rpc_port) - } - - /// Returns the full URL for the GRPC address. - pub fn grpc_address(&self) -> String { - format!("http://localhost:{}", self.grpc_port) - } - - /** - Returns the full URL for the RPC address to listen to when starting - the full node. - - This is somehow different from [`rpc_address`](ChainDriver::rpc_address) - as it requires the `"tcp://"` scheme. - */ - pub fn rpc_listen_address(&self) -> String { - format!("tcp://localhost:{}", self.rpc_port) - } - - /** - Returns the full URL for the GRPC address to listen to when starting - the full node. - - This is somehow different from [`grpc_address`](ChainDriver::grpc_address) - as it requires no scheme to be specified. - */ - pub fn grpc_listen_address(&self) -> String { - format!("localhost:{}", self.grpc_port) - } - - /** - Query for the balances for a given wallet address and denomination - */ - pub fn query_balance(&self, wallet_id: &WalletAddress, denom: &Denom) -> Result { - query_balance( - self.chain_id.as_str(), - &self.command_path, - &self.rpc_listen_address(), - &wallet_id.0, - &denom.to_string(), - ) - } - - /** - Assert that a wallet should eventually have the expected amount in the - given denomination. - */ - pub fn assert_eventual_wallet_amount( - &self, - wallet: &WalletAddress, - token: &Token, - ) -> Result<(), Error> { - assert_eventually_succeed( - &format!("wallet reach {wallet} amount {token}"), - WAIT_WALLET_AMOUNT_ATTEMPTS, - Duration::from_secs(1), - || { - let amount: Amount = self.query_balance(wallet, &token.denom)?; - - if amount == token.amount { - Ok(()) - } else { - Err(Error::generic(eyre!( - "current balance of account {} with amount {} does not match the target amount {}", - wallet, - amount, - token - ))) - } - }, - )?; - - Ok(()) - } -} diff --git a/tools/test-framework/src/chain/exec.rs b/tools/test-framework/src/chain/exec.rs deleted file mode 100644 index 167d15a16..000000000 --- a/tools/test-framework/src/chain/exec.rs +++ /dev/null @@ -1,52 +0,0 @@ -use std::process::Command; -use std::str; - -use eyre::eyre; -use tracing::{debug, trace}; - -use crate::error::{handle_exec_error, handle_generic_error, Error}; - -pub struct ExecOutput { - pub stdout: String, - pub stderr: String, -} - -pub fn simple_exec(desc: &str, command_path: &str, args: &[&str]) -> Result { - debug!( - "Executing command for {}: {} {}", - desc, - command_path, - itertools::join(args, " ") - ); - - let output = Command::new(command_path) - .args(args) - .output() - .map_err(handle_exec_error(command_path))?; - - if output.status.success() { - let stdout = str::from_utf8(&output.stdout) - .map_err(handle_generic_error)? - .to_string(); - - let stderr = str::from_utf8(&output.stderr) - .map_err(handle_generic_error)? - .to_string(); - - trace!( - "command executed successfully with stdout: {}, stderr: {}", - stdout, - stderr - ); - - Ok(ExecOutput { stdout, stderr }) - } else { - let message = str::from_utf8(&output.stderr).map_err(handle_generic_error)?; - - Err(Error::generic(eyre!( - "command exited with error status {:?} and message: {}", - output.status.code(), - message - ))) - } -} diff --git a/tools/test-framework/src/chain/ext/bootstrap.rs b/tools/test-framework/src/chain/ext/bootstrap.rs deleted file mode 100644 index 9fae2e2d7..000000000 --- a/tools/test-framework/src/chain/ext/bootstrap.rs +++ /dev/null @@ -1,338 +0,0 @@ -use core::str::FromStr; -use std::path::PathBuf; -use std::{fs, str}; - -use eyre::eyre; -use hdpath::StandardHDPath; -use ibc_relayer::keyring::{Secp256k1KeyPair, SigningKeyPair}; -use tracing::debug; -use {serde_json as json, toml}; - -use crate::chain::cli::bootstrap::{ - add_genesis_account, add_genesis_validator, add_wallet, collect_gen_txs, initialize, - start_chain, -}; -use crate::chain::cli::provider::{ - copy_validator_key_pair, query_consumer_genesis, replace_genesis_state, - submit_consumer_chain_proposal, -}; -use crate::chain::driver::ChainDriver; -use crate::chain::exec::simple_exec; -use crate::error::{handle_generic_error, Error}; -use crate::ibc::token::Token; -use crate::types::process::ChildProcess; -use crate::types::wallet::{Wallet, WalletAddress, WalletId}; - -pub trait ChainBootstrapMethodsExt { - /** - Read the content at a file path relative to the chain home - directory, and return the result as a string. - - This is not efficient but is sufficient for testing purposes. - */ - fn read_file(&self, file_path: &str) -> Result; - - /** - Write the string content to a file path relative to the chain home - directory. - - This is not efficient but is sufficient for testing purposes. - */ - fn write_file(&self, file_path: &str, content: &str) -> Result<(), Error>; - - /** - Modify the Gaia chain config which is saved in toml format. - */ - fn update_chain_config( - &self, - file: &str, - cont: impl FnOnce(&mut toml::Value) -> Result<(), Error>, - ) -> Result<(), Error>; - - /** - Initialized the chain data stores. - - This is used by - [`bootstrap_single_node`](crate::bootstrap::single::bootstrap_single_node). - */ - fn initialize(&self) -> Result<(), Error>; - - /** - Modify the Gaia genesis file. - */ - fn update_genesis_file( - &self, - file: &str, - cont: impl FnOnce(&mut serde_json::Value) -> Result<(), Error>, - ) -> Result<(), Error>; - - /** - Add a wallet with the given ID to the full node's keyring. - */ - fn add_wallet(&self, wallet_id: &str) -> Result; - - /** - Add a wallet address to the genesis account list for an uninitialized - full node. - */ - fn add_genesis_account(&self, wallet: &WalletAddress, amounts: &[&Token]) -> Result<(), Error>; - - /** - Add a wallet ID with the given stake amount to be the genesis validator - for an uninitialized chain. - */ - fn add_genesis_validator(&self, wallet_id: &WalletId, token: &Token) -> Result<(), Error>; - - /** - Call `gaiad collect-gentxs` to generate the genesis transactions. - */ - fn collect_gen_txs(&self) -> Result<(), Error>; - - /** - Start a full node by running in the background `gaiad start`. - - Returns a [`ChildProcess`] that stops the full node process when the - value is dropped. - */ - fn start(&self) -> Result; - - /** - Submit a consumer chain proposal. - */ - fn submit_consumer_chain_proposal( - &self, - consumer_chain_id: &str, - spawn_time: &str, - ) -> Result<(), Error>; - - /** - Query a consumer chain's genesis. - */ - fn query_consumer_genesis( - &self, - consumer_chain_driver: &ChainDriver, - consumer_chain_id: &str, - ) -> Result<(), Error>; - - /** - Replace genesis state. - */ - fn replace_genesis_state(&self) -> Result<(), Error>; - - /** - Copy validator key pair. - */ - fn copy_validator_key_pair(&self, provider_chain_driver: &ChainDriver) -> Result<(), Error>; -} - -impl ChainBootstrapMethodsExt for ChainDriver { - fn read_file(&self, file_path: &str) -> Result { - let full_path = PathBuf::from(&self.home_path).join(file_path); - let res = fs::read_to_string(full_path)?; - Ok(res) - } - - fn write_file(&self, file_path: &str, content: &str) -> Result<(), Error> { - let full_path = PathBuf::from(&self.home_path).join(file_path); - let full_path_str = format!("{}", full_path.display()); - fs::write(full_path, content)?; - debug!("created new file {:?}", full_path_str); - Ok(()) - } - - fn update_chain_config( - &self, - file: &str, - cont: impl FnOnce(&mut toml::Value) -> Result<(), Error>, - ) -> Result<(), Error> { - let config_path = format!("config/{file}"); - - let config1 = self.read_file(&config_path)?; - - let mut config2 = toml::from_str(&config1).map_err(handle_generic_error)?; - - cont(&mut config2)?; - - let config3 = toml::to_string_pretty(&config2).map_err(handle_generic_error)?; - - self.write_file(&config_path, &config3)?; - - Ok(()) - } - - fn initialize(&self) -> Result<(), Error> { - initialize(self.chain_id.as_str(), &self.command_path, &self.home_path) - } - - fn update_genesis_file( - &self, - file: &str, - cont: impl FnOnce(&mut serde_json::Value) -> Result<(), Error>, - ) -> Result<(), Error> { - let config1 = self.read_file(&format!("config/{file}"))?; - - let mut config2 = serde_json::from_str(&config1).map_err(handle_generic_error)?; - - cont(&mut config2)?; - - let config3 = serde_json::to_string_pretty(&config2).map_err(handle_generic_error)?; - - self.write_file("config/genesis.json", &config3)?; - - Ok(()) - } - - fn add_wallet(&self, wallet_id: &str) -> Result { - let seed_content = add_wallet( - self.chain_id.as_str(), - &self.command_path, - &self.home_path, - wallet_id, - )?; - - let json_val: json::Value = json::from_str(&seed_content).map_err(handle_generic_error)?; - - let wallet_address = json_val - .get("address") - .ok_or_else(|| eyre!("expect address string field to be present in json result"))? - .as_str() - .ok_or_else(|| eyre!("expect address string field to be present in json result"))? - .to_string(); - - let seed_path = format!("{wallet_id}-seed.json"); - self.write_file(&seed_path, &seed_content)?; - - let hd_path = StandardHDPath::from_str(self.chain_type.hd_path()) - .map_err(|e| eyre!("failed to create StandardHDPath: {:?}", e))?; - - let key = Secp256k1KeyPair::from_seed_file(&seed_content, &hd_path) - .map_err(handle_generic_error)?; - - Ok(Wallet::new(wallet_id.to_string(), wallet_address, key)) - } - - fn add_genesis_account(&self, wallet: &WalletAddress, amounts: &[&Token]) -> Result<(), Error> { - let amounts_str = amounts.iter().map(|t| t.to_string()).collect::>(); - - add_genesis_account( - self.chain_id.as_str(), - &self.command_path, - &self.home_path, - &wallet.0, - &amounts_str, - ) - } - - fn add_genesis_validator(&self, wallet_id: &WalletId, token: &Token) -> Result<(), Error> { - add_genesis_validator( - self.chain_id.as_str(), - &self.command_path, - &self.home_path, - &wallet_id.0, - &token.to_string(), - ) - } - - fn collect_gen_txs(&self) -> Result<(), Error> { - collect_gen_txs(self.chain_id.as_str(), &self.command_path, &self.home_path) - } - - fn start(&self) -> Result { - let extra_start_args = self.chain_type.extra_start_args(); - - start_chain( - &self.command_path, - &self.home_path, - &self.rpc_listen_address(), - &self.grpc_listen_address(), - &extra_start_args - .iter() - .map(|s| s.as_ref()) - .collect::>(), - ) - } - - fn submit_consumer_chain_proposal( - &self, - consumer_chain_id: &str, - _spawn_time: &str, - ) -> Result<(), Error> { - let res = simple_exec( - self.chain_id.as_str(), - "jq", - &[ - "-r", - ".genesis_time", - &format!("{}/config/genesis.json", self.home_path), - ], - )?; - let mut spawn_time = res.stdout; - // Remove newline character - spawn_time.pop(); - let raw_proposal = r#" - { - "title": "Create consumer chain", - "description": "First consumer chain", - "chain_id": "{consumer_chain_id}", - "initial_height": { - "revision_height": 1 - }, - "genesis_hash": "Z2VuX2hhc2g=", - "binary_hash": "YmluX2hhc2g=", - "spawn_time": "{spawn_time}", - "unbonding_period": 100000000000, - "ccv_timeout_period": 100000000000, - "transfer_timeout_period": 100000000000, - "consumer_redistribution_fraction": "0.75", - "blocks_per_distribution_transmission": 10, - "historical_entries": 10000, - "deposit": "10000001stake" - }"#; - - let proposal = raw_proposal.replace("{consumer_chain_id}", consumer_chain_id); - let proposal = proposal.replace("{spawn_time}", &spawn_time); - - self.write_file("consumer_proposal.json", &proposal)?; - - submit_consumer_chain_proposal( - self.chain_id.as_str(), - &self.command_path, - &self.home_path, - &self.rpc_listen_address(), - ) - } - - fn query_consumer_genesis( - &self, - consumer_chain_driver: &ChainDriver, - consumer_chain_id: &str, - ) -> Result<(), Error> { - let consumer_genesis = query_consumer_genesis( - self.chain_id.as_str(), - &self.command_path, - &self.home_path, - &self.rpc_listen_address(), - consumer_chain_id, - )?; - consumer_chain_driver.write_file("config/consumer_genesis.json", &consumer_genesis)?; - - Ok(()) - } - - fn replace_genesis_state(&self) -> Result<(), Error> { - let genesis_output = replace_genesis_state(self.chain_id.as_str(), &self.home_path)?; - self.write_file("config/genesis.json", &genesis_output)?; - - Ok(()) - } - - fn copy_validator_key_pair(&self, provider_chain_driver: &ChainDriver) -> Result<(), Error> { - copy_validator_key_pair( - self.chain_id.as_str(), - &provider_chain_driver.home_path, - &self.home_path, - )?; - - Ok(()) - } -} diff --git a/tools/test-framework/src/chain/ext/crosschainquery.rs b/tools/test-framework/src/chain/ext/crosschainquery.rs deleted file mode 100644 index 68e039db6..000000000 --- a/tools/test-framework/src/chain/ext/crosschainquery.rs +++ /dev/null @@ -1,95 +0,0 @@ -use std::time::Duration; - -use eyre::eyre; -use serde_json as json; - -use crate::chain::cli::query::query_cross_chain_query; -use crate::error::Error; -use crate::prelude::{assert_eventually_succeed, handle_generic_error, ChainDriver}; -use crate::types::tagged::MonoTagged; - -/** - Number of times (seconds) to try and query the list of cross chain - queries. - - If you encounter retry error, verify the value of `stride_epoch`in - the `stride_epoch` configuration in Stride's `genesis.toml` file. -*/ -const WAIT_CROSS_CHAIN_QUERY_ATTEMPTS: u16 = 60; - -pub trait CrossChainQueryMethodsExt { - fn assert_pending_cross_chain_query(&self) -> Result<(), Error>; - - fn assert_processed_cross_chain_query(&self) -> Result<(), Error>; -} - -impl CrossChainQueryMethodsExt for MonoTagged { - fn assert_pending_cross_chain_query(&self) -> Result<(), Error> { - assert_eventually_succeed( - "waiting for a cross chain query request", - WAIT_CROSS_CHAIN_QUERY_ATTEMPTS, - Duration::from_secs(1), - || { - let output = query_cross_chain_query( - self.0.chain_id.as_str(), - &self.0.command_path, - &self.0.rpc_listen_address(), - )?; - - // Verify that there is at least one pending Cross Chain Query. - let request_sent = json::from_str::(&output) - .map_err(handle_generic_error)? - .get("pending_queries") - .ok_or_else(|| eyre!("no pending cross chain queries"))? - .as_array() - .ok_or_else(|| eyre!("pending cross chain queries is not an array"))? - .first() - .ok_or_else(|| eyre!("no pending cross chain queries"))? - .as_bool(); - - if let Some(sent) = request_sent { - if !sent { - return Err(Error::generic(eyre!("Request found but not sent"))); - } - } - - Ok(()) - }, - )?; - - Ok(()) - } - - fn assert_processed_cross_chain_query(&self) -> Result<(), Error> { - assert_eventually_succeed( - "waiting for the cross chain query to be relayed", - WAIT_CROSS_CHAIN_QUERY_ATTEMPTS, - Duration::from_secs(1), - || { - let output = query_cross_chain_query( - self.0.chain_id.as_str(), - &self.0.command_path, - &self.0.rpc_listen_address(), - )?; - - // Verify that the there are no more pending Cross Chain Queries. - if !json::from_str::(&output) - .map_err(handle_generic_error)? - .get("pending_queries") - .ok_or_else(|| eyre!("no pending cross chain queries"))? - .as_array() - .ok_or_else(|| eyre!("pending cross chain queries is not an array"))? - .is_empty() - { - return Err(Error::generic(eyre!( - "Pending query has not been processed" - ))); - } - - Ok(()) - }, - )?; - - Ok(()) - } -} diff --git a/tools/test-framework/src/chain/ext/fee.rs b/tools/test-framework/src/chain/ext/fee.rs deleted file mode 100644 index 87d051d99..000000000 --- a/tools/test-framework/src/chain/ext/fee.rs +++ /dev/null @@ -1,185 +0,0 @@ -use core::time::Duration; - -use ibc_relayer::event::IbcEventWithHeight; -use ibc_relayer_types::applications::ics29_fee::packet_fee::IdentifiedPacketFees; -use ibc_relayer_types::core::ics04_channel::packet::Sequence; - -use crate::chain::driver::ChainDriver; -use crate::chain::tagged::TaggedChainDriverExt; -use crate::error::Error; -use crate::ibc::token::TaggedTokenRef; -use crate::relayer::fee::{ - ibc_token_transfer_with_fee, pay_packet_fee, query_counterparty_payee, - query_incentivized_packets, register_counterparty_payee, register_payee, -}; -use crate::types::id::{TaggedChannelIdRef, TaggedPortIdRef}; -use crate::types::tagged::*; -use crate::types::wallet::{Wallet, WalletAddress}; - -pub trait ChainFeeMethodsExt { - fn ibc_token_transfer_with_fee( - &self, - port_id: &TaggedPortIdRef<'_, Chain, Counterparty>, - channel_id: &TaggedChannelIdRef<'_, Chain, Counterparty>, - sender: &MonoTagged, - recipient: &MonoTagged, - send_amount: &TaggedTokenRef<'_, Chain>, - receive_fee: &TaggedTokenRef<'_, Chain>, - ack_fee: &TaggedTokenRef<'_, Chain>, - timeout_fee: &TaggedTokenRef<'_, Chain>, - timeout: Duration, - ) -> Result, Error>; - - fn pay_packet_fee( - &self, - port_id: &TaggedPortIdRef<'_, Chain, Counterparty>, - channel_id: &TaggedChannelIdRef<'_, Chain, Counterparty>, - sequence: &DualTagged, - payer: &MonoTagged, - receive_fee: &TaggedTokenRef<'_, Chain>, - ack_fee: &TaggedTokenRef<'_, Chain>, - timeout_fee: &TaggedTokenRef<'_, Chain>, - ) -> Result, Error>; - - fn register_counterparty_payee( - &self, - wallet: &MonoTagged, - counterparty_payee: &MonoTagged, - channel_id: &TaggedChannelIdRef<'_, Chain, Counterparty>, - port_id: &TaggedPortIdRef<'_, Chain, Counterparty>, - ) -> Result<(), Error>; - - fn register_payee( - &self, - wallet: &MonoTagged, - payee: &MonoTagged, - channel_id: &TaggedChannelIdRef<'_, Chain, Counterparty>, - port_id: &TaggedPortIdRef<'_, Chain, Counterparty>, - ) -> Result<(), Error>; - - fn query_counterparty_payee( - &self, - channel_id: &TaggedChannelIdRef<'_, Chain, Counterparty>, - address: &MonoTagged, - ) -> Result>, Error>; - - fn query_incentivized_packets( - &self, - channel_id: &TaggedChannelIdRef<'_, Chain, Counterparty>, - port_id: &TaggedPortIdRef<'_, Chain, Counterparty>, - ) -> Result, Error>; -} - -impl ChainFeeMethodsExt for MonoTagged { - fn ibc_token_transfer_with_fee( - &self, - port_id: &TaggedPortIdRef<'_, Chain, Counterparty>, - channel_id: &TaggedChannelIdRef<'_, Chain, Counterparty>, - sender: &MonoTagged, - recipient: &MonoTagged, - send_amount: &TaggedTokenRef<'_, Chain>, - receive_fee: &TaggedTokenRef<'_, Chain>, - ack_fee: &TaggedTokenRef<'_, Chain>, - timeout_fee: &TaggedTokenRef<'_, Chain>, - timeout: Duration, - ) -> Result, Error> { - let rpc_client = self.rpc_client()?; - self.value().runtime.block_on(ibc_token_transfer_with_fee( - rpc_client.as_ref(), - &self.tx_config(), - port_id, - channel_id, - sender, - recipient, - send_amount, - receive_fee, - ack_fee, - timeout_fee, - timeout, - )) - } - - fn pay_packet_fee( - &self, - port_id: &TaggedPortIdRef<'_, Chain, Counterparty>, - channel_id: &TaggedChannelIdRef<'_, Chain, Counterparty>, - sequence: &DualTagged, - payer: &MonoTagged, - receive_fee: &TaggedTokenRef<'_, Chain>, - ack_fee: &TaggedTokenRef<'_, Chain>, - timeout_fee: &TaggedTokenRef<'_, Chain>, - ) -> Result, Error> { - let rpc_client = self.rpc_client()?; - self.value().runtime.block_on(pay_packet_fee( - rpc_client.as_ref(), - &self.tx_config(), - port_id, - channel_id, - sequence, - payer, - receive_fee, - ack_fee, - timeout_fee, - )) - } - - fn register_counterparty_payee( - &self, - wallet: &MonoTagged, - counterparty_payee: &MonoTagged, - channel_id: &TaggedChannelIdRef<'_, Chain, Counterparty>, - port_id: &TaggedPortIdRef<'_, Chain, Counterparty>, - ) -> Result<(), Error> { - let rpc_client = self.rpc_client()?; - self.value().runtime.block_on(register_counterparty_payee( - rpc_client.as_ref(), - &self.tx_config(), - wallet, - counterparty_payee, - channel_id, - port_id, - )) - } - - fn register_payee( - &self, - wallet: &MonoTagged, - payee: &MonoTagged, - channel_id: &TaggedChannelIdRef<'_, Chain, Counterparty>, - port_id: &TaggedPortIdRef<'_, Chain, Counterparty>, - ) -> Result<(), Error> { - let rpc_client = self.rpc_client()?; - self.value().runtime.block_on(register_payee( - rpc_client.as_ref(), - &self.tx_config(), - wallet, - payee, - channel_id, - port_id, - )) - } - - fn query_counterparty_payee( - &self, - channel_id: &TaggedChannelIdRef<'_, Chain, Counterparty>, - address: &MonoTagged, - ) -> Result>, Error> { - self.value().runtime.block_on(query_counterparty_payee( - &self.tx_config().value().grpc_address, - channel_id, - address, - )) - } - - fn query_incentivized_packets( - &self, - channel_id: &TaggedChannelIdRef<'_, Chain, Counterparty>, - port_id: &TaggedPortIdRef<'_, Chain, Counterparty>, - ) -> Result, Error> { - self.value().runtime.block_on(query_incentivized_packets( - &self.tx_config().value().grpc_address, - channel_id, - port_id, - )) - } -} diff --git a/tools/test-framework/src/chain/ext/fee_grant.rs b/tools/test-framework/src/chain/ext/fee_grant.rs deleted file mode 100644 index 42402cdbe..000000000 --- a/tools/test-framework/src/chain/ext/fee_grant.rs +++ /dev/null @@ -1,20 +0,0 @@ -use crate::chain::cli::fee_grant::feegrant_grant; -use crate::error::Error; -use crate::prelude::ChainDriver; -use crate::types::tagged::MonoTagged; -pub trait FeeGrantMethodsExt { - fn feegrant_grant(&self, granter: &str, grantee: &str) -> Result<(), Error>; -} - -impl FeeGrantMethodsExt for MonoTagged { - fn feegrant_grant(&self, granter: &str, grantee: &str) -> Result<(), Error> { - feegrant_grant( - self.value().chain_id.as_str(), - &self.value().command_path, - &self.value().home_path, - &self.value().rpc_listen_address(), - granter, - grantee, - ) - } -} diff --git a/tools/test-framework/src/chain/ext/forward.rs b/tools/test-framework/src/chain/ext/forward.rs deleted file mode 100644 index 1e0c23ace..000000000 --- a/tools/test-framework/src/chain/ext/forward.rs +++ /dev/null @@ -1,28 +0,0 @@ -use ibc_relayer_types::core::ics24_host::identifier::{ChannelId, PortId}; - -use crate::prelude::{DualTagged, MonoTagged, WalletAddress}; - -/// Build the recipient address as following: -/// {intermediate_refund_address}|{foward_port}/{forward_channel}:{final_destination_address} -/// See -pub fn build_forward_address<'a, ChainB, ChainC>( - intermediate_destination_address: MonoTagged, - port: DualTagged, - channel: &'a ChannelId, - final_destination_address: MonoTagged, -) -> WalletAddress { - let forward_address = - format!("{intermediate_destination_address}|{port}/{channel}:{final_destination_address}"); - WalletAddress(forward_address) -} - -/// Build a forward address with the destination address invalid -pub fn build_invalid_forward_address<'a, ChainB, ChainC>( - intermediate_destination_address: MonoTagged, - port: DualTagged, - channel: &'a ChannelId, -) -> WalletAddress { - let forward_address = - format!("{intermediate_destination_address}|{port}/{channel}:invalid address"); - WalletAddress(forward_address) -} diff --git a/tools/test-framework/src/chain/ext/ica.rs b/tools/test-framework/src/chain/ext/ica.rs deleted file mode 100644 index e6ab3c31c..000000000 --- a/tools/test-framework/src/chain/ext/ica.rs +++ /dev/null @@ -1,110 +0,0 @@ -use ibc_relayer::chain::handle::ChainHandle; -use ibc_relayer::chain::tracking::TrackedMsgs; -use ibc_relayer_types::applications::ics27_ica::msgs::register::MsgRegisterInterchainAccount; -use ibc_relayer_types::core::ics04_channel::version::Version; -use ibc_relayer_types::events::IbcEvent; -use ibc_relayer_types::tx_msg::Msg; - -use crate::chain::cli::ica::{query_interchain_account, register_interchain_account_cli}; -use crate::chain::driver::ChainDriver; -use crate::error::Error; -use crate::prelude::*; -use crate::types::tagged::*; -use crate::types::wallet::WalletAddress; - -pub trait InterchainAccountMethodsExt { - fn register_interchain_account_cli( - &self, - from: &MonoTagged, - connection_id: &TaggedConnectionIdRef, - ) -> Result<(), Error>; - - fn query_interchain_account( - &self, - from: &MonoTagged, - connection_id: &TaggedConnectionIdRef, - ) -> Result, Error>; -} - -impl InterchainAccountMethodsExt for MonoTagged { - fn register_interchain_account_cli( - &self, - from: &MonoTagged, - connection_id: &TaggedConnectionIdRef, - ) -> Result<(), Error> { - let driver = *self.value(); - register_interchain_account_cli( - driver.chain_id.as_str(), - &driver.command_path, - &driver.home_path, - &driver.rpc_listen_address(), - from.value().as_str(), - connection_id.value().as_str(), - ) - } - - fn query_interchain_account( - &self, - from: &MonoTagged, - connection_id: &TaggedConnectionIdRef, - ) -> Result, Error> { - let driver = *self.value(); - let address = query_interchain_account( - driver.chain_id.as_str(), - &driver.command_path, - &driver.home_path, - &driver.rpc_listen_address(), - from.value().as_str(), - connection_id.value().as_str(), - )?; - - Ok(MonoTagged::new(WalletAddress(address))) - } -} - -#[allow(clippy::type_complexity)] -pub fn register_interchain_account( - chain: &MonoTagged, - handle: &Chain, - connection: &ConnectedConnection, -) -> Result< - ( - MonoTagged, - TaggedChannelId, - TaggedPortId, - ), - Error, -> { - let wallet = chain.wallets().relayer().cloned(); - - let owner = handle.get_signer()?; - - let version_str = format!("{{\"version\":\"ics27-1\",\"encoding\":\"proto3\",\"tx_type\":\"sdk_multi_msg\",\"controller_connection_id\":\"{}\",\"host_connection_id\":\"{}\"}}", connection.connection_id_a.0, connection.connection_id_b.0); - let msg = MsgRegisterInterchainAccount { - owner, - connection_id: connection.connection_id_a.0.clone(), - version: Version::new(version_str), - ordering: Ordering::Unordered, - }; - - let msg_any = msg.to_any(); - - let tm = TrackedMsgs::new_static(vec![msg_any], "RegisterInterchainAccount"); - - let events = handle - .send_messages_and_wait_commit(tm) - .map_err(Error::relayer)?; - - for event in events.iter() { - if let IbcEvent::OpenInitChannel(open_init) = &event.event { - let channel_id = open_init.channel_id.clone().ok_or(()).map_err(|_| Error::generic(eyre!("channel_id is empty in the event response after sending MsgRegisterInterchainAccount")))?; - return Ok(( - wallet, - TaggedChannelId::new(channel_id), - TaggedPortId::new(open_init.port_id.clone()), - )); - } - } - - Err(Error::generic(eyre!("could not retrieve an OpenInitChannel event resonse after sending MsgRegisterInterchainAccount"))) -} diff --git a/tools/test-framework/src/chain/ext/mod.rs b/tools/test-framework/src/chain/ext/mod.rs deleted file mode 100644 index 23f9ea194..000000000 --- a/tools/test-framework/src/chain/ext/mod.rs +++ /dev/null @@ -1,10 +0,0 @@ -pub mod bootstrap; -pub mod crosschainquery; -pub mod fee; -pub mod fee_grant; -pub mod forward; -pub mod ica; -pub mod proposal; -pub mod transfer; -pub mod version; -pub mod wait_chain; diff --git a/tools/test-framework/src/chain/ext/proposal.rs b/tools/test-framework/src/chain/ext/proposal.rs deleted file mode 100644 index 7d3fe5d7a..000000000 --- a/tools/test-framework/src/chain/ext/proposal.rs +++ /dev/null @@ -1,96 +0,0 @@ -use eyre::eyre; -use http::Uri; -use ibc_proto::cosmos::gov::v1beta1::query_client::QueryClient; -use ibc_proto::cosmos::gov::v1beta1::QueryProposalRequest; -use ibc_proto::ibc::core::client::v1::UpgradeProposal; -use ibc_relayer::config::default::max_grpc_decoding_size; -use ibc_relayer::error::Error as RelayerError; -use prost::Message; - -use crate::chain::cli::upgrade::vote_proposal; -use crate::chain::driver::ChainDriver; -use crate::error::Error; -use crate::prelude::handle_generic_error; -use crate::types::tagged::*; - -pub trait ChainProposalMethodsExt { - fn query_upgrade_proposal_height( - &self, - grpc_address: &Uri, - proposal_id: u64, - ) -> Result; - - fn vote_proposal(&self, fees: &str) -> Result<(), Error>; -} - -impl ChainProposalMethodsExt for MonoTagged { - fn query_upgrade_proposal_height( - &self, - grpc_address: &Uri, - proposal_id: u64, - ) -> Result { - self.value() - .runtime - .block_on(query_upgrade_proposal_height(grpc_address, proposal_id)) - } - - fn vote_proposal(&self, fees: &str) -> Result<(), Error> { - vote_proposal( - self.value().chain_id.as_str(), - &self.value().command_path, - &self.value().home_path, - &self.value().rpc_listen_address(), - fees, - )?; - Ok(()) - } -} - -/// Query the proposal with the given proposal_id, which is supposed to be an UpgradeProposal. -/// Extract the Plan from the UpgradeProposal and get the height at which the chain upgrades, -/// from the Plan. -pub async fn query_upgrade_proposal_height( - grpc_address: &Uri, - proposal_id: u64, -) -> Result { - let mut client = match QueryClient::connect(grpc_address.clone()).await { - Ok(client) => client, - Err(_) => { - return Err(Error::query_client()); - } - }; - - client = client.max_decoding_message_size(max_grpc_decoding_size().get_bytes() as usize); - - let request = tonic::Request::new(QueryProposalRequest { proposal_id }); - - let response = client - .proposal(request) - .await - .map(|r| r.into_inner()) - .map_err(|e| RelayerError::grpc_status(e, "query_upgrade_proposal_height".to_owned()))?; - - // Querying for a balance might fail, i.e. if the account doesn't actually exist - let proposal = response - .proposal - .ok_or_else(|| RelayerError::empty_query_account(proposal_id.to_string()))?; - - let proposal_content = proposal - .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 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 UpgradeProposal"))?; - - Ok(plan.height as u64) -} diff --git a/tools/test-framework/src/chain/ext/transfer.rs b/tools/test-framework/src/chain/ext/transfer.rs deleted file mode 100644 index cdd9a75ad..000000000 --- a/tools/test-framework/src/chain/ext/transfer.rs +++ /dev/null @@ -1,200 +0,0 @@ -use core::time::Duration; - -use ibc_relayer_types::core::ics02_client::height::Height; -use ibc_relayer_types::core::ics04_channel::packet::Packet; -use ibc_relayer_types::core::ics24_host::identifier::{ChannelId, PortId}; - -use crate::chain::cli::transfer::{local_transfer_token, transfer_from_chain}; -use crate::chain::driver::ChainDriver; -use crate::chain::tagged::TaggedChainDriverExt; -use crate::error::Error; -use crate::ibc::token::TaggedTokenRef; -use crate::relayer::transfer::{batched_ibc_token_transfer, ibc_token_transfer}; -use crate::types::id::{TaggedChannelIdRef, TaggedPortIdRef}; -use crate::types::tagged::*; -use crate::types::wallet::{Wallet, WalletAddress}; - -pub trait ChainTransferMethodsExt { - /** - Submits an IBC token transfer transaction to `Chain` to any other - `Counterparty` chain. - - The following parameters are accepted: - - - A `PortId` on `Chain` that corresponds to a channel connected to - `Counterparty`. - - - A `ChannelId` on `Chain` that corresponds to a channel connected to - `Counterparty`. - - - The [`Wallet`] of the sender on `Chain`. - - - The [`WalletAddress`] address of the recipient on `Counterparty`. - - - The denomination of the amount on `Chain`. - - - The transfer amount. - */ - fn ibc_transfer_token( - &self, - port_id: &TaggedPortIdRef, - channel_id: &TaggedChannelIdRef, - sender: &MonoTagged, - recipient: &MonoTagged, - token: &TaggedTokenRef, - ) -> Result; - - fn ibc_transfer_token_with_memo_and_timeout( - &self, - port_id: &TaggedPortIdRef, - channel_id: &TaggedChannelIdRef, - sender: &MonoTagged, - recipient: &MonoTagged, - token: &TaggedTokenRef, - memo: Option, - timeout: Option, - ) -> Result; - - fn ibc_transfer_token_multiple( - &self, - port_id: &TaggedPortIdRef, - channel_id: &TaggedChannelIdRef, - sender: &MonoTagged, - recipient: &MonoTagged, - token: &TaggedTokenRef, - num_msgs: usize, - memo: Option, - ) -> Result<(), Error>; - - fn local_transfer_token( - &self, - sender: &MonoTagged, - recipient: &MonoTagged, - token: &TaggedTokenRef, - ) -> Result<(), Error>; - - fn transfer_from_chain( - &self, - sender: &MonoTagged, - recipient: &MonoTagged, - port: &PortId, - channel: &ChannelId, - token: &TaggedTokenRef, - timeout_height: &Height, - ) -> Result<(), Error>; -} - -impl ChainTransferMethodsExt for MonoTagged { - fn ibc_transfer_token( - &self, - port_id: &TaggedPortIdRef, - channel_id: &TaggedChannelIdRef, - sender: &MonoTagged, - recipient: &MonoTagged, - token: &TaggedTokenRef, - ) -> Result { - let rpc_client = self.rpc_client()?; - self.value().runtime.block_on(ibc_token_transfer( - rpc_client.as_ref(), - &self.tx_config(), - port_id, - channel_id, - sender, - recipient, - token, - None, - None, - )) - } - - fn ibc_transfer_token_with_memo_and_timeout( - &self, - port_id: &TaggedPortIdRef, - channel_id: &TaggedChannelIdRef, - sender: &MonoTagged, - recipient: &MonoTagged, - token: &TaggedTokenRef, - memo: Option, - timeout: Option, - ) -> Result { - let rpc_client = self.rpc_client()?; - self.value().runtime.block_on(ibc_token_transfer( - rpc_client.as_ref(), - &self.tx_config(), - port_id, - channel_id, - sender, - recipient, - token, - memo, - timeout, - )) - } - - fn ibc_transfer_token_multiple( - &self, - port_id: &TaggedPortIdRef, - channel_id: &TaggedChannelIdRef, - sender: &MonoTagged, - recipient: &MonoTagged, - token: &TaggedTokenRef, - num_msgs: usize, - memo: Option, - ) -> Result<(), Error> { - let rpc_client = self.rpc_client()?; - self.value().runtime.block_on(batched_ibc_token_transfer( - rpc_client.as_ref(), - &self.tx_config(), - port_id, - channel_id, - sender, - recipient, - token, - num_msgs, - memo, - )) - } - - fn local_transfer_token( - &self, - sender: &MonoTagged, - recipient: &MonoTagged, - token: &TaggedTokenRef, - ) -> Result<(), Error> { - let driver = *self.value(); - local_transfer_token( - driver.chain_id.as_str(), - &driver.command_path, - &driver.home_path, - &driver.rpc_listen_address(), - sender.value().address.as_str(), - recipient.value().as_str(), - &token.value().to_string(), - ) - } - - fn transfer_from_chain( - &self, - sender: &MonoTagged, - recipient: &MonoTagged, - port: &PortId, - channel: &ChannelId, - token: &TaggedTokenRef, - timeout_height: &Height, - ) -> Result<(), Error> { - let driver = *self.value(); - let timeout_height_str = timeout_height.revision_height() + 100; - transfer_from_chain( - driver.chain_id.as_str(), - &driver.command_path, - &driver.home_path, - &driver.rpc_listen_address(), - sender.value().address.as_str(), - port.as_ref(), - channel.as_ref(), - recipient.value().as_str(), - &token.value().to_string(), - &timeout_height_str.to_string(), - ) - } -} diff --git a/tools/test-framework/src/chain/ext/version.rs b/tools/test-framework/src/chain/ext/version.rs deleted file mode 100644 index 3156ddacd..000000000 --- a/tools/test-framework/src/chain/ext/version.rs +++ /dev/null @@ -1,14 +0,0 @@ -use crate::chain::cli::version::major_version; -use crate::chain::driver::ChainDriver; -use crate::error::Error; -use crate::types::tagged::*; - -pub trait ChainVersionMethodsExt { - fn major_version(&self) -> Result; -} - -impl ChainVersionMethodsExt for MonoTagged { - fn major_version(&self) -> Result { - major_version(&self.value().command_path) - } -} diff --git a/tools/test-framework/src/chain/ext/wait_chain.rs b/tools/test-framework/src/chain/ext/wait_chain.rs deleted file mode 100644 index 1b8e07e05..000000000 --- a/tools/test-framework/src/chain/ext/wait_chain.rs +++ /dev/null @@ -1,43 +0,0 @@ -use std::time::SystemTime; - -use ibc_relayer_types::core::ics02_client::height::Height; - -use crate::prelude::*; - -/// Wait for a chain to get to a desired height, and timeout if -/// the chain didn't get to that height in the desired amount of -/// time. -pub fn wait_for_chain_height( - foreign_clients: &ForeignClientPair, - target_height_of_a: Height, - timeout_bound: Duration, -) -> Result<(), Error> { - // Query the latest height of the chain - let mut reference_application_latest_height = foreign_clients - .client_a_to_b - .src_chain() - .query_latest_height()?; - - let start = SystemTime::now(); - while reference_application_latest_height < target_height_of_a { - // Check if the wait time has timed out. - let elapsed_time = SystemTime::now() - .duration_since(start) - .map_err(handle_generic_error)?; - - if elapsed_time > timeout_bound { - return Err(Error::generic(eyre!( - "chain did not reach desired height after {} seconds", - timeout_bound.as_secs() - ))); - } - std::thread::sleep(Duration::from_millis(500)); - - // Query the latest height of the chain - reference_application_latest_height = foreign_clients - .client_a_to_b - .src_chain() - .query_latest_height()?; - } - Ok(()) -} diff --git a/tools/test-framework/src/chain/mod.rs b/tools/test-framework/src/chain/mod.rs deleted file mode 100644 index 81a1f1415..000000000 --- a/tools/test-framework/src/chain/mod.rs +++ /dev/null @@ -1,25 +0,0 @@ -/*! - Constructs for spawning and managing full nodes, e.g. the - Gaia chains. - - Note that this is different from the "chains" being referred on - the relayer side in [`ibc_relayer`]. In testing we also need - to refer to the actual chains running rather than the chain client that - communicate with the chain. - - There is not yet good terminology to differentiate the two sides. - For now we will refer to the running chains as full nodes or - chain servers when qualification is needed, while keeping the original - chain terminology in the relayer unchanged to avoid having to - rename existing constructs in the relayer code. -*/ - -pub mod builder; -pub mod chain_type; -pub mod cli; -pub mod config; -pub mod driver; -pub mod exec; -pub mod ext; -pub mod tagged; -pub mod version; diff --git a/tools/test-framework/src/chain/tagged.rs b/tools/test-framework/src/chain/tagged.rs deleted file mode 100644 index d4093644b..000000000 --- a/tools/test-framework/src/chain/tagged.rs +++ /dev/null @@ -1,157 +0,0 @@ -/*! - Methods for tagged version of the chain driver. -*/ - -use ibc_proto::google::protobuf::Any; -use ibc_relayer::chain::cosmos::tx::simple_send_tx; -use ibc_relayer::chain::cosmos::types::config::TxConfig; -use ibc_relayer::event::IbcEventWithHeight; -use serde_json as json; -use tendermint_rpc::client::{Client, CompatMode, HttpClient}; - -use crate::chain::cli::query::query_recipient_transactions; -use crate::chain::driver::ChainDriver; -use crate::error::{handle_generic_error, Error}; -use crate::ibc::denom::Denom; -use crate::ibc::token::{TaggedDenomExt, TaggedToken, TaggedTokenRef}; -use crate::types::id::TaggedChainIdRef; -use crate::types::tagged::*; -use crate::types::wallet::{Wallet, WalletAddress}; - -/** - A [`ChainDriver`] may be tagged with a `Chain` tag in the form - [`MonoTagged`]. - - It would implement the [`TaggedChainDriverExt`] trait to provide tagged - version of the chain methods. - - The tagged chain driver methods help ensure that the `ChainDriver` - methods are used with the values associated to the correct chain. -*/ -pub trait TaggedChainDriverExt { - fn chain_id(&self) -> TaggedChainIdRef; - - fn tx_config(&self) -> MonoTagged; - - /// Sets up an RPC client for making requests to the chain node. - /// - /// The RPC server must be running and be able to respond on the - /// `/status` endpoint. - fn rpc_client(&self) -> Result, Error>; - - fn send_tx( - &self, - wallet: &MonoTagged, - messages: Vec, - ) -> Result, Error>; - - /** - Tagged version of [`ChainDriver::query_balance`]. - - Query for the balance of a wallet that belongs to `Chain` - in the denomination that belongs to `Chain`. - */ - fn query_balance( - &self, - wallet_id: &MonoTagged, - denom: &MonoTagged, - ) -> Result, Error>; - - /** - Tagged version of [`ChainDriver::assert_eventual_wallet_amount`]. - - Assert that a wallet belongs to `Chain` would reach the target - amount in the denomination that belongs to `Chain`. - */ - fn assert_eventual_wallet_amount( - &self, - user: &MonoTagged, - token: &TaggedTokenRef, - ) -> Result<(), Error>; - - /** - Taggged version of [`query_recipient_transactions`]. - - Query for the transactions related to a wallet on `Chain` - receiving token transfer from others. - */ - fn query_recipient_transactions( - &self, - recipient_address: &MonoTagged, - ) -> Result; -} - -impl TaggedChainDriverExt for MonoTagged { - fn chain_id(&self) -> TaggedChainIdRef { - self.map_ref(|val| &val.chain_id) - } - - fn tx_config(&self) -> MonoTagged { - self.map_ref(|val| &val.tx_config) - } - - fn rpc_client(&self) -> Result, Error> { - let rpc_address = self.value().tx_config.rpc_address.clone(); - let rt = &self.value().runtime; - - let mut client = HttpClient::new(rpc_address).map_err(handle_generic_error)?; - - let status = rt.block_on(client.status()).map_err(handle_generic_error)?; - let compat_mode = - CompatMode::from_version(status.node_info.version).map_err(handle_generic_error)?; - client.set_compat_mode(compat_mode); - - Ok(MonoTagged::new(client)) - } - - fn send_tx( - &self, - wallet: &MonoTagged, - messages: Vec, - ) -> Result, Error> { - let rpc_client = self.rpc_client()?; - - self.value() - .runtime - .block_on(simple_send_tx( - rpc_client.as_ref().into_value(), - &self.value().tx_config, - &wallet.value().key, - messages, - )) - .map_err(Error::relayer) - } - - fn query_balance( - &self, - wallet_id: &MonoTagged, - denom: &MonoTagged, - ) -> Result, Error> { - let balance = self - .value() - .query_balance(wallet_id.value(), denom.value())?; - Ok(denom.with_amount(balance)) - } - - fn assert_eventual_wallet_amount( - &self, - user: &MonoTagged, - token: &TaggedTokenRef, - ) -> Result<(), Error> { - self.value() - .assert_eventual_wallet_amount(user.value(), token.value()) - } - - fn query_recipient_transactions( - &self, - recipient_address: &MonoTagged, - ) -> Result { - let driver = *self.value(); - query_recipient_transactions( - driver.chain_id.as_str(), - &driver.command_path, - &driver.rpc_listen_address(), - &recipient_address.value().0, - ) - } -} diff --git a/tools/test-framework/src/chain/version.rs b/tools/test-framework/src/chain/version.rs deleted file mode 100644 index db27cd094..000000000 --- a/tools/test-framework/src/chain/version.rs +++ /dev/null @@ -1,29 +0,0 @@ -use semver::Version; -use tracing::debug; - -use crate::chain::exec::simple_exec; -use crate::error::{handle_generic_error, Error}; - -pub fn get_chain_command_version(command: &str) -> Result, Error> { - let output = simple_exec("version-command", command, &["version"])?; - - // gaia6 somehow outputs version string result in STDERR - let raw_version_str = if output.stdout.is_empty() { - output.stderr - } else { - output.stdout - }; - - let version_str = match raw_version_str.trim().strip_prefix('v') { - Some(str) => str.trim(), - None => raw_version_str.trim(), - }; - - debug!("parsing version string: {}", version_str); - - let version = Version::parse(version_str) - .map_err(handle_generic_error) - .ok(); - - Ok(version) -} diff --git a/tools/test-framework/src/docs/mod.rs b/tools/test-framework/src/docs/mod.rs deleted file mode 100644 index 276e34792..000000000 --- a/tools/test-framework/src/docs/mod.rs +++ /dev/null @@ -1,3 +0,0 @@ -//! Documentation-only module containing long-form docs and walkthroughs. - -pub mod walkthroughs; diff --git a/tools/test-framework/src/docs/walkthroughs/memo.rs b/tools/test-framework/src/docs/walkthroughs/memo.rs deleted file mode 100644 index 7afbc5f7e..000000000 --- a/tools/test-framework/src/docs/walkthroughs/memo.rs +++ /dev/null @@ -1,130 +0,0 @@ -//! ## Memo Test -//! -//! This walkthrough illustrates an integration test that utilizes a non-empty -//! struct as test input. This test asserts that the process of transferring -//! IBC messages preserves the `memo` field. For the purposes of this explanation, -//! the `memo` field is nothing more than a `String` field for carrying along -//! some arbitrary metadata as part of the transaction. -//! -//! The test in most of its entirety (some parts omitted for brevity) looks like this: -//! -//! ```no_run -//! # use serde_json as json; -//! # use ibc_relayer::config::{types::Memo, Config}; -//! # use ibc_test_framework::framework::next::chain::{CanSpawnRelayer, HasTwoChains, HasTwoChannels}; -//! # use ibc_test_framework::ibc::denom::derive_ibc_denom; -//! # use ibc_test_framework::prelude::*; -//! # use ibc_test_framework::util::random::{random_string, random_u128_range}; -//! -//! #[test] -//! fn test_memo() -> Result<(), Error> { -//! let memo = Memo::new(random_string()).unwrap(); -//! let test = MemoTest { memo }; -//! run_binary_channel_test(&test) -//! } -//! -//! pub struct MemoTest { -//! memo: Memo, -//! } -//! -//! impl TestOverrides for MemoTest { -//! fn modify_relayer_config(&self, config: &mut Config) { -//! for mut chain in config.chains.iter_mut() { -//! chain.memo_prefix = self.memo.clone(); -//! } -//! } -//! } -//! -//! impl BinaryChannelTest for MemoTest { -//! fn run(&self, _relayer: RelayerDriver, context: &Context) -> Result<(), Error> -//! where -//! Context: HasTwoChains + HasTwoChannels + CanSpawnRelayer, -//! { -//! let _handle = context.spawn_relayer()?; -//! let chains = context.chains(); -//! let channel = context.channel(); -//! -//! let denom_a = chains.node_a.denom(); -//! -//! let a_to_b_amount = random_u128_range(1000, 5000); -//! -//! chains.node_a.chain_driver().ibc_transfer_token( -//! &channel.port_a.as_ref(), -//! &channel.channel_id_a.as_ref(), -//! &chains.node_a.wallets().user1(), -//! &chains.node_b.wallets().user1().address(), -//! &denom_a.with_amount(a_to_b_amount).as_ref(), -//! )?; -//! -//! let denom_b = derive_ibc_denom( -//! &channel.port_b.as_ref(), -//! &channel.channel_id_b.as_ref(), -//! &denom_a, -//! )?; -//! -//! chains.node_b.chain_driver().assert_eventual_wallet_amount( -//! &chains.node_b.wallets().user1().address(), -//! &denom_b.with_amount(a_to_b_amount).as_ref(), -//! )?; -//! -//! let tx_info = chains -//! .node_b -//! .chain_driver() -//! .query_recipient_transactions(&chains.node_b.wallets().user1().address())?; -//! -//! assert_tx_memo_equals(&tx_info, self.memo.as_str())?; -//! -//! Ok(()) -//! } -//! } -//! -//! # fn assert_tx_memo_equals(tx_info: &json::Value, expected_memo: &str) -> Result<(), Error> { -//! # debug!("comparing memo field from json value {}", tx_info); -//! # -//! # let memo_field = &tx_info["txs"][0]["tx"]["body"]["memo"]; -//! # -//! # info!("memo field value: {}", memo_field); -//! # -//! # let memo_str = memo_field -//! # .as_str() -//! # .ok_or_else(|| eyre!("expect memo string field to be present in JSON"))?; -//! # -//! # assert_eq!(memo_str, expected_memo); -//! # -//! # Ok(()) -//! # } -//! ``` -//! -//! This test runs initializes a `MemoTest` struct with a random string -//! in the `memo` field, then calls the `run_binary_channel_test` function -//! with it. The `TestOverrides` trait is implemented in order to set the -//! `memo_prefix` configuration value on the chains that are initialized -//! over the course of the test. -//! -//! At a high level, this test performs an IBC token transfer operation -//! from chain A to chain B. Once chain B has received the transaction -//! that chain A initialized, the test asserts that the value of the -//! memo string is indeed what we expected. -//! -//! The first two lines of the `run` function perform some necessary -//! setup for performing an IBC token transfer, namely fetching the -//! coin denomination of chain A as well as generating a random amount -//! of that denomination that will be sent to chain B. It then calls -//! the `ibc_token_transfer` function to generate a transaction with -//! this information, including the memo string that was generated -//! earlier, and sends it to chain B. -//! -//! Next, the `derive_ibc_denom` function is called in order to -//! calculate the appropriate amount of chain B's coin denomination -//! based on chain A's denomination and how much of that denomination -//! was sent over the transaction so that chain B can represent the -//! transferred value. -//! -//! The `assert_eventual_wallet_amount` function is then called on -//! chain B in order to confirm that the transaction was indeed -//! received by checking that chain B's wallet amount reflects the -//! expected updated value. The `query_recipient_transactions` -//! method is then called to fetch the memo value from the transaction -//! so that we can confirm that its value is indeed what we expect. -//! -//! You can find the file containing this test at `tools/integration-test/src/tests/memo.rs`. diff --git a/tools/test-framework/src/docs/walkthroughs/mod.rs b/tools/test-framework/src/docs/walkthroughs/mod.rs deleted file mode 100644 index c30aac061..000000000 --- a/tools/test-framework/src/docs/walkthroughs/mod.rs +++ /dev/null @@ -1,8 +0,0 @@ -//! Walkthroughs of integration tests that are used to test -//! the Hermes relayer in production. Use these walkthroughs -//! as references for writing your own integration tests -//! using the framework. - -pub mod memo; -pub mod ordered_channel; -pub mod simple; diff --git a/tools/test-framework/src/docs/walkthroughs/ordered_channel.rs b/tools/test-framework/src/docs/walkthroughs/ordered_channel.rs deleted file mode 100644 index 58377996e..000000000 --- a/tools/test-framework/src/docs/walkthroughs/ordered_channel.rs +++ /dev/null @@ -1,152 +0,0 @@ -//! ## Ordered Channel Test -//! -//! This walkthrough illustrates the behavior or an integration test that makes -//! use of the `BinaryChannelTest` trait. This trait is used for test cases that -//! require two running full nodes connected via IBC channels with completed -//! handshakes. The relayer is initialized with chain handles and foreign clients -//! for interfacing with the running full nodes. -//! -//! The test itself checks that transactions sent over an ordered channel are -//! successfully relayed and received by the intended recipient, even when the -//! transaction was queued up to be sent before the relayer was started. -//! -//! The test in most of its entirety (some parts omitted for brevity) looks like this: -//! -//! ```no_run -//! # use ibc_test_framework::framework::next::chain::{HasTwoChains, HasTwoChannels}; -//! # use ibc_test_framework::ibc::denom::derive_ibc_denom; -//! # use ibc_test_framework::prelude::*; -//! # use ibc_test_framework::util::random::random_u128_range; -//! -//! #[test] -//! fn test_ordered_channel() -> Result<(), Error> { -//! run_binary_channel_test(&OrderedChannelTest) -//! } -//! -//! pub struct OrderedChannelTest; -//! -//! impl TestOverrides for OrderedChannelTest { -//! fn modify_relayer_config(&self, config: &mut Config) { -//! config.mode.packets.clear_on_start = false; -//! config.mode.packets.clear_interval = 0; -//! } -//! -//! fn should_spawn_supervisor(&self) -> bool { -//! false -//! } -//! -//! fn channel_order(&self) -> Ordering { -//! Ordering::Ordered -//! } -//! } -//! -//! impl BinaryChannelTest for OrderedChannelTest { -//! fn run(&self, relayer: RelayerDriver, context: &Context) -> Result<(), Error> -//! where -//! Context: HasTwoChains + HasTwoChannels, -//! { -//! let chains = context.chains(); -//! let channel = context.channel(); -//! let denom_a = chains.node_a.denom(); -//! -//! let wallet_a = chains.node_a.wallets().user1().cloned(); -//! let wallet_b = chains.node_b.wallets().user1().cloned(); -//! -//! let balance_a = chains -//! .node_a -//! .chain_driver() -//! .query_balance(&wallet_a.address(), &denom_a)?; -//! -//! let amount1 = random_u128_range(1000, 5000); -//! -//! info!( -//! "Performing IBC transfer with amount {}, which should be relayed because it's an ordered channel", -//! amount1 -//! ); -//! -//! chains.node_a.chain_driver().ibc_transfer_token( -//! &channel.port_a.as_ref(), -//! &channel.channel_id_a.as_ref(), -//! &wallet_a.as_ref(), -//! &wallet_b.address(), -//! &denom_a.with_amount(amount1).as_ref(), -//! )?; -//! -//! sleep(Duration::from_secs(1)); -//! -//! relayer.with_supervisor(|| { -//! sleep(Duration::from_secs(1)); -//! -//! let amount2 = random_u128_range(1000, 5000); -//! -//! info!( -//! "Performing IBC transfer with amount {}, which should be relayed", -//! amount2 -//! ); -//! -//! chains.node_a.chain_driver().ibc_transfer_token( -//! &channel.port_a.as_ref(), -//! &channel.channel_id_a.as_ref(), -//! &wallet_a.as_ref(), -//! &wallet_b.address(), -//! &denom_a.with_amount(amount2).as_ref(), -//! )?; -//! -//! sleep(Duration::from_secs(1)); -//! -//! let denom_b = derive_ibc_denom( -//! &channel.port_b.as_ref(), -//! &channel.channel_id_b.as_ref(), -//! &denom_a, -//! )?; -//! -//! chains.node_a.chain_driver().assert_eventual_wallet_amount( -//! &wallet_a.address(), -//! &(balance_a - amount1 - amount2).as_ref(), -//! )?; -//! -//! chains.node_b.chain_driver().assert_eventual_wallet_amount( -//! &wallet_b.address(), -//! &denom_b.with_amount(amount1 + amount2).as_ref(), -//! )?; -//! -//! Ok(()) -//! }) -//! } -//! } -//! ``` -//! -//! The test is run by calling the `run_binary_channel_test` function, passing it -//! a struct, `OrderdChannelTest`, upon which we implement the `TestOverrides` -//! trait in order to configure the behavior of the test. We define the -//! `should_spawn_supervisor` function to have it return false in order to not -//! automatically spawn a supervisor when the relayer is initialized; this is -//! necessary in order to queue up an IBC transaction such that it is pending -//! until the relayer is initialized, not before that. We also define the -//! `channel_order` function in order to set the initialized channels to the -//! ordered variant; by default, the test will initialize unordered channels. -//! Lastly, we define the `modify_relayer_config` function in order to toggle off -//! the `clear_on_start` option, as well as set the `clear_interval` option to 0. -//! Setting these options means the relayer itself will not relay any packets -//! that were pending before the relayer started; we want to ensure that the -//! behavior of the ordered channel is what is causing the pending transaction -//! to be relayed. -//! -//! The logic of the test itself is defined in the `run` function of the -//! `BinaryChannelTest` trait. In this function, we first set up the two wallets, -//! the sending wallet, `wallet_a`, which is associated with chain A, and the -//! receiving wallet, `wallet_b`, which is associated iwth chain B. The balance -//! of `wallet_a` is also saved. An IBC transfer is then made from chain A to chain -//! B. At this point, because no relayer has been initialized yet, the transaction -//! is in a pending state. -//! -//! At this point, a relayer instance is initialized. The first thing it does is -//! perform another IBC transfer from chain A to chain B. The test then asserts -//! that `wallet_a` was indeed debited appropriately, that both transactions went -//! through due to the behavior of the ordered channel. It then checks `wallet_b`'s -//! balance to ensure that it was credited with the expected amount. If the assertions -//! pass, we can confident that the ordered channel is indeed exhibiting the expected -//! behavior of picking up pending transactions that were queued up before the relayer -//! was started. -//! -//! You can find the file containing this test at `tools/integration-test/src/tests/ordered_channel.rs`. diff --git a/tools/test-framework/src/docs/walkthroughs/simple.rs b/tools/test-framework/src/docs/walkthroughs/simple.rs deleted file mode 100644 index b426630c5..000000000 --- a/tools/test-framework/src/docs/walkthroughs/simple.rs +++ /dev/null @@ -1,66 +0,0 @@ -//! ## Simple Test -//! -//! Here's an example of a simple test that showcases some of the important features that the -//! framework exposes: -//! -//! ```no_run -//! # use ibc_test_framework::prelude::*; -//! -//! pub struct ExampleTest; -//! -//! #[test] -//! pub fn example_test() -> Result<(), Error> { -//! run_binary_channel_test(&ExampleTest) -//! } -//! -//! impl TestOverrides for ExampleTest {} -//! -//! impl BinaryChannelTest for ExampleTest { -//! fn run( -//! &self, -//! _relayer: RelayerDriver, -//! _context: &Context -//! ) -> Result<(), Error> { -//! suspend() -//! } -//! } -//! ``` -//! -//! The `example_test` function is the top-most function that drives the test itself. The top- -//! most test function typically does nothing more than to specify what kind of test we want -//! to run. In the case of this example, we're running a -//! [`BinaryChannelTest`](crate::framework::binary::channel::BinaryChannelTest), -//! which sets up a relayer instance between two full nodes connected via IBC channels with -//! completed handshakes. -//! -//! Note that the `run_binary_channel_test` (and indeed every `run_*` test function) takes as -//! its single parameter an struct that represents the test case. While in this case, the struct -//! is empty, fields can be added to the struct in the case that you want to run multiple tests -//! using it. See `tools/test-framework/src/docs/walkthroughs/memo.rs` as an example -//! of a test that utilizes a non-empty struct as input. In order to customize the behavior -//! of a test, different traits need to implemented on the empty struct, depending on how you -//! wish to modify the test. -//! -//! This example tests showcases implementing the `TestOverrides` trait, which is used to set -//! configuration and initialization values for the relayer instance that is being tested (in -//! this case though, nothing is being overriden). -//! -//! The main logic of the test is implemented in the `run` function of the `BinaryChannelTest` -//! trait. This trait is implemented for our empty test struct since we're choosing to run a -//! test between two chains connected via IBC channels. If we had instead opted to run a binary -//! _chain_ test using the `run_binary_chain_test`, then we would instead implement the -//! [`BinaryChainTest`](crate::framework::binary::channel::BinaryChannelTest) -//! trait for our empty test struct. -//! -//! The `run` function's parameters are: -//! 1. `config`: for accessing any test-specific configuration values during the course of the test -//! 2. `relayer`: the relayer instance that is being tested -//! 3. `chains`: handles to the two chains, `ChainA` and `ChainB`, that are being relayed between -//! 4. `channel`: handles to the uni-directional channels connecting both ends of the two chains -//! -//! In this simple example test, the `run` function simply calls the `suspend` function, -//! which suspends the test indefinitely. While this means the test will never actually -//! pass, we can use this as a starting point in order to perform _manual testing_ with -//! the chains that have been set up in the test. -//! -//! You can find the file containing this example test at `tools/integration-test/src/tests/example.rs`. diff --git a/tools/test-framework/src/error.rs b/tools/test-framework/src/error.rs deleted file mode 100644 index a7f1e782d..000000000 --- a/tools/test-framework/src/error.rs +++ /dev/null @@ -1,156 +0,0 @@ -//! Error type used for the tests. - -use core::convert::{From, Into}; -use std::io::{Error as IoError, ErrorKind as IoErrorKind}; - -use eyre::Report; -use flex_error::{define_error, TraceError}; -use ibc_relayer::channel::error::ChannelError; -use ibc_relayer::connection::ConnectionError; -use ibc_relayer::error::Error as RelayerError; -use ibc_relayer::foreign_client::ForeignClientError; -use ibc_relayer::link::error::LinkError; -use ibc_relayer::supervisor::error::Error as SupervisorError; -use ibc_relayer::transfer::TransferError; -use ibc_relayer::upgrade_chain::UpgradeChainError; - -define_error! { - Error { - Generic - [ TraceError ] - | _ | { "generic error" }, - - Assertion - { message: String } - | e | { format_args!("assertion failure: {}", e.message) }, - - Io - [ TraceError ] - | _ | { "io error"}, - - CommandNotFound - { command: String } - [ TraceError ] - | e | { format_args!("failed to execute command: {}. make sure it is available in $PATH", e.command) }, - - Relayer - [ RelayerError ] - | _ | { "relayer error"}, - - Supervisor - [ SupervisorError ] - | _ | { "supervisor error"}, - - Channel - [ ChannelError ] - | _ | { "channel error"}, - - Connection - [ ConnectionError ] - | _ | { "connection error"}, - - Transfer - [ TransferError ] - | _ | { "transfer error"}, - - Link - [ LinkError ] - | _ | { "link error" }, - - Retry - { - task_name: String, - attempts: u16, - } - | e | { - format_args!( - "Expected task to eventually succeeed, but failed after {} attempts: {}", - e.attempts, - e.task_name - ) - }, - - UpgradeChain - [ UpgradeChainError ] - | _ | { "upgrade chain error" }, - - ForeignClient - [ ForeignClientError ] - | _ | { "foreign client error" }, - - QueryClient - | _ | { "error querying client" }, - - IncorrectProposal - | _ | { "error decoding the Proposal to an UpgradeProposal" }, - - IncorrectProposalTypeUrl - { type_url: String } - | e | format_args!("expected /ibc.core.client.v1.UpgradeProposal but got {}", e.type_url), - - EmptyProposal - | _ | { "the Proposal content is empty" }, - - EmptyPlan - | _ | { "The plan in the UpgradeProposal is empty" }, - } -} - -pub fn handle_generic_error(e: impl Into) -> Error { - Error::generic(e.into()) -} - -pub fn handle_exec_error(command: &str) -> impl FnOnce(IoError) -> Error + '_ { - |e| match e.kind() { - IoErrorKind::NotFound => Error::command_not_found(command.to_string(), e), - _ => Error::io(e), - } -} - -impl From for Error { - fn from(e: Report) -> Self { - Error::generic(e) - } -} - -impl From for Error { - fn from(e: IoError) -> Self { - Error::io(e) - } -} - -impl From for Error { - fn from(e: RelayerError) -> Self { - Error::relayer(e) - } -} - -impl From for Error { - fn from(e: SupervisorError) -> Self { - Error::supervisor(e) - } -} - -impl From for Error { - fn from(e: ChannelError) -> Self { - Error::channel(e) - } -} - -impl From for Error { - fn from(e: ConnectionError) -> Self { - Error::connection(e) - } -} - -impl From for Error { - fn from(e: TransferError) -> Self { - Error::transfer(e) - } -} - -impl From for Error { - fn from(e: LinkError) -> Self { - Error::link(e) - } -} diff --git a/tools/test-framework/src/framework/base.rs b/tools/test-framework/src/framework/base.rs deleted file mode 100644 index 7d0306131..000000000 --- a/tools/test-framework/src/framework/base.rs +++ /dev/null @@ -1,109 +0,0 @@ -/*! - Base infrastructure for the test framework. Includes basic setup for - initializing the logger and loading the test configuration. -*/ - -use alloc::sync::Arc; - -use tokio::runtime::Runtime; -use tracing::info; - -use crate::bootstrap::init::init_test; -use crate::chain::builder::ChainBuilder; -use crate::error::Error; -use crate::types::config::TestConfig; - -/** - Runs a primitive test case implementing [`PrimitiveTest`]. -*/ -pub fn run_test(test: &Test) -> Result<(), Error> { - test.run() -} - -/** - Runs a basic test case implementing [`BasicTest`]. -*/ -pub fn run_basic_test(test: &Test) -> Result<(), Error> -where - Test: BasicTest, - Test: HasOverrides, - Overrides: TestConfigOverride, -{ - run_test(&RunBasicTest { test }) -} - -/** - Used for test case wrappers to indicate that the inner test case - implements override traits for overriding certain behavior of the test. - - Test writers do not need to be aware of this trait, as this is - automatically handled by - [TestOverrides](crate::framework::overrides::TestOverrides). -*/ -pub trait HasOverrides { - /** - The inner type that implements the override traits. - */ - type Overrides; - - /** - Get the reference to the inner override type. - */ - fn get_overrides(&self) -> &Self::Overrides; -} - -/** - A primitive test case provides no additional logic. -*/ -pub trait PrimitiveTest { - /// Test runner - fn run(&self) -> Result<(), Error>; -} - -/** - A basic test has the minimal test setup that is essential for almost all - tests. - - The test runner is given a [`TestConfig`] and [`ChainBuilder`], which - provides the essential customization for how the tests should be run. -*/ -pub trait BasicTest { - /// Test runner - fn run(&self, config: &TestConfig, builder: &ChainBuilder) -> Result<(), Error>; -} - -pub trait TestConfigOverride { - fn modify_test_config(&self, config: &mut TestConfig); -} - -/** - A wrapper type that lifts a test case that implements [`BasicTest`] - into a test case that implements [`PrimitiveTest`]. -*/ -pub struct RunBasicTest<'a, Test> { - /// Inner test - pub test: &'a Test, -} - -impl PrimitiveTest for RunBasicTest<'_, Test> -where - Test: BasicTest, - Test: HasOverrides, - Overrides: TestConfigOverride, -{ - fn run(&self) -> Result<(), Error> { - let mut config = init_test()?; - - let runtime = Arc::new(Runtime::new()?); - - self.test.get_overrides().modify_test_config(&mut config); - - info!("starting test with test config: {:?}", config); - - let builder = ChainBuilder::new_with_config(&config, runtime); - - self.test.run(&config, &builder)?; - - Ok(()) - } -} diff --git a/tools/test-framework/src/framework/binary/chain.rs b/tools/test-framework/src/framework/binary/chain.rs deleted file mode 100644 index ccb325425..000000000 --- a/tools/test-framework/src/framework/binary/chain.rs +++ /dev/null @@ -1,350 +0,0 @@ -/*! - Constructs for running test cases with two chains, - together with the relayer setup with chain handles and foreign clients. -*/ - -use ibc_relayer::chain::handle::ChainHandle; -use ibc_relayer::config::Config; -use ibc_relayer::foreign_client::CreateOptions as ClientOptions; -use tracing::info; - -use crate::bootstrap::binary::chain::{bootstrap_chains_with_full_nodes, BootstrapClientOptions}; -use crate::error::Error; -use crate::framework::base::{HasOverrides, TestConfigOverride}; -use crate::framework::binary::ics::InterchainSecurityChainTest; -use crate::framework::binary::node::{ - run_binary_node_test, run_single_node_test, BinaryNodeTest, NodeConfigOverride, - NodeGenesisOverride, -}; -use crate::framework::supervisor::{RunWithSupervisor, SupervisorOverride}; -use crate::relayer::driver::RelayerDriver; -use crate::types::binary::chains::{ConnectedChains, DropChainHandle}; -use crate::types::config::TestConfig; -use crate::types::env::write_env; -use crate::types::single::node::FullNode; -use crate::util::suspend::hang_on_error; - -/** - Runs a test case that implements [`BinaryChainTest`], with - the test case being executed twice, with the second time having the - position of the two chains flipped. -*/ -pub fn run_two_way_binary_chain_test(test: &Test) -> Result<(), Error> -where - Test: BinaryChainTest, - Test: HasOverrides, - Overrides: NodeConfigOverride - + NodeGenesisOverride - + RelayerConfigOverride - + ClientOptionsOverride - + SupervisorOverride - + TestConfigOverride, -{ - run_binary_chain_test(&RunTwoWayBinaryChainTest::new(test)) -} - -/** - Runs a test case that implements [`BinaryChainTest`]. -*/ -pub fn run_binary_chain_test(test: &Test) -> Result<(), Error> -where - Test: BinaryChainTest, - Test: HasOverrides, - Overrides: NodeConfigOverride - + NodeGenesisOverride - + RelayerConfigOverride - + ClientOptionsOverride - + SupervisorOverride - + TestConfigOverride, -{ - run_binary_node_test(&RunBinaryChainTest::new(&RunWithSupervisor::new(test))) -} - -/** - Runs a test case that implements [`BinaryChainTest`], with - the test case being executed with a single chain that is connected - to itself. -*/ -pub fn run_self_connected_binary_chain_test(test: &Test) -> Result<(), Error> -where - Test: BinaryChainTest, - Test: HasOverrides, - Overrides: NodeConfigOverride - + NodeGenesisOverride - + RelayerConfigOverride - + ClientOptionsOverride - + TestConfigOverride, -{ - run_single_node_test(&RunBinaryChainTest::new(test)) -} - -/** - This trait is implemented for test cases that need to have two - full nodes running together with the relayer setup with chain - handles and foreign clients. - - Test writers can use this to implement test cases that only - need the chains and relayers setup without the connection or - channel handshake. -*/ -pub trait BinaryChainTest { - /// Test runner - fn run( - &self, - config: &TestConfig, - relayer: RelayerDriver, - chains: ConnectedChains, - ) -> Result<(), Error>; -} - -/** - An internal trait that can be implemented by test cases to override the - relayer config before the relayer gets initialized. - - This is called by [`RunBinaryChainTest`] after the - full nodes are running and before the relayer is initialized. - - Test writers should implement - [`TestOverrides`](crate::framework::overrides::TestOverrides) - for their test cases instead of implementing this trait directly. -*/ -pub trait RelayerConfigOverride { - /// Modify the relayer config - fn modify_relayer_config(&self, config: &mut Config); -} - -/// An internal trait that can be implemented by test cases to override the -/// settings for the foreign clients bootstrapped for the test. -/// -/// The default implementation returns the settings for a client -/// connecting two Cosmos chains with no customizations. -/// Test writers should implement [`TestOverrides`] -/// for their test cases instead of implementing this trait directly. -/// -/// [`TestOverrides`]: crate::framework::overrides::TestOverrides -/// -pub trait ClientOptionsOverride { - fn client_options_a_to_b(&self) -> ClientOptions { - Default::default() - } - - fn client_options_b_to_a(&self) -> ClientOptions { - Default::default() - } -} - -/** - A wrapper type that lifts a test case that implements [`BinaryChainTest`] - into a test case the implements [`BinaryNodeTest`]. -*/ -pub struct RunBinaryChainTest<'a, Test> { - /// Inner test - pub test: &'a Test, -} - -/** - A wrapper type that lifts a test case that implements [`BinaryChainTest`] - into a test case the implements [`BinaryChainTest`]. - - During execution, the underlying [`BinaryChainTest`] is run twice, with - the second time having the position of the two chains flipped. -*/ -pub struct RunTwoWayBinaryChainTest<'a, Test> { - /// Inner test - pub test: &'a Test, -} - -/** - A wrapper type that lifts a test case that implements [`BinaryChainTest`] - into a test case that implements [`BinaryNodeTest`]. - - During execution, the test case is given a [`ConnectedChains`] with a - single underlying chain that is connected to itself. -*/ -pub struct RunSelfConnectedBinaryChainTest<'a, Test> { - /// Inner test - pub test: &'a Test, -} - -impl<'a, Test> RunBinaryChainTest<'a, Test> -where - Test: BinaryChainTest, -{ - /// Create a new [`RunBinaryChainTest`] - pub fn new(test: &'a Test) -> Self { - Self { test } - } -} - -impl<'a, Test> RunTwoWayBinaryChainTest<'a, Test> -where - Test: BinaryChainTest, -{ - /// Create a new [`RunTwoWayBinaryChainTest`] - pub fn new(test: &'a Test) -> Self { - Self { test } - } -} - -impl<'a, Test> RunSelfConnectedBinaryChainTest<'a, Test> -where - Test: BinaryChainTest, -{ - /// Create a new [`RunSelfConnectedBinaryChainTest`] - pub fn new(test: &'a Test) -> Self { - Self { test } - } -} - -impl BinaryNodeTest for RunBinaryChainTest<'_, Test> -where - Test: BinaryChainTest, - Test: HasOverrides, - Overrides: RelayerConfigOverride + ClientOptionsOverride, -{ - fn run(&self, config: &TestConfig, node_a: FullNode, node_b: FullNode) -> Result<(), Error> { - let overrides = self.test.get_overrides(); - - let bootstrap_options = BootstrapClientOptions::default() - .client_options_a_to_b(overrides.client_options_a_to_b()) - .client_options_b_to_a(overrides.client_options_b_to_a()) - .bootstrap_with_random_ids(config.bootstrap_with_random_ids); - - let (relayer, chains) = bootstrap_chains_with_full_nodes( - config, - node_a, - node_b, - bootstrap_options, - |config| { - overrides.modify_relayer_config(config); - }, - )?; - - let env_path = config.chain_store_dir.join("binary-chains.env"); - - write_env(&env_path, &(&relayer, &chains))?; - - info!("written chains environment to {}", env_path.display()); - - let _drop_handle_a = DropChainHandle(chains.handle_a.clone()); - let _drop_handle_b = DropChainHandle(chains.handle_b.clone()); - - self.test.run(config, relayer, chains)?; - - Ok(()) - } -} - -impl InterchainSecurityChainTest for RunBinaryChainTest<'_, Test> -where - Test: BinaryChainTest, - Test: HasOverrides, - Overrides: RelayerConfigOverride + ClientOptionsOverride, -{ - fn run(&self, config: &TestConfig, node_a: FullNode, node_b: FullNode) -> Result<(), Error> { - let overrides = self.test.get_overrides(); - - let bootstrap_options = BootstrapClientOptions::default() - .client_options_a_to_b(overrides.client_options_a_to_b()) - .client_options_b_to_a(overrides.client_options_b_to_a()) - .bootstrap_with_random_ids(config.bootstrap_with_random_ids); - - let (relayer, chains) = bootstrap_chains_with_full_nodes( - config, - node_a, - node_b, - bootstrap_options, - |config| { - overrides.modify_relayer_config(config); - }, - )?; - - let env_path = config.chain_store_dir.join("binary-chains.env"); - - write_env(&env_path, &(&relayer, &chains))?; - - info!("written chains environment to {}", env_path.display()); - - let _drop_handle_a = DropChainHandle(chains.handle_a.clone()); - let _drop_handle_b = DropChainHandle(chains.handle_b.clone()); - - self.test.run(config, relayer, chains)?; - - Ok(()) - } -} - -impl BinaryChainTest for RunTwoWayBinaryChainTest<'_, Test> { - fn run( - &self, - config: &TestConfig, - relayer: RelayerDriver, - chains: ConnectedChains, - ) -> Result<(), Error> { - info!( - "running two-way chain test, from {} to {}", - chains.chain_id_a(), - chains.chain_id_b(), - ); - - self.test.run(config, relayer.clone(), chains.clone())?; - - info!( - "running two-way chain test in the opposite direction, from {} to {}", - chains.chain_id_b(), - chains.chain_id_a(), - ); - - let chains = chains.flip(); - - self.test.run(config, relayer, chains)?; - - Ok(()) - } -} - -impl BinaryChainTest for RunWithSupervisor<'_, Test> -where - Test: BinaryChainTest, - Test: HasOverrides, - Overrides: SupervisorOverride, -{ - fn run( - &self, - config: &TestConfig, - relayer: RelayerDriver, - chains: ConnectedChains, - ) -> Result<(), Error> { - if self.get_overrides().should_spawn_supervisor() { - relayer - .clone() - .with_supervisor(|| self.test.run(config, relayer, chains)) - } else { - hang_on_error(config.hang_on_fail, || { - self.test.run(config, relayer, chains) - }) - } - } -} - -impl HasOverrides for RunBinaryChainTest<'_, Test> -where - Test: HasOverrides, -{ - type Overrides = Overrides; - - fn get_overrides(&self) -> &Self::Overrides { - self.test.get_overrides() - } -} - -impl HasOverrides for RunTwoWayBinaryChainTest<'_, Test> -where - Test: HasOverrides, -{ - type Overrides = Overrides; - - fn get_overrides(&self) -> &Self::Overrides { - self.test.get_overrides() - } -} diff --git a/tools/test-framework/src/framework/binary/channel.rs b/tools/test-framework/src/framework/binary/channel.rs deleted file mode 100644 index e187d7c5c..000000000 --- a/tools/test-framework/src/framework/binary/channel.rs +++ /dev/null @@ -1,348 +0,0 @@ -/*! - Constructs for running test cases with two full nodes together with the - relayer setup with chain handles and foreign clients, as well as - connected IBC channels with completed handshakes. -*/ -use ibc_relayer::chain::handle::ChainHandle; -use ibc_relayer_types::core::ics04_channel::channel::Ordering; -use ibc_relayer_types::core::ics04_channel::version::Version; -use ibc_relayer_types::core::ics24_host::identifier::PortId; -use tracing::info; - -use crate::bootstrap::binary::channel::{ - bootstrap_channel_with_connection, BootstrapChannelOptions, -}; -use crate::error::Error; -use crate::framework::base::{HasOverrides, TestConfigOverride}; -use crate::framework::binary::chain::{ - ClientOptionsOverride, RelayerConfigOverride, RunBinaryChainTest, -}; -use crate::framework::binary::connection::{ - BinaryConnectionTest, ConnectionDelayOverride, RunBinaryConnectionTest, -}; -use crate::framework::binary::ics::run_binary_interchain_security_node_test; -use crate::framework::binary::node::{ - run_binary_node_test, NodeConfigOverride, NodeGenesisOverride, -}; -use crate::framework::next::chain::{ - CanShutdown, CanSpawnRelayer, CanWaitForAck, HasContextId, HasTestConfig, HasTwoChains, - HasTwoChannels, HasTwoNodes, -}; -use crate::framework::next::context::build_test_context; -use crate::framework::supervisor::{RunWithSupervisor, SupervisorOverride}; -use crate::relayer::driver::RelayerDriver; -use crate::types::binary::chains::ConnectedChains; -use crate::types::binary::connection::ConnectedConnection; -use crate::types::config::TestConfig; -use crate::types::env::write_env; -use crate::types::tagged::*; -use crate::util::suspend::hang_on_error; - -/** - Runs a test case that implements [`BinaryChannelTest`], with - the test case being executed twice, with the second time having the position - of the two chains flipped. -*/ -pub fn run_two_way_binary_channel_test(test: &Test) -> Result<(), Error> -where - Test: BinaryChannelTest, - Test: HasOverrides, - Overrides: TestConfigOverride - + NodeConfigOverride - + NodeGenesisOverride - + RelayerConfigOverride - + ClientOptionsOverride - + SupervisorOverride - + ConnectionDelayOverride - + PortsOverride - + ChannelOrderOverride - + ChannelVersionOverride, -{ - run_binary_channel_test(&RunTwoWayBinaryChannelTest::new(test)) -} - -/** - Runs a test case that implements [`BinaryChannelTest`]. -*/ -pub fn run_binary_channel_test(test: &Test) -> Result<(), Error> -where - Test: BinaryChannelTest, - Test: HasOverrides, - Overrides: TestConfigOverride - + NodeConfigOverride - + NodeGenesisOverride - + RelayerConfigOverride - + ClientOptionsOverride - + SupervisorOverride - + ConnectionDelayOverride - + PortsOverride - + ChannelOrderOverride - + ChannelVersionOverride, -{ - run_binary_node_test(&RunBinaryChainTest::new(&RunBinaryConnectionTest::new( - &RunBinaryChannelTest::new(&RunWithSupervisor::new(test)), - ))) -} - -pub fn run_binary_interchain_security_channel_test( - test: &Test, -) -> Result<(), Error> -where - Test: BinaryChannelTest, - Test: HasOverrides, - Overrides: TestConfigOverride - + NodeConfigOverride - + NodeGenesisOverride - + RelayerConfigOverride - + ClientOptionsOverride - + SupervisorOverride - + ConnectionDelayOverride - + PortsOverride - + ChannelOrderOverride - + ChannelVersionOverride, -{ - run_binary_interchain_security_node_test(&RunBinaryChainTest::new( - &RunBinaryConnectionTest::new(&RunBinaryChannelTest::new(&RunWithSupervisor::new(test))), - )) -} - -/** - This trait is implemented for test cases that need to have two - full nodes running together with the relayer setup with chain - handles and foreign clients, together with connected IBC channels - with completed handshakes. -*/ -pub trait BinaryChannelTest { - /// Test runner - fn run(&self, relayer: RelayerDriver, context: &Context) -> Result<(), Error> - where - Context: HasTwoChains - + HasTwoChannels - + HasTwoNodes - + HasTestConfig - + CanSpawnRelayer - + HasContextId - + CanWaitForAck - + CanShutdown; -} - -/** - An internal trait that can be implemented by test cases to override - the port IDs used when creating the channels. - - This is called by [`RunBinaryChannelTest`] before creating - the IBC channels. - - Test writers should implement - [`TestOverrides`](crate::framework::overrides::TestOverrides) - for their test cases instead of implementing this trait directly. -*/ -pub trait PortsOverride { - /** - Return the port ID for chain A. - */ - fn channel_port_a(&self) -> PortId; - - /** - Return the port ID for chain B. - */ - fn channel_port_b(&self) -> PortId; -} - -/** - An internal trait for test cases to override the channel ordering - when creating channels. - - This is called by [`RunBinaryChannelTest`] before creating - the IBC channels. - - Test writers should implement - [`TestOverrides`](crate::framework::overrides::TestOverrides) - for their test cases instead of implementing this trait directly. -*/ -pub trait ChannelOrderOverride { - /** - Return the channel ordering as [`Ordering`]. - */ - fn channel_order(&self) -> Ordering; -} - -/** Facility for overriding the channel version */ -pub trait ChannelVersionOverride { - fn channel_version(&self) -> Version; -} - -/** - A wrapper type that lifts a test case that implements [`BinaryChannelTest`] - into a test case the implements [`BinaryConnectionTest`]. -*/ -pub struct RunBinaryChannelTest<'a, Test> { - /// Inner test - pub test: &'a Test, -} - -/** - A wrapper type that lifts a test case that implements [`BinaryChannelTest`] - into a test case the implements [`BinaryChannelTest`]. -*/ -pub struct RunTwoWayBinaryChannelTest<'a, Test> { - /// Inner test - pub test: &'a Test, -} - -impl<'a, Test> RunBinaryChannelTest<'a, Test> -where - Test: BinaryChannelTest, -{ - /// Create a new [`RunBinaryChannelTest`] - pub fn new(test: &'a Test) -> Self { - Self { test } - } -} - -impl<'a, Test> RunTwoWayBinaryChannelTest<'a, Test> -where - Test: BinaryChannelTest, -{ - /// Create a new [`BinaryChannelTest`] - pub fn new(test: &'a Test) -> Self { - Self { test } - } -} - -impl BinaryConnectionTest for RunBinaryChannelTest<'_, Test> -where - Test: BinaryChannelTest, - Test: HasOverrides, - Overrides: PortsOverride + ChannelOrderOverride + ChannelVersionOverride, -{ - fn run( - &self, - config: &TestConfig, - relayer: RelayerDriver, - chains: ConnectedChains, - connection: ConnectedConnection, - ) -> Result<(), Error> { - let overrides = self.test.get_overrides(); - - let port_a = overrides.channel_port_a(); - let port_b = overrides.channel_port_b(); - - let bootstrap_options = BootstrapChannelOptions::default() - .order(overrides.channel_order()) - .version(overrides.channel_version()) - .bootstrap_with_random_ids(config.bootstrap_with_random_ids); - - let channels = bootstrap_channel_with_connection( - &chains.handle_a, - &chains.handle_b, - connection, - &DualTagged::new(port_a).as_ref(), - &DualTagged::new(port_b).as_ref(), - bootstrap_options, - )?; - - let env_path = config.chain_store_dir.join("binary-channels.env"); - - write_env(&env_path, &(&chains, &(&relayer, &channels)))?; - - info!("written channel environment to {}", env_path.display()); - - let test_context = build_test_context(config, relayer.clone(), chains, channels)?; - - self.test.run(relayer, &test_context)?; - - Ok(()) - } -} - -impl BinaryChannelTest for RunTwoWayBinaryChannelTest<'_, Test> { - fn run(&self, relayer: RelayerDriver, context: &Context) -> Result<(), Error> - where - Context: HasTwoChains + HasTwoChannels + HasTestConfig, - { - let config = context.config(); - let chains = context.chains().clone(); - let channels = context.channel().clone(); - - info!( - "running two-way channel test, from {}/{} to {}/{}", - chains.chain_id_a(), - channels.channel_id_a, - chains.chain_id_b(), - channels.channel_id_b, - ); - - let test_context = - build_test_context(config, relayer.clone(), chains.clone(), channels.clone())?; - - self.test.run(relayer.clone(), &test_context)?; - - info!( - "running two-way channel test in the opposite direction, from {}/{} to {}/{}", - chains.chain_id_b(), - channels.channel_id_b, - chains.chain_id_a(), - channels.channel_id_a, - ); - - let chains = chains.flip(); - let channels = channels.flip(); - - let test_context = build_test_context(config, relayer.clone(), chains, channels)?; - - self.test.run(relayer, &test_context)?; - - Ok(()) - } -} - -impl BinaryChannelTest for RunWithSupervisor<'_, Test> -where - Test: BinaryChannelTest, - Test: HasOverrides, - Overrides: SupervisorOverride, -{ - fn run(&self, relayer: RelayerDriver, context: &Context) -> Result<(), Error> - where - Context: HasTwoChains - + HasTwoChannels - + HasTwoNodes - + HasTestConfig - + CanSpawnRelayer - + HasContextId - + CanWaitForAck - + CanShutdown, - { - let config = context.config(); - if self.get_overrides().should_spawn_supervisor() { - relayer - .clone() - .with_supervisor(|| self.test.run(relayer, context)) - } else { - hang_on_error(config.hang_on_fail, || self.test.run(relayer, context)) - } - } -} - -impl HasOverrides for RunBinaryChannelTest<'_, Test> -where - Test: HasOverrides, -{ - type Overrides = Overrides; - - fn get_overrides(&self) -> &Self::Overrides { - self.test.get_overrides() - } -} - -impl HasOverrides for RunTwoWayBinaryChannelTest<'_, Test> -where - Test: HasOverrides, -{ - type Overrides = Overrides; - - fn get_overrides(&self) -> &Self::Overrides { - self.test.get_overrides() - } -} diff --git a/tools/test-framework/src/framework/binary/connection.rs b/tools/test-framework/src/framework/binary/connection.rs deleted file mode 100644 index 3d9a98193..000000000 --- a/tools/test-framework/src/framework/binary/connection.rs +++ /dev/null @@ -1,256 +0,0 @@ -/*! - Constructs for running test cases with two full nodes together with the - relayer setup with chain handles and foreign clients, as well as - connected IBC connections with completed handshakes. -*/ - -use core::time::Duration; - -use ibc_relayer::chain::handle::ChainHandle; -use tracing::info; - -use crate::bootstrap::binary::connection::{bootstrap_connection, BootstrapConnectionOptions}; -use crate::error::Error; -use crate::framework::base::{HasOverrides, TestConfigOverride}; -use crate::framework::binary::chain::{ - BinaryChainTest, ClientOptionsOverride, RelayerConfigOverride, RunBinaryChainTest, -}; -use crate::framework::binary::node::{ - run_binary_node_test, NodeConfigOverride, NodeGenesisOverride, -}; -use crate::framework::supervisor::{RunWithSupervisor, SupervisorOverride}; -use crate::relayer::driver::RelayerDriver; -use crate::types::binary::chains::ConnectedChains; -use crate::types::binary::connection::ConnectedConnection; -use crate::types::config::TestConfig; -use crate::types::env::write_env; -use crate::util::suspend::hang_on_error; - -/** - Runs a test case that implements [`BinaryConnectionTest`], with - the test case being executed twice, with the second time having the position - of the two chains flipped. -*/ -pub fn run_two_way_binary_connection_test(test: &Test) -> Result<(), Error> -where - Test: BinaryConnectionTest, - Test: HasOverrides, - Overrides: TestConfigOverride - + NodeConfigOverride - + NodeGenesisOverride - + RelayerConfigOverride - + ClientOptionsOverride - + SupervisorOverride - + ConnectionDelayOverride, -{ - run_binary_connection_test(&RunTwoWayBinaryConnectionTest::new(test)) -} - -/** - Runs a test case that implements [`BinaryConnectionTest`]. -*/ -pub fn run_binary_connection_test(test: &Test) -> Result<(), Error> -where - Test: BinaryConnectionTest, - Test: HasOverrides, - Overrides: TestConfigOverride - + NodeConfigOverride - + NodeGenesisOverride - + RelayerConfigOverride - + ClientOptionsOverride - + SupervisorOverride - + ConnectionDelayOverride, -{ - run_binary_node_test(&RunBinaryChainTest::new(&RunBinaryConnectionTest::new( - &RunWithSupervisor::new(test), - ))) -} - -/** - This trait is implemented for test cases that need to have two - full nodes running together with the relayer setup with chain - handles and foreign clients, together with connected IBC connections - with completed handshakes. - - Test writers can use this to implement test cases that only - need the connection setup without the channel handshake. -*/ -pub trait BinaryConnectionTest { - /// Test runner - fn run( - &self, - config: &TestConfig, - relayer: RelayerDriver, - chains: ConnectedChains, - connection: ConnectedConnection, - ) -> Result<(), Error>; -} - -/** - An internal trait that can be implemented by test cases to override - the connection delay parameter when creating connections. - - This is called by [`RunBinaryConnectionTest`] before creating - the IBC connections. - - Test writers should implement - [`TestOverrides`](crate::framework::overrides::TestOverrides) - for their test cases instead of implementing this trait directly. -*/ -pub trait ConnectionDelayOverride { - /** - Return the connection delay as [`Duration`]. - */ - fn connection_delay(&self) -> Duration; -} - -/** - A wrapper type that lifts a test case that implements [`BinaryConnectionTest`] - into a test case the implements [`BinaryChainTest`]. -*/ -pub struct RunBinaryConnectionTest<'a, Test> { - /// Inner test - pub test: &'a Test, -} - -/** - A wrapper type that lifts a test case that implements [`BinaryConnectionTest`] - into a test case the implements [`BinaryConnectionTest`]. -*/ -pub struct RunTwoWayBinaryConnectionTest<'a, Test> { - /// Inner test - pub test: &'a Test, -} - -impl<'a, Test> RunBinaryConnectionTest<'a, Test> -where - Test: BinaryConnectionTest, -{ - /// Create a new [`RunBinaryConnectionTest`] - pub fn new(test: &'a Test) -> Self { - Self { test } - } -} - -impl<'a, Test> RunTwoWayBinaryConnectionTest<'a, Test> -where - Test: BinaryConnectionTest, -{ - /// Create a new [`BinaryConnectionTest`] - pub fn new(test: &'a Test) -> Self { - Self { test } - } -} - -impl BinaryChainTest for RunBinaryConnectionTest<'_, Test> -where - Test: BinaryConnectionTest, - Test: HasOverrides, - Overrides: ConnectionDelayOverride, -{ - fn run( - &self, - config: &TestConfig, - relayer: RelayerDriver, - chains: ConnectedChains, - ) -> Result<(), Error> { - let bootstrap_options = BootstrapConnectionOptions::default() - .connection_delay(self.get_overrides().connection_delay()) - .bootstrap_with_random_ids(config.bootstrap_with_random_ids); - - let connection = bootstrap_connection(&chains.foreign_clients, bootstrap_options)?; - - let env_path = config.chain_store_dir.join("binary-connections.env"); - - write_env(&env_path, &(&chains, &connection))?; - - info!("written connection environment to {}", env_path.display()); - - self.test.run(config, relayer, chains, connection)?; - - Ok(()) - } -} - -impl BinaryConnectionTest for RunTwoWayBinaryConnectionTest<'_, Test> { - fn run( - &self, - config: &TestConfig, - relayer: RelayerDriver, - chains: ConnectedChains, - connection: ConnectedConnection, - ) -> Result<(), Error> { - info!( - "running two-way connection test, from {}/{} to {}/{}", - chains.chain_id_a(), - connection.connection_id_a, - chains.chain_id_b(), - connection.connection_id_b, - ); - - self.test - .run(config, relayer.clone(), chains.clone(), connection.clone())?; - - info!( - "running two-way connection test in the opposite direction, from {}/{} to {}/{}", - chains.chain_id_b(), - connection.connection_id_b, - chains.chain_id_a(), - connection.connection_id_a, - ); - - let chains = chains.flip(); - let connection = connection.flip(); - - self.test.run(config, relayer, chains, connection)?; - - Ok(()) - } -} - -impl BinaryConnectionTest for RunWithSupervisor<'_, Test> -where - Test: BinaryConnectionTest, - Test: HasOverrides, - Overrides: SupervisorOverride, -{ - fn run( - &self, - config: &TestConfig, - relayer: RelayerDriver, - chains: ConnectedChains, - connection: ConnectedConnection, - ) -> Result<(), Error> { - if self.get_overrides().should_spawn_supervisor() { - relayer - .clone() - .with_supervisor(|| self.test.run(config, relayer, chains, connection)) - } else { - hang_on_error(config.hang_on_fail, || { - self.test.run(config, relayer, chains, connection) - }) - } - } -} - -impl HasOverrides for RunBinaryConnectionTest<'_, Test> -where - Test: HasOverrides, -{ - type Overrides = Overrides; - - fn get_overrides(&self) -> &Self::Overrides { - self.test.get_overrides() - } -} - -impl HasOverrides for RunTwoWayBinaryConnectionTest<'_, Test> -where - Test: HasOverrides, -{ - type Overrides = Overrides; - - fn get_overrides(&self) -> &Self::Overrides { - self.test.get_overrides() - } -} diff --git a/tools/test-framework/src/framework/binary/ics.rs b/tools/test-framework/src/framework/binary/ics.rs deleted file mode 100644 index d5754be4a..000000000 --- a/tools/test-framework/src/framework/binary/ics.rs +++ /dev/null @@ -1,117 +0,0 @@ -use std::str::FromStr; -use std::thread; -use std::time::Duration; - -use crate::bootstrap::consumer::bootstrap_consumer_node; -use crate::bootstrap::single::bootstrap_single_node; -use crate::chain::builder::ChainBuilder; -use crate::chain::chain_type::ChainType; -use crate::chain::cli::upgrade::vote_proposal; -use crate::chain::ext::bootstrap::ChainBootstrapMethodsExt; -use crate::error::Error; -use crate::framework::base::{run_basic_test, BasicTest, HasOverrides, TestConfigOverride}; -use crate::framework::binary::node::{NodeConfigOverride, NodeGenesisOverride}; -use crate::prelude::FullNode; -use crate::types::config::TestConfig; - -/** -Runs a test case that implements [`InterchainSecurityChainTest`]. -*/ -pub fn run_binary_interchain_security_node_test(test: &Test) -> Result<(), Error> -where - Test: InterchainSecurityChainTest, - Test: HasOverrides, - Overrides: NodeConfigOverride + NodeGenesisOverride + TestConfigOverride, -{ - run_basic_test(&RunInterchainSecurityChainTest { test }) -} -pub trait InterchainSecurityChainTest { - /// Test runner - fn run(&self, config: &TestConfig, node_a: FullNode, node_b: FullNode) -> Result<(), Error>; -} - -/** - A wrapper type that lifts a test case that implements [`InterchainSecurityChainTest`] - into a test case the implements [`BasicTest`]. -*/ -pub struct RunInterchainSecurityChainTest<'a, Test> { - /// Inner test - pub test: &'a Test, -} - -impl<'a, Test> RunInterchainSecurityChainTest<'a, Test> -where - Test: InterchainSecurityChainTest, -{ - /// Create a new [`InterchainSecurityChainTest`] - pub fn new(test: &'a Test) -> Self { - Self { test } - } -} - -impl BasicTest for RunInterchainSecurityChainTest<'_, Test> -where - Test: InterchainSecurityChainTest, - Test: HasOverrides, - Overrides: NodeConfigOverride + NodeGenesisOverride, -{ - fn run(&self, config: &TestConfig, builder: &ChainBuilder) -> Result<(), Error> { - // Bootstrap provider - let node_a = bootstrap_single_node( - builder, - "provider", - false, - |config| self.test.get_overrides().modify_node_config(config), - |genesis| self.test.get_overrides().modify_genesis_file(genesis), - 0, - )?; - - // Get consumer chain id - let chain_type = ChainType::from_str(&builder.command_paths[1])?; - let chain_id = chain_type.chain_id("consumer", false); - - node_a - .chain_driver - .submit_consumer_chain_proposal(chain_id.as_str(), "2023-05-31T12:09:47.048227Z")?; - - thread::sleep(Duration::from_secs(2)); - - vote_proposal( - 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(), - "1200stake", - )?; - - thread::sleep(Duration::from_secs(30)); - - let node_b = bootstrap_consumer_node( - builder, - "consumer", - &node_a, - |config| self.test.get_overrides().modify_node_config(config), - |genesis| self.test.get_overrides().modify_genesis_file(genesis), - 1, - &node_a.chain_driver, - )?; - - let _node_process_a = node_a.process.clone(); - let _node_process_b = node_b.process.clone(); - - self.test.run(config, node_a, node_b)?; - - Ok(()) - } -} - -impl HasOverrides for RunInterchainSecurityChainTest<'_, Test> -where - Test: HasOverrides, -{ - type Overrides = Overrides; - - fn get_overrides(&self) -> &Self::Overrides { - self.test.get_overrides() - } -} diff --git a/tools/test-framework/src/framework/binary/mod.rs b/tools/test-framework/src/framework/binary/mod.rs deleted file mode 100644 index 02045138a..000000000 --- a/tools/test-framework/src/framework/binary/mod.rs +++ /dev/null @@ -1,10 +0,0 @@ -/*! - Constructs for test cases that involve interaction between two chains. -*/ - -pub mod chain; -pub mod channel; -pub mod connection; -pub mod ics; -pub mod next; -pub mod node; diff --git a/tools/test-framework/src/framework/binary/next.rs b/tools/test-framework/src/framework/binary/next.rs deleted file mode 100644 index c637cc360..000000000 --- a/tools/test-framework/src/framework/binary/next.rs +++ /dev/null @@ -1,407 +0,0 @@ -use std::thread; -use std::time::Duration; - -use cgp::extra::run::CanRun; -use eyre::eyre; -use hermes_cosmos_relayer::contexts::birelay::CosmosBiRelay; -use hermes_runtime_components::traits::runtime::HasRuntime; -use ibc_relayer::chain::counterparty::unreceived_acknowledgements; -use ibc_relayer::chain::handle::ChainHandle; -use ibc_relayer::chain::requests::{IncludeProof, Paginate, QueryChannelRequest, QueryHeight}; -use ibc_relayer::foreign_client::ForeignClient; -use ibc_relayer::path::PathIdentifiers; -use ibc_relayer_types::core::ics04_channel::channel::{ChannelEnd, IdentifiedChannelEnd}; -use ibc_relayer_types::core::ics24_host::identifier::{ChannelId, PortId}; -use tokio::task::JoinHandle; - -use crate::error::Error; -use crate::framework::next::chain::{ - CanShutdown, CanSpawnRelayer, CanWaitForAck, HasContextId, HasTestConfig, HasTwoChains, - HasTwoChannels, HasTwoNodes, -}; -use crate::prelude::{ - assert_eventually_succeed, ConnectedChains, ConnectedChannel, FullNode, RelayerDriver, - TestConfig, -}; -use crate::types::tagged::*; -use crate::util::suspend::hang_on_error; - -const WAIT_PENDING_ACKS_ATTEMPTS: u16 = 90; - -/// Test context for the current relayer. -/// Uses a RelayerDriver. -pub struct TestContextV1 { - pub context_id: String, - pub config: TestConfig, - pub relayer: RelayerDriver, - pub chains: ConnectedChains, - pub channel: ConnectedChannel, -} - -impl HasTwoChains for TestContextV1 { - type ChainA = ChainA; - - type ChainB = ChainB; - - fn chain_a(&self) -> &Self::ChainA { - self.chains.handle_a() - } - - fn chain_b(&self) -> &Self::ChainB { - self.chains.handle_b() - } - - fn foreign_client_a_to_b(&self) -> &ForeignClient { - &self.chains.foreign_clients.client_a_to_b - } - - fn foreign_client_b_to_a(&self) -> &ForeignClient { - &self.chains.foreign_clients.client_b_to_a - } - - fn chains(&self) -> &ConnectedChains { - &self.chains - } -} - -impl HasTwoNodes for TestContextV1 { - fn node_a(&self) -> &MonoTagged { - &self.chains.node_a - } - - fn node_b(&self) -> &MonoTagged { - &self.chains.node_b - } -} - -impl HasTestConfig for TestContextV1 { - fn config(&self) -> &TestConfig { - &self.config - } -} - -impl HasTwoChannels for TestContextV1 { - fn channel(&self) -> &ConnectedChannel { - &self.channel - } -} - -impl CanSpawnRelayer for TestContextV1 { - fn spawn_relayer(&self) -> Result>, Error> { - let relayer = self.relayer.clone(); - thread::spawn(move || { - if let Ok(handler) = relayer.spawn_supervisor() { - handler.wait(); - } - }); - - Ok(None) - } - - fn with_supervisor(&self, cont: impl FnOnce() -> Result) -> Result { - self.relayer.with_supervisor(cont) - } -} - -pub fn wait_for_acks( - chain: &Chain, - counterparty: &Counterparty, - path_identifiers: &PathIdentifiers, -) -> Result<(), Error> -where - Chain: ChainHandle, - Counterparty: ChainHandle, -{ - assert_eventually_succeed( - "waiting on pending acks on chain", - WAIT_PENDING_ACKS_ATTEMPTS, - Duration::from_secs(1), - || { - let unreceived_acks = - unreceived_acknowledgements(chain, counterparty, path_identifiers, Paginate::All); - - match unreceived_acks { - Ok(Some((acks, _))) => { - if acks.is_empty() { - Ok(()) - } else { - Err(Error::generic(eyre!( - "there are still {} pending acks", - acks.len() - ))) - } - } - Ok(None) => Ok(()), - Err(e) => Err(Error::generic(eyre!( - "error retrieving number of pending acks {}", - e - ))), - } - }, - ) -} - -impl CanWaitForAck for TestContextV1 { - fn wait_for_src_acks(&self) -> Result<(), Error> { - let src_chain = self.chain_a(); - let dst_chain = self.chain_b(); - let channel = self.channel(); - - let channel_end_a = query_channel( - src_chain, - channel.channel_id_a.value(), - channel.port_a.value(), - )?; - - let identified_channel_end_a = IdentifiedChannelEnd::new( - channel.port_a.0.clone(), - channel.channel_id_a.0.clone(), - channel_end_a, - ); - let path_identifiers_a = - match PathIdentifiers::from_channel_end(identified_channel_end_a.clone()) { - Some(path_identifiers) => path_identifiers, - None => { - return Err(Error::generic(eyre!( - "No path identifier found for {:?}", - identified_channel_end_a - ))); - } - }; - - wait_for_acks(src_chain, dst_chain, &path_identifiers_a)?; - - Ok(()) - } - - fn wait_for_dst_acks(&self) -> Result<(), Error> { - let src_chain = self.chain_a(); - let dst_chain = self.chain_b(); - let channel = self.channel(); - let channel_end_b = query_channel( - dst_chain, - channel.channel_id_b.value(), - channel.port_b.value(), - )?; - - let identified_channel_end_b = IdentifiedChannelEnd::new( - channel.port_b.0.clone(), - channel.channel_id_b.0.clone(), - channel_end_b, - ); - let path_identifiers_b = - match PathIdentifiers::from_channel_end(identified_channel_end_b.clone()) { - Some(path_identifiers) => path_identifiers, - None => { - tracing::error!( - "{}", - Error::generic(eyre!("error getting path_identifiers b")) - ); - return Err(Error::generic(eyre!( - "No path identifier found for {:?}", - identified_channel_end_b - ))); - } - }; - - wait_for_acks(dst_chain, src_chain, &path_identifiers_b)?; - - Ok(()) - } -} - -impl CanShutdown for TestContextV1 { - fn shutdown(&self, _auto_relay_handle: Option>) {} -} - -impl HasContextId for TestContextV1 { - fn context_id(&self) -> String { - self.context_id.clone() - } -} - -/// Test context for the relayer-next. -/// Uses a OfaBiRelayWrapper. -pub struct TestContextV2 { - pub context_id: String, - pub config: TestConfig, - pub relayer: CosmosBiRelay, - pub chains: ConnectedChains, - pub channel: ConnectedChannel, -} - -impl HasTwoChains for TestContextV2 { - type ChainA = ChainA; - - type ChainB = ChainB; - - fn chain_a(&self) -> &Self::ChainA { - self.chains.handle_a() - } - - fn chain_b(&self) -> &Self::ChainB { - self.chains.handle_b() - } - - fn foreign_client_a_to_b(&self) -> &ForeignClient { - &self.chains.foreign_clients.client_a_to_b - } - - fn foreign_client_b_to_a(&self) -> &ForeignClient { - &self.chains.foreign_clients.client_b_to_a - } - - fn chains(&self) -> &ConnectedChains { - &self.chains - } -} - -impl HasTwoNodes for TestContextV2 { - fn node_a(&self) -> &MonoTagged { - &self.chains.node_a - } - - fn node_b(&self) -> &MonoTagged { - &self.chains.node_b - } -} - -impl HasTestConfig for TestContextV2 { - fn config(&self) -> &TestConfig { - &self.config - } -} - -impl HasTwoChannels for TestContextV2 { - fn channel(&self) -> &ConnectedChannel { - &self.channel - } -} - -impl CanSpawnRelayer for TestContextV2 { - fn spawn_relayer(&self) -> Result>, Error> { - let runtime = self.relayer.runtime(); - let birelay = self.relayer.clone(); - - let handle = runtime.runtime.spawn(async move { - let _ = birelay.run().await; - }); - - Ok(Some(handle)) - } - - fn with_supervisor(&self, cont: impl FnOnce() -> Result) -> Result { - self.spawn_relayer()?; - - hang_on_error(false, cont) - } -} - -impl CanWaitForAck for TestContextV2 { - fn wait_for_src_acks(&self) -> Result<(), Error> { - let src_chain = self.chain_a(); - let dst_chain = self.chain_b(); - let channel = self.channel(); - let channel_end_a = query_channel( - src_chain, - channel.channel_id_a.value(), - channel.port_a.value(), - )?; - - let identified_channel_end_a = IdentifiedChannelEnd::new( - channel.port_a.0.clone(), - channel.channel_id_a.0.clone(), - channel_end_a, - ); - let path_identifiers_a = - match PathIdentifiers::from_channel_end(identified_channel_end_a.clone()) { - Some(path_identifiers) => path_identifiers, - None => { - return Err(Error::generic(eyre!( - "No path identifier found for {:?}", - identified_channel_end_a - ))); - } - }; - - wait_for_acks(src_chain, dst_chain, &path_identifiers_a)?; - - Ok(()) - } - - fn wait_for_dst_acks(&self) -> Result<(), Error> { - let src_chain = self.chain_a(); - let dst_chain = self.chain_b(); - let channel = self.channel(); - let channel_end_b = query_channel( - dst_chain, - channel.channel_id_b.value(), - channel.port_b.value(), - )?; - - let identified_channel_end_b = IdentifiedChannelEnd::new( - channel.port_b.0.clone(), - channel.channel_id_b.0.clone(), - channel_end_b, - ); - let path_identifiers_b = - match PathIdentifiers::from_channel_end(identified_channel_end_b.clone()) { - Some(path_identifiers) => path_identifiers, - None => { - tracing::error!( - "{}", - Error::generic(eyre!("error getting path_identifiers b")) - ); - return Err(Error::generic(eyre!( - "No path identifier found for {:?}", - identified_channel_end_b - ))); - } - }; - - wait_for_acks(dst_chain, src_chain, &path_identifiers_b)?; - - Ok(()) - } -} - -/// This is a temporary solution. When the clean shutdown is implemented in the runtime -/// context, this should be replaced, see . -impl CanShutdown for TestContextV2 { - fn shutdown(&self, auto_relay_handle: Option>) { - if let Some(handle) = auto_relay_handle { - JoinHandle::abort(&handle); - loop { - if handle.is_finished() { - break; - } - thread::sleep(Duration::from_secs(1)); - } - } - } -} - -impl HasContextId for TestContextV2 { - fn context_id(&self) -> String { - self.context_id.clone() - } -} - -fn query_channel( - chain: &Chain, - channel_id: &ChannelId, - port_id: &PortId, -) -> Result { - let channel = chain - .query_channel( - QueryChannelRequest { - port_id: port_id.clone(), - channel_id: channel_id.clone(), - height: QueryHeight::Latest, - }, - IncludeProof::No, - ) - .map(|(channel_end, _)| channel_end)?; - - Ok(channel) -} diff --git a/tools/test-framework/src/framework/binary/node.rs b/tools/test-framework/src/framework/binary/node.rs deleted file mode 100644 index 3baf88c5d..000000000 --- a/tools/test-framework/src/framework/binary/node.rs +++ /dev/null @@ -1,183 +0,0 @@ -/*! - Constructs for running test cases with two full nodes - running without setting up the relayer. -*/ - -use toml; - -use crate::bootstrap::single::bootstrap_single_node; -use crate::chain::builder::ChainBuilder; -use crate::error::Error; -use crate::framework::base::{run_basic_test, BasicTest, HasOverrides, TestConfigOverride}; -use crate::types::config::TestConfig; -use crate::types::single::node::FullNode; - -/** - Runs a test case that implements [`BinaryNodeTest`]. -*/ -pub fn run_binary_node_test(test: &Test) -> Result<(), Error> -where - Test: BinaryNodeTest, - Test: HasOverrides, - Overrides: NodeConfigOverride + NodeGenesisOverride + TestConfigOverride, -{ - run_basic_test(&RunBinaryNodeTest { test }) -} - -pub fn run_single_node_test(test: &Test) -> Result<(), Error> -where - Test: BinaryNodeTest, - Test: HasOverrides, - Overrides: NodeConfigOverride + NodeGenesisOverride + TestConfigOverride, -{ - run_basic_test(&RunSingleNodeTest { test }) -} - -/** - This trait is implemented for test cases that need to have two full nodes - running without the relayer being setup. - - The test case is given two [`FullNode`] which represents the two running full nodes. - - Test writers can use this to implement more advanced test cases which - require manual setup of the relayer, so that the relayer can be started - and stopped at a suitable time within the test. -*/ -pub trait BinaryNodeTest { - /// Test runner - fn run(&self, config: &TestConfig, node_a: FullNode, node_b: FullNode) -> Result<(), Error>; -} - -/** - An internal trait that can be implemented by test cases to override the - full node config before the chain gets initialized. - - The config is in the dynamic-typed [`toml::Value`] format, as we do not - want to model the full format of the node config in Rust. Test authors - can use the helper methods in [`chain::config`](crate::chain::config) - to modify common config fields. - - This is called by [`RunBinaryNodeTest`] before the full nodes are - initialized and started. - - Test writers should implement - [`TestOverrides`](crate::framework::overrides::TestOverrides) - for their test cases instead of implementing this trait directly. -*/ -pub trait NodeConfigOverride { - /// Modify the full node config - fn modify_node_config(&self, config: &mut toml::Value) -> Result<(), Error>; -} - -/** - An internal trait that can be implemented by test cases to override the - genesis file before the chain gets initialized. - - The config is in the dynamic-typed [`serde_json::Value`] format, as we do not - want to model the full format of the genesis file in Rust. - - This is called by [`RunBinaryNodeTest`] before the full nodes are - initialized and started. - - Test writers should implement - [`TestOverrides`](crate::framework::overrides::TestOverrides) - for their test cases instead of implementing this trait directly. -*/ -pub trait NodeGenesisOverride { - /// Modify the genesis file - fn modify_genesis_file(&self, genesis: &mut serde_json::Value) -> Result<(), Error>; -} - -/** - A wrapper type that lifts a test case that implements [`BinaryNodeTest`] - into a test case that implements [`BasicTest`]. -*/ -pub struct RunBinaryNodeTest<'a, Test> { - /// Inner test - pub test: &'a Test, -} - -pub struct RunSingleNodeTest<'a, Test> { - /// Inner test - pub test: &'a Test, -} - -impl BasicTest for RunBinaryNodeTest<'_, Test> -where - Test: BinaryNodeTest, - Test: HasOverrides, - Overrides: NodeConfigOverride + NodeGenesisOverride, -{ - fn run(&self, config: &TestConfig, builder: &ChainBuilder) -> Result<(), Error> { - let node_a = bootstrap_single_node( - builder, - "1", - config.bootstrap_with_random_ids, - |config| self.test.get_overrides().modify_node_config(config), - |genesis| self.test.get_overrides().modify_genesis_file(genesis), - 0, - )?; - - let node_b = bootstrap_single_node( - builder, - "2", - config.bootstrap_with_random_ids, - |config| self.test.get_overrides().modify_node_config(config), - |genesis| self.test.get_overrides().modify_genesis_file(genesis), - 1, - )?; - - let _node_process_a = node_a.process.clone(); - let _node_process_b = node_b.process.clone(); - - self.test.run(config, node_a, node_b)?; - - Ok(()) - } -} - -impl BasicTest for RunSingleNodeTest<'_, Test> -where - Test: BinaryNodeTest, - Test: HasOverrides, - Overrides: NodeConfigOverride + NodeGenesisOverride, -{ - fn run(&self, config: &TestConfig, builder: &ChainBuilder) -> Result<(), Error> { - let node = bootstrap_single_node( - builder, - "1", - config.bootstrap_with_random_ids, - |config| self.test.get_overrides().modify_node_config(config), - |genesis| self.test.get_overrides().modify_genesis_file(genesis), - 0, - )?; - - let _node_process = node.process.clone(); - - self.test.run(config, node.clone(), node)?; - - Ok(()) - } -} - -impl HasOverrides for RunBinaryNodeTest<'_, Test> -where - Test: HasOverrides, -{ - type Overrides = Overrides; - - fn get_overrides(&self) -> &Self::Overrides { - self.test.get_overrides() - } -} - -impl HasOverrides for RunSingleNodeTest<'_, Test> -where - Test: HasOverrides, -{ - type Overrides = Overrides; - - fn get_overrides(&self) -> &Self::Overrides { - self.test.get_overrides() - } -} diff --git a/tools/test-framework/src/framework/mod.rs b/tools/test-framework/src/framework/mod.rs deleted file mode 100644 index b5e46780e..000000000 --- a/tools/test-framework/src/framework/mod.rs +++ /dev/null @@ -1,40 +0,0 @@ -/*! - Framework code for making it easier to write test cases. - - If you want to create a common test setup that is shared - by multiple test cases, the best way is to define them as - new traits within the [`framework`](crate::framework) module. - - The actual operations for bootstrapping the test setup - should *not* be implemented in this module. Instead, they - should be implemented as functions in the - [`bootstrap`](crate::bootstrap) module. This is so that - test writers can still have the option to manually - bootstrap the test setup without getting locked-in to - using the test framework. - - We can think of the test framework as being a DSL for - making it easier to write _declarative_ tests. On the - other hand, the [`bootstrap`](crate::bootstrap) module - allows the same test setup to be done in an _imperative_ way. - - ## Common Test Cases - - Here is a short list of common traits that are used for - defining simple test scenarios: - - - [`BinaryNodeTest`](binary::node::BinaryNodeTest) - - Test with two full nodes running without setting up the relayer. - - [`BinaryChainTest`](binary::chain::BinaryChainTest) - - Test with two full nodes running with the relayer setup with chain handles. - - [`BinaryChannelTest`](binary::channel::BinaryChannelTest) - - Test with two full nodes running with the relayer setup with chain handles - together with channels that are already connected. -*/ - -pub mod base; -pub mod binary; -pub mod nary; -pub mod next; -pub mod overrides; -pub mod supervisor; diff --git a/tools/test-framework/src/framework/nary/chain.rs b/tools/test-framework/src/framework/nary/chain.rs deleted file mode 100644 index faa7d7a04..000000000 --- a/tools/test-framework/src/framework/nary/chain.rs +++ /dev/null @@ -1,247 +0,0 @@ -/*! - Constructs for running test cases with more than two chains, - together with the relayer setup with chain handles and foreign clients. -*/ - -use ibc_relayer::chain::handle::ChainHandle; -use tracing::info; - -use crate::bootstrap::nary::chain::{ - boostrap_chains_with_nodes, boostrap_chains_with_self_connected_node, -}; -use crate::error::Error; -use crate::framework::base::{HasOverrides, TestConfigOverride}; -use crate::framework::binary::chain::RelayerConfigOverride; -use crate::framework::binary::node::{NodeConfigOverride, NodeGenesisOverride}; -use crate::framework::nary::node::{run_nary_node_test, NaryNodeTest}; -use crate::framework::supervisor::{RunWithSupervisor, SupervisorOverride}; -use crate::relayer::driver::RelayerDriver; -use crate::types::binary::chains::DropChainHandle; -use crate::types::config::TestConfig; -use crate::types::env::write_env; -use crate::types::nary::chains::NaryConnectedChains; -use crate::types::single::node::FullNode; -use crate::util::suspend::hang_on_error; - -/** - Runs a test case that implements [`NaryChainTest`] with a `SIZE` number of - chains bootstrapped. - - Note that the test may take more time as the number of chains increase, - as the required connections would increase exponentially. For each - new chain added, a self-connected foreign client is also created. - - Following shows a quick idea of how many connections are needed for each - new chain added: - - 1. 0-0 - 2. 0-0, 0-1, 1-1 - 3. 0-0, 0-1, 0-2, 1-1, 1-2, 2-2 - 4. 0-0, 0-1, 0-2, 0-3, 1-1, 1-2, 1-3, 2-2, 2-3, 3-3 - 5. ... -*/ -pub fn run_nary_chain_test(test: &Test) -> Result<(), Error> -where - Test: NaryChainTest, - Test: HasOverrides, - Overrides: TestConfigOverride - + NodeConfigOverride - + NodeGenesisOverride - + RelayerConfigOverride - + SupervisorOverride, -{ - run_nary_node_test(&RunNaryChainTest::new(&RunWithSupervisor::new(test))) -} - -/** - Runs a test case that implements [`NaryChainTest`], with one self-connected chain used - to emulate many connnections. - - This works because IBC allows a chain to connect back to itself without the chain - knowing it. Using this, we can emulate N-ary chain tests using only one chain - and save the performance overhead of spawning many chains. - - Note that with this, there is still performance overhead of establishing - new connections and channels for each position, as otherwise the transferred - IBC denoms will get mixed up. Some test cases also may not able to make - use of self connected chains, e.g. if they need to start and stop individual - chains. -*/ -pub fn run_self_connected_nary_chain_test( - test: &Test, -) -> Result<(), Error> -where - Test: NaryChainTest, - Test: HasOverrides, - Overrides: TestConfigOverride - + NodeConfigOverride - + NodeGenesisOverride - + RelayerConfigOverride - + SupervisorOverride, -{ - run_nary_node_test(&RunSelfConnectedNaryChainTest::new( - &RunWithSupervisor::new(test), - )) -} - -/** - This trait is implemented for test cases that need to have more than - two chains running. - - Test writers can use this to implement test cases that only - need the chains and relayers setup without the connection or - channel handshake. -*/ -pub trait NaryChainTest { - /// Test runner - fn run( - &self, - config: &TestConfig, - relayer: RelayerDriver, - chains: NaryConnectedChains, - ) -> Result<(), Error>; -} - -/** - A wrapper type that lifts a test case that implements [`RunNaryChainTest`] - into a test case the implements [`NaryNodeTest`]. -*/ -pub struct RunNaryChainTest<'a, Test, const SIZE: usize> { - /// Inner test - pub test: &'a Test, -} - -/** - A wrapper type that lifts a test case that implements [`RunNaryChainTest`] - into a test case the implements [`NaryNodeTest<1>`]. i.e. only one underlying - full node is spawned to emulate all chains. -*/ -pub struct RunSelfConnectedNaryChainTest<'a, Test, const SIZE: usize> { - /// Inner test - pub test: &'a Test, -} - -impl NaryNodeTest for RunNaryChainTest<'_, Test, SIZE> -where - Test: NaryChainTest, - Test: HasOverrides, - Overrides: RelayerConfigOverride, -{ - fn run(&self, config: &TestConfig, nodes: [FullNode; SIZE]) -> Result<(), Error> { - let (relayer, chains) = boostrap_chains_with_nodes(config, nodes, |config| { - self.test.get_overrides().modify_relayer_config(config); - })?; - - let env_path = config.chain_store_dir.join("nary-chains.env"); - - write_env(&env_path, &(&relayer, &chains))?; - - info!("written chains environment to {}", env_path.display()); - - let _drop_handles = chains - .chain_handles() - .iter() - .map(|handle| DropChainHandle(handle.clone())) - .collect::>(); - - self.test.run(config, relayer, chains)?; - - Ok(()) - } -} - -impl NaryNodeTest<1> - for RunSelfConnectedNaryChainTest<'_, Test, SIZE> -where - Test: NaryChainTest, - Test: HasOverrides, - Overrides: RelayerConfigOverride, -{ - fn run(&self, config: &TestConfig, nodes: [FullNode; 1]) -> Result<(), Error> { - let (relayer, chains) = - boostrap_chains_with_self_connected_node(config, nodes[0].clone(), |config| { - self.test.get_overrides().modify_relayer_config(config); - })?; - - let env_path = config.chain_store_dir.join("nary-chains.env"); - - write_env(&env_path, &(&relayer, &chains))?; - - info!("written chains environment to {}", env_path.display()); - - let _drop_handles = chains - .chain_handles() - .iter() - .map(|handle| DropChainHandle(handle.clone())) - .collect::>(); - - self.test.run(config, relayer, chains)?; - - Ok(()) - } -} - -impl NaryChainTest for RunWithSupervisor<'_, Test> -where - Test: NaryChainTest, - Test: HasOverrides, - Overrides: SupervisorOverride, -{ - fn run( - &self, - config: &TestConfig, - relayer: RelayerDriver, - chains: NaryConnectedChains, - ) -> Result<(), Error> { - if self.get_overrides().should_spawn_supervisor() { - relayer - .clone() - .with_supervisor(|| self.test.run(config, relayer, chains)) - } else { - hang_on_error(config.hang_on_fail, || { - self.test.run(config, relayer, chains) - }) - } - } -} - -impl<'a, Test, const SIZE: usize> RunNaryChainTest<'a, Test, SIZE> -where - Test: NaryChainTest, -{ - pub fn new(test: &'a Test) -> Self { - Self { test } - } -} - -impl<'a, Test, const SIZE: usize> RunSelfConnectedNaryChainTest<'a, Test, SIZE> -where - Test: NaryChainTest, -{ - pub fn new(test: &'a Test) -> Self { - Self { test } - } -} - -impl HasOverrides for RunNaryChainTest<'_, Test, SIZE> -where - Test: HasOverrides, -{ - type Overrides = Overrides; - - fn get_overrides(&self) -> &Self::Overrides { - self.test.get_overrides() - } -} - -impl HasOverrides - for RunSelfConnectedNaryChainTest<'_, Test, SIZE> -where - Test: HasOverrides, -{ - type Overrides = Overrides; - - fn get_overrides(&self) -> &Self::Overrides { - self.test.get_overrides() - } -} diff --git a/tools/test-framework/src/framework/nary/channel.rs b/tools/test-framework/src/framework/nary/channel.rs deleted file mode 100644 index 5281948c7..000000000 --- a/tools/test-framework/src/framework/nary/channel.rs +++ /dev/null @@ -1,262 +0,0 @@ -/*! - Constructs for running test cases with more than two chains, - together with the relayer setup with chain handles and foreign clients, - as well as connected IBC channels with completed handshakes. -*/ -use ibc_relayer::chain::handle::ChainHandle; -use ibc_relayer_types::core::ics24_host::identifier::PortId; -use tracing::info; - -use crate::bootstrap::nary::channel::bootstrap_channels_with_connections; -use crate::error::Error; -use crate::framework::base::{HasOverrides, TestConfigOverride}; -use crate::framework::binary::chain::RelayerConfigOverride; -use crate::framework::binary::channel::{BinaryChannelTest, ChannelOrderOverride}; -use crate::framework::binary::connection::ConnectionDelayOverride; -use crate::framework::binary::node::{NodeConfigOverride, NodeGenesisOverride}; -use crate::framework::nary::chain::RunNaryChainTest; -use crate::framework::nary::connection::{NaryConnectionTest, RunNaryConnectionTest}; -use crate::framework::nary::node::run_nary_node_test; -use crate::framework::next::context::build_test_context; -use crate::framework::supervisor::{RunWithSupervisor, SupervisorOverride}; -use crate::relayer::driver::RelayerDriver; -use crate::types::config::TestConfig; -use crate::types::env::write_env; -use crate::types::nary::chains::NaryConnectedChains; -use crate::types::nary::channel::ConnectedChannels; -use crate::types::nary::connection::ConnectedConnections; -use crate::util::suspend::hang_on_error; - -pub fn run_nary_channel_test(test: &Test) -> Result<(), Error> -where - Test: NaryChannelTest, - Test: HasOverrides, - Overrides: TestConfigOverride - + NodeConfigOverride - + NodeGenesisOverride - + RelayerConfigOverride - + SupervisorOverride - + ConnectionDelayOverride - + PortsOverride - + ChannelOrderOverride, -{ - run_nary_node_test(&RunNaryChainTest::new(&RunNaryConnectionTest::new( - &RunNaryChannelTest::new(&RunWithSupervisor::new(test)), - ))) -} - -pub fn run_binary_as_nary_channel_test(test: &Test) -> Result<(), Error> -where - Test: BinaryChannelTest, - Test: HasOverrides, - Overrides: TestConfigOverride - + NodeConfigOverride - + NodeGenesisOverride - + RelayerConfigOverride - + SupervisorOverride - + ConnectionDelayOverride - + PortsOverride<2> - + ChannelOrderOverride, -{ - run_nary_channel_test(&RunBinaryAsNaryChannelTest::new(test)) -} - -/** - Returns a `SIZE`x`SIZE` number of transfer ports. - - This can be used by N-ary channel test cases to have a default - implementation of `PortsOverride`, with `"transfer"` used for - all port IDs. -*/ -pub fn transfer_port_overrides() -> [[PortId; SIZE]; SIZE] { - let port = PortId::transfer(); - let ports_ref = [[&port; SIZE]; SIZE]; - ports_ref.map(|inner_ports| inner_ports.map(Clone::clone)) -} - -/** - This trait is implemented for test cases that need to have more than - two chains running with connected channels. -*/ -pub trait NaryChannelTest { - /// Test runner - fn run( - &self, - config: &TestConfig, - relayer: RelayerDriver, - chains: NaryConnectedChains, - channels: ConnectedChannels, - ) -> Result<(), Error>; -} - -/** - An internal trait that can be implemented by test cases to override - the port IDs used when creating N-ary channels. - - When called, the implementer returns a `SIZE`x`SIZE` matrix - of [`PortId`]s to indicate which port ID for the chain at - the first position when connected to the chain at the second - position. - - This is called by [`RunNaryChannelTest`] before creating - the IBC channels. - - Note that this trait is not automatically implemented - for test cases via - [`TestOverrides`](crate::framework::overrides::TestOverrides), - except for the binary case `PortsOverride<2>`. - So each N-ary channel test must also implement this trait manually. - - It is possible to implement this with an empty body, in which case - the port ID matrix will all be populated with `"transfer"` ports. -*/ -pub trait PortsOverride { - fn channel_ports(&self) -> [[PortId; SIZE]; SIZE] { - transfer_port_overrides() - } -} - -/** - A wrapper type that lifts a test case that implements [`NaryChannelTest`] - into a test case the implements [`NaryConnectionTest`]. -*/ -pub struct RunNaryChannelTest<'a, Test, const SIZE: usize> { - /// Inner test - pub test: &'a Test, -} - -/** - A wrapper type that lifts a test case that implements [`BinaryChannelTest`] - into a test case the implements [`NaryChannelTest`]. - - This can be used to test the implementation of the N-ary test framework, - by running binary channel tests as N-ary channel tests. -*/ -pub struct RunBinaryAsNaryChannelTest<'a, Test> { - /// Inner test - pub test: &'a Test, -} - -impl<'a, Test, const SIZE: usize> RunNaryChannelTest<'a, Test, SIZE> -where - Test: NaryChannelTest, -{ - pub fn new(test: &'a Test) -> Self { - Self { test } - } -} - -impl<'a, Test> RunBinaryAsNaryChannelTest<'a, Test> -where - Test: BinaryChannelTest, -{ - pub fn new(test: &'a Test) -> Self { - Self { test } - } -} - -impl NaryConnectionTest - for RunNaryChannelTest<'_, Test, SIZE> -where - Test: NaryChannelTest, - Test: HasOverrides, - Overrides: PortsOverride + ChannelOrderOverride, -{ - fn run( - &self, - config: &TestConfig, - relayer: RelayerDriver, - chains: NaryConnectedChains, - connections: ConnectedConnections, - ) -> Result<(), Error> { - let overrides = self.test.get_overrides(); - let port_ids = overrides.channel_ports(); - let order = overrides.channel_order(); - - let channels = bootstrap_channels_with_connections( - connections, - chains.chain_handles().clone(), - port_ids, - order, - config.bootstrap_with_random_ids, - )?; - - let env_path = config.chain_store_dir.join("nary-channels.env"); - - write_env(&env_path, &(&chains, &(&relayer, &channels)))?; - - info!("written channel environment to {}", env_path.display()); - - self.test.run(config, relayer, chains, channels)?; - - Ok(()) - } -} - -impl NaryChannelTest<2> for RunBinaryAsNaryChannelTest<'_, Test> -where - Test: BinaryChannelTest, -{ - fn run( - &self, - config: &TestConfig, - relayer: RelayerDriver, - chains: NaryConnectedChains, - channels: ConnectedChannels, - ) -> Result<(), Error> { - let connected_chains = chains.connected_chains_at::<0, 1>()?; - let connected_channel = channels.channel_at::<0, 1>()?; - - let test_context = - build_test_context(config, relayer.clone(), connected_chains, connected_channel)?; - - self.test.run(relayer, &test_context) - } -} - -impl NaryChannelTest for RunWithSupervisor<'_, Test> -where - Test: NaryChannelTest, - Test: HasOverrides, - Overrides: SupervisorOverride, -{ - fn run( - &self, - config: &TestConfig, - relayer: RelayerDriver, - chains: NaryConnectedChains, - channels: ConnectedChannels, - ) -> Result<(), Error> { - if self.get_overrides().should_spawn_supervisor() { - relayer - .clone() - .with_supervisor(|| self.test.run(config, relayer, chains, channels)) - } else { - hang_on_error(config.hang_on_fail, || { - self.test.run(config, relayer, chains, channels) - }) - } - } -} - -impl HasOverrides for RunNaryChannelTest<'_, Test, SIZE> -where - Test: HasOverrides, -{ - type Overrides = Overrides; - - fn get_overrides(&self) -> &Self::Overrides { - self.test.get_overrides() - } -} - -impl HasOverrides for RunBinaryAsNaryChannelTest<'_, Test> -where - Test: HasOverrides, -{ - type Overrides = Overrides; - - fn get_overrides(&self) -> &Self::Overrides { - self.test.get_overrides() - } -} diff --git a/tools/test-framework/src/framework/nary/connection.rs b/tools/test-framework/src/framework/nary/connection.rs deleted file mode 100644 index 18a4bbf73..000000000 --- a/tools/test-framework/src/framework/nary/connection.rs +++ /dev/null @@ -1,188 +0,0 @@ -/*! - Constructs for running test cases with more than two chains, - together with the relayer setup with chain handles and foreign clients, - as well as connected IBC connections with completed handshakes. -*/ - -use ibc_relayer::chain::handle::ChainHandle; -use tracing::info; - -use crate::bootstrap::nary::connection::bootstrap_connections; -use crate::error::Error; -use crate::framework::base::{HasOverrides, TestConfigOverride}; -use crate::framework::binary::chain::RelayerConfigOverride; -use crate::framework::binary::connection::{BinaryConnectionTest, ConnectionDelayOverride}; -use crate::framework::binary::node::{NodeConfigOverride, NodeGenesisOverride}; -use crate::framework::nary::chain::{NaryChainTest, RunNaryChainTest}; -use crate::framework::nary::node::run_nary_node_test; -use crate::framework::supervisor::{RunWithSupervisor, SupervisorOverride}; -use crate::relayer::driver::RelayerDriver; -use crate::types::config::TestConfig; -use crate::types::env::write_env; -use crate::types::nary::chains::NaryConnectedChains; -use crate::types::nary::connection::ConnectedConnections; -use crate::util::suspend::hang_on_error; - -pub fn run_nary_connection_test( - test: &Test, -) -> Result<(), Error> -where - Test: NaryConnectionTest, - Test: HasOverrides, - Overrides: TestConfigOverride - + NodeConfigOverride - + NodeGenesisOverride - + RelayerConfigOverride - + SupervisorOverride - + ConnectionDelayOverride, -{ - run_nary_node_test(&RunNaryChainTest::new(&RunNaryConnectionTest::new( - &RunWithSupervisor::new(test), - ))) -} - -/** - This trait is implemented for test cases that need to have more than - two chains running with connected connections. - - Test writers can use this to implement test cases that only - need the connections without channel handshake. -*/ -pub trait NaryConnectionTest { - /// Test runner - fn run( - &self, - config: &TestConfig, - relayer: RelayerDriver, - chains: NaryConnectedChains, - connections: ConnectedConnections, - ) -> Result<(), Error>; -} - -/** - A wrapper type that lifts a test case that implements [`NaryConnectionTest`] - into a test case the implements [`NaryChainTest`]. -*/ -pub struct RunNaryConnectionTest<'a, Test, const SIZE: usize> { - /// Inner test - pub test: &'a Test, -} - -pub struct RunBinaryAsNaryConnectionTest<'a, Test> { - /// Inner test - pub test: &'a Test, -} - -impl<'a, Test, const SIZE: usize> RunNaryConnectionTest<'a, Test, SIZE> -where - Test: NaryConnectionTest, -{ - pub fn new(test: &'a Test) -> Self { - Self { test } - } -} - -impl<'a, Test> RunBinaryAsNaryConnectionTest<'a, Test> -where - Test: BinaryConnectionTest, -{ - pub fn new(test: &'a Test) -> Self { - Self { test } - } -} - -impl NaryChainTest - for RunNaryConnectionTest<'_, Test, SIZE> -where - Test: NaryConnectionTest, - Test: HasOverrides, - Overrides: ConnectionDelayOverride, -{ - fn run( - &self, - config: &TestConfig, - relayer: RelayerDriver, - chains: NaryConnectedChains, - ) -> Result<(), Error> { - let connection_delay = self.get_overrides().connection_delay(); - - let connections = bootstrap_connections( - chains.foreign_clients().clone(), - connection_delay, - config.bootstrap_with_random_ids, - )?; - - let env_path = config.chain_store_dir.join("nary-connections.env"); - - write_env(&env_path, &(&chains, &(&relayer, &connections)))?; - - info!("written channel environment to {}", env_path.display()); - - self.test.run(config, relayer, chains, connections)?; - - Ok(()) - } -} - -impl NaryConnectionTest<2> for RunBinaryAsNaryConnectionTest<'_, Test> -where - Test: BinaryConnectionTest, -{ - fn run( - &self, - config: &TestConfig, - relayer: RelayerDriver, - chains: NaryConnectedChains, - connections: ConnectedConnections, - ) -> Result<(), Error> { - self.test - .run(config, relayer, chains.into(), connections.into()) - } -} - -impl NaryConnectionTest for RunWithSupervisor<'_, Test> -where - Test: NaryConnectionTest, - Test: HasOverrides, - Overrides: SupervisorOverride, -{ - fn run( - &self, - config: &TestConfig, - relayer: RelayerDriver, - chains: NaryConnectedChains, - connections: ConnectedConnections, - ) -> Result<(), Error> { - if self.get_overrides().should_spawn_supervisor() { - relayer - .clone() - .with_supervisor(|| self.test.run(config, relayer, chains, connections)) - } else { - hang_on_error(config.hang_on_fail, || { - self.test.run(config, relayer, chains, connections) - }) - } - } -} - -impl HasOverrides for RunNaryConnectionTest<'_, Test, SIZE> -where - Test: HasOverrides, -{ - type Overrides = Overrides; - - fn get_overrides(&self) -> &Self::Overrides { - self.test.get_overrides() - } -} - -impl HasOverrides for RunBinaryAsNaryConnectionTest<'_, Test> -where - Test: HasOverrides, -{ - type Overrides = Overrides; - - fn get_overrides(&self) -> &Self::Overrides { - self.test.get_overrides() - } -} diff --git a/tools/test-framework/src/framework/nary/mod.rs b/tools/test-framework/src/framework/nary/mod.rs deleted file mode 100644 index f2e5bacb8..000000000 --- a/tools/test-framework/src/framework/nary/mod.rs +++ /dev/null @@ -1,8 +0,0 @@ -/*! - Run N-ary test cases that involve more than 2 chains. -*/ - -pub mod chain; -pub mod channel; -pub mod connection; -pub mod node; diff --git a/tools/test-framework/src/framework/nary/node.rs b/tools/test-framework/src/framework/nary/node.rs deleted file mode 100644 index fc8a19768..000000000 --- a/tools/test-framework/src/framework/nary/node.rs +++ /dev/null @@ -1,86 +0,0 @@ -/*! - Constructs for running test cases with more than two full nodes, - running without setting up the relayer. -*/ - -use crate::bootstrap::single::bootstrap_single_node; -use crate::chain::builder::ChainBuilder; -use crate::error::Error; -use crate::framework::base::{run_basic_test, BasicTest, HasOverrides, TestConfigOverride}; -use crate::framework::binary::node::{NodeConfigOverride, NodeGenesisOverride}; -use crate::types::config::TestConfig; -use crate::types::single::node::FullNode; -use crate::util::array::try_into_array; - -pub fn run_nary_node_test(test: &Test) -> Result<(), Error> -where - Test: NaryNodeTest, - Test: HasOverrides, - Overrides: NodeConfigOverride + NodeGenesisOverride + TestConfigOverride, -{ - run_basic_test(&RunNaryNodeTest { test }) -} - -/** - This trait is implemented for test cases that need to have more than two - full nodes running without the relayer being setup. - - The test case is given `SIZE` number of [`FullNode`]s which represents - the running full nodes. - - Test writers can use this to implement more advanced test cases which - require manual setup of the relayer, so that the relayer can be started - and stopped at a suitable time within the test. -*/ -pub trait NaryNodeTest { - fn run(&self, config: &TestConfig, nodes: [FullNode; SIZE]) -> Result<(), Error>; -} - -/** - A wrapper type that lifts a test case that implements [`NaryNodeTest`] - into a test case the implements [`BasicTest`]. -*/ -pub struct RunNaryNodeTest<'a, Test, const SIZE: usize> { - pub test: &'a Test, -} - -impl BasicTest for RunNaryNodeTest<'_, Test, SIZE> -where - Test: NaryNodeTest, - Test: HasOverrides, - Overrides: NodeConfigOverride + NodeGenesisOverride, -{ - fn run(&self, config: &TestConfig, builder: &ChainBuilder) -> Result<(), Error> { - let mut nodes = Vec::new(); - let mut node_processes = Vec::new(); - - for i in 0..SIZE { - let node = bootstrap_single_node( - builder, - &format!("{}", i + 1), - config.bootstrap_with_random_ids, - |config| self.test.get_overrides().modify_node_config(config), - |genesis| self.test.get_overrides().modify_genesis_file(genesis), - i, - )?; - - node_processes.push(node.process.clone()); - nodes.push(node); - } - - self.test.run(config, try_into_array(nodes)?)?; - - Ok(()) - } -} - -impl HasOverrides for RunNaryNodeTest<'_, Test, SIZE> -where - Test: HasOverrides, -{ - type Overrides = Overrides; - - fn get_overrides(&self) -> &Self::Overrides { - self.test.get_overrides() - } -} diff --git a/tools/test-framework/src/framework/next/chain.rs b/tools/test-framework/src/framework/next/chain.rs deleted file mode 100644 index 2abe9dc38..000000000 --- a/tools/test-framework/src/framework/next/chain.rs +++ /dev/null @@ -1,56 +0,0 @@ -use ibc_relayer::chain::handle::ChainHandle; -use ibc_relayer::foreign_client::ForeignClient; -use tokio::task::JoinHandle; - -use crate::error::Error; -use crate::prelude::{ConnectedChains, ConnectedChannel, FullNode, TestConfig}; -use crate::types::tagged::*; - -pub trait HasTwoChains { - type ChainA: ChainHandle; - type ChainB: ChainHandle; - - fn chain_a(&self) -> &Self::ChainA; - - fn chain_b(&self) -> &Self::ChainB; - - fn foreign_client_a_to_b(&self) -> &ForeignClient; - - fn foreign_client_b_to_a(&self) -> &ForeignClient; - - fn chains(&self) -> &ConnectedChains; -} - -pub trait HasTwoNodes: HasTwoChains { - fn node_a(&self) -> &MonoTagged; - - fn node_b(&self) -> &MonoTagged; -} - -pub trait HasTestConfig { - fn config(&self) -> &TestConfig; -} - -pub trait HasTwoChannels: HasTwoChains { - fn channel(&self) -> &ConnectedChannel; -} - -pub trait CanSpawnRelayer { - fn spawn_relayer(&self) -> Result>, Error>; - - fn with_supervisor(&self, cont: impl FnOnce() -> Result) -> Result; -} - -pub trait CanWaitForAck: HasTwoChains { - fn wait_for_src_acks(&self) -> Result<(), Error>; - - fn wait_for_dst_acks(&self) -> Result<(), Error>; -} - -pub trait CanShutdown { - fn shutdown(&self, auto_relay_handle: Option>); -} - -pub trait HasContextId { - fn context_id(&self) -> String; -} diff --git a/tools/test-framework/src/framework/next/context.rs b/tools/test-framework/src/framework/next/context.rs deleted file mode 100644 index 5a6b1127f..000000000 --- a/tools/test-framework/src/framework/next/context.rs +++ /dev/null @@ -1,32 +0,0 @@ -use crate::framework::binary::next::TestContextV1; -use crate::framework::next::chain::{ - CanShutdown, CanSpawnRelayer, CanWaitForAck, HasContextId, HasTestConfig, HasTwoChannels, - HasTwoNodes, -}; -use crate::prelude::*; - -pub fn build_test_context( - config: &TestConfig, - relayer: RelayerDriver, - chains: ConnectedChains, - channels: ConnectedChannel, -) -> Result< - impl HasTwoChannels - + HasTwoNodes - + HasTestConfig - + CanSpawnRelayer - + HasContextId - + CanWaitForAck - + CanShutdown, - Error, -> { - let context_current = TestContextV1 { - context_id: "current_relayer".to_owned(), - config: config.clone(), - relayer, - chains, - channel: channels, - }; - - Ok(context_current) -} diff --git a/tools/test-framework/src/framework/next/mod.rs b/tools/test-framework/src/framework/next/mod.rs deleted file mode 100644 index d04fb322c..000000000 --- a/tools/test-framework/src/framework/next/mod.rs +++ /dev/null @@ -1,2 +0,0 @@ -pub mod chain; -pub mod context; diff --git a/tools/test-framework/src/framework/overrides.rs b/tools/test-framework/src/framework/overrides.rs deleted file mode 100644 index 327d4d269..000000000 --- a/tools/test-framework/src/framework/overrides.rs +++ /dev/null @@ -1,233 +0,0 @@ -/*! - Constructs for implementing overrides for test cases. -*/ - -use core::time::Duration; - -use ibc_relayer::config::default::connection_delay as default_connection_delay; -use ibc_relayer::config::Config; -use ibc_relayer::foreign_client::CreateOptions as ClientOptions; -use ibc_relayer_types::core::ics04_channel::channel::Ordering; -use ibc_relayer_types::core::ics04_channel::version::Version; -use ibc_relayer_types::core::ics24_host::identifier::PortId; - -use crate::error::Error; -use crate::framework::base::{HasOverrides, TestConfigOverride}; -use crate::framework::binary::chain::{ClientOptionsOverride, RelayerConfigOverride}; -use crate::framework::binary::channel::{ - ChannelOrderOverride, ChannelVersionOverride, PortsOverride, -}; -use crate::framework::binary::connection::ConnectionDelayOverride; -use crate::framework::binary::node::{NodeConfigOverride, NodeGenesisOverride}; -use crate::framework::nary::channel::PortsOverride as NaryPortsOverride; -use crate::framework::supervisor::SupervisorOverride; -use crate::types::config::TestConfig; - -/** - This trait should be implemented for all test cases to allow overriding - some parts of the behavior during the test setup. - - Since all methods in this trait have default implementation, test cases - that do not need any override can have an empty implementation body for - this trait. - - The trait provides generic implementation of the specialized traits such as - [`RelayerConfigOverride`]. As a result, it is sufficient for test - writers to only implement this trait instead of implementing the - numerous override traits. - - When a new override trait is defined, the same trait method should - also be defined inside this trait with a default method body. -*/ -pub trait TestOverrides { - fn modify_test_config(&self, _config: &mut TestConfig) {} - - /** - Modify the full node config before the chain gets initialized. - - The config is in the dynamic-typed [`toml::Value`] format, as we do not - want to model the full format of the node config in Rust. Test authors - can use the helper methods in [`chain::config`](crate::chain::config) - to modify common config fields. - - Implemented for [`NodeConfigOverride`]. - */ - fn modify_node_config(&self, _config: &mut toml::Value) -> Result<(), Error> { - Ok(()) - } - - /** - Modify the genesis file before the chain gets initialized. - - The config is in the dynamic-typed [`serde_json::Value`] format, as we do not - want to model the full format of the genesis file in Rust. - - Implemented for [`NodeGenesisOverride`]. - */ - fn modify_genesis_file(&self, _genesis: &mut serde_json::Value) -> Result<(), Error> { - Ok(()) - } - - /** - Modify the relayer config before initializing the relayer. Does no - modification by default. - - Implemented for [`RelayerConfigOverride`]. - */ - fn modify_relayer_config(&self, _config: &mut Config) { - // No modification by default - } - - /// Returns the settings for the foreign client on the first chain for the - /// second chain. The defaults are for a client connecting two Cosmos chains - /// with no custom settings. - fn client_options_a_to_b(&self) -> ClientOptions { - Default::default() - } - - /// Returns the settings for the foreign client on the second chain for the - /// first chain. The defaults are for a client connecting two Cosmos chains - /// with no custom settings. - fn client_options_b_to_a(&self) -> ClientOptions { - Default::default() - } - - fn should_spawn_supervisor(&self) -> bool { - true - } - - /** - Return the connection delay used for creating connections as [`Duration`]. - Defaults to zero. - - Implemented for [`ConnectionDelayOverride`]. - */ - fn connection_delay(&self) -> Duration { - default_connection_delay() - } - - /** - Return the port ID used for creating the channel for the first chain. - Returns the "transfer" port by default. - - Implemented for [`PortsOverride`]. - */ - fn channel_port_a(&self) -> PortId { - PortId::transfer() - } - - /** - Return the port ID used for creating the channel for the second chain. - Returns the "transfer" port by default. - - Implemented for [`PortsOverride`]. - */ - fn channel_port_b(&self) -> PortId { - PortId::transfer() - } - - /** - Return the channel ordering used for creating channels as [`Ordering`]. - Defaults to [`Ordering::Unordered`]. - - Implemented for [`ChannelOrderOverride`]. - */ - fn channel_order(&self) -> Ordering { - Ordering::Unordered - } - - /** - Return the channel version used for creating channels as [`Version`]. - Defaults to [`Version::ics20()`]. - - Implemented for [`ChannelVersionOverride`]. - */ - fn channel_version(&self) -> Version { - Version::ics20() - } -} - -impl HasOverrides for Test { - type Overrides = Self; - - fn get_overrides(&self) -> &Self { - self - } -} - -impl TestConfigOverride for Test { - fn modify_test_config(&self, config: &mut TestConfig) { - TestOverrides::modify_test_config(self, config) - } -} - -impl NodeConfigOverride for Test { - fn modify_node_config(&self, config: &mut toml::Value) -> Result<(), Error> { - TestOverrides::modify_node_config(self, config) - } -} - -impl NodeGenesisOverride for Test { - fn modify_genesis_file(&self, genesis: &mut serde_json::Value) -> Result<(), Error> { - TestOverrides::modify_genesis_file(self, genesis) - } -} - -impl RelayerConfigOverride for Test { - fn modify_relayer_config(&self, config: &mut Config) { - TestOverrides::modify_relayer_config(self, config) - } -} - -impl ClientOptionsOverride for Test { - fn client_options_a_to_b(&self) -> ClientOptions { - TestOverrides::client_options_a_to_b(self) - } - - fn client_options_b_to_a(&self) -> ClientOptions { - TestOverrides::client_options_b_to_a(self) - } -} - -impl SupervisorOverride for Test { - fn should_spawn_supervisor(&self) -> bool { - TestOverrides::should_spawn_supervisor(self) - } -} - -impl ConnectionDelayOverride for Test { - fn connection_delay(&self) -> Duration { - TestOverrides::connection_delay(self) - } -} - -impl PortsOverride for Test { - fn channel_port_a(&self) -> PortId { - TestOverrides::channel_port_a(self) - } - - fn channel_port_b(&self) -> PortId { - TestOverrides::channel_port_b(self) - } -} - -impl ChannelOrderOverride for Test { - fn channel_order(&self) -> Ordering { - TestOverrides::channel_order(self) - } -} - -impl ChannelVersionOverride for Test { - fn channel_version(&self) -> Version { - TestOverrides::channel_version(self) - } -} - -impl NaryPortsOverride<2> for Test { - fn channel_ports(&self) -> [[PortId; 2]; 2] { - let port_a = self.channel_port_a(); - let port_b = self.channel_port_b(); - - [[port_a.clone(), port_b.clone()], [port_b, port_a]] - } -} diff --git a/tools/test-framework/src/framework/supervisor.rs b/tools/test-framework/src/framework/supervisor.rs deleted file mode 100644 index e5c9f1933..000000000 --- a/tools/test-framework/src/framework/supervisor.rs +++ /dev/null @@ -1,58 +0,0 @@ -/** - Constructs for wrapping test cases to spawn the relayer supervisor - before the inner test is executed. -*/ -use crate::framework::base::HasOverrides; - -/** - An internal trait that can be implemented by test cases to override - whether to automatically spawn the relayer supervisor before the - test starts. - - This is used by [`RunWithSupervisor`] to determine whether to - spawn the relayer. - - Test writers should implement - [`TestOverrides`](crate::framework::overrides::TestOverrides) - for their test cases instead of implementing this trait directly. -*/ -pub trait SupervisorOverride { - fn should_spawn_supervisor(&self) -> bool; -} - -/** - A wrapper type that implements the same test traits as the wrapped - `Test` type, and spawns the relayer supervisor before the inner test - is called. - - For example, if `Test` implements - [`BinaryChannelTest`](crate::framework::binary::channel::BinaryChannelTest), - then `RunWithSupervisor` also implements `BinaryChannelTest`. - - The automatic spawning of supervisor can be disabled by implementing - [`SupervisorOverride`] and returning false. - - When composing the test runners with `RunWithSupervisor`, it is important - to ensure that `RunWithSupervisor` do not appear more than once in the - nesting. Otherwise the supervisor may spawn more than once during tests. -*/ -pub struct RunWithSupervisor<'a, Test> { - pub test: &'a Test, -} - -impl<'a, Test> RunWithSupervisor<'a, Test> { - pub fn new(test: &'a Test) -> Self { - Self { test } - } -} - -impl HasOverrides for RunWithSupervisor<'_, Test> -where - Test: HasOverrides, -{ - type Overrides = Overrides; - - fn get_overrides(&self) -> &Self::Overrides { - self.test.get_overrides() - } -} diff --git a/tools/test-framework/src/ibc/denom.rs b/tools/test-framework/src/ibc/denom.rs deleted file mode 100644 index 21ba3068b..000000000 --- a/tools/test-framework/src/ibc/denom.rs +++ /dev/null @@ -1,160 +0,0 @@ -/*! - Helper functions for deriving IBC denom. -*/ - -use core::fmt::{self, Display}; - -use eyre::Report as Error; -use ibc_relayer_types::core::ics24_host::identifier::{ChannelId, PortId}; -use sha2::{Digest, Sha256}; -use subtle_encoding::hex; - -use crate::types::id::{TaggedChannelIdRef, TaggedPortIdRef}; -use crate::types::tagged::*; - -/** - A newtype wrapper to represent a denomination string. -*/ -#[derive(Debug, Clone)] -pub enum Denom { - Base(String), - Ibc { - path: String, - denom: String, - hashed: String, - }, -} - -/** - Type alias for [`Denom`] tagged with the chain it belongs to. -*/ -pub type TaggedDenom = MonoTagged; - -/** - Type alias for [`&Denom`](Denom) tagged with the chain it belongs to. -*/ -pub type TaggedDenomRef<'a, Chain> = MonoTagged; - -/** - Derives the denom on `ChainB` based on a denom on `ChainA` that has been - transferred to `ChainB` via IBC. - - Accepts the following arguments: - - - A `PortId` on `ChainB` that corresponds to a channel connected - to `ChainA`. - - - A `ChannelId` on `ChainB` that corresponds to a channel connected - to `ChainA`. - - - The original denomination on `ChainA`. - - Returns the derived denomination on `ChainB`. -*/ -pub fn derive_ibc_denom( - port_id: &TaggedPortIdRef, - channel_id: &TaggedChannelIdRef, - denom: &TaggedDenomRef, -) -> Result, Error> { - fn derive_denom( - port_id: &PortId, - channel_id: &ChannelId, - denom: &str, - ) -> Result { - let transfer_path = format!("{port_id}/{channel_id}/{denom}"); - derive_denom_with_path(&transfer_path) - } - - /// Derive the transferred token denomination using - /// - fn derive_denom_with_path(transfer_path: &str) -> Result { - let mut hasher = Sha256::new(); - hasher.update(transfer_path.as_bytes()); - - let denom_bytes = hasher.finalize(); - let denom_hex = String::from_utf8(hex::encode_upper(denom_bytes))?; - - Ok(format!("ibc/{denom_hex}")) - } - - match denom.value() { - Denom::Base(denom) => { - let hashed = derive_denom(port_id.value(), channel_id.value(), denom)?; - - Ok(MonoTagged::new(Denom::Ibc { - path: format!("{port_id}/{channel_id}"), - denom: denom.clone(), - hashed, - })) - } - Denom::Ibc { path, denom, .. } => { - let new_path = format!("{port_id}/{channel_id}/{path}"); - let hashed = derive_denom_with_path(&format!("{new_path}/{denom}"))?; - - Ok(MonoTagged::new(Denom::Ibc { - path: new_path, - denom: denom.clone(), - hashed, - })) - } - } -} - -impl Denom { - pub fn base(denom: &str) -> Self { - Denom::Base(denom.to_string()) - } - - pub fn hash_only(&self) -> String { - match self { - Denom::Base(denom) => denom.to_string(), - Denom::Ibc { hashed, .. } => match hashed.find('/') { - Some(index) => hashed[index + 1..].to_string(), - None => hashed.to_string(), - }, - } - } - - pub fn as_str(&self) -> &str { - match self { - Denom::Base(denom) => denom, - Denom::Ibc { hashed, .. } => hashed, - } - } -} - -impl Display for Denom { - fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { - match self { - Denom::Base(denom) => { - write!(f, "{denom}") - } - Denom::Ibc { hashed, .. } => { - write!(f, "{hashed}") - } - } - } -} - -impl PartialEq for Denom { - fn eq(&self, other: &Self) -> bool { - match (self, other) { - (Self::Base(d1), Self::Base(d2)) => d1 == d2, - ( - Self::Ibc { - path: p1, - denom: d1, - hashed: h1, - }, - Self::Ibc { - path: p2, - denom: d2, - hashed: h2, - }, - ) => p1 == p2 && d1 == d2 && h1 == h2, - _ => self.as_str() == other.as_str(), - } - } -} - -impl Eq for Denom {} diff --git a/tools/test-framework/src/ibc/mod.rs b/tools/test-framework/src/ibc/mod.rs deleted file mode 100644 index 13a89ad47..000000000 --- a/tools/test-framework/src/ibc/mod.rs +++ /dev/null @@ -1,7 +0,0 @@ -/*! - Code that may belong to the `ibc` module, but are currently - in this crate for easier review or maintenance. -*/ - -pub mod denom; -pub mod token; diff --git a/tools/test-framework/src/ibc/token.rs b/tools/test-framework/src/ibc/token.rs deleted file mode 100644 index eae205151..000000000 --- a/tools/test-framework/src/ibc/token.rs +++ /dev/null @@ -1,118 +0,0 @@ -use core::ops::{Add, Sub}; - -use ibc_relayer_types::applications::transfer::amount::Amount; -use ibc_relayer_types::applications::transfer::coin::{Coin, RawCoin}; - -use crate::error::Error; -use crate::ibc::denom::{derive_ibc_denom, Denom, TaggedDenom, TaggedDenomRef}; -use crate::types::id::{TaggedChannelIdRef, TaggedPortIdRef}; -use crate::types::tagged::MonoTagged; - -pub type Token = Coin; - -pub type TaggedToken = MonoTagged; -pub type TaggedTokenRef<'a, Chain> = MonoTagged; - -pub trait TaggedTokenExt { - fn denom(&self) -> TaggedDenomRef; - - fn amount(&self) -> Amount; - - fn as_coin(&self) -> RawCoin; - - fn transfer( - &self, - port_id: &TaggedPortIdRef, - channel_id: &TaggedChannelIdRef, - ) -> Result, Error>; -} - -pub trait TaggedDenomExt { - fn with_amount(&self, amount: impl Into) -> TaggedToken; -} - -impl TaggedTokenExt for TaggedToken { - fn denom(&self) -> TaggedDenomRef { - self.map_ref(|t| &t.denom) - } - - fn amount(&self) -> Amount { - self.value().amount - } - - fn as_coin(&self) -> RawCoin { - RawCoin::new(self.value().denom.to_string(), self.value().amount) - } - - fn transfer( - &self, - port_id: &TaggedPortIdRef, - channel_id: &TaggedChannelIdRef, - ) -> Result, Error> { - let denom = derive_ibc_denom(port_id, channel_id, &self.denom())?; - - Ok(denom.with_amount(self.value().amount)) - } -} - -impl TaggedTokenExt for TaggedTokenRef<'_, Chain> { - fn denom(&self) -> TaggedDenomRef { - self.map_ref(|t| &t.denom) - } - - fn amount(&self) -> Amount { - self.value().amount - } - - fn as_coin(&self) -> RawCoin { - RawCoin::new(self.value().denom.to_string(), self.value().amount) - } - - fn transfer( - &self, - port_id: &TaggedPortIdRef, - channel_id: &TaggedChannelIdRef, - ) -> Result, Error> { - let denom = derive_ibc_denom(port_id, channel_id, &self.denom())?; - - Ok(denom.with_amount(self.value().amount)) - } -} - -impl TaggedDenomExt for TaggedDenom { - fn with_amount(&self, amount: impl Into) -> TaggedToken { - self.map(|denom| Token { - denom: denom.clone(), - amount: amount.into(), - }) - } -} - -impl TaggedDenomExt for TaggedDenomRef<'_, Chain> { - fn with_amount(&self, amount: impl Into) -> TaggedToken { - self.map(|denom| Token { - denom: (*denom).clone(), - amount: amount.into(), - }) - } -} - -impl> Add for MonoTagged { - type Output = Self; - - fn add(self, amount: I) -> Self { - self.map_into(|t| t.checked_add(amount)) - .transpose() - .unwrap() - } -} - -impl> Sub for MonoTagged { - type Output = Self; - - fn sub(self, amount: I) -> Self { - self.map_into(|t| t.checked_sub(amount)) - .transpose() - .unwrap() - } -} diff --git a/tools/test-framework/src/lib.rs b/tools/test-framework/src/lib.rs deleted file mode 100644 index e6dd97eb2..000000000 --- a/tools/test-framework/src/lib.rs +++ /dev/null @@ -1,83 +0,0 @@ -// #![deny(warnings)] -#![allow(clippy::too_many_arguments)] -#![allow(clippy::type_complexity)] -#![allow(clippy::ptr_arg)] -#![doc = include_str!("../README.md")] - -//! ## Overview -//! -//! This IBC test framework gives developers working on relayer software in Rust a robust -//! yet flexible suite of functionality to test the correctness of their relayer implementations, -//! as well as verify the expected state of chains in response to relayed messages and packets. -//! -//! ## Running Tests -//! -//! We can run tests via the command line as follows: -//! -//! ```bash -//! RUST_LOG=info RUST_BACKTRACE=1 \ -//! cargo test -p ibc-integration-test --features example -- --test-threads=1 \ -//! example_test -//! ``` -//! -//! The environment variable `RUST_LOG` controls log filtering for Hermes and, -//! besides the global log level, can be used to pass more elaborate directives -//! for the tracing framework. The `RUST_BACKTRACE` variable -//! displays a backtrace when errors occur in a test. The test flag `--test-threads=1` is -//! set so that tests are run serially (this makes it easier to follow what is going on -//! via the log output). Take a look at the [`TestConfig`](crate::types::config::TestConfig) -//! type for more information about configuring how tests can be run. -//! -//! For this example, we disable the test from running by default, since it calls the -//! `suspend` function and will thus never pass. We explicitly pass `--features example` -//! so that the `example` feature is activated such that this test will run. Finally, we -//! specify the name of the test so that _only_ our example test is run. -//! -//! After starting the test run, we may see logs such as the following: -//! -//! ```text -//! $ cargo test -p ibc-integration-test --features example -- --nocapture --test-threads=1 example_test -//! ... -//! INFO created new chain/client/connection/channel from ibc-alpha-c4aed8f9/07-tendermint-4/connection-6/channel-1 to ibc-beta-fcb867bb/07-tendermint-6/connection-1/channel-6 -//! INFO written channel environment to /path/to/ibc-rs/tools/integration-test/data/test-1094235493/binary-channels.env -//! WARN suspending the test indefinitely. you can still interact with any spawned chains and relayers -//! ... -//! ``` -//! -//! The INFO lines are notifying us of the path environment variables exported by the test. -//! The WARN line states that the test has been suspended indefinitely, as we knew it would. -//! Note that the chains are created with random IDs and are listening on random ports. -//! -//! Using the logs, we can for example use `gaiad` to query for the balance of the accounts -//! created by the test by running: -//! -//! ```bash -//! $ source /path/to/ibc-rs/tools/integration-test/data/test-1094235493/binary-channels.env -//! $ gaiad --home "$NODE_A_HOME" --node $NODE_A_RPC_ADDR query bank balances $NODE_A_WALLETS_USER1_ADDRESS -//! balances: -//! - amount: "6902395390297" -//! denom: coin95143d31 -//! - amount: "6902395390297" -//! denom: stake -//! pagination: -//! next_key: null -//! total: "0" -//! ``` -//! -//! The test data and configuration files are stored at the absolute path shown in the -//! log, which looks something like `/path/to/ibc-rs/tools/integration-test/data/test-1094235493`. -//! The sub-directory `test-1094235493` is randomly generated at the beginning of a test -//! case such that all data related to that test lives in the same directory. - -extern crate alloc; - -pub mod bootstrap; -pub mod chain; -pub mod docs; -pub mod error; -pub mod framework; -pub mod ibc; -pub mod prelude; -pub mod relayer; -pub mod types; -pub mod util; diff --git a/tools/test-framework/src/prelude.rs b/tools/test-framework/src/prelude.rs deleted file mode 100644 index fb90db7d9..000000000 --- a/tools/test-framework/src/prelude.rs +++ /dev/null @@ -1,77 +0,0 @@ -/*! - Re-export of common constructs that are used by test cases. -*/ - -pub use core::time::Duration; -pub use std::thread::sleep; - -pub use eyre::eyre; -pub use ibc_relayer::chain::handle::ChainHandle; -pub use ibc_relayer::config::Config; -pub use ibc_relayer::foreign_client::ForeignClient; -pub use ibc_relayer::registry::SharedRegistry; -pub use ibc_relayer::supervisor::SupervisorHandle; -pub use ibc_relayer_types::core::ics04_channel::channel::Ordering; -pub use ibc_relayer_types::core::ics24_host::identifier::{ - ChainId, ChannelId, ClientId, ConnectionId, PortId, -}; -pub use tracing::{debug, error, info, warn}; - -pub use crate::chain::driver::ChainDriver; -pub use crate::chain::ext::fee::ChainFeeMethodsExt; -pub use crate::chain::ext::ica::InterchainAccountMethodsExt; -pub use crate::chain::ext::proposal::ChainProposalMethodsExt; -pub use crate::chain::ext::transfer::ChainTransferMethodsExt; -pub use crate::chain::tagged::TaggedChainDriverExt; -pub use crate::error::{handle_generic_error, Error}; -pub use crate::framework::base::HasOverrides; -pub use crate::framework::binary::chain::{ - run_binary_chain_test, run_self_connected_binary_chain_test, run_two_way_binary_chain_test, - BinaryChainTest, RunBinaryChainTest, RunSelfConnectedBinaryChainTest, -}; -pub use crate::framework::binary::channel::{ - run_binary_channel_test, run_two_way_binary_channel_test, BinaryChannelTest, - RunBinaryChannelTest, -}; -pub use crate::framework::binary::connection::{ - run_binary_connection_test, run_two_way_binary_connection_test, BinaryConnectionTest, - RunBinaryConnectionTest, -}; -pub use crate::framework::binary::node::{run_binary_node_test, BinaryNodeTest, RunBinaryNodeTest}; -pub use crate::framework::nary::chain::{ - run_nary_chain_test, run_self_connected_nary_chain_test, NaryChainTest, RunNaryChainTest, - RunSelfConnectedNaryChainTest, -}; -pub use crate::framework::nary::channel::{ - run_binary_as_nary_channel_test, run_nary_channel_test, NaryChannelTest, PortsOverride, - RunBinaryAsNaryChannelTest, RunNaryChannelTest, -}; -pub use crate::framework::nary::connection::{ - run_nary_connection_test, NaryConnectionTest, RunNaryConnectionTest, -}; -pub use crate::framework::nary::node::{run_nary_node_test, NaryNodeTest, RunNaryNodeTest}; -pub use crate::framework::overrides::TestOverrides; -pub use crate::framework::supervisor::RunWithSupervisor; -pub use crate::ibc::denom::{derive_ibc_denom, Denom}; -pub use crate::ibc::token::{TaggedDenomExt, TaggedToken, TaggedTokenExt, TaggedTokenRef, Token}; -pub use crate::relayer::channel::TaggedChannelEndExt; -pub use crate::relayer::connection::{TaggedConnectionEndExt, TaggedConnectionExt}; -pub use crate::relayer::driver::RelayerDriver; -pub use crate::relayer::foreign_client::TaggedForeignClientExt; -pub use crate::types::binary::chains::ConnectedChains; -pub use crate::types::binary::channel::ConnectedChannel; -pub use crate::types::binary::connection::ConnectedConnection; -pub use crate::types::binary::foreign_client::ForeignClientPair; -pub use crate::types::config::TestConfig; -pub use crate::types::id::*; -pub use crate::types::nary::chains::NaryConnectedChains; -pub use crate::types::nary::channel::ConnectedChannels as NaryConnectedChannels; -pub use crate::types::nary::connection::ConnectedConnections as NaryConnectedConnections; -pub use crate::types::single::node::{FullNode, TaggedFullNodeExt}; -pub use crate::types::tagged::{DualTagged, MonoTagged}; -pub use crate::types::wallet::{ - TaggedTestWalletsExt, TaggedWallet, TestWallets, Wallet, WalletAddress, WalletId, -}; -pub use crate::util::assert::*; -pub use crate::util::retry::assert_eventually_succeed; -pub use crate::util::suspend::suspend; diff --git a/tools/test-framework/src/relayer/chain.rs b/tools/test-framework/src/relayer/chain.rs deleted file mode 100644 index 0881f351c..000000000 --- a/tools/test-framework/src/relayer/chain.rs +++ /dev/null @@ -1,462 +0,0 @@ -/*! - Definition for a proxy [`ChainHandle`] implementation for tagged - chain handles. - - Since we use the chain handle type to distinguish the chain tags, we will - run into problem if we have the same concrete `ChainHandle` implementations - for two chains that are not encapsulated behind an `impl ChainHandle`. - - This is the case for creating N-ary chains, because we cannot rely on the - existential type encapsulation of `impl ChainHandle` to turn the - [`CountingAndCachingChainHandle`](ibc_relayer::chain::handle::CountingAndCachingChainHandle) to turn - them into unqiue types. - - A workaround for this is to add a unique tag to `CountingAndCachingChainHandle` itself, - so that the type `MonoTagged` becomes a unique chain - handle type. - - We implement [`ChainHandle`] for a `MonoTagged`, since if the - underlying `Handle` type implements [`ChainHandle`], then a tagged handle - is still a [`ChainHandle`]. -*/ - -use crossbeam_channel as channel; -use ibc_proto::ibc::apps::fee::v1::{ - QueryIncentivizedPacketRequest, QueryIncentivizedPacketResponse, -}; -use ibc_proto::ibc::core::channel::v1::{QueryUpgradeErrorRequest, QueryUpgradeRequest}; -use ibc_relayer::account::Balance; -use ibc_relayer::chain::client::ClientSettings; -use ibc_relayer::chain::endpoint::{ChainStatus, HealthCheck}; -use ibc_relayer::chain::handle::{ChainHandle, ChainRequest, Subscription}; -use ibc_relayer::chain::requests::*; -use ibc_relayer::chain::tracking::TrackedMsgs; -use ibc_relayer::client_state::{AnyClientState, IdentifiedAnyClientState}; -use ibc_relayer::config::ChainConfig; -use ibc_relayer::connection::ConnectionMsgType; -use ibc_relayer::consensus_state::AnyConsensusState; -use ibc_relayer::denom::DenomTrace; -use ibc_relayer::error::Error; -use ibc_relayer::event::IbcEventWithHeight; -use ibc_relayer::keyring::AnySigningKeyPair; -use ibc_relayer::misbehaviour::MisbehaviourEvidence; -use ibc_relayer_types::applications::ics28_ccv::msgs::{ConsumerChain, ConsumerId}; -use ibc_relayer_types::applications::ics31_icq::response::CrossChainQueryResponse; -use ibc_relayer_types::core::ics02_client::events::UpdateClient; -use ibc_relayer_types::core::ics02_client::header::AnyHeader; -use ibc_relayer_types::core::ics03_connection::connection::{ - ConnectionEnd, IdentifiedConnectionEnd, -}; -use ibc_relayer_types::core::ics03_connection::version::Version; -use ibc_relayer_types::core::ics04_channel::channel::{ChannelEnd, IdentifiedChannelEnd}; -use ibc_relayer_types::core::ics04_channel::packet::{PacketMsgType, Sequence}; -use ibc_relayer_types::core::ics04_channel::upgrade::{ErrorReceipt, Upgrade}; -use ibc_relayer_types::core::ics23_commitment::commitment::CommitmentPrefix; -use ibc_relayer_types::core::ics23_commitment::merkle::MerkleProof; -use ibc_relayer_types::core::ics24_host::identifier::{ - ChainId, ChannelId, ClientId, ConnectionId, PortId, -}; -use ibc_relayer_types::proofs::Proofs; -use ibc_relayer_types::signer::Signer; -use ibc_relayer_types::Height; -use tracing::Span; - -use crate::types::tagged::*; - -/** - Implement `ChainHandle` for any existential type `Handle: ChainHandle`. - This allows us to tag values for chains that are tagged by position - in [N-ary chains](crate::types::nary). -*/ -impl ChainHandle for MonoTagged -where - Tag: Send + Sync + 'static, - Handle: ChainHandle, -{ - fn new(chain_id: ChainId, sender: channel::Sender<(Span, ChainRequest)>) -> Self { - Self::new(Handle::new(chain_id, sender)) - } - - fn id(&self) -> ChainId { - self.value().id() - } - - fn shutdown(&self) -> Result<(), Error> { - self.value().shutdown() - } - - fn health_check(&self) -> Result { - self.value().health_check() - } - - fn subscribe(&self) -> Result { - self.value().subscribe() - } - - fn send_messages_and_wait_commit( - &self, - tracked_msgs: TrackedMsgs, - ) -> Result, Error> { - self.value().send_messages_and_wait_commit(tracked_msgs) - } - - fn send_messages_and_wait_check_tx( - &self, - tracked_msgs: TrackedMsgs, - ) -> Result, Error> { - self.value().send_messages_and_wait_check_tx(tracked_msgs) - } - - fn get_signer(&self) -> Result { - self.value().get_signer() - } - - fn config(&self) -> Result { - self.value().config() - } - - fn get_key(&self) -> Result { - self.value().get_key() - } - - fn add_key(&self, key_name: String, key: AnySigningKeyPair) -> Result<(), Error> { - self.value().add_key(key_name, key) - } - - fn query_application_status(&self) -> Result { - self.value().query_application_status() - } - - fn query_latest_height(&self) -> Result { - self.value().query_latest_height() - } - - fn query_clients( - &self, - request: QueryClientStatesRequest, - ) -> Result, Error> { - self.value().query_clients(request) - } - - fn query_client_state( - &self, - request: QueryClientStateRequest, - include_proof: IncludeProof, - ) -> Result<(AnyClientState, Option), Error> { - self.value().query_client_state(request, include_proof) - } - - fn query_client_connections( - &self, - request: QueryClientConnectionsRequest, - ) -> Result, Error> { - self.value().query_client_connections(request) - } - - fn query_consensus_state_heights( - &self, - request: QueryConsensusStateHeightsRequest, - ) -> Result, Error> { - self.value().query_consensus_state_heights(request) - } - - fn query_consensus_state( - &self, - request: QueryConsensusStateRequest, - include_proof: IncludeProof, - ) -> Result<(AnyConsensusState, Option), Error> { - self.value().query_consensus_state(request, include_proof) - } - - fn query_upgraded_client_state( - &self, - request: QueryUpgradedClientStateRequest, - ) -> Result<(AnyClientState, MerkleProof), Error> { - self.value().query_upgraded_client_state(request) - } - - fn query_upgraded_consensus_state( - &self, - request: QueryUpgradedConsensusStateRequest, - ) -> Result<(AnyConsensusState, MerkleProof), Error> { - self.value().query_upgraded_consensus_state(request) - } - - fn query_commitment_prefix(&self) -> Result { - self.value().query_commitment_prefix() - } - - fn query_compatible_versions(&self) -> Result, Error> { - self.value().query_compatible_versions() - } - - fn query_connection( - &self, - request: QueryConnectionRequest, - include_proof: IncludeProof, - ) -> Result<(ConnectionEnd, Option), Error> { - self.value().query_connection(request, include_proof) - } - - fn query_connections( - &self, - request: QueryConnectionsRequest, - ) -> Result, Error> { - self.value().query_connections(request) - } - - fn query_connection_channels( - &self, - request: QueryConnectionChannelsRequest, - ) -> Result, Error> { - self.value().query_connection_channels(request) - } - - fn query_next_sequence_receive( - &self, - request: QueryNextSequenceReceiveRequest, - include_proof: IncludeProof, - ) -> Result<(Sequence, Option), Error> { - self.value() - .query_next_sequence_receive(request, include_proof) - } - - fn query_channels( - &self, - request: QueryChannelsRequest, - ) -> Result, Error> { - self.value().query_channels(request) - } - - fn query_channel( - &self, - request: QueryChannelRequest, - include_proof: IncludeProof, - ) -> Result<(ChannelEnd, Option), Error> { - self.value().query_channel(request, include_proof) - } - - fn query_channel_client_state( - &self, - request: QueryChannelClientStateRequest, - ) -> Result, Error> { - self.value().query_channel_client_state(request) - } - - fn build_header( - &self, - trusted_height: Height, - target_height: Height, - client_state: AnyClientState, - ) -> Result<(AnyHeader, Vec), Error> { - self.value() - .build_header(trusted_height, target_height, client_state) - } - - /// Constructs a client state at the given height - fn build_client_state( - &self, - height: Height, - settings: ClientSettings, - ) -> Result { - self.value().build_client_state(height, settings) - } - - /// Constructs a consensus state at the given height - fn build_consensus_state( - &self, - trusted: Height, - target: Height, - client_state: AnyClientState, - ) -> Result { - self.value() - .build_consensus_state(trusted, target, client_state) - } - - fn check_misbehaviour( - &self, - update: UpdateClient, - client_state: AnyClientState, - ) -> Result, Error> { - self.value().check_misbehaviour(update, client_state) - } - - fn build_connection_proofs_and_client_state( - &self, - message_type: ConnectionMsgType, - connection_id: &ConnectionId, - client_id: &ClientId, - height: Height, - ) -> Result<(Option, Proofs), Error> { - self.value().build_connection_proofs_and_client_state( - message_type, - connection_id, - client_id, - height, - ) - } - - fn build_channel_proofs( - &self, - port_id: &PortId, - channel_id: &ChannelId, - height: Height, - ) -> Result { - self.value() - .build_channel_proofs(port_id, channel_id, height) - } - - fn build_packet_proofs( - &self, - packet_type: PacketMsgType, - port_id: &PortId, - channel_id: &ChannelId, - sequence: Sequence, - height: Height, - ) -> Result { - self.value() - .build_packet_proofs(packet_type, port_id, channel_id, sequence, height) - } - - fn query_packet_commitment( - &self, - request: QueryPacketCommitmentRequest, - include_proof: IncludeProof, - ) -> Result<(Vec, Option), Error> { - self.value().query_packet_commitment(request, include_proof) - } - - fn query_packet_commitments( - &self, - request: QueryPacketCommitmentsRequest, - ) -> Result<(Vec, Height), Error> { - self.value().query_packet_commitments(request) - } - - fn query_packet_receipt( - &self, - request: QueryPacketReceiptRequest, - include_proof: IncludeProof, - ) -> Result<(Vec, Option), Error> { - self.value().query_packet_receipt(request, include_proof) - } - - fn query_unreceived_packets( - &self, - request: QueryUnreceivedPacketsRequest, - ) -> Result, Error> { - self.value().query_unreceived_packets(request) - } - - fn query_packet_acknowledgement( - &self, - request: QueryPacketAcknowledgementRequest, - include_proof: IncludeProof, - ) -> Result<(Vec, Option), Error> { - self.value() - .query_packet_acknowledgement(request, include_proof) - } - - fn query_packet_acknowledgements( - &self, - request: QueryPacketAcknowledgementsRequest, - ) -> Result<(Vec, Height), Error> { - self.value().query_packet_acknowledgements(request) - } - - fn query_unreceived_acknowledgements( - &self, - request: QueryUnreceivedAcksRequest, - ) -> Result, Error> { - self.value().query_unreceived_acknowledgements(request) - } - - fn query_txs(&self, request: QueryTxRequest) -> Result, Error> { - self.value().query_txs(request) - } - - fn query_packet_events( - &self, - request: QueryPacketEventDataRequest, - ) -> Result, Error> { - self.value().query_packet_events(request) - } - - fn query_host_consensus_state( - &self, - request: QueryHostConsensusStateRequest, - ) -> Result { - self.value().query_host_consensus_state(request) - } - - fn query_balance( - &self, - key_name: Option, - denom: Option, - ) -> Result { - self.value().query_balance(key_name, denom) - } - - fn query_all_balances(&self, key_name: Option) -> Result, Error> { - self.value().query_all_balances(key_name) - } - - fn maybe_register_counterparty_payee( - &self, - channel_id: ChannelId, - port_id: PortId, - counterparty_payee: Signer, - ) -> Result<(), Error> { - self.value() - .maybe_register_counterparty_payee(channel_id, port_id, counterparty_payee) - } - - fn query_denom_trace(&self, hash: String) -> Result { - self.value().query_denom_trace(hash) - } - - fn cross_chain_query( - &self, - request: Vec, - ) -> Result, Error> { - self.value().cross_chain_query(request) - } - - fn query_incentivized_packet( - &self, - request: QueryIncentivizedPacketRequest, - ) -> Result { - self.value().query_incentivized_packet(request) - } - - fn query_consumer_chains(&self) -> Result, Error> { - self.value().query_consumer_chains() - } - - fn version_specs(&self) -> Result { - self.value().version_specs() - } - - fn query_upgrade( - &self, - request: QueryUpgradeRequest, - height: Height, - include_proof: IncludeProof, - ) -> Result<(Upgrade, Option), Error> { - self.value().query_upgrade(request, height, include_proof) - } - - fn query_upgrade_error( - &self, - request: QueryUpgradeErrorRequest, - height: Height, - include_proof: IncludeProof, - ) -> Result<(ErrorReceipt, Option), Error> { - self.value() - .query_upgrade_error(request, height, include_proof) - } - - fn query_ccv_consumer_id(&self, client_id: &ClientId) -> Result { - self.value().query_ccv_consumer_id(client_id) - } -} diff --git a/tools/test-framework/src/relayer/channel.rs b/tools/test-framework/src/relayer/channel.rs deleted file mode 100644 index 97f5c8c26..000000000 --- a/tools/test-framework/src/relayer/channel.rs +++ /dev/null @@ -1,209 +0,0 @@ -use core::time::Duration; - -use eyre::eyre; -use ibc_relayer::chain::handle::ChainHandle; -use ibc_relayer::chain::requests::{IncludeProof, QueryChannelRequest, QueryHeight}; -use ibc_relayer::channel::{extract_channel_id, Channel, ChannelSide}; -use ibc_relayer_types::core::ics04_channel::channel::{ChannelEnd, IdentifiedChannelEnd, Ordering}; -use ibc_relayer_types::core::ics24_host::identifier::ConnectionId; - -use crate::error::Error; -use crate::types::id::{ - TaggedChannelId, TaggedChannelIdRef, TaggedClientIdRef, TaggedConnectionIdRef, TaggedPortId, - TaggedPortIdRef, -}; -use crate::types::tagged::DualTagged; -use crate::util::retry::assert_eventually_succeed; - -pub trait TaggedChannelEndExt { - fn tagged_counterparty_channel_id(&self) -> Option>; - fn tagged_counterparty_port_id(&self) -> TaggedPortId; -} - -impl TaggedChannelEndExt - for DualTagged -{ - fn tagged_counterparty_channel_id(&self) -> Option> { - self.contra_map(|c| c.counterparty().channel_id.clone()) - .transpose() - } - - fn tagged_counterparty_port_id(&self) -> TaggedPortId { - self.contra_map(|c| c.counterparty().port_id.clone()) - } -} - -pub fn init_channel( - handle_a: &ChainA, - handle_b: &ChainB, - client_id_a: &TaggedClientIdRef, - client_id_b: &TaggedClientIdRef, - connection_id_a: &TaggedConnectionIdRef, - connection_id_b: &TaggedConnectionIdRef, - src_port_id: &TaggedPortIdRef, - dst_port_id: &TaggedPortIdRef, -) -> Result<(TaggedChannelId, Channel), Error> { - let channel = Channel { - connection_delay: Default::default(), - ordering: Ordering::Unordered, - a_side: ChannelSide::new( - handle_a.clone(), - client_id_a.cloned_value(), - connection_id_a.cloned_value(), - src_port_id.cloned_value(), - None, - None, - ), - b_side: ChannelSide::new( - handle_b.clone(), - client_id_b.cloned_value(), - connection_id_b.cloned_value(), - dst_port_id.cloned_value(), - None, - None, - ), - }; - - let event = channel.build_chan_open_init_and_send()?; - let channel_id = extract_channel_id(&event)?.clone(); - let channel2 = Channel::restore_from_event(handle_b.clone(), handle_a.clone(), event)?; - - Ok((DualTagged::new(channel_id), channel2)) -} - -pub fn init_channel_optimistic( - handle_a: &ChainA, - handle_b: &ChainB, - client_id_a: &TaggedClientIdRef, - client_id_b: &TaggedClientIdRef, - connection_id_b: &TaggedConnectionIdRef, - src_port_id: &TaggedPortIdRef, - dst_port_id: &TaggedPortIdRef, -) -> Result, Error> { - let channel = Channel { - connection_delay: Default::default(), - ordering: Ordering::Unordered, - a_side: ChannelSide::new( - handle_a.clone(), - client_id_a.cloned_value(), - ConnectionId::default(), - src_port_id.cloned_value(), - None, - None, - ), - b_side: ChannelSide::new( - handle_b.clone(), - client_id_b.cloned_value(), - connection_id_b.cloned_value(), - dst_port_id.cloned_value(), - None, - None, - ), - }; - - let event = channel.build_chan_open_init_and_send()?; - let channel_id = extract_channel_id(&event)?.clone(); - Ok(DualTagged::new(channel_id)) -} - -pub fn try_channel( - handle_a: &ChainA, - handle_b: &ChainB, - channel: &Channel, -) -> Result<(TaggedChannelId, Channel), Error> { - let event = channel.build_chan_open_try_and_send()?; - let channel_id = extract_channel_id(&event)?.clone(); - let channel2 = Channel::restore_from_event(handle_a.clone(), handle_b.clone(), event)?; - - Ok((DualTagged::new(channel_id), channel2)) -} - -pub fn ack_channel( - handle_a: &ChainA, - handle_b: &ChainB, - channel: &Channel, -) -> Result<(TaggedChannelId, Channel), Error> { - let event = channel.build_chan_open_ack_and_send()?; - let channel_id = extract_channel_id(&event)?.clone(); - let channel2 = Channel::restore_from_event(handle_a.clone(), handle_b.clone(), event)?; - - Ok((DualTagged::new(channel_id), channel2)) -} - -pub fn query_channel_end( - handle: &ChainA, - channel_id: &TaggedChannelIdRef, - port_id: &TaggedPortIdRef, -) -> Result, Error> { - let (channel_end, _) = handle.query_channel( - QueryChannelRequest { - port_id: port_id.into_value().clone(), - channel_id: channel_id.into_value().clone(), - height: QueryHeight::Latest, - }, - IncludeProof::No, - )?; - - Ok(DualTagged::new(channel_end)) -} - -pub fn query_identified_channel_end( - handle: &ChainA, - channel_id: TaggedChannelIdRef, - port_id: TaggedPortIdRef, -) -> Result, Error> { - let (channel_end, _) = handle.query_channel( - QueryChannelRequest { - port_id: port_id.into_value().clone(), - channel_id: channel_id.into_value().clone(), - height: QueryHeight::Latest, - }, - IncludeProof::No, - )?; - Ok(DualTagged::new(IdentifiedChannelEnd::new( - port_id.into_value().clone(), - channel_id.into_value().clone(), - channel_end, - ))) -} - -pub fn assert_eventually_channel_established( - handle_a: &ChainA, - handle_b: &ChainB, - channel_id_a: &TaggedChannelIdRef, - port_id_a: &TaggedPortIdRef, -) -> Result, Error> { - assert_eventually_succeed( - "channel should eventually established", - 20, - Duration::from_secs(1), - || { - let channel_end_a = query_channel_end(handle_a, channel_id_a, port_id_a)?; - - if !channel_end_a.value().is_open() { - return Err(Error::generic(eyre!( - "expected channel end A to be in open state" - ))); - } - - let channel_id_b = channel_end_a - .tagged_counterparty_channel_id() - .ok_or_else(|| { - eyre!("expected counterparty channel id to present on open channel") - })?; - - let port_id_b = channel_end_a.tagged_counterparty_port_id(); - - let channel_end_b = - query_channel_end(handle_b, &channel_id_b.as_ref(), &port_id_b.as_ref())?; - - if !channel_end_b.value().is_open() { - return Err(Error::generic(eyre!( - "expected channel end B to be in open state" - ))); - } - - Ok(channel_id_b) - }, - ) -} diff --git a/tools/test-framework/src/relayer/connection.rs b/tools/test-framework/src/relayer/connection.rs deleted file mode 100644 index c80347083..000000000 --- a/tools/test-framework/src/relayer/connection.rs +++ /dev/null @@ -1,196 +0,0 @@ -/*! - Definition for extension trait methods for [`Connection`] -*/ - -use core::time::Duration; - -use eyre::eyre; -use ibc_relayer::chain::handle::ChainHandle; -use ibc_relayer::chain::requests::{IncludeProof, QueryConnectionRequest, QueryHeight}; -use ibc_relayer::connection::{extract_connection_id, Connection, ConnectionSide}; -use ibc_relayer_types::core::ics03_connection::connection::{ - ConnectionEnd, IdentifiedConnectionEnd, State as ConnectionState, -}; -use ibc_relayer_types::timestamp::ZERO_DURATION; - -use crate::error::Error; -use crate::types::id::{TaggedClientIdRef, TaggedConnectionId, TaggedConnectionIdRef}; -use crate::types::tagged::DualTagged; -use crate::util::retry::assert_eventually_succeed; - -/** - An extension trait that provide helper methods to get tagged identifiers - out of a [`Connection`]. -*/ -pub trait TaggedConnectionExt { - /** - Get the connection ID from side A of the chain. - */ - fn tagged_connection_id_a(&self) -> Option>; - - /** - Get the connection ID from side B of the chain. - */ - fn tagged_connection_id_b(&self) -> Option>; -} - -pub trait TaggedConnectionEndExt { - fn tagged_counterparty_connection_id(&self) -> Option>; -} - -impl TaggedConnectionExt - for Connection -{ - fn tagged_connection_id_a(&self) -> Option> { - self.a_side.connection_id().map(DualTagged::new) - } - - fn tagged_connection_id_b(&self) -> Option> { - self.b_side.connection_id().map(DualTagged::new) - } -} - -impl TaggedConnectionEndExt - for DualTagged -{ - fn tagged_counterparty_connection_id(&self) -> Option> { - self.contra_map(|c| c.counterparty().connection_id.clone()) - .transpose() - } -} - -pub fn init_connection( - handle_a: &ChainA, - handle_b: &ChainB, - client_id_a: &TaggedClientIdRef, - client_id_b: &TaggedClientIdRef, -) -> Result< - ( - TaggedConnectionId, - Connection, - ), - Error, -> { - let connection = Connection { - delay_period: ZERO_DURATION, - a_side: ConnectionSide::new(handle_a.clone(), (*client_id_a.value()).clone(), None), - b_side: ConnectionSide::new(handle_b.clone(), (*client_id_b.value()).clone(), None), - }; - - let event = connection.build_conn_init_and_send()?; - let connection_id = extract_connection_id(&event)?.clone(); - let connection2 = Connection::restore_from_event(handle_b.clone(), handle_a.clone(), &event)?; - - Ok((DualTagged::new(connection_id), connection2)) -} - -pub fn try_connection( - handle_a: &ChainA, - handle_b: &ChainB, - connection: &Connection, -) -> Result< - ( - TaggedConnectionId, - Connection, - ), - Error, -> { - let event = connection.build_conn_try_and_send()?; - let connection_id = extract_connection_id(&event)?.clone(); - let connection2 = Connection::restore_from_event(handle_b.clone(), handle_a.clone(), &event)?; - - Ok((DualTagged::new(connection_id), connection2)) -} - -pub fn ack_connection( - handle_a: &ChainA, - handle_b: &ChainB, - connection: &Connection, -) -> Result< - ( - TaggedConnectionId, - Connection, - ), - Error, -> { - let event = connection.build_conn_ack_and_send()?; - let connection_id = extract_connection_id(&event)?.clone(); - let connection2 = Connection::restore_from_event(handle_b.clone(), handle_a.clone(), &event)?; - - Ok((DualTagged::new(connection_id), connection2)) -} - -pub fn query_connection_end( - handle: &ChainA, - connection_id: &TaggedConnectionIdRef, -) -> Result, Error> { - let (connection_end, _) = handle.query_connection( - QueryConnectionRequest { - connection_id: connection_id.into_value().clone(), - height: QueryHeight::Latest, - }, - IncludeProof::No, - )?; - - Ok(DualTagged::new(connection_end)) -} - -pub fn query_identified_connection_end( - handle: &ChainA, - connection_id: TaggedConnectionIdRef, -) -> Result, Error> { - let (connection_end, _) = handle.query_connection( - QueryConnectionRequest { - connection_id: connection_id.into_value().clone(), - height: QueryHeight::Latest, - }, - IncludeProof::No, - )?; - Ok(DualTagged::new(IdentifiedConnectionEnd::new( - connection_id.into_value().clone(), - connection_end, - ))) -} - -pub fn assert_eventually_connection_established( - handle_a: &ChainA, - handle_b: &ChainB, - connection_id_a: &TaggedConnectionIdRef, -) -> Result, Error> { - assert_eventually_succeed( - "connection should eventually established", - 20, - Duration::from_secs(1), - || { - let connection_end_a = query_connection_end(handle_a, connection_id_a)?; - - if !connection_end_a - .value() - .state_matches(&ConnectionState::Open) - { - return Err(Error::generic(eyre!( - "expected connection end A to be in open state" - ))); - } - - let connection_id_b = connection_end_a - .tagged_counterparty_connection_id() - .ok_or_else(|| { - eyre!("expected counterparty connection id to present on open connection") - })?; - - let connection_end_b = query_connection_end(handle_b, &connection_id_b.as_ref())?; - - if !connection_end_b - .value() - .state_matches(&ConnectionState::Open) - { - return Err(Error::generic(eyre!( - "expected connection end B to be in open state" - ))); - } - - Ok(connection_id_b) - }, - ) -} diff --git a/tools/test-framework/src/relayer/driver.rs b/tools/test-framework/src/relayer/driver.rs deleted file mode 100644 index c0ebdefe1..000000000 --- a/tools/test-framework/src/relayer/driver.rs +++ /dev/null @@ -1,90 +0,0 @@ -/*! - Driver for spawning the relayer. -*/ - -use std::path::PathBuf; - -use ibc_relayer::chain::handle::CountingAndCachingChainHandle; -use ibc_relayer::config::Config; -use ibc_relayer::registry::SharedRegistry; -use ibc_relayer::supervisor::{spawn_supervisor, SupervisorHandle, SupervisorOptions}; - -use crate::error::Error; -use crate::types::env::{EnvWriter, ExportEnv}; -use crate::util::suspend::hang_on_error; - -/** - Encapsulates the parameters needed to spawn the relayer supervisor. - - In the future, other methods that correspond to the relayer CLI can - also be added here. -*/ -#[derive(Clone)] -pub struct RelayerDriver { - /** - The path to the relayer config saved on the filesystem. - - This allows users to test the relayer manually with the config file - while the test is suspended. - */ - pub config_path: PathBuf, - - /** - The relayer [`Config`]. Use this config when spawning new supervisor - using `spawn_supervisor`. - */ - pub config: Config, - - /** - The relayer chain [`Registry`](ibc_relayer::registry::Registry) - that is shared with any running supervisor. - - Use this shared registry when spawning new supervisor using - `spawn_supervisor`. - */ - pub registry: SharedRegistry, - - /** - Whether the driver should hang the test when the continuation - closure in [`with_supervisor`](Self::with_supervisor) fails. - */ - pub hang_on_fail: bool, -} - -impl RelayerDriver { - /** - Spawns the relayer supervisor and return the [`SupervisorHandle`]. - */ - pub fn spawn_supervisor(&self) -> Result { - spawn_supervisor( - self.config.clone(), - self.registry.clone(), - None, - SupervisorOptions { - health_check: false, - force_full_scan: false, - }, - ) - .map_err(Error::supervisor) - } - - /** - Spawns the relayer supervisor and then executes the provided continuation - with the supervisor running. - - The supervisor is stopped after the continuation returned. If - `hang_on_fail` is set to true, the call will suspend if the continuation - returns error. - */ - pub fn with_supervisor(&self, cont: impl FnOnce() -> Result) -> Result { - let _handle = self.spawn_supervisor()?; - - hang_on_error(self.hang_on_fail, cont) - } -} - -impl ExportEnv for RelayerDriver { - fn export_env(&self, writer: &mut impl EnvWriter) { - writer.write_env("RELAYER_CONFIG", &format!("{}", self.config_path.display())); - } -} diff --git a/tools/test-framework/src/relayer/fee.rs b/tools/test-framework/src/relayer/fee.rs deleted file mode 100644 index 3929725a2..000000000 --- a/tools/test-framework/src/relayer/fee.rs +++ /dev/null @@ -1,213 +0,0 @@ -use core::time::Duration; - -use http::uri::Uri; -use ibc_relayer::chain::cosmos::query::fee::{ - query_counterparty_payee as raw_query_counterparty_payee, - query_incentivized_packets as raw_query_incentivized_packets, -}; -use ibc_relayer::chain::cosmos::tx::simple_send_tx; -use ibc_relayer::chain::cosmos::types::config::TxConfig; -use ibc_relayer::event::IbcEventWithHeight; -use ibc_relayer_types::applications::ics29_fee::msgs::pay_packet::build_pay_packet_message; -use ibc_relayer_types::applications::ics29_fee::msgs::pay_packet_async::build_pay_packet_fee_async_message; -use ibc_relayer_types::applications::ics29_fee::msgs::register_payee::{ - build_register_counterparty_payee_message, build_register_payee_message, -}; -use ibc_relayer_types::applications::ics29_fee::packet_fee::IdentifiedPacketFees; -use ibc_relayer_types::core::ics04_channel::packet::Sequence; -use tendermint_rpc::HttpClient; - -use crate::error::{handle_generic_error, Error}; -use crate::ibc::token::{TaggedTokenExt, TaggedTokenRef}; -use crate::relayer::transfer::build_transfer_message; -use crate::types::id::{TaggedChannelIdRef, TaggedPortIdRef}; -use crate::types::tagged::{DualTagged, MonoTagged}; -use crate::types::wallet::{Wallet, WalletAddress}; - -pub async fn ibc_token_transfer_with_fee( - rpc_client: MonoTagged, - tx_config: &MonoTagged, - port_id: &TaggedPortIdRef<'_, SrcChain, DstChain>, - channel_id: &TaggedChannelIdRef<'_, SrcChain, DstChain>, - sender: &MonoTagged, - recipient: &MonoTagged, - send_amount: &TaggedTokenRef<'_, SrcChain>, - receive_fee: &TaggedTokenRef<'_, SrcChain>, - ack_fee: &TaggedTokenRef<'_, SrcChain>, - timeout_fee: &TaggedTokenRef<'_, SrcChain>, - timeout: Duration, -) -> Result, Error> { - let transfer_message = build_transfer_message( - port_id, - channel_id, - sender, - recipient, - send_amount, - timeout, - None, - )?; - - let pay_message = build_pay_packet_message( - port_id.value(), - channel_id.value(), - &sender - .value() - .address - .0 - .parse() - .map_err(handle_generic_error)?, - vec![receive_fee.as_coin()], - vec![ack_fee.as_coin()], - vec![timeout_fee.as_coin()], - ) - .map_err(handle_generic_error)?; - - let messages = vec![pay_message, transfer_message]; - - let events = simple_send_tx( - rpc_client.value(), - tx_config.value(), - &sender.value().key, - messages, - ) - .await?; - - Ok(events) -} - -pub async fn pay_packet_fee( - rpc_client: MonoTagged, - tx_config: &MonoTagged, - port_id: &TaggedPortIdRef<'_, Chain, Counterparty>, - channel_id: &TaggedChannelIdRef<'_, Chain, Counterparty>, - sequence: &DualTagged, - payer: &MonoTagged, - receive_fee: &TaggedTokenRef<'_, Chain>, - ack_fee: &TaggedTokenRef<'_, Chain>, - timeout_fee: &TaggedTokenRef<'_, Chain>, -) -> Result, Error> { - let message = build_pay_packet_fee_async_message( - port_id.value(), - channel_id.value(), - *sequence.value(), - &payer - .value() - .address - .0 - .parse() - .map_err(handle_generic_error)?, - vec![receive_fee.as_coin()], - vec![ack_fee.as_coin()], - vec![timeout_fee.as_coin()], - ) - .map_err(handle_generic_error)?; - - let events = simple_send_tx( - rpc_client.value(), - tx_config.value(), - &payer.value().key, - vec![message], - ) - .await - .map_err(Error::relayer)?; - - Ok(events) -} - -pub async fn register_counterparty_payee( - rpc_client: MonoTagged, - tx_config: &MonoTagged, - wallet: &MonoTagged, - counterparty_payee: &MonoTagged, - channel_id: &TaggedChannelIdRef<'_, Chain, Counterparty>, - port_id: &TaggedPortIdRef<'_, Chain, Counterparty>, -) -> Result<(), Error> { - let message = build_register_counterparty_payee_message( - &wallet - .value() - .address - .0 - .parse() - .map_err(handle_generic_error)?, - &counterparty_payee - .value() - .0 - .parse() - .map_err(handle_generic_error)?, - channel_id.value(), - port_id.value(), - ) - .map_err(handle_generic_error)?; - - let messages = vec![message]; - - simple_send_tx( - rpc_client.value(), - tx_config.value(), - &wallet.value().key, - messages, - ) - .await?; - - Ok(()) -} - -pub async fn register_payee( - rpc_client: MonoTagged, - tx_config: &MonoTagged, - wallet: &MonoTagged, - payee: &MonoTagged, - channel_id: &TaggedChannelIdRef<'_, Chain, Counterparty>, - port_id: &TaggedPortIdRef<'_, Chain, Counterparty>, -) -> Result<(), Error> { - let message = build_register_payee_message( - &wallet - .value() - .address - .0 - .parse() - .map_err(handle_generic_error)?, - &payee.value().0.parse().map_err(handle_generic_error)?, - channel_id.value(), - port_id.value(), - ) - .map_err(handle_generic_error)?; - - let messages = vec![message]; - - simple_send_tx( - rpc_client.value(), - tx_config.value(), - &wallet.value().key, - messages, - ) - .await?; - - Ok(()) -} - -pub async fn query_counterparty_payee( - grpc_address: &Uri, - channel_id: &TaggedChannelIdRef<'_, Chain, Counterparty>, - address: &MonoTagged, -) -> Result>, Error> { - let counterparty_payee = raw_query_counterparty_payee( - grpc_address, - channel_id.value(), - &address.value().0.parse().map_err(handle_generic_error)?, - ) - .await - .map_err(handle_generic_error)?; - - Ok(counterparty_payee.map(|address| MonoTagged::new(WalletAddress(address)))) -} - -pub async fn query_incentivized_packets( - grpc_address: &Uri, - channel_id: &TaggedChannelIdRef<'_, Chain, Counterparty>, - port_id: &TaggedPortIdRef<'_, Chain, Counterparty>, -) -> Result, Error> { - raw_query_incentivized_packets(grpc_address, channel_id.value(), port_id.value()) - .await - .map_err(handle_generic_error) -} diff --git a/tools/test-framework/src/relayer/foreign_client.rs b/tools/test-framework/src/relayer/foreign_client.rs deleted file mode 100644 index beb94641c..000000000 --- a/tools/test-framework/src/relayer/foreign_client.rs +++ /dev/null @@ -1,47 +0,0 @@ -/*! - Definition for extension trait methods for [`ForeignClient`] -*/ - -use ibc_relayer::chain::handle::ChainHandle; -use ibc_relayer::foreign_client::ForeignClient; - -use crate::types::id::{TaggedChainId, TaggedClientIdRef}; -use crate::types::tagged::*; - -/** - An extension trait for providing methods for getting tagged identifiers - out of a [`ForeignClient`]. -*/ -pub trait TaggedForeignClientExt { - /** - Get the source chain ID. - */ - fn tagged_src_chain_id(&self) -> TaggedChainId; - - /** - Get the destination chain ID. - */ - fn tagged_dst_chain_id(&self) -> TaggedChainId; - - /** - Get the client ID of the destination chain that corresponds - to the source chain. - */ - fn tagged_client_id(&self) -> TaggedClientIdRef; -} - -impl TaggedForeignClientExt - for ForeignClient -{ - fn tagged_src_chain_id(&self) -> TaggedChainId { - MonoTagged::new(self.src_chain().id()) - } - - fn tagged_dst_chain_id(&self) -> TaggedChainId { - MonoTagged::new(self.dst_chain().id()) - } - - fn tagged_client_id(&self) -> TaggedClientIdRef { - DualTagged::new(self.id()) - } -} diff --git a/tools/test-framework/src/relayer/mod.rs b/tools/test-framework/src/relayer/mod.rs deleted file mode 100644 index 0f90d7b1b..000000000 --- a/tools/test-framework/src/relayer/mod.rs +++ /dev/null @@ -1,29 +0,0 @@ -/*! - Code that may belong to the [`ibc_relayer`] module, but are currently - in this crate for easier review or maintenance. - - Sometimes new constructs are implemented just for testing, and it is - unclear whether the constructs have more general use that are worth - provided in the main library, so we put them here so that test authors - do not get blocked on writing tests. - - There may also be cases where the original code in the main library - are difficult to be used in a test setting, and we may want to temporarily - make a copy of the code and modify them in this crate to make it - easier to be used for testing. We would first do a forked modification - here so that there are less worry about the behavior of the original - code being changed due to subtle modifications. The changes can be - merged back to the main library at a later time once the tests have - sufficiently proven that the modified code preserve the semantics of - the original code. -*/ - -pub mod chain; -pub mod channel; -pub mod connection; -pub mod driver; -pub mod fee; -pub mod foreign_client; -pub mod refresh; -pub mod transfer; -pub mod tx; diff --git a/tools/test-framework/src/relayer/refresh.rs b/tools/test-framework/src/relayer/refresh.rs deleted file mode 100644 index 04f373548..000000000 --- a/tools/test-framework/src/relayer/refresh.rs +++ /dev/null @@ -1,19 +0,0 @@ -use eyre::eyre; -use ibc_relayer::chain::handle::ChainHandle; -use ibc_relayer::util::task::TaskHandle; -use ibc_relayer::worker::client::spawn_refresh_client; - -use crate::error::Error; -use crate::types::binary::foreign_client::ForeignClientPair; - -pub fn spawn_refresh_client_tasks( - foreign_clients: &ForeignClientPair, -) -> Result<[TaskHandle; 2], Error> { - let refresh_task_a = spawn_refresh_client(foreign_clients.client_b_to_a.clone()) - .ok_or_else(|| eyre!("expect refresh task spawned"))?; - - let refresh_task_b = spawn_refresh_client(foreign_clients.client_a_to_b.clone()) - .ok_or_else(|| eyre!("expect refresh task spawned"))?; - - Ok([refresh_task_a, refresh_task_b]) -} diff --git a/tools/test-framework/src/relayer/transfer.rs b/tools/test-framework/src/relayer/transfer.rs deleted file mode 100644 index b1f9f2cff..000000000 --- a/tools/test-framework/src/relayer/transfer.rs +++ /dev/null @@ -1,157 +0,0 @@ -/*! - Functions for performing IBC transfer that works similar to - `hermes tx ft-transfer`. -*/ - -use core::ops::Add; -use core::time::Duration; - -use eyre::eyre; -use ibc_proto::google::protobuf::Any; -use ibc_relayer::chain::cosmos::tx::{batched_send_tx, simple_send_tx}; -use ibc_relayer::chain::cosmos::types::config::TxConfig; -use ibc_relayer::transfer::{build_transfer_message as raw_build_transfer_message, TransferError}; -use ibc_relayer_types::applications::transfer::error::Error as Ics20Error; -use ibc_relayer_types::core::ics04_channel::packet::Packet; -use ibc_relayer_types::core::ics04_channel::timeout::TimeoutHeight; -use ibc_relayer_types::events::IbcEvent; -use ibc_relayer_types::timestamp::Timestamp; -use tendermint_rpc::HttpClient; - -use crate::error::{handle_generic_error, Error}; -use crate::ibc::token::TaggedTokenRef; -use crate::types::id::{TaggedChannelIdRef, TaggedPortIdRef}; -use crate::types::tagged::*; -use crate::types::wallet::{Wallet, WalletAddress}; - -pub fn build_transfer_message( - port_id: &TaggedPortIdRef<'_, SrcChain, DstChain>, - channel_id: &TaggedChannelIdRef<'_, SrcChain, DstChain>, - sender: &MonoTagged, - recipient: &MonoTagged, - token: &TaggedTokenRef<'_, SrcChain>, - timeout: Duration, - memo: Option, -) -> Result { - let timeout_timestamp = Timestamp::now() - .add(timeout) - .map_err(handle_generic_error)?; - - let sender = sender - .value() - .address - .0 - .parse() - .map_err(|e| TransferError::token_transfer(Ics20Error::signer(e)))?; - - let receiver = recipient - .value() - .0 - .parse() - .map_err(|e| TransferError::token_transfer(Ics20Error::signer(e)))?; - - Ok(raw_build_transfer_message( - (*port_id.value()).clone(), - (*channel_id.value()).clone(), - token.value().amount, - token.value().denom.to_string(), - sender, - receiver, - TimeoutHeight::no_timeout(), - timeout_timestamp, - memo, - )) -} - -/** - Perform a simplified version of IBC token transfer for testing purpose. - - It makes use of the local time to construct a 60 seconds IBC timeout - for testing. During test, all chains should have the same local clock. - We are also not really interested in setting a timeout for most tests, - so we just put an approximate 1 minute timeout as the timeout - field is compulsary, and we want to avoid IBC timeout on CI. - - The other reason we do not allow precise timeout to be specified is - because it requires accessing the counterparty chain to query for - the parameters. This will complicate the API which is unnecessary - in most cases. - - If tests require explicit timeout, they should explicitly construct the - transfer message and pass it to send_tx. -*/ -pub async fn ibc_token_transfer( - rpc_client: MonoTagged, - tx_config: &MonoTagged, - port_id: &TaggedPortIdRef<'_, SrcChain, DstChain>, - channel_id: &TaggedChannelIdRef<'_, SrcChain, DstChain>, - sender: &MonoTagged, - recipient: &MonoTagged, - token: &TaggedTokenRef<'_, SrcChain>, - memo: Option, - timeout: Option, -) -> Result { - let message = build_transfer_message( - port_id, - channel_id, - sender, - recipient, - token, - timeout.unwrap_or(Duration::from_secs(60)), - memo.clone(), - )?; - - let events = simple_send_tx( - rpc_client.into_value(), - tx_config.value(), - &sender.value().key, - vec![message], - ) - .await?; - - let packet = events - .into_iter() - .find_map(|event| match event.event { - IbcEvent::SendPacket(ev) => Some(ev.packet), - _ => None, - }) - .ok_or_else(|| eyre!("failed to find send packet event"))?; - - Ok(packet) -} - -pub async fn batched_ibc_token_transfer( - rpc_client: MonoTagged, - tx_config: &MonoTagged, - port_id: &TaggedPortIdRef<'_, SrcChain, DstChain>, - channel_id: &TaggedChannelIdRef<'_, SrcChain, DstChain>, - sender: &MonoTagged, - recipient: &MonoTagged, - token: &TaggedTokenRef<'_, SrcChain>, - num_msgs: usize, - memo: Option, -) -> Result<(), Error> { - let messages = std::iter::repeat_with(|| { - build_transfer_message( - port_id, - channel_id, - sender, - recipient, - token, - Duration::from_secs(60), - memo.clone(), - ) - }) - .take(num_msgs) - .collect::, _>>()?; - - batched_send_tx( - rpc_client.value(), - tx_config.value(), - &sender.value().key, - messages, - ) - .await?; - - Ok(()) -} diff --git a/tools/test-framework/src/relayer/tx.rs b/tools/test-framework/src/relayer/tx.rs deleted file mode 100644 index 4088171ee..000000000 --- a/tools/test-framework/src/relayer/tx.rs +++ /dev/null @@ -1,66 +0,0 @@ -use core::str::FromStr; -use core::time::Duration; - -use http::uri::Uri; -use ibc_proto::cosmos::tx::v1beta1::Fee; -use ibc_relayer::chain::cosmos::gas::calculate_fee; -use ibc_relayer::chain::cosmos::types::config::TxConfig; -use ibc_relayer::chain::cosmos::types::gas::GasConfig; -use ibc_relayer::config::{AddressType, GasPrice}; -use ibc_relayer_types::core::ics24_host::identifier::ChainId; -use tendermint_rpc::Url; - -use crate::error::{handle_generic_error, Error}; - -pub fn gas_config_for_test() -> GasConfig { - let max_gas = 3000000; - let gas_multiplier = 1.1; - let gas_price = GasPrice::new(0.003, "stake".to_string()); - - let default_gas = max_gas; - let fee_granter = "".to_string(); - - let max_fee = Fee { - amount: vec![calculate_fee(max_gas, &gas_price)], - gas_limit: max_gas, - payer: "".to_string(), - granter: fee_granter.clone(), - }; - - GasConfig { - default_gas, - max_gas, - gas_multiplier, - gas_price, - max_fee, - fee_granter, - dynamic_gas_price: Default::default(), - } -} - -pub fn new_tx_config_for_test( - chain_id: ChainId, - raw_rpc_address: String, - raw_grpc_address: String, - address_type: AddressType, -) -> 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 rpc_timeout = Duration::from_secs(30); - let max_msg_num = Default::default(); - let max_tx_size = Default::default(); - let extension_options = Default::default(); - - Ok(TxConfig { - chain_id, - gas_config, - rpc_address, - grpc_address, - rpc_timeout, - address_type, - max_msg_num, - max_tx_size, - extension_options, - }) -} diff --git a/tools/test-framework/src/types/binary/chains.rs b/tools/test-framework/src/types/binary/chains.rs deleted file mode 100644 index 1f0057760..000000000 --- a/tools/test-framework/src/types/binary/chains.rs +++ /dev/null @@ -1,175 +0,0 @@ -/*! - Type definition for two connected chains. -*/ - -use ibc_relayer::chain::handle::ChainHandle; -use tracing::info; - -use super::foreign_client::ForeignClientPair; -use crate::types::env::{prefix_writer, EnvWriter, ExportEnv}; -use crate::types::id::{TaggedChainIdRef, TaggedClientIdRef}; -use crate::types::single::node::{FullNode, TaggedFullNodeExt}; -use crate::types::tagged::*; - -/** - Two connected chains including the full node, chain handles, and - the corresponding foreign clients. -*/ -#[derive(Clone)] -pub struct ConnectedChains { - /** - The [`ChainHandle`] for chain A. - - The handle is wrapped in [`DropChainHandle`] to stop the chain - handle when this is dropped. - */ - pub handle_a: ChainA, - - /** - The [`ChainHandle`] for chain B. - - The handle is wrapped in [`DropChainHandle`] to stop the chain - handle when this is dropped. - */ - pub handle_b: ChainB, - - /** - The tagged [`FullNode`] for chain A. - */ - pub node_a: MonoTagged, - - /** - The tagged [`FullNode`] for chain B. - */ - pub node_b: MonoTagged, - - pub foreign_clients: ForeignClientPair, -} - -impl ConnectedChains { - /** - Create a new [`ConnectedChains`] - */ - pub fn new( - handle_a: ChainA, - handle_b: ChainB, - node_a: MonoTagged, - node_b: MonoTagged, - foreign_clients: ForeignClientPair, - ) -> Self { - Self { - handle_a, - handle_b, - node_a, - node_b, - foreign_clients, - } - } - - /** - Get a reference to the chain handle for chain A. - */ - pub fn handle_a(&self) -> &ChainA { - &self.handle_a - } - - /** - Get a reference to the chain handle for chain B. - */ - pub fn handle_b(&self) -> &ChainB { - &self.handle_b - } - - /** - The chain ID of chain A. - */ - pub fn chain_id_a(&self) -> TaggedChainIdRef { - self.node_a.chain_id() - } - - pub fn client_id_a(&self) -> TaggedClientIdRef { - self.foreign_clients.client_id_a() - } - - pub fn client_id_b(&self) -> TaggedClientIdRef { - self.foreign_clients.client_id_b() - } - - /** - The chain ID of chain B. - */ - pub fn chain_id_b(&self) -> TaggedChainIdRef { - self.node_b.chain_id() - } - - /** - Switch the position between chain A and chain B. - - The original chain B become the new chain A, and the original chain A - become the new chain B. - */ - pub fn flip(self) -> ConnectedChains { - ConnectedChains { - handle_a: self.handle_b, - handle_b: self.handle_a, - node_a: self.node_b, - node_b: self.node_a, - foreign_clients: self.foreign_clients.flip(), - } - } - - pub fn map_chain( - self, - map_a: &impl Fn(ChainA) -> ChainC, - map_b: &impl Fn(ChainB) -> ChainD, - ) -> ConnectedChains { - ConnectedChains { - handle_a: map_a(self.handle_a), - handle_b: map_b(self.handle_b), - node_a: self.node_a.retag(), - node_b: self.node_b.retag(), - foreign_clients: self.foreign_clients.map_chain(map_a, map_b), - } - } -} - -impl ExportEnv for ConnectedChains { - fn export_env(&self, writer: &mut impl EnvWriter) { - writer.write_env("CHAIN_ID_A", &format!("{}", self.node_a.chain_id())); - writer.write_env("CHAIN_ID_B", &format!("{}", self.node_b.chain_id())); - - writer.write_env( - "CLIENT_ID_B", - &format!("{}", self.foreign_clients.client_a_to_b.id()), - ); - writer.write_env( - "CLIENT_ID_A", - &format!("{}", self.foreign_clients.client_b_to_a.id()), - ); - - self.node_a.export_env(&mut prefix_writer("NODE_A", writer)); - self.node_b.export_env(&mut prefix_writer("NODE_B", writer)); - } -} - -/** - Newtype wrapper for [`ChainHandle`] to stop the chain handle when - this value is dropped. - - Note that we cannot stop the chain on drop for - [`CountingAndCachingChainHandle`](ibc_relayer::chain::handle::CountingAndCachingChainHandle) - itself, as the chain handles can be cloned. But for testing purposes, - we alway stop the chain handle when this "canonical" chain handle - is dropped. - - This is necessary as otherwise the chain handle will display error - logs when the full node is terminated at the end of tests. -*/ -pub struct DropChainHandle(pub Chain); - -impl Drop for DropChainHandle { - fn drop(&mut self) { - info!("stopping chain handle {}", self.0.id()); - let _ = self.0.shutdown(); - } -} diff --git a/tools/test-framework/src/types/binary/channel.rs b/tools/test-framework/src/types/binary/channel.rs deleted file mode 100644 index 99f5bb2e8..000000000 --- a/tools/test-framework/src/types/binary/channel.rs +++ /dev/null @@ -1,98 +0,0 @@ -/*! - Type definitions for channel connected between two chains. -*/ - -use ibc_relayer::chain::handle::ChainHandle; -use ibc_relayer::channel::Channel; - -use super::connection::ConnectedConnection; -use crate::types::env::{EnvWriter, ExportEnv}; -use crate::types::id::{TaggedChannelId, TaggedPortId}; - -/** - A channel that is connected between two chains with the full handshake - completed. - - This is a wrapper around [`Channel`] with infallible retrieval - of the channel IDs, as the channel handshake has been completed. -*/ -#[derive(Debug, Clone)] -pub struct ConnectedChannel { - /** - The underlying [`ConnectedConnection`] that the channel operates on. - */ - pub connection: ConnectedConnection, - - /** - The underlying relayer [`Channel`]. - */ - pub channel: Channel, - - /** - The channel ID on chain A, corresponding to the channel connected - to chain B. - */ - pub channel_id_a: TaggedChannelId, - - /** - The channel ID on chain B, corresponding to the channel connected - to chain A. - */ - pub channel_id_b: TaggedChannelId, - - /** - The port ID on chain A, corresponding to the channel connected - to chain B. - */ - pub port_a: TaggedPortId, - - /** - The port ID on chain B, corresponding to the channel connected - to chain A. - */ - pub port_b: TaggedPortId, -} - -impl ConnectedChannel { - /** - Flip the position between chain A and chain B. - - The original chain A become the new chain B, and the original chain B - become the new chain A. - */ - pub fn flip(self) -> ConnectedChannel { - ConnectedChannel { - connection: self.connection.flip(), - channel: self.channel.flipped(), - channel_id_a: self.channel_id_b, - channel_id_b: self.channel_id_a, - port_a: self.port_b, - port_b: self.port_a, - } - } - - pub fn map_chain( - self, - map_a: impl Fn(ChainA) -> ChainC, - map_b: impl Fn(ChainB) -> ChainD, - ) -> ConnectedChannel { - ConnectedChannel { - connection: self.connection.map_chain(&map_a, &map_b), - channel: self.channel.map_chain(&map_a, &map_b), - channel_id_a: self.channel_id_a.retag(), - channel_id_b: self.channel_id_b.retag(), - port_a: self.port_a.retag(), - port_b: self.port_b.retag(), - } - } -} - -impl ExportEnv for ConnectedChannel { - fn export_env(&self, writer: &mut impl EnvWriter) { - self.connection.export_env(writer); - writer.write_env("CHANNEL_ID_A", &format!("{}", self.channel_id_a)); - writer.write_env("PORT_A", &format!("{}", self.port_a)); - writer.write_env("CHANNEL_ID_B", &format!("{}", self.channel_id_b)); - writer.write_env("PORT_B", &format!("{}", self.port_b)); - } -} diff --git a/tools/test-framework/src/types/binary/client.rs b/tools/test-framework/src/types/binary/client.rs deleted file mode 100644 index 87d503243..000000000 --- a/tools/test-framework/src/types/binary/client.rs +++ /dev/null @@ -1,51 +0,0 @@ -/*! - Type definitions for IBC clients connected between two chains. -*/ - -use crate::types::env::{EnvWriter, ExportEnv}; -use crate::types::id::TaggedClientId; - -/** - Data type to store the client IDs of two chains that are connected. -*/ -#[derive(Debug, Clone)] -pub struct ClientIdPair { - /** - The client ID on chain A. - */ - pub client_id_a: TaggedClientId, - - /** - The client ID on chain B. - */ - pub client_id_b: TaggedClientId, -} - -impl ClientIdPair { - pub fn new( - client_id_a: TaggedClientId, - client_id_b: TaggedClientId, - ) -> Self { - Self { - client_id_a, - client_id_b, - } - } - - /** - Flip the position of chain A and B of the client. - */ - pub fn flip(self) -> ClientIdPair { - ClientIdPair { - client_id_a: self.client_id_b, - client_id_b: self.client_id_a, - } - } -} - -impl ExportEnv for ClientIdPair { - fn export_env(&self, writer: &mut impl EnvWriter) { - writer.write_env("CLIENT_ID_A", &format!("{}", self.client_id_a)); - writer.write_env("CLIENT_ID_B", &format!("{}", self.client_id_b)); - } -} diff --git a/tools/test-framework/src/types/binary/connection.rs b/tools/test-framework/src/types/binary/connection.rs deleted file mode 100644 index 34455c3e8..000000000 --- a/tools/test-framework/src/types/binary/connection.rs +++ /dev/null @@ -1,95 +0,0 @@ -/*! - Type definitions for connection that is connected between two chains. -*/ - -use ibc_relayer::chain::handle::ChainHandle; -use ibc_relayer::connection::Connection; - -use super::client::ClientIdPair; -use crate::types::env::{EnvWriter, ExportEnv}; -use crate::types::id::TaggedConnectionId; - -/** - A connection that is connected between two chains with the full - handshake completed. - - This is a wrapper around [`Connection`] with infallible retrieval - of the connection IDs, as the connection handshake has been completed. -*/ -#[derive(Debug, Clone)] -pub struct ConnectedConnection { - /** - The underlying connected clients - */ - pub client_ids: ClientIdPair, - - /** - The underlying [`Connection`] data - */ - pub connection: Connection, - - /** - The connection ID on chain A. - */ - pub connection_id_a: TaggedConnectionId, - - /** - The connection ID on chain B. - */ - pub connection_id_b: TaggedConnectionId, -} - -impl ConnectedConnection { - pub fn new( - client_ids: ClientIdPair, - connection: Connection, - connection_id_a: TaggedConnectionId, - connection_id_b: TaggedConnectionId, - ) -> Self { - Self { - client_ids, - connection, - connection_id_a, - connection_id_b, - } - } - - /** - Flip the position of chain A and B of the connection. - */ - pub fn flip(self) -> ConnectedConnection { - ConnectedConnection { - client_ids: self.client_ids.flip(), - - connection: self.connection.flipped(), - - connection_id_a: self.connection_id_b, - - connection_id_b: self.connection_id_a, - } - } - - pub fn map_chain( - self, - map_a: impl Fn(ChainA) -> ChainC, - map_b: impl Fn(ChainB) -> ChainD, - ) -> ConnectedConnection { - ConnectedConnection::new( - ClientIdPair::new( - self.client_ids.client_id_a.retag(), - self.client_ids.client_id_b.retag(), - ), - self.connection.map_chain(map_a, map_b), - self.connection_id_a.retag(), - self.connection_id_b.retag(), - ) - } -} - -impl ExportEnv for ConnectedConnection { - fn export_env(&self, writer: &mut impl EnvWriter) { - self.client_ids.export_env(writer); - writer.write_env("CONNECTION_ID_A", &format!("{}", self.connection_id_a)); - writer.write_env("CONNECTION_ID_B", &format!("{}", self.connection_id_b)); - } -} diff --git a/tools/test-framework/src/types/binary/foreign_client.rs b/tools/test-framework/src/types/binary/foreign_client.rs deleted file mode 100644 index 32f5c2b9e..000000000 --- a/tools/test-framework/src/types/binary/foreign_client.rs +++ /dev/null @@ -1,63 +0,0 @@ -use ibc_relayer::chain::handle::ChainHandle; -use ibc_relayer::foreign_client::ForeignClient; - -use crate::relayer::foreign_client::TaggedForeignClientExt; -use crate::types::id::TaggedClientIdRef; - -#[derive(Clone)] -pub struct ForeignClientPair { - pub client_a_to_b: ForeignClient, - pub client_b_to_a: ForeignClient, -} - -impl ForeignClientPair { - pub fn new( - client_a_to_b: ForeignClient, - client_b_to_a: ForeignClient, - ) -> Self { - Self { - client_a_to_b, - client_b_to_a, - } - } - - pub fn client_id_a(&self) -> TaggedClientIdRef { - self.client_b_to_a.tagged_client_id() - } - - pub fn client_id_b(&self) -> TaggedClientIdRef { - self.client_a_to_b.tagged_client_id() - } - - pub fn handle_a(&self) -> ChainA { - self.client_b_to_a.dst_chain() - } - - pub fn handle_b(&self) -> ChainB { - self.client_a_to_b.dst_chain() - } - - /** - Switch the position between chain A and chain B. - - The original chain B become the new chain A, and the original chain A - become the new chain B. - */ - pub fn flip(self) -> ForeignClientPair { - ForeignClientPair { - client_a_to_b: self.client_b_to_a, - client_b_to_a: self.client_a_to_b, - } - } - - pub fn map_chain( - self, - map_a: &impl Fn(ChainA) -> ChainC, - map_b: &impl Fn(ChainB) -> ChainD, - ) -> ForeignClientPair { - ForeignClientPair { - client_a_to_b: self.client_a_to_b.map_chain(map_b, map_a), - client_b_to_a: self.client_b_to_a.map_chain(map_a, map_b), - } - } -} diff --git a/tools/test-framework/src/types/binary/mod.rs b/tools/test-framework/src/types/binary/mod.rs deleted file mode 100644 index 24fc47b30..000000000 --- a/tools/test-framework/src/types/binary/mod.rs +++ /dev/null @@ -1,9 +0,0 @@ -/*! - Definitions for data structures involving two chains. -*/ - -pub mod chains; -pub mod channel; -pub mod client; -pub mod connection; -pub mod foreign_client; diff --git a/tools/test-framework/src/types/config.rs b/tools/test-framework/src/types/config.rs deleted file mode 100644 index 1cbfb95ff..000000000 --- a/tools/test-framework/src/types/config.rs +++ /dev/null @@ -1,61 +0,0 @@ -/*! - Definition for the test configuration. -*/ - -use core::fmt::Debug; -use std::path::PathBuf; - -/** - The test config to be passed to each test case. Currently this is loaded - from the [`init_test`](crate::bootstrap::init::init_test) function - based on the test environment variables. -*/ -#[derive(Clone, Debug)] -pub struct TestConfig { - /** - The command that the [`ChainDriver`](crate::chain::driver::ChainDriver) - should use to execute chain commands. Defaults to `gaiad`. This can be - overridden with the `$CHAIN_COMMAND_PATH` environment variable. - - TODO: We might want to add a new field - `extra_chain_command_paths: Vec` - for additional chain command paths that the `ChainDriver` can use for different - implementations of chains to be spawned. - - For example one can list `"gaiad4"` as the main chain command and then - `["gaiad5"]` in `extra_chain_command_paths`, so that binary chain tests - will use `gaiad5` for the second chain being spawned. - */ - pub chain_command_paths: Vec, - - pub account_prefixes: Vec, - - /** - The directory path for storing the chain and relayer files. - Defaults to `"data"`. This can be overridden with the `$CHAIN_STORE_DIR` - environment variable. - - Note that this will resolve to `"relayer-test/data"` relative to the - root project directory, as `cargo test` will automatically csuspende the - working directory to the sub crate's directory. - */ - pub chain_store_dir: PathBuf, - - /** - Whether to suspend a test case when it fails whenever possible. - Defaults to `false`. This can be overrideen by setting `HANG_ON_FAIL=1`. - - Note that even when this is enabled, not all test case will necessary - suspend on failure. The suspend-on-failure hook is handled by individual - test runners such as - [`RunBinaryChainTest`](crate::framework::binary::chain::RunBinaryChainTest), - which will suspend the test case only if the test has been setup - successfully and only for the case when the runner holds the required - reference for the underlying resources. Because otherwise there is - no point suspending the test if the underlying chains or relayers are - no longer running. - */ - pub hang_on_fail: bool, - - pub bootstrap_with_random_ids: bool, -} diff --git a/tools/test-framework/src/types/env.rs b/tools/test-framework/src/types/env.rs deleted file mode 100644 index e43108580..000000000 --- a/tools/test-framework/src/types/env.rs +++ /dev/null @@ -1,119 +0,0 @@ -/*! - Types for exporting test setup information into environment variables. -*/ - -use core::convert::AsRef; -use std::collections::BTreeMap; -use std::fs::write; -use std::path::Path; - -use itertools::Itertools; - -use crate::error::Error; -use crate::types::tagged::*; - -/** - This trait is implemented by data types that can export the contained - information as environment variables. - - Using this, test framework can export them as `.env` files, which users - can then manually `source` them in the terminal to interact with the - test chains and relayer when the tests are suspended. -*/ -pub trait ExportEnv { - /** - Export the environment variables using the given [`EnvWriter`]. - */ - fn export_env(&self, writer: &mut impl EnvWriter); -} - -/** - The exported environment variables are stored in a data type that - implements this trait. -*/ -pub trait EnvWriter { - /** - Write an environment variable with the given key and value. - - Note that overlapping keys will be overridden with the new value. - */ - fn write_env(&mut self, key: &str, value: &str); -} - -/** - Create an [`EnvWriter`] that adds a prefix to the keys of the exported envs. -*/ -pub fn prefix_writer<'a, Writer: EnvWriter>( - prefix: &str, - writer: &'a mut Writer, -) -> impl EnvWriter + 'a { - PrefixEnvWriter { - prefix: prefix.to_string(), - writer, - } -} - -/** - A wrapper that implements [`EnvWriter`] by adding a prefix to the key - before writing to the underlying [`EnvWriter`]. -*/ -pub struct PrefixEnvWriter<'a, Writer> { - prefix: String, - writer: &'a mut Writer, -} - -impl EnvWriter for BTreeMap { - fn write_env(&mut self, key: &str, value: &str) { - self.insert(key.to_string(), value.to_string()); - } -} - -impl EnvWriter for PrefixEnvWriter<'_, Writer> { - fn write_env(&mut self, key: &str, value: &str) { - self.writer - .write_env(&format!("{}_{}", self.prefix, key), value); - } -} - -impl ExportEnv for MonoTagged { - fn export_env(&self, writer: &mut impl EnvWriter) { - self.value().export_env(writer); - } -} - -impl ExportEnv for DualTagged { - fn export_env(&self, writer: &mut impl EnvWriter) { - self.value().export_env(writer); - } -} - -impl<'a, T1: ExportEnv, T2: ExportEnv> ExportEnv for (&'a T1, &'a T2) { - fn export_env(&self, writer: &mut impl EnvWriter) { - self.0.export_env(writer); - self.1.export_env(writer); - } -} - -/** - Retrieve the environment variables exported by a type implementing - `ExportEnv`, and export them as a string containing the variables - in the form of `KEY=VALUE` on each line. -*/ -pub fn format_env(exporter: &impl ExportEnv) -> String { - let mut envs = BTreeMap::new(); - exporter.export_env(&mut envs); - - envs.iter() - .map(|(key, value)| format!("{key}={value}")) - .join("\n") -} - -/** - Retrieve the environment variables exported by a type implementing - `ExportEnv`, and save them as a `.env` file to the given file path. -*/ -pub fn write_env(path: impl AsRef, exporter: &impl ExportEnv) -> Result<(), Error> { - write(path, format_env(exporter))?; - - Ok(()) -} diff --git a/tools/test-framework/src/types/id.rs b/tools/test-framework/src/types/id.rs deleted file mode 100644 index 9269ff837..000000000 --- a/tools/test-framework/src/types/id.rs +++ /dev/null @@ -1,77 +0,0 @@ -/*! - This module contains the [tagged version](crate::types::tagged) of the - identifier types defined in [`ibc_relayer_types::core::ics24_host::identifier`]. -*/ - -use ibc_relayer_types::core::ics24_host::identifier::*; - -use crate::types::tagged::*; - -/** - A [`ChainId`] tagged with the chain it belongs to. -*/ -pub type TaggedChainId = MonoTagged; - -/** - A reference to [`ChainId`] tagged with the chain it - belongs to. -*/ -pub type TaggedChainIdRef<'a, Chain> = MonoTagged; - -/** - A [`ClientId`] tagged with first, the chain it belongs to, and second, - the counterparty chain that the client ID corresponds to. -*/ -pub type TaggedClientId = DualTagged; - -/** - A reference to [`ClientId`] tagged with first, the chain it belongs to, - and second, the counterparty chain that the client ID corresponds to. -*/ -pub type TaggedClientIdRef<'a, ChainA, ChainB> = DualTagged; - -/** - A [`PortId`] tagged with first, the host chain that has - the port ID, and second, the counterparty chain that the port ID - corresponds to. -*/ -pub type TaggedPortId = DualTagged; - -/** - A reference to `PortId` tagged with first, the host chain - that has the port ID, and second, the counterparty chain that the port ID - corresponds to. -*/ -pub type TaggedPortIdRef<'a, ChainA, ChainB> = DualTagged; - -/** - A [`ChannelId`] tagged with first, the host chain that - has the channel ID, and second, the counterparty chain that the channel - ID corresponds to. -*/ -pub type TaggedChannelId = DualTagged; - -/** - A reference to [`ChannelId`] tagged with first, the host - chain that has the channel ID, and second, the counterparty chain that the - channel ID corresponds to. -*/ -pub type TaggedChannelIdRef<'a, ChainA, ChainB> = DualTagged; - -/** - A [`ConnectionId`] tagged with first, the host chain - that has the connection ID, and second, the counterparty chain that the - connection ID corresponds to. -*/ -pub type TaggedConnectionId = DualTagged; - -/** - A reference to [`ConnectionId`] tagged with first, - the host chain that has the connection ID, and second, the counterparty - chain that the connection ID corresponds to. -*/ -pub type TaggedConnectionIdRef<'a, ChainA, ChainB> = DualTagged; - -pub fn tagged_transfer_port() -> TaggedPortId { - DualTagged::new(PortId::transfer()) -} diff --git a/tools/test-framework/src/types/mod.rs b/tools/test-framework/src/types/mod.rs deleted file mode 100644 index a1c1db153..000000000 --- a/tools/test-framework/src/types/mod.rs +++ /dev/null @@ -1,19 +0,0 @@ -/*! - This module contains definitions of core data structures that are used - in the test suite. - - A data type belongs to this module if it only comes with the struct - definition with few methods associated to that struct. If a data - type has many complicated methods or trait implementations, it - probably does not belong to here. -*/ - -pub mod binary; -pub mod config; -pub mod env; -pub mod id; -pub mod nary; -pub mod process; -pub mod single; -pub mod tagged; -pub mod wallet; diff --git a/tools/test-framework/src/types/nary/aliases.rs b/tools/test-framework/src/types/nary/aliases.rs deleted file mode 100644 index 514ae8c95..000000000 --- a/tools/test-framework/src/types/nary/aliases.rs +++ /dev/null @@ -1,34 +0,0 @@ -use crate::types::tagged::*; - -/** - Lifts a const generic `usize` into a type. - - This allows us to use `usize` as a tag, for example, - `MonoTagged, String>` is a `String` that is - tagged by the const generic `1`. -*/ -pub enum Size {} - -/** - Tag a `Handle: ChainHandle` type with a const generic `TAG: usize`. - - In an N-ary chain implementation, we have to use the same - [`Handle: ChainHandle`](ibc_relayer::chain::handle::ChainHandle) - type for all elements in the N-ary data structures. However since the - [`ChainHandle`](ibc_relayer::chain::handle::ChainHandle) type is - also being used to tag other values, we want to be able to differentiate - between tagged values coming from chains at different positions - in the N-ary setup. - - The solution is to tag each `Handle` with the const generic - positions. With that a position-tagged type like - `MonoTagged, Handle>` would have a different type - from the type tagged at a different position like - `MonoTagged, Handle>`. - - To reduce the boilerplate, we define the type alias - `TaggedHandle` so that less typing is needed to refer - to `ChainHandle`s that are tagged by position. - -*/ -pub type NthChainHandle = MonoTagged, Handle>; diff --git a/tools/test-framework/src/types/nary/chains.rs b/tools/test-framework/src/types/nary/chains.rs deleted file mode 100644 index c4218a82d..000000000 --- a/tools/test-framework/src/types/nary/chains.rs +++ /dev/null @@ -1,256 +0,0 @@ -/*! - Constructs for N-ary connected chains. -*/ - -use core::convert::{From, TryFrom}; - -use eyre::eyre; -use ibc_relayer::chain::handle::ChainHandle; -use ibc_relayer::foreign_client::ForeignClient; - -use crate::error::Error; -use crate::types::binary::chains::ConnectedChains as BinaryConnectedChains; -use crate::types::env::{prefix_writer, EnvWriter, ExportEnv}; -use crate::types::nary::aliases::*; -use crate::types::nary::foreign_client::*; -use crate::types::single::node::FullNode; -use crate::types::tagged::*; -use crate::util::array::try_into_array; - -/** - A fixed-size N-ary connected chains as specified by `SIZE`. - - Contains `SIZE` number of [`ChainHandle`]s, `SIZE` number of - [`FullNode`]s, and `SIZE`x`SIZE` numbers of [`ForeignClient`] pairs. - - A `ConnectedChains` can be constructed by first constructing - a [`DynamicConnectedChains`], and then calling - [`try_into()`](core::convert::TryInto::try_into). -*/ -#[derive(Clone)] -pub struct NaryConnectedChains { - chain_handles: [Handle; SIZE], - full_nodes: [FullNode; SIZE], - foreign_clients: ForeignClientPairs, -} - -/** - A dynamic-sized N-ary connected chains, based on the - length of the underlying [`Vec`]. Each list must have the - same length. - - The main use of [`DynamicConnectedChains`] is to convert it into - a [`NaryConnectedChains`]. -*/ -#[derive(Clone)] -pub struct DynamicConnectedChains { - chain_handles: Vec, - full_nodes: Vec, - pub foreign_clients: Vec>>, -} - -/** - A pair of binary [`ConnectedChains`](BinaryConnectedChains) that are - tagged by a `Handle: CHainHandle` and the const generics - `CHAIN_A: usize` and `CHAIN_B: usize`. - - Recall that binary [`ConnectedChains`](BinaryConnectedChains) is tagged - by two generic types `ChainA: ChainHandle` and `ChainB: ChainHandle`. - For the case of N-ary chains, all elements must have the same type - `Handle: ChainHandle`. But we want to still able to differentiate - them when used as type parameter to `ConnectedChains`. - - The solution is to tag each `Handle` with the const generic - positions. So the first chain is `MonoTagged, Handle>`, - which has a different type from the second chain - `MonoTagged, Handle>`. - - Since writing the fully qualified chain types are rather cumbersome, - we use the type alias `TaggedConnectedChains` to refer to - connected chains that are parameterized by const generics rather - than the usual abstract type tags. -*/ -pub type NthConnectedChains = - BinaryConnectedChains, NthChainHandle>; - -/** - A [`FullNode`] that is tagged by a `Handle: ChainHandle` and - the const generics `TAG: usize`. -*/ -pub type NthFullNode = MonoTagged, FullNode>; - -impl NaryConnectedChains { - /** - Get a connected chain pair at position `CHAIN_A` and `CHAIN_B`, which - must be less than `SIZE`. - - Returns a binary [`ConnectedChains`](BinaryConnectedChains) with the - first chain tagged by `CHAIN_A`, and second chain tagged by `CHAIN_B`. - */ - pub fn connected_chains_at( - &self, - ) -> Result, Error> { - if CHAIN_A >= SIZE || CHAIN_B >= SIZE { - Err(Error::generic(eyre!( - "cannot get chains beyond position {}/{}", - CHAIN_A, - CHAIN_B - ))) - } else { - let node_a = self.full_nodes[CHAIN_A].clone(); - let node_b = self.full_nodes[CHAIN_B].clone(); - - let handle_a = self.chain_handles[CHAIN_A].clone(); - let handle_b = self.chain_handles[CHAIN_B].clone(); - - let foreign_clients = self.foreign_client_pair_at::()?; - - Ok(BinaryConnectedChains::new( - MonoTagged::new(handle_a), - MonoTagged::new(handle_b), - MonoTagged::new(node_a), - MonoTagged::new(node_b), - foreign_clients, - )) - } - } - - /** - Get the [`FullNode`] at position `POS`, which must be less than `SIZE`. - - Returns a [`FullNode`] tagged with `POS`. - */ - pub fn full_node_at(&self) -> Result, Error> { - if POS >= SIZE { - Err(Error::generic(eyre!( - "cannot get full_node beyond position {}", - POS - ))) - } else { - let full_node: FullNode = self.full_nodes[POS].clone(); - Ok(MonoTagged::new(full_node)) - } - } - - /** - Get the [`ChainHandle`] at position `POS`, which must be less than `SIZE`. - - Returns a [`ChainHandle`] tagged by `POS`. - */ - pub fn chain_handle_at(&self) -> Result, Error> { - if POS >= SIZE { - Err(Error::generic(eyre!( - "cannot get full_node beyond position {}", - POS - ))) - } else { - let handle = self.chain_handles[POS].clone(); - Ok(MonoTagged::new(handle)) - } - } - - /** - Get the [`ForeignClient`] with the source chain at position - `SRC: usize` and destination chain at position `DEST: usize`, - which must be less than `SIZE`. - */ - pub fn foreign_client_at( - &self, - ) -> Result, Error> { - self.foreign_clients.foreign_client_at::() - } - - pub fn foreign_client_pair_at( - &self, - ) -> Result, Error> { - self.foreign_clients - .foreign_client_pair_at::() - } - - pub fn chain_handles(&self) -> &[Handle; SIZE] { - &self.chain_handles - } - - pub fn full_nodes(&self) -> &[FullNode; SIZE] { - &self.full_nodes - } - - pub fn foreign_clients(&self) -> &ForeignClientPairs { - &self.foreign_clients - } -} - -impl DynamicConnectedChains { - pub fn new( - chain_handles: Vec, - full_nodes: Vec, - foreign_clients: Vec>>, - ) -> Self { - Self { - chain_handles, - full_nodes, - foreign_clients, - } - } - - pub fn chain_handles(&self) -> &Vec { - &self.chain_handles - } - - pub fn full_nodes(&self) -> &Vec { - &self.full_nodes - } - - pub fn foreign_clients(&self) -> &Vec>> { - &self.foreign_clients - } -} - -impl From> - for DynamicConnectedChains -{ - fn from(chains: NaryConnectedChains) -> Self { - Self { - chain_handles: chains.chain_handles.into(), - full_nodes: chains.full_nodes.into(), - foreign_clients: chains.foreign_clients.into_nested_vec(), - } - } -} - -impl TryFrom> - for NaryConnectedChains -{ - type Error = Error; - - fn try_from(chains: DynamicConnectedChains) -> Result { - Ok(NaryConnectedChains { - chain_handles: try_into_array(chains.chain_handles)?, - full_nodes: try_into_array(chains.full_nodes)?, - foreign_clients: chains.foreign_clients.try_into()?, - }) - } -} - -impl From> - for NthConnectedChains<0, 1, Handle> -{ - fn from(chains: NaryConnectedChains) -> Self { - chains.connected_chains_at::<0, 1>().unwrap() - } -} - -impl ExportEnv for NaryConnectedChains { - fn export_env(&self, writer: &mut impl EnvWriter) { - for (i, node) in self.full_nodes.iter().enumerate() { - writer.write_env( - &format!("CHAIN_ID_{i}"), - &format!("{}", node.chain_driver.chain_id), - ); - - self.foreign_clients.export_env(writer); - - node.export_env(&mut prefix_writer(&format!("NODE_{i}"), writer)); - } - } -} diff --git a/tools/test-framework/src/types/nary/channel.rs b/tools/test-framework/src/types/nary/channel.rs deleted file mode 100644 index e2ced738b..000000000 --- a/tools/test-framework/src/types/nary/channel.rs +++ /dev/null @@ -1,159 +0,0 @@ -/*! - Constructs for N-ary connected channels. -*/ - -use core::convert::TryFrom; - -use eyre::eyre; -use ibc_relayer::chain::handle::ChainHandle; -use ibc_relayer::channel::Channel; -use ibc_relayer_types::core::ics24_host::identifier::{ChannelId, PortId}; - -use super::aliases::NthChainHandle; -use crate::error::Error; -use crate::types::binary::channel::ConnectedChannel; -use crate::types::env::{EnvWriter, ExportEnv}; -use crate::types::tagged::*; -use crate::util::array::try_into_nested_array; - -/** - A fixed-size N-ary connected channels as specified by `SIZE`. - - Contains `SIZE`x`SIZE` number of binary [`ConnectedChannel`]s. -*/ -#[derive(Debug, Clone)] -pub struct ConnectedChannels { - channels: [[ConnectedChannel; SIZE]; SIZE], -} - -/** - A dynamic-sized N-ary connected channels, consist of a nested - vector of binary [`ConnectedChannel`]s which must be of the - same length. -*/ -#[derive(Debug, Clone)] -pub struct DynamicConnectedChannels { - channels: Vec>>, -} - -/** - A tagged [`ConnectedChannel`] that is connected between the chains - at position `CHAIN_A` and `CHAIN_B`. -*/ -pub type NthConnectedChannel = - ConnectedChannel, NthChainHandle>; - -/** - A tagged [`Channel`] with the A side at `CHAIN_A` position and B side at - the `CHAIN_B` position. -*/ -pub type NthChannel = - Channel, NthChainHandle>; - -/** - A tagged [`ChannelId`] for the chain at position `CHAIN_A` that is correspond - to the counterparty chain at position `CHAIN_B` -*/ -pub type NthChannelId = - DualTagged, NthChainHandle, ChannelId>; - -/** - A tagged [`PortId`] for the chain at position `CHAIN_A` that is correspond - to the counterparty chain at position `CHAIN_B` -*/ -pub type NthPortId = - DualTagged, NthChainHandle, PortId>; - -impl ConnectedChannels { - /** - Get the binary [`ConnectedChannel`] at position `CHAIN_A` and `CHAIN_B`, - which must be less than `SIZE`. - */ - pub fn channel_at( - &self, - ) -> Result, Error> { - if CHAIN_A >= SIZE || CHAIN_B >= SIZE { - Err(Error::generic(eyre!( - "cannot get channel beyond position {}/{}", - CHAIN_A, - CHAIN_B - ))) - } else { - let raw_channel = self.channels[CHAIN_A][CHAIN_B].clone(); - - let channel = raw_channel.map_chain(MonoTagged::new, MonoTagged::new); - - Ok(channel) - } - } - - pub fn channels(&self) -> &[[ConnectedChannel; SIZE]; SIZE] { - &self.channels - } -} - -impl DynamicConnectedChannels { - pub fn new(channels: Vec>>) -> Self { - Self { channels } - } - - pub fn channels(&self) -> &Vec>> { - &self.channels - } -} - -impl TryFrom> - for ConnectedChannels -{ - type Error = Error; - - fn try_from(channels: DynamicConnectedChannels) -> Result { - Ok(ConnectedChannels { - channels: try_into_nested_array(channels.channels)?, - }) - } -} - -impl From> for NthConnectedChannel<0, 1, Handle> { - fn from(channels: ConnectedChannels) -> Self { - channels.channel_at::<0, 1>().unwrap() - } -} - -impl ExportEnv for ConnectedChannels { - fn export_env(&self, writer: &mut impl EnvWriter) { - for (i, inner_channels) in self.channels.iter().enumerate() { - for (j, channel_i_to_j) in inner_channels.iter().enumerate() { - writer.write_env( - &format!("CONNECTION_ID_{j}_to_{i}"), - &format!("{}", channel_i_to_j.connection.connection_id_a), - ); - - writer.write_env( - &format!("CONNECTION_ID_{i}_to_{j}"), - &format!("{}", channel_i_to_j.connection.connection_id_b), - ); - - writer.write_env( - &format!("CHANNEL_ID_{j}_to_{i}"), - &format!("{}", channel_i_to_j.channel_id_a), - ); - - writer.write_env( - &format!("PORT_{j}_to_{i}"), - &format!("{}", channel_i_to_j.port_a), - ); - - writer.write_env( - &format!("CHANNEL_ID_{i}_to_{j}"), - &format!("{}", channel_i_to_j.channel_id_b), - ); - - writer.write_env( - &format!("PORT_{i}_to_{j}"), - &format!("{}", channel_i_to_j.port_b), - ); - } - } - } -} diff --git a/tools/test-framework/src/types/nary/connection.rs b/tools/test-framework/src/types/nary/connection.rs deleted file mode 100644 index f0451c794..000000000 --- a/tools/test-framework/src/types/nary/connection.rs +++ /dev/null @@ -1,136 +0,0 @@ -/*! - Constructs for N-ary connected connections. -*/ - -use core::convert::TryFrom; - -use eyre::eyre; -use ibc_relayer::chain::handle::ChainHandle; -use ibc_relayer_types::core::ics24_host::identifier::ConnectionId; - -use super::aliases::NthChainHandle; -use crate::error::Error; -use crate::types::binary::connection::ConnectedConnection; -use crate::types::env::{EnvWriter, ExportEnv}; -use crate::types::tagged::*; -use crate::util::array::{into_nested_vec, try_into_nested_array}; - -/** - A fixed-size N-ary connected connections as specified by `SIZE`. - - Contains `SIZE`x`SIZE` number of binary [`ConnectedConnection`]s. -*/ -#[derive(Debug, Clone)] -pub struct ConnectedConnections { - connections: [[ConnectedConnection; SIZE]; SIZE], -} - -/** - A dynamic-sized N-ary connected connections, made of a - nested vector of binary [`ConnectedConnection`] which must be - in the same dimension. -*/ -#[derive(Debug, Clone)] -pub struct DynamicConnectedConnections { - connections: Vec>>, -} - -/** - A tagged binary [`ConnectedConnection`] that is connected between the chains at - position `CHAIN_A` and `CHAIN_B`. -*/ -pub type NthConnectedConnection = - ConnectedConnection, NthChainHandle>; - -/** - The connection ID on the chain at position `CHAIN_A` that corresponds to - the counterparty chain at position `CHAIN_B`. -*/ -pub type NthConnectionId = - DualTagged, NthChainHandle, ConnectionId>; - -impl ConnectedConnections { - /** - Get the connection pair for chains at position `CHAIN_A` and `CHAIN_B`, - which must be less then `SIZE`. - */ - pub fn connection_at( - &self, - ) -> Result, Error> { - if CHAIN_A >= SIZE || CHAIN_B >= SIZE { - Err(Error::generic(eyre!( - "cannot get connection beyond position {}/{}", - CHAIN_A, - CHAIN_B - ))) - } else { - let raw_connection = self.connections[CHAIN_A][CHAIN_B].clone(); - - let channel = raw_connection.map_chain(MonoTagged::new, MonoTagged::new); - - Ok(channel) - } - } - - pub fn connections(&self) -> &[[ConnectedConnection; SIZE]; SIZE] { - &self.connections - } -} - -impl DynamicConnectedConnections { - pub fn new(connections: Vec>>) -> Self { - Self { connections } - } - - pub fn connections(&self) -> &Vec>> { - &self.connections - } -} - -impl From> - for DynamicConnectedConnections -{ - fn from(connections: ConnectedConnections) -> Self { - DynamicConnectedConnections { - connections: into_nested_vec(connections.connections), - } - } -} - -impl TryFrom> - for ConnectedConnections -{ - type Error = Error; - - fn try_from(connections: DynamicConnectedConnections) -> Result { - Ok(ConnectedConnections { - connections: try_into_nested_array(connections.connections)?, - }) - } -} - -impl From> - for NthConnectedConnection<0, 1, Handle> -{ - fn from(channels: ConnectedConnections) -> Self { - channels.connection_at::<0, 1>().unwrap() - } -} - -impl ExportEnv for ConnectedConnections { - fn export_env(&self, writer: &mut impl EnvWriter) { - for (i, inner_connections) in self.connections.iter().enumerate() { - for (j, connection_i_to_j) in inner_connections.iter().enumerate() { - writer.write_env( - &format!("CONNECTION_ID_{j}_to_{i}"), - &format!("{}", connection_i_to_j.connection_id_a), - ); - - writer.write_env( - &format!("CONNECTION_ID_{i}_to_{j}"), - &format!("{}", connection_i_to_j.connection_id_b), - ); - } - } - } -} diff --git a/tools/test-framework/src/types/nary/foreign_client.rs b/tools/test-framework/src/types/nary/foreign_client.rs deleted file mode 100644 index 5572ae245..000000000 --- a/tools/test-framework/src/types/nary/foreign_client.rs +++ /dev/null @@ -1,89 +0,0 @@ -use core::convert::TryFrom; - -use eyre::eyre; -use ibc_relayer::chain::handle::ChainHandle; -use ibc_relayer::foreign_client::ForeignClient; - -use super::aliases::NthChainHandle; -use crate::error::Error; -use crate::types::binary::foreign_client::ForeignClientPair; -use crate::types::env::{EnvWriter, ExportEnv}; -use crate::types::tagged::*; -use crate::util::array::{into_nested_vec, try_into_nested_array}; - -/** - A [`ForeignClient`] that is tagged by a `Handle: ChainHandle` and - the const generics `DEST: usize` and `SRC: usize`. -*/ -pub type NthForeignClient = - ForeignClient, NthChainHandle>; - -pub type NthForeignClientPair = - ForeignClientPair, NthChainHandle>; - -#[derive(Clone)] -pub struct ForeignClientPairs { - foreign_clients: [[ForeignClient; SIZE]; SIZE], -} - -impl ForeignClientPairs { - /** - Get the [`ForeignClient`] with the source chain at position - `SRC: usize` and destination chain at position `DEST: usize`, - which must be less than `SIZE`. - */ - pub fn foreign_client_at( - &self, - ) -> Result, Error> { - if SRC >= SIZE || DEST >= SIZE { - Err(Error::generic(eyre!( - "cannot get foreign client beyond position {}/{}", - SRC, - DEST - ))) - } else { - let client = self.foreign_clients[SRC][DEST] - .clone() - .map_chain(MonoTagged::new, MonoTagged::new); - - Ok(client) - } - } - - pub fn foreign_client_pair_at( - &self, - ) -> Result, Error> { - let client_a_to_b = self.foreign_client_at::()?; - let client_b_to_a = self.foreign_client_at::()?; - - Ok(ForeignClientPair::new(client_a_to_b, client_b_to_a)) - } - - pub fn into_nested_vec(self) -> Vec>> { - into_nested_vec(self.foreign_clients) - } -} - -impl TryFrom>>> - for ForeignClientPairs -{ - type Error = Error; - - fn try_from(clients: Vec>>) -> Result { - let foreign_clients = try_into_nested_array(clients)?; - Ok(Self { foreign_clients }) - } -} - -impl ExportEnv for ForeignClientPairs { - fn export_env(&self, writer: &mut impl EnvWriter) { - for (source, inner_clients) in self.foreign_clients.iter().enumerate() { - for (destination, client) in inner_clients.iter().enumerate() { - writer.write_env( - &format!("CLIENT_ID_{source}_to_{destination}"), - &format!("{}", client.id()), - ); - } - } - } -} diff --git a/tools/test-framework/src/types/nary/mod.rs b/tools/test-framework/src/types/nary/mod.rs deleted file mode 100644 index 04bc360fd..000000000 --- a/tools/test-framework/src/types/nary/mod.rs +++ /dev/null @@ -1,66 +0,0 @@ -/*! - Definitions for tagged data structures involving N-ary chains. - - In the binary version of the tagged data structures, we use the - existential types `ChainA: ChainHandle` and `ChainB: ChainHandle` - to differentiate between two chains. Since Rust treat each type - differently, we can use `ChainA` and `ChainB` as type tags - to differentiate values coming from different chains. - For example, `DualTagged` - can be used to refer to a `ChainId` on `ChainA` with the - counterparty chain being `ChainB`. - - When extending to the N-ary case, we can no longer use - existential types to refer to each chain, because we cannot - know before hand how many types are needed. Instead, - we can use _const generics_ to identify chains by _position_. - - The first construct we need is the [`Size`](aliases::Size) struct, - which lifts a const generic `usize` into a type: - - ```rust - enum Size {} - ``` - - Using `Size`, we can for example use a `usize` as a tag. - For example, `MonoTagged, String>` is a `String` - that is tagged by the `usize` value `42`. - - Aside from the position, we still need to be able to differentiate - values coming from different _collections_ of chains. For example, - given a first collection `[ChainA, ChainB, ChainC]`, and a second - collection `[ChainD, ChainE]`, a naively position-tagged value like - `MonoTagged, Denom>` could be used to refer to a denomination - that come from either `ChainB` or `ChainE`, which defeats the purpose - of tagging values with type tags. - - Due to the initial design of using the `ChainHandle` existential type as - the type tag, it is also required that any type that is used to tag - values for chains to also implement `ChainHandle`. Since `Size` does - not implement `ChainHandle`, it is also not possible to use it directly - as tags in structures such as `ForeignClient`. - - Instead, we also require an existential `Collection: ChainHandle` type - to identify all chains within an N-ary collection. We then tag - the handle with the position, before tagging it again with the - values. For example, a `Denom` that is tagged with the third chain - in the first collection would be written as - `MonoTagged, Collection1>, Denom>`. - The tagging also works because we have defined a `ChainHandle` - implementation for `MonoTagged` for any `Chain: ChainHandle`. - - The current approach for tagging N-ary chain values is a bit cumbersome. - To save the effort of typing the fully qualified type of N-ary tagged - values, we also define type aliases such as - [`NthChainHandle`](aliases::NthChainHandle) and - [`NthForeignClient`](foreign_client::NthForeignClient). - This would still result in overly verbose messages in type errors involving - these types. If necessary, we will refactor these defintions as newtypes - so that they can be used and shown in a cleaner form. -*/ - -pub mod aliases; -pub mod chains; -pub mod channel; -pub mod connection; -pub mod foreign_client; diff --git a/tools/test-framework/src/types/process.rs b/tools/test-framework/src/types/process.rs deleted file mode 100644 index fdab93b5b..000000000 --- a/tools/test-framework/src/types/process.rs +++ /dev/null @@ -1,53 +0,0 @@ -/*! - Define wrapper type around [`std::process::Child`] to kill the - child process when the value is dropped. -*/ - -use std::process::Child; - -use eyre::Report as Error; - -/** - A lightweight wrapper around std::process::Child to ensure that the - process is killed when the handle is dropped. -*/ -pub struct ChildProcess { - child: Child, - waited: bool, -} - -impl ChildProcess { - /// Create a new [`ChildProcess`] from the primitive [`Child`] type. - pub fn new(child: Child) -> Self { - Self { - child, - waited: false, - } - } - - /// Wait for the child process to terminate. - pub fn wait(&mut self) -> Result<(), Error> { - if !self.waited { - self.waited = true; - self.child.wait()?; - } - - Ok(()) - } - - /// Kill the underlying child process. - pub fn kill(&mut self) -> Result<(), Error> { - self.child.kill()?; - self.wait()?; - - Ok(()) - } -} - -impl Drop for ChildProcess { - fn drop(&mut self) { - if !self.waited { - let _ = self.kill(); - } - } -} diff --git a/tools/test-framework/src/types/single/mod.rs b/tools/test-framework/src/types/single/mod.rs deleted file mode 100644 index 2ccc0ddc2..000000000 --- a/tools/test-framework/src/types/single/mod.rs +++ /dev/null @@ -1,5 +0,0 @@ -/*! - Definitions for data types that involve a single chain. -*/ - -pub mod node; diff --git a/tools/test-framework/src/types/single/node.rs b/tools/test-framework/src/types/single/node.rs deleted file mode 100644 index b43a6d680..000000000 --- a/tools/test-framework/src/types/single/node.rs +++ /dev/null @@ -1,205 +0,0 @@ -/*! - Type definition for a single running full node. -*/ - -use core::str::FromStr; -use core::time::Duration; -use std::sync::{Arc, RwLock}; - -use eyre::{eyre, Report as Error}; -use ibc_relayer::chain::cosmos::config::CosmosSdkConfig; -use ibc_relayer::config; -use ibc_relayer::config::gas_multiplier::GasMultiplier; -use ibc_relayer::keyring::Store; -use ibc_relayer_types::core::ics24_host::identifier::ChainId; -use tendermint_rpc::{Url, WebSocketClientUrl}; - -use crate::chain::chain_type::ChainType as TestedChainType; -use crate::chain::driver::ChainDriver; -use crate::ibc::denom::Denom; -use crate::prelude::TestConfig; -use crate::types::env::{prefix_writer, EnvWriter, ExportEnv}; -use crate::types::process::ChildProcess; -use crate::types::tagged::*; -use crate::types::wallet::TestWallets; - -pub type TaggedFullNode = MonoTagged; - -pub type TaggedFullNodeRef<'a, Chain> = MonoTagged; - -/** - Represents a full node running as a child process managed by the test. -*/ -#[derive(Clone)] -pub struct FullNode { - /** - The [`ChainDriver`] used to communicate with the full node. - */ - pub chain_driver: ChainDriver, - - /** - The currency denomination which the wallets have been loaded - with initial balance during the chain setup. - */ - pub denom: Denom, - - /** - The test wallets with more than sufficient account balance that - can be used for testing. - */ - pub wallets: TestWallets, - - /** - The child process that is running the full node. - - The full node is killed when the `Arc` shared pointer is dropped. - - Test authors can acquire the child process and kill the full node - in the middle of tests using [`kill`](FullNode::kill). - */ - pub process: Arc>, -} - -/** - Extra methods for [`FullNode`] that is [tagged](crate::types::tagged). - - This trait is auto implemented for `MonoTagged` so - that we can call methods on it directly. -*/ -pub trait TaggedFullNodeExt { - /// Get the [`ChainId`] tagged with the given `Chain`. - fn chain_id(&self) -> MonoTagged; - - /// Get the [`ChainDriver`] tagged with the given `Chain`. - fn chain_driver(&self) -> MonoTagged; - - /// Get the [`TestWallets`] tagged with the given `Chain`. - fn wallets(&self) -> MonoTagged; - - /// Get the [`Denom`] tagged with the given `Chain`. - fn denom(&self) -> MonoTagged; -} - -impl TaggedFullNodeExt for MonoTagged { - fn chain_id(&self) -> MonoTagged { - self.map_ref(|c| &c.chain_driver.chain_id) - } - - fn chain_driver(&self) -> MonoTagged { - self.map_ref(|c| &c.chain_driver) - } - - fn wallets(&self) -> MonoTagged { - self.map_ref(|c| &c.wallets) - } - - fn denom(&self) -> MonoTagged { - self.map_ref(|c| &c.denom) - } -} - -impl TaggedFullNodeExt for MonoTagged { - fn chain_id(&self) -> MonoTagged { - self.map_ref(|c| &c.chain_driver.chain_id) - } - - fn chain_driver(&self) -> MonoTagged { - self.map_ref(|c| &c.chain_driver) - } - - fn wallets(&self) -> MonoTagged { - self.map_ref(|c| &c.wallets) - } - - fn denom(&self) -> MonoTagged { - self.map_ref(|c| &c.denom) - } -} - -impl FullNode { - /** - Generate the relayer's chain config based on the configuration of - the full node. - */ - pub fn generate_chain_config( - &self, - chain_type: &TestedChainType, - test_config: &TestConfig, - ) -> Result { - let hermes_keystore_dir = test_config - .chain_store_dir - .join("hermes_keyring") - .as_path() - .display() - .to_string(); - - Ok(config::ChainConfig::CosmosSdk(CosmosSdkConfig { - id: self.chain_driver.chain_id.clone(), - rpc_addr: Url::from_str(&self.chain_driver.rpc_address())?, - grpc_addr: Url::from_str(&self.chain_driver.grpc_address())?, - event_source: config::EventSourceMode::Push { - url: WebSocketClientUrl::from_str(&self.chain_driver.websocket_address())?, - batch_delay: config::default::batch_delay(), - }, - rpc_timeout: config::default::rpc_timeout(), - trusted_node: false, - genesis_restart: None, - account_prefix: self.chain_driver.account_prefix.clone(), - key_name: self.wallets.relayer.id.0.clone(), - key_store_type: Store::Test, - key_store_folder: Some(hermes_keystore_dir.into()), - store_prefix: "ibc".to_string(), - default_gas: None, - max_gas: Some(3000000), - gas_adjustment: None, - gas_multiplier: Some(GasMultiplier::unsafe_new(1.2)), - fee_granter: None, - max_msg_num: Default::default(), - max_tx_size: Default::default(), - max_grpc_decoding_size: config::default::max_grpc_decoding_size(), - max_block_time: Duration::from_secs(30), - clock_drift: Duration::from_secs(5), - 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()), - 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: None, - clear_interval: None, - query_packets_chunk_size: config::default::query_packets_chunk_size(), - client_refresh_rate: config::default::client_refresh_rate(), - memo_overwrite: None, - dynamic_gas_price: Default::default(), - excluded_sequences: Default::default(), - allow_ccq: false, - })) - } - - /** - Kill the underlying child process of the full node, thereby terminating it. - - Test writers can use this to kill the full node in the middle of tests, and - then restart it using - [`ChainDriver::start`](crate::chain::ext::bootstrap::ChainBootstrapMethodsExt::start). - */ - pub fn kill(&self) -> Result<(), Error> { - self.process - .write() - .map_err(|_| eyre!("poisoned mutex"))? - .kill() - } -} - -impl ExportEnv for FullNode { - fn export_env(&self, writer: &mut impl EnvWriter) { - self.chain_driver.export_env(writer); - writer.write_env("DENOM", self.denom.as_str()); - self.wallets - .export_env(&mut prefix_writer("WALLETS", writer)); - } -} diff --git a/tools/test-framework/src/types/tagged/dual.rs b/tools/test-framework/src/types/tagged/dual.rs deleted file mode 100644 index 5a1a569fc..000000000 --- a/tools/test-framework/src/types/tagged/dual.rs +++ /dev/null @@ -1,470 +0,0 @@ -/*! - Tagged data types with two type tags. - - This is mainly used to tag data types that are associated - to a single chain and also uniquely correspond to some - resource on a counterparty chain. - - Example: - - - [`Tagged`](crate::types::id::TaggedChannelId) - - A channel ID belongs to a chain `ChainA`, and it is also uniquely - corresponds to a channel connected to a counterparty chain `ChainB`. -*/ - -use core::cmp::{Eq, Ord, Ordering, PartialEq, PartialOrd}; -use core::fmt::{self, Debug, Display}; -use core::iter::{IntoIterator, Iterator}; -use core::marker::PhantomData; - -/** - Tag a `Value` type with a two type tags `TagA` and `TagB`. -*/ -pub struct Tagged(pub Value, PhantomData<(TagA, TagB)>); - -impl Tagged { - /** - Create a new tagged value with any type tag. - - Example: - - ```rust - # use ibc_test_framework::types::tagged::dual::Tagged; - struct Foo; - struct Bar; - - let val: Tagged = Tagged::new(42); - ``` - */ - pub fn new(value: Value) -> Self { - Tagged(value, PhantomData) - } - - /** - Get a reference to the underlying value. - - Example: - - ```rust - # use ibc_test_framework::types::tagged::dual::Tagged; - struct Foo; - struct Bar; - - let val1: Tagged = Tagged::new(42); - let val2: &i64 = val1.value(); - ``` - */ - pub fn value(&self) -> &Value { - &self.0 - } - - /** - Get a mutable reference to the underlying value. - - Example: - - ```rust - # use ibc_test_framework::types::tagged::dual::Tagged; - struct Foo; - struct Bar; - - let mut val1: Tagged = Tagged::new(42); - let val2: i64 = val1.into_value(); - ``` - */ - pub fn into_value(self) -> Value { - self.0 - } - - /** - Convert a tagged value into a tagged reference. - - Example: - - ```rust - # use ibc_test_framework::types::tagged::dual::Tagged; - struct Foo; - struct Bar; - - let val1: Tagged = Tagged::new(42); - let val2: Tagged = val1.as_ref(); - ``` - */ - pub fn as_ref(&self) -> Tagged { - Tagged::new(&self.0) - } - - /** - Flips the ordering of the two tags. - - Example: - - ```rust - # use ibc_test_framework::types::tagged::dual::Tagged; - struct Foo; - struct Bar; - - let val1: Tagged = Tagged::new(42); - let val2: Tagged = val1.flip(); - ``` - */ - pub fn flip(self) -> Tagged { - Tagged::new(self.0) - } - - /** - Retag a tagged value with a different tag. - - Example: - - ```rust - # use ibc_test_framework::types::tagged::dual::Tagged; - struct Foo; - struct Bar; - struct Baz; - struct Quux; - - let val1: Tagged = Tagged::new(42); - let val2: Tagged = val1.retag(); - ``` - */ - pub fn retag(self) -> Tagged { - Tagged::new(self.0) - } - - /** - Perform operation with the reference to the underlying reference, - and have result that preserve the tag. - - Example: - - ```rust - # use ibc_test_framework::types::tagged::dual::Tagged; - struct Foo; - struct Bar; - - let val1: Tagged = Tagged::new(42); - let val2: Tagged = val1.map(|x| format!("{}", x)); - ``` - */ - pub fn map(&self, mapper: impl FnOnce(&Value) -> T) -> Tagged { - Tagged::new(mapper(&self.0)) - } - - /** - Perform operation with the reference to the underlying reference, - and have result reference with the same lifetime that preserve the tags. - - Example: - - ```rust - # use ibc_test_framework::types::tagged::dual::Tagged; - struct Person { name: String, age: u8 } - struct Alice; - struct Wonderland; - - let person: Tagged = Tagged::new(Person { - name: "Alice".to_string(), - age: 30, - }); - - let name: Tagged = person - .map_ref(|person| person.name.as_str()); - ``` - */ - pub fn map_ref<'a, T: ?Sized>( - &'a self, - mapper: impl FnOnce(&'a Value) -> &'a T, - ) -> Tagged { - Tagged::new(mapper(self.value())) - } - - /** - Perform an operation consuming the original tagged value, and return - a result value preserving the original tag. - - Example: - - ```rust - # use ibc_test_framework::types::tagged::dual::Tagged; - struct Person { name: String, age: u8 } - struct Alice; - struct Wonderland; - - let person: Tagged = Tagged::new(Person { - name: "Alice".to_string(), - age: 30, - }); - - let name: Tagged = person.map_into(|person| person.name); - ``` - */ - pub fn map_into(self, mapper: impl FnOnce(Value) -> T) -> Tagged { - Tagged::new(mapper(self.0)) - } - - /** - Perform operation with the reference to the underlying reference, - and have two tags flipped in the result. - - Example: - - ```rust - # use ibc_test_framework::types::tagged::dual::Tagged; - struct Foo; - struct Bar; - - let val1: Tagged = Tagged::new(42); - let val2: Tagged = val1.contra_map(|x| format!("{}", x)); - ``` - - This is mainly useful for accessing IBC data structures that may contain - information about the counterparty chain. For example, consider - a tagged and simplified version of - [`ConnectionEnd`](ibc_relayer_types::core::ics03_connection::connection::ConnectionEnd): - - ```rust - # use ibc_relayer_types::core::ics24_host::identifier::ConnectionId; - # use ibc_test_framework::types::tagged::dual::Tagged; - struct ConnectionEnd { - connection_id: ConnectionId, - counterparty_connection_id: ConnectionId, - } - - fn process_connection_end( - connection_end: Tagged) - { - let connection_id: Tagged = - connection_end.map(|c| c.connection_id.clone()); - - let counterparty_connection_id: Tagged = - connection_end.contra_map(|c| c.connection_id.clone()); - - // do something - } - ``` - - The `ConnectionEnd` data type above is a _bidirectional_ data type that - contains fields that are specific to both chains: the connection ID - and the counterparty connection ID. But when we tag the `ConnectionEnd` - type, we have to choose one dominant chain to appear at the first position. - - When we extract the `connection_id` field, we use `map` to preserve the - tag ordering to say that the connection ID _belongs_ to the `ChainA`, - and corresponds to a connection to the counterparty `ChainB`. - - When we extract the `counterparty_connection_id` field, we use - `contra_map` to flip the tag ordering to say that the connection ID - _belongs_ to the counterparty `ChainB`, and corresponds to a connection - to `ChainA`. - */ - pub fn contra_map(&self, mapper: impl FnOnce(&Value) -> T) -> Tagged { - Tagged::new(mapper(&self.0)) - } - - /** - Perform operation with the reference to the underlying reference, - and have the result reference with the same lifetime and have the - two tags flipped in the result. - - Example: - - ```rust - # use ibc_test_framework::types::tagged::dual::Tagged; - struct Person { name: String, age: u8 } - struct Alice; - struct Wonderland; - - let person: Tagged = Tagged::new(Person { - name: "Alice".to_string(), - age: 30, - }); - - let name: Tagged = person - .contra_map_ref(|person| person.name.as_str()); - ``` - */ - pub fn contra_map_ref<'a, T: ?Sized>( - &'a self, - mapper: impl FnOnce(&'a Value) -> &'a T, - ) -> Tagged { - Tagged::new(mapper(self.value())) - } - - /** - Perform operation consuming the underlying reference, - and have two tags switched in the result. - - Example: - - ```rust - # use ibc_test_framework::types::tagged::dual::Tagged; - struct Foo; - struct Bar; - - let val1: Tagged = Tagged::new(42); - let val2: Tagged = val1.contra_map_into(|x| format!("{}", x)); - ``` - */ - pub fn contra_map_into(self, mapper: impl FnOnce(Value) -> T) -> Tagged { - Tagged::new(mapper(self.0)) - } -} - -impl Tagged { - /** - Convert a [`Clone`]eable tagged reference into a tagged value. - - Example: - - ```rust - # use ibc_test_framework::types::tagged::dual::Tagged; - struct Foo; - struct Bar; - - let val1: String = "foo".to_string(); - let val2: Tagged = Tagged::new(&val1); - let val3: Tagged = val2.cloned(); - ``` - */ - pub fn cloned(&self) -> Tagged { - Tagged::new(self.0.clone()) - } - - pub fn cloned_value(&self) -> Value { - self.0.clone() - } -} - -impl Tagged> { - /** - Convert a tagged [`Option`] value into an optional tagged value. - - Example: - - ```rust - # use ibc_test_framework::types::tagged::dual::Tagged; - struct Foo; - struct Bar; - - let val1: Tagged> = Tagged::new(Some(8)); - let val2: Option> = val1.transpose(); - ``` - */ - pub fn transpose(self) -> Option> { - self.0.map(Tagged::new) - } -} - -impl Tagged> { - /** - Convert a tagged [`Result`] value into an result tagged value. - - Example: - - ```rust - # use ibc_test_framework::types::tagged::dual::Tagged; - struct Foo; - struct Bar; - struct Error; - - let val1: Tagged> = Tagged::new(Ok(8)); - let val2: Result, Error> = val1.transpose(); - ``` - */ - pub fn transpose(self) -> Result, E> { - self.0.map(Tagged::new) - } -} - -impl AsRef for Tagged { - fn as_ref(&self) -> &Value { - self.value() - } -} - -impl AsRef for Tagged { - fn as_ref(&self) -> &Value { - self.value() - } -} - -impl Copy for Tagged {} - -unsafe impl Send for Tagged {} -unsafe impl Sync for Tagged {} - -impl Clone for Tagged { - fn clone(&self) -> Self { - Self::new(self.0.clone()) - } -} - -impl Debug for Tagged { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - Debug::fmt(self.value(), f) - } -} - -impl Display for Tagged { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - Display::fmt(self.value(), f) - } -} - -impl PartialEq for Tagged { - fn eq(&self, other: &Self) -> bool { - self.value().eq(other.value()) - } -} - -impl Eq for Tagged {} - -impl PartialOrd for Tagged { - fn partial_cmp(&self, other: &Self) -> Option { - self.value().partial_cmp(other.value()) - } -} - -impl Ord for Tagged { - fn cmp(&self, other: &Self) -> Ordering { - self.value().cmp(other.value()) - } -} - -/** - Create a tagged iterator, if the underlying value supports iteration. - - Example: - - ```rust - # use ibc_test_framework::types::tagged::dual::Tagged; - struct Foo; - struct Bar; - - let values: Tagged> = Tagged::new(vec![1, 2, 3]); - for value in values.into_iter() { - let value: Tagged = value; - // do something - } - ``` -*/ -pub struct TaggedIterator(Tagged); - -impl Iterator for TaggedIterator { - type Item = Tagged; - - fn next(&mut self) -> Option { - self.0 .0.next().map(Tagged::new) - } -} - -impl IntoIterator for Tagged { - type Item = Tagged; - - type IntoIter = TaggedIterator; - - fn into_iter(self) -> Self::IntoIter { - TaggedIterator(self.map_into(|v| v.into_iter())) - } -} diff --git a/tools/test-framework/src/types/tagged/mod.rs b/tools/test-framework/src/types/tagged/mod.rs deleted file mode 100644 index 50f75dc6c..000000000 --- a/tools/test-framework/src/types/tagged/mod.rs +++ /dev/null @@ -1,130 +0,0 @@ -/*! - A small library for adding one or two type tags to data types. - - This module introduces two data types, [`MonoTagged`] and - [`DualTagged`], for adding one or two type tags to any data - type, respectively. - - The main idea is that we add any type as a tag to a type, - so that two values with different tags are considered - different types. - - ```rust,compile_fail - # use ibc_test_framework::types::tagged::*; - struct Foo; - struct Bar; - - // Helper to test whether two values have the same type. - fn same(_: T, _: T) {} - - let val1: i64 = 42; // A raw `i64` value. - - // An `i64` value tagged with the `Foo` type. - let val2: MonoTagged = MonoTagged::new(42); - - // An `i64` value tagged with the `Bar` type. - let val3: MonoTagged = MonoTagged::new(42); - - // error, because the tags `Foo` and `Bar` are different. - same(val2, val3); - ``` - - The `tagged` library does not enforce how the type tags should be used - correctly. Therefore we can freely add or remove tags for a value at - any time. It is up to the user of this library to ensure that values - are tagged with the proper type tag as intended. - - For example, it is entirely fine to do something like: - - ```rust - # use ibc_test_framework::types::tagged::*; - struct Foo; - struct Bar; - struct Baz; - - let val1: i64 = 42; - - // Add a new tag `Foo` to `val1`. - let val2: MonoTagged = MonoTagged::new(val1); - - // Remove the tag `Foo` from `val2`. - let val3: i64 = val2.into_value(); - - // Retag `val3` with a new tag `Bar`. - let val4: MonoTagged = MonoTagged::new(val3); - - // Directly retag `val4` from `Bar` tag to `Baz` tag. - let val5: MonoTagged = val4.retag(); - ``` - - As a result, user is free to switch to work with the untagged version - of the values, if they find the tagged values to have too complicated - types to deal with. The retagging approach also works well for - interoperability between functions that use tagged and untagged values, - so that there is no need to convert an entire code base to use - tagged values. - - Currently the main use of the `tagged` library is to tag data types and - identifiers associated with different chains. For example, a tagged - type `DualTagged` is used to represent - a `ChannelId` value that is used on `ChainA` to identify a channel - that is connected to `ChainB`. With the tagged identifier, it is - more unlikely for us to accidentally use the `ChannelId` coming from - counterparty chain, as it would have the the type - `DualTagged` and thus result in - type error. - - Currently the type tags for the chain data types are derived from - the spawned chain handles, which has the existential type - [`impl ChainHandle`](ibc_relayer::chain::handle::ChainHandle). - Note that even though there is only one implementation of - `ChainHandle`, - [`CountingAndCachingChainHandle`](ibc_relayer::chain::handle::CountingAndCachingChainHandle), - when they are returned as `impl ChainHandle` they would be - considered by Rust as an - [abstract type](https://doc.rust-lang.org/reference/types/impl-trait.html#abstract-return-types) - that is different from the original type. Inside generic functions, - we can also treat the same type as different types by specifying - them as separate generic parameters. - - By using `impl ChainHandle` as the type tag, it also encourage - us to treat different `ChainHandle` values as having different - types. This will help us in the future to have easier transition - into implementing relayer code that support relaying between different - implementations of `ChainHandle`s that corresponding to different - chain implementations. - - - The use of tagged identifiers are especially useful for avoiding confusion - when using data types that have tags in _contravariant_ ordering, - such as - [`ForeignClient`](ibc_relayer::foreign_client::ForeignClient). - Whereas most relayer constructs such as - `Connection` would mean - "a connection from chain A to chain B", a - `ForeignClient` actually means "a foreign client from - chain B to chain A". As a result, if we want to always refer to - "from chain A to chain B", then we would have to instead write - `ForeignClient`. - - The use of contravariant ordering can be very confusing for developers - who are new to the code base, and we cannot expect developers to always - remember which construct requires contravariant ordering. We also cannot - easily refactor legacy constructs such as `ForeignClient` to use covariant - ordering, as we would have to search for the entire code base to - replace the ordering, and there is no guarantee to do the refactoring - correctly. - - With tagged identifiers, we can alleviate some of the confusion by - leaving it to the type system to track which identifier belong to - which chain. This way if a developer ever think that - `ForeignClient` means "foreign client from chain A - to chain B", the compiler will correct them of the mistake with a - type error. -*/ - -pub mod dual; -pub mod mono; - -pub use dual::Tagged as DualTagged; -pub use mono::Tagged as MonoTagged; diff --git a/tools/test-framework/src/types/tagged/mono.rs b/tools/test-framework/src/types/tagged/mono.rs deleted file mode 100644 index 9b1565cda..000000000 --- a/tools/test-framework/src/types/tagged/mono.rs +++ /dev/null @@ -1,411 +0,0 @@ -/*! - Tagged data types with a single type tag. - - This is mainly used to tag data types that are associated - to a single chain and do not uniquely correspond to any - resource on a counterparty chain. - - Example: - - - [`Tagged`](crate::types::id::TaggedChainId) - - A chain ID belongs to a chain and do not uniquely - correspond to a counterparty chain. - - - [`Tagged`](crate::types::wallet::Wallet) - - A wallet belongs to a chain and do not uniquely - correspond to a counterparty chain - -*/ - -use core::cmp::{Eq, Ord, Ordering, PartialEq, PartialOrd}; -use core::fmt::{self, Debug, Display}; -use core::iter::{IntoIterator, Iterator}; -use core::marker::PhantomData; - -use serde::{Serialize, Serializer}; - -use super::dual::Tagged as DualTagged; - -/** - Tag a `Value` type with a single `Tag` type tag. -*/ -pub struct Tagged(pub Value, pub PhantomData); - -impl Tagged { - /** - Create a new tagged value with any type tag. - - Example: - - ```rust - # use ibc_test_framework::types::tagged::mono::Tagged; - struct Foo; - - let val: Tagged = Tagged::new(42); - ``` - */ - pub fn new(value: Value) -> Self { - Tagged(value, PhantomData) - } - - /** - Get a reference to the underlying value. - - Example: - - ```rust - # use ibc_test_framework::types::tagged::mono::Tagged; - struct Foo; - - let val1: Tagged = Tagged::new(42); - let val2: &i64 = val1.value(); - ``` - */ - pub fn value(&self) -> &Value { - &self.0 - } - - /** - Get a mutable reference to the underlying value. - - Example: - - ```rust - # use ibc_test_framework::types::tagged::mono::Tagged; - struct Foo; - - let mut val1: Tagged = Tagged::new(42); - let val2: &mut i64 = val1.mut_value(); - ``` - */ - pub fn mut_value(&mut self) -> &mut Value { - &mut self.0 - } - - /** - Convert the tagged value into an untagged value. - - Example: - - ```rust - # use ibc_test_framework::types::tagged::mono::Tagged; - struct Foo; - - let val1: Tagged = Tagged::new(42); - let val2: i64 = val1.into_value(); - ``` - */ - pub fn into_value(self) -> Value { - self.0 - } - - /** - Convert a tagged value into a tagged reference. - - Example: - - ```rust - # use ibc_test_framework::types::tagged::mono::Tagged; - struct Foo; - - let val1: Tagged = Tagged::new(42); - let val2: Tagged = val1.as_ref(); - ``` - */ - pub fn as_ref(&self) -> Tagged { - Tagged::new(&self.0) - } - - /** - Retag a tagged value with a different tag. - - Example: - - ```rust - # use ibc_test_framework::types::tagged::mono::Tagged; - struct Foo; - struct Bar; - - let val1: Tagged = Tagged::new(42); - let val2: Tagged = val1.retag(); - ``` - */ - pub fn retag(self) -> Tagged { - Tagged::new(self.0) - } - - /** - Add an additional tag to a mono-tagged value, turning - it into a [`DualTagged`] value. - - Example: - - ```rust - # use ibc_test_framework::types::tagged::mono::Tagged; - # use ibc_test_framework::types::tagged::dual::Tagged as DualTagged; - struct Foo; - struct Bar; - - let val1: Tagged = Tagged::new(42); - let val2: DualTagged = val1.add_tag(); - ``` - */ - pub fn add_tag(self) -> DualTagged { - DualTagged::new(self.into_value()) - } - - /** - Perform operation with the reference to the underlying reference, - and have result that preserve the tag. - - Example: - - ```rust - # use ibc_test_framework::types::tagged::mono::Tagged; - struct Foo; - - let val1: Tagged = Tagged::new(42); - let val2: Tagged = val1.map(|x| format!("{}", x)); - ``` - */ - pub fn map(&self, mapper: impl FnOnce(&Value) -> T) -> Tagged { - Tagged::new(mapper(self.value())) - } - - /** - Perform operation with the reference to the underlying reference, - and have result reference with the same lifetime that preserve the tag. - - Example: - - ```rust - # use ibc_test_framework::types::tagged::mono::Tagged; - struct Person { name: String, age: u8 } - struct Alice; - - let person: Tagged = Tagged::new(Person { - name: "Alice".to_string(), - age: 30, - }); - - let name: Tagged = person.map_ref(|person| person.name.as_str()); - ``` - */ - pub fn map_ref<'a, T: ?Sized>( - &'a self, - mapper: impl FnOnce(&'a Value) -> &'a T, - ) -> Tagged { - Tagged::new(mapper(self.value())) - } - - /** - Perform an operation consuming the original tagged value, and return - a result value preserving the original tag. - - Example: - - ```rust - # use ibc_test_framework::types::tagged::mono::Tagged; - struct Person { name: String, age: u8 } - struct Alice; - - let person: Tagged = Tagged::new(Person { - name: "Alice".to_string(), - age: 30, - }); - - let name: Tagged = person.map_into(|person| person.name); - ``` - */ - pub fn map_into(self, mapper: impl FnOnce(Value) -> T) -> Tagged { - Tagged::new(mapper(self.0)) - } -} - -impl Tagged { - /** - Convert a [`Clone`]eable tagged reference into a tagged value. - - Example: - - ```rust - # use ibc_test_framework::types::tagged::mono::Tagged; - struct Foo; - - let val1: String = "foo".to_string(); - let val2: Tagged = Tagged::new(&val1); - let val3: Tagged = val2.cloned(); - ``` - */ - pub fn cloned(&self) -> Tagged { - Tagged::new(self.0.clone()) - } - - pub fn cloned_value(&self) -> Value { - self.0.clone() - } -} - -impl Tagged> { - /** - Convert a tagged [`Option`] value into an optional tagged value. - - Example: - - ```rust - # use ibc_test_framework::types::tagged::mono::Tagged; - struct Foo; - - let val1: Tagged> = Tagged::new(Some(8)); - let val2: Option> = val1.transpose(); - ``` - */ - pub fn transpose(self) -> Option> { - self.0.map(Tagged::new) - } -} - -impl Tagged> { - /** - Convert a tagged [`Result`] value into an result tagged value. - - Example: - - ```rust - # use ibc_test_framework::types::tagged::mono::Tagged; - struct Foo; - struct Error; - - let val1: Tagged> = Tagged::new(Ok(8)); - let val2: Result, Error> = val1.transpose(); - ``` - */ - pub fn transpose(self) -> Result, E> { - self.0.map(Tagged::new) - } -} - -impl Tagged> { - /** - Convert a tagged [`Vec`] value into a list of tagged value. - - Example: - - ```rust - # use ibc_test_framework::types::tagged::mono::Tagged; - struct Foo; - - let val1: Tagged> = Tagged::new(vec![1, 2, 3]); - let val2: Vec> = val1.transpose(); - ``` - */ - pub fn transpose(self) -> Vec> { - self.into_iter().collect() - } -} - -impl AsRef for Tagged { - fn as_ref(&self) -> &Value { - self.value() - } -} - -impl AsRef for Tagged { - fn as_ref(&self) -> &Value { - self.value() - } -} - -impl Serialize for Tagged { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - self.0.serialize(serializer) - } -} - -/** - Create a tagged iterator, if the underlying value supports iteration. - - Example: - - ```rust - # use ibc_test_framework::types::tagged::mono::Tagged; - struct Foo; - - let values: Tagged> = Tagged::new(vec![1, 2, 3]); - for value in values.into_iter() { - let value: Tagged = value; - // do something - } - ``` -*/ -pub struct TaggedIterator(Tagged); - -impl Iterator for TaggedIterator { - type Item = Tagged; - - fn next(&mut self) -> Option { - self.0 .0.next().map(Tagged::new) - } -} - -impl IntoIterator for Tagged { - type Item = Tagged; - - type IntoIter = TaggedIterator; - - fn into_iter(self) -> Self::IntoIter { - TaggedIterator(self.map_into(|v| v.into_iter())) - } -} - -impl Copy for Tagged {} - -unsafe impl Send for Tagged {} -unsafe impl Sync for Tagged {} - -impl Clone for Tagged { - fn clone(&self) -> Self { - Self::new(self.0.clone()) - } -} - -impl Default for Tagged { - fn default() -> Self { - Self::new(Value::default()) - } -} - -impl Debug for Tagged { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - Debug::fmt(self.value(), f) - } -} - -impl Display for Tagged { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - Display::fmt(self.value(), f) - } -} - -impl PartialEq for Tagged { - fn eq(&self, other: &Self) -> bool { - self.value().eq(other.value()) - } -} - -impl Eq for Tagged {} - -impl PartialOrd for Tagged { - fn partial_cmp(&self, other: &Self) -> Option { - self.value().partial_cmp(other.value()) - } -} - -impl Ord for Tagged { - fn cmp(&self, other: &Self) -> Ordering { - self.value().cmp(other.value()) - } -} diff --git a/tools/test-framework/src/types/wallet.rs b/tools/test-framework/src/types/wallet.rs deleted file mode 100644 index 1fc1a22bb..000000000 --- a/tools/test-framework/src/types/wallet.rs +++ /dev/null @@ -1,218 +0,0 @@ -/*! - Types for information about a chain wallet. -*/ - -use core::fmt::{self, Display}; - -use ibc_relayer::keyring::Secp256k1KeyPair; - -use crate::types::env::{prefix_writer, EnvWriter, ExportEnv}; -use crate::types::tagged::*; - -/** - Newtype wrapper for a wallet ID as identified by the chain and relayer. -*/ -#[derive(Debug, Clone, Eq, PartialEq)] -pub struct WalletId(pub String); - -/** - Newtype wrapper for the address a wallet corresponds to. -*/ -#[derive(Debug, Clone, Eq, PartialEq)] -pub struct WalletAddress(pub String); - -/** - A wallet containing the information about the ID, address, - and also the public/private key information in the form of - [SigningKeyPair](ibc_relayer::keyring::SigningKeyPair). -*/ -#[derive(Debug, Clone)] -pub struct Wallet { - /// The ID of the wallet for accessing it from the key store. - pub id: WalletId, - - /// The address for receiving tokens for this wallet. - pub address: WalletAddress, - - // TODO: Parameterize this type on `SigningKeyPair` - /// The wallet key information in the form of `SigningKeyPair` - /// that is used by the relayer. - pub key: Secp256k1KeyPair, -} - -/** - A collection of wallets used for testing. We use an explicit - struct instead of a generic HashMap so that the retrieval - of a specific wallet can always succeed. We shouldn't need - more than the wallets listed here for testing purposes. - - In case we do need more wallets for testing, there shouldn't - be much overhead for adding a few more wallets here globally. - Alternatively the particular test that needs more wallets - can add new wallets in the test itself, or we can add - a HashMap here together with a - [`TestOverrides`](crate::framework::overrides::TestOverrides) - trait to generate additional wallets during test setup. -*/ -#[derive(Debug, Clone)] -pub struct TestWallets { - /// The validator wallet. - pub validator: Wallet, - - /// The relayer wallet. This is used by the relayer by default. - pub relayer: Wallet, - - /// The first user wallet that can be used for testing. - pub user1: Wallet, - - /// The second user wallet that can be used for testing. - pub user2: Wallet, -} - -/** - Extra methods for [`Wallet`] that is [tagged](crate::types::tagged). - - This trait is auto implemented for `MonoTagged` so - that we can call methods on it directly. -*/ -pub trait TaggedWallet { - /// Get the [`WalletId`] tagged with the given `Chain`. - fn id(&self) -> MonoTagged; - - /// Get the [`WalletAddress`] tagged with the given `Chain`. - fn address(&self) -> MonoTagged; - - /// Get the `SigningKeyPair` tagged with the given `Chain`. - fn key(&self) -> MonoTagged; -} - -/** - Extra methods for [`TestWallets`] that is [tagged](crate::types::tagged). - - This trait is auto implemented for `MonoTagged` so - that we can call methods on it directly. -*/ -pub trait TaggedTestWalletsExt { - /// Get the validator [`Wallet`] tagged with the given `Chain`. - fn validator(&self) -> MonoTagged; - - /// Get the relayer [`Wallet`] tagged with the given `Chain`. - fn relayer(&self) -> MonoTagged; - - /// Get the first user [`Wallet`] tagged with the given `Chain`. - fn user1(&self) -> MonoTagged; - - /// Get the second user [`Wallet`] tagged with the given `Chain`. - fn user2(&self) -> MonoTagged; -} - -impl Wallet { - /// Create a new [`Wallet`] - pub fn new(id: String, address: String, key: Secp256k1KeyPair) -> Self { - Self { - id: WalletId(id), - address: WalletAddress(address), - key, - } - } -} - -impl WalletAddress { - pub fn as_str(&self) -> &str { - self.0.as_str() - } -} - -impl TaggedWallet for MonoTagged { - fn id(&self) -> MonoTagged { - self.map_ref(|w| &w.id) - } - - fn address(&self) -> MonoTagged { - self.map_ref(|w| &w.address) - } - - fn key(&self) -> MonoTagged { - self.map_ref(|w| &w.key) - } -} - -impl TaggedWallet for MonoTagged { - fn id(&self) -> MonoTagged { - self.map_ref(|w| &w.id) - } - - fn address(&self) -> MonoTagged { - self.map_ref(|w| &w.address) - } - - fn key(&self) -> MonoTagged { - self.map_ref(|w| &w.key) - } -} - -impl TaggedTestWalletsExt for MonoTagged { - fn validator(&self) -> MonoTagged { - self.map_ref(|w| &w.validator) - } - - fn relayer(&self) -> MonoTagged { - self.map_ref(|w| &w.relayer) - } - - fn user1(&self) -> MonoTagged { - self.map_ref(|w| &w.user1) - } - - fn user2(&self) -> MonoTagged { - self.map_ref(|w| &w.user2) - } -} - -impl TaggedTestWalletsExt for MonoTagged { - fn validator(&self) -> MonoTagged { - self.map_ref(|w| &w.validator) - } - - fn relayer(&self) -> MonoTagged { - self.map_ref(|w| &w.relayer) - } - - fn user1(&self) -> MonoTagged { - self.map_ref(|w| &w.user1) - } - - fn user2(&self) -> MonoTagged { - self.map_ref(|w| &w.user2) - } -} - -impl ExportEnv for TestWallets { - fn export_env(&self, writer: &mut impl EnvWriter) { - self.validator - .export_env(&mut prefix_writer("VALIDATOR", writer)); - self.relayer - .export_env(&mut prefix_writer("RELAYER", writer)); - self.user1.export_env(&mut prefix_writer("USER1", writer)); - self.user2.export_env(&mut prefix_writer("USER2", writer)); - } -} - -impl ExportEnv for Wallet { - fn export_env(&self, writer: &mut impl EnvWriter) { - writer.write_env("KEY_ID", &self.id.0); - writer.write_env("ADDRESS", &self.address.0); - } -} - -impl Display for WalletId { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.0.fmt(f) - } -} - -impl Display for WalletAddress { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.0.fmt(f) - } -} diff --git a/tools/test-framework/src/util/array.rs b/tools/test-framework/src/util/array.rs deleted file mode 100644 index 9bb5ed686..000000000 --- a/tools/test-framework/src/util/array.rs +++ /dev/null @@ -1,88 +0,0 @@ -/*! - Helpers for manipulating fixed-sized arrays. -*/ - -use core::convert::TryInto; - -use eyre::eyre; - -use crate::error::Error; - -/** - Converts a dynamic-sized vector `Vec` into a fixed-sized array - `[T; SIZE]`. Fails if the vector is not the same length as `SIZE`. -*/ -pub fn try_into_array(list: Vec) -> Result<[T; SIZE], Error> { - list.try_into() - .map_err(|_| Error::generic(eyre!("vector is not of length {}", SIZE))) -} - -/** - Converts a dynamic-sized nested vector `Vec>` into a fixed-sized - nested array `[[T; SIZE]; SIZE]`. Fails if the nested vector is not of - `SIZE`x`SIZE` length. -*/ -pub fn try_into_nested_array( - list: Vec>, -) -> Result<[[T; SIZE]; SIZE], Error> { - let list_a = list - .into_iter() - .map(try_into_array) - .collect::, _>>()?; - - try_into_array(list_a) -} - -/** - Converts a fixed-sized nested array `[[T; SIZE]; SIZE]` into a nested - vector `Vec>`. -*/ -pub fn into_nested_vec(array: [[T; SIZE]; SIZE]) -> Vec> { - array.map(|array_b| array_b.into()).into() -} - -/** - Map the elements in the fixed-sized array `[[T; SIZE]; SIZE]`. -*/ -pub fn map_nested_array( - array: [[T; SIZE]; SIZE], - mapper: impl Fn(T) -> Result, -) -> Result<[[R; SIZE]; SIZE], Error> { - let mapped = into_nested_vec(array) - .into_iter() - .map(|inner| { - inner - .into_iter() - .map(&mapper) - .collect::, _>>() - }) - .collect::, _>>()?; - - try_into_nested_array(mapped) -} - -/** - Asserts that a nested vector `Vec>` has the same dimension - in its inner vectors. -*/ -pub fn assert_same_dimension(size: usize, list: &Vec>) -> Result<(), Error> { - if list.len() != size { - return Err(Error::generic(eyre!( - "expect nested vector to have the dimension {} x {}", - size, - size - ))); - } - - for list_b in list.iter() { - if list_b.len() != size { - return Err(Error::generic(eyre!( - "expect nested vector to have the dimension {} x {}", - size, - size - ))); - } - } - - Ok(()) -} diff --git a/tools/test-framework/src/util/assert.rs b/tools/test-framework/src/util/assert.rs deleted file mode 100644 index 33bbd1b57..000000000 --- a/tools/test-framework/src/util/assert.rs +++ /dev/null @@ -1,43 +0,0 @@ -use core::fmt::Debug; - -use crate::error::Error; - -pub fn assert_eq(message: &str, left: &T, right: &T) -> Result<(), Error> { - if left == right { - Ok(()) - } else { - Err(Error::assertion(format!( - "expect left ({left:?}) to be equal to right ({right:?}): {message}" - ))) - } -} - -pub fn assert_not_eq(message: &str, left: &T, right: &T) -> Result<(), Error> { - if left != right { - Ok(()) - } else { - Err(Error::assertion(format!( - "expect left ({left:?}) to be not equal to right ({right:?}): {message}" - ))) - } -} - -pub fn assert_gt(message: &str, left: &T, right: &T) -> Result<(), Error> { - if left > right { - Ok(()) - } else { - Err(Error::assertion(format!( - "expect left ({left:?}) to be greater than right ({right:?}): {message}" - ))) - } -} - -pub fn assert_err(message: &str, result: Result) -> Result<(), Error> { - if result.is_err() { - Ok(()) - } else { - Err(Error::assertion(format!( - "expect result ({result:?}) to be an error: {message}" - ))) - } -} diff --git a/tools/test-framework/src/util/file.rs b/tools/test-framework/src/util/file.rs deleted file mode 100644 index d238410f6..000000000 --- a/tools/test-framework/src/util/file.rs +++ /dev/null @@ -1,30 +0,0 @@ -/*! - Filesystem utilities. -*/ - -use std::{fs, io, thread}; - -use crate::error::Error; - -/** - Pipe a streaming source implementing [`std::io::Read`] to a file in - append mode. - - This is used to pipe log output from a full node's child process - to log files. -*/ -pub fn pipe_to_file( - mut source: impl io::Read + Send + 'static, - file_path: &str, -) -> Result<(), Error> { - let mut file = fs::OpenOptions::new() - .append(true) - .create(true) - .open(file_path)?; - - thread::spawn(move || { - std::io::copy(&mut source, &mut file).unwrap(); - }); - - Ok(()) -} diff --git a/tools/test-framework/src/util/interchain_security.rs b/tools/test-framework/src/util/interchain_security.rs deleted file mode 100644 index 5ada502d7..000000000 --- a/tools/test-framework/src/util/interchain_security.rs +++ /dev/null @@ -1,31 +0,0 @@ -use ibc_relayer::config::ChainConfig; - -use crate::chain::config::set_voting_period; -use crate::prelude::*; - -pub fn update_genesis_for_consumer_chain(genesis: &mut serde_json::Value) -> Result<(), Error> { - // Consumer chain doesn't have a gov key. - if genesis - .get_mut("app_state") - .and_then(|app_state| app_state.get("gov")) - .is_some() - { - set_voting_period(genesis, "10s")?; - } - Ok(()) -} - -pub fn update_relayer_config_for_consumer_chain(config: &mut Config) { - // The `ccv_consumer_chain` must be `true` for the Consumer chain. - // The `trusting_period` must be strictly smaller than the `unbonding_period` - // specified in the Consumer chain proposal. The test framework uses 100s in - // the proposal. - for chain_config in config.chains.iter_mut() { - let ChainConfig::CosmosSdk(sdk_config) = chain_config; - - if sdk_config.id == ChainId::from_string("ibcconsumer") { - sdk_config.ccv_consumer_chain = true; - sdk_config.trusting_period = Some(Duration::from_secs(99)); - } - } -} diff --git a/tools/test-framework/src/util/mod.rs b/tools/test-framework/src/util/mod.rs deleted file mode 100644 index bb1d92e67..000000000 --- a/tools/test-framework/src/util/mod.rs +++ /dev/null @@ -1,11 +0,0 @@ -/*! - Utility and helper functions used in the tests. -*/ - -pub mod array; -pub mod assert; -pub mod file; -pub mod interchain_security; -pub mod random; -pub mod retry; -pub mod suspend; diff --git a/tools/test-framework/src/util/random.rs b/tools/test-framework/src/util/random.rs deleted file mode 100644 index f66988504..000000000 --- a/tools/test-framework/src/util/random.rs +++ /dev/null @@ -1,69 +0,0 @@ -/*! - Utilities for random value generation. -*/ - -use std::collections::HashSet; -use std::net::{Ipv4Addr, SocketAddrV4, TcpListener}; -use std::sync::Mutex; - -use ibc_relayer_types::applications::transfer::amount::Amount; -use once_cell::sync::Lazy; -use rand::Rng; - -/// Generates a random `u32` value. -pub fn random_u32() -> u32 { - let mut rng = rand::thread_rng(); - rng.gen() -} - -/// Generates a random `u64` value. -pub fn random_u64() -> u64 { - let mut rng = rand::thread_rng(); - rng.gen() -} - -pub fn random_u128() -> u128 { - let mut rng = rand::thread_rng(); - rng.gen() -} - -/// Generates a random `u64` value between the given min and max. -pub fn random_u64_range(min: u64, max: u64) -> u64 { - let mut rng = rand::thread_rng(); - rng.gen_range(min..max) -} - -/// Generates a random `u128` value between the given min and max. -pub fn random_u128_range(min: u128, max: u128) -> u128 { - let mut rng = rand::thread_rng(); - rng.gen_range(min..max) -} - -pub fn random_amount_range(min: u128, max: u128) -> Amount { - let mut rng = rand::thread_rng(); - rng.gen_range(min..max).into() -} - -/// Generates a random string value, in the form of `u64` hex for simplicity. -pub fn random_string() -> String { - format!("{:x}", random_u64()) -} - -/// Generates a random non-privileged port that is greater than 1024. -fn random_port() -> u16 { - let mut rng = rand::thread_rng(); - rng.gen_range(1024..=u16::MAX) -} - -/// Find a random unused non-privileged TCP port. -pub fn random_unused_tcp_port() -> u16 { - static ALLOCATED_PORTS: Lazy>> = Lazy::new(|| Mutex::new(HashSet::new())); - - let port = random_port(); - let loopback = Ipv4Addr::new(127, 0, 0, 1); - let address = SocketAddrV4::new(loopback, port); - match TcpListener::bind(address) { - Ok(_) if ALLOCATED_PORTS.lock().unwrap().insert(port) => port, - _ => random_unused_tcp_port(), - } -} diff --git a/tools/test-framework/src/util/retry.rs b/tools/test-framework/src/util/retry.rs deleted file mode 100644 index 27509c706..000000000 --- a/tools/test-framework/src/util/retry.rs +++ /dev/null @@ -1,39 +0,0 @@ -/*! - Utilities for retrying test operations. -*/ - -use core::time::Duration; -use std::thread::sleep; - -use tracing::{info, trace}; - -use crate::error::Error; - -/** - A simplified version of retry logic used for testing. - We do not need complicated retry logic as we need this - only to test eventual consistency which should reach - within a few seconds. -*/ -pub fn assert_eventually_succeed( - task_name: &str, - attempts: u16, - interval: Duration, - task: impl Fn() -> Result, -) -> Result { - sleep(interval); - for i in 0..attempts { - match task() { - Ok(res) => { - info!("task {} succeed after {} tries", task_name, i); - return Ok(res); - } - Err(e) => { - trace!("retrying task {} that failed with error: {}", task_name, e); - sleep(interval) - } - } - } - - Err(Error::retry(task_name.to_string(), attempts)) -} diff --git a/tools/test-framework/src/util/suspend.rs b/tools/test-framework/src/util/suspend.rs deleted file mode 100644 index 578d32c45..000000000 --- a/tools/test-framework/src/util/suspend.rs +++ /dev/null @@ -1,69 +0,0 @@ -/*! - Utilities for suspending the test. -*/ - -use core::time::Duration; -use std::panic::{catch_unwind, resume_unwind, AssertUnwindSafe}; -use std::thread::sleep; - -use tracing::{error, warn}; - -use crate::error::Error; - -/** - Call this function in the middle of a test code of interest, - so that we can suspend the test and still interact with the - spawned Gaia chains and chain supervisor for debugging. -*/ -pub fn suspend() -> R { - warn!("suspending the test indefinitely. you can still interact with any spawned chains and relayers"); - - loop { - sleep(Duration::from_secs(999_999_999)) - } -} - -/** - Suspends the test using [`suspend`] if `hang_on_fail` is `true` and if - the continuation returns `Err`. - - The parameter `hang_on_fail` should be obtained from - [`TestConfig`](crate::types::config::TestConfig), - which in turns is set from the `HANG_ON_FAIL` environment variable. -*/ -pub fn hang_on_error( - hang_on_fail: bool, - cont: impl FnOnce() -> Result, -) -> Result { - let result = catch_unwind(AssertUnwindSafe(cont)); - - match result { - Err(e) => { - if hang_on_fail { - let message = e.downcast::<&str>().ok(); - error!("test panicked with HANG_ON_FAIL=1, suspending the test to allow debugging: {:?}", - message); - - suspend() - } else { - error!("test panicked. set HANG_ON_FAIL=1 to suspend the test on failure for debugging."); - - resume_unwind(e) - } - } - Ok(Err(e)) => { - if hang_on_fail { - error!("test failure occured with HANG_ON_FAIL=1, suspending the test to allow debugging: {:?}", - e); - - suspend() - } else { - error!("test failure occured. set HANG_ON_FAIL=1 to suspend the test on failure for debugging: {:?}", - e); - - Err(e) - } - } - Ok(Ok(res)) => Ok(res), - } -}