hermes_cli_components/impls/commands/queries/
consensus_state.rs

1use 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}