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 5 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
5 changes: 5 additions & 0 deletions modules/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,12 @@ 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" }

[build-dependencies]
prost-build = { version = "0.6.1" }
5 changes: 5 additions & 0 deletions modules/build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
extern crate prost_build;

fn main() {
prost_build::compile_protos(&["src/proto/connection.proto"], &["src/proto"]).unwrap();
}
46 changes: 46 additions & 0 deletions modules/src/ics03_connection/connection.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
use super::exported::*;
use crate::ics03_connection::error::{Error, Kind};
use crate::ics03_connection::proto_connection;
use crate::ics23_commitment::CommitmentPrefix;
use crate::ics24_host::identifier::{ClientId, ConnectionId};
use serde_derive::{Deserialize, Serialize};

use anomaly::fail;
use std::str::FromStr;

#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct ConnectionEnd {
state: State,
Expand All @@ -25,6 +29,34 @@ 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(pc: proto_connection::ConnectionEnd) -> Result<Self, Error> {
// The Counterparty field is an Option, may be missing.
match pc.counterparty {
Some(cp) => {
let mut conn = ConnectionEnd::new(
ClientId::from_str(&pc.client_id).unwrap(),
Copy link
Collaborator

Choose a reason for hiding this comment

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

Could we get rid of the unwrap()s? If the user issues a query command and gets back a few pages of traces it does not help. I had this comment earlier but I guess it got lost. Try to query with non-exsiting connection id.

Copy link
Member

Choose a reason for hiding this comment

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

I'd like to make this into a From trait, if possible.

Copy link
Member

Choose a reason for hiding this comment

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

Also I guess this should be verifying all the fields, not just 2? And should we really have an error per field or maybe start with a more general InvalidConnectionEnd error of some kind and include what's missing as a string? Not sure ...

Copy link
Member Author

@adizere adizere Jul 14, 2020

Choose a reason for hiding this comment

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

I'd like to make this into a From trait, if possible.

Either option could work, the question is if we want to keep validation inside the from or outside. The current code uses the FromStr trait, with the signature fn from_str(s: &str) -> Result<Self, Self::Err> so we can do validation inside there and return error if validation fails. With From, the sig is fn from(T) -> Self so we'd have to do validation after calling from. Is it generally speaking, or specifically in this case, better to do validation outside of from?

LE: Maybe this helps?

Also I guess this should be verifying all the fields, not just 2?

Agree this deserves a discussion to find a more principled approach.

Counterparty::from_proto_counterparty(cp).unwrap(),
pc.versions,
)
.unwrap();

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

// If no counterparty was set, signal the error.
None => fail!(
Kind::MissingCounterparty,
"no counterparty in the given connection"
),
}
}
}

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

pub fn from_proto_counterparty(pc: proto_connection::Counterparty) -> Result<Self, Error> {
match pc.prefix {
Some(prefix) => Counterparty::new(
pc.client_id,
pc.connection_id,
CommitmentPrefix::new(prefix.key_prefix),
),
None => fail!(
Kind::MissingCounterpartyPrefix,
"no prefix in the given counterparty"
),
}
}
}

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

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

#[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
5 changes: 5 additions & 0 deletions modules/src/ics03_connection/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,8 @@ pub mod events;
pub mod exported;
pub mod msgs;
pub mod query;

// Use the generated proto file for the connection according to prost_build instructions
pub mod proto_connection {
include!(concat!(env!("OUT_DIR"), "/connection.rs"));
}
16 changes: 12 additions & 4 deletions modules/src/ics03_connection/query.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,12 @@ use crate::path::{ConnectionPath, Path};
use crate::query::{IbcQuery, IbcResponse};
use crate::Height;

// Protobuf
use crate::ics03_connection::error::Error;
use crate::ics03_connection::proto_connection;
use bytes::Bytes;
use prost::Message;

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

Ok(ConnectionResponse::new(
query.connection_id,
connection,
decoded_conn,
response.proof,
response.height.into(),
))
Expand All @@ -105,6 +111,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 = proto_connection::ConnectionEnd::decode(buf).unwrap();
ConnectionEnd::from_proto_connection(decoded)
}
10 changes: 7 additions & 3 deletions modules/src/ics23_commitment/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ impl CommitmentPath {
where
P: Path,
{
todo!()
CommitmentPath {}
}
}

Expand All @@ -32,6 +32,10 @@ impl CommitmentProof {
*/

#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct CommitmentPrefix;
pub struct CommitmentPrefix(std::vec::Vec<u8>);

// TODO: impl CommitPrefix
impl CommitmentPrefix {
pub fn new(content: Vec<u8>) -> Self {
Self { 0: content }
}
}
2 changes: 1 addition & 1 deletion modules/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
trivial_casts,
trivial_numeric_casts,
unused_import_braces,
unused_qualifications,
//unused_qualifications,
rust_2018_idioms
)]
#![allow(dead_code)]
Expand Down
54 changes: 54 additions & 0 deletions modules/src/proto/connection.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
syntax = "proto3";

package connection;

// ICS03 - Connection Data Structures as defined in
// https://github.com/cosmos/ics/tree/master/spec/ics-003-connection-semantics#data-structures

// ConnectionEnd defines a stateful object on a chain connected to another separate
// one.
// NOTE: there must only be 2 defined ConnectionEnds to establish a connection
// between two chains.
message ConnectionEnd {
// connection identifier.
string id = 1;
// client associated with this connection.
string client_id = 2;
// opaque string which can be utilised to determine encodings or protocols for
// channels or packets utilising this connection
repeated string versions = 3;
// current state of the connection end.
State state = 4;
// counterparty chain associated with this connection.
Counterparty counterparty = 5;
}

// State defines if a connection is in one of the following states:
// INIT, TRYOPEN, OPEN or UNINITIALIZED.
enum State {
// Default State
STATE_UNINITIALIZED_UNSPECIFIED = 0;
// A connection end has just started the opening handshake.
STATE_INIT = 1;
// A connection end has acknowledged the handshake step on the counterparty chain.
STATE_TRYOPEN = 2;
// A connection end has completed the handshake.
STATE_OPEN = 3;
}

// Counterparty defines the counterparty chain associated with a connection end.
message Counterparty {
// identifies the client on the counterparty chain associated with a given connection.
string client_id = 1;
// identifies the connection end on the counterparty chain associated with a given connection.
string connection_id = 2;
// commitment merkle prefix of the counterparty chain
MerklePrefix prefix = 3;
}


// MerklePrefix is merkle path prefixed to the key.
// The constructed key from the Path and the key will be append(Path.KeyPath, append(Path.KeyPrefix, key...))
message MerklePrefix {
bytes key_prefix = 1;
}