nym_bandwidth_controller/acquire/
mod.rs

1// Copyright 2023-2024 - Nym Technologies SA <contact@nymtech.net>
2// SPDX-License-Identifier: Apache-2.0
3
4use crate::error::BandwidthControllerError;
5use crate::utils::{
6    get_aggregate_verification_key, get_coin_index_signatures, get_expiration_date_signatures,
7};
8use log::info;
9use nym_credential_storage::storage::Storage;
10use nym_credentials::ecash::bandwidth::IssuanceTicketBook;
11use nym_credentials::ecash::utils::obtain_aggregate_wallet;
12use nym_credentials::IssuedTicketBook;
13use nym_credentials_interface::TicketType;
14use nym_crypto::asymmetric::ed25519;
15use nym_ecash_time::{ecash_default_expiration_date, Date};
16use nym_validator_client::coconut::all_ecash_api_clients;
17use nym_validator_client::nym_api::EpochId;
18use nym_validator_client::nyxd::contract_traits::EcashSigningClient;
19use nym_validator_client::nyxd::contract_traits::{DkgQueryClient, EcashQueryClient};
20use nym_validator_client::nyxd::cosmwasm_client::ContractResponseData;
21use nym_validator_client::EcashApiClient;
22use rand::rngs::OsRng;
23
24pub async fn make_deposit<C>(
25    client: &C,
26    client_id: &[u8],
27    expiration: Option<Date>,
28    ticketbook_type: TicketType,
29) -> Result<IssuanceTicketBook, BandwidthControllerError>
30where
31    C: EcashSigningClient + EcashQueryClient + Sync,
32{
33    let mut rng = OsRng;
34    let signing_key = ed25519::PrivateKey::new(&mut rng);
35    let expiration = expiration.unwrap_or_else(ecash_default_expiration_date);
36
37    let deposit_amount = client.get_required_deposit_amount().await?;
38    info!("we'll need to deposit {deposit_amount} to obtain the ticketbook");
39    let result = client
40        .make_ticketbook_deposit(
41            signing_key.public_key().to_base58_string(),
42            deposit_amount.into(),
43            None,
44        )
45        .await?;
46
47    let deposit_id = result.parse_singleton_u32_contract_data()?;
48
49    info!("our ticketbook deposit has been stored under id {deposit_id}");
50
51    Ok(IssuanceTicketBook::new_with_expiration(
52        deposit_id,
53        client_id,
54        signing_key,
55        ticketbook_type,
56        expiration,
57    ))
58}
59
60pub async fn query_and_persist_required_global_data<S>(
61    storage: &S,
62    epoch_id: EpochId,
63    expiration_date: Date,
64    apis: Vec<EcashApiClient>,
65) -> Result<(), BandwidthControllerError>
66where
67    S: Storage,
68    <S as Storage>::StorageError: Send + Sync + 'static,
69{
70    log::info!("Getting master verification key");
71    // this will also persist the key in the storage if was not there already
72    get_aggregate_verification_key(storage, epoch_id, apis.clone()).await?;
73
74    log::info!("Getting expiration date signatures");
75    // this will also persist the signatures in the storage if they were not there already
76    get_expiration_date_signatures(storage, epoch_id, expiration_date, apis.clone()).await?;
77
78    log::info!("Getting coin indices signatures");
79    // this will also persist the signatures in the storage if they were not there already
80    get_coin_index_signatures(storage, epoch_id, apis).await?;
81    Ok(())
82}
83
84pub async fn get_ticket_book<C, St>(
85    issuance_data: &IssuanceTicketBook,
86    client: &C,
87    storage: &St,
88    apis: Option<Vec<EcashApiClient>>,
89) -> Result<IssuedTicketBook, BandwidthControllerError>
90where
91    C: DkgQueryClient + Send + Sync,
92    St: Storage,
93    <St as Storage>::StorageError: Send + Sync + 'static,
94{
95    let epoch_id = client.get_current_epoch().await?.epoch_id;
96    let threshold = client
97        .get_current_epoch_threshold()
98        .await?
99        .ok_or(BandwidthControllerError::NoThreshold)?;
100
101    let apis = match apis {
102        Some(apis) => apis,
103        None => all_ecash_api_clients(client, epoch_id).await?,
104    };
105
106    log::info!("Querying wallet signatures");
107    let wallet = obtain_aggregate_wallet(issuance_data, &apis, threshold).await?;
108    info!("managed to obtain sufficient number of partial signatures!");
109
110    log::info!("Getting expiration date signatures");
111    // this will also persist the signatures in the storage if they were not there already
112    get_expiration_date_signatures(
113        storage,
114        epoch_id,
115        issuance_data.expiration_date(),
116        apis.clone(),
117    )
118    .await?;
119
120    log::info!("Getting coin indices signatures");
121    // this will also persist the signatures in the storage if they were not there already
122    get_coin_index_signatures(storage, epoch_id, apis).await?;
123
124    let issued = issuance_data.to_issued_ticketbook(wallet, epoch_id);
125
126    info!("persisting the ticketbook into the storage...");
127    storage
128        .insert_issued_ticketbook(&issued)
129        .await
130        .map_err(|err| BandwidthControllerError::CredentialStorageError(Box::new(err)))?;
131    Ok(issued)
132}