Browse Source

Metadata follow up (#1268)

* feat: cache_ttl as RwLock instead of Mutex

This is a read heavy workflow that is not held across await points.
So we can use a RwLock instead of Mutex.

* refactor: remove TTL check from load_from_mint for guaranteed fresh fetches

Remove TTL parameter and check from load_from_mint() to ensure it always
fetches fresh metadata from the mint as documented. The method now truly
forces a refresh, while load() continues to handle TTL-based caching.
tsk 6 days ago
parent
commit
2f9100ea4f

+ 4 - 4
crates/cdk/src/wallet/builder.rs

@@ -3,11 +3,11 @@ use std::sync::Arc;
 use std::time::Duration;
 
 use cdk_common::database;
-use cdk_common::parking_lot::Mutex;
+use cdk_common::parking_lot::RwLock;
 #[cfg(feature = "auth")]
 use cdk_common::AuthToken;
 #[cfg(feature = "auth")]
-use tokio::sync::RwLock;
+use tokio::sync::RwLock as TokioRwLock;
 
 use crate::cdk_database::WalletDatabase;
 use crate::error::Error;
@@ -228,10 +228,10 @@ impl WalletBuilder {
             unit,
             localstore,
             metadata_cache,
-            metadata_cache_ttl: Arc::new(Mutex::new(metadata_cache_ttl)),
+            metadata_cache_ttl: Arc::new(RwLock::new(metadata_cache_ttl)),
             target_proof_count: self.target_proof_count.unwrap_or(3),
             #[cfg(feature = "auth")]
-            auth_wallet: Arc::new(RwLock::new(self.auth_wallet)),
+            auth_wallet: Arc::new(TokioRwLock::new(self.auth_wallet)),
             seed,
             client: client.clone(),
             subscription: SubscriptionManager::new(client, self.use_http_subscription),

+ 5 - 8
crates/cdk/src/wallet/keysets.rs

@@ -16,7 +16,7 @@ impl Wallet {
     pub async fn load_keyset_keys(&self, keyset_id: Id) -> Result<Keys, Error> {
         self.metadata_cache
             .load(&self.localstore, &self.client, {
-                let ttl = self.metadata_cache_ttl.lock();
+                let ttl = self.metadata_cache_ttl.read();
                 *ttl
             })
             .await?
@@ -42,7 +42,7 @@ impl Wallet {
         let keysets = self
             .metadata_cache
             .load(&self.localstore, &self.client, {
-                let ttl = self.metadata_cache_ttl.lock();
+                let ttl = self.metadata_cache_ttl.read();
                 *ttl
             })
             .await?
@@ -75,10 +75,7 @@ impl Wallet {
 
         let keysets = self
             .metadata_cache
-            .load_from_mint(&self.localstore, &self.client, {
-                let ttl = self.metadata_cache_ttl.lock();
-                *ttl
-            })
+            .load_from_mint(&self.localstore, &self.client)
             .await?
             .keysets
             .iter()
@@ -121,7 +118,7 @@ impl Wallet {
     pub async fn get_active_keyset(&self) -> Result<KeySetInfo, Error> {
         self.metadata_cache
             .load(&self.localstore, &self.client, {
-                let ttl = self.metadata_cache_ttl.lock();
+                let ttl = self.metadata_cache_ttl.read();
                 *ttl
             })
             .await?
@@ -140,7 +137,7 @@ impl Wallet {
         let metadata = self
             .metadata_cache
             .load(&self.localstore, &self.client, {
-                let ttl = self.metadata_cache_ttl.lock();
+                let ttl = self.metadata_cache_ttl.read();
                 *ttl
             })
             .await?;

+ 3 - 9
crates/cdk/src/wallet/mint_metadata_cache.rs

@@ -144,7 +144,7 @@ impl std::fmt::Debug for MintMetadataCache {
 impl Wallet {
     /// Sets the metadata cache TTL
     pub fn set_metadata_cache_ttl(&self, ttl: Option<Duration>) {
-        let mut guarded_ttl = self.metadata_cache_ttl.lock();
+        let mut guarded_ttl = self.metadata_cache_ttl.write();
         *guarded_ttl = ttl;
     }
 
@@ -211,7 +211,6 @@ impl MintMetadataCache {
     ///
     /// * `storage` - Database to persist metadata to (async background write)
     /// * `client` - HTTP client for fetching from mint server
-    /// * `ttl` - Optional TTL, if not provided it is assumed that any cached data is good enough
     ///
     /// # Returns
     ///
@@ -228,7 +227,6 @@ impl MintMetadataCache {
         &self,
         storage: &Arc<dyn WalletDatabase<Err = database::Error> + Send + Sync>,
         client: &Arc<dyn MintConnector + Send + Sync>,
-        ttl: Option<Duration>,
     ) -> Result<Arc<MintMetadata>, Error> {
         // Acquire lock to ensure only one fetch at a time
         let current_version = self.metadata.load().status.version;
@@ -236,11 +234,7 @@ impl MintMetadataCache {
 
         // Check if another caller already updated the cache while we waited
         let current_metadata = self.metadata.load().clone();
-        if current_metadata.status.is_populated
-            && ttl
-                .map(|ttl| current_metadata.status.updated_at + ttl > Instant::now())
-                .unwrap_or(true)
-            && current_metadata.status.version > current_version
+        if current_metadata.status.is_populated && current_metadata.status.version > current_version
         {
             // Cache was just updated by another caller - return it
             tracing::debug!(
@@ -320,7 +314,7 @@ impl MintMetadataCache {
         }
 
         // Cache not populated - fetch from mint
-        self.load_from_mint(storage, client, ttl).await
+        self.load_from_mint(storage, client).await
     }
 
     /// Load auth keysets and keys (auth feature only)

+ 6 - 6
crates/cdk/src/wallet/mod.rs

@@ -9,12 +9,12 @@ use std::time::Duration;
 
 use cdk_common::amount::FeeAndAmounts;
 use cdk_common::database::{self, WalletDatabase};
-use cdk_common::parking_lot::Mutex;
+use cdk_common::parking_lot::RwLock;
 use cdk_common::subscription::WalletParams;
 use getrandom::getrandom;
 use subscription::{ActiveSubscription, SubscriptionManager};
 #[cfg(feature = "auth")]
-use tokio::sync::RwLock;
+use tokio::sync::RwLock as TokioRwLock;
 use tracing::instrument;
 use zeroize::Zeroize;
 
@@ -95,9 +95,9 @@ pub struct Wallet {
     pub metadata_cache: Arc<MintMetadataCache>,
     /// The targeted amount of proofs to have at each size
     pub target_proof_count: usize,
-    metadata_cache_ttl: Arc<Mutex<Option<Duration>>>,
+    metadata_cache_ttl: Arc<RwLock<Option<Duration>>>,
     #[cfg(feature = "auth")]
-    auth_wallet: Arc<RwLock<Option<AuthWallet>>>,
+    auth_wallet: Arc<TokioRwLock<Option<AuthWallet>>>,
     seed: [u8; 64],
     client: Arc<dyn MintConnector + Send + Sync>,
     subscription: SubscriptionManager,
@@ -228,7 +228,7 @@ impl Wallet {
         let metadata = self
             .metadata_cache
             .load(&self.localstore, &self.client, {
-                let ttl = self.metadata_cache_ttl.lock();
+                let ttl = self.metadata_cache_ttl.read();
                 *ttl
             })
             .await?;
@@ -252,7 +252,7 @@ impl Wallet {
         let input_fee_ppk = self
             .metadata_cache
             .load(&self.localstore, &self.client, {
-                let ttl = self.metadata_cache_ttl.lock();
+                let ttl = self.metadata_cache_ttl.read();
                 *ttl
             })
             .await?

+ 1 - 1
crates/cdk/src/wallet/swap.rs

@@ -50,7 +50,7 @@ impl Wallet {
         let active_keys = self
             .metadata_cache
             .load(&self.localstore, &self.client, {
-                let ttl = self.metadata_cache_ttl.lock();
+                let ttl = self.metadata_cache_ttl.read();
                 *ttl
             })
             .await?