Skip to content

Commit

Permalink
Initial refactoring of TendermintClientState::verify_header into CGP …
Browse files Browse the repository at this point in the history
…component
  • Loading branch information
soareschen committed Oct 26, 2023
1 parent 6f59bfd commit 06fab7d
Show file tree
Hide file tree
Showing 3 changed files with 140 additions and 76 deletions.
213 changes: 137 additions & 76 deletions crates/ibc-cosmos-components/src/client/verify.rs
Original file line number Diff line number Diff line change
@@ -1,106 +1,167 @@
use alloc::format;
use core::fmt::Display;

use cgp_core::prelude::*;
use ibc::clients::ics07_tendermint::consensus_state::ConsensusState as TmConsensusState;
use ibc::clients::ics07_tendermint::error::{Error, IntoResult};
use ibc::clients::ics07_tendermint::header::Header as TmHeader;
use ibc::clients::ics07_tendermint::ValidationContext as TmValidationContext;
use ibc::core::ics02_client::error::ClientError;
use ibc::core::ics24_host::identifier::{ChainId, ClientId};
use ibc::core::ics24_host::path::ClientConsensusStatePath;
use ibc::core::timestamp::Timestamp;
use ibc::core::ContextError;
use ibc::prelude::ToString;
use tendermint_light_client_verifier::options::Options;
use tendermint_light_client_verifier::types::{TrustedBlockState, UntrustedBlockState};
use tendermint_light_client_verifier::{ProdVerifier, Verifier};

pub trait HasClientStateMethods {
pub trait HasChainId {
fn chain_id(&self) -> &ChainId;
}

pub trait HasLightClientOptions {
fn light_client_options(&self) -> Options;
}

pub trait HasVerifier {
fn verifier(&self) -> &ProdVerifier;
}

pub fn verify_header<ClientValidationContext, ClientState>(
client_state: &ClientState,
ctx: &ClientValidationContext,
client_id: &ClientId,
header: TmHeader,
) -> Result<(), ClientError>
pub trait HasHostTimestamp {
fn host_timestamp(&self) -> Result<Timestamp, ContextError>;
}

pub trait HasConsensusState: HasAnyConsensusStateType {
fn consensus_state(
&self,
client_cons_state_path: &ClientConsensusStatePath,
) -> Result<Self::AnyConsensusState, ContextError>;
}

pub trait HasAnyConsensusStateType {
type AnyConsensusState;
}

pub trait HasClientStateType<ClientType> {
type ClientState;
}

pub trait HasModule {
type ModuleId;

type Module;
}

pub trait CanGetRoute: HasModule {
fn get_route(&self, module_id: &Self::ModuleId) -> &Self::Module;
}

pub struct TendermintClientType;

#[derive_component(HeaderVerifierComponent, HeaderVerifier<Context>)]

Check warning on line 61 in crates/ibc-cosmos-components/src/client/verify.rs

View check run for this annotation

Codecov / codecov/patch

crates/ibc-cosmos-components/src/client/verify.rs#L61

Added line #L61 was not covered by tests
pub trait CanVerifyHeader<ClientType>: HasClientStateType<ClientType> + HasErrorType {
fn verify_header(
&self,
client_state: &Self::ClientState,
client_id: &ClientId,
header: TmHeader,
) -> Result<(), Self::Error>;
}

pub struct VerifyTendermintHeader;

impl<Context> HeaderVerifier<Context, TendermintClientType> for VerifyTendermintHeader
where
ClientState: HasClientStateMethods,
ClientValidationContext: TmValidationContext,
Context: HasConsensusState
+ HasHostTimestamp
+ HasClientStateType<TendermintClientType>
+ HasErrorType<Error = ClientError>,
Context::AnyConsensusState: TryInto<TmConsensusState>,
<Context::AnyConsensusState as TryInto<TmConsensusState>>::Error: Display,
Context::ClientState: HasChainId + HasLightClientOptions + HasVerifier,
{
// Checks that the header fields are valid.
header.validate_basic()?;
fn verify_header(
ctx: &Context,
client_state: &Context::ClientState,
client_id: &ClientId,
header: TmHeader,
) -> Result<(), ClientError>
where
Context: HasConsensusState + HasHostTimestamp + HasClientStateType<TendermintClientType>,
Context::AnyConsensusState: TryInto<TmConsensusState>,
<Context::AnyConsensusState as TryInto<TmConsensusState>>::Error: Display,
Context::ClientState: HasChainId + HasLightClientOptions + HasVerifier,
{
// Checks that the header fields are valid.
header.validate_basic()?;

Check warning on line 96 in crates/ibc-cosmos-components/src/client/verify.rs

View check run for this annotation

Codecov / codecov/patch

crates/ibc-cosmos-components/src/client/verify.rs#L96

Added line #L96 was not covered by tests

// The tendermint-light-client crate though works on heights that are assumed
// to have the same revision number. We ensure this here.
header.verify_chain_id_version_matches_height(client_state.chain_id())?;
// The tendermint-light-client crate though works on heights that are assumed
// to have the same revision number. We ensure this here.
header.verify_chain_id_version_matches_height(client_state.chain_id())?;

Check warning on line 100 in crates/ibc-cosmos-components/src/client/verify.rs

View check run for this annotation

Codecov / codecov/patch

crates/ibc-cosmos-components/src/client/verify.rs#L100

Added line #L100 was not covered by tests

// Delegate to tendermint-light-client, which contains the required checks
// of the new header against the trusted consensus state.
{
let trusted_state = {
let trusted_client_cons_state_path =
ClientConsensusStatePath::new(client_id, &header.trusted_height);
let trusted_consensus_state: TmConsensusState = ctx
.consensus_state(&trusted_client_cons_state_path)?
.try_into()
.map_err(|err| ClientError::Other {
description: err.to_string(),
})?;

check_header_trusted_next_validator_set(&header, &trusted_consensus_state)?;

TrustedBlockState {
chain_id: &client_state
.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,
height: header
.trusted_height
.revision_height()
.try_into()
.map_err(|_| ClientError::ClientSpecific {
description: Error::InvalidHeaderHeight {
height: header.trusted_height.revision_height(),
}
.to_string(),
})?,
next_validators: &header.trusted_next_validator_set,
next_validators_hash: trusted_consensus_state.next_validators_hash,
}
};

let untrusted_state = UntrustedBlockState {
signed_header: &header.signed_header,
validators: &header.validator_set,
// NB: This will skip the
// VerificationPredicates::next_validators_match check for the
// untrusted state.
next_validators: None,
};

let options = client_state.light_client_options();
let now =
ctx.host_timestamp()?
.into_tm_time()
.ok_or_else(|| ClientError::ClientSpecific {
// Delegate to tendermint-light-client, which contains the required checks
// of the new header against the trusted consensus state.
{
let trusted_state =

Check warning on line 105 in crates/ibc-cosmos-components/src/client/verify.rs

View check run for this annotation

Codecov / codecov/patch

crates/ibc-cosmos-components/src/client/verify.rs#L105

Added line #L105 was not covered by tests
{
let trusted_client_cons_state_path =
ClientConsensusStatePath::new(client_id, &header.trusted_height);
let trusted_consensus_state: TmConsensusState = ctx
.consensus_state(&trusted_client_cons_state_path)?
.try_into()
.map_err(|err| ClientError::Other {
description: err.to_string(),
})?;

Check warning on line 114 in crates/ibc-cosmos-components/src/client/verify.rs

View check run for this annotation

Codecov / codecov/patch

crates/ibc-cosmos-components/src/client/verify.rs#L107-L114

Added lines #L107 - L114 were not covered by tests

check_header_trusted_next_validator_set(&header, &trusted_consensus_state)?;

Check warning on line 116 in crates/ibc-cosmos-components/src/client/verify.rs

View check run for this annotation

Codecov / codecov/patch

crates/ibc-cosmos-components/src/client/verify.rs#L116

Added line #L116 was not covered by tests

TrustedBlockState {
chain_id: &client_state
.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,
height: header.trusted_height.revision_height().try_into().map_err(
|_| ClientError::ClientSpecific {
description: Error::InvalidHeaderHeight {
height: header.trusted_height.revision_height(),
}
.to_string(),
},
)?,
next_validators: &header.trusted_next_validator_set,
next_validators_hash: trusted_consensus_state.next_validators_hash,
}
};

let untrusted_state = UntrustedBlockState {
signed_header: &header.signed_header,
validators: &header.validator_set,
// NB: This will skip the
// VerificationPredicates::next_validators_match check for the
// untrusted state.
next_validators: None,
};

let options = client_state.light_client_options();
let now = ctx.host_timestamp()?.into_tm_time().ok_or_else(|| {
ClientError::ClientSpecific {
description: "host timestamp is not a valid TM timestamp".to_string(),
})?;
}
})?;

Check warning on line 154 in crates/ibc-cosmos-components/src/client/verify.rs

View check run for this annotation

Codecov / codecov/patch

crates/ibc-cosmos-components/src/client/verify.rs#L119-L154

Added lines #L119 - L154 were not covered by tests

// main header verification, delegated to the tendermint-light-client crate.
client_state
.verifier()
.verify_update_header(untrusted_state, trusted_state, &options, now)
.into_result()?;
}
// main header verification, delegated to the tendermint-light-client crate.
client_state
.verifier()
.verify_update_header(untrusted_state, trusted_state, &options, now)
.into_result()?;

Check warning on line 160 in crates/ibc-cosmos-components/src/client/verify.rs

View check run for this annotation

Codecov / codecov/patch

crates/ibc-cosmos-components/src/client/verify.rs#L157-L160

Added lines #L157 - L160 were not covered by tests
}

Ok(())
Ok(())
}

Check warning on line 164 in crates/ibc-cosmos-components/src/client/verify.rs

View check run for this annotation

Codecov / codecov/patch

crates/ibc-cosmos-components/src/client/verify.rs#L163-L164

Added lines #L163 - L164 were not covered by tests
}

fn check_header_trusted_next_validator_set(
Expand Down
1 change: 1 addition & 0 deletions crates/ibc/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ num-traits = { version = "0.2.15", default-features = false }
derive_more = { version = "0.99.17", default-features = false, features = ["from", "into", "display", "try_into"] }
uint = { version = "0.9", default-features = false }
primitive-types = { version = "0.12.0", default-features = false, features = ["serde_no_std"] }
cgp-core = { version = "0.1.0" }

## for codec encode or decode
parity-scale-codec = { version = "3.0.0", default-features = false, features = ["full"], optional = true }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ impl ClientState {
where
ClientValidationContext: TmValidationContext,
{
// VerifyTendermintHeader::verify_header(ctx, self, client_id, header)

// Checks that the header fields are valid.
header.validate_basic()?;

Expand Down

0 comments on commit 06fab7d

Please sign in to comment.