Selaa lähdekoodia

Enhance `add_proofs` to fail with a custom error when the proof already exists

Cesar Rodas 1 viikko sitten
vanhempi
säilyke
150f2596e7

+ 3 - 0
crates/cdk-common/src/database/mint/mod.rs

@@ -114,6 +114,9 @@ pub trait ProofsDatabase {
     type Err: Into<Error> + From<Error>;
 
     /// Add  [`Proofs`]
+    ///
+    /// Adds proofs to the database. The database should error if the proof already exits, with a
+    /// `AttemptUpdateSpentProof` if the proof is already spent or a `Duplicate` error otherwise.
     async fn add_proofs(&self, proof: Proofs, quote_id: Option<Uuid>) -> Result<(), Self::Err>;
     /// Remove [`Proofs`]
     async fn remove_proofs(

+ 20 - 0
crates/cdk-sqlite/src/mint/mod.rs

@@ -816,6 +816,26 @@ impl MintProofsDatabase for MintSqliteDatabase {
 
         let current_time = unix_time();
 
+        // Check any previous proof, this query should return None in order to proceed storing
+        // Any result here would error
+        match query(r#"SELECT state FROM proof WHERE y IN (:ys) LIMIT 1"#)
+            .bind_vec(
+                ":ys",
+                proofs
+                    .iter()
+                    .map(|y| y.y().map(|y| y.to_bytes().to_vec()))
+                    .collect::<Result<_, _>>()?,
+            )
+            .pluck(&transaction)
+            .await?
+            .map(|state| Ok::<_, Error>(column_as_string!(&state, State::from_str)))
+            .transpose()?
+        {
+            Some(State::Spent) => Err(database::Error::AttemptUpdateSpentProof),
+            Some(_) => Err(database::Error::Duplicate),
+            None => Ok(()), // no previous record
+        }?;
+
         for proof in proofs {
             query(
                 r#"

+ 7 - 5
crates/cdk/src/mint/melt.rs

@@ -347,15 +347,17 @@ impl Mint {
             .await
             .err()
         {
-            match err {
-                cdk_common::database::Error::Duplicate => {
-                    // the proofs already exits, it will be errored by `check_ys_spendable`
+            return match err {
+                cdk_common::database::Error::Duplicate => Err(Error::TokenPending),
+                cdk_common::database::Error::AttemptUpdateSpentProof => {
+                    Err(Error::TokenAlreadySpent)
                 }
-                err => return Err(Error::Database(err)),
-            }
+                err => Err(Error::Database(err)),
+            };
         }
 
         self.check_ys_spendable(&input_ys, State::Pending).await?;
+
         for proof in melt_request.inputs() {
             self.pubsub_manager
                 .proof_state((proof.y()?, State::Pending));

+ 6 - 5
crates/cdk/src/mint/swap.rs

@@ -30,12 +30,13 @@ impl Mint {
             .await
             .err()
         {
-            match err {
-                cdk_common::database::Error::Duplicate => {
-                    // the proofs already exits, it will be errored by `check_ys_spendable`
+            return match err {
+                cdk_common::database::Error::Duplicate => Err(Error::TokenPending),
+                cdk_common::database::Error::AttemptUpdateSpentProof => {
+                    Err(Error::TokenAlreadySpent)
                 }
-                err => return Err(Error::Database(err)),
-            }
+                err => Err(Error::Database(err)),
+            };
         }
         self.check_ys_spendable(&input_ys, State::Pending).await?;