diff --git a/crates/cli/cli-components/src/impls/commands/connection/create.rs b/crates/cli/cli-components/src/impls/commands/connection/create.rs new file mode 100644 index 000000000..b095a1459 --- /dev/null +++ b/crates/cli/cli-components/src/impls/commands/connection/create.rs @@ -0,0 +1,146 @@ +use core::fmt::Display; +use core::marker::PhantomData; + +use cgp::prelude::*; +use hermes_logging_components::traits::has_logger::HasLogger; +use hermes_logging_components::traits::logger::CanLog; +use hermes_logging_components::types::level::LevelInfo; +use hermes_relayer_components::build::traits::builders::relay_builder::CanBuildRelay; +use hermes_relayer_components::chain::traits::types::chain_id::HasChainIdType; +use hermes_relayer_components::chain::traits::types::connection::HasInitConnectionOptionsType; +use hermes_relayer_components::chain::traits::types::ibc::HasClientIdType; +use hermes_relayer_components::multi::traits::chain_at::HasChainTypeAt; +use hermes_relayer_components::multi::traits::relay_at::HasRelayTypeAt; +use hermes_relayer_components::multi::types::index::Index; +use hermes_relayer_components::relay::impls::connection::bootstrap::CanBootstrapConnection; +use hermes_relayer_components::relay::traits::chains::HasRelayChains; + +use crate::traits::build::CanLoadBuilder; +use crate::traits::command::CommandRunner; +use crate::traits::output::{CanProduceOutput, HasOutputType}; +use crate::traits::parse::CanParseArg; + +pub struct RunCreateConnectionCommand; + +#[derive(Debug, clap::Parser, HasField)] +pub struct CreateConnectionArgs { + #[clap( + long = "target-chain-id", + required = true, + value_name = "TARGET_CHAIN_ID", + help_heading = "REQUIRED" + )] + target_chain_id: String, + + #[clap( + long = "target-client-id", + required = true, + value_name = "TARGET_CLIENT_ID", + help_heading = "REQUIRED" + )] + target_client_id: String, + + #[clap( + long = "counterparty-chain-id", + required = true, + value_name = "COUNTERPARTY_CHAIN_ID", + help_heading = "REQUIRED" + )] + counterparty_chain_id: String, + + #[clap( + long = "counterparty-client-id", + required = true, + value_name = "COUNTERPARTY_CLIENT_ID", + help_heading = "REQUIRED" + )] + counterparty_client_id: String, +} + +impl CommandRunner + for RunCreateConnectionCommand +where + App: HasOutputType + HasErrorType, + App: CanLoadBuilder + + HasLogger + + CanProduceOutput<&'static str> + + CanRaiseError + + CanRaiseError + + CanParseArg + + CanParseArg + + CanParseArg + + CanParseArg, + App::Logger: CanLog, + Builder: HasChainTypeAt, Chain = Chain> + + HasChainTypeAt, Chain = Counterparty> + + CanBuildRelay, Index<1>, Relay = Relay> + + HasRelayTypeAt, Index<1>>, + Chain: + HasChainIdType + HasClientIdType + HasInitConnectionOptionsType, + Counterparty: HasChainIdType + HasClientIdType, + Chain::InitConnectionOptions: Default, + Chain::ChainId: Display, + Chain::ClientId: Display, + Counterparty::ChainId: Display, + Counterparty::ClientId: Display, + Relay: CanBootstrapConnection + HasRelayChains, + Args: Async, +{ + async fn run_command(app: &App, args: &Args) -> Result { + let logger = app.logger(); + let builder = app.load_builder().await?; + + let target_chain_id = app.parse_arg(args, PhantomData::)?; + let target_client_id = app.parse_arg(args, PhantomData::)?; + let counterparty_chain_id = + app.parse_arg(args, PhantomData::)?; + let counterparty_client_id = + app.parse_arg(args, PhantomData::)?; + + logger + .log( + &format!( + "Creating connection between {}:{} and {}:{}...", + target_chain_id, + target_client_id, + counterparty_chain_id, + counterparty_client_id + ), + &LevelInfo, + ) + .await; + + let relay = builder + .build_relay( + PhantomData::<(Index<0>, Index<1>)>, + &target_chain_id, + &counterparty_chain_id, + &target_client_id, + &counterparty_client_id, + ) + .await + .map_err(App::raise_error)?; + + let (target_connection_id, counterparty_connection_id) = relay + .bootstrap_connection(&Default::default()) + .await + .map_err(App::raise_error)?; + + logger + .log( + &format!( + "Connection {}:{} successfully created between {}:{} and {}:{}", + target_connection_id, + counterparty_connection_id, + target_chain_id, + target_client_id, + counterparty_chain_id, + counterparty_client_id, + ), + &LevelInfo, + ) + .await; + + Ok(app.produce_output("Done")) + } +} diff --git a/crates/cli/cli-components/src/impls/commands/connection/mod.rs b/crates/cli/cli-components/src/impls/commands/connection/mod.rs new file mode 100644 index 000000000..c5fb369c1 --- /dev/null +++ b/crates/cli/cli-components/src/impls/commands/connection/mod.rs @@ -0,0 +1 @@ +pub mod create; diff --git a/crates/cli/cli-components/src/impls/commands/mod.rs b/crates/cli/cli-components/src/impls/commands/mod.rs index 4dac4eb32..d4bad9cc7 100644 --- a/crates/cli/cli-components/src/impls/commands/mod.rs +++ b/crates/cli/cli-components/src/impls/commands/mod.rs @@ -1,4 +1,5 @@ pub mod bootstrap; pub mod client; +pub mod connection; pub mod queries; pub mod start; diff --git a/crates/cli/cli/src/commands/connection/create.rs b/crates/cli/cli/src/commands/connection/create.rs deleted file mode 100644 index 8b6c80d0b..000000000 --- a/crates/cli/cli/src/commands/connection/create.rs +++ /dev/null @@ -1,101 +0,0 @@ -use core::marker::PhantomData; -use std::time::Duration; - -use hermes_cli_components::traits::build::CanLoadBuilder; -use hermes_cli_framework::command::CommandRunner; -use hermes_cli_framework::output::Output; -use hermes_cosmos_chain_components::types::connection::CosmosInitConnectionOptions; -use hermes_relayer_components::build::traits::builders::relay_builder::CanBuildRelay; -use hermes_relayer_components::multi::types::index::Index; -use hermes_relayer_components::relay::impls::connection::bootstrap::CanBootstrapConnection; -use ibc::core::connection::types::version::Version; -use ibc::core::host::types::identifiers::{ChainId, ClientId}; -use oneline_eyre::eyre::eyre; -use tracing::info; - -use crate::contexts::app::HermesApp; -use crate::Result; - -#[derive(Debug, clap::Parser)] -pub struct ConnectionCreate { - /// Identifier of chain A - #[clap( - long = "chain-a", - required = true, - value_name = "CHAIN_ID_A", - help_heading = "REQUIRED" - )] - chain_id_a: ChainId, - - /// Identifier of client A - #[clap( - long = "client-a", - required = true, - value_name = "CLIENT_ID_A", - help_heading = "REQUIRED" - )] - client_id_a: ClientId, - - /// Identifier of chain B - #[clap( - long = "chain-b", - required = true, - value_name = "CHAIN_ID_B", - help_heading = "REQUIRED" - )] - chain_id_b: ChainId, - - /// Identifier of client B - #[clap( - long = "client-b", - required = true, - value_name = "CLIENT_ID_B", - help_heading = "REQUIRED" - )] - client_id_b: ClientId, -} - -impl CommandRunner for ConnectionCreate { - async fn run(&self, app: &HermesApp) -> Result { - let builder = app.load_builder().await?; - - let relay = builder - .build_relay( - PhantomData::<(Index<0>, Index<1>)>, - &self.chain_id_a, - &self.chain_id_b, - &self.client_id_a, - &self.client_id_b, - ) - .await - .map_err(|e| eyre!("Failed to build relay: {e}"))?; - - let options = CosmosInitConnectionOptions { - delay_period: Duration::from_secs(0), - // Can unwrap safely since compatibles() returns a vector containing 1 Version - connection_version: Version::compatibles().first().unwrap().clone(), - }; - - info!( - ?options, - "Creating connection between {}:{} and {}:{}...", - self.chain_id_a, - self.client_id_a, - self.chain_id_b, - self.client_id_b - ); - - let (connection_id_a, connection_id_b) = relay - .bootstrap_connection(&options) - .await - .map_err(|e| eyre!("Failed to create connection: connection handshake failed: {e}"))?; - - info!( - %connection_id_a, %connection_id_b, - "Connection successfully created between {}:{} and {}:{}", - self.chain_id_a, self.client_id_a, self.chain_id_b, self.client_id_b - ); - - Ok(Output::success_msg("Done")) - } -} diff --git a/crates/cli/cli/src/commands/connection/mod.rs b/crates/cli/cli/src/commands/connection/mod.rs index 3eeb4c800..d65777f12 100644 --- a/crates/cli/cli/src/commands/connection/mod.rs +++ b/crates/cli/cli/src/commands/connection/mod.rs @@ -1,5 +1,8 @@ -mod create; -pub use create::ConnectionCreate; +// mod create; +// pub use create::ConnectionCreate; + +use hermes_cli_components::impls::commands::connection::create::CreateConnectionArgs; +use hermes_cli_components::traits::command::CanRunCommand; use hermes_cli_framework::command::CommandRunner; use hermes_cli_framework::output::Output; @@ -9,13 +12,13 @@ use crate::Result; #[derive(Debug, clap::Subcommand)] pub enum ConnectionCommands { /// Create a new connection - Create(ConnectionCreate), + Create(CreateConnectionArgs), } impl CommandRunner for ConnectionCommands { async fn run(&self, app: &HermesApp) -> Result { match self { - Self::Create(cmd) => cmd.run(app).await, + Self::Create(cmd) => app.run_command(cmd).await, } } } diff --git a/crates/cli/cli/src/contexts/app.rs b/crates/cli/cli/src/contexts/app.rs index 246418c8b..328cf16f1 100644 --- a/crates/cli/cli/src/contexts/app.rs +++ b/crates/cli/cli/src/contexts/app.rs @@ -14,6 +14,9 @@ use hermes_cli_components::impls::commands::client::create::{ use hermes_cli_components::impls::commands::client::update::{ RunUpdateClientCommand, UpdateClientArgs, }; +use hermes_cli_components::impls::commands::connection::create::{ + CreateConnectionArgs, RunCreateConnectionCommand, +}; use hermes_cli_components::impls::commands::queries::balance::{ QueryBalanceArgs, RunQueryBalanceCommand, }; @@ -63,9 +66,7 @@ use hermes_cli_components::traits::bootstrap::{BootstrapLoaderComponent, Bootstr use hermes_cli_components::traits::build::{ BuilderLoaderComponent, BuilderTypeComponent, CanLoadBuilder, }; -use hermes_cli_components::traits::command::{ - CanRunCommand, CommandRunner, CommandRunnerComponent, -}; +use hermes_cli_components::traits::command::{CanRunCommand, CommandRunnerComponent}; use hermes_cli_components::traits::config::config_path::ConfigPathGetterComponent; use hermes_cli_components::traits::config::load_config::{CanLoadConfig, ConfigLoaderComponent}; use hermes_cli_components::traits::config::write_config::{CanWriteConfig, ConfigWriterComponent}; @@ -198,6 +199,11 @@ delegate_components! { (CreateClientArgs, symbol!("target_chain_id")): ParseFromString, (CreateClientArgs, symbol!("counterparty_chain_id")): ParseFromString, + (CreateConnectionArgs, symbol!("target_chain_id")): ParseFromString, + (CreateConnectionArgs, symbol!("target_client_id")): ParseFromString, + (CreateConnectionArgs, symbol!("counterparty_chain_id")): ParseFromString, + (CreateConnectionArgs, symbol!("counterparty_client_id")): ParseFromString, + (UpdateClientArgs, symbol!("host_chain_id")): ParseFromString, (UpdateClientArgs, symbol!("client_id")): ParseFromString, (UpdateClientArgs, symbol!("counterparty_client_id")): ParseFromString, @@ -218,6 +224,7 @@ delegate_components! { QueryConsensusStateArgs: RunQueryConsensusStateCommand, CreateClientArgs: RunCreateClientCommand, + CreateConnectionArgs: RunCreateConnectionCommand, UpdateClientArgs: RunUpdateClientCommand, BootstrapSubCommand: RunBootstrapSubCommand, @@ -297,6 +304,7 @@ pub trait CanUseHermesApp: + CanRunCommand + CanRunCommand + CanRunCommand + + CanRunCommand + CanRunCommand + CanRunCommand + CanRunCommand @@ -309,7 +317,3 @@ pub trait CanUseHermesApp: } impl CanUseHermesApp for HermesApp {} - -pub trait CanRunQueryClientsCommand: CommandRunner {} - -impl CanRunQueryClientsCommand for RunQueryClientsCommand {} diff --git a/crates/cosmos/cosmos-relayer/src/contexts/build.rs b/crates/cosmos/cosmos-relayer/src/contexts/build.rs index dd247d0ae..52b964b75 100644 --- a/crates/cosmos/cosmos-relayer/src/contexts/build.rs +++ b/crates/cosmos/cosmos-relayer/src/contexts/build.rs @@ -22,8 +22,8 @@ use hermes_relayer_components::build::traits::builders::birelay_from_relay_build use hermes_relayer_components::build::traits::builders::chain_builder::ChainBuilder; use hermes_relayer_components::build::traits::cache::{HasChainCache, HasRelayCache}; use hermes_relayer_components::multi::traits::birelay_at::BiRelayTypeAtComponent; -use hermes_relayer_components::multi::traits::chain_at::ChainTypeAtComponent; -use hermes_relayer_components::multi::traits::relay_at::RelayTypeAtComponent; +use hermes_relayer_components::multi::traits::chain_at::{ChainTypeAtComponent, HasChainTypeAt}; +use hermes_relayer_components::multi::traits::relay_at::{HasRelayTypeAt, RelayTypeAtComponent}; use hermes_relayer_components::multi::types::index::Index; use hermes_relayer_components::multi::types::tags::{Dst, Src}; use hermes_relayer_components::relay::traits::target::SourceTarget; @@ -386,3 +386,13 @@ impl HasBatchConfig for CosmosBuilder { &self.batch_config } } + +pub trait CanUseCosmosBuilder: + HasChainTypeAt, Chain = CosmosChain> + + HasChainTypeAt, Chain = CosmosChain> + + HasRelayTypeAt, Index<1>, Relay = CosmosRelay> + + HasRelayTypeAt, Index<0>, Relay = CosmosRelay> +{ +} + +impl CanUseCosmosBuilder for CosmosBuilder {}