From 44e39bd3eeeea60e2929a6f081f39b69cde9e4ab Mon Sep 17 00:00:00 2001 From: thesimplekid Date: Wed, 22 May 2024 22:21:34 +0100 Subject: [PATCH] refactor: get proofs by spending condition --- crates/cdk-redb/src/wallet.rs | 26 ++++---------- crates/cdk-rexie/src/wallet.rs | 32 ++++++----------- crates/cdk/src/cdk_database/mod.rs | 3 +- crates/cdk/src/cdk_database/wallet_memory.rs | 30 ++++------------ crates/cdk/src/nuts/nut11/mod.rs | 10 ++++++ crates/cdk/src/types.rs | 38 +++++++++++++++++++- crates/cdk/src/wallet.rs | 15 +++++--- 7 files changed, 83 insertions(+), 71 deletions(-) diff --git a/crates/cdk-redb/src/wallet.rs b/crates/cdk-redb/src/wallet.rs index 1d4b5b7c..93b6fdbc 100644 --- a/crates/cdk-redb/src/wallet.rs +++ b/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, state: Option>, + spending_conditions: Option>, ) -> Result, 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::(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(_) => (), } } diff --git a/crates/cdk-rexie/src/wallet.rs b/crates/cdk-rexie/src/wallet.rs index 2e3d5f9b..ca2c0b35 100644 --- a/crates/cdk-rexie/src/wallet.rs +++ b/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, state: Option>, + spending_conditions: Option>, ) -> Result, 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::(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 diff --git a/crates/cdk/src/cdk_database/mod.rs b/crates/cdk/src/cdk_database/mod.rs index cbd74fd8..8c31b123 100644 --- a/crates/cdk/src/cdk_database/mod.rs +++ b/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, state: Option>, + spending_conditions: Option>, ) -> Result, Self::Err>; async fn remove_proofs(&self, proofs: &Proofs) -> Result<(), Self::Err>; diff --git a/crates/cdk/src/cdk_database/wallet_memory.rs b/crates/cdk/src/cdk_database/wallet_memory.rs index 3fa6c881..b51a18e6 100644 --- a/crates/cdk/src/cdk_database/wallet_memory.rs +++ b/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, state: Option>, + spending_conditions: Option>, ) -> Result, 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(); diff --git a/crates/cdk/src/nuts/nut11/mod.rs b/crates/cdk/src/nuts/nut11/mod.rs index 1c47d2f1..0af05f93 100644 --- a/crates/cdk/src/nuts/nut11/mod.rs +++ b/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 { + let nut10_secret: Nut10Secret = secret.try_into()?; + + nut10_secret.try_into() + } +} + impl TryFrom for SpendingConditions { type Error = Error; fn try_from(secret: Nut10Secret) -> Result { diff --git a/crates/cdk/src/types.rs b/crates/cdk/src/types.rs index bf2e5fa8..46e1fbcb 100644 --- a/crates/cdk/src/types.rs +++ b/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, } impl ProofInfo { @@ -107,11 +108,46 @@ impl ProofInfo { .y() .map_err(|_| Error::CustomError("Could not find y".to_string()))?; + let spending_condition: Option = (&proof.secret).try_into().ok(); + Ok(Self { proof, y, mint_url, state, + spending_condition, }) } + + pub fn matches_conditions( + &self, + mint_url: &Option, + state: &Option>, + spending_conditions: &Option>, + ) -> Result { + 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) + } } diff --git a/crates/cdk/src/wallet.rs b/crates/cdk/src/wallet.rs index 2dff4718..34bab4a3 100644 --- a/crates/cdk/src/wallet.rs +++ b/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, 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 { 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)?;