@@ -235,9 +235,12 @@ where
235
235
///
236
236
/// `invoice_expiry_delta_secs` describes the number of seconds that the invoice is valid for
237
237
/// in excess of the current time.
238
+ /// You can specify a custom `min_final_cltv_expiry_delta`, or let LDK default it to
239
+ /// `MIN_FINAL_CLTV_EXPIRY_DELTA`. The provided expiry must be at least `MIN_FINAL_CLTV_EXPIRY_DELTA`.
238
240
pub fn create_invoice_from_channelmanager < M : Deref , T : Deref , K : Deref , F : Deref , L : Deref > (
239
241
channelmanager : & ChannelManager < M , T , K , F , L > , keys_manager : K , logger : L ,
240
- network : Currency , amt_msat : Option < u64 > , description : String , invoice_expiry_delta_secs : u32
242
+ network : Currency , amt_msat : Option < u64 > , description : String , invoice_expiry_delta_secs : u32 ,
243
+ min_final_cltv_expiry_delta : Option < u32 > ,
241
244
) -> Result < Invoice , SignOrCreationError < ( ) > >
242
245
where
243
246
M :: Target : chain:: Watch < <K :: Target as KeysInterface >:: Signer > ,
@@ -251,7 +254,7 @@ where
251
254
. expect ( "for the foreseeable future this shouldn't happen" ) ;
252
255
create_invoice_from_channelmanager_and_duration_since_epoch (
253
256
channelmanager, keys_manager, logger, network, amt_msat, description, duration,
254
- invoice_expiry_delta_secs
257
+ invoice_expiry_delta_secs, min_final_cltv_expiry_delta ,
255
258
)
256
259
}
257
260
@@ -268,7 +271,7 @@ where
268
271
pub fn create_invoice_from_channelmanager_with_description_hash < M : Deref , T : Deref , K : Deref , F : Deref , L : Deref > (
269
272
channelmanager : & ChannelManager < M , T , K , F , L > , keys_manager : K , logger : L ,
270
273
network : Currency , amt_msat : Option < u64 > , description_hash : Sha256 ,
271
- invoice_expiry_delta_secs : u32
274
+ invoice_expiry_delta_secs : u32 , min_final_cltv_expiry_delta : Option < u32 > ,
272
275
) -> Result < Invoice , SignOrCreationError < ( ) > >
273
276
where
274
277
M :: Target : chain:: Watch < <K :: Target as KeysInterface >:: Signer > ,
@@ -285,7 +288,7 @@ where
285
288
286
289
create_invoice_from_channelmanager_with_description_hash_and_duration_since_epoch (
287
290
channelmanager, keys_manager, logger, network, amt_msat,
288
- description_hash, duration, invoice_expiry_delta_secs
291
+ description_hash, duration, invoice_expiry_delta_secs, min_final_cltv_expiry_delta ,
289
292
)
290
293
}
291
294
@@ -295,7 +298,7 @@ where
295
298
pub fn create_invoice_from_channelmanager_with_description_hash_and_duration_since_epoch < M : Deref , T : Deref , K : Deref , F : Deref , L : Deref > (
296
299
channelmanager : & ChannelManager < M , T , K , F , L > , keys_manager : K , logger : L ,
297
300
network : Currency , amt_msat : Option < u64 > , description_hash : Sha256 ,
298
- duration_since_epoch : Duration , invoice_expiry_delta_secs : u32
301
+ duration_since_epoch : Duration , invoice_expiry_delta_secs : u32 , min_final_cltv_expiry_delta : Option < u32 > ,
299
302
) -> Result < Invoice , SignOrCreationError < ( ) > >
300
303
where
301
304
M :: Target : chain:: Watch < <K :: Target as KeysInterface >:: Signer > ,
@@ -307,7 +310,7 @@ where
307
310
_create_invoice_from_channelmanager_and_duration_since_epoch (
308
311
channelmanager, keys_manager, logger, network, amt_msat,
309
312
InvoiceDescription :: Hash ( & description_hash) ,
310
- duration_since_epoch, invoice_expiry_delta_secs
313
+ duration_since_epoch, invoice_expiry_delta_secs, min_final_cltv_expiry_delta ,
311
314
)
312
315
}
313
316
@@ -317,7 +320,7 @@ where
317
320
pub fn create_invoice_from_channelmanager_and_duration_since_epoch < M : Deref , T : Deref , K : Deref , F : Deref , L : Deref > (
318
321
channelmanager : & ChannelManager < M , T , K , F , L > , keys_manager : K , logger : L ,
319
322
network : Currency , amt_msat : Option < u64 > , description : String , duration_since_epoch : Duration ,
320
- invoice_expiry_delta_secs : u32
323
+ invoice_expiry_delta_secs : u32 , min_final_cltv_expiry_delta : Option < u32 > ,
321
324
) -> Result < Invoice , SignOrCreationError < ( ) > >
322
325
where
323
326
M :: Target : chain:: Watch < <K :: Target as KeysInterface >:: Signer > ,
@@ -331,14 +334,14 @@ where
331
334
InvoiceDescription :: Direct (
332
335
& Description :: new ( description) . map_err ( SignOrCreationError :: CreationError ) ?,
333
336
) ,
334
- duration_since_epoch, invoice_expiry_delta_secs
337
+ duration_since_epoch, invoice_expiry_delta_secs, min_final_cltv_expiry_delta ,
335
338
)
336
339
}
337
340
338
341
fn _create_invoice_from_channelmanager_and_duration_since_epoch < M : Deref , T : Deref , K : Deref , F : Deref , L : Deref > (
339
342
channelmanager : & ChannelManager < M , T , K , F , L > , keys_manager : K , logger : L ,
340
343
network : Currency , amt_msat : Option < u64 > , description : InvoiceDescription ,
341
- duration_since_epoch : Duration , invoice_expiry_delta_secs : u32
344
+ duration_since_epoch : Duration , invoice_expiry_delta_secs : u32 , min_final_cltv_expiry_delta : Option < u32 > ,
342
345
) -> Result < Invoice , SignOrCreationError < ( ) > >
343
346
where
344
347
M :: Target : chain:: Watch < <K :: Target as KeysInterface >:: Signer > ,
@@ -347,6 +350,10 @@ where
347
350
F :: Target : FeeEstimator ,
348
351
L :: Target : Logger ,
349
352
{
353
+ if min_final_cltv_expiry_delta. is_some ( ) && min_final_cltv_expiry_delta. unwrap ( ) < MIN_FINAL_CLTV_EXPIRY_DELTA {
354
+ return Err ( SignOrCreationError :: CreationError ( CreationError :: MinFinalCltvExpiryDeltaTooShort ) ) ;
355
+ }
356
+
350
357
// `create_inbound_payment` only returns an error if the amount is greater than the total bitcoin
351
358
// supply.
352
359
let ( payment_hash, payment_secret) = channelmanager
@@ -370,7 +377,7 @@ where
370
377
. payment_hash ( Hash :: from_slice ( & payment_hash. 0 ) . unwrap ( ) )
371
378
. payment_secret ( payment_secret)
372
379
. basic_mpp ( )
373
- . min_final_cltv_expiry_delta ( MIN_FINAL_CLTV_EXPIRY_DELTA . into ( ) )
380
+ . min_final_cltv_expiry_delta ( min_final_cltv_expiry_delta . unwrap_or ( MIN_FINAL_CLTV_EXPIRY_DELTA ) . into ( ) )
374
381
. expiry_time ( Duration :: from_secs ( invoice_expiry_delta_secs. into ( ) ) ) ;
375
382
if let Some ( amt) = amt_msat {
376
383
invoice = invoice. amount_milli_satoshis ( amt) ;
@@ -683,7 +690,7 @@ impl<'a, S: Score> Score for ScorerAccountingForInFlightHtlcs<'a, S> {
683
690
#[ cfg( test) ]
684
691
mod test {
685
692
use core:: time:: Duration ;
686
- use crate :: { Currency , Description , InvoiceDescription } ;
693
+ use crate :: { Currency , Description , InvoiceDescription , SignOrCreationError , CreationError } ;
687
694
use bitcoin_hashes:: Hash ;
688
695
use bitcoin_hashes:: sha256:: Hash as Sha256 ;
689
696
use lightning:: chain:: keysinterface:: PhantomKeysManager ;
@@ -710,8 +717,9 @@ mod test {
710
717
let invoice = create_invoice_from_channelmanager_and_duration_since_epoch (
711
718
& nodes[ 1 ] . node , nodes[ 1 ] . keys_manager , nodes[ 1 ] . logger , Currency :: BitcoinTestnet ,
712
719
Some ( 10_000 ) , "test" . to_string ( ) , Duration :: from_secs ( 1234567 ) ,
713
- non_default_invoice_expiry_secs) . unwrap ( ) ;
720
+ non_default_invoice_expiry_secs, None ) . unwrap ( ) ;
714
721
assert_eq ! ( invoice. amount_pico_btc( ) , Some ( 100_000 ) ) ;
722
+ // If no `min_final_cltv_expiry_delta` is specified, then it should be `MIN_FINAL_CLTV_EXPIRY_DELTA`.
715
723
assert_eq ! ( invoice. min_final_cltv_expiry_delta( ) , MIN_FINAL_CLTV_EXPIRY_DELTA as u64 ) ;
716
724
assert_eq ! ( invoice. description( ) , InvoiceDescription :: Direct ( & Description ( "test" . to_string( ) ) ) ) ;
717
725
assert_eq ! ( invoice. expiry_time( ) , Duration :: from_secs( non_default_invoice_expiry_secs. into( ) ) ) ;
@@ -775,7 +783,7 @@ mod test {
775
783
let description_hash = crate :: Sha256 ( Hash :: hash ( "Testing description_hash" . as_bytes ( ) ) ) ;
776
784
let invoice = crate :: utils:: create_invoice_from_channelmanager_with_description_hash_and_duration_since_epoch (
777
785
& nodes[ 1 ] . node , nodes[ 1 ] . keys_manager , nodes[ 1 ] . logger , Currency :: BitcoinTestnet ,
778
- Some ( 10_000 ) , description_hash, Duration :: from_secs ( 1234567 ) , 3600
786
+ Some ( 10_000 ) , description_hash, Duration :: from_secs ( 1234567 ) , 3600 , None ,
779
787
) . unwrap ( ) ;
780
788
assert_eq ! ( invoice. amount_pico_btc( ) , Some ( 100_000 ) ) ;
781
789
assert_eq ! ( invoice. min_final_cltv_expiry_delta( ) , MIN_FINAL_CLTV_EXPIRY_DELTA as u64 ) ;
@@ -967,7 +975,7 @@ mod test {
967
975
let invoice = create_invoice_from_channelmanager_and_duration_since_epoch (
968
976
& invoice_node. node , invoice_node. keys_manager , invoice_node. logger ,
969
977
Currency :: BitcoinTestnet , invoice_amt, "test" . to_string ( ) , Duration :: from_secs ( 1234567 ) ,
970
- 3600 ) . unwrap ( ) ;
978
+ 3600 , None ) . unwrap ( ) ;
971
979
let hints = invoice. private_routes ( ) ;
972
980
973
981
for hint in hints {
@@ -1494,4 +1502,33 @@ mod test {
1494
1502
}
1495
1503
assert ! ( chan_ids_to_match. is_empty( ) , "Unmatched short channel ids: {:?}" , chan_ids_to_match) ;
1496
1504
}
1505
+
1506
+ #[ test]
1507
+ fn test_create_invoice_with_valid_custom_min_final_cltv_expiry_delta ( ) {
1508
+ let chanmon_cfgs = create_chanmon_cfgs ( 2 ) ;
1509
+ let node_cfgs = create_node_cfgs ( 2 , & chanmon_cfgs) ;
1510
+ let node_chanmgrs = create_node_chanmgrs ( 2 , & node_cfgs, & [ None , None ] ) ;
1511
+ let nodes = create_network ( 2 , & node_cfgs, & node_chanmgrs) ;
1512
+ let invoice = crate :: utils:: create_invoice_from_channelmanager_and_duration_since_epoch (
1513
+ & nodes[ 1 ] . node , nodes[ 1 ] . keys_manager , nodes[ 1 ] . logger , Currency :: BitcoinTestnet ,
1514
+ Some ( 10_000 ) , "Some description" . into ( ) , Duration :: from_secs ( 1234567 ) , 3600 , Some ( 30 ) ,
1515
+ ) . unwrap ( ) ;
1516
+ assert_eq ! ( invoice. min_final_cltv_expiry_delta( ) , 30 as u64 ) ;
1517
+ }
1518
+
1519
+ #[ test]
1520
+ fn test_create_invoice_fails_with_invalid_custom_min_final_cltv_expiry_delta ( ) {
1521
+ let chanmon_cfgs = create_chanmon_cfgs ( 2 ) ;
1522
+ let node_cfgs = create_node_cfgs ( 2 , & chanmon_cfgs) ;
1523
+ let node_chanmgrs = create_node_chanmgrs ( 2 , & node_cfgs, & [ None , None ] ) ;
1524
+ let nodes = create_network ( 2 , & node_cfgs, & node_chanmgrs) ;
1525
+ let result = crate :: utils:: create_invoice_from_channelmanager_and_duration_since_epoch (
1526
+ & nodes[ 1 ] . node , nodes[ 1 ] . keys_manager , nodes[ 1 ] . logger , Currency :: BitcoinTestnet ,
1527
+ Some ( 10_000 ) , "Some description" . into ( ) , Duration :: from_secs ( 1234567 ) , 3600 , Some ( MIN_FINAL_CLTV_EXPIRY_DELTA - 1 ) ,
1528
+ ) ;
1529
+ match result {
1530
+ Err ( SignOrCreationError :: CreationError ( CreationError :: MinFinalCltvExpiryDeltaTooShort ) ) => { } ,
1531
+ _ => panic ! ( ) ,
1532
+ }
1533
+ }
1497
1534
}
0 commit comments