1use ibc::core::client::context::client_state::ClientStateValidation;
4use ibc::core::client::context::ClientValidationContext;
5use ibc::core::client::types::error::ClientError;
6use ibc::core::host::types::path::{
7 ClientConsensusStatePath, ClientStatePath, Path, UpgradeClientStatePath,
8 UpgradeConsensusStatePath, UPGRADED_IBC_STATE,
9};
10use ibc::core::host::{ConsensusStateRef, ValidationContext};
11use ibc::cosmos_host::upgrade_proposal::{UpgradeValidationContext, UpgradedConsensusStateRef};
12use ibc::primitives::prelude::{format, ToString};
13use ibc::primitives::proto::Any;
14
15use super::{
16 ConsensusStateWithHeight, IdentifiedClientState, QueryClientStateResponse,
17 QueryClientStatesRequest, QueryClientStatesResponse, QueryClientStatusRequest,
18 QueryClientStatusResponse, QueryConsensusStateHeightsRequest,
19 QueryConsensusStateHeightsResponse, QueryConsensusStateRequest, QueryConsensusStateResponse,
20 QueryConsensusStatesRequest, QueryConsensusStatesResponse, QueryUpgradedClientStateRequest,
21 QueryUpgradedClientStateResponse, QueryUpgradedConsensusStateRequest,
22 QueryUpgradedConsensusStateResponse,
23};
24use crate::core::client::QueryClientStateRequest;
25use crate::core::context::{ProvableContext, QueryContext};
26use crate::error::QueryError;
27
28pub fn query_client_state<I>(
30 ibc_ctx: &I,
31 request: &QueryClientStateRequest,
32) -> Result<QueryClientStateResponse, QueryError>
33where
34 I: QueryContext,
35{
36 let client_id = request.client_id.clone();
37
38 let client_val_ctx = ibc_ctx.get_client_validation_context();
39
40 let client_state = client_val_ctx.client_state(&client_id)?;
41
42 let proof_height = match request.query_height {
43 Some(height) => height,
44 None => ibc_ctx.host_height()?,
45 };
46
47 let proof = ibc_ctx
48 .get_proof(
49 proof_height,
50 &Path::ClientState(ClientStatePath::new(client_id.clone())),
51 )
52 .ok_or_else(|| {
53 QueryError::missing_proof(format!(
54 "Proof not found for client state path: {client_id:?}"
55 ))
56 })?;
57
58 Ok(QueryClientStateResponse::new(
59 client_state.into(),
60 proof,
61 proof_height,
62 ))
63}
64
65pub fn query_client_states<I>(
67 ibc_ctx: &I,
68 _request: &QueryClientStatesRequest,
69) -> Result<QueryClientStatesResponse, QueryError>
70where
71 I: QueryContext,
72{
73 let client_states = ibc_ctx.client_states()?;
74
75 Ok(QueryClientStatesResponse::new(
76 client_states
77 .into_iter()
78 .map(|(id, state)| IdentifiedClientState::new(id, state.into()))
79 .collect(),
80 None,
82 ))
83}
84
85pub fn query_consensus_state<I>(
87 ibc_ctx: &I,
88 request: &QueryConsensusStateRequest,
89) -> Result<QueryConsensusStateResponse, QueryError>
90where
91 I: QueryContext,
92 ConsensusStateRef<I>: Into<Any>,
93{
94 let client_id = request.client_id.clone();
95
96 let (height, consensus_state) = if let Some(height) = request.consensus_height {
97 let client_val_ctx = ibc_ctx.get_client_validation_context();
98
99 let consensus_state = client_val_ctx.consensus_state(&ClientConsensusStatePath::new(
100 client_id.clone(),
101 height.revision_number(),
102 height.revision_height(),
103 ))?;
104
105 (height, consensus_state)
106 } else {
107 ibc_ctx
108 .consensus_states(&client_id)?
109 .into_iter()
110 .max_by_key(|&(h, _)| h)
111 .ok_or_else(|| {
112 QueryError::missing_proof(format!(
113 "No consensus state found for client: {client_id:?}"
114 ))
115 })?
116 };
117
118 let proof_height = match request.query_height {
119 Some(height) => height,
120 None => ibc_ctx.host_height()?,
121 };
122
123 let proof = ibc_ctx
124 .get_proof(
125 proof_height,
126 &Path::ClientConsensusState(ClientConsensusStatePath::new(
127 client_id.clone(),
128 height.revision_number(),
129 height.revision_height(),
130 )),
131 )
132 .ok_or_else(|| {
133 QueryError::missing_proof(format!(
134 "Proof not found for consensus state path: {client_id:?}"
135 ))
136 })?;
137
138 Ok(QueryConsensusStateResponse::new(
139 consensus_state.into(),
140 proof,
141 proof_height,
142 ))
143}
144
145pub fn query_consensus_states<I>(
147 ibc_ctx: &I,
148 request: &QueryConsensusStatesRequest,
149) -> Result<QueryConsensusStatesResponse, QueryError>
150where
151 I: QueryContext,
152 ConsensusStateRef<I>: Into<Any>,
153{
154 let consensus_states = ibc_ctx.consensus_states(&request.client_id)?;
155
156 Ok(QueryConsensusStatesResponse::new(
157 consensus_states
158 .into_iter()
159 .map(|(height, state)| ConsensusStateWithHeight::new(height, state.into()))
160 .collect(),
161 None,
163 ))
164}
165
166pub fn query_consensus_state_heights<I>(
168 ibc_ctx: &I,
169 request: &QueryConsensusStateHeightsRequest,
170) -> Result<QueryConsensusStateHeightsResponse, QueryError>
171where
172 I: QueryContext,
173{
174 let consensus_state_heights = ibc_ctx.consensus_state_heights(&request.client_id)?;
175
176 Ok(QueryConsensusStateHeightsResponse::new(
177 consensus_state_heights,
178 None,
180 ))
181}
182
183pub fn query_client_status<I>(
185 ibc_ctx: &I,
186 request: &QueryClientStatusRequest,
187) -> Result<QueryClientStatusResponse, QueryError>
188where
189 I: ValidationContext,
190{
191 let client_val_ctx = ibc_ctx.get_client_validation_context();
192 let client_state = client_val_ctx.client_state(&request.client_id)?;
193 let client_validation_ctx = ibc_ctx.get_client_validation_context();
194 let client_status = client_state.status(client_validation_ctx, &request.client_id)?;
195
196 Ok(QueryClientStatusResponse::new(client_status))
197}
198
199pub fn query_upgraded_client_state<I, U>(
201 ibc_ctx: &I,
202 upgrade_ctx: &U,
203 request: &QueryUpgradedClientStateRequest,
204) -> Result<QueryUpgradedClientStateResponse, QueryError>
205where
206 I: ValidationContext,
207 U: UpgradeValidationContext + ProvableContext,
208{
209 let upgrade_path = match &request.upgrade_path {
210 Some(path) if !path.is_empty() => path,
211 _ => UPGRADED_IBC_STATE,
212 }
213 .to_string();
214
215 let upgrade_revision_height = match request.upgrade_height {
216 Some(height) => height.revision_height(),
217 None => {
218 upgrade_ctx
219 .upgrade_plan()
220 .map_err(ClientError::from)?
221 .height
222 }
223 };
224
225 let upgraded_client_state_path = UpgradeClientStatePath {
226 upgrade_path,
227 height: upgrade_revision_height,
228 };
229
230 let upgraded_client_state = upgrade_ctx
231 .upgraded_client_state(&upgraded_client_state_path)
232 .map_err(ClientError::from)?;
233
234 let proof_height = match request.query_height {
235 Some(height) => height,
236 None => ibc_ctx.host_height()?,
237 };
238
239 let proof = upgrade_ctx
240 .get_proof(
241 proof_height,
242 &Path::UpgradeClientState(upgraded_client_state_path),
243 )
244 .ok_or_else(|| {
245 QueryError::missing_proof(format!(
246 "Proof not found for upgraded client state at: {proof_height:?}"
247 ))
248 })?;
249
250 Ok(QueryUpgradedClientStateResponse::new(
251 upgraded_client_state.into(),
252 proof,
253 proof_height,
254 ))
255}
256
257pub fn query_upgraded_consensus_state<I, U>(
259 ibc_ctx: &I,
260 upgrade_ctx: &U,
261 request: &QueryUpgradedConsensusStateRequest,
262) -> Result<QueryUpgradedConsensusStateResponse, QueryError>
263where
264 I: ValidationContext,
265 U: UpgradeValidationContext + ProvableContext,
266 UpgradedConsensusStateRef<U>: Into<Any>,
267{
268 let upgrade_path = match &request.upgrade_path {
269 Some(path) if !path.is_empty() => path,
270 _ => UPGRADED_IBC_STATE,
271 }
272 .to_string();
273
274 let upgrade_revision_height = match request.upgrade_height {
275 Some(height) => height.revision_height(),
276 None => {
277 upgrade_ctx
278 .upgrade_plan()
279 .map_err(ClientError::from)?
280 .height
281 }
282 };
283
284 let upgraded_consensus_state_path = UpgradeConsensusStatePath {
285 upgrade_path,
286 height: upgrade_revision_height,
287 };
288
289 let upgraded_consensus_state = upgrade_ctx
290 .upgraded_consensus_state(&upgraded_consensus_state_path)
291 .map_err(ClientError::from)?;
292
293 let proof_height = match request.query_height {
294 Some(height) => height,
295 None => ibc_ctx.host_height()?,
296 };
297
298 let proof = upgrade_ctx
299 .get_proof(
300 proof_height,
301 &Path::UpgradeConsensusState(upgraded_consensus_state_path),
302 )
303 .ok_or_else(|| {
304 QueryError::missing_proof(format!(
305 "Proof not found for upgraded consensus state at: {proof_height:?}"
306 ))
307 })?;
308
309 Ok(QueryUpgradedConsensusStateResponse::new(
310 upgraded_consensus_state.into(),
311 proof,
312 proof_height,
313 ))
314}