Skip to main content

nym_bandwidth_controller/
traits.rs

1// Copyright 2025 - Nym Technologies SA <contact@nymtech.net>
2// SPDX-License-Identifier: Apache-2.0
3
4use async_trait::async_trait;
5use nym_credential_storage::storage::Storage;
6use nym_credentials_interface::TicketType;
7use nym_crypto::asymmetric::ed25519;
8use nym_validator_client::nyxd::contract_traits::DkgQueryClient;
9
10use crate::{error::BandwidthControllerError, BandwidthController, PreparedCredential};
11
12pub const DEFAULT_TICKETS_TO_SPEND: u32 = 1;
13
14// TODO: this does not really belong here
15pub const UPGRADE_MODE_JWT_TYPE: &str = "UPGRADE_MODE_JWT";
16
17#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
18#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
19pub trait BandwidthTicketProvider: Send + Sync {
20    async fn get_ecash_ticket(
21        &self,
22        ticket_type: TicketType,
23        gateway_id: ed25519::PublicKey,
24        tickets_to_spend: u32,
25    ) -> Result<PreparedCredential, BandwidthControllerError>;
26
27    async fn get_upgrade_mode_token(&self) -> Result<Option<String>, BandwidthControllerError>;
28
29    async fn close(&self) {}
30}
31
32#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
33#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
34impl<C, St> BandwidthTicketProvider for BandwidthController<C, St>
35where
36    C: DkgQueryClient + Sync + Send,
37    St: nym_credential_storage::storage::Storage,
38    <St as Storage>::StorageError: Send + Sync + 'static,
39{
40    async fn get_ecash_ticket(
41        &self,
42        ticket_type: TicketType,
43        gateway_id: ed25519::PublicKey,
44        tickets_to_spend: u32,
45    ) -> Result<PreparedCredential, BandwidthControllerError> {
46        self.prepare_ecash_ticket(ticket_type, gateway_id.to_bytes(), tickets_to_spend)
47            .await
48    }
49
50    async fn get_upgrade_mode_token(&self) -> Result<Option<String>, BandwidthControllerError> {
51        let Some(emergency_credential) =
52            self.get_emergency_credential(UPGRADE_MODE_JWT_TYPE).await?
53        else {
54            return Ok(None);
55        };
56        // upgrade mode credential is just a simple stringified JWT
57        let token = String::from_utf8(emergency_credential.data.content)
58            .map_err(|_| BandwidthControllerError::MalformedUpgradeModeToken)?;
59        Ok(Some(token))
60    }
61
62    async fn close(&self) {
63        self.storage.close().await;
64    }
65}
66
67#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
68#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
69impl<T: BandwidthTicketProvider + ?Sized + Send> BandwidthTicketProvider for Box<T> {
70    async fn get_ecash_ticket(
71        &self,
72        ticket_type: TicketType,
73        gateway_id: ed25519::PublicKey,
74        tickets_to_spend: u32,
75    ) -> Result<PreparedCredential, BandwidthControllerError> {
76        (**self)
77            .get_ecash_ticket(ticket_type, gateway_id, tickets_to_spend)
78            .await
79    }
80
81    async fn get_upgrade_mode_token(&self) -> Result<Option<String>, BandwidthControllerError> {
82        (**self).get_upgrade_mode_token().await
83    }
84
85    async fn close(&self) {
86        (**self).close().await;
87    }
88}