@@ -271,6 +271,8 @@ where
271271 log_trace ! ( self . logger, "Payment {} rejected by destination; not retrying (attempts: {})" , log_bytes!( payment_hash. 0 ) , attempts) ;
272272 } else if * attempts == max_payment_attempts {
273273 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) ;
274276 } else if self . pay_cached_invoice ( invoice) . is_err ( ) {
275277 log_trace ! ( self . logger, "Error retrying payment {}; not retrying (attempts: {})" , log_bytes!( payment_hash. 0 ) , attempts) ;
276278 } else {
@@ -304,13 +306,14 @@ where
304306#[ cfg( test) ]
305307mod tests {
306308 use super :: * ;
307- use crate :: { InvoiceBuilder , Currency } ;
309+ use crate :: { DEFAULT_EXPIRY_TIME , InvoiceBuilder , Currency } ;
308310 use lightning:: ln:: PaymentPreimage ;
309311 use lightning:: ln:: msgs:: { ErrorAction , LightningError } ;
310312 use lightning:: util:: test_utils:: TestLogger ;
311313 use lightning:: util:: errors:: APIError ;
312314 use lightning:: util:: events:: Event ;
313315 use secp256k1:: { SecretKey , PublicKey , Secp256k1 } ;
316+ use std:: time:: { SystemTime , Duration } ;
314317
315318 fn invoice ( payment_preimage : PaymentPreimage ) -> Invoice {
316319 let payment_hash = Sha256 :: hash ( & payment_preimage. 0 ) ;
@@ -328,6 +331,25 @@ mod tests {
328331 . unwrap ( )
329332 }
330333
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+
331353 #[ test]
332354 fn pays_invoice_on_first_attempt ( ) {
333355 let event_handled = core:: cell:: RefCell :: new ( false ) ;
@@ -416,6 +438,34 @@ mod tests {
416438 assert_eq ! ( * payer. attempts. borrow( ) , 3 ) ;
417439 }
418440
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+
419469 #[ test]
420470 fn fails_paying_invoice_after_retry_error ( ) {
421471 let event_handled = core:: cell:: RefCell :: new ( false ) ;
0 commit comments