From dc2006359fcc249454f832f9a7ec4708c10ecd1e Mon Sep 17 00:00:00 2001 From: Luca Joss Date: Tue, 27 Jun 2023 17:37:32 +0200 Subject: [PATCH 1/6] Add producer consumer chain bootstrap and a template test --- tools/integration-test/Cargo.toml | 1 + .../src/tests/interchain_security.rs | 58 +++++++ tools/integration-test/src/tests/mod.rs | 3 + .../src/bootstrap/binary/chain.rs | 4 +- .../test-framework/src/bootstrap/consumer.rs | 162 ++++++++++++++++++ tools/test-framework/src/bootstrap/mod.rs | 1 + tools/test-framework/src/chain/chain_type.rs | 2 +- tools/test-framework/src/chain/cli/mod.rs | 1 + .../test-framework/src/chain/cli/provider.rs | 87 ++++++++++ tools/test-framework/src/chain/config.rs | 2 +- .../test-framework/src/chain/ext/bootstrap.rs | 62 ++++++- .../src/framework/binary/chain.rs | 95 ++++++++++ .../src/framework/binary/channel.rs | 23 +++ .../src/framework/binary/ics.rs | 117 +++++++++++++ .../src/framework/binary/mod.rs | 1 + 15 files changed, 615 insertions(+), 4 deletions(-) create mode 100644 tools/integration-test/src/tests/interchain_security.rs create mode 100644 tools/test-framework/src/bootstrap/consumer.rs create mode 100644 tools/test-framework/src/chain/cli/provider.rs create mode 100644 tools/test-framework/src/framework/binary/ics.rs diff --git a/tools/integration-test/Cargo.toml b/tools/integration-test/Cargo.toml index f126e8bc1b..d5d9781bc5 100644 --- a/tools/integration-test/Cargo.toml +++ b/tools/integration-test/Cargo.toml @@ -38,6 +38,7 @@ forward-packet = [] ics31 = [] clean-workers = [] fee-grant = [] +interchain-security = [] [[bin]] name = "test_setup_with_binary_channel" diff --git a/tools/integration-test/src/tests/interchain_security.rs b/tools/integration-test/src/tests/interchain_security.rs new file mode 100644 index 0000000000..03f7790f7e --- /dev/null +++ b/tools/integration-test/src/tests/interchain_security.rs @@ -0,0 +1,58 @@ +//! The following tests are for the Cross-chain Queries, ICS31. +//! These tests require the first chain to be a Gaia chain and +//! the second chain a Stride chain. Only the Stride chain requires +//! to have the ICS31 enabled. +//! +//! The test `ICS31Test` registers the cosmos account as a host-zone +//! using `strided tx stakeibc register-host-zone` in order to have +//! the Stride chain trigger Cross-chain Queries. +//! The test then waits for a Cross-chain Query to be pending and +//! then processed. +use std::thread; + +use ibc_test_framework::chain::config::set_voting_period; +use ibc_test_framework::framework::binary::channel::run_binary_interchain_security_channel_test; +use ibc_test_framework::prelude::*; + +#[test] +fn test_ics31_cross_chain_queries() -> Result<(), Error> { + run_binary_interchain_security_channel_test(&InterchainSecurityTest) +} + +struct InterchainSecurityTest; + +impl TestOverrides for InterchainSecurityTest { + fn modify_genesis_file(&self, 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(()) + } + + fn modify_relayer_config(&self, config: &mut Config) { + for chain_config in config.chains.iter_mut() { + if chain_config.id == ChainId::from_string("ibcconsumer") { + chain_config.ccv_consumer_chain = true; + chain_config.trusting_period = Some(Duration::from_secs(99)); + } + } + } +} + +impl BinaryChannelTest for InterchainSecurityTest { + fn run( + &self, + _config: &TestConfig, + _relayer: RelayerDriver, + _chains: ConnectedChains, + _channel: ConnectedChannel, + ) -> Result<(), Error> { + thread::sleep(Duration::from_secs(1)); + Ok(()) + } +} diff --git a/tools/integration-test/src/tests/mod.rs b/tools/integration-test/src/tests/mod.rs index 9a2eaa3734..57526ac08b 100644 --- a/tools/integration-test/src/tests/mod.rs +++ b/tools/integration-test/src/tests/mod.rs @@ -54,3 +54,6 @@ pub mod clean_workers; #[cfg(any(doc, feature = "fee-grant"))] pub mod fee_grant; + +#[cfg(any(doc, feature = "interchain-security"))] +pub mod interchain_security; diff --git a/tools/test-framework/src/bootstrap/binary/chain.rs b/tools/test-framework/src/bootstrap/binary/chain.rs index 5ec10402d2..f80336b1c7 100644 --- a/tools/test-framework/src/bootstrap/binary/chain.rs +++ b/tools/test-framework/src/bootstrap/binary/chain.rs @@ -13,8 +13,9 @@ use ibc_relayer::foreign_client::{ use ibc_relayer::keyring::errors::ErrorDetail as KeyringErrorDetail; use ibc_relayer::registry::SharedRegistry; use ibc_relayer_types::core::ics24_host::identifier::ClientId; -use std::fs; use std::path::Path; +use std::time::Duration; +use std::{fs, thread}; use tracing::{debug, info}; use crate::relayer::driver::RelayerDriver; @@ -71,6 +72,7 @@ pub fn bootstrap_chains_with_full_nodes( // 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)?; + 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)?; diff --git a/tools/test-framework/src/bootstrap/consumer.rs b/tools/test-framework/src/bootstrap/consumer.rs new file mode 100644 index 0000000000..53e3592d4b --- /dev/null +++ b/tools/test-framework/src/bootstrap/consumer.rs @@ -0,0 +1,162 @@ +/*! +Helper functions for bootstrapping a consumer full node. +*/ +use eyre::eyre; +use std::sync::{Arc, RwLock}; +use std::thread; +use std::time::Duration; +use toml; +use tracing::info; + +use crate::chain::builder::ChainBuilder; +use crate::chain::cli::provider::{jq_exp, query_consumer_genesis}; +use crate::chain::config; +use crate::chain::exec::simple_exec; +use crate::chain::ext::bootstrap::ChainBootstrapMethodsExt; +use crate::error::Error; +use crate::prelude::{ChainDriver, Denom, FullNode, TestWallets, Token}; +use crate::types::wallet::Wallet; +use crate::util::random::{random_u128_range, random_u32}; + +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 = add_wallet(&chain_driver, "validator", false)?; + let relayer = add_wallet(&chain_driver, "relayer", false)?; + let user1 = add_wallet(&chain_driver, "user1", false)?; + let user2 = add_wallet(&chain_driver, "user2", false)?; + + 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(10)); + + query_consumer_genesis( + &chain_driver, + 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(), + chain_driver.chain_id.as_str(), + )?; + + jq_exp( + &chain_driver, + &chain_driver.home_path, + node_a.chain_driver.chain_id.as_str(), + )?; + + chain_driver.update_genesis_file("genesis.json", genesis_modifier)?; + + 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(()) + })?; + + simple_exec( + chain_driver.chain_id.as_str(), + "cp", + &[ + &format!( + "{}/config/priv_validator_key.json", + provider_chain_driver.home_path + ), + &format!("{}/config/priv_validator_key.json", chain_driver.home_path), + ], + )?; + + 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) +} + +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/bootstrap/mod.rs b/tools/test-framework/src/bootstrap/mod.rs index 96a1e6de5f..17216d9455 100644 --- a/tools/test-framework/src/bootstrap/mod.rs +++ b/tools/test-framework/src/bootstrap/mod.rs @@ -12,6 +12,7 @@ */ pub mod binary; +pub mod consumer; pub mod init; pub mod nary; pub mod single; diff --git a/tools/test-framework/src/chain/chain_type.rs b/tools/test-framework/src/chain/chain_type.rs index 5f52fabf57..2d39f8f811 100644 --- a/tools/test-framework/src/chain/chain_type.rs +++ b/tools/test-framework/src/chain/chain_type.rs @@ -28,7 +28,7 @@ impl ChainType { if use_random_id { ChainId::from_string(&format!("ibc-{}-{:x}", prefix, random_u32())) } else { - ChainId::from_string(&format!("ibc-{prefix}")) + ChainId::from_string(&format!("ibc{prefix}")) } } Self::Evmos => ChainId::from_string(&format!("evmos_9000-{prefix}")), diff --git a/tools/test-framework/src/chain/cli/mod.rs b/tools/test-framework/src/chain/cli/mod.rs index 40c1d1aa17..88ac42bf9e 100644 --- a/tools/test-framework/src/chain/cli/mod.rs +++ b/tools/test-framework/src/chain/cli/mod.rs @@ -2,6 +2,7 @@ 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; diff --git a/tools/test-framework/src/chain/cli/provider.rs b/tools/test-framework/src/chain/cli/provider.rs new file mode 100644 index 0000000000..dc920c95e7 --- /dev/null +++ b/tools/test-framework/src/chain/cli/provider.rs @@ -0,0 +1,87 @@ +use std::str; + +use crate::chain::driver::ChainDriver; +use crate::chain::exec::simple_exec; +use crate::chain::ext::bootstrap::ChainBootstrapMethodsExt; +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_driver: &ChainDriver, + chain_id: &str, + command_path: &str, + home_path: &str, + rpc_listen_address: &str, + consumer_chain_id: &str, +) -> Result<(), Error> { + 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", + ], + )?; + + chain_driver.write_file("config/consumer_genesis.json", &exec_output.stdout)?; + + Ok(()) +} + +pub fn jq_exp(chain_driver: &ChainDriver, home_path: &str, chain_id: &str) -> Result<(), Error> { + 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), + ], + )?; + + chain_driver.write_file("config/genesis.json", &exec_output.stdout)?; + + Ok(()) +} diff --git a/tools/test-framework/src/chain/config.rs b/tools/test-framework/src/chain/config.rs index f0b6a8e385..6e5c9215b8 100644 --- a/tools/test-framework/src/chain/config.rs +++ b/tools/test-framework/src/chain/config.rs @@ -248,7 +248,7 @@ pub fn set_voting_period(genesis: &mut serde_json::Value, period: &str) -> Resul .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 update voting_period in genesis file"))?; + .ok_or_else(|| eyre!("failed to get voting_params in genesis file"))?; voting_period .insert( diff --git a/tools/test-framework/src/chain/ext/bootstrap.rs b/tools/test-framework/src/chain/ext/bootstrap.rs index e3593473ea..4ac94cd149 100644 --- a/tools/test-framework/src/chain/ext/bootstrap.rs +++ b/tools/test-framework/src/chain/ext/bootstrap.rs @@ -1,5 +1,4 @@ use core::str::FromStr; - use eyre::eyre; use hdpath::StandardHDPath; use serde_json as json; @@ -15,7 +14,9 @@ use crate::chain::cli::bootstrap::{ add_genesis_account, add_genesis_validator, add_wallet, collect_gen_txs, initialize, start_chain, }; +use crate::chain::cli::provider::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; @@ -93,6 +94,15 @@ pub trait ChainBootstrapMethodsExt { 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>; } impl ChainBootstrapMethodsExt for ChainDriver { @@ -221,4 +231,54 @@ impl ChainBootstrapMethodsExt for ChainDriver { .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(), + ) + } } diff --git a/tools/test-framework/src/framework/binary/chain.rs b/tools/test-framework/src/framework/binary/chain.rs index fb7d0649d9..aa79ad5113 100644 --- a/tools/test-framework/src/framework/binary/chain.rs +++ b/tools/test-framework/src/framework/binary/chain.rs @@ -11,6 +11,7 @@ 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, @@ -141,6 +142,21 @@ pub struct RunBinaryChainTest<'a, Test> { pub test: &'a Test, } +pub struct RunBinaryChainFromInterchainSecurityTest<'a, Test> { + /// Inner test + pub test: &'a Test, +} + +impl<'a, Test> RunBinaryChainFromInterchainSecurityTest<'a, Test> +where + Test: BinaryChainTest, +{ + /// Create a new [`RunBinaryChainTest`] + pub fn new(test: &'a Test) -> Self { + Self { test } + } +} + /** A wrapper type that lifts a test case that implements [`BinaryChainTest`] into a test case the implements [`BinaryChainTest`]. @@ -175,6 +191,46 @@ where } } +impl<'a, Test, Overrides> InterchainSecurityChainTest + for RunBinaryChainFromInterchainSecurityTest<'a, 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<'a, Test> RunTwoWayBinaryChainTest<'a, Test> where Test: BinaryChainTest, @@ -234,6 +290,45 @@ where } } +impl<'a, Test, Overrides> InterchainSecurityChainTest for RunBinaryChainTest<'a, 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<'a, Test: BinaryChainTest> BinaryChainTest for RunTwoWayBinaryChainTest<'a, Test> { fn run( &self, diff --git a/tools/test-framework/src/framework/binary/channel.rs b/tools/test-framework/src/framework/binary/channel.rs index 7380249464..00ae9efd89 100644 --- a/tools/test-framework/src/framework/binary/channel.rs +++ b/tools/test-framework/src/framework/binary/channel.rs @@ -22,6 +22,7 @@ use crate::framework::binary::chain::{ 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, }; @@ -81,6 +82,28 @@ where ))) } +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 diff --git a/tools/test-framework/src/framework/binary/ics.rs b/tools/test-framework/src/framework/binary/ics.rs new file mode 100644 index 0000000000..b4d5658bdb --- /dev/null +++ b/tools/test-framework/src/framework/binary/ics.rs @@ -0,0 +1,117 @@ +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 [`BinaryNodeTest`]. +*/ +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<'a, Test, Overrides> BasicTest for RunInterchainSecurityChainTest<'a, Test> +where + Test: InterchainSecurityChainTest, + Test: HasOverrides, + Overrides: NodeConfigOverride + NodeGenesisOverride, +{ + fn run(&self, config: &TestConfig, builder: &ChainBuilder) -> Result<(), Error> { + // Bootstrap producer + let node_a = bootstrap_single_node( + builder, + "producer", + 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(1)); + + 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(1)); + + 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<'a, Test, Overrides> HasOverrides for RunInterchainSecurityChainTest<'a, 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 index b0b9ecdf16..38e9dd4550 100644 --- a/tools/test-framework/src/framework/binary/mod.rs +++ b/tools/test-framework/src/framework/binary/mod.rs @@ -5,4 +5,5 @@ pub mod chain; pub mod channel; pub mod connection; +pub mod ics; pub mod node; From f955fb6132f594191ae5d285398461230fbd81bd Mon Sep 17 00:00:00 2001 From: Luca Joss Date: Wed, 28 Jun 2023 10:43:40 +0200 Subject: [PATCH 2/6] Fix ICS test to work with Gaia/Neutron and added a simple transfer in the test --- .../src/tests/interchain_security.rs | 107 +++++++++++++++++- .../test-framework/src/bootstrap/consumer.rs | 6 + tools/test-framework/src/chain/config.rs | 20 ++++ 3 files changed, 127 insertions(+), 6 deletions(-) diff --git a/tools/integration-test/src/tests/interchain_security.rs b/tools/integration-test/src/tests/interchain_security.rs index 03f7790f7e..ce198f4766 100644 --- a/tools/integration-test/src/tests/interchain_security.rs +++ b/tools/integration-test/src/tests/interchain_security.rs @@ -8,14 +8,13 @@ //! the Stride chain trigger Cross-chain Queries. //! The test then waits for a Cross-chain Query to be pending and //! then processed. -use std::thread; - use ibc_test_framework::chain::config::set_voting_period; use ibc_test_framework::framework::binary::channel::run_binary_interchain_security_channel_test; use ibc_test_framework::prelude::*; +use ibc_test_framework::util::random::random_u128_range; #[test] -fn test_ics31_cross_chain_queries() -> Result<(), Error> { +fn test_ics_transfer() -> Result<(), Error> { run_binary_interchain_security_channel_test(&InterchainSecurityTest) } @@ -49,10 +48,106 @@ impl BinaryChannelTest for InterchainSecurityTest { &self, _config: &TestConfig, _relayer: RelayerDriver, - _chains: ConnectedChains, - _channel: ConnectedChannel, + chains: ConnectedChains, + channel: ConnectedChannel, ) -> Result<(), Error> { - thread::sleep(Duration::from_secs(1)); + 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_u128_range(1000, 5000); + + info!( + "Sending IBC transfer from chain {} to chain {} with: channel id {}, port id {} and amount of {} {}", + chains.chain_id_a(), + chains.chain_id_b(), + channel.channel_id_a.to_string(), + channel.port_a.to_string(), + 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 + ); + + 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_u128_range(500, a_to_b_amount); + + info!( + "Sending IBC transfer from chain {} to chain {} with: channel id {}, port id {} and amount of {}", + chains.chain_id_b(), + chains.chain_id_a(), + channel.channel_id_b.to_string(), + channel.port_b.to_string(), + 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(), + )?; + + 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(), + ); Ok(()) } } diff --git a/tools/test-framework/src/bootstrap/consumer.rs b/tools/test-framework/src/bootstrap/consumer.rs index 53e3592d4b..fbe329c4b5 100644 --- a/tools/test-framework/src/bootstrap/consumer.rs +++ b/tools/test-framework/src/bootstrap/consumer.rs @@ -75,6 +75,12 @@ pub fn bootstrap_consumer_node( )?; 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()); diff --git a/tools/test-framework/src/chain/config.rs b/tools/test-framework/src/chain/config.rs index 6e5c9215b8..617485e04a 100644 --- a/tools/test-framework/src/chain/config.rs +++ b/tools/test-framework/src/chain/config.rs @@ -260,6 +260,26 @@ pub fn set_voting_period(genesis: &mut serde_json::Value, period: &str) -> Resul 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 From 6f09f2c0560c77cc89030dae1d693c5f4f89a542 Mon Sep 17 00:00:00 2001 From: Luca Joss Date: Wed, 28 Jun 2023 11:37:23 +0200 Subject: [PATCH 3/6] Add CI job to run interchain-security tests --- .github/workflows/integration.yaml | 40 ++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/.github/workflows/integration.yaml b/.github/workflows/integration.yaml index 341284c4b3..761752834e 100644 --- a/.github/workflows/integration.yaml +++ b/.github/workflows/integration.yaml @@ -406,6 +406,46 @@ jobs: test -p ibc-integration-test --features clean-workers --no-fail-fast -- \ --nocapture --test-threads=1 clean_workers:: + interchain-security: + runs-on: ubuntu-20.04 + strategy: + fail-fast: false + matrix: + chain: + - package: neutron + command: neutrond + account_prefix: neutron + steps: + - uses: actions/checkout@v3 + - uses: cachix/install-nix-action@v22 + with: + install_url: https://nixos-nix-install-tests.cachix.org/serve/vij683ly7sl95nnhb67bdjjfabclr85m/install + install_options: '--tarball-url-prefix https://nixos-nix-install-tests.cachix.org/serve' + extra_nix_config: | + experimental-features = nix-command flakes + - uses: cachix/cachix-action@v12 + with: + name: cosmos + - uses: actions-rs/toolchain@v1 + with: + toolchain: stable + override: true + - uses: Swatinem/rust-cache@v1 + - uses: actions-rs/cargo@v1 + with: + command: test + args: -p ibc-integration-test --features interchain-security --no-fail-fast --no-run + - env: + RUST_LOG: info + RUST_BACKTRACE: 1 + NO_COLOR_LOG: 1 + CHAIN_COMMAND_PATHS: gaiad,${{ matrix.chain.command }} + ACCOUNT_PREFIXES: cosmos,${{ matrix.chain.account_prefix }} + run: | + nix shell .#gaia9 .#${{ matrix.chain.package }} -c cargo \ + test -p ibc-integration-test --features interchain-security --no-fail-fast -- \ + --nocapture --test-threads=1 interchain_security:: + model-based-test: runs-on: ubuntu-20.04 timeout-minutes: 60 From 033720836984fd1651e407b2eb3bdace43a047ce Mon Sep 17 00:00:00 2001 From: Luca Joss Date: Wed, 28 Jun 2023 11:47:16 +0200 Subject: [PATCH 4/6] Add Neutron to flake.nix --- flake.nix | 1 + 1 file changed, 1 insertion(+) diff --git a/flake.nix b/flake.nix index 1d56d7ec7f..10c95e8a04 100644 --- a/flake.nix +++ b/flake.nix @@ -49,6 +49,7 @@ stride stride-no-admin migaloo + neutron ; python = nixpkgs.python3.withPackages (p: [ From ca573b920c31f7f3564196d0b6e42d6f861d2a1e Mon Sep 17 00:00:00 2001 From: Luca Joss Date: Wed, 28 Jun 2023 12:38:41 +0200 Subject: [PATCH 5/6] Clean ICS test bootstrap --- .../src/tests/interchain_security.rs | 17 +++--- .../src/bootstrap/binary/chain.rs | 2 + .../test-framework/src/bootstrap/consumer.rs | 54 ++++------------- .../test-framework/src/chain/cli/provider.rs | 28 ++++++--- .../test-framework/src/chain/ext/bootstrap.rs | 58 ++++++++++++++++++- .../src/framework/binary/chain.rs | 55 ------------------ .../src/framework/binary/ics.rs | 6 +- 7 files changed, 99 insertions(+), 121 deletions(-) diff --git a/tools/integration-test/src/tests/interchain_security.rs b/tools/integration-test/src/tests/interchain_security.rs index ce198f4766..bcc531743f 100644 --- a/tools/integration-test/src/tests/interchain_security.rs +++ b/tools/integration-test/src/tests/interchain_security.rs @@ -1,13 +1,6 @@ -//! The following tests are for the Cross-chain Queries, ICS31. -//! These tests require the first chain to be a Gaia chain and -//! the second chain a Stride chain. Only the Stride chain requires -//! to have the ICS31 enabled. -//! -//! The test `ICS31Test` registers the cosmos account as a host-zone -//! using `strided tx stakeibc register-host-zone` in order to have -//! the Stride chain trigger Cross-chain Queries. -//! The test then waits for a Cross-chain Query to be pending and -//! then processed. +//! The following tests are for the Interchain Security. +//! These tests require the first chain to be a Producer chain and +//! the second chain a Consumer chain. use ibc_test_framework::chain::config::set_voting_period; use ibc_test_framework::framework::binary::channel::run_binary_interchain_security_channel_test; use ibc_test_framework::prelude::*; @@ -33,6 +26,10 @@ impl TestOverrides for InterchainSecurityTest { Ok(()) } + // 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. fn modify_relayer_config(&self, config: &mut Config) { for chain_config in config.chains.iter_mut() { if chain_config.id == ChainId::from_string("ibcconsumer") { diff --git a/tools/test-framework/src/bootstrap/binary/chain.rs b/tools/test-framework/src/bootstrap/binary/chain.rs index f80336b1c7..386e743b28 100644 --- a/tools/test-framework/src/bootstrap/binary/chain.rs +++ b/tools/test-framework/src/bootstrap/binary/chain.rs @@ -72,6 +72,8 @@ pub fn bootstrap_chains_with_full_nodes( // 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)?; diff --git a/tools/test-framework/src/bootstrap/consumer.rs b/tools/test-framework/src/bootstrap/consumer.rs index fbe329c4b5..6a7c1a4d5c 100644 --- a/tools/test-framework/src/bootstrap/consumer.rs +++ b/tools/test-framework/src/bootstrap/consumer.rs @@ -9,14 +9,11 @@ use toml; use tracing::info; use crate::chain::builder::ChainBuilder; -use crate::chain::cli::provider::{jq_exp, query_consumer_genesis}; use crate::chain::config; -use crate::chain::exec::simple_exec; use crate::chain::ext::bootstrap::ChainBootstrapMethodsExt; use crate::error::Error; use crate::prelude::{ChainDriver, Denom, FullNode, TestWallets, Token}; -use crate::types::wallet::Wallet; -use crate::util::random::{random_u128_range, random_u32}; +use crate::util::random::random_u128_range; pub fn bootstrap_consumer_node( builder: &ChainBuilder, @@ -46,10 +43,10 @@ pub fn bootstrap_consumer_node( chain_driver.initialize()?; - let validator = add_wallet(&chain_driver, "validator", false)?; - let relayer = add_wallet(&chain_driver, "relayer", false)?; - let user1 = add_wallet(&chain_driver, "user1", false)?; - let user2 = add_wallet(&chain_driver, "user2", false)?; + 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])?; @@ -59,20 +56,11 @@ pub fn bootstrap_consumer_node( // Wait for the consumer chain to be initialized before querying the genesis thread::sleep(Duration::from_secs(10)); - query_consumer_genesis( - &chain_driver, - 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(), - chain_driver.chain_id.as_str(), - )?; - - jq_exp( - &chain_driver, - &chain_driver.home_path, - node_a.chain_driver.chain_id.as_str(), - )?; + 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 @@ -107,17 +95,7 @@ pub fn bootstrap_consumer_node( Ok(()) })?; - simple_exec( - chain_driver.chain_id.as_str(), - "cp", - &[ - &format!( - "{}/config/priv_validator_key.json", - provider_chain_driver.home_path - ), - &format!("{}/config/priv_validator_key.json", chain_driver.home_path), - ], - )?; + chain_driver.copy_validator_key_pair(provider_chain_driver)?; let process = chain_driver.start()?; @@ -156,13 +134,3 @@ pub fn bootstrap_consumer_node( 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/cli/provider.rs b/tools/test-framework/src/chain/cli/provider.rs index dc920c95e7..b4c44dd672 100644 --- a/tools/test-framework/src/chain/cli/provider.rs +++ b/tools/test-framework/src/chain/cli/provider.rs @@ -1,8 +1,6 @@ use std::str; -use crate::chain::driver::ChainDriver; use crate::chain::exec::simple_exec; -use crate::chain::ext::bootstrap::ChainBootstrapMethodsExt; use crate::error::Error; pub fn submit_consumer_chain_proposal( @@ -40,13 +38,12 @@ pub fn submit_consumer_chain_proposal( } pub fn query_consumer_genesis( - chain_driver: &ChainDriver, chain_id: &str, command_path: &str, home_path: &str, rpc_listen_address: &str, consumer_chain_id: &str, -) -> Result<(), Error> { +) -> Result { let exec_output = simple_exec( chain_id, command_path, @@ -64,12 +61,10 @@ pub fn query_consumer_genesis( ], )?; - chain_driver.write_file("config/consumer_genesis.json", &exec_output.stdout)?; - - Ok(()) + Ok(exec_output.stdout) } -pub fn jq_exp(chain_driver: &ChainDriver, home_path: &str, chain_id: &str) -> Result<(), Error> { +pub fn replace_genesis_state(chain_id: &str, home_path: &str) -> Result { let exec_output = simple_exec( chain_id, "jq", @@ -81,7 +76,22 @@ pub fn jq_exp(chain_driver: &ChainDriver, home_path: &str, chain_id: &str) -> Re ], )?; - chain_driver.write_file("config/genesis.json", &exec_output.stdout)?; + 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/ext/bootstrap.rs b/tools/test-framework/src/chain/ext/bootstrap.rs index 4ac94cd149..8e0dee8e35 100644 --- a/tools/test-framework/src/chain/ext/bootstrap.rs +++ b/tools/test-framework/src/chain/ext/bootstrap.rs @@ -14,7 +14,10 @@ use crate::chain::cli::bootstrap::{ add_genesis_account, add_genesis_validator, add_wallet, collect_gen_txs, initialize, start_chain, }; -use crate::chain::cli::provider::submit_consumer_chain_proposal; +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}; @@ -103,6 +106,25 @@ pub trait ChainBootstrapMethodsExt { 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 { @@ -281,4 +303,38 @@ impl ChainBootstrapMethodsExt for ChainDriver { &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/framework/binary/chain.rs b/tools/test-framework/src/framework/binary/chain.rs index aa79ad5113..a1a3aae940 100644 --- a/tools/test-framework/src/framework/binary/chain.rs +++ b/tools/test-framework/src/framework/binary/chain.rs @@ -142,21 +142,6 @@ pub struct RunBinaryChainTest<'a, Test> { pub test: &'a Test, } -pub struct RunBinaryChainFromInterchainSecurityTest<'a, Test> { - /// Inner test - pub test: &'a Test, -} - -impl<'a, Test> RunBinaryChainFromInterchainSecurityTest<'a, Test> -where - Test: BinaryChainTest, -{ - /// Create a new [`RunBinaryChainTest`] - pub fn new(test: &'a Test) -> Self { - Self { test } - } -} - /** A wrapper type that lifts a test case that implements [`BinaryChainTest`] into a test case the implements [`BinaryChainTest`]. @@ -191,46 +176,6 @@ where } } -impl<'a, Test, Overrides> InterchainSecurityChainTest - for RunBinaryChainFromInterchainSecurityTest<'a, 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<'a, Test> RunTwoWayBinaryChainTest<'a, Test> where Test: BinaryChainTest, diff --git a/tools/test-framework/src/framework/binary/ics.rs b/tools/test-framework/src/framework/binary/ics.rs index b4d5658bdb..37ad7f08ad 100644 --- a/tools/test-framework/src/framework/binary/ics.rs +++ b/tools/test-framework/src/framework/binary/ics.rs @@ -32,7 +32,7 @@ pub trait InterchainSecurityChainTest { /** A wrapper type that lifts a test case that implements [`InterchainSecurityChainTest`] - into a test case the implements [`BinaryNodeTest`]. + into a test case the implements [`BasicTest`]. */ pub struct RunInterchainSecurityChainTest<'a, Test> { /// Inner test @@ -56,10 +56,10 @@ where Overrides: NodeConfigOverride + NodeGenesisOverride, { fn run(&self, config: &TestConfig, builder: &ChainBuilder) -> Result<(), Error> { - // Bootstrap producer + // Bootstrap provider let node_a = bootstrap_single_node( builder, - "producer", + "provider", false, |config| self.test.get_overrides().modify_node_config(config), |genesis| self.test.get_overrides().modify_genesis_file(genesis), From 2a102e37005db01cb94fbe933080e1bf0c5a69cf Mon Sep 17 00:00:00 2001 From: Luca Joss Date: Wed, 28 Jun 2023 12:46:46 +0200 Subject: [PATCH 6/6] Add changelog entry --- .../ibc-integration-test/3450-bootstrap-ics-tests.md | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 .changelog/unreleased/features/ibc-integration-test/3450-bootstrap-ics-tests.md diff --git a/.changelog/unreleased/features/ibc-integration-test/3450-bootstrap-ics-tests.md b/.changelog/unreleased/features/ibc-integration-test/3450-bootstrap-ics-tests.md new file mode 100644 index 0000000000..5ec5270457 --- /dev/null +++ b/.changelog/unreleased/features/ibc-integration-test/3450-bootstrap-ics-tests.md @@ -0,0 +1,6 @@ +- Add a new trait `InterchainSecurityChainTest` and two functions + `run_binary_interchain_security_node_test` and `run_binary_interchain_security_channel_test` + which can be used to bootstrap a Provider and Consumer chain for integration tests. + Add a CI job to run tests with Gaia as a provider chain and Neutron as a Consumer chain. + ([\#3450](https://github.com/informalsystems/hermes/issues/3450)) + ([\#3387](https://github.com/informalsystems/hermes/issues/3387)) \ No newline at end of file