1use ibc_client_tendermint_types::{
2 ClientState as ClientStateType, ConsensusState as ConsensusStateType, Header as TmHeader,
3};
4use ibc_core_client::context::prelude::*;
5use ibc_core_client::types::error::ClientError;
6use ibc_core_client::types::Height;
7use ibc_core_host::types::identifiers::ClientId;
8use ibc_core_host::types::path::{ClientConsensusStatePath, ClientStatePath};
9use ibc_primitives::prelude::*;
10use ibc_primitives::proto::Any;
11use ibc_primitives::{IntoHostTime, TimestampError};
12
13use super::ClientState;
14
15impl<E> ClientStateExecution<E> for ClientState
16where
17 E: ExtClientExecutionContext,
18 E::ClientStateRef: From<ClientStateType>,
19 ConsensusStateType: Convertible<E::ConsensusStateRef>,
20 <ConsensusStateType as TryFrom<E::ConsensusStateRef>>::Error: Into<ClientError>,
21{
22 fn initialise(
23 &self,
24 ctx: &mut E,
25 client_id: &ClientId,
26 consensus_state: Any,
27 ) -> Result<(), ClientError> {
28 initialise(self.inner(), ctx, client_id, consensus_state)
29 }
30
31 fn update_state(
32 &self,
33 ctx: &mut E,
34 client_id: &ClientId,
35 header: Any,
36 ) -> Result<Vec<Height>, ClientError> {
37 update_state(self.inner(), ctx, client_id, header)
38 }
39
40 fn update_state_on_misbehaviour(
41 &self,
42 ctx: &mut E,
43 client_id: &ClientId,
44 client_message: Any,
45 ) -> Result<(), ClientError> {
46 update_on_misbehaviour(self.inner(), ctx, client_id, client_message)
47 }
48
49 fn update_state_on_upgrade(
50 &self,
51 ctx: &mut E,
52 client_id: &ClientId,
53 upgraded_client_state: Any,
54 upgraded_consensus_state: Any,
55 ) -> Result<Height, ClientError> {
56 update_on_upgrade(
57 self.inner(),
58 ctx,
59 client_id,
60 upgraded_client_state,
61 upgraded_consensus_state,
62 )
63 }
64
65 fn update_on_recovery(
66 &self,
67 ctx: &mut E,
68 subject_client_id: &ClientId,
69 substitute_client_state: Any,
70 substitute_consensus_state: Any,
71 ) -> Result<(), ClientError> {
72 let subject_client_state = self.inner().clone();
73
74 update_on_recovery(
75 subject_client_state,
76 ctx,
77 subject_client_id,
78 substitute_client_state,
79 substitute_consensus_state,
80 )
81 }
82}
83
84pub fn initialise<E>(
90 client_state: &ClientStateType,
91 ctx: &mut E,
92 client_id: &ClientId,
93 consensus_state: Any,
94) -> Result<(), ClientError>
95where
96 E: ExtClientExecutionContext,
97 E::ClientStateRef: From<ClientStateType>,
98 ConsensusStateType: Convertible<E::ConsensusStateRef>,
99{
100 let host_timestamp = ExtClientValidationContext::host_timestamp(ctx)?;
101 let host_height = ExtClientValidationContext::host_height(ctx)?;
102
103 let tm_consensus_state: ConsensusStateType = consensus_state.try_into()?;
104
105 ctx.store_client_state(
106 ClientStatePath::new(client_id.clone()),
107 client_state.clone().into(),
108 )?;
109 ctx.store_consensus_state(
110 ClientConsensusStatePath::new(
111 client_id.clone(),
112 client_state.latest_height.revision_number(),
113 client_state.latest_height.revision_height(),
114 ),
115 tm_consensus_state.into(),
116 )?;
117
118 ctx.store_update_meta(
119 client_id.clone(),
120 client_state.latest_height,
121 host_timestamp,
122 host_height,
123 )?;
124
125 Ok(())
126}
127
128pub fn update_state<E>(
135 client_state: &ClientStateType,
136 ctx: &mut E,
137 client_id: &ClientId,
138 header: Any,
139) -> Result<Vec<Height>, ClientError>
140where
141 E: ExtClientExecutionContext,
142 E::ClientStateRef: From<ClientStateType>,
143 ConsensusStateType: Convertible<E::ConsensusStateRef>,
144 <ConsensusStateType as TryFrom<E::ConsensusStateRef>>::Error: Into<ClientError>,
145{
146 let header = TmHeader::try_from(header)?;
147 let header_height = header.height();
148
149 prune_oldest_consensus_state(client_state, ctx, client_id)?;
150
151 let maybe_existing_consensus_state = {
152 let path_at_header_height = ClientConsensusStatePath::new(
153 client_id.clone(),
154 header_height.revision_number(),
155 header_height.revision_height(),
156 );
157
158 ctx.consensus_state(&path_at_header_height).ok()
159 };
160
161 if maybe_existing_consensus_state.is_some() {
162 } else {
167 let host_timestamp = ExtClientValidationContext::host_timestamp(ctx)?;
168 let host_height = ExtClientValidationContext::host_height(ctx)?;
169
170 let new_consensus_state = ConsensusStateType::from(header.clone());
171 let new_client_state = client_state.clone().with_header(header)?;
172
173 ctx.store_consensus_state(
174 ClientConsensusStatePath::new(
175 client_id.clone(),
176 header_height.revision_number(),
177 header_height.revision_height(),
178 ),
179 new_consensus_state.into(),
180 )?;
181 ctx.store_client_state(
182 ClientStatePath::new(client_id.clone()),
183 new_client_state.into(),
184 )?;
185 ctx.store_update_meta(
186 client_id.clone(),
187 header_height,
188 host_timestamp,
189 host_height,
190 )?;
191 }
192
193 Ok(vec![header_height])
194}
195
196pub fn update_on_misbehaviour<E>(
203 client_state: &ClientStateType,
204 ctx: &mut E,
205 client_id: &ClientId,
206 _client_message: Any,
207) -> Result<(), ClientError>
208where
209 E: ExtClientExecutionContext,
210 E::ClientStateRef: From<ClientStateType>,
211{
212 let frozen_client_state = client_state.clone().with_frozen_height(Height::min(0));
218
219 ctx.store_client_state(
220 ClientStatePath::new(client_id.clone()),
221 frozen_client_state.into(),
222 )?;
223
224 Ok(())
225}
226
227pub fn update_on_upgrade<E>(
234 client_state: &ClientStateType,
235 ctx: &mut E,
236 client_id: &ClientId,
237 upgraded_client_state: Any,
238 upgraded_consensus_state: Any,
239) -> Result<Height, ClientError>
240where
241 E: ExtClientExecutionContext,
242 E::ClientStateRef: From<ClientStateType>,
243 ConsensusStateType: Convertible<E::ConsensusStateRef>,
244{
245 let mut upgraded_tm_client_state = ClientState::try_from(upgraded_client_state)?;
246 let upgraded_tm_cons_state: ConsensusStateType = upgraded_consensus_state.try_into()?;
247
248 upgraded_tm_client_state.0.zero_custom_fields();
249
250 let new_client_state = ClientStateType::new(
255 upgraded_tm_client_state.0.chain_id,
256 client_state.trust_level,
257 client_state.trusting_period,
258 upgraded_tm_client_state.0.unbonding_period,
259 client_state.max_clock_drift,
260 upgraded_tm_client_state.0.latest_height,
261 upgraded_tm_client_state.0.proof_specs,
262 upgraded_tm_client_state.0.upgrade_path,
263 client_state.allow_update,
264 )?;
265
266 let sentinel_root = b"sentinel_root".to_vec();
280 let new_consensus_state = ConsensusStateType::new(
281 sentinel_root.into(),
282 upgraded_tm_cons_state.timestamp(),
283 upgraded_tm_cons_state.next_validators_hash,
284 );
285
286 let latest_height = new_client_state.latest_height;
287 let host_timestamp = ExtClientValidationContext::host_timestamp(ctx)?;
288 let host_height = ExtClientValidationContext::host_height(ctx)?;
289
290 ctx.store_client_state(
291 ClientStatePath::new(client_id.clone()),
292 new_client_state.into(),
293 )?;
294 ctx.store_consensus_state(
295 ClientConsensusStatePath::new(
296 client_id.clone(),
297 latest_height.revision_number(),
298 latest_height.revision_height(),
299 ),
300 new_consensus_state.into(),
301 )?;
302 ctx.store_update_meta(
303 client_id.clone(),
304 latest_height,
305 host_timestamp,
306 host_height,
307 )?;
308
309 Ok(latest_height)
310}
311
312pub fn prune_oldest_consensus_state<E>(
316 client_state: &ClientStateType,
317 ctx: &mut E,
318 client_id: &ClientId,
319) -> Result<(), ClientError>
320where
321 E: ClientExecutionContext + ExtClientValidationContext,
322 E::ClientStateRef: From<ClientStateType>,
323 ConsensusStateType: Convertible<E::ConsensusStateRef>,
324 <ConsensusStateType as TryFrom<E::ConsensusStateRef>>::Error: Into<ClientError>,
325{
326 let mut heights = ctx.consensus_state_heights(client_id)?;
327
328 heights.sort();
329
330 for height in heights {
331 let client_consensus_state_path = ClientConsensusStatePath::new(
332 client_id.clone(),
333 height.revision_number(),
334 height.revision_height(),
335 );
336 let consensus_state = ctx.consensus_state(&client_consensus_state_path)?;
337 let tm_consensus_state: ConsensusStateType =
338 consensus_state.try_into().map_err(Into::into)?;
339
340 let host_timestamp = ctx.host_timestamp()?.into_host_time()?;
341
342 let tm_consensus_state_timestamp = tm_consensus_state.timestamp();
343 let tm_consensus_state_expiry = (tm_consensus_state_timestamp
344 + client_state.trusting_period)
345 .map_err(|_| TimestampError::OverflowedTimestamp)?;
346
347 if tm_consensus_state_expiry > host_timestamp {
348 break;
349 }
350
351 ctx.delete_consensus_state(client_consensus_state_path)?;
352 ctx.delete_update_meta(client_id.clone(), height)?;
353 }
354
355 Ok(())
356}
357
358pub fn update_on_recovery<E>(
370 subject_client_state: ClientStateType,
371 ctx: &mut E,
372 subject_client_id: &ClientId,
373 substitute_client_state: Any,
374 substitute_consensus_state: Any,
375) -> Result<(), ClientError>
376where
377 E: ExtClientExecutionContext,
378 E::ClientStateRef: From<ClientStateType>,
379 ConsensusStateType: Convertible<E::ConsensusStateRef>,
380{
381 let substitute_client_state = ClientState::try_from(substitute_client_state)?
382 .inner()
383 .clone();
384
385 let chain_id = substitute_client_state.chain_id;
386 let trusting_period = substitute_client_state.trusting_period;
387 let latest_height = substitute_client_state.latest_height;
388
389 let new_client_state = ClientStateType {
390 chain_id,
391 trusting_period,
392 latest_height,
393 frozen_height: None,
394 ..subject_client_state
395 };
396
397 let host_timestamp = E::host_timestamp(ctx)?;
398 let host_height = E::host_height(ctx)?;
399
400 let tm_consensus_state: ConsensusStateType = substitute_consensus_state.try_into()?;
401
402 ctx.store_consensus_state(
403 ClientConsensusStatePath::new(
404 subject_client_id.clone(),
405 new_client_state.latest_height.revision_number(),
406 new_client_state.latest_height.revision_height(),
407 ),
408 tm_consensus_state.into(),
409 )?;
410
411 ctx.store_client_state(
412 ClientStatePath::new(subject_client_id.clone()),
413 new_client_state.into(),
414 )?;
415
416 ctx.store_update_meta(
417 subject_client_id.clone(),
418 latest_height,
419 host_timestamp,
420 host_height,
421 )?;
422
423 Ok(())
424}