Skip to content

Commit

Permalink
Add client queries to the relayer (informalsystems#38)
Browse files Browse the repository at this point in the history
* debugging the consensus query with proof

* started on client state

* fixed unused warning

* add height param to client query

* cargo fmt

* make proof option for client state

* fix client state prove flag

* cleanup queries

* Try integration with tm-rs v0.33 to pick the new merkle proof

* add validation function for common params

* add utils

* some cleanup and err handling

* addressing Ismail's comments
  • Loading branch information
ancazamfir committed Apr 10, 2020
1 parent f91e5fe commit e44b22d
Show file tree
Hide file tree
Showing 12 changed files with 417 additions and 33 deletions.
3 changes: 2 additions & 1 deletion relayer/cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ authors = [

[dependencies]
relayer = { path = "../relay" }
tendermint = { git = "https://github.com/informalsystems/tendermint-rs.git" }
relayer-modules = { path = "../../modules" }
tendermint = { git = "https://github.com/informalsystems/tendermint-rs.git", branch = "tendermint/v0.33" }

anomaly = "0.2.0"
gumdrop = "0.7"
Expand Down
18 changes: 13 additions & 5 deletions relayer/cli/src/commands.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,14 @@

mod config;
mod light;
mod query;
mod start;
mod utils;
mod version;

use self::{config::ConfigCmd, light::LightCmd, start::StartCmd, version::VersionCmd};
use self::{
config::ConfigCmd, light::LightCmd, query::QueryCmd, start::StartCmd, version::VersionCmd,
};

use crate::config::Config;
use abscissa_core::{Command, Configurable, FrameworkError, Help, Options, Runnable};
Expand All @@ -26,10 +30,6 @@ pub enum CliCmd {
#[options(help = "get usage information")]
Help(Help<Self>),

/// The `version` subcommand
#[options(help = "display version information")]
Version(VersionCmd),

/// The `start` subcommand
#[options(help = "start the relayer")]
Start(StartCmd),
Expand All @@ -38,6 +38,14 @@ pub enum CliCmd {
#[options(help = "manipulate the relayer configuration")]
Config(ConfigCmd),

/// The `version` subcommand
#[options(help = "display version information")]
Version(VersionCmd),

/// The `query` subcommand
#[options(help = "query state from chain")]
Query(QueryCmd),

/// The `light` subcommand
#[options(help = "basic functionality for managing the lite clients")]
Light(LightCmd),
Expand Down
23 changes: 23 additions & 0 deletions relayer/cli/src/commands/query.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
//! `query` subcommand

use abscissa_core::{Command, Options, Runnable};

mod query_client;

/// `query` subcommand
#[derive(Command, Debug, Options, Runnable)]
pub enum QueryCmd {
/// The `query client` subcommand
#[options(help = "query client")]
Client(QueryClientCmds),
}

#[derive(Command, Debug, Options, Runnable)]
pub enum QueryClientCmds {
/// The `query client` subcommand
#[options(help = "query client state")]
State(query_client::QueryClientStateCmd),

#[options(help = "query client consensus")]
Consensus(query_client::QueryClientConsensusCmd),
}
216 changes: 216 additions & 0 deletions relayer/cli/src/commands/query/query_client.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,216 @@
use crate::prelude::*;

use abscissa_core::{Command, Options, Runnable};
use relayer::config::{ChainConfig, Config};
use relayer::query::client_consensus_state::query_client_consensus_state;
use relayer::query::client_state::query_client_full_state;

use relayer_modules::ics24_host::client::ClientId;

use crate::commands::utils::block_on;
use relayer::chain::tendermint::TendermintChain;
use tendermint::chain::Id as ChainId;

#[derive(Command, Debug, Options)]
pub struct QueryClientStateCmd {
#[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 QueryClientStateOptions {
client_id: ClientId,
height: u64,
proof: bool,
}

impl QueryClientStateCmd {
fn validate_options(
&self,
config: &Config,
) -> Result<(ChainConfig, QueryClientStateOptions), String> {
let (chain_config, client_id) =
validate_common_options(&self.chain_id, &self.client_id, config)?;
let opts = QueryClientStateOptions {
client_id: client_id.parse().unwrap(),
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))
}
}

impl Runnable for QueryClientStateCmd {
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);

// run with proof:
// cargo run --bin relayer -- -c simple_config.toml query client state ibc0 ibconeclient
//
// run without proof:
// cargo run --bin relayer -- -c simple_config.toml query client state ibc0 ibconeclient -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 res = block_on(query_client_full_state(
&chain,
opts.height,
opts.client_id.clone(),
opts.proof,
));
match res {
Ok(cs) => status_info!("client state query result: ", "{:?}", cs.client_state),
Err(e) => status_info!("client state query error: ", "{:?}", e),
}
}
}

#[derive(Command, Debug, Options)]
pub struct QueryClientConsensusCmd {
#[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(free, help = "height of the consensus state to query")]
consensus_height: Option<u64>,

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

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

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

impl QueryClientConsensusCmd {
fn validate_options(
&self,
config: &Config,
) -> Result<(ChainConfig, QueryClientConsensusOptions), String> {
let (chain_config, client_id) =
validate_common_options(&self.chain_id, &self.client_id, config)?;

match self.consensus_height {
Some(consensus_height) => {
let opts = QueryClientConsensusOptions {
client_id: client_id.parse().unwrap(),
consensus_height,
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))
}
None => Err("missing client consensus height".to_string()),
}
}
}

impl Runnable for QueryClientConsensusCmd {
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);

// run with proof:
// cargo run --bin relayer -- -c simple_config.toml query client consensus ibc0 ibconeclient 22
//
// run without proof:
// cargo run --bin relayer -- -c simple_config.toml query client consensus ibc0 ibconeclient 22 -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 res = block_on(query_client_consensus_state(
&chain,
opts.height,
opts.client_id,
opts.consensus_height,
opts.proof,
));
match res {
Ok(cs) => status_info!(
"client consensus state query result: ",
"{:?}",
cs.consensus_state
),
Err(e) => status_info!("client consensus state query error: ", "{:?}", e),
}
}
}

fn validate_common_options(
chain_id: &Option<ChainId>,
client_id: &Option<String>,
config: &Config,
) -> Result<(ChainConfig, String), String> {
match (&chain_id, &client_id) {
(Some(chain_id), Some(client_id)) => {
let chain_config = config.chains.iter().find(|c| c.id == *chain_id);

match chain_config {
Some(chain_config) => {
// check that the client_id is specified in one of the chain configurations
match config
.chains
.iter()
.find(|c| c.client_ids.contains(client_id))
{
Some(_) => Ok((chain_config.clone(), client_id.parse().unwrap())),
None => Err(format!("cannot find client {} in config", client_id)),
}
}
None => Err(format!("cannot find chain {} in config", chain_id)),
}
}

(None, _) => Err("missing chain identifier".to_string()),
(_, None) => Err("missing client identifier".to_string()),
}
}
11 changes: 1 addition & 10 deletions relayer/cli/src/commands/start.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
use std::future::Future;
use std::time::{Duration, SystemTime};

// use crate::application::APPLICATION;
Expand All @@ -9,6 +8,7 @@ use abscissa_core::{Command, Options, Runnable};

use tendermint::lite::types::Header;

use crate::commands::utils::block_on;
use relayer::chain::tendermint::TendermintChain;
use relayer::chain::Chain;
use relayer::client::Client;
Expand Down Expand Up @@ -98,12 +98,3 @@ async fn create_client(

Client::new(chain, store, trust_options).await.unwrap()
}

fn block_on<F: Future>(future: F) -> F::Output {
tokio::runtime::Builder::new()
.basic_scheduler()
.enable_all()
.build()
.unwrap()
.block_on(future)
}
11 changes: 11 additions & 0 deletions relayer/cli/src/commands/utils.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
use core::future::Future;

/// block on future
pub fn block_on<F: Future>(future: F) -> F::Output {
tokio::runtime::Builder::new()
.basic_scheduler()
.enable_all()
.build()
.unwrap()
.block_on(future)
}
3 changes: 1 addition & 2 deletions relayer/relay/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,7 @@ authors = [

[dependencies]
relayer-modules = { path = "../../modules" }
tendermint = { git = "https://github.com/informalsystems/tendermint-rs.git" }

tendermint = { git = "https://github.com/informalsystems/tendermint-rs.git", branch = "tendermint/v0.33" }
anomaly = "0.2.0"
async-trait = "0.1.24"
humantime-serde = "1.0.0"
Expand Down
4 changes: 3 additions & 1 deletion relayer/relay/src/chain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use ::tendermint::lite::types as tmlite;
use ::tendermint::lite::{self, Height, TrustThresholdFraction};
use ::tendermint::rpc::Client as RpcClient;

use relayer_modules::ics02_client::state::ConsensusState;
use relayer_modules::ics02_client::state::{ClientState, ConsensusState};

use crate::config::ChainConfig;
use crate::error;
Expand All @@ -28,6 +28,8 @@ pub trait Chain {

/// Type of consensus state for this chain
type ConsensusState: ConsensusState + Serialize + DeserializeOwned;
type Type;
type ClientState: ClientState;

/// Type of RPC requester (wrapper around low-level RPC client) for this chain
type Requester: tmlite::Requester<Self::Commit, Self::Header>;
Expand Down
4 changes: 4 additions & 0 deletions relayer/relay/src/chain/tendermint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ use tendermint::block::Header as TMHeader;
use tendermint::lite::TrustThresholdFraction;
use tendermint::rpc::Client as RpcClient;

use relayer_modules::ics02_client::client_type::ClientType;
use relayer_modules::ics07_tendermint::client_state::ClientState;
use relayer_modules::ics07_tendermint::consensus_state::ConsensusState;

use crate::client::rpc_requester::RpcRequester;
Expand Down Expand Up @@ -34,10 +36,12 @@ impl TendermintChain {
}

impl Chain for TendermintChain {
type Type = ClientType;
type Header = TMHeader;
type Commit = TMCommit;
type ConsensusState = ConsensusState;
type Requester = RpcRequester;
type ClientState = ClientState;

fn config(&self) -> &ChainConfig {
&self.config
Expand Down
3 changes: 2 additions & 1 deletion relayer/relay/src/query.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use crate::chain::Chain;
use crate::error;

pub mod client_consensus_state;
pub mod client_state;

/// The type of IBC response sent back for a given IBC `Query`.
pub trait IbcResponse<Query>: Sized {
Expand Down Expand Up @@ -72,5 +73,5 @@ where
/// 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 {
todo!()
false
}
Loading

0 comments on commit e44b22d

Please sign in to comment.