Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP Connection queries for Relayer #136

Merged
merged 12 commits into from
Jul 14, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion modules/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,18 @@ paths-ics = []
tendermint = { git = "https://github.com/informalsystems/tendermint-rs.git", branch = "master" }
tendermint-rpc = { git = "https://github.com/informalsystems/tendermint-rs.git", path = "/rpc", features=["client"] }

# Proto definitions for all IBC-related interfaces, e.g., connections or channels.
ibc-proto = "0.1.0"

anomaly = "0.2.0"
thiserror = "1.0.11"
serde_derive = "1.0.104"
serde = "1.0.104"
serde_json = "1"
tracing = "0.1.13"
prost = "0.6.1"
bytes = "0.5.5"

[dev-dependencies]
tokio = { version = "0.2", features = ["macros"] }
subtle-encoding = { version = "0.5" }
subtle-encoding = { version = "0.5" }
4 changes: 4 additions & 0 deletions modules/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ pub enum Kind {
/// Event error (raised by the event monitor)
#[error("Bad Notification")]
Event,

/// Response parsing error
#[error("Could not parse/unmarshall response")]
ResponseParsing,
}

impl Kind {
Expand Down
46 changes: 46 additions & 0 deletions modules/src/ics03_connection/connection.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ use crate::ics23_commitment::CommitmentPrefix;
use crate::ics24_host::identifier::{ClientId, ConnectionId};
use serde_derive::{Deserialize, Serialize};

// Import proto declarations.
use ibc_proto::connection::ConnectionEnd as ProtoConnectionEnd;
use ibc_proto::connection::Counterparty as ProtoCounterparty;

#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct ConnectionEnd {
state: State,
Expand All @@ -25,6 +29,37 @@ impl ConnectionEnd {
versions: validate_versions(versions).map_err(|e| Kind::InvalidVersion.context(e))?,
})
}

pub fn set_state(&mut self, new_state: State) {
self.state = new_state;
}

pub fn from_proto_connection_end(pc: ProtoConnectionEnd) -> Result<Self, Error> {
if pc.id == "" {
return Err(Kind::ConnectionNotFound.into());
}

// The Counterparty field is an Option, may be missing.
match pc.counterparty {
Some(cp) => {
let mut conn = ConnectionEnd::new(
pc.client_id
.parse()
.map_err(|e| Kind::IdentifierError.context(e))?,
Counterparty::from_proto_counterparty(cp)?,
validate_versions(pc.versions).map_err(|e| Kind::InvalidVersion.context(e))?,
)
.unwrap();

// Set the state.
conn.set_state(State::from_i32(pc.state));
Ok(conn)
}

// If no counterparty was set, signal the error.
None => Err(Kind::MissingCounterparty.into()),
}
}
}

impl Connection for ConnectionEnd {
Expand Down Expand Up @@ -76,6 +111,17 @@ impl Counterparty {
prefix,
})
}

pub fn from_proto_counterparty(pc: ProtoCounterparty) -> Result<Self, Error> {
match pc.prefix {
Some(prefix) => Counterparty::new(
pc.client_id,
pc.connection_id,
CommitmentPrefix::new(prefix.key_prefix),
),
None => Err(Kind::MissingCounterpartyPrefix.into()),
}
}
}

impl ConnectionCounterparty for Counterparty {
Expand Down
9 changes: 9 additions & 0 deletions modules/src/ics03_connection/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,15 @@ pub enum Kind {

#[error("invalid proof")]
InvalidProof,

#[error("queried for a non-existing connection")]
ConnectionNotFound,

#[error("missing counterparty")]
MissingCounterparty,

#[error("missing counterparty prefix")]
MissingCounterpartyPrefix,
}

impl Kind {
Expand Down
9 changes: 9 additions & 0 deletions modules/src/ics03_connection/exported.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,15 @@ impl State {
Self::Open => "OPEN",
}
}

pub fn from_i32(nr: i32) -> Self {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ancazamfir was not sure this is accurate, please double-check.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good.

match nr {
1 => Self::Init,
2 => Self::TryOpen,
3 => Self::Open,
_ => Self::Uninitialized,
}
}
}

impl std::str::FromStr for State {
Expand Down
4 changes: 2 additions & 2 deletions modules/src/ics03_connection/msgs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -308,7 +308,7 @@ mod tests {
client_id: "srcclient".to_string(),
counterparty_connection_id: "destconnection".to_string(),
counterparty_client_id: "destclient".to_string(),
counterparty_commitment_prefix: CommitmentPrefix {},
counterparty_commitment_prefix: CommitmentPrefix::new(vec![]),
};

let tests: Vec<Test> = vec![
Expand Down Expand Up @@ -398,7 +398,7 @@ mod tests {
client_id: "srcclient".to_string(),
counterparty_connection_id: "destconnection".to_string(),
counterparty_client_id: "destclient".to_string(),
counterparty_commitment_prefix: CommitmentPrefix {},
counterparty_commitment_prefix: CommitmentPrefix::new(vec![]),
counterparty_versions: vec!["1.0.0".to_string()],
proof_init: get_dummy_proof(),
proof_consensus: get_dummy_proof(),
Expand Down
31 changes: 21 additions & 10 deletions modules/src/ics03_connection/query.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,14 @@ use crate::path::{ConnectionPath, Path};
use crate::query::{IbcQuery, IbcResponse};
use crate::Height;

use crate::ics03_connection::error::Error;

// Import protobuf definitions.
use ibc_proto::connection::ConnectionEnd as ProtoConnectionEnd;

use bytes::Bytes;
use prost::Message;

pub struct QueryConnection {
pub chain_height: Height,
pub connection_id: ConnectionId,
Expand Down Expand Up @@ -79,14 +87,15 @@ impl IbcResponse<QueryConnection> for ConnectionResponse {
query: QueryConnection,
response: AbciQuery,
) -> Result<Self, error::Error> {
let connection = amino_unmarshal_binary_length_prefixed(&response.value)?;

Ok(ConnectionResponse::new(
query.connection_id,
connection,
response.proof,
response.height.into(),
))
match proto_unmarshal(response.value) {
Ok(decoded_conn) => Ok(ConnectionResponse::new(
query.connection_id,
decoded_conn,
response.proof,
response.height.into(),
)),
Err(e) => Err(error::Kind::ResponseParsing.context(e).into()),
}
}
}

Expand All @@ -105,6 +114,8 @@ impl IdentifiedConnectionEnd {
}
}

fn amino_unmarshal_binary_length_prefixed<T>(_bytes: &[u8]) -> Result<T, error::Error> {
todo!()
fn proto_unmarshal(bytes: Vec<u8>) -> Result<ConnectionEnd, Error> {
let buf = Bytes::from(bytes);
let decoded = ProtoConnectionEnd::decode(buf).unwrap();
ConnectionEnd::from_proto_connection_end(decoded)
}
23 changes: 19 additions & 4 deletions modules/src/ics23_commitment/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use serde_derive::{Deserialize, Serialize};

use crate::path::Path;
use std::fmt;
use tendermint::merkle::proof::Proof;

#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
Expand All @@ -14,7 +15,7 @@ impl CommitmentPath {
where
P: Path,
{
todo!()
CommitmentPath {}
}
}

Expand All @@ -31,7 +32,21 @@ impl CommitmentProof {
}
*/

#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct CommitmentPrefix;
#[derive(Clone, PartialEq, Serialize, Deserialize)]
pub struct CommitmentPrefix(Vec<u8>);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wondering if we should have a formatter for this. The output of the query shows: prefix: CommitmentPrefix([112, 114, 101, 102, 105, 120]) } (decimal), in the genesis and curl it's cHJlZml4 (base64), ascii is "prefix"

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Implemented a fmt::Debug trait to properly format the CommitmentPrefix output in this commit


// TODO: impl CommitPrefix
impl CommitmentPrefix {
pub fn new(content: Vec<u8>) -> Self {
Self { 0: content }
}
}

impl fmt::Debug for CommitmentPrefix {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let converted = String::from_utf8(self.clone().0);
match converted {
Ok(s) => write!(f, "{}", s),
Err(_e) => write!(f, "{:?}", &self.0),
}
}
}
5 changes: 3 additions & 2 deletions relayer/cli/src/commands/query/connection.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ 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
//
Expand All @@ -89,16 +90,16 @@ impl Runnable for QueryConnectionEndCmd {
//
// 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_connection(
&chain,
opts.height,
opts.connection_id.clone(),
opts.proof,
));

match res {
Ok(cs) => status_info!("connection query result: ", "{:?}", cs.connection),
Err(e) => status_info!("connection query error: ", "{:?}", e),
Err(e) => status_info!("connection query error", "{}", e),
}
}
}
Expand Down
5 changes: 4 additions & 1 deletion relayer/relay/src/query.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,10 @@ where
.map_err(|e| error::Kind::Rpc.context(e))?;

if !abci_response.code.is_ok() {
todo!() // TODO: Fail with response log
// Fail with response log
return Err(error::Kind::Rpc
.context(abci_response.log.to_string())
.into());
}

// Data that is not from trusted node or subspace query needs verification
Expand Down