layer_climb_core/querier/
abci.rs1use tracing::instrument;
2
3use crate::{
4 ibc_types::{IbcChannelId, IbcClientId, IbcConnectionId, IbcPortId},
5 prelude::*,
6};
7
8use super::ConnectionMode;
9
10impl QueryClient {
11 #[instrument]
17 pub async fn abci_proof(
18 &self,
19 kind: AbciProofKind,
20 height: Option<u64>,
21 ) -> Result<AbciProofResponse> {
22 self.run_with_middleware(AbciProofReq {
23 kind: kind.clone(),
24 height,
25 })
26 .await
27 }
28}
29
30#[derive(Clone, Debug)]
31pub struct AbciProofReq {
32 pub kind: AbciProofKind,
33 pub height: Option<u64>,
34}
35
36#[derive(Clone, Debug)]
37pub enum AbciProofKind {
38 IbcClientState {
39 client_id: IbcClientId,
40 },
41 IbcConnection {
42 connection_id: IbcConnectionId,
43 },
44 IbcConsensus {
45 client_id: IbcClientId,
46 height: layer_climb_proto::RevisionHeight,
47 },
48 IbcChannel {
49 channel_id: IbcChannelId,
50 port_id: IbcPortId,
51 },
52 IbcPacketCommitment {
53 port_id: IbcPortId,
54 channel_id: IbcChannelId,
55 sequence: u64,
56 },
57 IbcPacketReceive {
58 port_id: IbcPortId,
59 channel_id: IbcChannelId,
60 sequence: u64,
61 },
62 IbcPacketAck {
63 port_id: IbcPortId,
64 channel_id: IbcChannelId,
65 sequence: u64,
66 },
67 StakingParams,
68 AuthBaseAccount {
69 address: Address,
70 },
71}
72impl AbciProofKind {
73 pub fn path(&self) -> &str {
74 match self {
75 Self::IbcClientState { .. }
76 | Self::IbcConnection { .. }
77 | Self::IbcConsensus { .. }
78 | Self::IbcChannel { .. }
79 | Self::IbcPacketCommitment { .. }
80 | Self::IbcPacketReceive { .. }
81 | Self::IbcPacketAck { .. } => "store/ibc/key",
82 Self::StakingParams => "store/staking/key",
83 Self::AuthBaseAccount { .. } => "store/acc/key",
84 }
85 }
86 pub fn data_bytes(&self) -> Vec<u8> {
87 match self {
89 Self::IbcClientState { client_id } => {
90 format!("clients/{client_id}/clientState").into_bytes()
91 }
92 Self::IbcConnection { connection_id } => {
93 format!("connections/{connection_id}").into_bytes()
94 }
95 Self::IbcConsensus { client_id, height } => format!(
96 "clients/{client_id}/consensusStates/{}-{}",
97 height.revision_number, height.revision_height
98 )
99 .into_bytes(),
100 Self::IbcChannel {
101 channel_id,
102 port_id,
103 } => format!("channelEnds/ports/{port_id}/channels/{channel_id}").into_bytes(),
104 Self::IbcPacketCommitment {
105 port_id,
106 channel_id,
107 sequence,
108 } => format!("commitments/ports/{port_id}/channels/{channel_id}/sequences/{sequence}")
109 .into_bytes(),
110 Self::IbcPacketReceive {
111 port_id,
112 channel_id,
113 sequence,
114 } => format!("receipts/ports/{port_id}/channels/{channel_id}/sequences/{sequence}")
115 .into_bytes(),
116 Self::IbcPacketAck {
117 port_id,
118 channel_id,
119 sequence,
120 } => format!("acks/ports/{port_id}/channels/{channel_id}/sequences/{sequence}")
121 .into_bytes(),
122 Self::StakingParams => vec![0x01],
123 Self::AuthBaseAccount { address } => {
124 let mut data = vec![0x01];
125 data.extend(address.as_bytes());
126 data
127 }
128 }
129 }
130}
131
132#[derive(Debug)]
133pub struct AbciProofResponse {
134 pub proof: Vec<u8>,
135 pub value: Vec<u8>,
136 }
138
139impl QueryRequest for AbciProofReq {
140 type QueryResponse = AbciProofResponse;
141
142 async fn request(&self, client: QueryClient) -> Result<AbciProofResponse> {
143 match client.get_connection_mode() {
144 ConnectionMode::Grpc => {
145 let req = tonic::Request::new(layer_climb_proto::tendermint::AbciQueryRequest {
146 path: self.kind.path().to_string(),
147 data: self.kind.data_bytes(),
148 height: match self.height {
149 Some(height) => height.try_into()?,
150 None => 0.into(),
152 },
153 prove: true,
154 });
155
156 let mut query_client =
160 layer_climb_proto::tendermint::service_client::ServiceClient::new(
161 client.clone_grpc_channel()?,
162 );
163 let resp: layer_climb_proto::tendermint::AbciQueryResponse = query_client
164 .abci_query(req)
165 .await
166 .map(|res| res.into_inner())
167 .with_context(|| format!("couldn't get abci proof for {:?}", self.kind))?;
168
169 let proof_ops = resp.proof_ops.context("missing proof_ops in abci_query")?;
173
174 let proof = AbciProofToConvert::Grpc(proof_ops).convert_abci_proof()?;
175
176 Ok(AbciProofResponse {
177 proof,
178 value: resp.value,
179 })
180 }
181 ConnectionMode::Rpc => {
182 let resp = client
184 .rpc_client()?
185 .abci_query(
186 self.kind.path().to_string(),
187 self.kind.data_bytes(),
188 self.height,
189 true,
190 )
191 .await?;
192
193 let proof_ops = resp.proof.context("missing proof_ops in abci_query")?;
194
195 let proof = AbciProofToConvert::Rpc(proof_ops).convert_abci_proof()?;
196
197 Ok(AbciProofResponse {
198 proof,
199 value: resp.value,
200 })
201 }
202 }
203 }
204}
205
206enum AbciProofToConvert {
207 Grpc(layer_climb_proto::tendermint::ProofOps),
208 Rpc(tendermint::merkle::proof::ProofOps),
209}
210
211impl AbciProofToConvert {
212 fn into_vec(self) -> Vec<Vec<u8>> {
213 match self {
214 Self::Grpc(proof_ops) => proof_ops.ops.into_iter().map(|op| op.data).collect(),
215 Self::Rpc(proof_ops) => proof_ops.ops.into_iter().map(|op| op.data).collect(),
216 }
217 }
218
219 fn convert_abci_proof(self) -> Result<Vec<u8>> {
220 let mut proofs = Vec::new();
221
222 for op in self.into_vec() {
223 let mut parsed = layer_climb_proto::ibc::ics23::CommitmentProof { proof: None };
224 layer_climb_proto::Message::merge(&mut parsed, op.as_slice())?;
225 proofs.push(parsed);
229 }
230
231 let merkle_proof = layer_climb_proto::MerkleProof { proofs };
232
233 let mut bytes = Vec::new();
234 layer_climb_proto::Message::encode(&merkle_proof, &mut bytes)?;
235
236 Ok(bytes)
237 }
238}
239
240