Skip to content

Commit

Permalink
fix: move consensus_state API implementation into ibc-client-tendermint
Browse files Browse the repository at this point in the history
  • Loading branch information
Farhad-Shabani committed Nov 22, 2023
1 parent 90c5633 commit db42ee2
Show file tree
Hide file tree
Showing 18 changed files with 204 additions and 126 deletions.
1 change: 1 addition & 0 deletions ibc-clients/ics07-tendermint/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ ibc-core-handler-types = { workspace = true }
ibc-primitives = { workspace = true }

# cosmos dependencies
tendermint = { workspace = true }
tendermint-light-client-verifier = { workspace = true, features = ["rust-crypto"] }

[features]
Expand Down
77 changes: 40 additions & 37 deletions ibc-clients/ics07-tendermint/src/client_state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,13 @@ use ibc_client_tendermint_types::error::Error;
use ibc_client_tendermint_types::proto::v1::ClientState as RawTmClientState;
use ibc_client_tendermint_types::proto::{Any, Protobuf};
use ibc_client_tendermint_types::{
client_type as tm_client_type, ClientState as TmClientState,
ConsensusState as TmConsensusState, Header as TmHeader, Misbehaviour as TmMisbehaviour,
client_type as tm_client_type, ClientState as ClientStateType,
ConsensusState as ConsensusStateType, Header as TmHeader, Misbehaviour as TmMisbehaviour,
};
use ibc_core_client::context::client_state::{
ClientStateCommon, ClientStateExecution, ClientStateValidation,
};
use ibc_core_client::context::consensus_state::ConsensusState;
use ibc_core_client::context::{ClientExecutionContext, ClientValidationContext};
use ibc_core_client::types::error::{ClientError, UpgradeClientError};
use ibc_core_client::types::{Height, Status, UpdateKind};
Expand All @@ -24,65 +25,67 @@ use ibc_core_host::ExecutionContext;
use ibc_primitives::prelude::*;
use prost::Message;

use super::consensus_state::ConsensusState as TmConsensusState;
use crate::context::{
CommonContext, ExecutionContext as TmExecutionContext, ValidationContext as TmValidationContext,
};

mod misbehaviour;
mod update_client;

/// Newtype wrapper around the `ClientState` type imported from the `ibc-client-tendermint-types`
/// crate. This wrapper exists so that we can bypass Rust's orphan rules and implement traits
/// from `ibc::core::client::context` on the `ClientState` type.
/// Newtype wrapper around the `ClientState` type imported from the
/// `ibc-client-tendermint-types` crate. This wrapper exists so that we can
/// bypass Rust's orphan rules and implement traits from
/// `ibc::core::client::context` on the `ClientState` type.
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[derive(Clone, Debug, PartialEq)]
pub struct ClientStateWrapper(TmClientState);
pub struct ClientState(ClientStateType);

impl ClientStateWrapper {
pub fn inner(&self) -> &TmClientState {
impl ClientState {
pub fn inner(&self) -> &ClientStateType {
&self.0
}
}

impl From<TmClientState> for ClientStateWrapper {
fn from(client_state: TmClientState) -> Self {
impl From<ClientStateType> for ClientState {
fn from(client_state: ClientStateType) -> Self {
Self(client_state)
}
}

impl Protobuf<RawTmClientState> for ClientStateWrapper {}
impl Protobuf<RawTmClientState> for ClientState {}

impl TryFrom<RawTmClientState> for ClientStateWrapper {
impl TryFrom<RawTmClientState> for ClientState {
type Error = Error;

fn try_from(raw: RawTmClientState) -> Result<Self, Self::Error> {
Ok(Self(TmClientState::try_from(raw)?))
Ok(Self(ClientStateType::try_from(raw)?))
}
}

impl From<ClientStateWrapper> for RawTmClientState {
fn from(client_state: ClientStateWrapper) -> Self {
impl From<ClientState> for RawTmClientState {
fn from(client_state: ClientState) -> Self {
client_state.0.into()
}
}

impl Protobuf<Any> for ClientStateWrapper {}
impl Protobuf<Any> for ClientState {}

impl TryFrom<Any> for ClientStateWrapper {
impl TryFrom<Any> for ClientState {
type Error = ClientError;

fn try_from(raw: Any) -> Result<Self, Self::Error> {
Ok(Self(TmClientState::try_from(raw)?))
Ok(Self(ClientStateType::try_from(raw)?))
}
}

impl From<ClientStateWrapper> for Any {
fn from(client_state: ClientStateWrapper) -> Self {
impl From<ClientState> for Any {
fn from(client_state: ClientState) -> Self {
client_state.0.into()
}
}

impl ClientStateCommon for ClientStateWrapper {
impl ClientStateCommon for ClientState {
fn verify_consensus_state(&self, consensus_state: Any) -> Result<(), ClientError> {
let tm_consensus_state = TmConsensusState::try_from(consensus_state)?;
if tm_consensus_state.root().is_empty() {
Expand Down Expand Up @@ -229,7 +232,7 @@ impl ClientStateCommon for ClientStateWrapper {
}
}

impl<V> ClientStateValidation<V> for ClientStateWrapper
impl<V> ClientStateValidation<V> for ClientState
where
V: ClientValidationContext + TmValidationContext,
V::AnyConsensusState: TryInto<TmConsensusState>,
Expand Down Expand Up @@ -310,10 +313,10 @@ where
}
}

impl<E> ClientStateExecution<E> for ClientStateWrapper
impl<E> ClientStateExecution<E> for ClientState
where
E: TmExecutionContext + ExecutionContext,
<E as ClientExecutionContext>::AnyClientState: From<ClientStateWrapper>,
<E as ClientExecutionContext>::AnyClientState: From<ClientState>,
<E as ClientExecutionContext>::AnyConsensusState: From<TmConsensusState>,
{
fn initialise(
Expand Down Expand Up @@ -372,7 +375,7 @@ where
let host_timestamp = CommonContext::host_timestamp(ctx)?;
let host_height = CommonContext::host_height(ctx)?;

let new_consensus_state = TmConsensusState::from(header.clone());
let new_consensus_state = ConsensusStateType::from(header.clone());
let new_client_state = self.0.clone().with_header(header)?;

ctx.store_consensus_state(
Expand All @@ -381,11 +384,11 @@ where
new_client_state.latest_height.revision_number(),
new_client_state.latest_height.revision_height(),
),
new_consensus_state.into(),
TmConsensusState::from(new_consensus_state).into(),
)?;
ctx.store_client_state(
ClientStatePath::new(client_id),
ClientStateWrapper::from(new_client_state).into(),
ClientState::from(new_client_state).into(),
)?;
ctx.store_update_time(client_id.clone(), header_height, host_timestamp)?;
ctx.store_update_height(client_id.clone(), header_height, host_height)?;
Expand All @@ -403,7 +406,7 @@ where
) -> Result<(), ClientError> {
let frozen_client_state = self.0.clone().with_frozen_height(Height::min(0));

let wrapped_frozen_client_state = ClientStateWrapper::from(frozen_client_state);
let wrapped_frozen_client_state = ClientState::from(frozen_client_state);

ctx.store_client_state(
ClientStatePath::new(client_id),
Expand All @@ -430,7 +433,7 @@ where
// parameters are ignored. All chain-chosen parameters come from
// committed client, all client-chosen parameters come from current
// client.
let new_client_state = TmClientState::new(
let new_client_state = ClientStateType::new(
upgraded_tm_client_state.0.chain_id,
self.0.trust_level,
self.0.trusting_period,
Expand All @@ -456,10 +459,10 @@ where
// the root is empty. The next consensus state submitted using update
// will be usable for packet-verification.
let sentinel_root = "sentinel_root".as_bytes().to_vec();
let new_consensus_state = TmConsensusState::new(
let new_consensus_state = ConsensusStateType::new(
sentinel_root.into(),
upgraded_tm_cons_state.timestamp,
upgraded_tm_cons_state.next_validators_hash,
upgraded_tm_cons_state.timestamp(),
upgraded_tm_cons_state.next_validators_hash(),
);

let latest_height = new_client_state.latest_height;
Expand All @@ -468,15 +471,15 @@ where

ctx.store_client_state(
ClientStatePath::new(client_id),
ClientStateWrapper::from(new_client_state).into(),
ClientState::from(new_client_state).into(),
)?;
ctx.store_consensus_state(
ClientConsensusStatePath::new(
client_id.clone(),
latest_height.revision_number(),
latest_height.revision_height(),
),
new_consensus_state.into(),
TmConsensusState::from(new_consensus_state).into(),
)?;
ctx.store_update_time(client_id.clone(), latest_height, host_timestamp)?;
ctx.store_update_height(client_id.clone(), latest_height, host_height)?;
Expand Down Expand Up @@ -519,7 +522,7 @@ mod tests {
struct Test {
name: String,
height: Height,
setup: Option<Box<dyn FnOnce(ClientStateWrapper) -> ClientStateWrapper>>,
setup: Option<Box<dyn FnOnce(ClientState) -> ClientState>>,
want_pass: bool,
}

Expand Down Expand Up @@ -553,8 +556,8 @@ mod tests {
)
.expect("Never fails");
let client_state = match test.setup {
Some(setup) => (setup)(ClientStateWrapper(client_state)),
_ => ClientStateWrapper(client_state),
Some(setup) => (setup)(ClientState(client_state)),
_ => ClientState(client_state),
};
let res = client_state.validate_proof_height(test.height);

Expand Down
15 changes: 7 additions & 8 deletions ibc-clients/ics07-tendermint/src/client_state/misbehaviour.rs
Original file line number Diff line number Diff line change
@@ -1,18 +1,16 @@
use ibc_client_tendermint_types::error::{Error, IntoResult};
use ibc_client_tendermint_types::{
check_header_trusted_next_validator_set, ConsensusState as TmConsensusState,
Header as TmHeader, Misbehaviour as TmMisbehaviour,
};
use ibc_client_tendermint_types::{Header as TmHeader, Misbehaviour as TmMisbehaviour};
use ibc_core_client::types::error::ClientError;
use ibc_core_host::types::identifiers::ClientId;
use ibc_core_host::types::path::ClientConsensusStatePath;
use ibc_primitives::prelude::*;
use ibc_primitives::Timestamp;
use tendermint_light_client_verifier::Verifier;

use super::{ClientStateWrapper, TmValidationContext};
use super::{ClientState as TmClientState, TmValidationContext};
use crate::consensus_state::ConsensusState as TmConsensusState;

impl ClientStateWrapper {
impl TmClientState {
// verify_misbehaviour determines whether or not two conflicting headers at
// the same height would have convinced the light client.
pub fn verify_misbehaviour<ClientValidationContext>(
Expand Down Expand Up @@ -70,7 +68,7 @@ impl ClientStateWrapper {
current_timestamp: Timestamp,
) -> Result<(), ClientError> {
// ensure correctness of the trusted next validator set provided by the relayer
check_header_trusted_next_validator_set(header, trusted_consensus_state)?;
header.check_trusted_next_validator_set(trusted_consensus_state.inner())?;

// ensure trusted consensus state is within trusting period
{
Expand Down Expand Up @@ -101,7 +99,8 @@ impl ClientStateWrapper {
.map_err(|e| ClientError::Other {
description: format!("failed to parse chain id: {}", e),
})?;
let trusted_state = header.as_trusted_block_state(trusted_consensus_state, &chain_id)?;
let trusted_state =
header.as_trusted_block_state(trusted_consensus_state.inner(), &chain_id)?;

let options = self.0.as_light_client_options()?;
let current_timestamp = current_timestamp.into_tm_time().ok_or(ClientError::Other {
Expand Down
24 changes: 12 additions & 12 deletions ibc-clients/ics07-tendermint/src/client_state/update_client.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
use ibc_client_tendermint_types::error::{Error, IntoResult};
use ibc_client_tendermint_types::{
check_header_trusted_next_validator_set, ConsensusState as TmConsensusState, Header as TmHeader,
};
use ibc_client_tendermint_types::{ConsensusState as ConsensusStateType, Header as TmHeader};
use ibc_core_client::context::ClientExecutionContext;
use ibc_core_client::types::error::ClientError;
use ibc_core_host::types::identifiers::ClientId;
Expand All @@ -10,10 +8,11 @@ use ibc_primitives::prelude::*;
use tendermint_light_client_verifier::types::{TrustedBlockState, UntrustedBlockState};
use tendermint_light_client_verifier::Verifier;

use super::ClientStateWrapper;
use super::ClientState;
use crate::consensus_state::ConsensusState as TmConsensusState;
use crate::context::{CommonContext, ValidationContext as TmValidationContext};

impl ClientStateWrapper {
impl ClientState {
pub fn verify_header<ClientValidationContext>(
&self,
ctx: &ClientValidationContext,
Expand Down Expand Up @@ -47,15 +46,15 @@ impl ClientStateWrapper {
description: err.to_string(),
})?;

check_header_trusted_next_validator_set(&header, &trusted_consensus_state)?;
header.check_trusted_next_validator_set(trusted_consensus_state.inner())?;

TrustedBlockState {
chain_id: &self.0.chain_id.to_string().try_into().map_err(|e| {
ClientError::Other {
description: format!("failed to parse chain id: {}", e),
}
})?,
header_time: trusted_consensus_state.timestamp,
header_time: trusted_consensus_state.timestamp(),
height: header.trusted_height.revision_height().try_into().map_err(
|_| ClientError::ClientSpecific {
description: Error::InvalidHeaderHeight {
Expand All @@ -65,7 +64,7 @@ impl ClientStateWrapper {
},
)?,
next_validators: &header.trusted_next_validator_set,
next_validators_hash: trusted_consensus_state.next_validators_hash,
next_validators_hash: trusted_consensus_state.next_validators_hash(),
}
};

Expand Down Expand Up @@ -104,8 +103,6 @@ impl ClientStateWrapper {
where
ClientValidationContext: TmValidationContext,
{
let header_consensus_state = TmConsensusState::from(header.clone());

let maybe_existing_consensus_state = {
let path_at_header_height = ClientConsensusStatePath::new(
client_id.clone(),
Expand All @@ -124,6 +121,9 @@ impl ClientStateWrapper {
description: err.to_string(),
})?;

let header_consensus_state =
TmConsensusState::from(ConsensusStateType::from(header.clone()));

// There is evidence of misbehaviour if the stored consensus state
// is different from the new one we received.
Ok(existing_consensus_state != header_consensus_state)
Expand All @@ -144,7 +144,7 @@ impl ClientStateWrapper {
description: err.to_string(),
})?;

if header.signed_header.header().time <= prev_cs.timestamp {
if header.signed_header.header().time <= prev_cs.timestamp() {
return Ok(true);
}
}
Expand All @@ -163,7 +163,7 @@ impl ClientStateWrapper {
description: err.to_string(),
})?;

if header.signed_header.header().time >= next_cs.timestamp {
if header.signed_header.header().time >= next_cs.timestamp() {
return Ok(true);
}
}
Expand Down
Loading

0 comments on commit db42ee2

Please sign in to comment.