ibc_client_cw/context/
client_ctx.rs1use 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}