Skip to content

Commit

Permalink
Improve SDK test bootstrap and add packet clearing test
Browse files Browse the repository at this point in the history
  • Loading branch information
ljoss17 committed Nov 8, 2024
1 parent 48911da commit 3e6bc7c
Show file tree
Hide file tree
Showing 4 changed files with 366 additions and 171 deletions.
196 changes: 196 additions & 0 deletions tools/sdk-integration-test/src/tests/bootstrap.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,196 @@
use alloc::collections::btree_map::BTreeMap as HashMap;
use core::time::Duration;
use hermes_cosmos_integration_tests::contexts::binary_channel::test_driver::CosmosBinaryChannelTestDriver;
use std::env;
use std::fs;
use std::future::Future;
use std::pin::Pin;
use std::sync::{Arc, RwLock};

use hermes_cosmos_integration_tests::contexts::binary_channel::setup::CosmosBinaryChannelSetup;
use hermes_cosmos_integration_tests::contexts::bootstrap::CosmosBootstrap;
use hermes_cosmos_integration_tests::init::init_test_runtime;
use hermes_cosmos_relayer::contexts::build::CosmosBuilder;
use hermes_error::types::Error;
use hermes_relayer_components::multi::types::index::Index;
use hermes_runtime_components::traits::runtime::HasRuntime;
use hermes_test_components::chain_driver::traits::types::chain::HasChain;
use hermes_test_components::driver::traits::types::chain_driver_at::HasChainDriverAt;
use hermes_test_components::setup::traits::driver::CanBuildTestDriver;

use ibc_relayer::chain::cosmos::client::Settings;
use ibc_relayer::chain::handle::CountingAndCachingChainHandle;
use ibc_relayer::config::Config;
use ibc_relayer::registry::{Registry, SharedRegistry};
use ibc_relayer_types::core::ics02_client::trust_threshold::TrustThreshold;
use ibc_relayer_types::core::ics24_host::identifier::PortId;
use ibc_test_framework::bootstrap::binary::chain::save_relayer_config;
use ibc_test_framework::prelude::{RelayerDriver, TestConfig};
use ibc_test_framework::util::random::random_u32;

pub type BoxFuture<'a, T> = Pin<Box<dyn Future<Output = T> + Send + 'a>>;

#[allow(clippy::type_complexity)]
pub fn bootstrap_and_run_test<F, Fut>(
test_method: F,
config_modifier: impl FnOnce(&mut Config),
) -> Result<(), Error>
where
F: for<'a> Fn(
&'a CosmosBinaryChannelTestDriver,
RelayerDriver,
) -> BoxFuture<'a, Result<(), Error>>
+ Send
+ Sync
+ 'static,
{
let runtime = init_test_runtime();

let builder = Arc::new(CosmosBuilder::new_with_default(runtime.clone()));

// TODO: load parameters from environment variables
let bootstrap = Arc::new(CosmosBootstrap {
runtime: runtime.clone(),
builder,
should_randomize_identifiers: true,
chain_store_dir: "./test-data".into(),
chain_command_path: "gaiad".into(),
account_prefix: "cosmos".into(),
staking_denom: "stake".into(),
transfer_denom: "coin".into(),
genesis_config_modifier: Box::new(|_| Ok(())),
comet_config_modifier: Box::new(|_| Ok(())),
});

let create_client_settings = Settings {
max_clock_drift: Duration::from_secs(40),
trusting_period: None,
trust_threshold: TrustThreshold::ONE_THIRD,
};

let setup = CosmosBinaryChannelSetup {
bootstrap_a: bootstrap.clone(),
bootstrap_b: bootstrap.clone(),
create_client_settings,
init_connection_options: Default::default(),
init_channel_options: Default::default(),
port_id: PortId::transfer(),
};

// TODO: Use a test suite entry point for running multiple tests
runtime.runtime.clone().block_on(async move {
let driver = setup.build_driver().await?;

let chain_driver_a = driver.chain_driver_at(Index::<0>);
let chain_driver_b = driver.chain_driver_at(Index::<1>);
let chain_a = chain_driver_a.chain();
let chain_b = chain_driver_b.chain();

// Extract method `init_test()` but remove calls related to initialising tracing
// as this would throw errors
let mut test_config = {
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 native_token = env::var("NATIVE_TOKENS").unwrap_or_else(|_| "stake".to_string());

let compat_modes = env::var("COMPAT_MODES").ok().map(parse_chain_command_paths);

let ipv6_grpc = env::var("IPV6_GRPC")
.ok()
.map(|val| val == "true")
.unwrap_or(false);

let account_prefixes = parse_chain_command_paths(account_prefix);

let native_tokens = parse_chain_command_paths(native_token);

let chain_store_dir = format!("{}/test-{}", base_chain_store_dir, random_u32());

fs::create_dir_all(&chain_store_dir)?;

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);

TestConfig {
chain_command_paths,
chain_store_dir,
account_prefixes,
hang_on_fail,
bootstrap_with_random_ids: false,
native_tokens,
ipv6_grpc,
compat_modes,
}
};

test_config.chain_command_paths = vec![bootstrap
.chain_command_path
.clone()
.to_string_lossy()
.into()];
test_config.chain_store_dir = bootstrap.chain_store_dir.clone();

let config_path = test_config.chain_store_dir.join("relayer-config.toml");

let mut config = Config::default();

config
.chains
.push(ibc_relayer::config::ChainConfig::CosmosSdk(
chain_a.chain_config.clone(),
));
config
.chains
.push(ibc_relayer::config::ChainConfig::CosmosSdk(
chain_b.chain_config.clone(),
));

config_modifier(&mut config);

save_relayer_config(&config, &config_path)?;

let registry: Registry<CountingAndCachingChainHandle> = Registry {
config: config.clone(),
handles: HashMap::new(),
rt: chain_driver_a.runtime().runtime.clone(),
};

let shared_registry = SharedRegistry {
registry: Arc::new(RwLock::new(registry)),
};

let relayer_v1_driver = RelayerDriver {
config_path,
config,
registry: shared_registry,
hang_on_fail: test_config.hang_on_fail,
};

test_method(&driver, relayer_v1_driver).await?;

<Result<(), Error>>::Ok(())
})?;

Ok(())
}

fn parse_chain_command_paths(chain_command_path: String) -> Vec<String> {
let patterns: Vec<String> = chain_command_path
.split(',')
.map(|chain_binary| chain_binary.to_string())
.collect();
patterns
}
157 changes: 157 additions & 0 deletions tools/sdk-integration-test/src/tests/clear_packet.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
use hermes_cosmos_integration_tests::contexts::binary_channel::test_driver::CosmosBinaryChannelTestDriver;
use hermes_error::types::Error;
use hermes_relayer_components::multi::types::index::Index;
use hermes_relayer_components::multi::types::index::Twindex;
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::amount::HasAmountMethods;
use hermes_test_components::chain_driver::traits::fields::amount::CanGenerateRandomAmount;
use hermes_test_components::chain_driver::traits::fields::denom_at::HasDenomAt;
use hermes_test_components::chain_driver::traits::fields::denom_at::TransferDenom;
use hermes_test_components::chain_driver::traits::types::chain::HasChain;
use hermes_test_components::driver::traits::channel_at::HasChannelAt;

use ibc_test_framework::prelude::RelayerDriver;
use ibc_test_framework::prelude::*;

use crate::tests::bootstrap::bootstrap_and_run_test;
use crate::tests::bootstrap::BoxFuture;

#[test]
fn run_test() -> Result<(), Error> {
bootstrap_and_run_test::<_, BoxFuture<'_, Result<(), Error>>>(
|setup, relay_driver| Box::pin(test_clear_packet_no_scan(setup, relay_driver)),
|config| {
// Disabling the client workers and clear_on_start should make the relayer not
// relay any packet it missed before starting.
config.mode.clients.enabled = false;
config.mode.connections.enabled = false;
config.mode.channels.enabled = false;

config.mode.packets.enabled = true;
config.mode.packets.clear_on_start = false;
config.mode.packets.clear_interval = 10;
},
)
}

async fn test_clear_packet_no_scan(
setup: &CosmosBinaryChannelTestDriver,
relay_driver: RelayerDriver,
) -> Result<(), Error> {
let chain_driver_a = &setup.chain_driver_a;
let chain_driver_b = &setup.chain_driver_b;

let chain_a = chain_driver_a.chain();
let chain_b = chain_driver_b.chain();

let channel_id_a = setup.channel_id_at(Twindex::<0, 1>);
let port_id_a = setup.port_id_at(Twindex::<0, 1>);

let channel_id_b = setup.channel_id_at(Twindex::<1, 0>);
let port_id_b = setup.port_id_at(Twindex::<1, 0>);

let denom_a = chain_driver_a.denom_at(TransferDenom, Index::<0>);
// fee denom

let wallet_a = &chain_driver_a.user_wallet_a;
let wallet_b = &chain_driver_b.user_wallet_a;

let balance_a = chain_a.query_balance(&wallet_a.address, denom_a).await?;

let a_to_b_amount = chain_driver_a.random_amount(1000, &balance_a).await;

<hermes_cosmos_relayer::contexts::chain::CosmosChain as CanIbcTransferToken<
hermes_cosmos_relayer::contexts::chain::CosmosChain,
>>::ibc_transfer_token(
chain_a,
channel_id_a,
port_id_a,
wallet_a,
&wallet_b.address,
&a_to_b_amount,
)
.await?;

tokio::time::sleep(Duration::from_secs(25)).await;

let _handle = tokio::task::spawn_blocking(move || relay_driver.spawn_supervisor().unwrap());

info!("Assert clear on start does not trigger");

let expected_balance_a = hermes_cosmos_relayer::contexts::chain::CosmosChain::subtract_amount(
&balance_a,
&a_to_b_amount,
)?;

let zero_coin = hermes_cosmos_relayer::contexts::chain::CosmosChain::subtract_amount(
&a_to_b_amount,
&a_to_b_amount,
)?;

let expected_balance_b =
<hermes_cosmos_relayer::contexts::chain::CosmosChain as CanConvertIbcTransferredAmount<
hermes_cosmos_relayer::contexts::chain::CosmosChain,
>>::ibc_transfer_amount_from(&zero_coin, channel_id_b, port_id_b)?;

chain_a
.assert_eventual_amount(&wallet_a.address, &expected_balance_a)
.await?;

chain_b
.assert_eventual_amount(&wallet_b.address, &expected_balance_b)
.await?;

// Wait for clear interval to trigger
tokio::time::sleep(Duration::from_secs(20)).await;

info!("Assert clear interval does not trigger");

chain_b
.assert_eventual_amount(&wallet_b.address, &expected_balance_b)
.await?;

<hermes_cosmos_relayer::contexts::chain::CosmosChain as CanIbcTransferToken<
hermes_cosmos_relayer::contexts::chain::CosmosChain,
>>::ibc_transfer_token(
chain_a,
channel_id_a,
port_id_a,
wallet_a,
&wallet_b.address,
&a_to_b_amount,
)
.await?;

info!("Assert clear interval correctly triggers");

let expected_balance_a2 = hermes_cosmos_relayer::contexts::chain::CosmosChain::subtract_amount(
&expected_balance_a,
&a_to_b_amount,
)?;

let expected_balance_b2_as_coin =
hermes_cosmos_relayer::contexts::chain::CosmosChain::subtract_amount(
&a_to_b_amount,
&a_to_b_amount,
)?;

let expected_balance_b2 =
<hermes_cosmos_relayer::contexts::chain::CosmosChain as CanConvertIbcTransferredAmount<
hermes_cosmos_relayer::contexts::chain::CosmosChain,
>>::ibc_transfer_amount_from(&expected_balance_b2_as_coin, channel_id_b, port_id_b)?;

chain_a
.assert_eventual_amount(&wallet_a.address, &expected_balance_a2)
.await?;

info!("Assert clear interval does not trigger");

chain_b
.assert_eventual_amount(&wallet_b.address, &expected_balance_b2)
.await?;

Ok(())
}
2 changes: 2 additions & 0 deletions tools/sdk-integration-test/src/tests/mod.rs
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
pub mod bootstrap;
pub mod clear_packet;
pub mod transfer;
Loading

0 comments on commit 3e6bc7c

Please sign in to comment.