Skip to content

Commit

Permalink
CLI Command to query connection channels (#506)
Browse files Browse the repository at this point in the history
* Implemented the 'query connection channels' command

* Avoid calls to unwrap

* Updated the changelog

* Added basic CLI test

* Fix FMT

* Added JSON output option

* Overrriding default tracing cfg [WIP]

* Revert "Overrriding default tracing cfg [WIP]"

This reverts commit fb2e270.

* Simplified output, removed JSON

* Fixed output text

* Using find_chain method

* Added TODO addressing Vitor's comment
  • Loading branch information
adizere committed Jan 13, 2021
1 parent b324dc0 commit 1e5f2dc
Show file tree
Hide file tree
Showing 6 changed files with 230 additions and 14 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,20 @@
### FEATURES

- Add support for streamlining releases ([#507])
- [relayer-cli]
- Implement command to query the channels associated with a connection ([#505])

### IMPROVEMENTS

- Update to `tendermint-rs` v0.17.1 ([#517])


[#505]: https://github.com/informalsystems/ibc-rs/issues/505
[#507]: https://github.com/informalsystems/ibc-rs/issues/507
[#511]: https://github.com/informalsystems/ibc-rs/pull/511
[#517]: https://github.com/informalsystems/ibc-rs/issues/517


## v0.0.6
*December 23, 2020*

Expand Down
4 changes: 4 additions & 0 deletions relayer-cli/src/commands/query.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,10 @@ pub enum QueryConnectionCmds {
/// The `query connection end` subcommand
#[options(help = "query connection end")]
End(connection::QueryConnectionEndCmd),

/// The `query connection channels` subcommand
#[options(help = "query connection channels")]
Channels(connection::QueryConnectionChannelsCmd),
}

#[derive(Command, Debug, Options, Runnable)]
Expand Down
172 changes: 170 additions & 2 deletions relayer-cli/src/commands/query/connection.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use ibc::ics03_connection::connection::ConnectionEnd;
use ibc::ics24_host::error::ValidationError;
use ibc::ics24_host::identifier::ChainId;
use ibc::ics24_host::identifier::ConnectionId;

use ibc_proto::ibc::core::channel::v1::QueryConnectionChannelsRequest;
use relayer::chain::{Chain, CosmosSDKChain};
use relayer::config::{ChainConfig, Config};

Expand Down Expand Up @@ -96,11 +96,87 @@ impl Runnable for QueryConnectionEndCmd {
}
}

/// Command for querying the channel identifiers associated with a connection.
/// Sample invocation:
/// `cargo run --bin relayer -- -c simple_config.toml query connection channels ibc-0 connection-0`
#[derive(Clone, Command, Debug, Options)]
pub struct QueryConnectionChannelsCmd {
#[options(free, help = "identifier of the chain to query")]
chain_id: Option<ChainId>,

#[options(free, help = "identifier of the connection to query")]
connection_id: Option<String>,
}

#[derive(Debug)]
struct QueryConnectionChannelsOptions {
connection_id: ConnectionId,
}

impl QueryConnectionChannelsCmd {
fn validate_options(
&self,
config: &Config,
) -> Result<(ChainConfig, QueryConnectionChannelsOptions), String> {
let chain_id = self
.chain_id
.clone()
.ok_or_else(|| "no chain chain identifier provided".to_string())?;
let chain_config = config
.find_chain(&chain_id)
.ok_or_else(|| "missing chain configuration for the given chain id".to_string())?;

let connection_id = self
.connection_id
.as_ref()
.ok_or_else(|| "no connection identifier was provided".to_string())?
.parse()
.map_err(|err: ValidationError| err.to_string())?;

let opts = QueryConnectionChannelsOptions { connection_id };

Ok((chain_config.clone(), opts))
}
}

impl Runnable for QueryConnectionChannelsCmd {
fn run(&self) {
let config = app_config();

let (chain_config, opts) = match self.validate_options(&config) {
Err(err) => {
status_err!("invalid options: {}", err);
return;
}
Ok(result) => result,
};
status_info!("Options", "{:?}", opts);

let rt = Arc::new(Mutex::new(TokioRuntime::new().unwrap()));
let chain = CosmosSDKChain::bootstrap(chain_config, rt).unwrap();

let req = QueryConnectionChannelsRequest {
connection: opts.connection_id.to_string(),
pagination: None,
};

let res: Result<_, Error> = chain
.query_connection_channels(req)
.map_err(|e| Kind::Query.context(e).into());

match res {
Ok(cs) => status_info!("connection channels query result: ", "{:?}", cs),
Err(e) => status_info!("connection channels query error", "{}", e),
}
}
}

#[cfg(test)]
mod tests {
use crate::commands::query::connection::QueryConnectionEndCmd;
use relayer::config::parse;

use crate::commands::query::connection::{QueryConnectionChannelsCmd, QueryConnectionEndCmd};

#[test]
fn parse_connection_query_end_parameters() {
let default_params = QueryConnectionEndCmd {
Expand Down Expand Up @@ -194,4 +270,96 @@ mod tests {
}
}
}

#[test]
fn parse_query_connection_channels_parameters() {
let default_params = QueryConnectionChannelsCmd {
chain_id: Some("ibc-0".to_string().parse().unwrap()),
connection_id: Some("ibconeconnection".to_string().parse().unwrap()),
};

struct Test {
name: String,
params: QueryConnectionChannelsCmd,
want_pass: bool,
}

let tests: Vec<Test> = vec![
Test {
name: "Good parameters".to_string(),
params: default_params.clone(),
want_pass: true,
},
Test {
name: "No chain specified".to_string(),
params: QueryConnectionChannelsCmd {
chain_id: None,
..default_params.clone()
},
want_pass: false,
},
Test {
name: "Chain not configured".to_string(),
params: QueryConnectionChannelsCmd {
chain_id: Some("ibc007".to_string().parse().unwrap()),
..default_params.clone()
},
want_pass: false,
},
Test {
name: "No connection id specified".to_string(),
params: QueryConnectionChannelsCmd {
connection_id: None,
..default_params.clone()
},
want_pass: false,
},
Test {
name: "Bad connection, non-alpha".to_string(),
params: QueryConnectionChannelsCmd {
connection_id: Some("connection-0^".to_string()),
..default_params.clone()
},
want_pass: false,
},
Test {
name: "Bad connection, name too short".to_string(),
params: QueryConnectionChannelsCmd {
connection_id: Some("connshort".to_string()),
..default_params
},
want_pass: false,
},
]
.into_iter()
.collect();

let path = concat!(
env!("CARGO_MANIFEST_DIR"),
"/tests/fixtures/two_chains.toml"
);

let config = parse(path).unwrap();

for test in tests {
let res = test.params.validate_options(&config);

match res {
Ok(_res) => {
assert!(
test.want_pass,
"validate_options should have failed for test {}",
test.name
);
}
Err(err) => {
assert!(
!test.want_pass,
"validate_options failed for test {}, \nerr {}",
test.name, err
);
}
}
}
}
}
10 changes: 8 additions & 2 deletions relayer/src/chain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ use tendermint::account::Id as AccountId;
use tendermint::block::Height;

use ibc_proto::ibc::core::channel::v1::{
PacketState, QueryPacketAcknowledgementsRequest, QueryPacketCommitmentsRequest,
QueryUnreceivedAcksRequest, QueryUnreceivedPacketsRequest,
PacketState, QueryConnectionChannelsRequest, QueryPacketAcknowledgementsRequest,
QueryPacketCommitmentsRequest, QueryUnreceivedAcksRequest, QueryUnreceivedPacketsRequest,
};
use ibc_proto::ibc::core::commitment::v1::MerkleProof;

Expand Down Expand Up @@ -337,6 +337,12 @@ pub trait Chain: Sized {
request: QueryUnreceivedAcksRequest,
) -> Result<Vec<u64>, Error>;

/// Performs a query to retrieve the identifiers of all channels associated with a connection.
fn query_connection_channels(
&self,
request: QueryConnectionChannelsRequest,
) -> Result<Vec<ChannelId>, Error>;

fn build_packet_proofs(
&self,
packet_type: PacketMsgType,
Expand Down
41 changes: 34 additions & 7 deletions relayer/src/chain/cosmos.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,8 @@ use ibc_proto::cosmos::tx::v1beta1::{AuthInfo, Fee, ModeInfo, SignDoc, SignerInf
// Support for GRPC
use ibc_proto::cosmos::auth::v1beta1::{BaseAccount, QueryAccountRequest};
use ibc_proto::ibc::core::channel::v1::{
PacketState, QueryPacketAcknowledgementsRequest, QueryPacketCommitmentsRequest,
QueryUnreceivedAcksRequest, QueryUnreceivedPacketsRequest,
PacketState, QueryConnectionChannelsRequest, QueryPacketAcknowledgementsRequest,
QueryPacketCommitmentsRequest, QueryUnreceivedAcksRequest, QueryUnreceivedPacketsRequest,
};
use ibc_proto::ibc::core::commitment::v1::MerkleProof;

Expand All @@ -51,7 +51,7 @@ use ibc::ics07_tendermint::header::Header as TMHeader;

use ibc::ics23_commitment::commitment::CommitmentPrefix;
use ibc::ics23_commitment::merkle::convert_tm_to_ics_merkle_proof;
use ibc::ics24_host::identifier::{ChainId, ClientId};
use ibc::ics24_host::identifier::{ChainId, ChannelId, ClientId};
use ibc::ics24_host::Path::ClientConsensusState as ClientConsensusPath;
use ibc::ics24_host::Path::ClientState as ClientStatePath;
use ibc::ics24_host::{Path, IBC_QUERY_PATH};
Expand Down Expand Up @@ -516,7 +516,6 @@ impl Chain for CosmosSDKChain {
Ok(key)
}
/// Queries the packet commitment hashes associated with a channel.
/// TODO - move to the chain trait
fn query_packet_commitments(
&self,
request: QueryPacketCommitmentsRequest,
Expand Down Expand Up @@ -548,7 +547,6 @@ impl Chain for CosmosSDKChain {
}

/// Queries the packet commitment hashes associated with a channel.
/// TODO - move the chain trait
fn query_unreceived_packets(
&self,
request: QueryUnreceivedPacketsRequest,
Expand All @@ -572,7 +570,6 @@ impl Chain for CosmosSDKChain {
}

/// Queries the packet acknowledgment hashes associated with a channel.
/// TODO - move to the chain trait
fn query_packet_acknowledgements(
&self,
request: QueryPacketAcknowledgementsRequest,
Expand Down Expand Up @@ -604,7 +601,6 @@ impl Chain for CosmosSDKChain {
}

/// Queries the packet commitment hashes associated with a channel.
/// TODO - move the chain trait
fn query_unreceived_acknowledgements(
&self,
request: QueryUnreceivedAcksRequest,
Expand Down Expand Up @@ -655,6 +651,37 @@ impl Chain for CosmosSDKChain {
}
Ok(result)
}

fn query_connection_channels(
&self,
request: QueryConnectionChannelsRequest,
) -> Result<Vec<ChannelId>, Error> {
let grpc_addr =
Uri::from_str(&self.config().grpc_addr).map_err(|e| Kind::Grpc.context(e))?;
let mut client = self
.block_on(
ibc_proto::ibc::core::channel::v1::query_client::QueryClient::connect(grpc_addr),
)?
.map_err(|e| Kind::Grpc.context(e))?;

let request = tonic::Request::new(request);

let response = self
.block_on(client.connection_channels(request))?
.map_err(|e| Kind::Grpc.context(e))?
.into_inner();

// TODO: add warnings for any identifiers that fail to parse (below).
// https://github.com/informalsystems/ibc-rs/pull/506#discussion_r555945560

let vec_ids = response
.channels
.iter()
.filter_map(|ic| ChannelId::from_str(ic.channel_id.as_str()).ok())
.collect();

Ok(vec_ids)
}
}

fn packet_query(request: &QueryPacketEventDataRequest, seq: &Sequence) -> Result<Query, Error> {
Expand Down
13 changes: 10 additions & 3 deletions relayer/src/chain/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ use tendermint::account::Id;
use tendermint_testgen::light_block::TMLightBlock;

use ibc_proto::ibc::core::channel::v1::{
PacketState, QueryPacketAcknowledgementsRequest, QueryPacketCommitmentsRequest,
QueryUnreceivedAcksRequest, QueryUnreceivedPacketsRequest,
PacketState, QueryConnectionChannelsRequest, QueryPacketAcknowledgementsRequest,
QueryPacketCommitmentsRequest, QueryUnreceivedAcksRequest, QueryUnreceivedPacketsRequest,
};
use ibc_proto::ibc::core::commitment::v1::MerkleProof;

Expand All @@ -25,7 +25,7 @@ use ibc::ics07_tendermint::consensus_state::ConsensusState as TendermintConsensu
use ibc::ics07_tendermint::header::Header as TendermintHeader;
use ibc::ics18_relayer::context::ICS18Context;
use ibc::ics23_commitment::commitment::CommitmentPrefix;
use ibc::ics24_host::identifier::{ChainId, ClientId};
use ibc::ics24_host::identifier::{ChainId, ChannelId, ClientId};
use ibc::ics24_host::Path;
use ibc::mock::context::MockContext;
use ibc::mock::host::HostType;
Expand Down Expand Up @@ -228,6 +228,13 @@ impl Chain for MockChain {
unimplemented!()
}

fn query_connection_channels(
&self,
_request: QueryConnectionChannelsRequest,
) -> Result<Vec<ChannelId>, Error> {
unimplemented!()
}

fn query_txs(&self, _request: QueryPacketEventDataRequest) -> Result<Vec<IBCEvent>, Error> {
unimplemented!()
}
Expand Down

0 comments on commit 1e5f2dc

Please sign in to comment.