Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 40 additions & 5 deletions src/payment/bolt11.rs
Original file line number Diff line number Diff line change
Expand Up @@ -102,12 +102,14 @@ impl Bolt11Payment {
pub(crate) fn receive_inner(
&self, amount_msat: Option<u64>, invoice_description: &LdkBolt11InvoiceDescription,
expiry_secs: u32, manual_claim_payment_hash: Option<PaymentHash>,
min_final_cltv_expiry_delta: Option<u16>,
) -> Result<LdkBolt11Invoice, Error> {
let invoice_params = Bolt11InvoiceParameters {
amount_msats: amount_msat,
description: invoice_description.clone(),
invoice_expiry_delta_secs: Some(expiry_secs),
payment_hash: manual_claim_payment_hash,
min_final_cltv_expiry_delta,
..Default::default()
};

Expand Down Expand Up @@ -549,7 +551,8 @@ impl Bolt11Payment {
&self, amount_msat: u64, description: &Bolt11InvoiceDescription, expiry_secs: u32,
) -> Result<Bolt11Invoice, Error> {
let description = maybe_try_convert_enum(description)?;
let invoice = self.receive_inner(Some(amount_msat), &description, expiry_secs, None)?;
let invoice =
self.receive_inner(Some(amount_msat), &description, expiry_secs, None, None)?;
Ok(maybe_wrap(invoice))
}

Expand Down Expand Up @@ -578,8 +581,39 @@ impl Bolt11Payment {
payment_hash: PaymentHash,
) -> Result<Bolt11Invoice, Error> {
let description = maybe_try_convert_enum(description)?;
let invoice =
self.receive_inner(Some(amount_msat), &description, expiry_secs, Some(payment_hash))?;
let invoice = self.receive_inner(
Some(amount_msat),
&description,
expiry_secs,
Some(payment_hash),
None,
)?;
Ok(maybe_wrap(invoice))
}

/// Same as [`receive_for_hash`], but requires the payment's final HTLC to leave at least
/// `min_final_cltv_expiry_delta` blocks until it expires, giving the user that much more time
/// to obtain the preimage.
///
/// The invoice requests three blocks more than the given value, to allow for blocks being
/// connected while the payment is in flight, and an HTLC arriving with fewer than
/// `min_final_cltv_expiry_delta` blocks left is failed back without a [`PaymentClaimable`]
/// event.
///
/// [`receive_for_hash`]: Self::receive_for_hash
/// [`PaymentClaimable`]: crate::Event::PaymentClaimable
pub fn receive_for_hash_with_min_final_cltv_expiry_delta(
&self, amount_msat: u64, description: &Bolt11InvoiceDescription, expiry_secs: u32,
payment_hash: PaymentHash, min_final_cltv_expiry_delta: u16,
) -> Result<Bolt11Invoice, Error> {
let description = maybe_try_convert_enum(description)?;
let invoice = self.receive_inner(
Some(amount_msat),
&description,
expiry_secs,
Some(payment_hash),
Some(min_final_cltv_expiry_delta),
)?;
Ok(maybe_wrap(invoice))
}

Expand All @@ -591,7 +625,7 @@ impl Bolt11Payment {
&self, description: &Bolt11InvoiceDescription, expiry_secs: u32,
) -> Result<Bolt11Invoice, Error> {
let description = maybe_try_convert_enum(description)?;
let invoice = self.receive_inner(None, &description, expiry_secs, None)?;
let invoice = self.receive_inner(None, &description, expiry_secs, None, None)?;
Ok(maybe_wrap(invoice))
}

Expand Down Expand Up @@ -619,7 +653,8 @@ impl Bolt11Payment {
&self, description: &Bolt11InvoiceDescription, expiry_secs: u32, payment_hash: PaymentHash,
) -> Result<Bolt11Invoice, Error> {
let description = maybe_try_convert_enum(description)?;
let invoice = self.receive_inner(None, &description, expiry_secs, Some(payment_hash))?;
let invoice =
self.receive_inner(None, &description, expiry_secs, Some(payment_hash), None)?;
Ok(maybe_wrap(invoice))
}

Expand Down
1 change: 1 addition & 0 deletions src/payment/unified.rs
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,7 @@ impl UnifiedPayment {
&invoice_description,
expiry_sec,
None,
None,
) {
Ok(invoice) => Some(invoice),
Err(e) => {
Expand Down
38 changes: 36 additions & 2 deletions tests/common/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1561,6 +1561,39 @@ pub(crate) async fn do_channel_full_cycle<E: ElectrumApi>(
assert_eq!(manual_payment.amount_msat, Some(invoice_amount_3_msat));
assert!(matches!(&manual_payment.kind, PaymentKind::Bolt11 { .. }));

// Test claiming manually registered payments that require a longer final CLTV expiry.
let manual_cltv_amount_msat = 5_532_000;
let min_final_cltv_expiry_delta = 81;
let manual_cltv_preimage = PaymentPreimage([44u8; 32]);
let manual_cltv_payment_hash =
PaymentHash(Sha256::hash(&manual_cltv_preimage.0).to_byte_array());
let manual_cltv_invoice = node_b
.bolt11_payment()
.receive_for_hash_with_min_final_cltv_expiry_delta(
manual_cltv_amount_msat,
&invoice_description.clone().into(),
9217,
manual_cltv_payment_hash,
min_final_cltv_expiry_delta,
)
.unwrap();
assert_eq!(
manual_cltv_invoice.min_final_cltv_expiry_delta(),
u64::from(min_final_cltv_expiry_delta) + 3
);
let outbound_manual_cltv_payment_id =
node_a.bolt11_payment().send(&manual_cltv_invoice, None).unwrap();

let (manual_cltv_payment_id, claimable_amount_msat) =
expect_payment_claimable_event!(node_b, manual_cltv_payment_hash, manual_cltv_amount_msat);
node_b
.bolt11_payment()
.claim_for_id(manual_cltv_payment_id, claimable_amount_msat, manual_cltv_preimage)
.unwrap();
let received_payment_id = expect_payment_received_event!(node_b, claimable_amount_msat);
assert_eq!(received_payment_id, manual_cltv_payment_id);
expect_payment_successful_event!(node_a, outbound_manual_cltv_payment_id, None);

// Test failing manually registered payments.
let invoice_amount_4_msat = 5_532_000;
let manual_fail_preimage = PaymentPreimage([43u8; 32]);
Expand Down Expand Up @@ -1632,11 +1665,11 @@ pub(crate) async fn do_channel_full_cycle<E: ElectrumApi>(
assert!(matches!(&received_keysend_payment.kind, PaymentKind::Spontaneous { .. }));
assert_eq!(
node_a.list_payments_matching(|p| matches!(p.kind, PaymentKind::Bolt11 { .. })).len(),
5
6
);
assert_eq!(
node_b.list_payments_matching(|p| matches!(p.kind, PaymentKind::Bolt11 { .. })).len(),
5
6
);
assert_eq!(
node_a.list_payments_matching(|p| matches!(p.kind, PaymentKind::Spontaneous { .. })).len(),
Expand Down Expand Up @@ -1849,6 +1882,7 @@ pub(crate) async fn do_channel_full_cycle<E: ElectrumApi>(
+ invoice_amount_1_msat
+ overpaid_amount_msat
+ invoice_amount_3_msat
+ manual_cltv_amount_msat
+ determined_amount_msat
+ keysend_amount_msat)
/ 1000 - splice_out_sat;
Expand Down
Loading