Skip to main content

nym_validator_client/nyxd/contract_traits/
dkg_query_client.rs

1// Copyright 2022-2024 - Nym Technologies SA <contact@nymtech.net>
2// SPDX-License-Identifier: Apache-2.0
3
4use crate::collect_paged;
5use crate::nyxd::contract_traits::NymContractsProvider;
6use crate::nyxd::error::NyxdError;
7use crate::nyxd::CosmWasmClient;
8use async_trait::async_trait;
9use cosmrs::AccountId;
10use cosmwasm_std::Addr;
11use nym_coconut_dkg_common::dealer::RegisteredDealerDetails;
12use nym_coconut_dkg_common::types::{ChunkIndex, NodeIndex, StateAdvanceResponse};
13use serde::Deserialize;
14use tracing::trace;
15
16pub use nym_coconut_dkg_common::{
17    dealer::{DealerDetailsResponse, PagedDealerIndexResponse, PagedDealerResponse},
18    dealing::{
19        DealerDealingsStatusResponse, DealingChunkResponse, DealingChunkStatusResponse,
20        DealingMetadataResponse, DealingStatusResponse,
21    },
22    msg::QueryMsg as DkgQueryMsg,
23    types::{DealerDetails, DealingIndex, Epoch, EpochId, EpochState, State},
24    verification_key::{
25        ContractVKShare, PagedVKSharesResponse, VerificationKeyShare, VkShareResponse,
26    },
27};
28
29#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
30#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
31pub trait DkgQueryClient: Send + Sync {
32    async fn query_dkg_contract<T>(&self, query: DkgQueryMsg) -> Result<T, NyxdError>
33    where
34        for<'a> T: Deserialize<'a>;
35
36    async fn get_state(&self) -> Result<State, NyxdError> {
37        let request = DkgQueryMsg::GetState {};
38        self.query_dkg_contract(request).await
39    }
40
41    async fn get_current_epoch(&self) -> Result<Epoch, NyxdError> {
42        let request = DkgQueryMsg::GetCurrentEpochState {};
43        self.query_dkg_contract(request).await
44    }
45
46    async fn get_epoch_at_height(&self, height: u64) -> Result<Option<Epoch>, NyxdError> {
47        let request = DkgQueryMsg::GetEpochStateAtHeight { height };
48        self.query_dkg_contract(request).await
49    }
50
51    async fn can_advance_state(&self) -> Result<StateAdvanceResponse, NyxdError> {
52        let request = DkgQueryMsg::CanAdvanceState {};
53        self.query_dkg_contract(request).await
54    }
55
56    async fn get_current_epoch_threshold(&self) -> Result<Option<u64>, NyxdError> {
57        let request = DkgQueryMsg::GetCurrentEpochThreshold {};
58        self.query_dkg_contract(request).await
59    }
60
61    async fn get_epoch_threshold(&self, epoch_id: EpochId) -> Result<Option<u64>, NyxdError> {
62        let request = DkgQueryMsg::GetEpochThreshold { epoch_id };
63        self.query_dkg_contract(request).await
64    }
65
66    async fn get_registered_dealer_details(
67        &self,
68        address: &AccountId,
69        epoch_id: Option<EpochId>,
70    ) -> Result<RegisteredDealerDetails, NyxdError> {
71        let request = DkgQueryMsg::GetRegisteredDealer {
72            dealer_address: address.to_string(),
73            epoch_id,
74        };
75        self.query_dkg_contract(request).await
76    }
77
78    async fn get_dealer_details(
79        &self,
80        address: &AccountId,
81    ) -> Result<DealerDetailsResponse, NyxdError> {
82        let request = DkgQueryMsg::GetDealerDetails {
83            dealer_address: address.to_string(),
84        };
85        self.query_dkg_contract(request).await
86    }
87
88    async fn get_current_dealers_paged(
89        &self,
90        start_after: Option<String>,
91        limit: Option<u32>,
92    ) -> Result<PagedDealerResponse, NyxdError> {
93        let request = DkgQueryMsg::GetCurrentDealers { start_after, limit };
94        self.query_dkg_contract(request).await
95    }
96
97    async fn get_epoch_dealers_paged(
98        &self,
99        epoch_id: EpochId,
100        start_after: Option<String>,
101        limit: Option<u32>,
102    ) -> Result<PagedDealerResponse, NyxdError> {
103        let request = DkgQueryMsg::GetEpochDealers {
104            epoch_id,
105            start_after,
106            limit,
107        };
108        self.query_dkg_contract(request).await
109    }
110
111    async fn get_epoch_dealers_addresses_paged(
112        &self,
113        epoch_id: EpochId,
114        start_after: Option<String>,
115        limit: Option<u32>,
116    ) -> Result<PagedDealerResponse, NyxdError> {
117        let request = DkgQueryMsg::GetEpochDealersAddresses {
118            epoch_id,
119            start_after,
120            limit,
121        };
122        self.query_dkg_contract(request).await
123    }
124
125    async fn get_dealer_indices_paged(
126        &self,
127        start_after: Option<String>,
128        limit: Option<u32>,
129    ) -> Result<PagedDealerIndexResponse, NyxdError> {
130        let request = DkgQueryMsg::GetDealerIndices { start_after, limit };
131        self.query_dkg_contract(request).await
132    }
133
134    async fn get_dealings_metadata(
135        &self,
136        epoch_id: EpochId,
137        dealer: String,
138        dealing_index: DealingIndex,
139    ) -> Result<DealingMetadataResponse, NyxdError> {
140        let request = DkgQueryMsg::GetDealingsMetadata {
141            epoch_id,
142            dealer,
143            dealing_index,
144        };
145
146        self.query_dkg_contract(request).await
147    }
148
149    async fn get_dealer_dealings_status(
150        &self,
151        epoch_id: EpochId,
152        dealer: String,
153    ) -> Result<DealerDealingsStatusResponse, NyxdError> {
154        let request = DkgQueryMsg::GetDealerDealingsStatus { epoch_id, dealer };
155
156        self.query_dkg_contract(request).await
157    }
158
159    async fn get_dealing_status(
160        &self,
161        epoch_id: EpochId,
162        dealer: String,
163        dealing_index: DealingIndex,
164    ) -> Result<DealingStatusResponse, NyxdError> {
165        let request = DkgQueryMsg::GetDealingStatus {
166            epoch_id,
167            dealer,
168            dealing_index,
169        };
170
171        self.query_dkg_contract(request).await
172    }
173
174    async fn get_dealing_chunk_status(
175        &self,
176        epoch_id: EpochId,
177        dealer: String,
178        dealing_index: DealingIndex,
179        chunk_index: ChunkIndex,
180    ) -> Result<DealingChunkStatusResponse, NyxdError> {
181        let request = DkgQueryMsg::GetDealingChunkStatus {
182            epoch_id,
183            dealer,
184            dealing_index,
185            chunk_index,
186        };
187
188        self.query_dkg_contract(request).await
189    }
190
191    async fn get_dealing_chunk(
192        &self,
193        epoch_id: EpochId,
194        dealer: String,
195        dealing_index: DealingIndex,
196        chunk_index: ChunkIndex,
197    ) -> Result<DealingChunkResponse, NyxdError> {
198        let request = DkgQueryMsg::GetDealingChunk {
199            epoch_id,
200            dealer,
201            dealing_index,
202            chunk_index,
203        };
204
205        self.query_dkg_contract(request).await
206    }
207
208    async fn get_vk_share(
209        &self,
210        epoch_id: EpochId,
211        owner: String,
212    ) -> Result<VkShareResponse, NyxdError> {
213        let request = DkgQueryMsg::GetVerificationKey { epoch_id, owner };
214        self.query_dkg_contract(request).await
215    }
216
217    async fn get_vk_shares_paged(
218        &self,
219        epoch_id: EpochId,
220        start_after: Option<String>,
221        limit: Option<u32>,
222    ) -> Result<PagedVKSharesResponse, NyxdError> {
223        let request = DkgQueryMsg::GetVerificationKeys {
224            epoch_id,
225            limit,
226            start_after,
227        };
228        self.query_dkg_contract(request).await
229    }
230
231    async fn get_contract_cw2_version(&self) -> Result<cw2::ContractVersion, NyxdError> {
232        self.query_dkg_contract(DkgQueryMsg::GetCW2ContractVersion {})
233            .await
234    }
235}
236
237// extension trait to the query client to deal with the paged queries
238// (it didn't feel appropriate to combine it with the existing trait
239#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
240#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
241pub trait PagedDkgQueryClient: DkgQueryClient {
242    async fn get_all_current_dealers(&self) -> Result<Vec<DealerDetails>, NyxdError> {
243        collect_paged!(self, get_current_dealers_paged, dealers)
244    }
245
246    async fn get_all_epoch_dealers(
247        &self,
248        epoch_id: EpochId,
249    ) -> Result<Vec<DealerDetails>, NyxdError> {
250        collect_paged!(self, get_epoch_dealers_paged, dealers, epoch_id)
251    }
252
253    async fn get_all_epoch_dealers_addresses(
254        &self,
255        epoch_id: EpochId,
256    ) -> Result<Vec<DealerDetails>, NyxdError> {
257        collect_paged!(self, get_epoch_dealers_addresses_paged, dealers, epoch_id)
258    }
259
260    async fn get_all_dealer_indices(&self) -> Result<Vec<(Addr, NodeIndex)>, NyxdError> {
261        collect_paged!(self, get_dealer_indices_paged, indices)
262    }
263
264    async fn get_all_verification_key_shares(
265        &self,
266        epoch_id: EpochId,
267    ) -> Result<Vec<ContractVKShare>, NyxdError> {
268        collect_paged!(self, get_vk_shares_paged, shares, epoch_id)
269    }
270}
271
272#[async_trait]
273impl<T> PagedDkgQueryClient for T where T: DkgQueryClient {}
274
275#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
276#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
277impl<C> DkgQueryClient for C
278where
279    C: CosmWasmClient + NymContractsProvider + Send + Sync,
280{
281    async fn query_dkg_contract<T>(&self, query: DkgQueryMsg) -> Result<T, NyxdError>
282    where
283        for<'a> T: Deserialize<'a>,
284    {
285        let dkg_contract_address = &self
286            .dkg_contract_address()
287            .ok_or_else(|| NyxdError::unavailable_contract_address("dkg contract"))?;
288        trace!("using the following dkg contract: {dkg_contract_address}");
289        self.query_contract_smart(dkg_contract_address, &query)
290            .await
291    }
292}
293
294#[cfg(test)]
295mod tests {
296    use super::*;
297    use crate::nyxd::contract_traits::tests::IgnoreValue;
298    use nym_coconut_dkg_common::msg::QueryMsg;
299
300    // it's enough that this compiles and clippy is happy about it
301    #[allow(dead_code)]
302    fn all_query_variants_are_covered<C: DkgQueryClient>(client: C, msg: DkgQueryMsg) {
303        match msg {
304            DkgQueryMsg::GetState {} => client.get_state().ignore(),
305            DkgQueryMsg::GetCurrentEpochState {} => client.get_current_epoch().ignore(),
306            DkgQueryMsg::GetEpochStateAtHeight { height } => {
307                client.get_epoch_at_height(height).ignore()
308            }
309            DkgQueryMsg::CanAdvanceState {} => client.can_advance_state().ignore(),
310            DkgQueryMsg::GetCurrentEpochThreshold {} => {
311                client.get_current_epoch_threshold().ignore()
312            }
313            DkgQueryMsg::GetEpochThreshold { epoch_id } => {
314                client.get_epoch_threshold(epoch_id).ignore()
315            }
316            DkgQueryMsg::GetRegisteredDealer {
317                dealer_address,
318                epoch_id,
319            } => client
320                .get_registered_dealer_details(&dealer_address.parse().unwrap(), epoch_id)
321                .ignore(),
322            DkgQueryMsg::GetDealerDetails { dealer_address } => client
323                .get_dealer_details(&dealer_address.parse().unwrap())
324                .ignore(),
325            DkgQueryMsg::GetCurrentDealers { limit, start_after } => client
326                .get_current_dealers_paged(start_after, limit)
327                .ignore(),
328            QueryMsg::GetEpochDealers {
329                epoch_id,
330                limit,
331                start_after,
332            } => client
333                .get_epoch_dealers_paged(epoch_id, start_after, limit)
334                .ignore(),
335            QueryMsg::GetEpochDealersAddresses {
336                epoch_id,
337                limit,
338                start_after,
339            } => client
340                .get_epoch_dealers_addresses_paged(epoch_id, start_after, limit)
341                .ignore(),
342            DkgQueryMsg::GetDealerIndices { limit, start_after } => {
343                client.get_dealer_indices_paged(start_after, limit).ignore()
344            }
345            DkgQueryMsg::GetDealingStatus {
346                epoch_id,
347                dealer,
348                dealing_index,
349            } => client
350                .get_dealing_status(epoch_id, dealer, dealing_index)
351                .ignore(),
352            DkgQueryMsg::GetDealingsMetadata {
353                epoch_id,
354                dealer,
355                dealing_index,
356            } => client
357                .get_dealings_metadata(epoch_id, dealer, dealing_index)
358                .ignore(),
359            QueryMsg::GetDealerDealingsStatus { epoch_id, dealer } => {
360                client.get_dealer_dealings_status(epoch_id, dealer).ignore()
361            }
362            DkgQueryMsg::GetDealingChunkStatus {
363                epoch_id,
364                dealer,
365                dealing_index,
366                chunk_index,
367            } => client
368                .get_dealing_chunk_status(epoch_id, dealer, dealing_index, chunk_index)
369                .ignore(),
370            DkgQueryMsg::GetDealingChunk {
371                epoch_id,
372                dealer,
373                dealing_index,
374                chunk_index,
375            } => client
376                .get_dealing_chunk(epoch_id, dealer, dealing_index, chunk_index)
377                .ignore(),
378            DkgQueryMsg::GetVerificationKey { epoch_id, owner } => {
379                client.get_vk_share(epoch_id, owner).ignore()
380            }
381            DkgQueryMsg::GetVerificationKeys {
382                epoch_id,
383                limit,
384                start_after,
385            } => client
386                .get_vk_shares_paged(epoch_id, start_after, limit)
387                .ignore(),
388            DkgQueryMsg::GetCW2ContractVersion {} => client.get_contract_cw2_version().ignore(),
389        };
390    }
391}