Skip to content

Commit

Permalink
Add MsgCreateClient and MsgUpdateClient message structs (#15)
Browse files Browse the repository at this point in the history
* Add stubs for MsgUpdateClient message, and other related structs

* Flesh out MsgUpdateClient and implement MsgCreateClient and its deps

* Remove ClientType::Unknown

* Cleanup
  • Loading branch information
romac authored Mar 2, 2020
1 parent e5970e7 commit f6ecd3c
Show file tree
Hide file tree
Showing 28 changed files with 623 additions and 42 deletions.
12 changes: 10 additions & 2 deletions modules/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,9 +1,17 @@
[package]
name = "modules"
name = "relayer-modules"
version = "0.1.0"
authors = ["Anca Zamfir <[email protected]>"]
edition = "2018"
authors = [
"Anca Zamfir <[email protected]>",
"Romain Ruetschi <[email protected]>"
]

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
tendermint = { path = "../../tendermint-rs/tendermint" }
anomaly = "0.2.0"
thiserror = "1.0.11"
serde_derive = "1.0.104"
serde = "1.0.104"
Empty file removed modules/src/02-client/handler.rs
Empty file.
28 changes: 0 additions & 28 deletions modules/src/07-tendermint/msgs.rs

This file was deleted.

Empty file.
Empty file removed modules/src/24-host/validate.rs
Empty file.
56 changes: 56 additions & 0 deletions modules/src/ics02_client/client_type.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
use super::error;
use anomaly::fail;

/// Type of the consensus algorithm
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum ClientType {
Tendermint = 1,
}

impl ClientType {
/// Yields the identifier of this client type as a string
pub fn as_string(&self) -> &'static str {
match self {
Self::Tendermint => "tendermint",
}
}
}

impl std::str::FromStr for ClientType {
type Err = error::Error;

fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"tendermint" => Ok(Self::Tendermint),
_ => fail!(error::Kind::UnknownClientType, s),
}
}
}

#[cfg(test)]
mod tests {
use super::ClientType;
use std::str::FromStr;

#[test]
fn parse_tendermint_client_type() {
let client_type = ClientType::from_str("tendermint");
match client_type {
Ok(ClientType::Tendermint) => assert!(true),
Err(_) => assert!(false, "parse failed"),
}
}

#[test]
fn parse_unknown_client_type() {
let client_type = ClientType::from_str("some-random-client-type");

match client_type {
Err(err) => assert_eq!(
format!("{}", err),
"unknown client type: some-random-client-type"
),
_ => assert!(false, "parse didn't fail"),
}
}
}
16 changes: 16 additions & 0 deletions modules/src/ics02_client/error.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
use anomaly::{BoxError, Context};
use thiserror::Error;

pub type Error = anomaly::Error<Kind>;

#[derive(Clone, Debug, Error)]
pub enum Kind {
#[error("unknown client type")]
UnknownClientType,
}

impl Kind {
pub fn context(self, source: impl Into<BoxError>) -> Context<Self> {
Context::new(self, Some(source.into()))
}
}
11 changes: 11 additions & 0 deletions modules/src/ics02_client/header.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
use super::client_type::ClientType;
use crate::Height;

/// Abstract of consensus state update information
pub trait Header {
/// The type of client (eg. Tendermint)
fn client_type(&self) -> ClientType;

/// The height of the consensus state
fn height(&self) -> Height;
}
7 changes: 7 additions & 0 deletions modules/src/ics02_client/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
//! ICS 02: IBC Client implementation
pub mod client_type;
pub mod error;
pub mod header;
pub mod msgs;
pub mod state;
41 changes: 41 additions & 0 deletions modules/src/ics02_client/msgs.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
use super::client_type::ClientType;
use super::header::Header;
use super::state::ConsensusState;
use crate::ics24_host::client::ClientId;

// FIXME: Remove Header associated type and use Box<dyn tendermint::lite::Header> instead of Self::Header?

pub trait Msg {
type ValidationError: std::error::Error;
type Header: Header;

fn route(&self) -> String; // TODO: Make this &'static str or custom type?
fn get_type(&self) -> String;

fn validate_basic(&self) -> Result<(), Self::ValidationError>;

fn get_sign_bytes(&self) -> Vec<u8>;
fn get_signers(&self) -> Vec<ClientId>;
fn get_client_id(&self) -> &ClientId;
fn get_header(&self) -> &Self::Header;
}

pub trait MsgUpdateClient
where
Self: Msg,
{
fn client_id(&self) -> &ClientId;
fn header(&self) -> &Self::Header;
}

pub trait MsgCreateClient
where
Self: Msg,
{
type ConsensusState: ConsensusState;

fn client_id(&self) -> &ClientId;
fn client_type(&self) -> ClientType;
fn header(&self) -> &Self::Header;
fn consensus_state(&self) -> Self::ConsensusState;
}
20 changes: 20 additions & 0 deletions modules/src/ics02_client/state.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
use super::client_type::ClientType;

use crate::ics23_commitment::CommitmentRoot;
use crate::Height;

pub trait ConsensusState {
type ValidationError: std::error::Error;

/// Type of client associated with this consensus state (eg. Tendermint)
fn client_type(&self) -> ClientType;

/// Height of consensus state
fn height(&self) -> Height;

/// Commitment root of the consensus state, which is used for key-value pair verification.
fn root(&self) -> &CommitmentRoot;

/// Performs basic validation of the consensus state
fn validate_basic(&self) -> Result<(), Self::ValidationError>;
}
28 changes: 28 additions & 0 deletions modules/src/ics07_tendermint/error.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
use anomaly::{BoxError, Context};
use thiserror::Error;

pub type Error = anomaly::Error<Kind>;

#[derive(Clone, Debug, Error)]
pub enum Kind {
#[error("invalid trusting period")]
InvalidTrustingPeriod,

#[error("invalid unbounding period")]
InvalidUnboundingPeriod,

#[error("invalid address")]
InvalidAddress,

#[error("invalid header, failed basic validation with its own chain-id")]
InvalidHeader,

#[error("validation error")]
ValidationError,
}

impl Kind {
pub fn context(self, source: impl Into<BoxError>) -> Context<Self> {
Context::new(self, Some(source.into()))
}
}
27 changes: 27 additions & 0 deletions modules/src/ics07_tendermint/header.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
use serde_derive::{Deserialize, Serialize};

// use tendermint::lite::types::SignedHeader;
use tendermint::block::signed_header::SignedHeader;
use tendermint::validator::Set as ValidatorSet;

use crate::ics02_client::client_type::ClientType;
use crate::Height;

/// Tendermint consensus header
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct Header {
pub signed_header: SignedHeader,
pub validator_set: ValidatorSet,
pub next_validator_set: ValidatorSet,
}

impl crate::ics02_client::header::Header for Header {
fn client_type(&self) -> ClientType {
ClientType::Tendermint
}

fn height(&self) -> Height {
use tendermint::lite::types::Header;
self.signed_header.header.height()
}
}
6 changes: 6 additions & 0 deletions modules/src/ics07_tendermint/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
//! ICS 07: Tendermint Client
pub mod error;
pub mod header;
pub mod msgs;
pub mod state;
2 changes: 2 additions & 0 deletions modules/src/ics07_tendermint/msgs.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
pub mod create_client;
pub mod update_client;
100 changes: 100 additions & 0 deletions modules/src/ics07_tendermint/msgs/create_client.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
use crate::ics02_client::client_type::ClientType;
use crate::ics02_client::msgs::Msg;
use crate::ics07_tendermint::header::Header;
use crate::ics07_tendermint::state::consensus::ConsensusState;
use crate::ics23_commitment::CommitmentRoot;
use crate::ics24_host::client::ClientId;

use serde_derive::{Deserialize, Serialize};
use tendermint::account::Id as AccountId;

pub const TYPE_MSG_CREATE_CLIENT: &str = "create_client";

#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct MsgCreateClient {
client_id: ClientId,
header: Header,
trusting_period: std::time::Duration,
bonding_period: std::time::Duration,
signer: AccountId,
}

impl MsgCreateClient {
pub fn new(
client_id: ClientId,
header: Header,
trusting_period: std::time::Duration,
bonding_period: std::time::Duration,
signer: AccountId,
) -> Self {
Self {
client_id,
header,
trusting_period,
bonding_period,
signer,
}
}
}

impl Msg for MsgCreateClient {
type ValidationError = crate::ics24_host::error::ValidationError;
type Header = Header;

fn route(&self) -> String {
crate::keys::ROUTER_KEY.to_string()
}

fn get_type(&self) -> String {
TYPE_MSG_CREATE_CLIENT.to_string()
}

fn validate_basic(&self) -> Result<(), Self::ValidationError> {
// Nothing to validate since both ClientId and AccountId perform validation on creation.
Ok(())
}

fn get_sign_bytes(&self) -> Vec<u8> {
todo!()
}

fn get_signers(&self) -> Vec<ClientId> {
vec![self.client_id.clone()]
}

fn get_client_id(&self) -> &ClientId {
&self.client_id
}

fn get_header(&self) -> &Self::Header {
&self.header
}
}

impl crate::ics02_client::msgs::MsgCreateClient for MsgCreateClient {
type ConsensusState = ConsensusState;

fn client_id(&self) -> &ClientId {
&self.client_id
}

fn header(&self) -> &Self::Header {
&self.header
}

fn consensus_state(&self) -> Self::ConsensusState {
let root = CommitmentRoot; // TODO
let header = &self.header.signed_header.header;

ConsensusState::new(
root,
header.height.into(),
header.time,
self.header.validator_set.clone(),
)
}

fn client_type(&self) -> ClientType {
ClientType::Tendermint
}
}
Loading

0 comments on commit f6ecd3c

Please sign in to comment.