@@ -270,6 +270,8 @@ where
270
270
log_trace ! ( self . logger, "Payment {} rejected by destination; not retrying (attempts: {})" , log_bytes!( payment_hash. 0 ) , attempts) ;
271
271
} else if * attempts == max_payment_attempts {
272
272
log_trace ! ( self . logger, "Payment {} failed; not retrying (attempts: {})" , log_bytes!( payment_hash. 0 ) , attempts) ;
273
+ } else if invoice. is_expired ( ) {
274
+ log_trace ! ( self . logger, "Invoice expired for payment {}; not retrying (attempts: {})" , log_bytes!( payment_hash. 0 ) , attempts) ;
273
275
} else if self . pay_cached_invoice ( invoice) . is_err ( ) {
274
276
log_trace ! ( self . logger, "Error retrying payment {}; not retrying (attempts: {})" , log_bytes!( payment_hash. 0 ) , attempts) ;
275
277
} else {
@@ -303,13 +305,14 @@ where
303
305
#[ cfg( test) ]
304
306
mod tests {
305
307
use super :: * ;
306
- use crate :: { InvoiceBuilder , Currency } ;
308
+ use crate :: { DEFAULT_EXPIRY_TIME , InvoiceBuilder , Currency } ;
307
309
use lightning:: ln:: PaymentPreimage ;
308
310
use lightning:: ln:: msgs:: { ErrorAction , LightningError } ;
309
311
use lightning:: util:: test_utils:: TestLogger ;
310
312
use lightning:: util:: errors:: APIError ;
311
313
use lightning:: util:: events:: Event ;
312
314
use secp256k1:: { SecretKey , PublicKey , Secp256k1 } ;
315
+ use std:: time:: { SystemTime , Duration } ;
313
316
314
317
fn invoice ( payment_preimage : PaymentPreimage ) -> Invoice {
315
318
let payment_hash = Sha256 :: hash ( & payment_preimage. 0 ) ;
@@ -327,6 +330,25 @@ mod tests {
327
330
. unwrap ( )
328
331
}
329
332
333
+ fn expired_invoice ( payment_preimage : PaymentPreimage ) -> Invoice {
334
+ let payment_hash = Sha256 :: hash ( & payment_preimage. 0 ) ;
335
+ let private_key = SecretKey :: from_slice ( & [ 42 ; 32 ] ) . unwrap ( ) ;
336
+ let timestamp = SystemTime :: now ( )
337
+ . checked_sub ( Duration :: from_secs ( DEFAULT_EXPIRY_TIME * 2 ) )
338
+ . unwrap ( ) ;
339
+ InvoiceBuilder :: new ( Currency :: Bitcoin )
340
+ . description ( "test" . into ( ) )
341
+ . payment_hash ( payment_hash)
342
+ . payment_secret ( PaymentSecret ( [ 0 ; 32 ] ) )
343
+ . timestamp ( timestamp)
344
+ . min_final_cltv_expiry ( 144 )
345
+ . amount_milli_satoshis ( 100 )
346
+ . build_signed ( |hash| {
347
+ Secp256k1 :: new ( ) . sign_recoverable ( hash, & private_key)
348
+ } )
349
+ . unwrap ( )
350
+ }
351
+
330
352
#[ test]
331
353
fn pays_invoice_on_first_attempt ( ) {
332
354
let event_handled = core:: cell:: RefCell :: new ( false ) ;
@@ -415,6 +437,34 @@ mod tests {
415
437
assert_eq ! ( * payer. attempts. borrow( ) , 3 ) ;
416
438
}
417
439
440
+ #[ test]
441
+ fn fails_paying_invoice_after_expiration ( ) {
442
+ let event_handled = core:: cell:: RefCell :: new ( false ) ;
443
+ let event_handler = |_: & _ | { * event_handled. borrow_mut ( ) = true ; } ;
444
+
445
+ let payer = TestPayer :: new ( ) ;
446
+ let router = NullRouter { } ;
447
+ let logger = TestLogger :: new ( ) ;
448
+ let invoice_payer = InvoicePayer :: new ( & payer, router, & logger, event_handler)
449
+ . with_retry_attempts ( 2 ) ;
450
+
451
+ let payment_preimage = PaymentPreimage ( [ 1 ; 32 ] ) ;
452
+ let invoice = expired_invoice ( payment_preimage) ;
453
+ assert ! ( invoice_payer. pay_invoice( & invoice) . is_ok( ) ) ;
454
+ assert_eq ! ( * payer. attempts. borrow( ) , 1 ) ;
455
+
456
+ let event = Event :: PaymentPathFailed {
457
+ payment_hash : PaymentHash ( invoice. payment_hash ( ) . clone ( ) . into_inner ( ) ) ,
458
+ network_update : None ,
459
+ rejected_by_dest : false ,
460
+ all_paths_failed : true ,
461
+ path : vec ! [ ] ,
462
+ } ;
463
+ invoice_payer. handle_event ( & event) ;
464
+ assert_eq ! ( * event_handled. borrow( ) , true ) ;
465
+ assert_eq ! ( * payer. attempts. borrow( ) , 1 ) ;
466
+ }
467
+
418
468
#[ test]
419
469
fn fails_paying_invoice_after_retry_error ( ) {
420
470
let event_handled = core:: cell:: RefCell :: new ( false ) ;
0 commit comments