-
Notifications
You must be signed in to change notification settings - Fork 235
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Move cred verification to common crate
- Loading branch information
Showing
23 changed files
with
577 additions
and
461 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
[package] | ||
name = "nym-credential-verification" | ||
version = "0.1.0" | ||
authors.workspace = true | ||
repository.workspace = true | ||
homepage.workspace = true | ||
documentation.workspace = true | ||
edition.workspace = true | ||
license.workspace = true | ||
rust-version.workspace = true | ||
readme.workspace = true | ||
|
||
[dependencies] | ||
bs58 = { workspace = true } | ||
cosmwasm-std = { workspace = true } | ||
cw-utils = { workspace = true } | ||
futures = { workspace = true } | ||
rand = { workspace = true } | ||
si-scale = { workspace = true } | ||
thiserror = { workspace = true } | ||
tokio = { workspace = true, features = ["rt-multi-thread", "macros"] } | ||
time = { workspace = true } | ||
tracing = { workspace = true } | ||
|
||
nym-api-requests = { path = "../../nym-api/nym-api-requests" } | ||
nym-credentials = { path = "../credentials" } | ||
nym-credentials-interface = { path = "../credentials-interface" } | ||
nym-ecash-contract-common = { path = "../cosmwasm-smart-contracts/ecash-contract" } | ||
nym-ecash-double-spending = { path = "../ecash-double-spending" } | ||
nym-gateway-requests = { path = "../gateway-requests" } | ||
nym-gateway-storage = { path = "../gateway-storage" } | ||
nym-task = { path = "../task" } | ||
nym-validator-client = { path = "../client-libs/validator-client" } |
148 changes: 148 additions & 0 deletions
148
common/credential-verification/src/bandwidth_storage_manager.rs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,148 @@ | ||
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net> | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
use nym_credentials::ecash::utils::ecash_today; | ||
use nym_credentials_interface::Bandwidth; | ||
use nym_gateway_requests::ServerResponse; | ||
use nym_gateway_storage::Storage; | ||
use si_scale::helpers::bibytes2; | ||
use time::OffsetDateTime; | ||
use tracing::*; | ||
|
||
use crate::error::*; | ||
use crate::BandwidthFlushingBehaviourConfig; | ||
use crate::ClientBandwidth; | ||
|
||
const FREE_TESTNET_BANDWIDTH_VALUE: Bandwidth = Bandwidth::new_unchecked(64 * 1024 * 1024 * 1024); // 64GB | ||
|
||
#[derive(Clone)] | ||
pub struct BandwidthStorageManager<S> { | ||
pub(crate) storage: S, | ||
pub(crate) client_bandwidth: ClientBandwidth, | ||
pub(crate) client_id: i64, | ||
pub(crate) bandwidth_cfg: BandwidthFlushingBehaviourConfig, | ||
pub(crate) only_coconut_credentials: bool, | ||
} | ||
|
||
impl<S: Storage + Clone + 'static> BandwidthStorageManager<S> { | ||
pub fn new( | ||
storage: S, | ||
client_bandwidth: ClientBandwidth, | ||
client_id: i64, | ||
bandwidth_cfg: BandwidthFlushingBehaviourConfig, | ||
only_coconut_credentials: bool, | ||
) -> Self { | ||
BandwidthStorageManager { | ||
storage, | ||
client_bandwidth, | ||
client_id, | ||
bandwidth_cfg, | ||
only_coconut_credentials, | ||
} | ||
} | ||
|
||
async fn sync_expiration(&mut self) -> Result<()> { | ||
self.storage | ||
.set_expiration(self.client_id, self.client_bandwidth.bandwidth.expiration) | ||
.await?; | ||
Ok(()) | ||
} | ||
|
||
pub async fn handle_claim_testnet_bandwidth(&mut self) -> Result<ServerResponse> { | ||
debug!("handling testnet bandwidth request"); | ||
|
||
if self.only_coconut_credentials { | ||
return Err(Error::OnlyCoconutCredentials); | ||
} | ||
|
||
self.increase_bandwidth(FREE_TESTNET_BANDWIDTH_VALUE, ecash_today()) | ||
.await?; | ||
let available_total = self.client_bandwidth.bandwidth.bytes; | ||
|
||
Ok(ServerResponse::Bandwidth { available_total }) | ||
} | ||
|
||
#[instrument(skip_all)] | ||
pub async fn try_use_bandwidth(&mut self, required_bandwidth: i64) -> Result<i64> { | ||
if self.client_bandwidth.bandwidth.expired() { | ||
self.expire_bandwidth().await?; | ||
} | ||
let available_bandwidth = self.client_bandwidth.bandwidth.bytes; | ||
|
||
if available_bandwidth < required_bandwidth { | ||
return Err(Error::OutOfBandwidth { | ||
required: required_bandwidth, | ||
available: available_bandwidth, | ||
}); | ||
} | ||
|
||
let available_bi2 = bibytes2(available_bandwidth as f64); | ||
let required_bi2 = bibytes2(required_bandwidth as f64); | ||
debug!(available = available_bi2, required = required_bi2); | ||
|
||
self.consume_bandwidth(required_bandwidth).await?; | ||
Ok(available_bandwidth) | ||
} | ||
|
||
async fn expire_bandwidth(&mut self) -> Result<()> { | ||
self.storage.reset_bandwidth(self.client_id).await?; | ||
self.client_bandwidth.bandwidth = Default::default(); | ||
self.client_bandwidth.update_sync_data(); | ||
Ok(()) | ||
} | ||
|
||
/// Decreases the amount of available bandwidth of the connected client by the specified value. | ||
/// | ||
/// # Arguments | ||
/// | ||
/// * `amount`: amount to decrease the available bandwidth by. | ||
async fn consume_bandwidth(&mut self, amount: i64) -> Result<()> { | ||
self.client_bandwidth.bandwidth.bytes -= amount; | ||
self.client_bandwidth.bytes_delta_since_sync -= amount; | ||
|
||
// since we're going to be operating on a fair use policy anyway, even if we crash and let extra few packets | ||
// through, that's completely fine | ||
if self.client_bandwidth.should_sync(self.bandwidth_cfg) { | ||
self.sync_bandwidth().await?; | ||
} | ||
|
||
Ok(()) | ||
} | ||
|
||
#[instrument(level = "trace", skip_all)] | ||
async fn sync_bandwidth(&mut self) -> Result<()> { | ||
trace!("syncing client bandwidth with the underlying storage"); | ||
let updated = self | ||
.storage | ||
.increase_bandwidth(self.client_id, self.client_bandwidth.bytes_delta_since_sync) | ||
.await?; | ||
|
||
trace!(updated); | ||
|
||
self.client_bandwidth.bandwidth.bytes = updated; | ||
|
||
self.client_bandwidth.update_sync_data(); | ||
Ok(()) | ||
} | ||
|
||
/// Increases the amount of available bandwidth of the connected client by the specified value. | ||
/// | ||
/// # Arguments | ||
/// | ||
/// * `amount`: amount to increase the available bandwidth by. | ||
/// * `expiration` : the expiration date of that bandwidth | ||
pub async fn increase_bandwidth( | ||
&mut self, | ||
bandwidth: Bandwidth, | ||
expiration: OffsetDateTime, | ||
) -> Result<()> { | ||
self.client_bandwidth.bandwidth.bytes += bandwidth.value() as i64; | ||
self.client_bandwidth.bytes_delta_since_sync += bandwidth.value() as i64; | ||
self.client_bandwidth.bandwidth.expiration = expiration; | ||
|
||
// any increases to bandwidth should get flushed immediately | ||
// (we don't want to accidentally miss somebody claiming a gigabyte voucher) | ||
self.sync_expiration().await?; | ||
self.sync_bandwidth().await | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net> | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
use std::time::Duration; | ||
|
||
use nym_credentials_interface::AvailableBandwidth; | ||
use time::OffsetDateTime; | ||
|
||
#[derive(Debug, Clone, Copy)] | ||
pub struct BandwidthFlushingBehaviourConfig { | ||
/// Defines maximum delay between client bandwidth information being flushed to the persistent storage. | ||
pub client_bandwidth_max_flushing_rate: Duration, | ||
|
||
/// Defines a maximum change in client bandwidth before it gets flushed to the persistent storage. | ||
pub client_bandwidth_max_delta_flushing_amount: i64, | ||
} | ||
|
||
#[derive(Debug, Clone, Copy)] | ||
pub struct ClientBandwidth { | ||
pub(crate) bandwidth: AvailableBandwidth, | ||
pub(crate) last_flushed: OffsetDateTime, | ||
|
||
/// the number of bytes the client had during the last sync. | ||
/// it is used to determine whether the current value should be synced with the storage | ||
/// by checking the delta with the known amount | ||
pub(crate) bytes_at_last_sync: i64, | ||
pub(crate) bytes_delta_since_sync: i64, | ||
} | ||
|
||
impl ClientBandwidth { | ||
pub fn new(bandwidth: AvailableBandwidth) -> ClientBandwidth { | ||
ClientBandwidth { | ||
bandwidth, | ||
last_flushed: OffsetDateTime::now_utc(), | ||
bytes_at_last_sync: bandwidth.bytes, | ||
bytes_delta_since_sync: 0, | ||
} | ||
} | ||
|
||
pub(crate) fn should_sync(&self, cfg: BandwidthFlushingBehaviourConfig) -> bool { | ||
if self.bytes_delta_since_sync.abs() >= cfg.client_bandwidth_max_delta_flushing_amount { | ||
return true; | ||
} | ||
|
||
if self.last_flushed + cfg.client_bandwidth_max_flushing_rate < OffsetDateTime::now_utc() { | ||
return true; | ||
} | ||
|
||
false | ||
} | ||
|
||
pub(crate) fn update_sync_data(&mut self) { | ||
self.last_flushed = OffsetDateTime::now_utc(); | ||
self.bytes_at_last_sync = self.bandwidth.bytes; | ||
self.bytes_delta_since_sync = 0; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.