nym-api exporting bloomfilter in separate task

This commit is contained in:
Jędrzej Stuczyński
2024-07-30 11:09:23 +01:00
parent 3cb69780a6
commit 4989d47ea2
3 changed files with 58 additions and 19 deletions
+1 -1
View File
@@ -195,7 +195,7 @@ pub async fn batch_redeem_tickets(
pub async fn double_spending_filter_v1(
state: &RocketState<EcashState>,
) -> crate::ecash::error::Result<Json<SpentCredentialsResponse>> {
let spent_credentials_export = state.export_bloomfilter().await;
let spent_credentials_export = state.get_bloomfilter_bytes().await;
Ok(Json(SpentCredentialsResponse::new(
spent_credentials_export,
)))
+49 -1
View File
@@ -9,8 +9,9 @@ use crate::ecash::keys::KeyPair;
use nym_config::defaults::BloomfilterParameters;
use nym_crypto::asymmetric::identity;
use nym_ecash_double_spending::DoubleSpendingFilter;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;
use time::Date;
use time::{Date, OffsetDateTime};
use tokio::sync::RwLock;
pub(crate) struct TicketDoubleSpendingFilter {
@@ -80,6 +81,17 @@ impl TicketDoubleSpendingFilter {
}
}
pub(crate) struct ExportedDoubleSpendingFilterData {
pub(crate) last_exported_at: OffsetDateTime,
pub(crate) bytes: Vec<u8>,
}
#[derive(Clone)]
pub(crate) struct ExportedDoubleSpendingFilter {
pub(crate) being_exported: Arc<AtomicBool>,
pub(crate) data: Arc<RwLock<ExportedDoubleSpendingFilterData>>,
}
pub(crate) struct LocalEcashState {
pub(crate) ecash_keypair: KeyPair,
pub(crate) identity_keypair: identity::KeyPair,
@@ -87,7 +99,12 @@ pub(crate) struct LocalEcashState {
pub(crate) partial_coin_index_signatures: CachedImmutableEpochItem<IssuedCoinIndicesSignatures>,
pub(crate) partial_expiration_date_signatures:
CachedImmutableItems<Date, IssuedExpirationDateSignatures>,
// the actual, up to date, bloomfilter
pub(crate) double_spending_filter: Arc<RwLock<TicketDoubleSpendingFilter>>,
// the cached byte representation of the bloomfilter to be used by the clients
pub(crate) exported_double_spending_filter: ExportedDoubleSpendingFilter,
}
impl LocalEcashState {
@@ -101,7 +118,38 @@ impl LocalEcashState {
identity_keypair,
partial_coin_index_signatures: Default::default(),
partial_expiration_date_signatures: Default::default(),
exported_double_spending_filter: ExportedDoubleSpendingFilter {
being_exported: Arc::new(Default::default()),
data: Arc::new(RwLock::new(ExportedDoubleSpendingFilterData {
last_exported_at: OffsetDateTime::now_utc(),
bytes: double_spending_filter.export_global_bitmap(),
})),
},
double_spending_filter: Arc::new(RwLock::new(double_spending_filter)),
}
}
pub(crate) fn maybe_background_update_exported_bloomfilter(&self) {
// make sure another query hasn't already spawned an exporting task
let Ok(should_export) = self
.exported_double_spending_filter
.being_exported
.compare_exchange(false, true, Ordering::SeqCst, Ordering::SeqCst)
else {
return;
};
let filter = self.double_spending_filter.clone();
let exported = self.exported_double_spending_filter.clone();
if should_export {
tokio::spawn(async move {
log::debug!("exporting bloomfilter bitmap");
let new = filter.read().await.export_global_bitmap();
let mut exported_guard = exported.data.write().await;
exported_guard.last_exported_at = OffsetDateTime::now_utc();
exported_guard.bytes = new;
});
}
}
}
+8 -17
View File
@@ -45,7 +45,7 @@ use nym_ecash_time::cred_exp_date;
use nym_validator_client::nyxd::AccountId;
use nym_validator_client::EcashApiClient;
use time::ext::NumericalDuration;
use time::{Date, OffsetDateTime};
use time::{Date, Duration, OffsetDateTime};
use tokio::sync::RwLockReadGuard;
use tokio::time::Instant;
@@ -841,23 +841,14 @@ impl EcashState {
res
}
pub async fn export_bloomfilter(&self) -> Vec<u8> {
let export_start = Instant::now();
let bytes = self
.local
.double_spending_filter
.read()
.await
.export_global_bitmap();
pub async fn get_bloomfilter_bytes(&self) -> Vec<u8> {
let guard = self.local.exported_double_spending_filter.data.read().await;
let taken = export_start.elapsed();
match taken.as_millis() {
// at that point it should somehow be cached; especially **IF** we have more reads than writes
ms if ms > 100 => error!("exporting the bloomfilter took {ms}ms to complete"),
ms if ms > 50 => warn!("exporting the bloomfilter took {ms}ms to complete"),
ms if ms > 10 => info!("exporting the bloomfilter took {ms}ms to complete"),
ms if ms > 2 => debug!("exporting the bloomfilter took {ms}ms to complete"),
ms => trace!("exporting the bloomfilter took {ms}ms to complete"),
let bytes = guard.bytes.clone();
// see if it's been > 5min since last export (that value is arbitrary)
if guard.last_exported_at + Duration::minutes(5) < OffsetDateTime::now_utc() {
self.local.maybe_background_update_exported_bloomfilter();
}
bytes