Prechádzať zdrojové kódy

refactor(wallet/database): get_proofs returns Vec<ProofInfo> instead of Option<Vec<ProofInfo>>

thesimplekid 8 mesiacov pred
rodič
commit
4f240f3953

+ 4 - 3
CHANGELOG.md

@@ -29,9 +29,10 @@
 ### Changed
 - cdk(wallet): `fn send` returns `Token` so the user can use the struct of convert it to a v3 or v4 string ([thesimplekid]).
 - cdk(wallet): Publicly export `MultiMintWallet` ([thesimplekid]).
-- cdk(cdk-database): Get `pending` and `spent` `proofs` by `ys` or `secrets` instead of a single proofs ([thesimplekid]).
-- cdk(cdk-database): Change `add_blind_signature` to `add_blind_signatures` ([thesimplekid]).
-- cdk(cdk-database): Rename `add_active_keyset` to `set_active_keyset` ([thesimplekid]).
+- cdk(cdk-database/mint): Get `pending` and `spent` `proofs` by `ys` or `secrets` instead of a single proofs ([thesimplekid]).
+- cdk(cdk-database/mint): Change `add_blind_signature` to `add_blind_signatures` ([thesimplekid]).
+- cdk(cdk-database/mint): Rename `add_active_keyset` to `set_active_keyset` ([thesimplekid]).
+- cdk(cdk-database/wallet): Change `get_proofs` to return `Vec<ProofInfo>` instead of `Option<Vec<ProofInfo>>` ([thesimplekid]).
 
 ### Added
 - cdk(NUT-11): Add `Copy` on `SigFlag` ([thesimplekid]).

+ 12 - 18
crates/cdk-redb/src/wallet/mod.rs

@@ -231,19 +231,17 @@ impl WalletDatabase for WalletRedbDatabase {
                 .await
                 .map_err(Error::from)?;
 
-            if let Some(proofs) = proofs {
-                // Proofs with new url
-                let updated_proofs: Vec<ProofInfo> = proofs
-                    .clone()
-                    .into_iter()
-                    .map(|mut p| {
-                        p.mint_url = new_mint_url.clone();
-                        p
-                    })
-                    .collect();
-
-                println!("{:?}", updated_proofs);
+            // Proofs with new url
+            let updated_proofs: Vec<ProofInfo> = proofs
+                .clone()
+                .into_iter()
+                .map(|mut p| {
+                    p.mint_url = new_mint_url.clone();
+                    p
+                })
+                .collect();
 
+            if !updated_proofs.is_empty() {
                 self.add_proofs(updated_proofs).await?;
             }
         }
@@ -577,7 +575,7 @@ impl WalletDatabase for WalletRedbDatabase {
         unit: Option<CurrencyUnit>,
         state: Option<Vec<State>>,
         spending_conditions: Option<Vec<SpendingConditions>>,
-    ) -> Result<Option<Vec<ProofInfo>>, Self::Err> {
+    ) -> Result<Vec<ProofInfo>, Self::Err> {
         let db = self.db.lock().await;
         let read_txn = db.begin_read().map_err(Error::from)?;
 
@@ -606,11 +604,7 @@ impl WalletDatabase for WalletRedbDatabase {
             })
             .collect();
 
-        if proofs.is_empty() {
-            return Ok(None);
-        }
-
-        Ok(Some(proofs))
+        Ok(proofs)
     }
 
     #[instrument(skip(self, proofs))]

+ 10 - 15
crates/cdk-rexie/src/wallet.rs

@@ -211,16 +211,15 @@ impl WalletDatabase for WalletRexieDatabase {
             .await
             .map_err(Error::from)?;
 
-        if let Some(proofs) = proofs {
-            let updated_proofs: Vec<ProofInfo> = proofs
-                .clone()
-                .into_iter()
-                .map(|mut p| {
-                    p.mint_url = new_mint_url.clone();
-                    p
-                })
-                .collect();
+        let updated_proofs: Vec<ProofInfo> = proofs
+            .into_iter()
+            .map(|mut p| {
+                p.mint_url = new_mint_url.clone();
+                p
+            })
+            .collect();
 
+        if !updated_proofs.is_empty() {
             self.add_proofs(updated_proofs).await?;
         }
 
@@ -583,7 +582,7 @@ impl WalletDatabase for WalletRexieDatabase {
         unit: Option<CurrencyUnit>,
         state: Option<Vec<State>>,
         spending_conditions: Option<Vec<SpendingConditions>>,
-    ) -> Result<Option<Vec<ProofInfo>>, Self::Err> {
+    ) -> Result<Vec<ProofInfo>, Self::Err> {
         let rexie = self.db.lock().await;
 
         let transaction = rexie
@@ -620,11 +619,7 @@ impl WalletDatabase for WalletRexieDatabase {
 
         transaction.done().await.map_err(Error::from)?;
 
-        if proofs.is_empty() {
-            return Ok(None);
-        }
-
-        Ok(Some(proofs))
+        Ok(proofs)
     }
 
     async fn remove_proofs(&self, proofs: &Proofs) -> Result<(), Self::Err> {

+ 4 - 7
crates/cdk-sqlite/src/wallet/mod.rs

@@ -507,7 +507,7 @@ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?);
         unit: Option<CurrencyUnit>,
         state: Option<Vec<State>>,
         spending_conditions: Option<Vec<SpendingConditions>>,
-    ) -> Result<Option<Vec<ProofInfo>>, Self::Err> {
+    ) -> Result<Vec<ProofInfo>, Self::Err> {
         let recs = sqlx::query(
             r#"
 SELECT *
@@ -520,13 +520,11 @@ FROM proof;
         let recs = match recs {
             Ok(rec) => rec,
             Err(err) => match err {
-                sqlx::Error::RowNotFound => return Ok(None),
+                sqlx::Error::RowNotFound => return Ok(vec![]),
                 _ => return Err(Error::SQLX(err).into()),
             },
         };
 
-        tracing::debug!("{}", recs.len());
-
         let proofs: Vec<ProofInfo> = recs
             .iter()
             .filter_map(|p| match sqlite_row_to_proof_info(p) {
@@ -547,11 +545,10 @@ FROM proof;
                 }
             })
             .collect();
-        tracing::debug!("{}", proofs.len());
 
         match proofs.is_empty() {
-            false => Ok(Some(proofs)),
-            true => return Ok(None),
+            false => Ok(proofs),
+            true => return Ok(vec![]),
         }
     }
     async fn remove_proofs(&self, proofs: &Proofs) -> Result<(), Self::Err> {

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

@@ -131,7 +131,7 @@ pub trait WalletDatabase: Debug {
         unit: Option<CurrencyUnit>,
         state: Option<Vec<State>>,
         spending_conditions: Option<Vec<SpendingConditions>>,
-    ) -> Result<Option<Vec<ProofInfo>>, Self::Err>;
+    ) -> Result<Vec<ProofInfo>, Self::Err>;
     /// Remove proofs from storage
     async fn remove_proofs(&self, proofs: &Proofs) -> Result<(), Self::Err>;
 

+ 4 - 8
crates/cdk/src/cdk_database/wallet_memory.rs

@@ -99,9 +99,9 @@ impl WalletDatabase for WalletMemoryDatabase {
             .await
             .map_err(Error::from)?;
 
-        if let Some(proofs) = proofs {
+        // Update proofs
+        {
             let updated_proofs: Vec<ProofInfo> = proofs
-                .clone()
                 .into_iter()
                 .map(|mut p| {
                     p.mint_url = new_mint_url.clone();
@@ -257,7 +257,7 @@ impl WalletDatabase for WalletMemoryDatabase {
         unit: Option<CurrencyUnit>,
         state: Option<Vec<State>>,
         spending_conditions: Option<Vec<SpendingConditions>>,
-    ) -> Result<Option<Vec<ProofInfo>>, Error> {
+    ) -> Result<Vec<ProofInfo>, Error> {
         let proofs = self.proofs.read().await;
 
         let proofs: Vec<ProofInfo> = proofs
@@ -272,11 +272,7 @@ impl WalletDatabase for WalletMemoryDatabase {
             })
             .collect();
 
-        if proofs.is_empty() {
-            return Ok(None);
-        }
-
-        Ok(Some(proofs))
+        Ok(proofs)
     }
 
     async fn remove_proofs(&self, proofs: &Proofs) -> Result<(), Error> {

+ 79 - 67
crates/cdk/src/wallet/mod.rs

@@ -113,7 +113,7 @@ impl Wallet {
     /// Total unspent balance of wallet
     #[instrument(skip(self))]
     pub async fn total_balance(&self) -> Result<Amount, Error> {
-        if let Some(proofs) = self
+        let proofs = self
             .localstore
             .get_proofs(
                 Some(self.mint_url.clone()),
@@ -121,22 +121,16 @@ impl Wallet {
                 Some(vec![State::Unspent]),
                 None,
             )
-            .await?
-        {
-            let balance = proofs.iter().map(|p| p.proof.amount).sum::<Amount>();
-
-            return Ok(balance);
-        }
+            .await?;
+        let balance = proofs.iter().map(|p| p.proof.amount).sum::<Amount>();
 
-        Ok(Amount::ZERO)
+        Ok(balance)
     }
 
     /// Total pending balance
     #[instrument(skip(self))]
     pub async fn total_pending_balance(&self) -> Result<HashMap<CurrencyUnit, Amount>, Error> {
-        let mut balances = HashMap::new();
-
-        if let Some(proofs) = self
+        let proofs = self
             .localstore
             .get_proofs(
                 Some(self.mint_url.clone()),
@@ -144,15 +138,12 @@ impl Wallet {
                 Some(vec![State::Pending]),
                 None,
             )
-            .await?
-        {
-            for proof in proofs {
-                balances
-                    .entry(proof.unit)
-                    .and_modify(|ps| *ps += proof.proof.amount)
-                    .or_insert(proof.proof.amount);
-            }
-        }
+            .await?;
+
+        let balances = proofs.iter().fold(HashMap::new(), |mut acc, proof| {
+            *acc.entry(proof.unit).or_insert(Amount::ZERO) += proof.proof.amount;
+            acc
+        });
 
         Ok(balances)
     }
@@ -160,9 +151,7 @@ impl Wallet {
     /// Total reserved balance
     #[instrument(skip(self))]
     pub async fn total_reserved_balance(&self) -> Result<HashMap<CurrencyUnit, Amount>, Error> {
-        let mut balances = HashMap::new();
-
-        if let Some(proofs) = self
+        let proofs = self
             .localstore
             .get_proofs(
                 Some(self.mint_url.clone()),
@@ -170,15 +159,12 @@ impl Wallet {
                 Some(vec![State::Reserved]),
                 None,
             )
-            .await?
-        {
-            for proof in proofs {
-                balances
-                    .entry(proof.unit)
-                    .and_modify(|ps| *ps += proof.proof.amount)
-                    .or_insert(proof.proof.amount);
-            }
-        }
+            .await?;
+
+        let balances = proofs.iter().fold(HashMap::new(), |mut acc, proof| {
+            *acc.entry(proof.unit).or_insert(Amount::ZERO) += proof.proof.amount;
+            acc
+        });
 
         Ok(balances)
     }
@@ -208,8 +194,9 @@ impl Wallet {
                 None,
             )
             .await?
-            .map(|p| p.into_iter().map(|p| p.proof).collect())
-            .unwrap_or_default())
+            .into_iter()
+            .map(|p| p.proof)
+            .collect())
     }
 
     /// Get pending [`Proofs`]
@@ -224,8 +211,9 @@ impl Wallet {
                 None,
             )
             .await?
-            .map(|p| p.into_iter().map(|p| p.proof).collect())
-            .unwrap_or_default())
+            .into_iter()
+            .map(|p| p.proof)
+            .collect())
     }
 
     /// Get reserved [`Proofs`]
@@ -240,8 +228,9 @@ impl Wallet {
                 None,
             )
             .await?
-            .map(|p| p.into_iter().map(|p| p.proof).collect())
-            .unwrap_or_default())
+            .into_iter()
+            .map(|p| p.proof)
+            .collect())
     }
 
     /// Return proofs to unspent allowing them to be selected and spent
@@ -405,7 +394,7 @@ impl Wallet {
     pub async fn check_all_pending_proofs(&self) -> Result<Amount, Error> {
         let mut balance = Amount::ZERO;
 
-        if let Some(proofs) = self
+        let proofs = self
             .localstore
             .get_proofs(
                 Some(self.mint_url.clone()),
@@ -413,33 +402,36 @@ impl Wallet {
                 Some(vec![State::Pending, State::Reserved]),
                 None,
             )
-            .await?
-        {
-            let states = self
-                .check_proofs_spent(proofs.clone().into_iter().map(|p| p.proof).collect())
-                .await?;
+            .await?;
 
-            // Both `State::Pending` and `State::Unspent` should be included in the pending table.
-            // This is because a proof that has been crated to send will be stored in the pending table
-            // in order to avoid accidentally double spending but to allow it to be explicitly reclaimed
-            let pending_states: HashSet<PublicKey> = states
-                .into_iter()
-                .filter(|s| s.state.ne(&State::Spent))
-                .map(|s| s.y)
-                .collect();
+        if proofs.is_empty() {
+            return Ok(Amount::ZERO);
+        }
 
-            let (pending_proofs, non_pending_proofs): (Vec<ProofInfo>, Vec<ProofInfo>) = proofs
-                .into_iter()
-                .partition(|p| pending_states.contains(&p.y));
+        let states = self
+            .check_proofs_spent(proofs.clone().into_iter().map(|p| p.proof).collect())
+            .await?;
+
+        // Both `State::Pending` and `State::Unspent` should be included in the pending table.
+        // This is because a proof that has been crated to send will be stored in the pending table
+        // in order to avoid accidentally double spending but to allow it to be explicitly reclaimed
+        let pending_states: HashSet<PublicKey> = states
+            .into_iter()
+            .filter(|s| s.state.ne(&State::Spent))
+            .map(|s| s.y)
+            .collect();
 
-            let amount = pending_proofs.iter().map(|p| p.proof.amount).sum();
+        let (pending_proofs, non_pending_proofs): (Vec<ProofInfo>, Vec<ProofInfo>) = proofs
+            .into_iter()
+            .partition(|p| pending_states.contains(&p.y));
 
-            self.localstore
-                .remove_proofs(&non_pending_proofs.into_iter().map(|p| p.proof).collect())
-                .await?;
+        let amount = pending_proofs.iter().map(|p| p.proof.amount).sum();
 
-            balance += amount;
-        }
+        self.localstore
+            .remove_proofs(&non_pending_proofs.into_iter().map(|p| p.proof).collect())
+            .await?;
+
+        balance += amount;
 
         Ok(balance)
     }
@@ -946,10 +938,20 @@ impl Wallet {
                 Some(vec![State::Unspent]),
                 None,
             )
-            .await?
-            .ok_or(Error::InsufficientFunds)?;
+            .await?;
 
-        let available_proofs = available_proofs.into_iter().map(|p| p.proof).collect();
+        let (available_proofs, proofs_sum) = available_proofs.into_iter().map(|p| p.proof).fold(
+            (Vec::new(), Amount::ZERO),
+            |(mut acc1, mut acc2), p| {
+                acc2 += p.amount;
+                acc1.push(p);
+                (acc1, acc2)
+            },
+        );
+
+        if proofs_sum < amount {
+            return Err(Error::InsufficientFunds);
+        }
 
         let proofs = self.select_proofs_to_swap(amount, available_proofs).await?;
 
@@ -1015,10 +1017,20 @@ impl Wallet {
                 Some(vec![State::Unspent]),
                 conditions.clone().map(|c| vec![c]),
             )
-            .await?
-            .unwrap_or_default();
+            .await?;
 
-        let available_proofs = available_proofs.into_iter().map(|p| p.proof).collect();
+        let (available_proofs, proofs_sum) = available_proofs.into_iter().map(|p| p.proof).fold(
+            (Vec::new(), Amount::ZERO),
+            |(mut acc1, mut acc2), p| {
+                acc2 += p.amount;
+                acc1.push(p);
+                (acc1, acc2)
+            },
+        );
+
+        if proofs_sum < amount {
+            return Err(Error::InsufficientFunds);
+        }
 
         let selected = self
             .select_proofs_to_send(amount, available_proofs, include_fees)