Merge pull request #655 from thesimplekid/fix_output_verification

fix: verification of melt quote with empty outputs
This commit is contained in:
thesimplekid
2025-03-13 10:45:23 +00:00
committed by GitHub
4 changed files with 50 additions and 20 deletions

View File

@@ -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));

View File

@@ -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);

View File

@@ -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());

View File

@@ -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
);