Kaynağa Gözat

refactor: get proofs by spending condition

thesimplekid 9 ay önce
ebeveyn
işleme
44e39bd3ee

+ 6 - 20
crates/cdk-redb/src/wallet.rs

@@ -5,7 +5,7 @@ use std::sync::Arc;
 use async_trait::async_trait;
 use cdk::cdk_database;
 use cdk::cdk_database::WalletDatabase;
-use cdk::nuts::{Id, KeySetInfo, Keys, MintInfo, Proofs, PublicKey, State};
+use cdk::nuts::{Id, KeySetInfo, Keys, MintInfo, Proofs, PublicKey, SpendingConditions, State};
 use cdk::types::{MeltQuote, MintQuote, ProofInfo};
 use cdk::url::UncheckedUrl;
 use redb::{Database, MultimapTableDefinition, ReadableTable, TableDefinition};
@@ -400,6 +400,7 @@ impl WalletDatabase for RedbWalletDatabase {
         &self,
         mint_url: Option<UncheckedUrl>,
         state: Option<Vec<State>>,
+        spending_conditions: Option<Vec<SpendingConditions>>,
     ) -> Result<Option<Proofs>, Self::Err> {
         let db = self.db.lock().await;
         let read_txn = db.begin_read().map_err(Error::from)?;
@@ -414,25 +415,10 @@ impl WalletDatabase for RedbWalletDatabase {
                 let mut proof = None;
 
                 if let Ok(proof_info) = serde_json::from_str::<ProofInfo>(v.value()) {
-                    match (&mint_url, &state) {
-                        (Some(mint_url), Some(state)) => {
-                            if state.contains(&proof_info.state)
-                                && mint_url.eq(&proof_info.mint_url)
-                            {
-                                proof = Some(proof_info.proof);
-                            }
-                        }
-                        (Some(mint_url), None) => {
-                            if mint_url.eq(&proof_info.mint_url) {
-                                proof = Some(proof_info.proof);
-                            }
-                        }
-                        (None, Some(state)) => {
-                            if state.contains(&proof_info.state) {
-                                proof = Some(proof_info.proof);
-                            }
-                        }
-                        (None, None) => proof = Some(proof_info.proof),
+                    match proof_info.matches_conditions(&mint_url, &state, &spending_conditions) {
+                        Ok(true) => proof = Some(proof_info.proof),
+                        Ok(false) => (),
+                        Err(_) => (),
                     }
                 }
 

+ 11 - 21
crates/cdk-rexie/src/wallet.rs

@@ -4,7 +4,7 @@ use std::result::Result;
 
 use async_trait::async_trait;
 use cdk::cdk_database::WalletDatabase;
-use cdk::nuts::{Id, KeySetInfo, Keys, MintInfo, Proofs, PublicKey, State};
+use cdk::nuts::{Id, KeySetInfo, Keys, MintInfo, Proofs, PublicKey, SpendingConditions, State};
 use cdk::types::{MeltQuote, MintQuote, ProofInfo};
 use cdk::url::UncheckedUrl;
 use rexie::*;
@@ -449,6 +449,7 @@ impl WalletDatabase for RexieWalletDatabase {
         &self,
         mint_url: Option<UncheckedUrl>,
         state: Option<Vec<State>>,
+        spending_conditions: Option<Vec<SpendingConditions>>,
     ) -> Result<Option<Proofs>, Self::Err> {
         let rexie = self.db.lock().await;
 
@@ -469,26 +470,15 @@ impl WalletDatabase for RexieWalletDatabase {
                 let mut proof = None;
 
                 if let Ok(proof_info) = serde_wasm_bindgen::from_value::<ProofInfo>(v) {
-                    match (&mint_url, &state) {
-                        (Some(mint_url), Some(state)) => {
-                            if state.contains(&proof_info.state)
-                                && mint_url.eq(&proof_info.mint_url)
-                            {
-                                proof = Some(proof_info.proof);
-                            }
-                        }
-                        (Some(mint_url), None) => {
-                            if mint_url.eq(&proof_info.mint_url) {
-                                proof = Some(proof_info.proof);
-                            }
-                        }
-                        (None, Some(state)) => {
-                            if state.contains(&proof_info.state) {
-                                proof = Some(proof_info.proof);
-                            }
-                        }
-                        (None, None) => proof = Some(proof_info.proof),
-                    }
+                    proof = match proof_info.matches_conditions(
+                        &mint_url,
+                        &state,
+                        &spending_conditions,
+                    ) {
+                        Ok(true) => Some(proof_info.proof),
+                        Ok(false) => None,
+                        Err(_) => None,
+                    };
                 }
 
                 proof

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

@@ -16,7 +16,7 @@ use crate::nuts::{BlindSignature, CurrencyUnit, Proof};
 #[cfg(any(feature = "wallet", feature = "mint"))]
 use crate::nuts::{Id, MintInfo, PublicKey};
 #[cfg(feature = "wallet")]
-use crate::nuts::{KeySetInfo, Keys, Proofs};
+use crate::nuts::{KeySetInfo, Keys, Proofs, SpendingConditions};
 #[cfg(feature = "mint")]
 use crate::secret::Secret;
 #[cfg(feature = "wallet")]
@@ -82,6 +82,7 @@ pub trait WalletDatabase {
         &self,
         mint_url: Option<UncheckedUrl>,
         state: Option<Vec<State>>,
+        spending_conditions: Option<Vec<SpendingConditions>>,
     ) -> Result<Option<Proofs>, Self::Err>;
     async fn remove_proofs(&self, proofs: &Proofs) -> Result<(), Self::Err>;
 

+ 7 - 23
crates/cdk/src/cdk_database/wallet_memory.rs

@@ -8,7 +8,7 @@ use tokio::sync::RwLock;
 
 use super::WalletDatabase;
 use crate::cdk_database::Error;
-use crate::nuts::{Id, KeySetInfo, Keys, MintInfo, Proofs, PublicKey, State};
+use crate::nuts::{Id, KeySetInfo, Keys, MintInfo, Proofs, PublicKey, SpendingConditions, State};
 use crate::types::{MeltQuote, MintQuote, ProofInfo};
 use crate::url::UncheckedUrl;
 
@@ -170,35 +170,19 @@ impl WalletDatabase for WalletMemoryDatabase {
         &self,
         mint_url: Option<UncheckedUrl>,
         state: Option<Vec<State>>,
+        spending_conditions: Option<Vec<SpendingConditions>>,
     ) -> Result<Option<Proofs>, Error> {
         let proofs = self.proofs.read().await;
 
         let proofs: Proofs = proofs
             .clone()
             .into_values()
-            .filter_map(|proof_info| match (mint_url.clone(), state.clone()) {
-                (Some(mint_url), Some(state)) => {
-                    if state.contains(&proof_info.state) && mint_url.eq(&proof_info.mint_url) {
-                        Some(proof_info.proof)
-                    } else {
-                        None
-                    }
+            .filter_map(|proof_info| {
+                match proof_info.matches_conditions(&mint_url, &state, &spending_conditions) {
+                    Ok(true) => Some(proof_info.proof),
+                    Ok(false) => None,
+                    Err(_) => None,
                 }
-                (Some(mint_url), None) => {
-                    if proof_info.mint_url.eq(&mint_url) {
-                        Some(proof_info.proof)
-                    } else {
-                        None
-                    }
-                }
-                (None, Some(state)) => {
-                    if state.contains(&proof_info.state) {
-                        Some(proof_info.proof)
-                    } else {
-                        None
-                    }
-                }
-                (None, None) => Some(proof_info.proof),
             })
             .collect();
 

+ 10 - 0
crates/cdk/src/nuts/nut11/mod.rs

@@ -18,6 +18,7 @@ use super::nut00::Witness;
 use super::nut01::PublicKey;
 use super::{Kind, Nut10Secret, Proof, Proofs, SecretKey};
 use crate::nuts::nut00::BlindedMessage;
+use crate::secret::Secret;
 use crate::util::{hex, unix_time};
 
 pub mod serde_p2pk_witness;
@@ -323,6 +324,15 @@ impl SpendingConditions {
     }
 }
 
+impl TryFrom<&Secret> for SpendingConditions {
+    type Error = Error;
+    fn try_from(secret: &Secret) -> Result<SpendingConditions, Error> {
+        let nut10_secret: Nut10Secret = secret.try_into()?;
+
+        nut10_secret.try_into()
+    }
+}
+
 impl TryFrom<Nut10Secret> for SpendingConditions {
     type Error = Error;
     fn try_from(secret: Nut10Secret) -> Result<SpendingConditions, Error> {

+ 37 - 1
crates/cdk/src/types.rs

@@ -4,7 +4,7 @@ use serde::{Deserialize, Serialize};
 use uuid::Uuid;
 
 use crate::error::Error;
-use crate::nuts::{CurrencyUnit, Proof, Proofs, PublicKey, State};
+use crate::nuts::{CurrencyUnit, Proof, Proofs, PublicKey, SpendingConditions, State};
 use crate::url::UncheckedUrl;
 use crate::Amount;
 
@@ -99,6 +99,7 @@ pub struct ProofInfo {
     pub y: PublicKey,
     pub mint_url: UncheckedUrl,
     pub state: State,
+    pub spending_condition: Option<SpendingConditions>,
 }
 
 impl ProofInfo {
@@ -107,11 +108,46 @@ impl ProofInfo {
             .y()
             .map_err(|_| Error::CustomError("Could not find y".to_string()))?;
 
+        let spending_condition: Option<SpendingConditions> = (&proof.secret).try_into().ok();
+
         Ok(Self {
             proof,
             y,
             mint_url,
             state,
+            spending_condition,
         })
     }
+
+    pub fn matches_conditions(
+        &self,
+        mint_url: &Option<UncheckedUrl>,
+        state: &Option<Vec<State>>,
+        spending_conditions: &Option<Vec<SpendingConditions>>,
+    ) -> Result<bool, Error> {
+        if let Some(mint_url) = mint_url {
+            if mint_url.ne(&self.mint_url) {
+                return Ok(false);
+            }
+        }
+
+        if let Some(state) = state {
+            if !state.contains(&self.state) {
+                return Ok(false);
+            }
+        }
+
+        if let Some(spending_conditions) = spending_conditions {
+            match &self.spending_condition {
+                None => return Ok(false),
+                Some(s) => {
+                    if !spending_conditions.contains(s) {
+                        return Ok(false);
+                    }
+                }
+            }
+        }
+
+        Ok(true)
+    }
 }

+ 10 - 5
crates/cdk/src/wallet.rs

@@ -143,7 +143,7 @@ impl Wallet {
 
         if let Some(proofs) = self
             .localstore
-            .get_proofs(None, Some(vec![State::Unspent]))
+            .get_proofs(None, Some(vec![State::Unspent]), None)
             .await?
         {
             let amount = proofs.iter().map(|p| p.amount).sum();
@@ -161,7 +161,7 @@ impl Wallet {
 
         if let Some(proofs) = self
             .localstore
-            .get_proofs(None, Some(vec![State::Pending]))
+            .get_proofs(None, Some(vec![State::Pending]), None)
             .await?
         {
             let amount = proofs.iter().map(|p| p.amount).sum();
@@ -179,7 +179,11 @@ impl Wallet {
         let mut balances = HashMap::new();
 
         for (mint, _) in mints {
-            if let Some(proofs) = self.localstore.get_proofs(Some(mint.clone()), None).await? {
+            if let Some(proofs) = self
+                .localstore
+                .get_proofs(Some(mint.clone()), None, None)
+                .await?
+            {
                 let amount = proofs.iter().map(|p| p.amount).sum();
 
                 balances.insert(mint, amount);
@@ -195,7 +199,7 @@ impl Wallet {
     pub async fn get_proofs(&self, mint_url: UncheckedUrl) -> Result<Option<Proofs>, Error> {
         Ok(self
             .localstore
-            .get_proofs(Some(mint_url), Some(vec![State::Unspent]))
+            .get_proofs(Some(mint_url), Some(vec![State::Unspent]), None)
             .await?)
     }
 
@@ -357,6 +361,7 @@ impl Wallet {
                 .get_proofs(
                     Some(mint.clone()),
                     Some(vec![State::Unspent, State::Pending]),
+                    None,
                 )
                 .await?
             {
@@ -935,7 +940,7 @@ impl Wallet {
     ) -> Result<Proofs, Error> {
         let mint_proofs = self
             .localstore
-            .get_proofs(Some(mint_url.clone()), Some(vec![State::Unspent]))
+            .get_proofs(Some(mint_url.clone()), Some(vec![State::Unspent]), None)
             .await?
             .ok_or(Error::InsufficientFunds)?;