Skip to content

Commit 6faec5c

Browse files
authored
Merge pull request #1137 from joschisan/receive-for-hash-min-final-cltv
Add receive_for_hash_with_min_final_cltv_expiry_delta
2 parents 7a4f7e7 + 9040c4b commit 6faec5c

3 files changed

Lines changed: 77 additions & 7 deletions

File tree

‎src/payment/bolt11.rs‎

Lines changed: 40 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -102,12 +102,14 @@ impl Bolt11Payment {
102102
pub(crate) fn receive_inner(
103103
&self, amount_msat: Option<u64>, invoice_description: &LdkBolt11InvoiceDescription,
104104
expiry_secs: u32, manual_claim_payment_hash: Option<PaymentHash>,
105+
min_final_cltv_expiry_delta: Option<u16>,
105106
) -> Result<LdkBolt11Invoice, Error> {
106107
let invoice_params = Bolt11InvoiceParameters {
107108
amount_msats: amount_msat,
108109
description: invoice_description.clone(),
109110
invoice_expiry_delta_secs: Some(expiry_secs),
110111
payment_hash: manual_claim_payment_hash,
112+
min_final_cltv_expiry_delta,
111113
..Default::default()
112114
};
113115

@@ -557,7 +559,8 @@ impl Bolt11Payment {
557559
&self, amount_msat: u64, description: &Bolt11InvoiceDescription, expiry_secs: u32,
558560
) -> Result<Bolt11Invoice, Error> {
559561
let description = maybe_try_convert_enum(description)?;
560-
let invoice = self.receive_inner(Some(amount_msat), &description, expiry_secs, None)?;
562+
let invoice =
563+
self.receive_inner(Some(amount_msat), &description, expiry_secs, None, None)?;
561564
Ok(maybe_wrap(invoice))
562565
}
563566

@@ -586,8 +589,39 @@ impl Bolt11Payment {
586589
payment_hash: PaymentHash,
587590
) -> Result<Bolt11Invoice, Error> {
588591
let description = maybe_try_convert_enum(description)?;
589-
let invoice =
590-
self.receive_inner(Some(amount_msat), &description, expiry_secs, Some(payment_hash))?;
592+
let invoice = self.receive_inner(
593+
Some(amount_msat),
594+
&description,
595+
expiry_secs,
596+
Some(payment_hash),
597+
None,
598+
)?;
599+
Ok(maybe_wrap(invoice))
600+
}
601+
602+
/// Same as [`receive_for_hash`], but requires the payment's final HTLC to leave at least
603+
/// `min_final_cltv_expiry_delta` blocks until it expires, giving the user that much more time
604+
/// to obtain the preimage.
605+
///
606+
/// The invoice requests three blocks more than the given value, to allow for blocks being
607+
/// connected while the payment is in flight, and an HTLC arriving with fewer than
608+
/// `min_final_cltv_expiry_delta` blocks left is failed back without a [`PaymentClaimable`]
609+
/// event.
610+
///
611+
/// [`receive_for_hash`]: Self::receive_for_hash
612+
/// [`PaymentClaimable`]: crate::Event::PaymentClaimable
613+
pub fn receive_for_hash_with_min_final_cltv_expiry_delta(
614+
&self, amount_msat: u64, description: &Bolt11InvoiceDescription, expiry_secs: u32,
615+
payment_hash: PaymentHash, min_final_cltv_expiry_delta: u16,
616+
) -> Result<Bolt11Invoice, Error> {
617+
let description = maybe_try_convert_enum(description)?;
618+
let invoice = self.receive_inner(
619+
Some(amount_msat),
620+
&description,
621+
expiry_secs,
622+
Some(payment_hash),
623+
Some(min_final_cltv_expiry_delta),
624+
)?;
591625
Ok(maybe_wrap(invoice))
592626
}
593627

@@ -599,7 +633,7 @@ impl Bolt11Payment {
599633
&self, description: &Bolt11InvoiceDescription, expiry_secs: u32,
600634
) -> Result<Bolt11Invoice, Error> {
601635
let description = maybe_try_convert_enum(description)?;
602-
let invoice = self.receive_inner(None, &description, expiry_secs, None)?;
636+
let invoice = self.receive_inner(None, &description, expiry_secs, None, None)?;
603637
Ok(maybe_wrap(invoice))
604638
}
605639

@@ -627,7 +661,8 @@ impl Bolt11Payment {
627661
&self, description: &Bolt11InvoiceDescription, expiry_secs: u32, payment_hash: PaymentHash,
628662
) -> Result<Bolt11Invoice, Error> {
629663
let description = maybe_try_convert_enum(description)?;
630-
let invoice = self.receive_inner(None, &description, expiry_secs, Some(payment_hash))?;
664+
let invoice =
665+
self.receive_inner(None, &description, expiry_secs, Some(payment_hash), None)?;
631666
Ok(maybe_wrap(invoice))
632667
}
633668

‎src/payment/unified.rs‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,7 @@ impl UnifiedPayment {
156156
&invoice_description,
157157
expiry_sec,
158158
None,
159+
None,
159160
) {
160161
Ok(invoice) => Some(invoice),
161162
Err(e) => {

‎tests/common/mod.rs‎

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1587,6 +1587,39 @@ pub(crate) async fn do_channel_full_cycle<E: ElectrumApi>(
15871587
assert_eq!(manual_payment.amount_msat, Some(invoice_amount_3_msat));
15881588
assert!(matches!(&manual_payment.kind, PaymentKind::Bolt11 { .. }));
15891589

1590+
// Test claiming manually registered payments that require a longer final CLTV expiry.
1591+
let manual_cltv_amount_msat = 5_532_000;
1592+
let min_final_cltv_expiry_delta = 81;
1593+
let manual_cltv_preimage = PaymentPreimage([44u8; 32]);
1594+
let manual_cltv_payment_hash =
1595+
PaymentHash(Sha256::hash(&manual_cltv_preimage.0).to_byte_array());
1596+
let manual_cltv_invoice = node_b
1597+
.bolt11_payment()
1598+
.receive_for_hash_with_min_final_cltv_expiry_delta(
1599+
manual_cltv_amount_msat,
1600+
&invoice_description.clone().into(),
1601+
9217,
1602+
manual_cltv_payment_hash,
1603+
min_final_cltv_expiry_delta,
1604+
)
1605+
.unwrap();
1606+
assert_eq!(
1607+
manual_cltv_invoice.min_final_cltv_expiry_delta(),
1608+
u64::from(min_final_cltv_expiry_delta) + 3
1609+
);
1610+
let outbound_manual_cltv_payment_id =
1611+
node_a.bolt11_payment().send(&manual_cltv_invoice, None).unwrap();
1612+
1613+
let (manual_cltv_payment_id, claimable_amount_msat) =
1614+
expect_payment_claimable_event!(node_b, manual_cltv_payment_hash, manual_cltv_amount_msat);
1615+
node_b
1616+
.bolt11_payment()
1617+
.claim_for_id(manual_cltv_payment_id, claimable_amount_msat, manual_cltv_preimage)
1618+
.unwrap();
1619+
let received_payment_id = expect_payment_received_event!(node_b, claimable_amount_msat);
1620+
assert_eq!(received_payment_id, manual_cltv_payment_id);
1621+
expect_payment_successful_event!(node_a, outbound_manual_cltv_payment_id, None);
1622+
15901623
// Test failing manually registered payments.
15911624
let invoice_amount_4_msat = 5_532_000;
15921625
let manual_fail_preimage = PaymentPreimage([43u8; 32]);
@@ -1658,11 +1691,11 @@ pub(crate) async fn do_channel_full_cycle<E: ElectrumApi>(
16581691
assert!(matches!(&received_keysend_payment.kind, PaymentKind::Spontaneous { .. }));
16591692
assert_eq!(
16601693
node_a.list_payments_matching(|p| matches!(p.kind, PaymentKind::Bolt11 { .. })).len(),
1661-
5
1694+
6
16621695
);
16631696
assert_eq!(
16641697
node_b.list_payments_matching(|p| matches!(p.kind, PaymentKind::Bolt11 { .. })).len(),
1665-
5
1698+
6
16661699
);
16671700
assert_eq!(
16681701
node_a.list_payments_matching(|p| matches!(p.kind, PaymentKind::Spontaneous { .. })).len(),
@@ -1875,6 +1908,7 @@ pub(crate) async fn do_channel_full_cycle<E: ElectrumApi>(
18751908
+ invoice_amount_1_msat
18761909
+ overpaid_amount_msat
18771910
+ invoice_amount_3_msat
1911+
+ manual_cltv_amount_msat
18781912
+ determined_amount_msat
18791913
+ keysend_amount_msat)
18801914
/ 1000 - splice_out_sat;

0 commit comments

Comments
 (0)