瀏覽代碼

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 2 天之前
父節點
當前提交
3df35b4a38
共有 1 個文件被更改,包括 40 次插入0 次删除
  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(),