|
@@ -855,9 +855,9 @@ FROM keyset;
|
|
|
async fn add_proofs(&self, proofs: Proofs, quote_id: Option<Uuid>) -> Result<(), Self::Err> {
|
|
|
let mut transaction = self.pool.begin().await.map_err(Error::from)?;
|
|
|
for proof in proofs {
|
|
|
- if let Err(err) = sqlx::query(
|
|
|
+ let result = sqlx::query(
|
|
|
r#"
|
|
|
-INSERT INTO proof
|
|
|
+INSERT OR IGNORE INTO proof
|
|
|
(y, amount, keyset_id, secret, c, witness, state, quote_id)
|
|
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?);
|
|
|
"#,
|
|
@@ -871,10 +871,25 @@ VALUES (?, ?, ?, ?, ?, ?, ?, ?);
|
|
|
.bind("UNSPENT")
|
|
|
.bind(quote_id.map(|q| q.hyphenated()))
|
|
|
.execute(&mut transaction)
|
|
|
- .await
|
|
|
- .map_err(Error::from)
|
|
|
- {
|
|
|
- tracing::debug!("Attempting to add known proof. Skipping.... {:?}", err);
|
|
|
+ .await;
|
|
|
+
|
|
|
+ // We still need to check for foreign key constraint errors
|
|
|
+ if let Err(err) = result {
|
|
|
+ if let sqlx::Error::Database(db_err) = &err {
|
|
|
+ if db_err.message().contains("FOREIGN KEY constraint failed") {
|
|
|
+ tracing::error!(
|
|
|
+ "Foreign key constraint failed when adding proof: {:?}",
|
|
|
+ err
|
|
|
+ );
|
|
|
+ transaction.rollback().await.map_err(Error::from)?;
|
|
|
+ return Err(database::Error::InvalidKeysetId);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // For any other error, roll back and return the error
|
|
|
+ tracing::error!("Error adding proof: {:?}", err);
|
|
|
+ transaction.rollback().await.map_err(Error::from)?;
|
|
|
+ return Err(Error::from(err).into());
|
|
|
}
|
|
|
}
|
|
|
transaction.commit().await.map_err(Error::from)?;
|
|
@@ -1077,7 +1092,7 @@ WHERE keyset_id=?;
|
|
|
"?,".repeat(ys.len()).trim_end_matches(',')
|
|
|
);
|
|
|
|
|
|
- let mut current_states = ys
|
|
|
+ let rows = ys
|
|
|
.iter()
|
|
|
.fold(sqlx::query(&sql), |query, y| {
|
|
|
query.bind(y.to_bytes().to_vec())
|
|
@@ -1087,7 +1102,16 @@ WHERE keyset_id=?;
|
|
|
.map_err(|err| {
|
|
|
tracing::error!("SQLite could not get state of proof: {err:?}");
|
|
|
Error::SQLX(err)
|
|
|
- })?
|
|
|
+ })?;
|
|
|
+
|
|
|
+ // Check if all proofs exist
|
|
|
+ if rows.len() != ys.len() {
|
|
|
+ transaction.rollback().await.map_err(Error::from)?;
|
|
|
+ tracing::warn!("Attempted to update state of non-existent proof");
|
|
|
+ return Err(database::Error::ProofNotFound);
|
|
|
+ }
|
|
|
+
|
|
|
+ let mut current_states = rows
|
|
|
.into_iter()
|
|
|
.map(|row| {
|
|
|
PublicKey::from_slice(row.get("y"))
|
|
@@ -1694,6 +1718,7 @@ fn sqlite_row_to_melt_request(row: SqliteRow) -> Result<(MeltBolt11Request<Uuid>
|
|
|
|
|
|
#[cfg(test)]
|
|
|
mod tests {
|
|
|
+ use cdk_common::mint::MintKeySetInfo;
|
|
|
use cdk_common::Amount;
|
|
|
|
|
|
use super::*;
|
|
@@ -1702,8 +1727,20 @@ mod tests {
|
|
|
async fn test_remove_spent_proofs() {
|
|
|
let db = memory::empty().await.unwrap();
|
|
|
|
|
|
- // Create some test proofs
|
|
|
+ // Create a keyset and add it to the database
|
|
|
let keyset_id = Id::from_str("00916bbf7ef91a36").unwrap();
|
|
|
+ let keyset_info = MintKeySetInfo {
|
|
|
+ id: keyset_id.clone(),
|
|
|
+ unit: CurrencyUnit::Sat,
|
|
|
+ active: true,
|
|
|
+ valid_from: 0,
|
|
|
+ valid_to: None,
|
|
|
+ derivation_path: bitcoin::bip32::DerivationPath::from_str("m/0'/0'/0'").unwrap(),
|
|
|
+ derivation_path_index: Some(0),
|
|
|
+ max_order: 32,
|
|
|
+ input_fee_ppk: 0,
|
|
|
+ };
|
|
|
+ db.add_keyset_info(keyset_info).await.unwrap();
|
|
|
|
|
|
let proofs = vec![
|
|
|
Proof {
|
|
@@ -1758,8 +1795,20 @@ mod tests {
|
|
|
async fn test_update_spent_proofs() {
|
|
|
let db = memory::empty().await.unwrap();
|
|
|
|
|
|
- // Create some test proofs
|
|
|
+ // Create a keyset and add it to the database
|
|
|
let keyset_id = Id::from_str("00916bbf7ef91a36").unwrap();
|
|
|
+ let keyset_info = MintKeySetInfo {
|
|
|
+ id: keyset_id.clone(),
|
|
|
+ unit: CurrencyUnit::Sat,
|
|
|
+ active: true,
|
|
|
+ valid_from: 0,
|
|
|
+ valid_to: None,
|
|
|
+ derivation_path: bitcoin::bip32::DerivationPath::from_str("m/0'/0'/0'").unwrap(),
|
|
|
+ derivation_path_index: Some(0),
|
|
|
+ max_order: 32,
|
|
|
+ input_fee_ppk: 0,
|
|
|
+ };
|
|
|
+ db.add_keyset_info(keyset_info).await.unwrap();
|
|
|
|
|
|
let proofs = vec![
|
|
|
Proof {
|