Ver código fonte

Fix race condition

Cesar Rodas 3 semanas atrás
pai
commit
597a15f892

+ 7 - 2
crates/cdk-signatory/src/db_signatory.rs

@@ -130,9 +130,13 @@ impl DbSignatory {
         let mut active_keysets = self.active_keysets.write().await;
         keysets.clear();
         active_keysets.clear();
-        for info in self.localstore.get_keyset_infos().await? {
+
+        let db_active_keysets = self.localstore.get_active_keysets().await?;
+
+        for mut info in self.localstore.get_keyset_infos().await? {
             let id = info.id;
             let keyset = self.generate_keyset(&info);
+            info.active = db_active_keysets.get(&info.unit) == Some(&info.id);
             if info.active {
                 active_keysets.insert(info.unit.clone(), id);
             }
@@ -140,12 +144,13 @@ impl DbSignatory {
         }
 
         if let Some(auth_db) = self.auth_localstore.clone() {
-            for info in auth_db.get_keyset_infos().await? {
+            for mut info in auth_db.get_keyset_infos().await? {
                 let id = info.id;
                 let keyset = self.generate_keyset(&info);
                 if info.unit != CurrencyUnit::Auth {
                     continue;
                 }
+                info.active = db_active_keysets.get(&info.unit) == Some(&info.id);
                 if info.active {
                     active_keysets.insert(info.unit.clone(), id);
                 }

+ 12 - 2
crates/cdk/src/mint/swap.rs

@@ -3,7 +3,7 @@ use tracing::instrument;
 use super::nut11::{enforce_sig_flag, EnforceSigFlag};
 use super::{Mint, PublicKey, SigFlag, State, SwapRequest, SwapResponse};
 use crate::nuts::nut00::ProofsMethods;
-use crate::Error;
+use crate::{cdk_database, Error};
 
 impl Mint {
     /// Process Swap
@@ -36,9 +36,19 @@ impl Mint {
             promises.push(blinded_signature);
         }
 
+        // TODO: It may be possible to have a race condition, that's why an error when changing the
+        // state can be converted to a TokenAlreadySpent error.
+        //
+        // A concept of transaction/writer for the Database trait would eliminate this problem and
+        // will remove all the "reset" codebase, resulting in fewer lines of code, and less
+        // error-prone database updates
         self.localstore
             .update_proofs_states(&input_ys, State::Spent)
-            .await?;
+            .await
+            .map_err(|e| match e {
+                cdk_database::Error::AttemptUpdateSpentProof => Error::TokenAlreadySpent,
+                e => e.into(),
+            })?;
 
         for pub_key in input_ys {
             self.pubsub_manager.proof_state((pub_key, State::Spent));

+ 0 - 1
crates/cdk/src/mint/verification.rs

@@ -114,7 +114,6 @@ impl Mint {
         let inputs_keyset_ids: HashSet<Id> = inputs.iter().map(|p| p.keyset_id).collect();
 
         for id in &inputs_keyset_ids {
-            // TODO: Should ping the signatory instead of DB
             match self.get_keyset_info(id).await? {
                 Some(keyset) => {
                     keyset_units.insert(keyset.unit);