@@ -855,9 +855,9 @@ FROM keyset;
855855 async fn add_proofs ( & self , proofs : Proofs , quote_id : Option < Uuid > ) -> Result < ( ) , Self :: Err > {
856856 let mut transaction = self . pool . begin ( ) . await . map_err ( Error :: from) ?;
857857 for proof in proofs {
858- if let Err ( err ) = sqlx:: query (
858+ let result = sqlx:: query (
859859 r#"
860- INSERT INTO proof
860+ INSERT OR IGNORE INTO proof
861861(y, amount, keyset_id, secret, c, witness, state, quote_id)
862862VALUES (?, ?, ?, ?, ?, ?, ?, ?);
863863 "# ,
@@ -871,10 +871,25 @@ VALUES (?, ?, ?, ?, ?, ?, ?, ?);
871871 . bind ( "UNSPENT" )
872872 . bind ( quote_id. map ( |q| q. hyphenated ( ) ) )
873873 . execute ( & mut transaction)
874- . await
875- . map_err ( Error :: from)
876- {
877- tracing:: debug!( "Attempting to add known proof. Skipping.... {:?}" , err) ;
874+ . await ;
875+
876+ // We still need to check for foreign key constraint errors
877+ if let Err ( err) = result {
878+ if let sqlx:: Error :: Database ( db_err) = & err {
879+ if db_err. message ( ) . contains ( "FOREIGN KEY constraint failed" ) {
880+ tracing:: error!(
881+ "Foreign key constraint failed when adding proof: {:?}" ,
882+ err
883+ ) ;
884+ transaction. rollback ( ) . await . map_err ( Error :: from) ?;
885+ return Err ( database:: Error :: InvalidKeysetId ) ;
886+ }
887+ }
888+
889+ // For any other error, roll back and return the error
890+ tracing:: error!( "Error adding proof: {:?}" , err) ;
891+ transaction. rollback ( ) . await . map_err ( Error :: from) ?;
892+ return Err ( Error :: from ( err) . into ( ) ) ;
878893 }
879894 }
880895 transaction. commit ( ) . await . map_err ( Error :: from) ?;
@@ -1077,7 +1092,7 @@ WHERE keyset_id=?;
10771092 "?," . repeat( ys. len( ) ) . trim_end_matches( ',' )
10781093 ) ;
10791094
1080- let mut current_states = ys
1095+ let rows = ys
10811096 . iter ( )
10821097 . fold ( sqlx:: query ( & sql) , |query, y| {
10831098 query. bind ( y. to_bytes ( ) . to_vec ( ) )
@@ -1087,7 +1102,16 @@ WHERE keyset_id=?;
10871102 . map_err ( |err| {
10881103 tracing:: error!( "SQLite could not get state of proof: {err:?}" ) ;
10891104 Error :: SQLX ( err)
1090- } ) ?
1105+ } ) ?;
1106+
1107+ // Check if all proofs exist
1108+ if rows. len ( ) != ys. len ( ) {
1109+ transaction. rollback ( ) . await . map_err ( Error :: from) ?;
1110+ tracing:: warn!( "Attempted to update state of non-existent proof" ) ;
1111+ return Err ( database:: Error :: ProofNotFound ) ;
1112+ }
1113+
1114+ let mut current_states = rows
10911115 . into_iter ( )
10921116 . map ( |row| {
10931117 PublicKey :: from_slice ( row. get ( "y" ) )
@@ -1694,6 +1718,7 @@ fn sqlite_row_to_melt_request(row: SqliteRow) -> Result<(MeltBolt11Request<Uuid>
16941718
16951719#[ cfg( test) ]
16961720mod tests {
1721+ use cdk_common:: mint:: MintKeySetInfo ;
16971722 use cdk_common:: Amount ;
16981723
16991724 use super :: * ;
@@ -1702,8 +1727,20 @@ mod tests {
17021727 async fn test_remove_spent_proofs ( ) {
17031728 let db = memory:: empty ( ) . await . unwrap ( ) ;
17041729
1705- // Create some test proofs
1730+ // Create a keyset and add it to the database
17061731 let keyset_id = Id :: from_str ( "00916bbf7ef91a36" ) . unwrap ( ) ;
1732+ let keyset_info = MintKeySetInfo {
1733+ id : keyset_id. clone ( ) ,
1734+ unit : CurrencyUnit :: Sat ,
1735+ active : true ,
1736+ valid_from : 0 ,
1737+ valid_to : None ,
1738+ derivation_path : bitcoin:: bip32:: DerivationPath :: from_str ( "m/0'/0'/0'" ) . unwrap ( ) ,
1739+ derivation_path_index : Some ( 0 ) ,
1740+ max_order : 32 ,
1741+ input_fee_ppk : 0 ,
1742+ } ;
1743+ db. add_keyset_info ( keyset_info) . await . unwrap ( ) ;
17071744
17081745 let proofs = vec ! [
17091746 Proof {
@@ -1758,8 +1795,20 @@ mod tests {
17581795 async fn test_update_spent_proofs ( ) {
17591796 let db = memory:: empty ( ) . await . unwrap ( ) ;
17601797
1761- // Create some test proofs
1798+ // Create a keyset and add it to the database
17621799 let keyset_id = Id :: from_str ( "00916bbf7ef91a36" ) . unwrap ( ) ;
1800+ let keyset_info = MintKeySetInfo {
1801+ id : keyset_id. clone ( ) ,
1802+ unit : CurrencyUnit :: Sat ,
1803+ active : true ,
1804+ valid_from : 0 ,
1805+ valid_to : None ,
1806+ derivation_path : bitcoin:: bip32:: DerivationPath :: from_str ( "m/0'/0'/0'" ) . unwrap ( ) ,
1807+ derivation_path_index : Some ( 0 ) ,
1808+ max_order : 32 ,
1809+ input_fee_ppk : 0 ,
1810+ } ;
1811+ db. add_keyset_info ( keyset_info) . await . unwrap ( ) ;
17631812
17641813 let proofs = vec ! [
17651814 Proof {
0 commit comments