Quellcode durchsuchen

refactor: store keyset by id

thesimplekid vor 10 Monaten
Ursprung
Commit
efd9b39722

+ 48 - 8
crates/cdk-redb/src/wallet.rs

@@ -17,12 +17,15 @@ use tracing::instrument;
 use super::error::Error;
 
 const MINTS_TABLE: TableDefinition<&str, &str> = TableDefinition::new("mints_table");
-const MINT_KEYSETS_TABLE: MultimapTableDefinition<&str, &str> =
+// <Mint_Url, Keyset_id>
+const MINT_KEYSETS_TABLE: MultimapTableDefinition<&str, &[u8]> =
     MultimapTableDefinition::new("mint_keysets");
+// <Keyset_id, KeysetInfo>
+const KEYSETS_TABLE: TableDefinition<&[u8], &str> = TableDefinition::new("keysets");
 const MINT_QUOTES_TABLE: TableDefinition<&str, &str> = TableDefinition::new("mint_quotes");
 const MELT_QUOTES_TABLE: TableDefinition<&str, &str> = TableDefinition::new("melt_quotes");
 const MINT_KEYS_TABLE: TableDefinition<&str, &str> = TableDefinition::new("mint_keys");
-// <Y, (Proof, Status, Mint url)>
+// <Y, Proof Info>
 const PROOFS_TABLE: TableDefinition<&[u8], &str> = TableDefinition::new("proofs");
 const CONFIG_TABLE: TableDefinition<&str, &str> = TableDefinition::new("config");
 const KEYSET_COUNTER: TableDefinition<&str, u32> = TableDefinition::new("keyset_counter");
@@ -62,6 +65,7 @@ impl RedbWalletDatabase {
                     // Open all tables to init a new db
                     let _ = write_txn.open_table(MINTS_TABLE)?;
                     let _ = write_txn.open_multimap_table(MINT_KEYSETS_TABLE)?;
+                    let _ = write_txn.open_table(KEYSETS_TABLE)?;
                     let _ = write_txn.open_table(MINT_QUOTES_TABLE)?;
                     let _ = write_txn.open_table(MELT_QUOTES_TABLE)?;
                     let _ = write_txn.open_table(MINT_KEYS_TABLE)?;
@@ -166,9 +170,7 @@ impl WalletDatabase for RedbWalletDatabase {
                 table
                     .insert(
                         mint_url.to_string().as_str(),
-                        serde_json::to_string(&keyset)
-                            .map_err(Error::from)?
-                            .as_str(),
+                        keyset.id.to_bytes().as_slice(),
                     )
                     .map_err(Error::from)?;
             }
@@ -189,14 +191,52 @@ impl WalletDatabase for RedbWalletDatabase {
             .open_multimap_table(MINT_KEYSETS_TABLE)
             .map_err(Error::from)?;
 
-        let keysets = table
+        let keyset_ids: Vec<Id> = table
             .get(mint_url.to_string().as_str())
             .map_err(Error::from)?
             .flatten()
-            .flat_map(|k| serde_json::from_str(k.value()))
+            .flat_map(|k| Id::from_bytes(k.value()))
             .collect();
 
-        Ok(keysets)
+        let mut keysets = vec![];
+
+        let keysets_t = read_txn.open_table(KEYSETS_TABLE).map_err(Error::from)?;
+
+        for keyset_id in keyset_ids {
+            if let Some(keyset) = keysets_t
+                .get(keyset_id.to_bytes().as_slice())
+                .map_err(Error::from)?
+            {
+                let keyset = serde_json::from_str(keyset.value()).map_err(Error::from)?;
+
+                keysets.push(keyset);
+            }
+        }
+
+        match keysets.is_empty() {
+            true => Ok(None),
+            false => Ok(Some(keysets)),
+        }
+    }
+
+    #[instrument(skip(self))]
+    async fn get_keyset_by_id(&self, keyset_id: &Id) -> Result<Option<KeySetInfo>, Self::Err> {
+        let db = self.db.lock().await;
+        let read_txn = db.begin_read().map_err(Into::<Error>::into)?;
+        let table = read_txn.open_table(KEYSETS_TABLE).map_err(Error::from)?;
+
+        match table
+            .get(keyset_id.to_bytes().as_slice())
+            .map_err(Error::from)?
+        {
+            Some(keyset) => {
+                let keyset: KeySetInfo =
+                    serde_json::from_str(keyset.value()).map_err(Error::from)?;
+
+                Ok(Some(keyset))
+            }
+            None => Ok(None),
+        }
     }
 
     #[instrument(skip_all)]

+ 87 - 16
crates/cdk-rexie/src/wallet.rs

@@ -1,4 +1,4 @@
-use std::collections::HashMap;
+use std::collections::{HashMap, HashSet};
 use std::rc::Rc;
 use std::result::Result;
 
@@ -15,7 +15,8 @@ use tokio::sync::Mutex;
 
 // Tables
 const MINTS: &str = "mints";
-const MINT_KEYSETS: &str = "mint_keysets";
+const MINT_KEYSETS: &str = "keysets_by_mint";
+const KEYSETS: &str = "keysets";
 const MINT_KEYS: &str = "mint_keys";
 const MINT_QUOTES: &str = "mint_quotes";
 const MELT_QUOTES: &str = "melt_quotes";
@@ -23,7 +24,7 @@ const PROOFS: &str = "proofs";
 const CONFIG: &str = "config";
 const KEYSET_COUNTER: &str = "keyset_counter";
 
-const DATABASE_VERSION: u32 = 1;
+const DATABASE_VERSION: u32 = 2;
 
 #[derive(Debug, Error)]
 pub enum Error {
@@ -61,15 +62,20 @@ unsafe impl Sync for RexieWalletDatabase {}
 impl RexieWalletDatabase {
     pub async fn new() -> Result<Self, Error> {
         let rexie = Rexie::builder("cdk")
-            // Set the version of the database to 1.0
             .version(DATABASE_VERSION)
-            // Add an object store named `employees`
-            .add_object_store(ObjectStore::new(PROOFS).add_index(Index::new("y", "y").unique(true)))
+            .add_object_store(
+                ObjectStore::new(PROOFS)
+                    .add_index(Index::new("y", "y").unique(true))
+                    .add_index(Index::new("mint_url", "mint_url"))
+                    .add_index(Index::new("state", "state"))
+                    .add_index(Index::new("unit", "unit")),
+            )
             .add_object_store(
                 ObjectStore::new(MINTS).add_index(Index::new("mint_url", "mint_url").unique(true)),
             )
+            .add_object_store(ObjectStore::new(MINT_KEYSETS))
             .add_object_store(
-                ObjectStore::new(MINT_KEYSETS)
+                ObjectStore::new(KEYSETS)
                     .add_index(Index::new("keyset_id", "keyset_id").unique(true)),
             )
             .add_object_store(
@@ -175,19 +181,46 @@ impl WalletDatabase for RexieWalletDatabase {
         let rexie = self.db.lock().await;
 
         let transaction = rexie
-            .transaction(&[MINT_KEYSETS], TransactionMode::ReadWrite)
+            .transaction(&[MINT_KEYSETS, KEYSETS], TransactionMode::ReadWrite)
             .map_err(Error::from)?;
 
-        let keysets_store = transaction.store(MINT_KEYSETS).map_err(Error::from)?;
+        let mint_keysets_store = transaction.store(MINT_KEYSETS).map_err(Error::from)?;
+        let keysets_store = transaction.store(KEYSETS).map_err(Error::from)?;
 
         let mint_url = serde_wasm_bindgen::to_value(&mint_url).map_err(Error::from)?;
-        let keysets = serde_wasm_bindgen::to_value(&keysets).map_err(Error::from)?;
 
-        keysets_store
-            .put(&keysets, Some(&mint_url))
+        let mint_keysets = mint_keysets_store
+            .get(&mint_url)
+            .await
+            .map_err(Error::from)?;
+
+        let mut mint_keysets: Option<HashSet<Id>> =
+            serde_wasm_bindgen::from_value(mint_keysets).map_err(Error::from)?;
+
+        let new_keyset_ids: Vec<Id> = keysets.iter().map(|k| k.id).collect();
+
+        mint_keysets
+            .as_mut()
+            .unwrap_or(&mut HashSet::new())
+            .extend(new_keyset_ids);
+
+        let mint_keysets = serde_wasm_bindgen::to_value(&mint_keysets).map_err(Error::from)?;
+
+        mint_keysets_store
+            .put(&mint_keysets, Some(&mint_url))
             .await
             .map_err(Error::from)?;
 
+        for keyset in keysets {
+            let id = serde_wasm_bindgen::to_value(&keyset.id).map_err(Error::from)?;
+            let keyset = serde_wasm_bindgen::to_value(&keyset).map_err(Error::from)?;
+
+            keysets_store
+                .put(&keyset, Some(&id))
+                .await
+                .map_err(Error::from)?;
+        }
+
         transaction.done().await.map_err(Error::from)?;
 
         Ok(())
@@ -200,20 +233,58 @@ impl WalletDatabase for RexieWalletDatabase {
         let rexie = self.db.lock().await;
 
         let transaction = rexie
-            .transaction(&[MINT_KEYSETS], TransactionMode::ReadOnly)
+            .transaction(&[MINT_KEYSETS, KEYSETS], TransactionMode::ReadOnly)
             .map_err(Error::from)?;
 
         let mints_store = transaction.store(MINT_KEYSETS).map_err(Error::from)?;
 
         let mint_url = serde_wasm_bindgen::to_value(&mint_url).map_err(Error::from)?;
-        let keysets = mints_store.get(&mint_url).await.map_err(Error::from)?;
+        let mint_keysets = mints_store.get(&mint_url).await.map_err(Error::from)?;
 
-        let keysets: Option<Vec<KeySetInfo>> =
-            serde_wasm_bindgen::from_value(keysets).map_err(Error::from)?;
+        let mint_keysets: Option<HashSet<Id>> =
+            serde_wasm_bindgen::from_value(mint_keysets).map_err(Error::from)?;
+
+        let keysets_store = transaction.store(KEYSETS).map_err(Error::from)?;
+
+        let keysets = match mint_keysets {
+            Some(mint_keysets) => {
+                let mut keysets = vec![];
+
+                for mint_keyset in mint_keysets {
+                    let id = serde_wasm_bindgen::to_value(&mint_keyset).map_err(Error::from)?;
+
+                    let keyset = keysets_store.get(&id).await.map_err(Error::from)?;
+
+                    let keyset = serde_wasm_bindgen::from_value(keyset).map_err(Error::from)?;
+
+                    keysets.push(keyset);
+                }
+
+                Some(keysets)
+            }
+            None => None,
+        };
+
+        transaction.done().await.map_err(Error::from)?;
 
         Ok(keysets)
     }
 
+    async fn get_keyset_by_id(&self, keyset_id: &Id) -> Result<Option<KeySetInfo>, Self::Err> {
+        let rexie = self.db.lock().await;
+
+        let transaction = rexie
+            .transaction(&[KEYSETS], TransactionMode::ReadOnly)
+            .map_err(Error::from)?;
+        let keysets_store = transaction.store(KEYSETS).map_err(Error::from)?;
+
+        let keyset_id = serde_wasm_bindgen::to_value(keyset_id).map_err(Error::from)?;
+
+        let keyset = keysets_store.get(&keyset_id).await.map_err(Error::from)?;
+
+        Ok(serde_wasm_bindgen::from_value(keyset).map_err(Error::from)?)
+    }
+
     async fn add_mint_quote(&self, quote: MintQuote) -> Result<(), Self::Err> {
         let rexie = self.db.lock().await;
 

+ 2 - 0
crates/cdk/src/cdk_database/mod.rs

@@ -64,6 +64,8 @@ pub trait WalletDatabase {
         &self,
         mint_url: UncheckedUrl,
     ) -> Result<Option<Vec<KeySetInfo>>, Self::Err>;
+    async fn get_keyset_by_id(&self, keyset_id: &Id) -> Result<Option<KeySetInfo>, Self::Err>;
+
     async fn add_mint_quote(&self, quote: MintQuote) -> Result<(), Self::Err>;
     async fn get_mint_quote(&self, quote_id: &str) -> Result<Option<MintQuote>, Self::Err>;
     async fn get_mint_quotes(&self) -> Result<Vec<MintQuote>, Self::Err>;

+ 36 - 11
crates/cdk/src/cdk_database/wallet_memory.rs

@@ -18,7 +18,8 @@ use crate::url::UncheckedUrl;
 #[derive(Default, Debug, Clone)]
 pub struct WalletMemoryDatabase {
     mints: Arc<RwLock<HashMap<UncheckedUrl, Option<MintInfo>>>>,
-    mint_keysets: Arc<RwLock<HashMap<UncheckedUrl, HashSet<KeySetInfo>>>>,
+    mint_keysets: Arc<RwLock<HashMap<UncheckedUrl, HashSet<Id>>>>,
+    keysets: Arc<RwLock<HashMap<Id, KeySetInfo>>>,
     mint_quotes: Arc<RwLock<HashMap<String, MintQuote>>>,
     melt_quotes: Arc<RwLock<HashMap<String, MeltQuote>>>,
     mint_keys: Arc<RwLock<HashMap<Id, Keys>>>,
@@ -39,6 +40,7 @@ impl WalletMemoryDatabase {
         Self {
             mints: Arc::new(RwLock::new(HashMap::new())),
             mint_keysets: Arc::new(RwLock::new(HashMap::new())),
+            keysets: Arc::new(RwLock::new(HashMap::new())),
             mint_quotes: Arc::new(RwLock::new(
                 mint_quotes.into_iter().map(|q| (q.id.clone(), q)).collect(),
             )),
@@ -83,10 +85,19 @@ impl WalletDatabase for WalletMemoryDatabase {
         mint_url: UncheckedUrl,
         keysets: Vec<KeySetInfo>,
     ) -> Result<(), Error> {
-        let mut current_keysets = self.mint_keysets.write().await;
-
-        let mint_keysets = current_keysets.entry(mint_url).or_insert(HashSet::new());
-        mint_keysets.extend(keysets);
+        let mut current_mint_keysets = self.mint_keysets.write().await;
+        let mut current_keysets = self.keysets.write().await;
+
+        for keyset in keysets {
+            current_mint_keysets
+                .entry(mint_url.clone())
+                .and_modify(|ks| {
+                    ks.insert(keyset.id);
+                })
+                .or_insert(HashSet::from_iter(vec![keyset.id]));
+
+            current_keysets.insert(keyset.id, keyset);
+        }
 
         Ok(())
     }
@@ -95,12 +106,26 @@ impl WalletDatabase for WalletMemoryDatabase {
         &self,
         mint_url: UncheckedUrl,
     ) -> Result<Option<Vec<KeySetInfo>>, Error> {
-        Ok(self
-            .mint_keysets
-            .read()
-            .await
-            .get(&mint_url)
-            .map(|ks| ks.iter().cloned().collect()))
+        match self.mint_keysets.read().await.get(&mint_url) {
+            Some(keyset_ids) => {
+                let mut keysets = vec![];
+
+                let db_keysets = self.keysets.read().await;
+
+                for id in keyset_ids {
+                    if let Some(keyset) = db_keysets.get(id) {
+                        keysets.push(keyset.clone());
+                    }
+                }
+
+                Ok(Some(keysets))
+            }
+            None => Ok(None),
+        }
+    }
+
+    async fn get_keyset_by_id(&self, keyset_id: &Id) -> Result<Option<KeySetInfo>, Error> {
+        Ok(self.keysets.read().await.get(keyset_id).cloned())
     }
 
     async fn add_mint_quote(&self, quote: MintQuote) -> Result<(), Error> {

+ 8 - 10
crates/cdk/src/wallet/mod.rs

@@ -694,14 +694,13 @@ impl Wallet {
             .post_swap(mint_url.clone().try_into()?, pre_swap.swap_request)
             .await?;
 
+        let active_keys = self.active_keys(mint_url, unit).await?.unwrap();
+
         let mut post_swap_proofs = construct_proofs(
             swap_response.signatures,
             pre_swap.pre_mint_secrets.rs(),
             pre_swap.pre_mint_secrets.secrets(),
-            &self
-                .active_keys(mint_url, unit)
-                .await?
-                .ok_or(Error::UnknownKey)?,
+            &active_keys,
         )?;
 
         let active_keyset_id = self.active_mint_keyset(mint_url, unit).await?;
@@ -793,7 +792,7 @@ impl Wallet {
         proofs: Proofs,
         spending_conditions: Option<SpendingConditions>,
     ) -> Result<PreSwap, Error> {
-        let active_keyset_id = self.active_mint_keyset(mint_url, unit).await?;
+        let active_keyset_id = self.active_mint_keyset(mint_url, unit).await.unwrap();
 
         // Desired amount is either amount passwed or value of all proof
         let proofs_total = proofs.iter().map(|p| p.amount).sum();
@@ -1047,11 +1046,10 @@ impl Wallet {
                 .collect();
         }
 
-        let mint_keysets = self
-            .localstore
-            .get_mint_keysets(mint_url.clone())
-            .await?
-            .ok_or(Error::UnknownKey)?;
+        let mint_keysets = match self.localstore.get_mint_keysets(mint_url.clone()).await? {
+            Some(keysets) => keysets,
+            None => self.get_mint_keysets(&mint_url).await?,
+        };
 
         let (active, inactive): (HashSet<KeySetInfo>, HashSet<KeySetInfo>) = mint_keysets
             .into_iter()