ibc_query/core/connection/
query.rs

1//! Provides utility functions for querying IBC connection states.
2
3use ibc::core::client::context::ClientValidationContext;
4use ibc::core::host::types::path::{
5    ClientConnectionPath, ClientConsensusStatePath, ClientStatePath, ConnectionPath, Path,
6};
7use ibc::core::host::{ConsensusStateRef, ValidationContext};
8use ibc::primitives::prelude::format;
9use ibc::primitives::proto::Any;
10
11use super::{
12    QueryClientConnectionsRequest, QueryClientConnectionsResponse,
13    QueryConnectionClientStateRequest, QueryConnectionClientStateResponse,
14    QueryConnectionConsensusStateRequest, QueryConnectionConsensusStateResponse,
15    QueryConnectionParamsRequest, QueryConnectionParamsResponse, QueryConnectionRequest,
16    QueryConnectionResponse, QueryConnectionsRequest, QueryConnectionsResponse,
17};
18use crate::core::client::IdentifiedClientState;
19use crate::core::context::{ProvableContext, QueryContext};
20use crate::error::QueryError;
21use crate::types::Proof;
22
23/// Queries for the connection end of a given connection id.
24pub fn query_connection<I>(
25    ibc_ctx: &I,
26    request: &QueryConnectionRequest,
27) -> Result<QueryConnectionResponse, QueryError>
28where
29    I: ValidationContext + ProvableContext,
30{
31    let connection_end = ibc_ctx.connection_end(&request.connection_id)?;
32
33    let proof_height = match request.query_height {
34        Some(height) => height,
35        None => ibc_ctx.host_height()?,
36    };
37
38    let proof = ibc_ctx
39        .get_proof(
40            proof_height,
41            &Path::Connection(ConnectionPath::new(&request.connection_id)),
42        )
43        .ok_or_else(|| {
44            QueryError::missing_proof(format!(
45                "Proof not found for connection path: {:?}",
46                request.connection_id
47            ))
48        })?;
49
50    Ok(QueryConnectionResponse::new(
51        connection_end,
52        proof,
53        proof_height,
54    ))
55}
56
57/// Queries for all the existing connection ends.
58pub fn query_connections<I>(
59    ibc_ctx: &I,
60    _request: &QueryConnectionsRequest,
61) -> Result<QueryConnectionsResponse, QueryError>
62where
63    I: QueryContext,
64{
65    let connections = ibc_ctx.connection_ends()?;
66
67    Ok(QueryConnectionsResponse::new(
68        connections,
69        ibc_ctx.host_height()?,
70        None,
71    ))
72}
73
74/// Queries for all the existing connection ends for a given client.
75pub fn query_client_connections<I>(
76    ibc_ctx: &I,
77    request: &QueryClientConnectionsRequest,
78) -> Result<QueryClientConnectionsResponse, QueryError>
79where
80    I: QueryContext,
81{
82    let connections = ibc_ctx.client_connection_ends(&request.client_id)?;
83
84    let proof_height = match request.query_height {
85        Some(height) => height,
86        None => ibc_ctx.host_height()?,
87    };
88
89    let proof: Proof = ibc_ctx
90        .get_proof(
91            proof_height,
92            &Path::ClientConnection(ClientConnectionPath::new(request.client_id.clone())),
93        )
94        .ok_or_else(|| {
95            QueryError::missing_proof(format!(
96                "Proof not found for client connection path: {:?}",
97                request.client_id
98            ))
99        })?;
100
101    Ok(QueryClientConnectionsResponse::new(
102        connections,
103        proof,
104        proof_height,
105    ))
106}
107
108/// Queries for the client state of a given connection id.
109pub fn query_connection_client_state<I>(
110    ibc_ctx: &I,
111    request: &QueryConnectionClientStateRequest,
112) -> Result<QueryConnectionClientStateResponse, QueryError>
113where
114    I: QueryContext,
115{
116    let connection_end = ibc_ctx.connection_end(&request.connection_id)?;
117
118    let client_val_ctx = ibc_ctx.get_client_validation_context();
119
120    let client_state = client_val_ctx.client_state(connection_end.client_id())?;
121
122    let proof_height = match request.query_height {
123        Some(height) => height,
124        None => ibc_ctx.host_height()?,
125    };
126
127    let proof = ibc_ctx
128        .get_proof(
129            proof_height,
130            &Path::ClientState(ClientStatePath::new(connection_end.client_id().clone())),
131        )
132        .ok_or_else(|| {
133            QueryError::missing_proof(format!(
134                "Proof not found for client state path: {:?}",
135                connection_end.client_id()
136            ))
137        })?;
138
139    Ok(QueryConnectionClientStateResponse::new(
140        IdentifiedClientState::new(connection_end.client_id().clone(), client_state.into()),
141        proof,
142        proof_height,
143    ))
144}
145
146/// Queries for the consensus state of a given connection id and height.
147pub fn query_connection_consensus_state<I>(
148    ibc_ctx: &I,
149    request: &QueryConnectionConsensusStateRequest,
150) -> Result<QueryConnectionConsensusStateResponse, QueryError>
151where
152    I: ValidationContext + ProvableContext,
153    ConsensusStateRef<I>: Into<Any>,
154{
155    let connection_end = ibc_ctx.connection_end(&request.connection_id)?;
156
157    let consensus_path = ClientConsensusStatePath::new(
158        connection_end.client_id().clone(),
159        request.height.revision_number(),
160        request.height.revision_height(),
161    );
162
163    let client_val_ctx = ibc_ctx.get_client_validation_context();
164
165    let consensus_state = client_val_ctx.consensus_state(&consensus_path)?;
166
167    let proof_height = match request.query_height {
168        Some(height) => height,
169        None => ibc_ctx.host_height()?,
170    };
171
172    let proof = ibc_ctx
173        .get_proof(proof_height, &Path::ClientConsensusState(consensus_path))
174        .ok_or_else(|| {
175            QueryError::missing_proof(format!(
176                "Proof not found for consensus state path: {:?}",
177                connection_end.client_id()
178            ))
179        })?;
180
181    Ok(QueryConnectionConsensusStateResponse::new(
182        consensus_state.into(),
183        connection_end.client_id().clone(),
184        proof,
185        proof_height,
186    ))
187}
188
189/// Queries for the connection parameters.
190pub fn query_connection_params<I>(
191    ibc_ctx: &I,
192    _request: &QueryConnectionParamsRequest,
193) -> Result<QueryConnectionParamsResponse, QueryError>
194where
195    I: QueryContext,
196{
197    Ok(QueryConnectionParamsResponse::new(
198        ibc_ctx.max_expected_time_per_block().as_secs(),
199    ))
200}