1use ibc::core::client::context::ClientValidationContext;
4use ibc::core::host::types::path::{
5 AckPath, ChannelEndPath, ClientConsensusStatePath, ClientStatePath, CommitmentPath, Path,
6 ReceiptPath, SeqRecvPath, SeqSendPath,
7};
8use ibc::core::host::{ConsensusStateRef, ValidationContext};
9use ibc::primitives::prelude::format;
10use ibc_proto::google::protobuf::Any;
11
12use super::{
13 QueryChannelClientStateRequest, QueryChannelClientStateResponse,
14 QueryChannelConsensusStateRequest, QueryChannelConsensusStateResponse, QueryChannelRequest,
15 QueryChannelResponse, QueryChannelsRequest, QueryChannelsResponse,
16 QueryConnectionChannelsRequest, QueryConnectionChannelsResponse,
17 QueryNextSequenceReceiveRequest, QueryNextSequenceReceiveResponse,
18 QueryNextSequenceSendRequest, QueryNextSequenceSendResponse, QueryPacketAcknowledgementRequest,
19 QueryPacketAcknowledgementResponse, QueryPacketAcknowledgementsRequest,
20 QueryPacketAcknowledgementsResponse, QueryPacketCommitmentRequest,
21 QueryPacketCommitmentResponse, QueryPacketCommitmentsRequest, QueryPacketCommitmentsResponse,
22 QueryPacketReceiptRequest, QueryPacketReceiptResponse, QueryUnreceivedAcksRequest,
23 QueryUnreceivedAcksResponse, QueryUnreceivedPacketsRequest, QueryUnreceivedPacketsResponse,
24};
25use crate::core::client::IdentifiedClientState;
26use crate::core::context::{ProvableContext, QueryContext};
27use crate::error::QueryError;
28
29pub fn query_channel<I>(
32 ibc_ctx: &I,
33 request: &QueryChannelRequest,
34) -> Result<QueryChannelResponse, QueryError>
35where
36 I: ValidationContext + ProvableContext,
37{
38 let channel_end_path = ChannelEndPath::new(&request.port_id, &request.channel_id);
39
40 let channel_end = ibc_ctx.channel_end(&channel_end_path)?;
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(proof_height, &Path::ChannelEnd(channel_end_path.clone()))
49 .ok_or_else(|| {
50 QueryError::missing_proof(format!(
51 "Proof not found for channel end path {channel_end_path:?}"
52 ))
53 })?;
54
55 Ok(QueryChannelResponse::new(channel_end, proof, proof_height))
56}
57
58pub fn query_channels<I>(
60 ibc_ctx: &I,
61 _request: &QueryChannelsRequest,
62) -> Result<QueryChannelsResponse, QueryError>
63where
64 I: QueryContext,
65{
66 let channel_ends = ibc_ctx.channel_ends()?;
67
68 Ok(QueryChannelsResponse::new(
69 channel_ends,
70 ibc_ctx.host_height()?,
71 None,
72 ))
73}
74
75pub fn query_connection_channels<I>(
77 ibc_ctx: &I,
78 request: &QueryConnectionChannelsRequest,
79) -> Result<QueryConnectionChannelsResponse, QueryError>
80where
81 I: QueryContext,
82{
83 let all_channel_ends = ibc_ctx.channel_ends()?;
84
85 let connection_channel_ends = all_channel_ends
86 .into_iter()
87 .filter(|channel_end| {
88 channel_end
89 .channel_end
90 .connection_hops()
91 .iter()
92 .any(|connection_hop| connection_hop == &request.connection_id)
93 })
94 .map(Into::into)
95 .collect();
96
97 Ok(QueryConnectionChannelsResponse::new(
98 connection_channel_ends,
99 ibc_ctx.host_height()?,
100 None,
101 ))
102}
103
104pub fn query_channel_client_state<I>(
107 ibc_ctx: &I,
108 request: &QueryChannelClientStateRequest,
109) -> Result<QueryChannelClientStateResponse, QueryError>
110where
111 I: QueryContext,
112{
113 let channel_end_path = ChannelEndPath::new(&request.port_id, &request.channel_id);
114
115 let channel_end = ibc_ctx.channel_end(&channel_end_path)?;
116
117 let connection_end = channel_end
118 .connection_hops()
119 .first()
120 .map(|connection_id| ibc_ctx.connection_end(connection_id))
121 .ok_or_else(|| {
122 QueryError::missing_proof(format!(
123 "Channel {} does not have a connection",
124 request.channel_id
125 ))
126 })??;
127
128 let client_val_ctx = ibc_ctx.get_client_validation_context();
129
130 let client_state = client_val_ctx.client_state(connection_end.client_id())?;
131
132 let proof_height = match request.query_height {
133 Some(height) => height,
134 None => ibc_ctx.host_height()?,
135 };
136
137 let proof = ibc_ctx
138 .get_proof(
139 proof_height,
140 &Path::ClientState(ClientStatePath::new(connection_end.client_id().clone())),
141 )
142 .ok_or_else(|| {
143 QueryError::missing_proof(format!(
144 "Proof not found for client state path: {:?}",
145 connection_end.client_id()
146 ))
147 })?;
148
149 Ok(QueryChannelClientStateResponse::new(
150 IdentifiedClientState::new(connection_end.client_id().clone(), client_state.into()),
151 proof,
152 proof_height,
153 ))
154}
155
156pub fn query_channel_consensus_state<I>(
159 ibc_ctx: &I,
160 request: &QueryChannelConsensusStateRequest,
161) -> Result<QueryChannelConsensusStateResponse, QueryError>
162where
163 I: QueryContext,
164 ConsensusStateRef<I>: Into<Any>,
165{
166 let channel_end_path = ChannelEndPath::new(&request.port_id, &request.channel_id);
167
168 let channel_end = ibc_ctx.channel_end(&channel_end_path)?;
169
170 let connection_end = channel_end
171 .connection_hops()
172 .first()
173 .map(|connection_id| ibc_ctx.connection_end(connection_id))
174 .ok_or_else(|| {
175 QueryError::missing_proof(format!(
176 "Channel {} does not have a connection",
177 request.channel_id
178 ))
179 })??;
180
181 let consensus_path = ClientConsensusStatePath::new(
182 connection_end.client_id().clone(),
183 request.consensus_height.revision_number(),
184 request.consensus_height.revision_height(),
185 );
186 let client_val_ctx = ibc_ctx.get_client_validation_context();
187
188 let consensus_state = client_val_ctx.consensus_state(&consensus_path)?;
189
190 let proof_height = match request.query_height {
191 Some(height) => height,
192 None => ibc_ctx.host_height()?,
193 };
194
195 let proof = ibc_ctx
196 .get_proof(
197 proof_height,
198 &Path::ClientConsensusState(consensus_path.clone()),
199 )
200 .ok_or_else(|| {
201 QueryError::missing_proof(format!(
202 "Proof not found for client consensus state path: {consensus_path:?}"
203 ))
204 })?;
205
206 Ok(QueryChannelConsensusStateResponse::new(
207 consensus_state.into(),
208 connection_end.client_id().clone(),
209 proof,
210 proof_height,
211 ))
212}
213
214pub fn query_packet_commitment<I>(
217 ibc_ctx: &I,
218 request: &QueryPacketCommitmentRequest,
219) -> Result<QueryPacketCommitmentResponse, QueryError>
220where
221 I: ValidationContext + ProvableContext,
222{
223 let commitment_path =
224 CommitmentPath::new(&request.port_id, &request.channel_id, request.sequence);
225
226 let packet_commitment_data = ibc_ctx.get_packet_commitment(&commitment_path)?;
227
228 let proof_height = match request.query_height {
229 Some(height) => height,
230 None => ibc_ctx.host_height()?,
231 };
232
233 let proof = ibc_ctx
234 .get_proof(proof_height, &Path::Commitment(commitment_path.clone()))
235 .ok_or_else(|| {
236 QueryError::missing_proof(format!(
237 "Proof not found for packet commitment path: {commitment_path:?}"
238 ))
239 })?;
240
241 Ok(QueryPacketCommitmentResponse::new(
242 packet_commitment_data,
243 proof,
244 proof_height,
245 ))
246}
247
248pub fn query_packet_commitments<I>(
250 ibc_ctx: &I,
251 request: &QueryPacketCommitmentsRequest,
252) -> Result<QueryPacketCommitmentsResponse, QueryError>
253where
254 I: QueryContext,
255{
256 let channel_end_path = ChannelEndPath::new(&request.port_id, &request.channel_id);
257
258 let commitments = ibc_ctx
259 .packet_commitments(&channel_end_path)?
260 .into_iter()
261 .map(Into::into)
262 .collect();
263
264 Ok(QueryPacketCommitmentsResponse::new(
265 commitments,
266 ibc_ctx.host_height()?,
267 None,
268 ))
269}
270
271pub fn query_packet_receipt<I>(
274 ibc_ctx: &I,
275 request: &QueryPacketReceiptRequest,
276) -> Result<QueryPacketReceiptResponse, QueryError>
277where
278 I: ValidationContext + ProvableContext,
279{
280 let receipt_path = ReceiptPath::new(&request.port_id, &request.channel_id, request.sequence);
281
282 let packet_receipt_data = ibc_ctx.get_packet_receipt(&receipt_path)?;
284
285 let proof_height = match request.query_height {
286 Some(height) => height,
287 None => ibc_ctx.host_height()?,
288 };
289
290 let proof = ibc_ctx
291 .get_proof(proof_height, &Path::Receipt(receipt_path.clone()))
292 .ok_or_else(|| {
293 QueryError::missing_proof(format!(
294 "Proof not found for packet receipt path: {receipt_path:?}"
295 ))
296 })?;
297
298 Ok(QueryPacketReceiptResponse::new(
299 packet_receipt_data.is_ok(),
300 proof,
301 proof_height,
302 ))
303}
304
305pub fn query_packet_acknowledgement<I>(
308 ibc_ctx: &I,
309 request: &QueryPacketAcknowledgementRequest,
310) -> Result<QueryPacketAcknowledgementResponse, QueryError>
311where
312 I: ValidationContext + ProvableContext,
313{
314 let acknowledgement_path =
315 AckPath::new(&request.port_id, &request.channel_id, request.sequence);
316
317 let packet_acknowledgement_data = ibc_ctx.get_packet_acknowledgement(&acknowledgement_path)?;
318
319 let proof_height = match request.query_height {
320 Some(height) => height,
321 None => ibc_ctx.host_height()?,
322 };
323
324 let proof = ibc_ctx
325 .get_proof(proof_height, &Path::Ack(acknowledgement_path.clone()))
326 .ok_or_else(|| {
327 QueryError::missing_proof(format!(
328 "Proof not found for packet acknowledgement path: {acknowledgement_path:?}"
329 ))
330 })?;
331
332 Ok(QueryPacketAcknowledgementResponse::new(
333 packet_acknowledgement_data,
334 proof,
335 proof_height,
336 ))
337}
338
339pub fn query_packet_acknowledgements<I>(
341 ibc_ctx: &I,
342 request: &QueryPacketAcknowledgementsRequest,
343) -> Result<QueryPacketAcknowledgementsResponse, QueryError>
344where
345 I: QueryContext,
346{
347 let commitment_sequences = request
348 .packet_commitment_sequences
349 .iter()
350 .copied()
351 .map(Into::into);
352
353 let channel_end_path = ChannelEndPath::new(&request.port_id, &request.channel_id);
354
355 let acknowledgements = ibc_ctx
356 .packet_acknowledgements(&channel_end_path, commitment_sequences)?
357 .into_iter()
358 .map(Into::into)
359 .collect();
360
361 Ok(QueryPacketAcknowledgementsResponse::new(
362 acknowledgements,
363 ibc_ctx.host_height()?,
364 None,
365 ))
366}
367
368pub fn query_unreceived_packets<I>(
370 ibc_ctx: &I,
371 request: &QueryUnreceivedPacketsRequest,
372) -> Result<QueryUnreceivedPacketsResponse, QueryError>
373where
374 I: QueryContext,
375{
376 let sequences = request
377 .packet_commitment_sequences
378 .iter()
379 .copied()
380 .map(Into::into);
381
382 let channel_end_path = ChannelEndPath::new(&request.port_id, &request.channel_id);
383
384 let unreceived_packets = ibc_ctx.unreceived_packets(&channel_end_path, sequences)?;
385
386 Ok(QueryUnreceivedPacketsResponse::new(
387 unreceived_packets,
388 ibc_ctx.host_height()?,
389 ))
390}
391
392pub fn query_unreceived_acks<I>(
394 ibc_ctx: &I,
395 request: &QueryUnreceivedAcksRequest,
396) -> Result<QueryUnreceivedAcksResponse, QueryError>
397where
398 I: QueryContext,
399{
400 let sequences = request.packet_ack_sequences.iter().copied().map(Into::into);
401
402 let channel_end_path = ChannelEndPath::new(&request.port_id, &request.channel_id);
403
404 let unreceived_acks = ibc_ctx.unreceived_acks(&channel_end_path, sequences)?;
405
406 Ok(QueryUnreceivedAcksResponse::new(
407 unreceived_acks,
408 ibc_ctx.host_height()?,
409 ))
410}
411
412pub fn query_next_sequence_send<I>(
415 ibc_ctx: &I,
416 request: &QueryNextSequenceSendRequest,
417) -> Result<QueryNextSequenceSendResponse, QueryError>
418where
419 I: ValidationContext + ProvableContext,
420{
421 let next_seq_send_path = SeqSendPath::new(&request.port_id, &request.channel_id);
422
423 let next_sequence_send = ibc_ctx.get_next_sequence_send(&next_seq_send_path)?;
424
425 let proof_height = match request.query_height {
426 Some(height) => height,
427 None => ibc_ctx.host_height()?,
428 };
429
430 let proof = ibc_ctx
431 .get_proof(proof_height, &Path::SeqSend(next_seq_send_path))
432 .ok_or_else(|| {
433 QueryError::missing_proof(format!(
434 "Next sequence send proof not found for channel {}",
435 request.channel_id
436 ))
437 })?;
438
439 Ok(QueryNextSequenceSendResponse::new(
440 next_sequence_send,
441 proof,
442 proof_height,
443 ))
444}
445
446pub fn query_next_sequence_receive<I>(
448 ibc_ctx: &I,
449 request: &QueryNextSequenceReceiveRequest,
450) -> Result<QueryNextSequenceReceiveResponse, QueryError>
451where
452 I: ValidationContext + ProvableContext,
453{
454 let next_seq_recv_path = SeqRecvPath::new(&request.port_id, &request.channel_id);
455
456 let next_sequence_recv = ibc_ctx.get_next_sequence_recv(&next_seq_recv_path)?;
457
458 let proof_height = match request.query_height {
459 Some(height) => height,
460 None => ibc_ctx.host_height()?,
461 };
462
463 let proof = ibc_ctx
464 .get_proof(proof_height, &Path::SeqRecv(next_seq_recv_path))
465 .ok_or_else(|| {
466 QueryError::missing_proof(format!(
467 "Next sequence receive proof not found for channel {}",
468 request.channel_id
469 ))
470 })?;
471
472 Ok(QueryNextSequenceReceiveResponse::new(
473 next_sequence_recv,
474 proof,
475 proof_height,
476 ))
477}