Browse Source

feat: sql store signatures dleq

thesimplekid 6 months ago
parent
commit
7ea568e615

+ 11 - 0
crates/cdk-fake-wallet/src/lib.rs

@@ -88,6 +88,17 @@ pub struct FakeInvoiceDescription {
     pub check_err: bool,
 }
 
+impl Default for FakeInvoiceDescription {
+    fn default() -> Self {
+        Self {
+            pay_invoice_state: MeltQuoteState::Paid,
+            check_payment_state: MeltQuoteState::Paid,
+            pay_err: false,
+            check_err: false,
+        }
+    }
+}
+
 #[async_trait]
 impl MintLightning for FakeWallet {
     type Err = cdk_lightning::Error;

+ 49 - 2
crates/cdk-integration-tests/tests/fake_wallet.rs

@@ -5,8 +5,8 @@ use bip39::Mnemonic;
 use cdk::{
     amount::SplitTarget,
     cdk_database::WalletMemoryDatabase,
-    nuts::{CurrencyUnit, MeltQuoteState, State},
-    wallet::Wallet,
+    nuts::{CurrencyUnit, MeltQuoteState, PreMintSecrets, State},
+    wallet::{client::HttpClient, Wallet},
 };
 use cdk_fake_wallet::{create_fake_invoice, FakeInvoiceDescription};
 use cdk_integration_tests::attempt_to_swap_pending;
@@ -311,3 +311,50 @@ async fn test_fake_melt_payment_err_paid() -> Result<()> {
 
     Ok(())
 }
+
+#[tokio::test(flavor = "multi_thread", worker_threads = 1)]
+async fn test_fake_melt_change_in_quote() -> Result<()> {
+    let wallet = Wallet::new(
+        MINT_URL,
+        CurrencyUnit::Sat,
+        Arc::new(WalletMemoryDatabase::default()),
+        &Mnemonic::generate(12)?.to_seed_normalized(""),
+        None,
+    )?;
+
+    let mint_quote = wallet.mint_quote(100.into(), None).await?;
+
+    let _mint_amount = wallet
+        .mint(&mint_quote.id, SplitTarget::default(), None)
+        .await?;
+
+    let fake_description = FakeInvoiceDescription::default();
+
+    let invoice = create_fake_invoice(9000, serde_json::to_string(&fake_description).unwrap());
+
+    let proofs = wallet.get_proofs().await?;
+
+    let melt_quote = wallet.melt_quote(invoice.to_string(), None).await?;
+
+    let keyset = wallet.get_active_mint_keyset().await?;
+
+    let premint_secrets = PreMintSecrets::random(keyset.id, 100.into(), &SplitTarget::default())?;
+
+    let client = HttpClient::new();
+
+    let melt_response = client
+        .post_melt(
+            MINT_URL.parse()?,
+            melt_quote.id.clone(),
+            proofs.clone(),
+            Some(premint_secrets.blinded_messages()),
+        )
+        .await?;
+
+    assert!(melt_response.change.is_some());
+
+    let check = wallet.melt_quote_status(&melt_quote.id).await?;
+
+    assert_eq!(melt_response.change, check.change);
+    Ok(())
+}

+ 3 - 3
crates/cdk-redb/src/mint/mod.rs

@@ -37,7 +37,7 @@ const BLINDED_SIGNATURES: TableDefinition<[u8; 33], &str> =
     TableDefinition::new("blinded_signatures");
 const QUOTE_PROOFS_TABLE: MultimapTableDefinition<&str, [u8; 33]> =
     MultimapTableDefinition::new("quote_proofs");
-const QUOTE_SIGNATURES_TABLE: MultimapTableDefinition<&str, &str> =
+const QUOTE_SIGNATURES_TABLE: MultimapTableDefinition<&str, [u8; 33]> =
     MultimapTableDefinition::new("quote_signatures");
 
 const MELT_REQUESTS: TableDefinition<&str, (&str, &str)> = TableDefinition::new("melt_requests");
@@ -683,7 +683,7 @@ impl MintDatabase for MintRedbDatabase {
 
                 if let Some(quote_id) = &quote_id {
                     quote_sigs_table
-                        .insert(quote_id.as_str(), blind_sig.as_str())
+                        .insert(quote_id.as_str(), blinded_message.to_bytes())
                         .map_err(Error::from)?;
                 }
             }
@@ -787,7 +787,7 @@ impl MintDatabase for MintRedbDatabase {
     ) -> Result<Vec<BlindSignature>, Self::Err> {
         let read_txn = self.db.begin_read().map_err(Error::from)?;
         let quote_proofs_table = read_txn
-            .open_multimap_table(QUOTE_PROOFS_TABLE)
+            .open_multimap_table(QUOTE_SIGNATURES_TABLE)
             .map_err(Error::from)?;
 
         let ys = quote_proofs_table.get(quote_id).unwrap();

+ 2 - 0
crates/cdk-sqlite/src/mint/migrations/20240930101140_dleq_for_sigs.sql

@@ -0,0 +1,2 @@
+ALTER TABLE blind_signature ADD COLUMN dleq_e TEXT;
+ALTER TABLE blind_signature ADD COLUMN dleq_s TEXT;

+ 35 - 16
crates/cdk-sqlite/src/mint/mod.rs

@@ -12,8 +12,8 @@ use cdk::mint::{MintKeySetInfo, MintQuote};
 use cdk::mint_url::MintUrl;
 use cdk::nuts::nut05::QuoteState;
 use cdk::nuts::{
-    BlindSignature, CurrencyUnit, Id, MeltBolt11Request, MeltQuoteState, MintQuoteState,
-    PaymentMethod, Proof, Proofs, PublicKey, State,
+    BlindSignature, BlindSignatureDleq, CurrencyUnit, Id, MeltBolt11Request, MeltQuoteState,
+    MintQuoteState, PaymentMethod, Proof, Proofs, PublicKey, SecretKey, State,
 };
 use cdk::secret::Secret;
 use cdk::types::LnKey;
@@ -1025,8 +1025,8 @@ WHERE y=?;
             let res = sqlx::query(
                 r#"
 INSERT INTO blind_signature
-(y, amount, keyset_id, c, quote_id)
-VALUES (?, ?, ?, ?, ?);
+(y, amount, keyset_id, c, quote_id, dleq_e, dleq_s)
+VALUES (?, ?, ?, ?, ?, ?, ?);
         "#,
             )
             .bind(message.to_bytes().to_vec())
@@ -1034,6 +1034,8 @@ VALUES (?, ?, ?, ?, ?);
             .bind(signature.keyset_id.to_string())
             .bind(signature.c.to_bytes().to_vec())
             .bind(quote_id.clone())
+            .bind(signature.dleq.as_ref().map(|dleq| dleq.e.to_secret_hex()))
+            .bind(signature.dleq.as_ref().map(|dleq| dleq.s.to_secret_hex()))
             .execute(&mut transaction)
             .await;
 
@@ -1210,9 +1212,7 @@ WHERE id=?;
     ) -> Result<Vec<BlindSignature>, Self::Err> {
         let mut transaction = self.pool.begin().await.map_err(Error::from)?;
 
-        let mut signatures = Vec::new();
-
-        let rec = sqlx::query(
+        let recs = sqlx::query(
             r#"
 SELECT *
 FROM blind_signature
@@ -1220,18 +1220,27 @@ WHERE quote_id=?;
         "#,
         )
         .bind(quote_id)
-        .fetch_one(&mut transaction)
+        .fetch_all(&mut transaction)
         .await;
 
-        if let Ok(row) = rec {
-            let blinded = sqlite_row_to_blind_signature(row)?;
+        match recs {
+            Ok(recs) => {
+                transaction.commit().await.map_err(Error::from)?;
 
-            signatures.push(blinded);
+                let keysets = recs
+                    .into_iter()
+                    .map(sqlite_row_to_blind_signature)
+                    .collect::<Result<Vec<_>, _>>()?;
+                Ok(keysets)
+            }
+            Err(err) => {
+                tracing::error!("SQLite could not get active keyset");
+                if let Err(err) = transaction.rollback().await {
+                    tracing::error!("Could not rollback sql transaction: {}", err);
+                }
+                Err(Error::from(err).into())
+            }
         }
-
-        transaction.commit().await.map_err(Error::from)?;
-
-        Ok(signatures)
     }
 }
 
@@ -1363,12 +1372,22 @@ fn sqlite_row_to_blind_signature(row: SqliteRow) -> Result<BlindSignature, Error
     let row_amount: i64 = row.try_get("amount").map_err(Error::from)?;
     let keyset_id: String = row.try_get("keyset_id").map_err(Error::from)?;
     let row_c: Vec<u8> = row.try_get("c").map_err(Error::from)?;
+    let row_dleq_e: Option<String> = row.try_get("dleq_e").map_err(Error::from)?;
+    let row_dleq_s: Option<String> = row.try_get("dleq_s").map_err(Error::from)?;
+
+    let dleq = match (row_dleq_e, row_dleq_s) {
+        (Some(e), Some(s)) => Some(BlindSignatureDleq {
+            e: SecretKey::from_hex(e)?,
+            s: SecretKey::from_hex(s)?,
+        }),
+        _ => None,
+    };
 
     Ok(BlindSignature {
         amount: Amount::from(row_amount as u64),
         keyset_id: Id::from_str(&keyset_id)?,
         c: PublicKey::from_slice(&row_c)?,
-        dleq: None,
+        dleq,
     })
 }
 

+ 3 - 1
crates/cdk/src/cdk_database/mint_memory.rs

@@ -372,7 +372,9 @@ impl MintDatabase for MintMemoryDatabase {
 
         if let Some(quote_id) = quote_id {
             let mut current_quote_signatures = self.quote_signatures.write().await;
-            current_quote_signatures.insert(quote_id, blind_signatures.to_vec());
+            current_quote_signatures.insert(quote_id.clone(), blind_signatures.to_vec());
+            let t = current_quote_signatures.get(&quote_id);
+            println!("after insert: {:?}", t);
         }
 
         Ok(())

+ 1 - 1
crates/cdk/src/mint/mod.rs

@@ -613,7 +613,7 @@ impl Mint {
             .get_blind_signatures_for_quote(quote_id)
             .await?;
 
-        let change = blind_signatures.is_empty().then_some(blind_signatures);
+        let change = (!blind_signatures.is_empty()).then_some(blind_signatures);
 
         Ok(MeltQuoteBolt11Response {
             quote: quote.id,

+ 2 - 2
misc/fake_itests.sh

@@ -76,8 +76,8 @@ done
 
 
 # Run cargo test
-cargo test -p cdk-integration-tests --test fake_wallet
-cargo test -p cdk-integration-tests --test mint
+cargo test -p cdk-integration-tests --test fake_wallet "test_fake_melt_change_in_quote"
+# cargo test -p cdk-integration-tests --test mint
 
 # Capture the exit status of cargo test
 test_status=$?