Skip to content

Commit

Permalink
Generic query, channel query and reduce code (informalsystems#152)
Browse files Browse the repository at this point in the history
* Added channel query and TryFromRaw trait

* Implemented generic query for abci queries, converted connection query and channel query to use that and disabled client query for now. Removed unused code.

* Fix for handling empty response value.

* Moved query parameters into the command parameters with Into. (informalsystems#155)

Co-authored-by: Adi Seredinschi <[email protected]>
  • Loading branch information
greg-szabo and adizere authored Jul 20, 2020
1 parent 5752876 commit 9728e16
Show file tree
Hide file tree
Showing 7 changed files with 152 additions and 124 deletions.
39 changes: 22 additions & 17 deletions relayer/cli/src/commands/query/channel.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,18 @@ use crate::prelude::*;

use abscissa_core::{Command, Options, Runnable};
use relayer::config::{ChainConfig, Config};
use relayer::query::channel::query_channel;
use relayer::query::{query, Request};

use relayer_modules::ics04_channel::channel::ChannelEnd;
use relayer_modules::ics24_host::identifier::{ChannelId, PortId};

use crate::commands::utils::block_on;
use relayer::chain::tendermint::TendermintChain;
use relayer_modules::error::Error;
use relayer_modules::ics24_host::error::ValidationError;
use relayer_modules::path::{ChannelEndsPath, Path};
use std::str::FromStr;
use tendermint::abci::Path as TendermintPath;
use tendermint::chain::Id as ChainId;

#[derive(Clone, Command, Debug, Options)]
Expand Down Expand Up @@ -37,6 +42,17 @@ struct QueryChannelOptions {
proof: bool,
}

impl Into<Request> for QueryChannelOptions {
fn into(self) -> Request {
Request {
path: Some(TendermintPath::from_str(&"store/ibc/key").unwrap()),
data: ChannelEndsPath::new(self.port_id, self.channel_id).to_string(),
height: self.height,
prove: self.proof,
}
}
}

impl QueryChannelEndCmd {
fn validate_options(
&self,
Expand Down Expand Up @@ -94,25 +110,14 @@ impl Runnable for QueryChannelEndCmd {
};
status_info!("Options", "{:?}", opts);

// run with proof:
// cargo run --bin relayer -- -c simple_config.toml query channel end ibc0 transfer ibconexfer
//
// run without proof:
// cargo run --bin relayer -- -c simple_config.toml query channel end ibc0 transfer ibconexfer -p false
//
// Note: currently both fail in amino_unmarshal_binary_length_prefixed().
// To test this start a Gaia node and configure a channel using the go relayer.
// cargo run --bin relayer -- -c relayer/relay/tests/config/fixtures/simple_config.toml query channel end ibc-test firstport firstchannel --height 3 -p false
let chain = TendermintChain::from_config(chain_config).unwrap();
let res = block_on(query_channel(
&chain,
opts.height,
opts.port_id.clone(),
opts.channel_id.clone(),
opts.proof,
));
let res: Result<ChannelEnd, Error> = block_on(query(&chain, opts));

match res {
Ok(cs) => status_info!("channel query result: ", "{:?}", cs.channel),
Err(e) => status_info!("channel query error: ", "{:?}", e),
Ok(cs) => status_info!("channel query result: ", "{:?}", cs),
Err(e) => status_info!("channel query error", "{}", e),
}
}
}
Expand Down
19 changes: 13 additions & 6 deletions relayer/cli/src/commands/query/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@ 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::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 crate::commands::utils::block_on;
use relayer::chain::tendermint::TendermintChain;
use relayer_modules::ics24_host::error::ValidationError;
use tendermint::chain::Id as ChainId;
Expand Down Expand Up @@ -70,14 +72,15 @@ impl Runnable for QueryClientStateCmd {
status_info!("Options", "{:?}", opts);

// run with proof:
// cargo run --bin relayer -- -c simple_config.toml query client state ibc0 ibconeclient
// cargo run --bin relayer -- -c relayer/relay/tests/config/fixtures/simple_config.toml query client state ibc-test ethbridge --height 3
//
// run without proof:
// cargo run --bin relayer -- -c simple_config.toml query client state ibc0 ibconeclient -p false
// cargo run --bin relayer -- -c relayer/relay/tests/config/fixtures/simple_config.toml query client state ibc-test ethbridge --height 3 -p false
//
// Note: currently both fail in amino_unmarshal_binary_length_prefixed().
// To test this start a Gaia node and configure a client using the go relayer.
let chain = TendermintChain::from_config(chain_config).unwrap();
let _chain = TendermintChain::from_config(chain_config).unwrap();
/* Todo: Implement client full state query
let res = block_on(query_client_full_state(
&chain,
opts.height,
Expand All @@ -88,6 +91,7 @@ impl Runnable for QueryClientStateCmd {
Ok(cs) => status_info!("client state query result: ", "{:?}", cs.client_state),
Err(e) => status_info!("client state query error: ", "{:?}", e),
}
*/
}
}

Expand Down Expand Up @@ -167,7 +171,8 @@ impl Runnable for QueryClientConsensusCmd {
//
// Note: currently both fail in amino_unmarshal_binary_length_prefixed().
// To test this start a Gaia node and configure a client using the go relayer.
let chain = TendermintChain::from_config(chain_config).unwrap();
let _chain = TendermintChain::from_config(chain_config).unwrap();
/* Todo: Implement client consensus state query
let res = block_on(query_client_consensus_state(
&chain,
opts.height,
Expand All @@ -183,6 +188,8 @@ impl Runnable for QueryClientConsensusCmd {
),
Err(e) => status_info!("client consensus state query error: ", "{:?}", e),
}
*/
}
}

Expand Down
36 changes: 21 additions & 15 deletions relayer/cli/src/commands/query/connection.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,20 @@ use crate::prelude::*;

use abscissa_core::{Command, Options, Runnable};
use relayer::config::{ChainConfig, Config};
use relayer::query::connection::query_connection;

use crate::commands::utils::block_on;
use relayer::chain::tendermint::TendermintChain;
use relayer::query::{query, Request};
use relayer_modules::error::Error;
use relayer_modules::ics24_host::error::ValidationError;
use relayer_modules::ics24_host::identifier::ConnectionId;
use relayer_modules::path::{ConnectionPath, Path};
use tendermint::chain::Id as ChainId;

use relayer_modules::ics03_connection::connection::ConnectionEnd;
use std::str::FromStr;
use tendermint::abci::Path as TendermintPath;

#[derive(Clone, Command, Debug, Options)]
pub struct QueryConnectionEndCmd {
#[options(free, help = "identifier of the chain to query")]
Expand All @@ -32,6 +38,17 @@ struct QueryConnectionOptions {
proof: bool,
}

impl Into<Request> for QueryConnectionOptions {
fn into(self) -> Request {
Request {
path: Some(TendermintPath::from_str(&"store/ibc/key").unwrap()),
data: ConnectionPath::new(self.connection_id).to_string(),
height: self.height,
prove: self.proof,
}
}
}

impl QueryConnectionEndCmd {
fn validate_options(
&self,
Expand Down Expand Up @@ -82,23 +99,12 @@ impl Runnable for QueryConnectionEndCmd {
status_info!("Options", "{:?}", opts);

let chain = TendermintChain::from_config(chain_config).unwrap();
// run with proof:
// cargo run --bin relayer -- -c simple_config.toml query connection end ibc0 ibconeconnection
//
// run without proof:
// cargo run --bin relayer -- -c simple_config.toml query connection end ibc0 ibconeconnection -p false
//
// Note: currently both fail in amino_unmarshal_binary_length_prefixed().
// To test this start a Gaia node and configure a client using the go relayer.
let res = block_on(query_connection(
&chain,
opts.height,
opts.connection_id.clone(),
opts.proof,
));
// cargo run --bin relayer -- -c relayer/relay/tests/config/fixtures/simple_config.toml query connection end ibc-test connectionidone --height 3 -p false
let res: Result<ConnectionEnd, Error> = block_on(query(&chain, opts));

match res {
Ok(cs) => status_info!("connection query result: ", "{:?}", cs.connection),
Ok(cs) => status_info!("connection query result: ", "{:?}", cs),
Err(e) => status_info!("connection query error", "{}", e),
}
}
Expand Down
83 changes: 56 additions & 27 deletions relayer/relay/src/query.rs
Original file line number Diff line number Diff line change
@@ -1,49 +1,78 @@
use tendermint::abci;

use crate::chain::Chain;
use relayer_modules::error;
use relayer_modules::query::IbcQuery;
use relayer_modules::try_from_raw::TryFromRaw;
use tendermint::abci::Path as TendermintPath;
use tendermint::block;

pub mod channel;
pub mod client;
pub mod connection;

/// Perform an IBC `query` on the given `chain`, and return the corresponding IBC response.
pub async fn ibc_query<C, Q>(chain: &C, query: Q) -> Result<Q::Response, error::Error>
/// Query the ABCI application for information
pub struct Request {
/// Path to the data
pub path: Option<TendermintPath>,

/// Data to query
pub data: String,

/// Block height
pub height: u64,

/// Include proof in response
pub prove: bool,
}

/// Whether or not this path requires proof verification.
///
/// is_query_store_with_proofxpects a format like /<queryType>/<storeName>/<subpath>,
/// where queryType must be "store" and subpath must be "key" to require a proof.
fn is_query_store_with_proof(_path: &TendermintPath) -> bool {
false
}

/// Perform a generic `abci_query` on the given `chain`, and return the corresponding deserialized response data.
pub async fn query<C, T, O>(chain: &C, request: O) -> Result<T, error::Error>
where
C: Chain,
Q: IbcQuery,
C: Chain, // Chain configuration
T: TryFromRaw, // Internal Struct type (expected response)
O: Into<Request>, // Query Command configuration (opts)
{
let abci_response = chain
// RPC Request

let request: Request = request.into();
let path = request.path.clone().unwrap(); // for the is_query_store_with_proof function

// Use the Tendermint-rs RPC client to do the query - Todo: generalize further for other type of chains
let response = chain
.rpc_client()
.abci_query(
Some(query.path()),
query.data(),
Some(query.height().into()),
query.prove(),
request.path,
request.data.to_string().into_bytes(),
match request.height {
0 => None,
_ => Some(block::Height::from(request.height)),
},
request.prove,
)
.await
.map_err(|e| error::Kind::Rpc.context(e))?;

if !abci_response.code.is_ok() {
if !response.code.is_ok() {
// Fail with response log
return Err(error::Kind::Rpc
.context(abci_response.log.to_string())
.into());
return Err(error::Kind::Rpc.context(response.log.to_string()).into());
}
if response.value.is_empty() {
// Fail due to empty response value (nothing to decode).
return Err(error::Kind::EmptyResponseValue.into());
}

// Verify response proof

// Data that is not from trusted node or subspace query needs verification
if is_query_store_with_proof(&query.path()) {
if is_query_store_with_proof(&path) {
todo!() // TODO: Verify proof
}

query.build_response(abci_response)
}
// Deserialize response data

/// Whether or not this path requires proof verification.
///
/// is_query_store_with_proofxpects a format like /<queryType>/<storeName>/<subpath>,
/// where queryType must be "store" and subpath must be "key" to require a proof.
fn is_query_store_with_proof(_path: &abci::Path) -> bool {
false
T::deserialize(response.value)
}
22 changes: 0 additions & 22 deletions relayer/relay/src/query/channel.rs

This file was deleted.

Loading

0 comments on commit 9728e16

Please sign in to comment.