diff --git a/Cargo.toml b/Cargo.toml index 18c4aa0..756f907 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -53,7 +53,7 @@ tendermint-light-client-verifier = "0.34.1" thiserror = { version = "1.0.49" } [patch.crates-io] -ibc-proto = { git = "https://github.com/cosmos/ibc-proto-rs.git", rev = "6cbe4c7ace5a688bc98831fa9c1cc2dabf3b2976", default-features = false } # "0.42.2" +ibc-proto = { git = "https://github.com/cosmos/ibc-proto-rs.git", rev = "6d57834e03b5a3789c8d32a04c833d8926fad27b", default-features = false } # "0.42.2" [dev-dependencies] cw-multi-test = "2.0.0" diff --git a/src/context/mod.rs b/src/context/mod.rs index 5f55695..d6895df 100644 --- a/src/context/mod.rs +++ b/src/context/mod.rs @@ -1,6 +1,7 @@ -// mod ctx; +mod ctx; mod custom_ctx; mod execution_ctx; mod validation_ctx; +pub use ctx::*; pub use custom_ctx::*; diff --git a/src/types/client_state.rs b/src/types/client_state.rs new file mode 100644 index 0000000..01b32a7 --- /dev/null +++ b/src/types/client_state.rs @@ -0,0 +1,259 @@ +use ibc_clients::tendermint::context::ConsensusStateConverter; +use ibc_clients::tendermint::types::ConsensusState; +use ibc_clients::tendermint::client_state::ClientState as TendermintClientState; +use ibc_proto::ibc::lightclients::rollkit::v1::ClientState as RawClientState; +use ibc_core::client::context::client_state::{ClientStateValidation, ClientStateExecution}; +use ibc_core::client::context::client_state::ClientStateCommon; +use ibc_core::client::types::error::ClientError; + +use ibc_core::client::types::Height; +use ibc_core::client::types::Status; +use ibc_core::commitment_types::commitment::{ + CommitmentPrefix, CommitmentProofBytes, CommitmentRoot, +}; +use ibc_core::primitives::proto::{Any, Protobuf}; +use ibc_core::host::types::path::Path; +use ibc_core::host::types::identifiers::{ClientType, ClientId}; + +use crate::types::Error; +use crate::types::da_params::DaParams; +use crate::context::{ValidationContext, ExecutionContext}; + +pub const ROLLKIT_CLIENT_STATE_TYPE_URL: &str = "/ibc.lightclients.rollkit.v1.ClientState"; + +/// Defines the `ClientState` type for the Rollkit rollups. +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[derive(Clone, Debug, PartialEq)] +pub struct ClientState { + pub tendermint_client_state: TendermintClientState, + pub da_params: DaParams, +} + +impl ClientState { + pub fn new(tendermint_client_state: TendermintClientState, da_params: DaParams) -> Self { + Self { + tendermint_client_state, + da_params, + } + } + + pub fn da_client_id(&self) -> &ClientId { + &self.da_params.client_id + } + + pub fn da_fraud_period_window(&self) -> u64 { + self.da_params.fraud_period_window + } +} + +impl Protobuf for ClientState {} + +impl TryFrom for ClientState { + type Error = ClientError; + + fn try_from(raw: RawClientState) -> Result { + let tendermint_client_state = raw + .tendermint_client_state + .ok_or(Error::missing("tendermint_client_state"))? + .try_into()?; + + let da_params = raw + .da_params + .ok_or(Error::missing("da_params"))? + .try_into()?; + + Ok(Self::new(tendermint_client_state, da_params)) + } +} + +impl From for RawClientState { + fn from(value: ClientState) -> Self { + Self { + tendermint_client_state: Some(value.tendermint_client_state.into()), + da_params: Some(value.da_params.into()), + } + } +} + +impl Protobuf for ClientState {} + +impl TryFrom for ClientState { + type Error = ClientError; + + fn try_from(raw: Any) -> Result { + fn decode_client_state(value: &[u8]) -> Result { + let client_state = + Protobuf::::decode(value).map_err(|e| ClientError::Other { + description: e.to_string(), + })?; + + Ok(client_state) + } + + match raw.type_url.as_str() { + ROLLKIT_CLIENT_STATE_TYPE_URL => decode_client_state(&raw.value), + _ => Err(ClientError::UnknownClientStateType { + client_state_type: raw.type_url, + }), + } + } +} + +impl From for Any { + fn from(client_state: ClientState) -> Self { + Any { + type_url: ROLLKIT_CLIENT_STATE_TYPE_URL.to_string(), + value: Protobuf::::encode_vec(client_state), + } + } +} + +impl ClientStateCommon for ClientState { + fn verify_consensus_state(&self, consensus_state: Any) -> Result<(), ClientError> { + let tm_consensus_state = ConsensusState::try_from(consensus_state)?; + if tm_consensus_state.root().is_empty() { + return Err(ClientError::Other { + description: "empty commitment root".into(), + }); + }; + + Ok(()) + } + + fn client_type(&self) -> ClientType { + unimplemented!("client_type") + } + + fn latest_height(&self) -> Height { + self.0.latest_height() + } + + fn validate_proof_height(&self, proof_height: Height) -> Result<(), ClientError> { + if self.latest_height() < proof_height { + return Err(ClientError::InvalidProofHeight { + latest_height: self.latest_height(), + proof_height, + }); + } + unimplemented!("validate_proof_height") + } + + /// Perform client-specific verifications and check all data in the new + /// client state to be the same across all valid clients for the new chain. + /// + /// You can learn more about how to upgrade IBC-connected SDK chains in + /// [this](https://ibc.cosmos.network/main/ibc/upgrades/quick-guide.html) + /// guide + fn verify_upgrade_client( + &self, + _upgraded_client_state: Any, + _upgraded_consensus_state: Any, + _proof_upgrade_client: CommitmentProofBytes, + _proof_upgrade_consensus_state: CommitmentProofBytes, + _root: &CommitmentRoot, + ) -> Result<(), ClientError> { + unimplemented!("verify_upgrade_client") + } + + fn verify_membership( + &self, + _prefix: &CommitmentPrefix, + _proof: &CommitmentProofBytes, + _root: &CommitmentRoot, + _path: Path, + _value: Vec, + ) -> Result<(), ClientError> { + unimplemented!("verify_membership") + } + + fn verify_non_membership( + &self, + _prefix: &CommitmentPrefix, + _proof: &CommitmentProofBytes, + _root: &CommitmentRoot, + _path: Path, + ) -> Result<(), ClientError> { + unimplemented!("verify_non_membership") + } +} + +impl ClientStateValidation for ClientState +where + V: ValidationContext, + V::ConsensusStateRef: ConsensusStateConverter, +{ + fn verify_client_message( + &self, + _ctx: &V, + _client_id: &ClientId, + _client_message: Any, + ) -> Result<(), ClientError> { + unimplemented!("verify_client_message") + } + + fn check_for_misbehaviour( + &self, + _ctx: &V, + _client_id: &ClientId, + _client_message: Any, + ) -> Result { + unimplemented!("check_for_misbehaviour") + } + + fn status(&self, ctx: &V, client_id: &ClientId) -> Result { + unimplemented!("status") + } +} + +impl ClientStateExecution for ClientState +where + E: ExecutionContext, + E::ClientStateRef: From, + E::ConsensusStateRef: ConsensusStateConverter, +{ + fn initialise( + &self, + ctx: &mut E, + client_id: &ClientId, + consensus_state: Any, + ) -> Result<(), ClientError> { + unimplemented!("initialise") + } + + fn update_state( + &self, + ctx: &mut E, + client_id: &ClientId, + header: Any, + ) -> Result, ClientError> { + unimplemented!("update_state") + } + + fn update_state_on_misbehaviour( + &self, + ctx: &mut E, + client_id: &ClientId, + client_message: Any, + ) -> Result<(), ClientError> { + unimplemented!("update_state_on_misbehaviour") + } + + fn update_state_on_upgrade( + &self, + ctx: &mut E, + client_id: &ClientId, + upgraded_client_state: Any, + upgraded_consensus_state: Any, + ) -> Result { + unimplemented!("update_state_on_upgrade") + } + + // fn update_on_recovery( + // &self, + // ctx: &mut E, + // subject_client_id: &ClientId, + // substitute_client_state: Any, + // ) -> Result<(), ClientError> { + // unimplemented!("update_on_recovery") + // } +} \ No newline at end of file diff --git a/src/types/da_data.rs b/src/types/da_data.rs index c4976d0..284b470 100644 --- a/src/types/da_data.rs +++ b/src/types/da_data.rs @@ -1,19 +1,15 @@ use base64::engine::general_purpose; use base64::Engine; use core::fmt::{Debug, Display, Error as FmtError, Formatter}; -use core::str::FromStr; -use ibc_core::host::types::identifiers::ClientId; use ibc_core::primitives::proto::Protobuf; use ibc_proto::ibc::lightclients::rollkit::v1::DaData as RawDaData; use crate::types::Error; #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -/// Tendermint consensus header #[derive(Clone, PartialEq, Eq)] pub struct DaData { - pub client_id: ClientId, pub shared_proof: Vec, } @@ -27,17 +23,15 @@ impl Display for DaData { fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> { write!( f, - "DaData {{ client_id: {}, shared_proof: {} }}", - &self.client_id, + "DaData {{ shared_proof: {} }}", &general_purpose::STANDARD.encode(&self.shared_proof) ) } } impl DaData { - pub fn new(client_id: ClientId, shared_proof: Vec) -> Self { + pub fn new(shared_proof: Vec) -> Self { Self { - client_id, shared_proof, } } @@ -49,16 +43,13 @@ impl TryFrom for DaData { type Error = Error; fn try_from(raw: RawDaData) -> Result { - let client_id = ClientId::from_str(&raw.client_id).map_err(Error::source)?; - - Ok(Self::new(client_id, raw.shared_proof)) + Ok(Self::new(raw.shared_proof)) } } impl From for RawDaData { fn from(value: DaData) -> Self { Self { - client_id: value.client_id.to_string(), shared_proof: value.shared_proof, } } diff --git a/src/types/da_params.rs b/src/types/da_params.rs new file mode 100644 index 0000000..a429dff --- /dev/null +++ b/src/types/da_params.rs @@ -0,0 +1,62 @@ +use core::str::FromStr; +use core::fmt::{Debug, Display, Error as FmtError, Formatter}; + +use ibc_core::host::types::identifiers::ClientId; +use ibc_core::primitives::proto::Protobuf; +use ibc_proto::ibc::lightclients::rollkit::v1::DaParams as RawDaParams; + +use crate::types::Error; + +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[derive(Clone, PartialEq, Eq)] +pub struct DaParams { + pub client_id: ClientId, + pub fraud_period_window: u64, +} + +impl Debug for DaParams { + fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> { + write!(f, " DaParams {{...}}") + } +} + +impl Display for DaParams { + fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> { + write!( + f, + "DaParams {{ client_id: {}, fraud_period_window: {} }}", + &self.client_id, + &self.fraud_period_window, + ) + } +} + +impl DaParams { + pub fn new(client_id: ClientId, fraud_period_window: u64) -> Self { + Self { + client_id, + fraud_period_window, + } + } +} + +impl Protobuf for DaParams {} + +impl TryFrom for DaParams { + type Error = Error; + + fn try_from(raw: RawDaParams) -> Result { + let client_id = ClientId::from_str(&raw.client_id).map_err(Error::source)?; + + Ok(Self::new(client_id, raw.fraud_period_window)) + } +} + +impl From for RawDaParams { + fn from(value: DaParams) -> Self { + Self { + client_id: value.client_id.to_string(), + fraud_period_window: value.fraud_period_window + } + } +} diff --git a/src/types/mod.rs b/src/types/mod.rs index 21456b1..2279012 100644 --- a/src/types/mod.rs +++ b/src/types/mod.rs @@ -1,14 +1,17 @@ +mod codec; mod client_message; mod client_type; -mod codec; +mod client_state; mod consensus_state; +mod da_params; mod da_data; mod error; mod header; +pub use codec::*; pub use client_message::*; pub use client_type::*; -pub use codec::*; +pub use client_state::*; pub use consensus_state::*; pub use da_data::*; pub use error::*;