diff --git a/modules/Cargo.toml b/modules/Cargo.toml index 1259bf578e..7445e05f5f 100644 --- a/modules/Cargo.toml +++ b/modules/Cargo.toml @@ -16,10 +16,10 @@ description = """ [dependencies] tendermint = "0.15.0" -tendermint-rpc = { version = "0.15.0", features=["client"] } +tendermint-rpc = { version = "0.15.0", features = ["client"] } # Proto definitions for all IBC-related interfaces, e.g., connections or channels. -ibc-proto = "0.2.2" +ibc-proto = "0.3.0" anomaly = "0.2.0" thiserror = "1.0.11" diff --git a/modules/src/address.rs b/modules/src/address.rs index 276562d4ed..a578b3cbc7 100644 --- a/modules/src/address.rs +++ b/modules/src/address.rs @@ -1 +1 @@ -pub struct AccAddress(Vec; +pub struct AccAddress(Vec); diff --git a/modules/src/ics02_client/client_def.rs b/modules/src/ics02_client/client_def.rs index 88614910e7..493dd43e44 100644 --- a/modules/src/ics02_client/client_def.rs +++ b/modules/src/ics02_client/client_def.rs @@ -1,24 +1,30 @@ +use prost::Message; use serde_derive::{Deserialize, Serialize}; use crate::downcast; use crate::ics02_client::client_type::ClientType; -use crate::ics02_client::error; +use crate::ics02_client::error::{self, Error}; use crate::ics02_client::header::Header; use crate::ics02_client::state::{ClientState, ConsensusState}; use crate::ics03_connection::connection::ConnectionEnd; use crate::ics07_tendermint as tendermint; use crate::ics07_tendermint::client_def::TendermintClient; +use crate::ics07_tendermint::client_state::ClientState as TendermintClientState; use crate::ics23_commitment::commitment::{CommitmentPrefix, CommitmentProof, CommitmentRoot}; use crate::ics24_host::identifier::{ClientId, ConnectionId}; +use crate::try_from_raw::TryFromRaw; + +use ibc_proto::ibc::tendermint::ClientState as RawTendermintClientState; use ::tendermint::block::Height; #[cfg(test)] -use crate::mock_client::client_def::MockClient; -#[cfg(test)] -use crate::mock_client::header::MockHeader; -#[cfg(test)] -use crate::mock_client::state::{MockClientState, MockConsensusState}; +use { + crate::mock_client::client_def::MockClient, + crate::mock_client::header::MockHeader, + crate::mock_client::state::{MockClientState, MockConsensusState}, + ibc_proto::ibc::mock::ClientState as RawMockClientState, +}; pub trait ClientDef: Clone { type Header: Header; @@ -63,6 +69,7 @@ pub trait ClientDef: Clone { ) -> Result<(), Box>; /// Verify the client state for this chain that it is stored on the counterparty chain. + #[allow(clippy::too_many_arguments)] fn verify_client_full_state( &self, _client_state: &Self::ClientState, @@ -106,12 +113,39 @@ impl Header for AnyHeader { #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] pub enum AnyClientState { - Tendermint(crate::ics07_tendermint::client_state::ClientState), + Tendermint(TendermintClientState), #[cfg(test)] Mock(MockClientState), } +impl AnyClientState { + pub fn from_any(any: prost_types::Any) -> Result { + match any.type_url.as_str() { + "ibc.tendermint.ClientState" => { + let raw = RawTendermintClientState::decode(any.value.as_ref()) + .map_err(|e| error::Kind::ProtoDecodingFailure.context(e))?; + let client_state = TendermintClientState::try_from(raw) + .map_err(|e| error::Kind::InvalidRawClientState.context(e))?; + + Ok(AnyClientState::Tendermint(client_state)) + } + + #[cfg(test)] + "ibc.mock.ClientState" => { + let raw = RawMockClientState::decode(any.value.as_ref()) + .map_err(|e| error::Kind::ProtoDecodingFailure.context(e))?; + let client_state = MockClientState::try_from(raw) + .map_err(|e| error::Kind::InvalidRawClientState.context(e))?; + + Ok(AnyClientState::Mock(client_state)) + } + + _ => Err(error::Kind::UnknownClientStateType(any.type_url).into()), + } + } +} + impl ClientState for AnyClientState { fn chain_id(&self) -> String { todo!() diff --git a/modules/src/ics02_client/error.rs b/modules/src/ics02_client/error.rs index 1434aec119..f6f19ffe23 100644 --- a/modules/src/ics02_client/error.rs +++ b/modules/src/ics02_client/error.rs @@ -28,6 +28,18 @@ pub enum Kind { #[error("header verification failed")] HeaderVerificationFailure, + #[error("unknown client state type: {0}")] + UnknownClientStateType(String), + + #[error("invalid raw client state")] + InvalidRawClientState, + + #[error("invalid raw header")] + InvalidRawHeader, + + #[error("Protobuf decoding failure")] + ProtoDecodingFailure, + #[error("mismatch between client and arguments types, expected: {0:?}")] ClientArgsTypeMismatch(ClientType), } diff --git a/modules/src/ics03_connection/connection.rs b/modules/src/ics03_connection/connection.rs index 1da5578204..225e4d6f36 100644 --- a/modules/src/ics03_connection/connection.rs +++ b/modules/src/ics03_connection/connection.rs @@ -1,12 +1,14 @@ use crate::ics03_connection::error::{Error, Kind}; use crate::ics23_commitment::commitment::CommitmentPrefix; +use crate::ics24_host::error::ValidationError; use crate::ics24_host::identifier::{ClientId, ConnectionId}; use crate::try_from_raw::TryFromRaw; -use serde_derive::{Deserialize, Serialize}; -// Import proto declarations. -use crate::ics24_host::error::ValidationError; -use ibc_proto::connection::{ConnectionEnd as RawConnectionEnd, Counterparty as RawCounterparty}; +use ibc_proto::ibc::connection::{ + ConnectionEnd as RawConnectionEnd, Counterparty as RawCounterparty, +}; + +use serde_derive::{Deserialize, Serialize}; use std::convert::{TryFrom, TryInto}; #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] diff --git a/modules/src/ics03_connection/handler.rs b/modules/src/ics03_connection/handler.rs index 93bf9048b5..29cfb3e0e2 100644 --- a/modules/src/ics03_connection/handler.rs +++ b/modules/src/ics03_connection/handler.rs @@ -95,7 +95,7 @@ where result, log, events, - } = conn_open_try::process(ctx, msg)?; + } = conn_open_try::process(ctx, *msg)?; keep(ctx, result.clone())?; Ok(HandlerOutput::builder() diff --git a/modules/src/ics03_connection/handler/conn_open_try.rs b/modules/src/ics03_connection/handler/conn_open_try.rs index 009b326553..e3a76c3043 100644 --- a/modules/src/ics03_connection/handler/conn_open_try.rs +++ b/modules/src/ics03_connection/handler/conn_open_try.rs @@ -126,20 +126,20 @@ mod tests { ctx: default_context .clone() .with_client_state(dummy_msg.client_id(), 10), - msg: ConnectionMsg::ConnectionOpenTry(dummy_msg.clone()), + msg: ConnectionMsg::ConnectionOpenTry(Box::new(dummy_msg.clone())), want_pass: true, }, Test { name: "Processing fails because no client exists".to_string(), ctx: default_context.clone(), - msg: ConnectionMsg::ConnectionOpenTry(dummy_msg.clone()), + msg: ConnectionMsg::ConnectionOpenTry(Box::new(dummy_msg.clone())), want_pass: false, }, Test { name: "Processing fails because connection exists in the store already".to_string(), ctx: default_context .add_connection(dummy_msg.connection_id().clone(), try_conn_end.clone()), - msg: ConnectionMsg::ConnectionOpenTry(dummy_msg.clone()), + msg: ConnectionMsg::ConnectionOpenTry(Box::new(dummy_msg.clone())), want_pass: false, }, ] diff --git a/modules/src/ics03_connection/msgs.rs b/modules/src/ics03_connection/msgs.rs index 90a3043c70..569d4217bb 100644 --- a/modules/src/ics03_connection/msgs.rs +++ b/modules/src/ics03_connection/msgs.rs @@ -14,23 +14,26 @@ //! TODO: Separate the Cosmos-SDK specific functionality from canonical ICS types. Decorators? #![allow(clippy::too_many_arguments)] + +use crate::ics02_client::client_def::AnyClientState; use crate::ics03_connection::connection::{validate_version, validate_versions, Counterparty}; use crate::ics03_connection::error::{Error, Kind}; use crate::ics24_host::identifier::{ClientId, ConnectionId}; use crate::proofs::{ConsensusProof, Proofs}; use crate::try_from_raw::TryFromRaw; use crate::tx_msg::Msg; -use ibc_proto::connection::MsgConnectionOpenAck as RawMsgConnectionOpenAck; -use ibc_proto::connection::MsgConnectionOpenConfirm as RawMsgConnectionOpenConfirm; -use ibc_proto::connection::MsgConnectionOpenInit as RawMsgConnectionOpenInit; -use ibc_proto::connection::MsgConnectionOpenTry as RawMsgConnectionOpenTry; -use crate::ics02_client::client_def::AnyClientState; +use ibc_proto::ibc::connection::MsgConnectionOpenAck as RawMsgConnectionOpenAck; +use ibc_proto::ibc::connection::MsgConnectionOpenConfirm as RawMsgConnectionOpenConfirm; +use ibc_proto::ibc::connection::MsgConnectionOpenInit as RawMsgConnectionOpenInit; +use ibc_proto::ibc::connection::MsgConnectionOpenTry as RawMsgConnectionOpenTry; + +use tendermint::account::Id as AccountId; +use tendermint::block::Height; + use serde_derive::{Deserialize, Serialize}; use std::convert::TryInto; use std::str::{from_utf8, FromStr}; -use tendermint::account::Id as AccountId; -use tendermint::block::Height; /// Message type for the `MsgConnectionOpenInit` message. pub const TYPE_MSG_CONNECTION_OPEN_INIT: &str = "connection_open_init"; @@ -48,7 +51,7 @@ pub const TYPE_MSG_CONNECTION_OPEN_CONFIRM: &str = "connection_open_confirm"; #[derive(Clone, Debug)] pub enum ConnectionMsg { ConnectionOpenInit(MsgConnectionOpenInit), - ConnectionOpenTry(MsgConnectionOpenTry), + ConnectionOpenTry(Box), // ConnectionOpenAck(MsgConnectionOpenAck), // ConnectionOpenConfirm(MsgConnectionOpenConfirm), } @@ -214,31 +217,19 @@ impl Msg for MsgConnectionOpenTry { } } -pub fn unpack_client_state( - any_client_raw: ::std::option::Option<::prost_types::Any>, -) -> Result, anomaly::Error> { - match any_client_raw { - None => Ok(None), - Some(_client_raw) => { - // TODO deserialize - //let _cs = client_raw.value.into(); - Ok(None) - } - } -} - impl TryFromRaw for MsgConnectionOpenTry { + type Error = Error; type RawType = RawMsgConnectionOpenTry; - type Error = anomaly::Error; + fn try_from(msg: RawMsgConnectionOpenTry) -> Result { let proof_height = msg .proof_height .ok_or_else(|| Kind::MissingProofHeight)? - .epoch_height; + .epoch_height; // FIXME: This is wrong as it does not take the epoch number into account let consensus_height = msg .consensus_height .ok_or_else(|| Kind::MissingConsensusHeight)? - .epoch_height; + .epoch_height; // FIXME: This is wrong as it does not take the epoch number into account let consensus_proof_obj = ConsensusProof::new(msg.proof_consensus.into(), consensus_height) .map_err(|e| Kind::InvalidProof.context(e))?; @@ -256,7 +247,10 @@ impl TryFromRaw for MsgConnectionOpenTry { .client_id .parse() .map_err(|e| Kind::IdentifierError.context(e))?, - client_state: unpack_client_state(msg.client_state) + client_state: msg + .client_state + .map(AnyClientState::from_any) + .transpose() .map_err(|e| Kind::InvalidProof.context(e))?, counterparty: msg .counterparty @@ -354,11 +348,11 @@ impl TryFromRaw for MsgConnectionOpenAck { let proof_height = msg .proof_height .ok_or_else(|| Kind::MissingProofHeight)? - .epoch_height; + .epoch_height; // FIXME: This is wrong as it does not take the epoch number into account let consensus_height = msg .consensus_height .ok_or_else(|| Kind::MissingConsensusHeight)? - .epoch_height; + .epoch_height; // FIXME: This is wrong as it does not take the epoch number into account let consensus_proof_obj = ConsensusProof::new(msg.proof_consensus.into(), consensus_height) .map_err(|e| Kind::InvalidProof.context(e))?; @@ -372,7 +366,10 @@ impl TryFromRaw for MsgConnectionOpenAck { .connection_id .parse() .map_err(|e| Kind::IdentifierError.context(e))?, - client_state: unpack_client_state(msg.client_state) + client_state: msg + .client_state + .map(AnyClientState::from_any) + .transpose() .map_err(|e| Kind::InvalidProof.context(e))?, version: validate_version(msg.version).map_err(|e| Kind::InvalidVersion.context(e))?, proofs: Proofs::new( @@ -444,7 +441,7 @@ impl TryFromRaw for MsgConnectionOpenConfirm { let proof_height = msg .proof_height .ok_or_else(|| Kind::MissingProofHeight)? - .epoch_height; + .epoch_height; // FIXME: This is wrong as it does not take the epoch number into account Ok(Self { connection_id: msg .connection_id @@ -462,14 +459,14 @@ impl TryFromRaw for MsgConnectionOpenConfirm { #[cfg(test)] pub mod test_util { - use ibc_proto::connection::Counterparty as RawCounterparty; - use ibc_proto::connection::MsgConnectionOpenAck as RawMsgConnectionOpenAck; - use ibc_proto::connection::MsgConnectionOpenConfirm as RawMsgConnectionOpenConfirm; - use ibc_proto::connection::MsgConnectionOpenInit as RawMsgConnectionOpenInit; - use ibc_proto::connection::MsgConnectionOpenTry as RawMsgConnectionOpenTry; + use ibc_proto::ibc::connection::Counterparty as RawCounterparty; + use ibc_proto::ibc::connection::MsgConnectionOpenAck as RawMsgConnectionOpenAck; + use ibc_proto::ibc::connection::MsgConnectionOpenConfirm as RawMsgConnectionOpenConfirm; + use ibc_proto::ibc::connection::MsgConnectionOpenInit as RawMsgConnectionOpenInit; + use ibc_proto::ibc::connection::MsgConnectionOpenTry as RawMsgConnectionOpenTry; - use ibc_proto::client::Height; - use ibc_proto::commitment::MerklePrefix; + use ibc_proto::ibc::client::Height; + use ibc_proto::ibc::commitment::MerklePrefix; pub fn get_dummy_proof() -> Vec { "Y29uc2Vuc3VzU3RhdGUvaWJjb25lY2xpZW50LzIy" @@ -573,12 +570,12 @@ mod tests { MsgConnectionOpenAck, MsgConnectionOpenConfirm, MsgConnectionOpenTry, }; use crate::try_from_raw::TryFromRaw; - use ibc_proto::client::Height; - use ibc_proto::connection::Counterparty as RawCounterparty; - use ibc_proto::connection::MsgConnectionOpenAck as RawMsgConnectionOpenAck; - use ibc_proto::connection::MsgConnectionOpenConfirm as RawMsgConnectionOpenConfirm; - use ibc_proto::connection::MsgConnectionOpenInit as RawMsgConnectionOpenInit; - use ibc_proto::connection::MsgConnectionOpenTry as RawMsgConnectionOpenTry; + use ibc_proto::ibc::client::Height; + use ibc_proto::ibc::connection::Counterparty as RawCounterparty; + use ibc_proto::ibc::connection::MsgConnectionOpenAck as RawMsgConnectionOpenAck; + use ibc_proto::ibc::connection::MsgConnectionOpenConfirm as RawMsgConnectionOpenConfirm; + use ibc_proto::ibc::connection::MsgConnectionOpenInit as RawMsgConnectionOpenInit; + use ibc_proto::ibc::connection::MsgConnectionOpenTry as RawMsgConnectionOpenTry; #[test] fn parse_connection_open_init_msg() { diff --git a/modules/src/ics04_channel/channel.rs b/modules/src/ics04_channel/channel.rs index 321f5e7605..d7fb41a016 100644 --- a/modules/src/ics04_channel/channel.rs +++ b/modules/src/ics04_channel/channel.rs @@ -1,10 +1,12 @@ use crate::ics04_channel::error::{self, Error, Kind}; use crate::ics24_host::identifier::{ChannelId, ConnectionId, PortId}; use crate::try_from_raw::TryFromRaw; + +use ibc_proto::ibc::channel::Channel as RawChannel; + use anomaly::fail; -use core::str::FromStr; -use ibc_proto::channel::Channel as RawChannel; use serde_derive::{Deserialize, Serialize}; +use std::str::FromStr; #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] pub struct ChannelEnd { @@ -221,11 +223,13 @@ impl State { #[cfg(test)] mod tests { + use std::str::FromStr; + use crate::ics04_channel::channel::ChannelEnd; use crate::try_from_raw::TryFromRaw; - use core::str::FromStr; - use ibc_proto::channel::Channel as RawChannel; - use ibc_proto::channel::Counterparty as RawCounterparty; + + use ibc_proto::ibc::channel::Channel as RawChannel; + use ibc_proto::ibc::channel::Counterparty as RawCounterparty; #[test] fn channel_end_try_from_raw() { diff --git a/modules/src/ics07_tendermint/client_state.rs b/modules/src/ics07_tendermint/client_state.rs index e48b4cbac6..fa83165efd 100644 --- a/modules/src/ics07_tendermint/client_state.rs +++ b/modules/src/ics07_tendermint/client_state.rs @@ -1,8 +1,10 @@ use crate::ics02_client::client_type::ClientType; - use crate::ics07_tendermint::error::{Error, Kind}; +use crate::try_from_raw::TryFromRaw; + use serde_derive::{Deserialize, Serialize}; -use std::time::Duration; +use std::{convert::TryInto, time::Duration}; + use tendermint::block::Height; #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] @@ -89,6 +91,44 @@ impl crate::ics02_client::state::ClientState for ClientState { } } +impl TryFromRaw for ClientState { + type Error = Error; + type RawType = ibc_proto::ibc::tendermint::ClientState; + + fn try_from(raw: Self::RawType) -> Result { + Ok(Self { + chain_id: raw.chain_id, + trusting_period: raw + .trusting_period + .ok_or_else(|| Kind::InvalidRawClientState.context("missing trusting period"))? + .try_into() + .map_err(|_| Kind::InvalidRawClientState.context("negative trusting period"))?, + unbonding_period: raw + .unbonding_period + .ok_or_else(|| Kind::InvalidRawClientState.context("missing unbonding period"))? + .try_into() + .map_err(|_| Kind::InvalidRawClientState.context("negative unbonding period"))?, + max_clock_drift: raw + .max_clock_drift + .ok_or_else(|| Kind::InvalidRawClientState.context("missing max clock drift"))? + .try_into() + .map_err(|_| Kind::InvalidRawClientState.context("negative max clock drift"))?, + latest_height: decode_height( + raw.latest_height + .ok_or_else(|| Kind::InvalidRawClientState.context("missing latest height"))?, + ), + frozen_height: decode_height( + raw.frozen_height + .ok_or_else(|| Kind::InvalidRawClientState.context("missing frozen height"))?, + ), + }) + } +} + +fn decode_height(height: ibc_proto::ibc::client::Height) -> Height { + Height(height.epoch_height) // FIXME: This is wrong as it does not take the epoch into account +} + #[cfg(test)] mod tests { use crate::ics07_tendermint::client_state::ClientState; diff --git a/modules/src/ics07_tendermint/error.rs b/modules/src/ics07_tendermint/error.rs index 4be7f96122..af9e13cf10 100644 --- a/modules/src/ics07_tendermint/error.rs +++ b/modules/src/ics07_tendermint/error.rs @@ -19,6 +19,9 @@ pub enum Kind { #[error("validation error")] ValidationError, + + #[error("invalid raw client state")] + InvalidRawClientState, } impl Kind { diff --git a/modules/src/ics23_commitment/merkle.rs b/modules/src/ics23_commitment/merkle.rs index aab52d43d3..845f2ea494 100644 --- a/modules/src/ics23_commitment/merkle.rs +++ b/modules/src/ics23_commitment/merkle.rs @@ -1,5 +1,6 @@ use crate::ics23_commitment::commitment::CommitmentPrefix; -use ibc_proto::commitment::MerklePath; + +use ibc_proto::ibc::commitment::MerklePath; pub fn apply_prefix( prefix: &CommitmentPrefix, diff --git a/modules/src/mock_client/header.rs b/modules/src/mock_client/header.rs index 22d173346a..0388be7b7d 100644 --- a/modules/src/mock_client/header.rs +++ b/modules/src/mock_client/header.rs @@ -1,6 +1,9 @@ use crate::ics02_client::client_def::AnyHeader; use crate::ics02_client::client_type::ClientType; +use crate::ics02_client::error::{self, Error}; use crate::ics02_client::header::Header; +use crate::try_from_raw::TryFromRaw; + use serde_derive::{Deserialize, Serialize}; use tendermint::block::Height; @@ -28,3 +31,17 @@ impl Header for MockHeader { todo!() } } + +impl TryFromRaw for MockHeader { + type Error = Error; + type RawType = ibc_proto::ibc::mock::Header; + + fn try_from(raw: Self::RawType) -> Result { + let proto_height = raw.height.ok_or_else(|| error::Kind::InvalidRawHeader)?; + Ok(Self(decode_height(proto_height))) + } +} + +fn decode_height(height: ibc_proto::ibc::client::Height) -> Height { + Height(height.epoch_height) // FIXME: This is wrong as it does not take the epoch into account +} diff --git a/modules/src/mock_client/state.rs b/modules/src/mock_client/state.rs index 02fb22cc90..a6e8fee154 100644 --- a/modules/src/mock_client/state.rs +++ b/modules/src/mock_client/state.rs @@ -2,13 +2,18 @@ use crate::ics02_client::client_def::{AnyClientState, AnyConsensusState, AnyHeader}; use crate::ics02_client::client_type::ClientType; +use crate::ics02_client::error::Error; +use crate::ics02_client::error::Kind; use crate::ics02_client::header::Header; use crate::ics02_client::state::{ClientState, ConsensusState}; use crate::ics23_commitment::commitment::CommitmentRoot; use crate::mock_client::header::MockHeader; +use crate::try_from_raw::TryFromRaw; + +use tendermint::block::Height; + use serde_derive::{Deserialize, Serialize}; use std::collections::HashMap; -use tendermint::block::Height; /// A mock of an IBC client record as it is stored in a mock context. /// For testing ICS02 handlers mostly, cf. `MockClientContext`. @@ -50,13 +55,25 @@ impl MockClientState { } } -#[cfg(test)] impl From for AnyClientState { fn from(mcs: MockClientState) -> Self { Self::Mock(mcs) } } +impl TryFromRaw for MockClientState { + type Error = Error; + type RawType = ibc_proto::ibc::mock::ClientState; + + fn try_from(raw: Self::RawType) -> Result { + let raw_header = raw + .header + .ok_or_else(|| Kind::InvalidRawClientState.context("missing header"))?; + + Ok(Self(MockHeader::try_from(raw_header)?)) + } +} + impl ClientState for MockClientState { fn chain_id(&self) -> String { todo!()