ibc_core_host_cosmos/
validate_self_client.rsuse core::time::Duration;
use ibc_client_tendermint::types::ClientState as TmClientState;
use ibc_core_client_types::Height;
use ibc_core_commitment_types::specs::ProofSpecs;
use ibc_core_host_types::error::HostError;
use ibc_core_host_types::identifiers::ChainId;
use ibc_primitives::prelude::*;
use tendermint::trust_threshold::TrustThresholdFraction as TendermintTrustThresholdFraction;
pub trait ValidateSelfClientContext {
fn validate_self_tendermint_client(
&self,
client_state_of_host_on_counterparty: TmClientState,
) -> Result<(), HostError> {
client_state_of_host_on_counterparty
.validate()
.map_err(|e| {
HostError::invalid_state(format!(
"counterparty client state could not be validated: {e}"
))
})?;
if client_state_of_host_on_counterparty.is_frozen() {
return Err(HostError::invalid_state("client unexpectedly frozen"));
}
let self_chain_id = self.chain_id();
if self_chain_id != &client_state_of_host_on_counterparty.chain_id {
return Err(HostError::invalid_state(format!(
"chain ID: expected `{}`, actual `{}`",
self_chain_id, client_state_of_host_on_counterparty.chain_id
)));
}
let latest_height = client_state_of_host_on_counterparty.latest_height;
let self_revision_number = self_chain_id.revision_number();
if self_revision_number != latest_height.revision_number() {
return Err(HostError::invalid_state(format!(
"mismatched client revision numbers; expected `{}`, actual `{}`",
self_revision_number,
latest_height.revision_number()
)));
}
if latest_height >= self.host_current_height() {
return Err(HostError::invalid_state(format!(
"client latest height `{}` should be less than chain height `{}`",
latest_height,
self.host_current_height()
)));
}
if self.proof_specs() != &client_state_of_host_on_counterparty.proof_specs {
return Err(HostError::invalid_state(format!(
"client proof specs; expected `{:?}`, actual `{:?}`",
self.proof_specs(),
client_state_of_host_on_counterparty.proof_specs
)));
}
let _ = {
let trust_level = client_state_of_host_on_counterparty.trust_level;
TendermintTrustThresholdFraction::new(
trust_level.numerator(),
trust_level.denominator(),
)
.map_err(HostError::invalid_state)?
};
if self.unbonding_period() != client_state_of_host_on_counterparty.unbonding_period {
return Err(HostError::invalid_state(format!(
"unbonding period; expected `{:?}`, actual `{:?}`",
self.unbonding_period(),
client_state_of_host_on_counterparty.unbonding_period,
)));
}
if client_state_of_host_on_counterparty.unbonding_period
< client_state_of_host_on_counterparty.trusting_period
{
return Err(HostError::invalid_state(format!(
"counterparty client state: unbonding period must be greater than trusting period; unbonding period ({:?}) < trusting period ({:?})",
client_state_of_host_on_counterparty.unbonding_period,
client_state_of_host_on_counterparty.trusting_period
)));
}
if !client_state_of_host_on_counterparty.upgrade_path.is_empty()
&& self.upgrade_path() != client_state_of_host_on_counterparty.upgrade_path
{
return Err(HostError::invalid_state(format!(
"upgrade path; expected `{:?}`, actual `{:?}`",
self.upgrade_path(),
client_state_of_host_on_counterparty.upgrade_path
)));
}
Ok(())
}
fn chain_id(&self) -> &ChainId;
fn host_current_height(&self) -> Height;
fn proof_specs(&self) -> &ProofSpecs;
fn unbonding_period(&self) -> Duration;
fn upgrade_path(&self) -> &[String];
}