diff --git a/CHANGELOG.md b/CHANGELOG.md index c4fc6847e0..a34096576d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ - Started `unwrap` cleanup ([#871]) - [ibc-relayer-cli] + - Include chain-id in `query clients` command, and sort output by client counter ([#992]) - Improve config loading message ([#996]) - Improve Hermes worker spawn time for `start` command ([#998]) - Better Hermes help message when command is unrecognized ([#1003]) @@ -37,6 +38,7 @@ [#972]: https://github.com/informalsystems/ibc-rs/issues/972 [#975]: https://github.com/informalsystems/ibc-rs/issues/975 [#983]: https://github.com/informalsystems/ibc-rs/issues/983 +[#992]: https://github.com/informalsystems/ibc-rs/issues/992 [#996]: https://github.com/informalsystems/ibc-rs/issues/996 [#998]: https://github.com/informalsystems/ibc-rs/issues/998 [#1003]: https://github.com/informalsystems/ibc-rs/issues/1003 diff --git a/relayer-cli/src/commands/query.rs b/relayer-cli/src/commands/query.rs index f32c01b654..10cdfa4103 100644 --- a/relayer-cli/src/commands/query.rs +++ b/relayer-cli/src/commands/query.rs @@ -19,7 +19,7 @@ pub enum QueryCmd { #[options(help = "Query information about clients")] Client(QueryClientCmds), - #[options(help = "Query clients")] + #[options(help = "Query the identifiers of all clients on a chain")] Clients(clients::QueryAllClientsCmd), /// The `query connection` subcommand diff --git a/relayer-cli/src/commands/query/clients.rs b/relayer-cli/src/commands/query/clients.rs index 46cd2f4e83..b192cb95eb 100644 --- a/relayer-cli/src/commands/query/clients.rs +++ b/relayer-cli/src/commands/query/clients.rs @@ -1,8 +1,10 @@ use std::sync::Arc; use abscissa_core::{Command, Options, Runnable}; +use serde::Serialize; use tokio::runtime::Runtime as TokioRuntime; +use ibc::ics02_client::client_state::ClientState; use ibc::ics24_host::identifier::{ChainId, ClientId}; use ibc_proto::ibc::core::client::v1::QueryClientStatesRequest; use ibc_relayer::chain::{Chain, CosmosSdkChain}; @@ -14,7 +16,25 @@ use crate::prelude::*; /// Query clients command #[derive(Clone, Command, Debug, Options)] pub struct QueryAllClientsCmd { - #[options(free, help = "identifier of the chain to query")] + #[options(free, required, help = "identifier of the chain to query")] + chain_id: ChainId, + + #[options( + help = "filter for clients which target a specific chain id (implies '-o')", + meta = "ID" + )] + src_chain_id: Option, + + #[options( + help = "omit printing the source chain for each client", + default = "false" + )] + omit_chain_ids: bool, +} + +#[derive(Debug, Serialize)] +struct ClientChain { + client_id: ClientId, chain_id: ChainId, } @@ -50,9 +70,47 @@ impl Runnable for QueryAllClientsCmd { match res { Ok(clients) => { - let client_ids: Vec = - clients.into_iter().map(|cs| cs.client_id).collect(); - Output::success(client_ids).exit() + match self.src_chain_id.clone() { + None => { + match self.omit_chain_ids { + true => { + // Omit chain identifiers + debug!( + "printing identifiers of all clients hosted on chain {}", + self.chain_id + ); + let out: Vec = + clients.into_iter().map(|cs| cs.client_id).collect(); + Output::success(out).exit() + } + false => { + // Include chain identifiers + debug!("printing identifiers (and target chain identifiers) of all clients hosted on chain {}", self.chain_id); + let out: Vec = clients + .into_iter() + .map(|cs| ClientChain { + client_id: cs.client_id, + chain_id: cs.client_state.chain_id(), + }) + .collect(); + Output::success(out).exit() + } + }; + } + Some(source_chain_id) => { + debug!( + "printing identifiers of all clients hosted on chain {} which target chain {}", + self.chain_id, source_chain_id + ); + // Filter and omit chain ids + let out: Vec = clients + .into_iter() + .filter(|cs| cs.client_state.chain_id().eq(&source_chain_id)) + .map(|cs| cs.client_id) + .collect(); + Output::success(out).exit() + } + } } Err(e) => Output::error(format!("{}", e)).exit(), } diff --git a/relayer/src/chain/cosmos.rs b/relayer/src/chain/cosmos.rs index 61ead497db..a58145e830 100644 --- a/relayer/src/chain/cosmos.rs +++ b/relayer/src/chain/cosmos.rs @@ -503,12 +503,20 @@ impl Chain for CosmosSdkChain { .map_err(|e| Kind::Grpc.context(e))? .into_inner(); - let clients = response + // Deserialize into domain type + let mut clients: Vec = response .client_states .into_iter() .filter_map(|cs| IdentifiedAnyClientState::try_from(cs).ok()) .collect(); + // Sort by client identifier counter + clients.sort_by(|a, b| { + client_id_suffix(&a.client_id) + .unwrap_or(0) // Fallback to `0` suffix (no sorting) if client id is malformed + .cmp(&client_id_suffix(&b.client_id).unwrap_or(0)) + }); + Ok(clients) } @@ -1525,3 +1533,15 @@ fn encode_to_bech32(address: &str, account_prefix: &str) -> Result Option { + client_id + .as_str() + .split('-') + .last() + .map(|e| e.parse::().ok()) + .flatten() +}