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