Skip to content

Commit

Permalink
Improve IBC query API (#25)
Browse files Browse the repository at this point in the history
* Refactor IbcQuery and IbcResponse to provide ibc_query with a better signature

* Remove associated type from IbcResponse trait
  • Loading branch information
romac authored Mar 11, 2020
1 parent 172220e commit c67f1fc
Show file tree
Hide file tree
Showing 2 changed files with 46 additions and 33 deletions.
35 changes: 21 additions & 14 deletions relayer/relay/src/query.rs
Original file line number Diff line number Diff line change
@@ -1,25 +1,32 @@
use tendermint::abci;
use tendermint::rpc::{self, endpoint::abci_query::AbciQuery};
use tendermint::rpc::endpoint::abci_query::AbciQuery;

use relayer_modules::Height;

use crate::chain::Chain;
use crate::error;

mod client_consensus_state;
pub use client_consensus_state::*;
pub mod client_consensus_state;

pub trait IbcResponse: Sized {}
pub trait IbcResponse<Query>: Sized {
fn from_abci_response(query: Query, response: AbciQuery) -> Result<Self, error::Error>;
}

pub trait IbcQuery {
type Response: IbcResponse;
pub trait IbcQuery: Sized {
type Response: IbcResponse<Self>;

fn path(&self) -> abci::Path;
fn height(&self) -> Height;
fn prove(&self) -> bool;
fn data(&self) -> Vec<u8>;

fn build_response(self, response: AbciQuery) -> Result<Self::Response, error::Error> {
Self::Response::from_abci_response(self, response)
}
}

pub async fn ibc_query<C, Q>(chain: &C, query: Q) -> Result<AbciQuery, rpc::Error>
/// 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>
where
C: Chain,
Q: IbcQuery,
Expand All @@ -32,19 +39,19 @@ where
Some(query.height().into()),
query.prove(),
)
.await?;
.await
.map_err(|e| error::Kind::Rpc.context(e))?;

if !abci_response.code.is_ok() {
todo!() // fail with response log
todo!() // TODO: Fail with response log
}

// Data from trusted node or subspace query doesn't need verification
if !is_query_store_with_proof(&query.path()) {
return Ok(abci_response);
// Data that is not from trusted node or subspace query needs verification
if is_query_store_with_proof(&query.path()) {
todo!() // TODO: Verify proof
}

// TODO: Verify proof and return response
Ok(abci_response)
query.build_response(abci_response)
}

/// Whether or not this path requires proof verification.
Expand Down
44 changes: 25 additions & 19 deletions relayer/relay/src/query/client_consensus_state.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use std::marker::PhantomData;
use tendermint::rpc::endpoint::abci_query::AbciQuery;

use tendermint::abci;

Expand All @@ -14,6 +15,7 @@ use crate::error;

pub struct QueryClientConsensusState<CS> {
pub height: Height,
pub client_id: ClientId,
pub consensus_state_path: ConsensusStatePath,
marker: PhantomData<CS>,
}
Expand All @@ -22,7 +24,8 @@ impl<CS> QueryClientConsensusState<CS> {
pub fn new(height: Height, client_id: ClientId) -> Self {
Self {
height,
consensus_state_path: ConsensusStatePath { client_id, height },
client_id: client_id.clone(),
consensus_state_path: ConsensusStatePath::new(client_id, height),
marker: PhantomData,
}
}
Expand Down Expand Up @@ -78,13 +81,28 @@ impl<CS> ConsensusStateResponse<CS> {
}
}

impl<CS> IbcResponse for ConsensusStateResponse<CS>
impl<CS> IbcResponse<QueryClientConsensusState<CS>> for ConsensusStateResponse<CS>
where
CS: ConsensusState,
{
// fn from_bytes(_bytes: &[u8]) -> Result<Self, rpc::Error> {
// todo!()
// }
fn from_abci_response(
query: QueryClientConsensusState<CS>,
response: AbciQuery,
) -> Result<Self, error::Error> {
match (response.value, response.proof) {
(Some(value), Some(proof)) => {
let consensus_state = amino_unmarshal_binary_length_prefixed(&value)?;

Ok(ConsensusStateResponse::new(
query.client_id,
consensus_state,
proof,
response.height.into(),
))
}
_ => todo!(),
}
}
}

pub async fn query_client_consensus_state<C>(
Expand All @@ -95,21 +113,9 @@ pub async fn query_client_consensus_state<C>(
where
C: Chain,
{
let query = QueryClientConsensusState::<C::ConsensusState>::new(height, client_id.clone());

let response = ibc_query(chain, query)
.await
.map_err(|e| error::Kind::Rpc.context(e))?;

// FIXME: Handle case where there is no value
let consensus_state = amino_unmarshal_binary_length_prefixed(&response.value.unwrap())?;
let query = QueryClientConsensusState::new(height, client_id);

Ok(ConsensusStateResponse::new(
client_id,
consensus_state,
response.proof.unwrap(), // FIXME: Handle case where there is no proof
response.height.into(),
))
ibc_query(chain, query).await
}

fn amino_unmarshal_binary_length_prefixed<T>(_bytes: &[u8]) -> Result<T, error::Error> {
Expand Down

0 comments on commit c67f1fc

Please sign in to comment.