diff --git a/crates/cdk-common/src/database/mint.rs b/crates/cdk-common/src/database/mint.rs index 3ce81f2e..5044853e 100644 --- a/crates/cdk-common/src/database/mint.rs +++ b/crates/cdk-common/src/database/mint.rs @@ -86,8 +86,14 @@ pub trait Database { /// Get [`MintKeySetInfo`]s async fn get_keyset_infos(&self) -> Result, Self::Err>; - /// Add spent [`Proofs`] + /// Add [`Proofs`] async fn add_proofs(&self, proof: Proofs, quote_id: Option) -> Result<(), Self::Err>; + /// Remove [`Proofs`] + async fn remove_proofs( + &self, + ys: &[PublicKey], + quote_id: Option, + ) -> Result<(), Self::Err>; /// Get [`Proofs`] by ys async fn get_proofs_by_ys(&self, ys: &[PublicKey]) -> Result>, Self::Err>; /// Get ys by quote id diff --git a/crates/cdk-redb/src/mint/mod.rs b/crates/cdk-redb/src/mint/mod.rs index 648caa4d..0a5a7656 100644 --- a/crates/cdk-redb/src/mint/mod.rs +++ b/crates/cdk-redb/src/mint/mod.rs @@ -534,6 +534,47 @@ impl MintDatabase for MintRedbDatabase { Ok(()) } + async fn remove_proofs( + &self, + ys: &[PublicKey], + quote_id: Option, + ) -> Result<(), Self::Err> { + let write_txn = self.db.begin_write().map_err(Error::from)?; + + { + let mut proofs_table = write_txn.open_table(PROOFS_TABLE).map_err(Error::from)?; + + for y in ys { + proofs_table.remove(&y.to_bytes()).map_err(Error::from)?; + } + } + + { + let mut proof_state_table = write_txn + .open_table(PROOFS_STATE_TABLE) + .map_err(Error::from)?; + for y in ys { + proof_state_table + .remove(&y.to_bytes()) + .map_err(Error::from)?; + } + } + + if let Some(quote_id) = quote_id { + let mut quote_proofs_table = write_txn + .open_multimap_table(QUOTE_PROOFS_TABLE) + .map_err(Error::from)?; + + quote_proofs_table + .remove_all(quote_id.as_bytes()) + .map_err(Error::from)?; + } + + write_txn.commit().map_err(Error::from)?; + + Ok(()) + } + async fn get_proofs_by_ys(&self, ys: &[PublicKey]) -> Result>, Self::Err> { let read_txn = self.db.begin_read().map_err(Error::from)?; let table = read_txn.open_table(PROOFS_TABLE).map_err(Error::from)?; diff --git a/crates/cdk-sqlite/src/mint/mod.rs b/crates/cdk-sqlite/src/mint/mod.rs index 65891d75..8ddb59d8 100644 --- a/crates/cdk-sqlite/src/mint/mod.rs +++ b/crates/cdk-sqlite/src/mint/mod.rs @@ -780,6 +780,33 @@ VALUES (?, ?, ?, ?, ?, ?, ?, ?); Ok(()) } + async fn remove_proofs( + &self, + ys: &[PublicKey], + _quote_id: Option, + ) -> Result<(), Self::Err> { + let mut transaction = self.pool.begin().await.map_err(Error::from)?; + + let sql = format!( + "DELETE FROM proof WHERE y IN ({})", + std::iter::repeat("?") + .take(ys.len()) + .collect::>() + .join(",") + ); + + ys.iter() + .fold(sqlx::query(&sql), |query, y| { + query.bind(y.to_bytes().to_vec()) + }) + .execute(&mut transaction) + .await + .map_err(Error::from)?; + + transaction.commit().await.map_err(Error::from)?; + Ok(()) + } + async fn get_proofs_by_ys(&self, ys: &[PublicKey]) -> Result>, Self::Err> { let mut transaction = self.pool.begin().await.map_err(Error::from)?; diff --git a/crates/cdk/src/cdk_database/mint_memory.rs b/crates/cdk/src/cdk_database/mint_memory.rs index 52bf4c70..c7bdabfb 100644 --- a/crates/cdk/src/cdk_database/mint_memory.rs +++ b/crates/cdk/src/cdk_database/mint_memory.rs @@ -284,6 +284,35 @@ impl MintDatabase for MintMemoryDatabase { Ok(()) } + async fn remove_proofs( + &self, + ys: &[PublicKey], + quote_id: Option, + ) -> Result<(), Self::Err> { + { + let mut db_proofs = self.proofs.write().await; + + ys.iter().for_each(|y| { + db_proofs.remove(&y.to_bytes()); + }); + } + + { + let mut db_proofs_state = self.proof_state.lock().await; + + ys.iter().for_each(|y| { + db_proofs_state.remove(&y.to_bytes()); + }); + } + + if let Some(quote_id) = quote_id { + let mut quote_proofs = self.quote_proofs.lock().await; + quote_proofs.remove("e_id); + } + + Ok(()) + } + async fn get_proofs_by_ys(&self, ys: &[PublicKey]) -> Result>, Self::Err> { let spent_proofs = self.proofs.read().await; diff --git a/crates/cdk/src/mint/melt.rs b/crates/cdk/src/mint/melt.rs index 7cd935f6..3b50f7c8 100644 --- a/crates/cdk/src/mint/melt.rs +++ b/crates/cdk/src/mint/melt.rs @@ -385,7 +385,7 @@ impl Mint { let input_ys = melt_request.inputs.ys()?; self.localstore - .update_proofs_states(&input_ys, State::Unspent) + .remove_proofs(&input_ys, Some(melt_request.quote)) .await?; self.localstore diff --git a/crates/cdk/src/mint/swap.rs b/crates/cdk/src/mint/swap.rs index dba94ecc..915e6096 100644 --- a/crates/cdk/src/mint/swap.rs +++ b/crates/cdk/src/mint/swap.rs @@ -72,18 +72,14 @@ impl Mint { .len() .ne(&proof_count) { - self.localstore - .update_proofs_states(&input_ys, State::Unspent) - .await?; + self.localstore.remove_proofs(&input_ys, None).await?; return Err(Error::DuplicateProofs); } for proof in &swap_request.inputs { if let Err(err) = self.verify_proof(proof).await { tracing::info!("Error verifying proof in swap"); - self.localstore - .update_proofs_states(&input_ys, State::Unspent) - .await?; + self.localstore.remove_proofs(&input_ys, None).await?; return Err(err); } } @@ -100,9 +96,7 @@ impl Mint { } None => { tracing::info!("Swap request with unknown keyset in inputs"); - self.localstore - .update_proofs_states(&input_ys, State::Unspent) - .await?; + self.localstore.remove_proofs(&input_ys, None).await?; } } } @@ -117,9 +111,7 @@ impl Mint { } None => { tracing::info!("Swap request with unknown keyset in outputs"); - self.localstore - .update_proofs_states(&input_ys, State::Unspent) - .await?; + self.localstore.remove_proofs(&input_ys, None).await?; } } } @@ -129,9 +121,7 @@ impl Mint { // now if keyset_units.len().gt(&1) { tracing::error!("Only one unit is allowed in request: {:?}", keyset_units); - self.localstore - .update_proofs_states(&input_ys, State::Unspent) - .await?; + self.localstore.remove_proofs(&input_ys, None).await?; return Err(Error::UnsupportedUnit); } @@ -146,9 +136,7 @@ impl Mint { for blinded_message in &swap_request.outputs { if let Err(err) = blinded_message.verify_p2pk(&pubkeys, sigs_required) { tracing::info!("Could not verify p2pk in swap request"); - self.localstore - .update_proofs_states(&input_ys, State::Unspent) - .await?; + self.localstore.remove_proofs(&input_ys, None).await?; return Err(err.into()); } }