ibc_client_tendermint/client_state/
validation.rs1use ibc_client_tendermint_types::{
2 ClientState as ClientStateType, ConsensusState as ConsensusStateType, Header as TmHeader,
3 Misbehaviour as TmMisbehaviour, TENDERMINT_HEADER_TYPE_URL, TENDERMINT_MISBEHAVIOUR_TYPE_URL,
4};
5use ibc_core_client::context::client_state::ClientStateValidation;
6use ibc_core_client::context::{Convertible, ExtClientValidationContext};
7use ibc_core_client::types::error::ClientError;
8use ibc_core_client::types::Status;
9use ibc_core_host::types::identifiers::ClientId;
10use ibc_core_host::types::path::ClientConsensusStatePath;
11use ibc_primitives::prelude::*;
12use ibc_primitives::proto::Any;
13use tendermint::crypto::default::Sha256;
14use tendermint::crypto::Sha256 as Sha256Trait;
15use tendermint::merkle::MerkleHash;
16use tendermint_light_client_verifier::{ProdVerifier, Verifier};
17
18use super::{
19 check_for_misbehaviour_on_misbehavior, check_for_misbehaviour_on_update,
20 consensus_state_status, ClientState,
21};
22use crate::client_state::{verify_header, verify_misbehaviour};
23
24impl<V> ClientStateValidation<V> for ClientState
25where
26 V: ExtClientValidationContext,
27 ConsensusStateType: Convertible<V::ConsensusStateRef>,
28 <ConsensusStateType as TryFrom<V::ConsensusStateRef>>::Error: Into<ClientError>,
29{
30 fn verify_client_message(
50 &self,
51 ctx: &V,
52 client_id: &ClientId,
53 client_message: Any,
54 ) -> Result<(), ClientError> {
55 verify_client_message::<V, Sha256>(
56 self.inner(),
57 ctx,
58 client_id,
59 client_message,
60 &ProdVerifier::default(),
61 )
62 }
63
64 fn check_for_misbehaviour(
65 &self,
66 ctx: &V,
67 client_id: &ClientId,
68 client_message: Any,
69 ) -> Result<bool, ClientError> {
70 check_for_misbehaviour(self.inner(), ctx, client_id, client_message)
71 }
72
73 fn status(&self, ctx: &V, client_id: &ClientId) -> Result<Status, ClientError> {
74 status(self.inner(), ctx, client_id)
75 }
76
77 fn check_substitute(&self, _ctx: &V, substitute_client_state: Any) -> Result<(), ClientError> {
78 check_substitute::<V>(self.inner(), substitute_client_state)
79 }
80}
81
82pub fn verify_client_message<V, H>(
92 client_state: &ClientStateType,
93 ctx: &V,
94 client_id: &ClientId,
95 client_message: Any,
96 verifier: &impl Verifier,
97) -> Result<(), ClientError>
98where
99 V: ExtClientValidationContext,
100 ConsensusStateType: Convertible<V::ConsensusStateRef>,
101 <ConsensusStateType as TryFrom<V::ConsensusStateRef>>::Error: Into<ClientError>,
102 H: MerkleHash + Sha256Trait + Default,
103{
104 match client_message.type_url.as_str() {
105 TENDERMINT_HEADER_TYPE_URL => {
106 let header = TmHeader::try_from(client_message)?;
107 verify_header::<V, H>(
108 ctx,
109 &header,
110 client_id,
111 client_state.chain_id(),
112 &client_state.as_light_client_options()?,
113 verifier,
114 )
115 }
116 TENDERMINT_MISBEHAVIOUR_TYPE_URL => {
117 let misbehaviour = TmMisbehaviour::try_from(client_message)?;
118 verify_misbehaviour::<V, H>(
119 ctx,
120 &misbehaviour,
121 client_id,
122 client_state.chain_id(),
123 &client_state.as_light_client_options()?,
124 verifier,
125 )
126 }
127 _ => Err(ClientError::InvalidUpdateClientMessage),
128 }
129}
130
131pub fn check_for_misbehaviour<V>(
164 client_state: &ClientStateType,
165 ctx: &V,
166 client_id: &ClientId,
167 client_message: Any,
168) -> Result<bool, ClientError>
169where
170 V: ExtClientValidationContext,
171 ConsensusStateType: Convertible<V::ConsensusStateRef>,
172 <ConsensusStateType as TryFrom<V::ConsensusStateRef>>::Error: Into<ClientError>,
173{
174 match client_message.type_url.as_str() {
175 TENDERMINT_HEADER_TYPE_URL => {
176 let header = TmHeader::try_from(client_message)?;
177 check_for_misbehaviour_on_update(ctx, header, client_id, &client_state.latest_height)
178 }
179 TENDERMINT_MISBEHAVIOUR_TYPE_URL => {
180 let misbehaviour = TmMisbehaviour::try_from(client_message)?;
181 check_for_misbehaviour_on_misbehavior(misbehaviour.header1(), misbehaviour.header2())
182 }
183 _ => Err(ClientError::InvalidUpdateClientMessage),
184 }
185}
186
187pub fn status<V>(
193 client_state: &ClientStateType,
194 ctx: &V,
195 client_id: &ClientId,
196) -> Result<Status, ClientError>
197where
198 V: ExtClientValidationContext,
199 ConsensusStateType: Convertible<V::ConsensusStateRef>,
200 <ConsensusStateType as TryFrom<V::ConsensusStateRef>>::Error: Into<ClientError>,
201{
202 if client_state.is_frozen() {
203 return Ok(Status::Frozen);
204 }
205
206 let latest_consensus_state: ConsensusStateType = {
207 match ctx.consensus_state(&ClientConsensusStatePath::new(
208 client_id.clone(),
209 client_state.latest_height.revision_number(),
210 client_state.latest_height.revision_height(),
211 )) {
212 Ok(cs) => cs.try_into().map_err(Into::into)?,
213 Err(_) => return Ok(Status::Expired),
216 }
217 };
218
219 let now = ctx.host_timestamp()?;
223
224 let status = consensus_state_status(
225 &latest_consensus_state.into(),
226 &now,
227 client_state.trusting_period,
228 )?;
229
230 Ok(status)
231}
232
233pub fn check_substitute<V>(
240 subject_client_state: &ClientStateType,
241 substitute_client_state: Any,
242) -> Result<(), ClientError>
243where
244 V: ExtClientValidationContext,
245 ConsensusStateType: Convertible<V::ConsensusStateRef>,
246{
247 let ClientStateType {
248 latest_height: _,
249 frozen_height: _,
250 trusting_period: _,
251 chain_id: _,
252 allow_update: _,
253 trust_level: subject_trust_level,
254 unbonding_period: subject_unbonding_period,
255 max_clock_drift: subject_max_clock_drift,
256 proof_specs: subject_proof_specs,
257 upgrade_path: subject_upgrade_path,
258 } = subject_client_state;
259
260 let substitute_client_state = ClientStateType::try_from(substitute_client_state)?;
261
262 let ClientStateType {
263 latest_height: _,
264 frozen_height: _,
265 trusting_period: _,
266 chain_id: _,
267 allow_update: _,
268 trust_level: substitute_trust_level,
269 unbonding_period: substitute_unbonding_period,
270 max_clock_drift: substitute_max_clock_drift,
271 proof_specs: substitute_proof_specs,
272 upgrade_path: substitute_upgrade_path,
273 } = substitute_client_state;
274
275 (subject_trust_level == &substitute_trust_level
276 && subject_unbonding_period == &substitute_unbonding_period
277 && subject_max_clock_drift == &substitute_max_clock_drift
278 && subject_proof_specs == &substitute_proof_specs
279 && subject_upgrade_path == &substitute_upgrade_path)
280 .then_some(())
281 .ok_or(ClientError::FailedToVerifyClientRecoveryStates)
282}