persisting the issued credentials

This commit is contained in:
Jędrzej Stuczyński
2024-02-08 15:01:58 +00:00
parent ddf2770c8e
commit f687ebb0f5
20 changed files with 210 additions and 195 deletions
Generated
+2
View File
@@ -5343,6 +5343,7 @@ dependencies = [
"sqlx",
"thiserror",
"tokio",
"zeroize",
]
[[package]]
@@ -5543,6 +5544,7 @@ dependencies = [
"sqlx",
"subtle-encoding",
"thiserror",
"time",
"tokio",
"tokio-stream",
"tokio-tungstenite",
+17 -14
View File
@@ -2,7 +2,7 @@
// SPDX-License-Identifier: Apache-2.0
use crate::error::BandwidthControllerError;
use nym_coconut::Base58;
use nym_credential_storage::models::StorableIssuedCredential;
use nym_credential_storage::storage::Storage;
use nym_credentials::coconut::bandwidth::{CredentialType, IssuanceBandwidthCredential};
use nym_credentials::coconut::utils::obtain_aggregate_signature;
@@ -13,6 +13,7 @@ use nym_validator_client::nyxd::contract_traits::DkgQueryClient;
use nym_validator_client::nyxd::Coin;
use rand::rngs::OsRng;
use state::State;
use zeroize::Zeroizing;
pub mod state;
@@ -43,7 +44,7 @@ where
Ok(state)
}
pub async fn get_credential<C, St>(
pub async fn get_bandwidth_voucher<C, St>(
state: &State,
client: &C,
storage: &St,
@@ -54,7 +55,7 @@ where
<St as Storage>::StorageError: Send + Sync + 'static,
{
// temporary
assert!(!state.voucher.typ().is_free_pass());
assert!(state.voucher.typ().is_voucher());
let epoch_id = client.get_current_epoch().await?.epoch_id;
let threshold = client
@@ -66,19 +67,21 @@ where
let signature =
obtain_aggregate_signature(&state.voucher, &coconut_api_clients, threshold).await?;
let issued = state.voucher.to_issued_credential(signature);
// make sure the data gets zeroized after persisting it
let credential_data = Zeroizing::new(issued.pack_v1());
let storable = StorableIssuedCredential {
serialization_revision: issued.current_serialization_revision(),
credential_data: credential_data.as_ref(),
credential_type: issued.typ().to_string(),
epoch_id: epoch_id
.try_into()
.expect("our epoch is has run over u32::MAX!"),
};
// we asserted the that the bandwidth credential we obtained is **NOT** the free pass
// so the first public attribute must be the value
let voucher_value = state.voucher.get_plain_public_attributes()[0].clone();
storage
.insert_coconut_credential(
voucher_value,
CredentialType::Voucher.to_string(),
state.voucher.get_private_attributes()[0].to_bs58(),
state.voucher.get_private_attributes()[1].to_bs58(),
signature.to_bs58(),
epoch_id.to_string(),
)
.insert_issued_credential(storable)
.await
.map_err(|err| BandwidthControllerError::CredentialStorageError(Box::new(err)))
}
+2 -5
View File
@@ -1,10 +1,9 @@
// Copyright 2021-2023 - Nym Technologies SA <contact@nymtech.net>
// Copyright 2021-2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::error::BandwidthControllerError;
use crate::utils::stored_credential_to_issued_bandwidth;
use log::{error, warn};
use nym_credential_storage::error::StorageError;
use nym_credential_storage::storage::Storage;
use nym_credentials::coconut::bandwidth::CredentialSpendingData;
use nym_credentials::coconut::utils::obtain_aggregate_verification_key;
@@ -12,7 +11,6 @@ use nym_credentials_interface::VerificationKey;
use nym_validator_client::coconut::all_coconut_api_clients;
use nym_validator_client::nym_api::EpochId;
use nym_validator_client::nyxd::contract_traits::DkgQueryClient;
use std::str::FromStr;
pub mod acquire;
pub mod error;
@@ -69,8 +67,7 @@ impl<C, St: Storage> BandwidthController<C, St> {
.await
.map_err(|err| BandwidthControllerError::CredentialStorageError(Box::new(err)))?;
let epoch_id = u64::from_str(&retrieved_credential.epoch_id)
.map_err(|_| StorageError::InconsistentData)?;
let epoch_id = retrieved_credential.epoch_id as EpochId;
let credential_id = retrieved_credential.id;
let issued_bandwidth = stored_credential_to_issued_bandwidth(retrieved_credential)?;
+1 -1
View File
@@ -2,7 +2,7 @@
// SPDX-License-Identifier: Apache-2.0
use crate::error::BandwidthControllerError;
use nym_credential_storage::models::StoredIssuedCredential;
use nym_credential_storage::models::{StorableIssuedCredential, StoredIssuedCredential};
use nym_credentials::coconut::bandwidth::IssuedBandwidthCredential;
use nym_validator_client::nym_api::EpochId;
+3 -1
View File
@@ -11,7 +11,9 @@ async-trait = { workspace = true }
log = { workspace = true }
thiserror = { workspace = true }
tokio = { version = "1.24.1", features = ["sync"]}
tokio = { workspace = true, features = ["sync"]}
zeroize = { workspace = true, features = ["zeroize_derive"] }
[target."cfg(not(target_arch = \"wasm32\"))".dependencies.sqlx]
workspace = true
@@ -3,3 +3,15 @@
* SPDX-License-Identifier: Apache-2.0
*/
DROP TABLE coconut_credentials;
CREATE TABLE coconut_credentials
(
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
-- introduce a way for us to introduce breaking changes in serialization
serialization_revision INTEGER NOT NULL,
credential_type TEXT NOT NULL,
credential_data BLOB NOT NULL,
epoch_id TEXT NOT NULL,
consumed BOOLEAN NOT NULL
);
@@ -1,59 +1,60 @@
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
// Copyright 2023-2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::models::CoconutCredential;
use crate::models::StoredIssuedCredential;
use std::sync::Arc;
use tokio::sync::RwLock;
#[derive(Clone)]
pub struct CoconutCredentialManager {
inner: Arc<RwLock<Vec<CoconutCredential>>>,
inner: Arc<RwLock<CoconutCredentialManagerInner>>,
}
#[derive(Default)]
struct CoconutCredentialManagerInner {
data: Vec<StoredIssuedCredential>,
_next_id: i64,
}
impl CoconutCredentialManagerInner {
fn next_id(&mut self) -> i64 {
let next = self._next_id;
self._next_id += 1;
next
}
}
impl CoconutCredentialManager {
/// Creates new empty instance of the `CoconutCredentialManager`.
pub fn new() -> Self {
CoconutCredentialManager {
inner: Arc::new(RwLock::new(Vec::new())),
inner: Default::default(),
}
}
/// Inserts provided signature into the database.
///
/// # Arguments
///
/// * `voucher_value`: Plaintext bandwidth value of the credential.
/// * `voucher_info`: Plaintext information of the credential.
/// * `serial_number`: Base58 representation of the serial number attribute.
/// * `binding_number`: Base58 representation of the binding number attribute.
/// * `signature`: Coconut credential in the form of a signature.
pub async fn insert_coconut_credential(
pub async fn insert_issued_credential(
&self,
voucher_value: String,
voucher_info: String,
serial_number: String,
binding_number: String,
signature: String,
epoch_id: String,
credential_type: String,
serialization_revision: u8,
credential_data: &[u8],
epoch_id: u32,
) {
let mut creds = self.inner.write().await;
let id = creds.len() as i64;
creds.push(CoconutCredential {
let mut inner = self.inner.write().await;
let id = inner.next_id();
inner.data.push(StoredIssuedCredential {
id,
voucher_value,
voucher_info,
serial_number,
binding_number,
signature,
serialization_revision,
credential_data: credential_data.to_vec(),
credential_type,
epoch_id,
consumed: false,
});
})
}
/// Tries to retrieve one of the stored, unused credentials.
pub async fn get_next_coconut_credential(&self) -> Option<CoconutCredential> {
pub async fn get_next_unspent_credential(&self) -> Option<StoredIssuedCredential> {
let creds = self.inner.read().await;
creds.iter().find(|c| !c.consumed).cloned()
creds.data.iter().find(|c| !c.consumed).cloned()
}
/// Consumes in the database the specified credential.
@@ -63,7 +64,7 @@ impl CoconutCredentialManager {
/// * `id`: Database id.
pub async fn consume_coconut_credential(&self, id: i64) {
let mut creds = self.inner.write().await;
if let Some(cred) = creds.get_mut(id as usize) {
if let Some(cred) = creds.data.get_mut(id as usize) {
cred.consumed = true;
}
}
@@ -1,7 +1,7 @@
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
// Copyright 2022-2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::models::CoconutCredential;
use crate::models::StoredIssuedCredential;
#[derive(Clone)]
pub struct CoconutCredentialManager {
@@ -18,43 +18,29 @@ impl CoconutCredentialManager {
CoconutCredentialManager { connection_pool }
}
/// Inserts provided signature into the database.
///
/// # Arguments
///
/// * `voucher_value`: Plaintext bandwidth value of the credential.
/// * `voucher_info`: Plaintext information of the credential.
/// * `serial_number`: Base58 representation of the serial number attribute.
/// * `binding_number`: Base58 representation of the binding number attribute.
/// * `signature`: Coconut credential in the form of a signature.
pub async fn insert_coconut_credential(
pub async fn insert_issued_credential(
&self,
voucher_value: String,
voucher_info: String,
serial_number: String,
binding_number: String,
signature: String,
epoch_id: String,
credential_type: String,
serialization_revision: u8,
credential_data: &[u8],
epoch_id: u32,
) -> Result<(), sqlx::Error> {
sqlx::query!(
"INSERT INTO coconut_credentials(voucher_value, voucher_info, serial_number, binding_number, signature, epoch_id, consumed) VALUES (?, ?, ?, ?, ?, ?, ?)",
voucher_value, voucher_info, serial_number, binding_number, signature, epoch_id, false
)
.execute(&self.connection_pool)
.await?;
r#"
INSERT INTO coconut_credentials(serialization_revision, credential_type, credential_data, epoch_id, consumed)
VALUES (?, ?, ?, ?, false)
"#,
serialization_revision, credential_type, credential_data, epoch_id
).execute(&self.connection_pool).await?;
Ok(())
}
/// Tries to retrieve one of the stored, unused credentials.
pub async fn get_next_coconut_credential(
pub async fn get_next_unspent_credential(
&self,
) -> Result<Option<CoconutCredential>, sqlx::Error> {
sqlx::query_as!(
CoconutCredential,
"SELECT * FROM coconut_credentials WHERE NOT consumed"
)
.fetch_optional(&self.connection_pool)
.await
) -> Result<Option<StoredIssuedCredential>, sqlx::Error> {
sqlx::query_as("SELECT * FROM coconut_credentials WHERE NOT consumed LIMIT 1")
.fetch_optional(&self.connection_pool)
.await
}
/// Consumes in the database the specified credential.
@@ -3,7 +3,7 @@
use crate::backends::memory::CoconutCredentialManager;
use crate::error::StorageError;
use crate::models::{CoconutCredential, StoredIssuedCredential};
use crate::models::{StorableIssuedCredential, StoredIssuedCredential};
use crate::storage::Storage;
use async_trait::async_trait;
@@ -27,43 +27,31 @@ impl Default for EphemeralStorage {
impl Storage for EphemeralStorage {
type StorageError = StorageError;
async fn insert_coconut_credential(
async fn insert_issued_credential<'a>(
&self,
voucher_value: String,
voucher_info: String,
serial_number: String,
binding_number: String,
signature: String,
epoch_id: String,
bandwidth_credential: StorableIssuedCredential<'a>,
) -> Result<(), StorageError> {
self.coconut_credential_manager
.insert_coconut_credential(
voucher_value,
voucher_info,
serial_number,
binding_number,
signature,
epoch_id,
.insert_issued_credential(
bandwidth_credential.credential_type,
bandwidth_credential.serialization_revision,
bandwidth_credential.credential_data,
bandwidth_credential.epoch_id,
)
.await;
Ok(())
}
async fn get_next_coconut_credential(&self) -> Result<CoconutCredential, StorageError> {
let credential = self
.coconut_credential_manager
.get_next_coconut_credential()
.await
.ok_or(StorageError::NoCredential)?;
Ok(credential)
}
async fn get_next_unspent_credential(
&self,
) -> Result<StoredIssuedCredential, Self::StorageError> {
todo!()
let credential = self
.coconut_credential_manager
.get_next_unspent_credential()
.await
.ok_or(StorageError::NoCredential)?;
Ok(credential)
}
async fn consume_coconut_credential(&self, id: i64) -> Result<(), StorageError> {
+27 -20
View File
@@ -1,31 +1,38 @@
// Copyright 2022-2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
#[derive(Clone)]
pub struct CoconutCredential {
#[allow(dead_code)]
pub id: i64,
pub voucher_value: String,
pub voucher_info: String,
pub serial_number: String,
pub binding_number: String,
pub signature: String,
pub epoch_id: String,
pub consumed: bool,
}
use zeroize::{Zeroize, ZeroizeOnDrop};
// #[derive(Clone)]
// pub struct CoconutCredential {
// #[allow(dead_code)]
// pub id: i64,
// pub voucher_value: String,
// pub voucher_info: String,
// pub serial_number: String,
// pub binding_number: String,
// pub signature: String,
// pub epoch_id: String,
// pub consumed: bool,
// }
#[cfg_attr(not(target_arch = "wasm32"), derive(sqlx::FromRow))]
#[derive(Zeroize, ZeroizeOnDrop, Clone)]
pub struct StoredIssuedCredential {
pub id: i64,
pub serial_number: String,
pub binding_number: String,
pub serialization_revision: u8,
pub credential_data: Vec<u8>,
pub credential_type: String,
pub signature: String,
pub variant_type: String,
pub serialized_variant_data: String,
pub epoch_id: String,
pub epoch_id: u32,
pub consumed: bool,
}
pub struct StorableIssuedCredential<'a> {
pub serialization_revision: u8,
pub credential_data: &'a [u8],
pub credential_type: String,
pub epoch_id: u32,
}
@@ -5,7 +5,7 @@ use crate::backends::sqlite::CoconutCredentialManager;
use crate::error::StorageError;
use crate::storage::Storage;
use crate::models::{CoconutCredential, StoredIssuedCredential};
use crate::models::{StorableIssuedCredential, StoredIssuedCredential};
use async_trait::async_trait;
use log::{debug, error};
use sqlx::ConnectOptions;
@@ -58,45 +58,34 @@ impl PersistentStorage {
impl Storage for PersistentStorage {
type StorageError = StorageError;
async fn insert_coconut_credential(
async fn insert_issued_credential<'a>(
&self,
voucher_value: String,
voucher_info: String,
serial_number: String,
binding_number: String,
signature: String,
epoch_id: String,
) -> Result<(), StorageError> {
bandwidth_credential: StorableIssuedCredential<'a>,
) -> Result<(), Self::StorageError> {
self.coconut_credential_manager
.insert_coconut_credential(
voucher_value,
voucher_info,
serial_number,
binding_number,
signature,
epoch_id,
.insert_issued_credential(
bandwidth_credential.credential_type,
bandwidth_credential.serialization_revision,
bandwidth_credential.credential_data,
bandwidth_credential.epoch_id,
)
.await?;
Ok(())
}
async fn get_next_coconut_credential(&self) -> Result<CoconutCredential, StorageError> {
async fn get_next_unspent_credential(
&self,
) -> Result<StoredIssuedCredential, Self::StorageError> {
let credential = self
.coconut_credential_manager
.get_next_coconut_credential()
.get_next_unspent_credential()
.await?
.ok_or(StorageError::NoCredential)?;
Ok(credential)
}
async fn get_next_unspent_credential(
&self,
) -> Result<StoredIssuedCredential, Self::StorageError> {
todo!()
}
async fn consume_coconut_credential(&self, id: i64) -> Result<(), StorageError> {
self.coconut_credential_manager
.consume_coconut_credential(id)
+3 -23
View File
@@ -1,7 +1,7 @@
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::models::{CoconutCredential, StoredIssuedCredential};
use crate::models::{StorableIssuedCredential, StoredIssuedCredential};
use async_trait::async_trait;
use std::error::Error;
@@ -9,31 +9,11 @@ use std::error::Error;
pub trait Storage: Send + Sync {
type StorageError: Error;
/// Inserts provided signature into the database.
///
/// # Arguments
///
/// * `voucher_value`: How much bandwidth is in the credential.
/// * `voucher_info`: What type of credential it is.
/// * `serial_number`: Serial number of the credential.
/// * `binding_number`: Binding number of the credential.
/// * `signature`: Coconut credential in the form of a signature.
/// * `epoch_id`: The epoch when it was signed.
#[deprecated]
async fn insert_coconut_credential(
async fn insert_issued_credential<'a>(
&self,
voucher_value: String,
voucher_info: String,
serial_number: String,
binding_number: String,
signature: String,
epoch_id: String,
bandwidth_credential: StorableIssuedCredential<'a>,
) -> Result<(), Self::StorageError>;
/// Tries to retrieve one of the stored, unused credentials.
#[deprecated]
async fn get_next_coconut_credential(&self) -> Result<CoconutCredential, Self::StorageError>;
/// Tries to retrieve one of the stored, unused credentials.
async fn get_next_unspent_credential(
&self,
+3 -2
View File
@@ -44,7 +44,7 @@ where
let state = nym_bandwidth_controller::acquire::deposit(client, amount.clone()).await?;
if nym_bandwidth_controller::acquire::get_credential(&state, client, persistent_storage)
if nym_bandwidth_controller::acquire::get_bandwidth_voucher(&state, client, persistent_storage)
.await
.is_err()
{
@@ -142,7 +142,8 @@ where
let state = State::new(voucher);
if let Err(e) =
nym_bandwidth_controller::acquire::get_credential(&state, client, shared_storage).await
nym_bandwidth_controller::acquire::get_bandwidth_voucher(&state, client, shared_storage)
.await
{
error!("Could not recover deposit {voucher_name} due to {e}, try again later",)
} else {
+1 -1
View File
@@ -13,6 +13,7 @@ cosmrs = { workspace = true }
thiserror = { workspace = true }
log = { workspace = true }
time = { workspace = true, features = ["serde"] }
serde = { workspace = true, features = ["derive"] }
zeroize = { workspace = true }
# I guess temporarily until we get serde support in coconut up and running
@@ -20,7 +21,6 @@ nym-credentials-interface = { path = "../credentials-interface" }
nym-crypto = { path = "../crypto", features = ["rand", "asymmetric", "serde"] }
nym-api-requests = { path = "../../nym-api/nym-api-requests" }
nym-validator-client = { path = "../client-libs/validator-client", default-features = false }
serde = { workspace = true, features = ["derive"] }
[dev-dependencies]
rand = "0.7.3"
@@ -30,7 +30,7 @@ impl FreePassIssuedData {
}
}
#[derive(Zeroize, ZeroizeOnDrop, Serialize, Deserialize)]
#[derive(Zeroize, Serialize, Deserialize)]
pub struct FreePassIssuanceData {
/// the plain validity value of this credential expressed as unix timestamp
#[zeroize(skip)]
@@ -238,9 +238,17 @@ impl IssuanceBandwidthCredential {
.map_err(Error::SignatureAggregationError)
}
// also drops self after the conversion
pub fn into_issued_credential(
self,
aggregate_signature: Signature,
) -> IssuedBandwidthCredential {
self.to_issued_credential(aggregate_signature)
}
pub fn to_issued_credential(
&self,
aggregate_signature: Signature,
) -> IssuedBandwidthCredential {
IssuedBandwidthCredential::new(
self.serial_number,
@@ -1,23 +1,25 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::coconut::bandwidth::bandwidth_credential_params;
use crate::coconut::bandwidth::freepass::FreePassIssuedData;
use crate::coconut::bandwidth::issuance::{
BandwidthCredentialIssuanceDataVariant, IssuanceBandwidthCredential,
};
use crate::coconut::bandwidth::voucher::BandwidthVoucherIssuedData;
use crate::coconut::bandwidth::{
bandwidth_credential_params, CredentialSpendingData, CredentialType,
};
use crate::coconut::bandwidth::{CredentialSpendingData, CredentialType};
use crate::coconut::utils::scalar_serde_helper;
use crate::error::Error;
use nym_credentials_interface::prove_bandwidth_credential;
use nym_credentials_interface::{
prove_bandwidth_credential, Parameters, PrivateAttribute, PublicAttribute, Signature,
VerificationKey,
Parameters, PrivateAttribute, PublicAttribute, Signature, VerificationKey,
};
use serde::{Deserialize, Serialize};
use zeroize::{Zeroize, ZeroizeOnDrop};
#[derive(Zeroize, ZeroizeOnDrop, Serialize, Deserialize)]
pub const CURRENT_SERIALIZATION_REVISION: u8 = 1;
#[derive(Zeroize, Serialize, Deserialize)]
pub enum BandwidthCredentialIssuedDataVariant {
Voucher(BandwidthVoucherIssuedData),
FreePass(FreePassIssuedData),
@@ -68,13 +70,15 @@ impl BandwidthCredentialIssuedDataVariant {
}
// the only important thing to zeroize here are the private attributes, the rest can be made fully public for what we're concerned
#[derive(Zeroize, ZeroizeOnDrop)]
#[derive(Zeroize, ZeroizeOnDrop, Serialize, Deserialize)]
pub struct IssuedBandwidthCredential {
// private attributes
/// a random secret value generated by the client used for double-spending detection
#[serde(with = "scalar_serde_helper")]
serial_number: PrivateAttribute,
/// a random secret value generated by the client used to bind multiple credentials together
#[serde(with = "scalar_serde_helper")]
binding_number: PrivateAttribute,
/// the underlying aggregated signature on the attributes
@@ -85,6 +89,7 @@ pub struct IssuedBandwidthCredential {
variant_data: BandwidthCredentialIssuedDataVariant,
/// type of the bandwdith credential hashed onto a scalar
#[serde(with = "scalar_serde_helper")]
type_prehashed: PublicAttribute,
}
@@ -105,6 +110,28 @@ impl IssuedBandwidthCredential {
}
}
pub fn current_serialization_revision(&self) -> u8 {
CURRENT_SERIALIZATION_REVISION
}
/// Pack (serialize) this credential data into a stream of bytes using v1 serializer.
pub fn pack_v1(&self) -> Vec<u8> {
use bincode::Options;
// safety: our data format is stable and thus the serialization should not fail
make_storable_bincode_serializer().serialize(self).unwrap()
}
/// Unpack (deserialize) the credential data from the given bytes using v1 serializer.
pub fn unpack_v1(bytes: &[u8]) -> Result<Self, Error> {
use bincode::Options;
Ok(make_storable_bincode_serializer().deserialize(bytes)?)
}
pub fn randomise_signature(&mut self) {
let signature_prime = self.signature.randomise(bandwidth_credential_params());
self.signature = signature_prime.0
}
pub fn default_parameters() -> Parameters {
IssuanceBandwidthCredential::default_parameters()
}
@@ -142,3 +169,10 @@ impl IssuedBandwidthCredential {
})
}
}
fn make_storable_bincode_serializer() -> impl bincode::Options {
use bincode::Options;
bincode::DefaultOptions::new()
.with_big_endian()
.with_varint_encoding()
}
+1
View File
@@ -3915,6 +3915,7 @@ dependencies = [
"sqlx",
"thiserror",
"tokio",
"zeroize",
]
[[package]]
+7 -3
View File
@@ -57,7 +57,7 @@ where
pub async fn acquire(&self, amount: u128) -> Result<()> {
let amount = Coin::new(amount, &self.network_details.chain_details.mix_denom.base);
let state = nym_bandwidth_controller::acquire::deposit(&self.client, amount).await?;
nym_bandwidth_controller::acquire::get_credential(&state, &self.client, self.storage)
nym_bandwidth_controller::acquire::get_bandwidth_voucher(&state, &self.client, self.storage)
.await
.map_err(|reason| Error::UnconvertedDeposit {
reason,
@@ -71,8 +71,12 @@ where
let voucher = IssuanceBandwidthCredential::try_from_recovered_bytes(voucher_blob)
.map_err(|_| Error::InvalidVoucherBlob)?;
let state = State::new(voucher);
nym_bandwidth_controller::acquire::get_credential(&state, &self.client, self.storage)
.await?;
nym_bandwidth_controller::acquire::get_bandwidth_voucher(
&state,
&self.client,
self.storage,
)
.await?;
Ok(())
}
+2 -2
View File
@@ -59,8 +59,8 @@ pub use nym_client_core::{
config::{GatewayEndpointConfig, GroupBy},
};
pub use nym_credential_storage::{
ephemeral_storage::EphemeralStorage as EphemeralCredentialStorage, models::CoconutCredential,
storage::Storage as CredentialStorage,
ephemeral_storage::EphemeralStorage as EphemeralCredentialStorage,
models::StoredIssuedCredential, storage::Storage as CredentialStorage,
};
pub use nym_network_defaults::NymNetworkDetails;
pub use nym_socks5_client_core::config::Socks5;