fedimint_mintv2_client/
api.rs1use std::collections::BTreeMap;
2use std::time::Duration;
3
4use bitcoin_hashes::sha256;
5use fedimint_api_client::api::{DynModuleApi, FederationApiExt, ServerError};
6use fedimint_api_client::query::FilterMapThreshold;
7use fedimint_core::module::ApiRequestErased;
8use fedimint_core::util::FmtCompactAnyhow as _;
9use fedimint_core::{NumPeersExt, OutPointRange, PeerId, apply, async_trait_maybe_send, runtime};
10use fedimint_mintv2_common::endpoint_constants::{
11 RECOVERY_COUNT_ENDPOINT, RECOVERY_SLICE_ENDPOINT, RECOVERY_SLICE_HASH_ENDPOINT,
12 SIGNATURE_SHARES_ENDPOINT, SIGNATURE_SHARES_RECOVERY_ENDPOINT,
13};
14use fedimint_mintv2_common::{Denomination, RecoveryItem};
15use tbs::{BlindedMessage, BlindedSignatureShare, PublicKeyShare};
16
17use crate::NoteIssuanceRequest;
18use crate::output::verify_blind_shares;
19
20#[apply(async_trait_maybe_send!)]
21pub trait MintV2ModuleApi {
22 async fn fetch_signature_shares(
23 &self,
24 range: OutPointRange,
25 issuance_requests: Vec<NoteIssuanceRequest>,
26 tbs_pks: BTreeMap<Denomination, BTreeMap<PeerId, PublicKeyShare>>,
27 ) -> BTreeMap<PeerId, Vec<BlindedSignatureShare>>;
28
29 async fn fetch_signature_shares_recovery(
30 &self,
31 issuance_requests: Vec<NoteIssuanceRequest>,
32 tbs_pks: BTreeMap<Denomination, BTreeMap<PeerId, PublicKeyShare>>,
33 ) -> BTreeMap<PeerId, Vec<BlindedSignatureShare>>;
34
35 async fn fetch_recovery_count(&self) -> anyhow::Result<u64>;
36
37 async fn fetch_recovery_slice_hash(&self, start: u64, end: u64) -> sha256::Hash;
38
39 async fn fetch_recovery_slice(
40 &self,
41 peer: PeerId,
42 timeout: Duration,
43 start: u64,
44 end: u64,
45 ) -> anyhow::Result<Vec<RecoveryItem>>;
46}
47
48#[apply(async_trait_maybe_send!)]
49impl MintV2ModuleApi for DynModuleApi {
50 async fn fetch_signature_shares(
51 &self,
52 range: OutPointRange,
53 issuance_requests: Vec<NoteIssuanceRequest>,
54 tbs_pks: BTreeMap<Denomination, BTreeMap<PeerId, PublicKeyShare>>,
55 ) -> BTreeMap<PeerId, Vec<BlindedSignatureShare>> {
56 self.request_with_strategy_retry(
57 FilterMapThreshold::new(
59 move |peer, signature_shares| {
60 verify_blind_shares(peer, signature_shares, &issuance_requests, &tbs_pks)
61 .map_err(|err| {
62 ServerError::InvalidResponse(err.fmt_compact_anyhow().to_string())
63 })
64 },
65 self.all_peers().to_num_peers(),
66 ),
67 SIGNATURE_SHARES_ENDPOINT.to_owned(),
68 ApiRequestErased::new(range),
69 )
70 .await
71 }
72
73 async fn fetch_signature_shares_recovery(
74 &self,
75 issuance_requests: Vec<NoteIssuanceRequest>,
76 tbs_pks: BTreeMap<Denomination, BTreeMap<PeerId, PublicKeyShare>>,
77 ) -> BTreeMap<PeerId, Vec<BlindedSignatureShare>> {
78 let blinded_messages: Vec<BlindedMessage> = issuance_requests
79 .iter()
80 .map(NoteIssuanceRequest::blinded_message)
81 .collect();
82
83 self.request_with_strategy_retry(
84 FilterMapThreshold::new(
86 move |peer, signature_shares| {
87 verify_blind_shares(peer, signature_shares, &issuance_requests, &tbs_pks)
88 .map_err(|err| {
89 ServerError::InvalidResponse(err.fmt_compact_anyhow().to_string())
90 })
91 },
92 self.all_peers().to_num_peers(),
93 ),
94 SIGNATURE_SHARES_RECOVERY_ENDPOINT.to_owned(),
95 ApiRequestErased::new(blinded_messages),
96 )
97 .await
98 }
99
100 async fn fetch_recovery_count(&self) -> anyhow::Result<u64> {
101 self.request_current_consensus::<u64>(
102 RECOVERY_COUNT_ENDPOINT.to_string(),
103 ApiRequestErased::default(),
104 )
105 .await
106 .map_err(|e| anyhow::anyhow!("{e}"))
107 }
108
109 async fn fetch_recovery_slice_hash(&self, start: u64, end: u64) -> sha256::Hash {
110 self.request_current_consensus_retry(
111 RECOVERY_SLICE_HASH_ENDPOINT.to_owned(),
112 ApiRequestErased::new((start, end)),
113 )
114 .await
115 }
116
117 async fn fetch_recovery_slice(
118 &self,
119 peer: PeerId,
120 timeout: Duration,
121 start: u64,
122 end: u64,
123 ) -> anyhow::Result<Vec<RecoveryItem>> {
124 let result = runtime::timeout(
125 timeout,
126 self.request_single_peer::<Vec<RecoveryItem>>(
127 RECOVERY_SLICE_ENDPOINT.to_owned(),
128 ApiRequestErased::new((start, end)),
129 peer,
130 ),
131 )
132 .await??;
133
134 Ok(result)
135 }
136}