hermes_cli_components/impls/commands/queries/
consensus_state.rs1use core::marker::PhantomData;
2
3use cgp::prelude::*;
4use hermes_relayer_components::build::traits::builders::chain_builder::CanBuildChain;
5use hermes_relayer_components::chain::traits::queries::chain_status::CanQueryChainHeight;
6use hermes_relayer_components::chain::traits::queries::consensus_state::CanQueryConsensusState;
7use hermes_relayer_components::chain::traits::queries::consensus_state_height::CanQueryConsensusStateHeights;
8use hermes_relayer_components::chain::traits::types::consensus_state::HasConsensusStateType;
9use hermes_relayer_components::chain::traits::types::height::HasHeightType;
10use hermes_relayer_components::multi::traits::chain_at::HasChainTypeAt;
11use hermes_relayer_components::multi::types::index::Index;
12
13use crate::traits::build::CanLoadBuilder;
14use crate::traits::command::CommandRunner;
15use crate::traits::output::CanProduceOutput;
16use crate::traits::parse::CanParseArg;
17
18pub struct RunQueryConsensusStateCommand;
19
20#[derive(Debug, clap::Parser, HasField)]
21pub struct QueryConsensusStateArgs {
22 #[clap(
23 long = "chain",
24 required = true,
25 value_name = "CHAIN_ID",
26 help_heading = "REQUIRED",
27 help = "Identifier of the chain to query"
28 )]
29 chain_id: String,
30
31 #[clap(
32 long = "client",
33 required = true,
34 value_name = "CLIENT_ID",
35 help_heading = "REQUIRED",
36 help = "Identifier of the client to query"
37 )]
38 client_id: String,
39
40 #[clap(
41 long = "consensus-height",
42 value_name = "CONSENSUS_HEIGHT",
43 help = "Height of the client's consensus state to query, if not specified the latest consensus height is used"
44 )]
45 consensus_height: Option<String>,
46
47 #[clap(
48 long = "query_height",
49 value_name = "QUERY_HEIGHT",
50 help = "The height at which to query the chain"
51 )]
52 query_height: Option<String>,
53}
54
55impl<App, Args, Build, Chain, Counterparty> CommandRunner<App, Args>
56 for RunQueryConsensusStateCommand
57where
58 App: CanLoadBuilder<Builder = Build>
59 + CanProduceOutput<Counterparty::ConsensusState>
60 + CanParseArg<Args, symbol!("chain_id"), Parsed = Chain::ChainId>
61 + CanParseArg<Args, symbol!("client_id"), Parsed = Chain::ClientId>
62 + CanParseArg<Args, symbol!("query_height"), Parsed = Option<Chain::Height>>
63 + CanParseArg<Args, symbol!("consensus_height"), Parsed = Option<Counterparty::Height>>
64 + CanRaiseError<Build::Error>
65 + CanRaiseError<Chain::Error>
66 + CanRaiseError<String>,
67 Build: CanBuildChain<0, Chain = Chain> + HasChainTypeAt<1, Chain = Counterparty>,
68 Chain: CanQueryChainHeight
69 + CanQueryConsensusState<Counterparty>
70 + CanQueryConsensusStateHeights<Counterparty>,
71 Counterparty: HasHeightType + HasConsensusStateType<Chain>,
72 Args: Async,
73{
74 async fn run_command(app: &App, args: &Args) -> Result<App::Output, App::Error> {
75 let chain_id = app.parse_arg(args, PhantomData::<symbol!("chain_id")>)?;
76 let client_id = app.parse_arg(args, PhantomData::<symbol!("client_id")>)?;
77 let m_query_height = app.parse_arg(args, PhantomData::<symbol!("query_height")>)?;
78 let m_consensus_height = app.parse_arg(args, PhantomData::<symbol!("consensus_height")>)?;
79
80 let builder = app.load_builder().await?;
81
82 let chain = builder
83 .build_chain(Index::<0>, &chain_id)
84 .await
85 .map_err(App::raise_error)?;
86
87 let query_height = match m_query_height {
88 Some(query_height) => query_height,
89 None => chain.query_chain_height().await.map_err(App::raise_error)?,
90 };
91
92 let consensus_height = match m_consensus_height {
93 Some(consensus_height) => consensus_height,
94 None => {
95 let heights = chain
96 .query_consensus_state_heights(&client_id)
97 .await
98 .map_err(App::raise_error)?;
99
100 heights.into_iter().next().ok_or_else(|| {
101 App::raise_error(format!(
102 "no consensus state found for client {} on chain {}",
103 client_id, chain_id
104 ))
105 })?
106 }
107 };
108
109 let consensus_state = chain
110 .query_consensus_state(&client_id, &consensus_height, &query_height)
111 .await
112 .map_err(App::raise_error)?;
113
114 Ok(app.produce_output(consensus_state))
115 }
116}