@@ -42,6 +42,11 @@ use core::time::Duration;
42
42
/// `invoice_expiry_delta_secs` describes the number of seconds that the invoice is valid for
43
43
/// in excess of the current time.
44
44
///
45
+ /// You can specify a custom `min_final_cltv_expiry_delta`, or let LDK default it to
46
+ /// [`MIN_FINAL_CLTV_EXPIRY_DELTA`]. The provided expiry must be at least [`MIN_FINAL_CLTV_EXPIRY_DELTA`].
47
+ /// Note that LDK will add a buffer of 3 blocks to the delta to allow for up to a few new block
48
+ /// confirmations during routing.
49
+ ///
45
50
/// Note that the provided `keys_manager`'s `NodeSigner` implementation must support phantom
46
51
/// invoices in its `sign_invoice` implementation ([`PhantomKeysManager`] satisfies this
47
52
/// requirement).
@@ -51,6 +56,7 @@ use core::time::Duration;
51
56
/// [`ChannelManager::create_inbound_payment`]: lightning::ln::channelmanager::ChannelManager::create_inbound_payment
52
57
/// [`ChannelManager::create_inbound_payment_for_hash`]: lightning::ln::channelmanager::ChannelManager::create_inbound_payment_for_hash
53
58
/// [`PhantomRouteHints::channels`]: lightning::ln::channelmanager::PhantomRouteHints::channels
59
+ /// [`MIN_FINAL_CLTV_EXPIRY_DETLA`]: lightning::ln::channelmanager::MIN_FINAL_CLTV_EXPIRY_DELTA
54
60
pub fn create_phantom_invoice < ES : Deref , NS : Deref , L : Deref > (
55
61
amt_msat : Option < u64 > , payment_hash : Option < PaymentHash > , description : String ,
56
62
invoice_expiry_delta_secs : u32 , phantom_route_hints : Vec < PhantomRouteHints > , entropy_source : ES ,
@@ -137,7 +143,7 @@ where
137
143
) ) ;
138
144
}
139
145
140
- if min_final_cltv_expiry_delta. is_some ( ) && min_final_cltv_expiry_delta. unwrap ( ) < MIN_FINAL_CLTV_EXPIRY_DELTA {
146
+ if min_final_cltv_expiry_delta. is_some ( ) && min_final_cltv_expiry_delta. unwrap ( ) + 3 < MIN_FINAL_CLTV_EXPIRY_DELTA {
141
147
return Err ( SignOrCreationError :: CreationError ( CreationError :: MinFinalCltvExpiryDeltaTooShort ) ) ;
142
148
}
143
149
@@ -245,6 +251,8 @@ where
245
251
///
246
252
/// You can specify a custom `min_final_cltv_expiry_delta`, or let LDK default it to
247
253
/// [`MIN_FINAL_CLTV_EXPIRY_DELTA`]. The provided expiry must be at least [`MIN_FINAL_CLTV_EXPIRY_DELTA`].
254
+ /// Note that LDK will add a buffer of 3 blocks to the delta to allow for up to a few new block
255
+ /// confirmations during routing.
248
256
///
249
257
/// [`MIN_FINAL_CLTV_EXPIRY_DETLA`]: lightning::ln::channelmanager::MIN_FINAL_CLTV_EXPIRY_DELTA
250
258
pub fn create_invoice_from_channelmanager < M : Deref , T : Deref , ES : Deref , NS : Deref , SP : Deref , F : Deref , R : Deref , L : Deref > (
@@ -281,6 +289,13 @@ where
281
289
///
282
290
/// `invoice_expiry_delta_secs` describes the number of seconds that the invoice is valid for
283
291
/// in excess of the current time.
292
+ ///
293
+ /// You can specify a custom `min_final_cltv_expiry_delta`, or let LDK default it to
294
+ /// [`MIN_FINAL_CLTV_EXPIRY_DELTA`]. The provided expiry must be at least [`MIN_FINAL_CLTV_EXPIRY_DELTA`].
295
+ /// Note that LDK will add a buffer of 3 blocks to the delta to allow for up to a few new block
296
+ /// confirmations during routing.
297
+ ///
298
+ /// [`MIN_FINAL_CLTV_EXPIRY_DETLA`]: lightning::ln::channelmanager::MIN_FINAL_CLTV_EXPIRY_DELTA
284
299
pub fn create_invoice_from_channelmanager_with_description_hash < M : Deref , T : Deref , ES : Deref , NS : Deref , SP : Deref , F : Deref , R : Deref , L : Deref > (
285
300
channelmanager : & ChannelManager < M , T , ES , NS , SP , F , R , L > , node_signer : NS , logger : L ,
286
301
network : Currency , amt_msat : Option < u64 > , description_hash : Sha256 ,
@@ -375,7 +390,7 @@ fn _create_invoice_from_channelmanager_and_duration_since_epoch<M: Deref, T: Der
375
390
R :: Target : Router ,
376
391
L :: Target : Logger ,
377
392
{
378
- if min_final_cltv_expiry_delta. is_some ( ) && min_final_cltv_expiry_delta. unwrap ( ) < MIN_FINAL_CLTV_EXPIRY_DELTA {
393
+ if min_final_cltv_expiry_delta. is_some ( ) && min_final_cltv_expiry_delta. unwrap ( ) . saturating_add ( 3 ) < MIN_FINAL_CLTV_EXPIRY_DELTA {
379
394
return Err ( SignOrCreationError :: CreationError ( CreationError :: MinFinalCltvExpiryDeltaTooShort ) ) ;
380
395
}
381
396
@@ -440,6 +455,10 @@ fn _create_invoice_from_channelmanager_and_duration_since_epoch_with_payment_has
440
455
let our_node_pubkey = channelmanager. get_our_node_id ( ) ;
441
456
let channels = channelmanager. list_channels ( ) ;
442
457
458
+ if min_final_cltv_expiry_delta. is_some ( ) && min_final_cltv_expiry_delta. unwrap ( ) . saturating_add ( 3 ) < MIN_FINAL_CLTV_EXPIRY_DELTA {
459
+ return Err ( SignOrCreationError :: CreationError ( CreationError :: MinFinalCltvExpiryDeltaTooShort ) ) ;
460
+ }
461
+
443
462
log_trace ! ( logger, "Creating invoice with payment hash {}" , log_bytes!( payment_hash. 0 ) ) ;
444
463
445
464
let invoice = match description {
@@ -742,6 +761,44 @@ mod test {
742
761
assert_eq ! ( events. len( ) , 2 ) ;
743
762
}
744
763
764
+ fn do_create_invoice_min_final_cltv_delta ( with_custom_delta : bool ) {
765
+ let chanmon_cfgs = create_chanmon_cfgs ( 2 ) ;
766
+ let node_cfgs = create_node_cfgs ( 2 , & chanmon_cfgs) ;
767
+ let node_chanmgrs = create_node_chanmgrs ( 2 , & node_cfgs, & [ None , None ] ) ;
768
+ let nodes = create_network ( 2 , & node_cfgs, & node_chanmgrs) ;
769
+ let custom_min_final_cltv_expiry_delta = Some ( 50 ) ;
770
+
771
+ let invoice = crate :: utils:: create_invoice_from_channelmanager_and_duration_since_epoch (
772
+ & nodes[ 1 ] . node , nodes[ 1 ] . keys_manager , nodes[ 1 ] . logger , Currency :: BitcoinTestnet ,
773
+ Some ( 10_000 ) , "" . into ( ) , Duration :: from_secs ( 1234567 ) , 3600 ,
774
+ if with_custom_delta { custom_min_final_cltv_expiry_delta } else { None } ,
775
+ ) . unwrap ( ) ;
776
+ assert_eq ! ( invoice. min_final_cltv_expiry_delta( ) , if with_custom_delta {
777
+ custom_min_final_cltv_expiry_delta. unwrap( ) + 3 /* Buffer */ } else { MIN_FINAL_CLTV_EXPIRY_DELTA } as u64 ) ;
778
+ }
779
+
780
+ #[ test]
781
+ fn test_create_invoice_custom_min_final_cltv_delta ( ) {
782
+ do_create_invoice_min_final_cltv_delta ( true ) ;
783
+ do_create_invoice_min_final_cltv_delta ( false ) ;
784
+ }
785
+
786
+ #[ test]
787
+ fn create_invoice_min_final_cltv_delta_equals_htlc_fail_buffer ( ) {
788
+ let chanmon_cfgs = create_chanmon_cfgs ( 2 ) ;
789
+ let node_cfgs = create_node_cfgs ( 2 , & chanmon_cfgs) ;
790
+ let node_chanmgrs = create_node_chanmgrs ( 2 , & node_cfgs, & [ None , None ] ) ;
791
+ let nodes = create_network ( 2 , & node_cfgs, & node_chanmgrs) ;
792
+ let custom_min_final_cltv_expiry_delta = Some ( 21 ) ;
793
+
794
+ let invoice = crate :: utils:: create_invoice_from_channelmanager_and_duration_since_epoch (
795
+ & nodes[ 1 ] . node , nodes[ 1 ] . keys_manager , nodes[ 1 ] . logger , Currency :: BitcoinTestnet ,
796
+ Some ( 10_000 ) , "" . into ( ) , Duration :: from_secs ( 1234567 ) , 3600 ,
797
+ custom_min_final_cltv_expiry_delta,
798
+ ) . unwrap ( ) ;
799
+ assert_eq ! ( invoice. min_final_cltv_expiry_delta( ) , MIN_FINAL_CLTV_EXPIRY_DELTA as u64 ) ;
800
+ }
801
+
745
802
#[ test]
746
803
fn test_create_invoice_with_description_hash ( ) {
747
804
let chanmon_cfgs = create_chanmon_cfgs ( 2 ) ;
@@ -1542,7 +1599,7 @@ mod test {
1542
1599
let nodes = create_network ( 2 , & node_cfgs, & node_chanmgrs) ;
1543
1600
let result = crate :: utils:: create_invoice_from_channelmanager_and_duration_since_epoch (
1544
1601
& nodes[ 1 ] . node , nodes[ 1 ] . keys_manager , nodes[ 1 ] . logger , Currency :: BitcoinTestnet ,
1545
- Some ( 10_000 ) , "Some description" . into ( ) , Duration :: from_secs ( 1234567 ) , 3600 , Some ( MIN_FINAL_CLTV_EXPIRY_DELTA - 1 ) ,
1602
+ Some ( 10_000 ) , "Some description" . into ( ) , Duration :: from_secs ( 1234567 ) , 3600 , Some ( MIN_FINAL_CLTV_EXPIRY_DELTA - 4 ) ,
1546
1603
) ;
1547
1604
match result {
1548
1605
Err ( SignOrCreationError :: CreationError ( CreationError :: MinFinalCltvExpiryDeltaTooShort ) ) => { } ,
0 commit comments