Prechádzať zdrojové kódy

fix: verification of melt quote with empty outputs

thesimplekid 1 mesiac pred
rodič
commit
cf9cacaff4

+ 23 - 11
crates/cdk-integration-tests/tests/regtest.rs

@@ -256,42 +256,54 @@ async fn test_restore() -> Result<()> {
 }
 
 #[tokio::test(flavor = "multi_thread", worker_threads = 1)]
-async fn test_pay_invoice_twice() -> Result<()> {
+async fn test_pay_invoice_twice() -> anyhow::Result<()> {
     let lnd_client = init_lnd_client().await;
 
-    let seed = Mnemonic::generate(12)?.to_seed_normalized("");
+    let seed = Mnemonic::generate(12).unwrap().to_seed_normalized("");
     let wallet = Wallet::new(
         &get_mint_url("0"),
         CurrencyUnit::Sat,
-        Arc::new(memory::empty().await?),
+        Arc::new(memory::empty().await.unwrap()),
         &seed,
         None,
     )?;
 
-    let mint_quote = wallet.mint_quote(100.into(), None).await?;
+    let mint_quote = wallet
+        .mint_quote(100.into(), None)
+        .await
+        .expect("Get mint quote");
 
     lnd_client
         .pay_invoice(mint_quote.request)
         .await
         .expect("Could not pay invoice");
 
-    wait_for_mint_to_be_paid(&wallet, &mint_quote.id, 60).await?;
+    wait_for_mint_to_be_paid(&wallet, &mint_quote.id, 60)
+        .await
+        .expect("Mint invoice timeout not paid");
 
     let proofs = wallet
         .mint(&mint_quote.id, SplitTarget::default(), None)
-        .await?;
+        .await
+        .expect("Could not mint");
 
-    let mint_amount = proofs.total_amount()?;
+    let mint_amount = proofs.total_amount().unwrap();
 
     assert_eq!(mint_amount, 100.into());
 
-    let invoice = lnd_client.create_invoice(Some(10)).await?;
+    let invoice = lnd_client
+        .create_invoice(Some(10))
+        .await
+        .expect("Could not create invoice");
 
-    let melt_quote = wallet.melt_quote(invoice.clone(), None).await?;
+    let melt_quote = wallet
+        .melt_quote(invoice.clone(), None)
+        .await
+        .expect("Could not get melt quote");
 
     let melt = wallet.melt(&melt_quote.id).await.unwrap();
 
-    let melt_two = wallet.melt_quote(invoice, None).await?;
+    let melt_two = wallet.melt_quote(invoice, None).await.unwrap();
 
     let melt_two = wallet.melt(&melt_two.id).await;
 
@@ -307,7 +319,7 @@ async fn test_pay_invoice_twice() -> Result<()> {
         }
     }
 
-    let balance = wallet.total_balance().await?;
+    let balance = wallet.total_balance().await.unwrap();
 
     assert_eq!(balance, (Amount::from(100) - melt.fee_paid - melt.amount));
 

+ 9 - 5
crates/cdk/src/mint/melt.rs

@@ -310,6 +310,8 @@ impl Mint {
             unit: input_unit,
         } = self.verify_inputs(&melt_request.inputs).await?;
 
+        ensure_cdk!(input_unit.is_some(), Error::UnsupportedUnit);
+
         let input_ys = melt_request.inputs.ys()?;
 
         let fee = self.get_proofs_fee(&melt_request.inputs).await?;
@@ -343,12 +345,14 @@ impl Mint {
         ensure_cdk!(sig_flag.ne(&SigFlag::SigAll), Error::SigAllUsedInMelt);
 
         if let Some(outputs) = &melt_request.outputs {
-            let Verification {
-                amount: _,
-                unit: output_unit,
-            } = self.verify_outputs(outputs).await?;
+            if !outputs.is_empty() {
+                let Verification {
+                    amount: _,
+                    unit: output_unit,
+                } = self.verify_outputs(outputs).await?;
 
-            ensure_cdk!(input_unit == output_unit, Error::UnsupportedUnit);
+                ensure_cdk!(input_unit == output_unit, Error::UnsupportedUnit);
+            }
         }
 
         tracing::debug!("Verified melt quote: {}", melt_request.quote);

+ 1 - 0
crates/cdk/src/mint/mint_nut04.rs

@@ -327,6 +327,7 @@ impl Mint {
             ));
         }
 
+        let unit = unit.ok_or(Error::UnsupportedUnit)?;
         ensure_cdk!(unit == mint_quote.unit, Error::UnsupportedUnit);
 
         let mut blind_signatures = Vec::with_capacity(mint_request.outputs.len());

+ 17 - 4
crates/cdk/src/mint/verification.rs

@@ -8,7 +8,7 @@ use super::{Error, Mint};
 #[derive(Debug, Clone, Hash, PartialEq, Eq)]
 pub struct Verification {
     pub amount: Amount,
-    pub unit: CurrencyUnit,
+    pub unit: Option<CurrencyUnit>,
 }
 
 impl Mint {
@@ -171,6 +171,13 @@ impl Mint {
     /// Checks outputs are unique, of the same unit and not signed before
     #[instrument(skip_all)]
     pub async fn verify_outputs(&self, outputs: &[BlindedMessage]) -> Result<Verification, Error> {
+        if outputs.is_empty() {
+            return Ok(Verification {
+                amount: Amount::ZERO,
+                unit: None,
+            });
+        }
+
         Mint::check_outputs_unique(outputs)?;
         self.check_output_already_signed(outputs).await?;
 
@@ -178,7 +185,10 @@ impl Mint {
 
         let amount = Amount::try_sum(outputs.iter().map(|o| o.amount).collect::<Vec<Amount>>())?;
 
-        Ok(Verification { amount, unit })
+        Ok(Verification {
+            amount,
+            unit: Some(unit),
+        })
     }
 
     /// Verifies inputs
@@ -194,7 +204,10 @@ impl Mint {
             self.verify_proof(proof).await?;
         }
 
-        Ok(Verification { amount, unit })
+        Ok(Verification {
+            amount,
+            unit: Some(unit),
+        })
     }
 
     /// Verify that inputs and outputs are valid and balanced
@@ -215,7 +228,7 @@ impl Mint {
 
         if output_verification.unit != input_verification.unit {
             tracing::debug!(
-                "Output unit {} does not match input unit {}",
+                "Output unit {:?} does not match input unit {:?}",
                 output_verification.unit,
                 input_verification.unit
             );