ibc_client_cw/context/
client_ctx.rs

1//! Implementation of the `ClientValidationContext` and `ClientExecutionContext`
2//! traits for the `Context` type.
3use core::fmt::Display;
4
5use ibc_client_wasm_types::client_state::ClientState as WasmClientState;
6use ibc_client_wasm_types::consensus_state::ConsensusState as WasmConsensusState;
7use ibc_core::client::context::{ClientExecutionContext, ClientValidationContext};
8use ibc_core::client::types::Height;
9use ibc_core::host::types::error::HostError;
10use ibc_core::host::types::identifiers::ClientId;
11use ibc_core::host::types::path::{ClientConsensusStatePath, ClientStatePath};
12use ibc_core::primitives::proto::{Any, Protobuf};
13use ibc_core::primitives::Timestamp;
14
15use super::{Context, StorageMut};
16use crate::api::ClientType;
17use crate::context::CONSENSUS_STATE_HEIGHT_MAP;
18use crate::utils::AnyCodec;
19
20impl<'a, C: ClientType<'a>> ClientValidationContext for Context<'a, C>
21where
22    <C::ClientState as TryFrom<Any>>::Error: Display,
23    <C::ConsensusState as TryFrom<Any>>::Error: Display,
24{
25    type ClientStateRef = C::ClientState;
26    type ConsensusStateRef = C::ConsensusState;
27
28    fn client_state(&self, _client_id: &ClientId) -> Result<Self::ClientStateRef, HostError> {
29        let client_state_value = self.retrieve(ClientStatePath::leaf())?;
30
31        let any_wasm: WasmClientState = Protobuf::<Any>::decode(client_state_value.as_slice())
32            .map_err(HostError::invalid_state)?;
33
34        let sov_client_state =
35            C::ClientState::decode_any_vec(any_wasm.data).map_err(HostError::invalid_state)?;
36
37        Ok(sov_client_state)
38    }
39
40    fn consensus_state(
41        &self,
42        client_cons_state_path: &ClientConsensusStatePath,
43    ) -> Result<Self::ConsensusStateRef, HostError> {
44        let consensus_state_value = self.retrieve(client_cons_state_path.leaf())?;
45
46        let any_wasm: WasmConsensusState = C::ConsensusState::decode_any_vec(consensus_state_value)
47            .map_err(HostError::invalid_state)?;
48
49        let consensus_state =
50            C::ConsensusState::decode_any_vec(any_wasm.data).map_err(HostError::invalid_state)?;
51
52        Ok(consensus_state)
53    }
54
55    fn client_update_meta(
56        &self,
57        _client_id: &ClientId,
58        height: &Height,
59    ) -> Result<(Timestamp, Height), HostError> {
60        let time_key = self.client_update_time_key(height);
61
62        let time_vec = self.retrieve(time_key)?;
63
64        let time = u64::from_be_bytes(
65            time_vec
66                .try_into()
67                .map_err(|_| HostError::invalid_state("time key cannot be converted to u64"))?,
68        );
69
70        let timestamp = Timestamp::from_nanoseconds(time);
71
72        let height_key = self.client_update_height_key(height);
73
74        let revision_height_vec = self.retrieve(height_key)?;
75
76        let revision_height = u64::from_be_bytes(revision_height_vec.try_into().map_err(|_| {
77            HostError::invalid_state("revision height key cannot be converted to u64")
78        })?);
79
80        let height = Height::new(0, revision_height).map_err(HostError::invalid_state)?;
81
82        Ok((timestamp, height))
83    }
84}
85
86impl<'a, C: ClientType<'a>> ClientExecutionContext for Context<'a, C>
87where
88    <C::ClientState as TryFrom<Any>>::Error: Display,
89    <C::ConsensusState as TryFrom<Any>>::Error: Display,
90{
91    type ClientStateMut = C::ClientState;
92
93    fn store_client_state(
94        &mut self,
95        _client_state_path: ClientStatePath,
96        client_state: Self::ClientStateMut,
97    ) -> Result<(), HostError> {
98        let prefixed_key = self.prefixed_key(ClientStatePath::leaf());
99
100        let encoded_client_state = self.encode_client_state(client_state)?;
101
102        self.insert(prefixed_key, encoded_client_state);
103
104        Ok(())
105    }
106
107    fn store_consensus_state(
108        &mut self,
109        consensus_state_path: ClientConsensusStatePath,
110        consensus_state: Self::ConsensusStateRef,
111    ) -> Result<(), HostError> {
112        let prefixed_key = self.prefixed_key(consensus_state_path.leaf());
113
114        let encoded_consensus_state = C::ConsensusState::encode_to_any_vec(consensus_state);
115
116        let wasm_consensus_state = WasmConsensusState {
117            data: encoded_consensus_state,
118        };
119
120        let encoded_wasm_consensus_state =
121            C::ConsensusState::encode_to_any_vec(wasm_consensus_state);
122
123        self.insert(prefixed_key, encoded_wasm_consensus_state);
124
125        Ok(())
126    }
127
128    fn delete_consensus_state(
129        &mut self,
130        consensus_state_path: ClientConsensusStatePath,
131    ) -> Result<(), HostError> {
132        let prefixed_key = self.prefixed_key(consensus_state_path.leaf());
133
134        self.remove(prefixed_key);
135
136        Ok(())
137    }
138
139    fn store_update_meta(
140        &mut self,
141        _client_id: ClientId,
142        height: Height,
143        host_timestamp: Timestamp,
144        host_height: Height,
145    ) -> Result<(), HostError> {
146        let time_key = self.client_update_time_key(&height);
147
148        let prefixed_time_key = self.prefixed_key(time_key);
149
150        let time_vec = host_timestamp.nanoseconds().to_be_bytes();
151
152        self.insert(prefixed_time_key, time_vec);
153
154        let height_key = self.client_update_height_key(&height);
155
156        let prefixed_height_key = self.prefixed_key(height_key);
157
158        let revision_height_vec = host_height.revision_height().to_be_bytes();
159
160        self.insert(prefixed_height_key, revision_height_vec);
161
162        CONSENSUS_STATE_HEIGHT_MAP
163            .save(
164                self.storage_mut(),
165                (height.revision_number(), height.revision_height()),
166                &Default::default(),
167            )
168            .map_err(HostError::failed_to_store)?;
169
170        Ok(())
171    }
172
173    fn delete_update_meta(
174        &mut self,
175        _client_id: ClientId,
176        height: Height,
177    ) -> Result<(), HostError> {
178        let time_key = self.client_update_time_key(&height);
179
180        let prefixed_time_key = self.prefixed_key(time_key);
181
182        self.remove(prefixed_time_key);
183
184        let height_key = self.client_update_height_key(&height);
185
186        let prefixed_height_key = self.prefixed_key(height_key);
187
188        self.remove(prefixed_height_key);
189
190        CONSENSUS_STATE_HEIGHT_MAP.remove(
191            self.storage_mut(),
192            (height.revision_number(), height.revision_height()),
193        );
194
195        Ok(())
196    }
197}