Skip to content

Commit

Permalink
Implement query for client connections (informalsystems#169)
Browse files Browse the repository at this point in the history
* Implemented logic to query client connections informalsystems#151

* Implemented a way to parse the client connections query response as a vector of string informalsystems#151

* Added test for client connections query params informalsystems#151

* Refactored TryFromRaw for Vec<String> as suggested on review informalsystems#169

* Fixed comments and fixed command line example to test the query client connections informalsystems#169

* Removing unused references informalsystems#169
  • Loading branch information
andynog authored Jul 29, 2020
1 parent 611b113 commit 21f637f
Show file tree
Hide file tree
Showing 2 changed files with 182 additions and 7 deletions.
4 changes: 4 additions & 0 deletions relayer/cli/src/commands/query.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@ pub enum QueryClientCmds {
/// The `query client consensus` subcommand
#[options(help = "query client consensus")]
Consensus(client::QueryClientConsensusCmd),

/// The `query client connections` subcommand
#[options(help = "query client connections")]
Connections(client::QueryClientConnectionsCmd),
}

#[derive(Command, Debug, Options, Runnable)]
Expand Down
185 changes: 178 additions & 7 deletions relayer/cli/src/commands/query/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,15 @@ use crate::prelude::*;

use abscissa_core::{Command, Options, Runnable};
use relayer::config::{ChainConfig, Config};
//use relayer::query::client::{query_client_consensus_state, query_client_full_state};
//use relayer::query::{query, Request};

//use relayer_modules::ics02_client::query::QueryClientFullState;
use relayer_modules::ics24_host::identifier::ClientId;

//use crate::commands::utils::block_on;
use relayer::chain::Chain;
use relayer::chain::CosmosSDKChain;
use relayer_modules::ics24_host::error::ValidationError;
use relayer_modules::ics24_host::identifier::ClientId;
use relayer_modules::ics24_host::Path::ClientConnections;
use tendermint::chain::Id as ChainId;

/// Query client state command
#[derive(Clone, Command, Debug, Options)]
pub struct QueryClientStateCmd {
#[options(free, help = "identifier of the chain to query")]
Expand Down Expand Up @@ -95,6 +93,7 @@ impl Runnable for QueryClientStateCmd {
}
}

/// Query client consensus command
#[derive(Clone, Command, Debug, Options)]
pub struct QueryClientConsensusCmd {
#[options(free, help = "identifier of the chain to query")]
Expand Down Expand Up @@ -214,9 +213,95 @@ fn validate_common_options(
Ok((chain_config.clone(), client_id))
}

/// Query client connections command
#[derive(Clone, Command, Debug, Options)]
pub struct QueryClientConnectionsCmd {
#[options(free, help = "identifier of the chain to query")]
chain_id: Option<ChainId>,

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

#[options(help = "height of the state to query", short = "h")]
height: Option<u64>,

#[options(help = "whether proof is required", short = "p")]
proof: Option<bool>,
}

#[derive(Debug)]
struct QueryClientConnectionsOptions {
client_id: ClientId,
height: u64,
proof: bool,
}

impl QueryClientConnectionsCmd {
fn validate_options(
&self,
config: &Config,
) -> Result<(ChainConfig, QueryClientConnectionsOptions), String> {
let chain_id = self
.chain_id
.ok_or_else(|| "missing chain identifier".to_string())?;
let chain_config = config
.chains
.iter()
.find(|c| c.id == chain_id)
.ok_or_else(|| "missing chain configuration".to_string())?;

let client_id = self
.client_id
.as_ref()
.ok_or_else(|| "missing client identifier".to_string())?
.parse()
.map_err(|err: ValidationError| err.to_string())?;

let opts = QueryClientConnectionsOptions {
client_id,
height: match self.height {
Some(h) => h,
None => 0 as u64,
},
proof: match self.proof {
Some(proof) => proof,
None => true,
},
};
Ok((chain_config.clone(), opts))
}
}

/// Command to handle query for client connections
/// To run without proof:
/// cargo run --bin relayer -- -c relayer/relay/tests/config/fixtures/relayer_conf_example.toml query client connections chain_A clientidone -h 4 -p false
impl Runnable for QueryClientConnectionsCmd {
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 chain = CosmosSDKChain::from_config(chain_config).unwrap();
let res =
chain.query::<Vec<String>>(ClientConnections(opts.client_id), opts.height, opts.proof);
match res {
Ok(cs) => status_info!("client connections query result: ", "{:?}", cs),
Err(e) => status_info!("client connections query error", "{}", e),
}
}
}

/// Tests
#[cfg(test)]
mod tests {
use crate::commands::query::client::QueryClientStateCmd;
use crate::commands::query::client::{QueryClientConnectionsCmd, QueryClientStateCmd};
use relayer::config::parse;

#[test]
Expand Down Expand Up @@ -304,4 +389,90 @@ mod tests {
}
}
}

#[test]
fn parse_query_client_connections_parameters() {
let default_params = QueryClientConnectionsCmd {
chain_id: Some("ibc0".to_string().parse().unwrap()),
client_id: Some("clientidone".to_string().parse().unwrap()),
height: Some(4),
proof: Some(false),
};

struct Test {
name: String,
params: QueryClientConnectionsCmd,
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: QueryClientConnectionsCmd {
chain_id: None,
..default_params.clone()
},
want_pass: false,
},
Test {
name: "Chain not configured".to_string(),
params: QueryClientConnectionsCmd {
chain_id: Some("notibc0oribc1".to_string().parse().unwrap()),
..default_params.clone()
},
want_pass: false,
},
Test {
name: "No client id specified".to_string(),
params: QueryClientConnectionsCmd {
client_id: None,
..default_params.clone()
},
want_pass: false,
},
Test {
name: "Bad client id, non-alpha".to_string(),
params: QueryClientConnectionsCmd {
client_id: Some("p34".to_string()),
..default_params.clone()
},
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
);
}
}
}
}
}

0 comments on commit 21f637f

Please sign in to comment.