hermes_cli_components/impls/commands/queries/
client_state.rs1use core::marker::PhantomData;
2
3use cgp::prelude::*;
4use hermes_logging_components::traits::has_logger::HasLogger;
5use hermes_logging_components::traits::logger::CanLog;
6use hermes_logging_components::types::level::LevelInfo;
7use hermes_relayer_components::build::traits::builders::chain_builder::CanBuildChain;
8use hermes_relayer_components::chain::traits::queries::chain_status::CanQueryChainHeight;
9use hermes_relayer_components::chain::traits::queries::client_state::CanQueryClientState;
10use hermes_relayer_components::chain::traits::types::chain_id::HasChainIdType;
11use hermes_relayer_components::chain::traits::types::client_state::HasClientStateType;
12use hermes_relayer_components::multi::types::index::Index;
13
14use crate::traits::any_counterparty::HasAnyCounterparty;
15use crate::traits::build::{CanLoadBuilder, HasBuilderType};
16use crate::traits::command::CommandRunner;
17use crate::traits::output::CanProduceOutput;
18use crate::traits::parse::CanParseArg;
19
20pub struct RunQueryClientStateCommand;
21
22#[derive(Debug, clap::Parser, HasField)]
23pub struct QueryClientStateArgs {
24 #[clap(
26 long = "chain",
27 required = true,
28 value_name = "CHAIN_ID",
29 help_heading = "REQUIRED"
30 )]
31 chain_id: String,
32
33 #[clap(
35 long = "client",
36 required = true,
37 value_name = "CLIENT_ID",
38 help_heading = "REQUIRED"
39 )]
40 client_id: String,
41
42 #[clap(
43 long = "height",
44 value_name = "HEIGHT",
45 help = "The height at which to query the client state. If not specified, the latest height is used."
46 )]
47 height: Option<String>,
48}
49
50impl<App, Args, Build, Chain, Counterparty> CommandRunner<App, Args> for RunQueryClientStateCommand
51where
52 App: HasBuilderType<Builder = Build>
53 + CanLoadBuilder
54 + HasLogger
55 + HasAnyCounterparty<AnyCounterparty = Counterparty>
56 + CanProduceOutput<Counterparty::ClientState>
57 + CanParseArg<Args, symbol!("chain_id"), Parsed = Chain::ChainId>
58 + CanParseArg<Args, symbol!("client_id"), Parsed = Chain::ClientId>
59 + CanParseArg<Args, symbol!("height"), Parsed = Option<Chain::Height>>
60 + CanRaiseError<Build::Error>
61 + CanRaiseError<Chain::Error>,
62 Args: Async,
63 Build: CanBuildChain<0, Chain = Chain>,
64 Chain: HasChainIdType + CanQueryChainHeight + CanQueryClientState<Counterparty>,
65 Counterparty: HasClientStateType<Chain>,
66 App::Logger: CanLog<LevelInfo>,
67{
68 async fn run_command(app: &App, args: &Args) -> Result<App::Output, App::Error> {
69 let chain_id = app.parse_arg(args, PhantomData::<symbol!("chain_id")>)?;
70 let client_id = app.parse_arg(args, PhantomData::<symbol!("client_id")>)?;
71 let m_height = app.parse_arg(args, PhantomData::<symbol!("height")>)?;
72
73 let logger = app.logger();
74 let builder = app.load_builder().await?;
75
76 let chain = builder
77 .build_chain(Index::<0>, &chain_id)
78 .await
79 .map_err(App::raise_error)?;
80
81 let query_height = match m_height {
82 Some(height) => height,
83 None => chain.query_chain_height().await.map_err(App::raise_error)?,
84 };
85
86 let client_state = chain
87 .query_client_state(&client_id, &query_height)
88 .await
89 .map_err(App::raise_error)?;
90
91 logger
92 .log(
93 &format!("Found client state for client `{client_id}` on chain `{chain_id}`!"),
94 &LevelInfo,
95 )
96 .await;
97
98 Ok(app.produce_output(client_state))
99 }
100}