Procházet zdrojové kódy

fix: load keyset keys from database to prevent duplicate insertions (#1291)

The wallet was failing on the second mint with "UNIQUE constraint failed: key.keyset_u32" because the MintMetadataCache never loaded keys from the database on startup.
Every new process would re-fetch keys from the mint's HTTP API and try to insert them again, causing aconstraint violation.
Fixed by loading existing keys from the database into the cache before fetching from HTTP (in both load_from_mint and load_auth).
Checking if keys already exist before trying to insert them in persist_to_database. This eliminates the duplicate
insertion errors and also saves bandwidth by not re-fetching keys we already have.
tsk před 2 dny
rodič
revize
3df35b4a38
1 změnil soubory, kde provedl 40 přidání a 0 odebrání
  1. 40 0
      crates/cdk/src/wallet/mint_metadata_cache.rs

+ 40 - 0
crates/cdk/src/wallet/mint_metadata_cache.rs

@@ -243,6 +243,20 @@ impl MintMetadataCache {
             return Ok(current_metadata);
         }
 
+        // Load keys from database before fetching from HTTP
+        // This prevents re-fetching keys we already have and avoids duplicate insertions
+        if let Some(keysets) = storage.get_mint_keysets(self.mint_url.clone()).await? {
+            let mut updated_metadata = (*self.metadata.load().clone()).clone();
+            for keyset_info in keysets {
+                if let Some(keys) = storage.get_keys(&keyset_info.id).await? {
+                    tracing::trace!("Loaded keys for keyset {} from database", keyset_info.id);
+                    updated_metadata.keys.insert(keyset_info.id, Arc::new(keys));
+                }
+            }
+            // Update cache with database keys before HTTP fetch
+            self.metadata.store(Arc::new(updated_metadata));
+        }
+
         // Perform the fetch
         #[cfg(feature = "auth")]
         let metadata = self.fetch_from_http(Some(client), None).await?;
@@ -371,6 +385,23 @@ impl MintMetadataCache {
             return Ok(current_metadata);
         }
 
+        // Load keys from database before fetching from HTTP
+        // This prevents re-fetching keys we already have and avoids duplicate insertions
+        if let Some(keysets) = storage.get_mint_keysets(self.mint_url.clone()).await? {
+            let mut updated_metadata = (*self.metadata.load().clone()).clone();
+            for keyset_info in keysets {
+                if let Some(keys) = storage.get_keys(&keyset_info.id).await? {
+                    tracing::trace!(
+                        "Loaded keys for keyset {} from database (auth)",
+                        keyset_info.id
+                    );
+                    updated_metadata.keys.insert(keyset_info.id, Arc::new(keys));
+                }
+            }
+            // Update cache with database keys before HTTP fetch
+            self.metadata.store(Arc::new(updated_metadata));
+        }
+
         // Auth data not in cache - fetch from mint
         let metadata = self.fetch_from_http(None, Some(auth_client)).await?;
 
@@ -455,6 +486,15 @@ impl MintMetadataCache {
         // Save keys for each keyset
         for (keyset_id, keys) in &metadata.keys {
             if let Some(keyset_info) = metadata.keysets.get(keyset_id) {
+                // Check if keys already exist in database to avoid duplicate insertion
+                if storage.get_keys(keyset_id).await.ok().flatten().is_some() {
+                    tracing::trace!(
+                        "Keys for keyset {} already in database, skipping insert",
+                        keyset_id
+                    );
+                    continue;
+                }
+
                 let keyset = KeySet {
                     id: *keyset_id,
                     unit: keyset_info.unit.clone(),