From a681c6e05443b690dda4bb917144cf04ffef280b Mon Sep 17 00:00:00 2001 From: Cesar Rodas Date: Wed, 18 Jun 2025 16:20:24 -0300 Subject: [PATCH] Fix SQLite race condition Bug: https://github.com/crodas/cdk/actions/runs/15732950296/job/44339804072#step:5:1853 Reason: When melting in parallel, many update the melt status and attempt to add proofs and they fail when adding the proof and the rollback code kicks in. The loser process removes all the proofs, and the winner process has no proof later on. Fix: Modify `update_melt_quote_state` requirements and implementation to allow only one winner. This will be solved by design with a transaction writer trait --- crates/cdk-common/src/database/mint/mod.rs | 4 +++- crates/cdk-sqlite/src/mint/mod.rs | 2 ++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/crates/cdk-common/src/database/mint/mod.rs b/crates/cdk-common/src/database/mint/mod.rs index 974f5e00..24d78b50 100644 --- a/crates/cdk-common/src/database/mint/mod.rs +++ b/crates/cdk-common/src/database/mint/mod.rs @@ -84,10 +84,12 @@ pub trait QuotesDatabase { /// Get [`mint::MeltQuote`] async fn get_melt_quote(&self, quote_id: &Uuid) -> Result, Self::Err>; /// Update [`mint::MeltQuote`] state + /// + /// It is expected for this function to fail if the state is already set to the new state async fn update_melt_quote_state( &self, quote_id: &Uuid, - state: MeltQuoteState, + new_state: MeltQuoteState, ) -> Result<(MeltQuoteState, mint::MeltQuote), Self::Err>; /// Get all [`mint::MeltQuote`]s async fn get_melt_quotes(&self) -> Result, Self::Err>; diff --git a/crates/cdk-sqlite/src/mint/mod.rs b/crates/cdk-sqlite/src/mint/mod.rs index c5681cd8..94ca7e66 100644 --- a/crates/cdk-sqlite/src/mint/mod.rs +++ b/crates/cdk-sqlite/src/mint/mod.rs @@ -696,9 +696,11 @@ ON CONFLICT(request_lookup_id) DO UPDATE SET melt_quote WHERE id=:id + AND state != :state "#, ) .bind(":id", quote_id.as_hyphenated().to_string()) + .bind(":state", state.to_string()) .fetch_one(&transaction) .await? .map(sqlite_row_to_melt_quote)