@@ -15,10 +15,10 @@ use bitcoin::secp256k1::{self, Secp256k1, SecretKey};
15
15
16
16
use crate :: chain:: keysinterface:: { EntropySource , KeysInterface , NodeSigner , Recipient } ;
17
17
use crate :: ln:: { PaymentHash , PaymentPreimage , PaymentSecret } ;
18
- use crate :: ln:: channelmanager:: { HTLCSource , IDEMPOTENCY_TIMEOUT_TICKS , MIN_HTLC_RELAY_HOLDING_CELL_MILLIS , PaymentId } ;
18
+ use crate :: ln:: channelmanager:: { ChannelDetails , HTLCSource , IDEMPOTENCY_TIMEOUT_TICKS , MIN_HTLC_RELAY_HOLDING_CELL_MILLIS , PaymentId } ;
19
19
use crate :: ln:: msgs:: DecodeError ;
20
20
use crate :: ln:: onion_utils:: HTLCFailReason ;
21
- use crate :: routing:: router:: { PaymentParameters , Route , RouteHop , RouteParameters , RoutePath } ;
21
+ use crate :: routing:: router:: { InFlightHtlcs , PaymentParameters , Route , RouteHop , RouteParameters , RoutePath , Router } ;
22
22
use crate :: util:: errors:: APIError ;
23
23
use crate :: util:: events;
24
24
use crate :: util:: logger:: Logger ;
@@ -233,6 +233,16 @@ impl Retry {
233
233
}
234
234
}
235
235
236
+ #[ cfg( feature = "std" ) ]
237
+ pub ( crate ) fn has_expired ( route_params : & RouteParameters ) -> bool {
238
+ if let Some ( expiry_time) = route_params. payment_params . expiry_time {
239
+ if let Ok ( elapsed) = std:: time:: SystemTime :: UNIX_EPOCH . elapsed ( ) {
240
+ return elapsed > core:: time:: Duration :: from_secs ( expiry_time)
241
+ }
242
+ }
243
+ false
244
+ }
245
+
236
246
pub ( crate ) type PaymentAttempts = PaymentAttemptsUsingTime < ConfiguredTime > ;
237
247
238
248
/// Storing minimal payment attempts information required for determining if a outbound payment can
@@ -412,9 +422,55 @@ impl OutboundPayments {
412
422
}
413
423
}
414
424
425
+ pub ( super ) fn retry_payment < R : Deref , K : Deref , F > ( & self , payment_id : PaymentId ,
426
+ route_params : RouteParameters , router : & R , first_hops : Vec < ChannelDetails > ,
427
+ inflight_htlcs : InFlightHtlcs , keys_manager : & K , best_block_height : u32 ,
428
+ send_payment_along_path : F ) -> Result < ( ) , PaymentSendFailure >
429
+ where
430
+ R :: Target : Router ,
431
+ K :: Target : KeysInterface ,
432
+ F : Fn ( & Vec < RouteHop > , & Option < PaymentParameters > , & PaymentHash , & Option < PaymentSecret > , u64 ,
433
+ u32 , PaymentId , & Option < PaymentPreimage > , [ u8 ; 32 ] ) -> Result < ( ) , APIError >
434
+ {
435
+ #[ cfg( feature = "std" ) ] {
436
+ if has_expired ( & route_params) {
437
+ return Err ( PaymentSendFailure :: ParameterError ( APIError :: APIMisuseError {
438
+ err : format ! ( "Invoice expired for payment id {}; not retrying" , log_bytes!( payment_id. 0 ) ) ,
439
+ } ) )
440
+ }
441
+ }
442
+
443
+ self . pending_outbound_payments . lock ( ) . unwrap ( ) . get_mut ( & payment_id) . map ( |pmt| pmt. increment_attempts ( ) ) ;
444
+ if !self . pending_outbound_payments . lock ( ) . unwrap ( ) . get ( & payment_id)
445
+ . map_or ( false , |payment| payment. is_retryable ( ) )
446
+ {
447
+ return Err ( PaymentSendFailure :: ParameterError ( APIError :: APIMisuseError {
448
+ err : format ! ( "Payment {} is not retryable" , log_bytes!( payment_id. 0 ) ) ,
449
+ } ) )
450
+ }
451
+
452
+ let route = router. find_route (
453
+ & keys_manager. get_node_id ( Recipient :: Node ) . unwrap ( ) , & route_params,
454
+ Some ( & first_hops. iter ( ) . collect :: < Vec < _ > > ( ) ) , & inflight_htlcs
455
+ ) . map_err ( |e| PaymentSendFailure :: ParameterError ( APIError :: APIMisuseError {
456
+ err : format ! ( "Failed to find a route for payment {}: {:?}" , log_bytes!( payment_id. 0 ) , e) , // TODO: add APIError::RouteNotFound
457
+ } ) ) ?;
458
+
459
+ match self . retry_payment_with_route ( & route, payment_id, keys_manager, best_block_height, & send_payment_along_path) {
460
+ Err ( PaymentSendFailure :: AllFailedResendSafe ( _) ) => {
461
+ self . retry_payment ( payment_id, route_params, router, first_hops, inflight_htlcs, keys_manager, best_block_height, send_payment_along_path)
462
+ } ,
463
+ Err ( PaymentSendFailure :: PartialFailure { failed_paths_retry : Some ( retry) , .. } ) => {
464
+ let _ = self . retry_payment ( payment_id, retry, router, first_hops, inflight_htlcs, keys_manager, best_block_height, send_payment_along_path) ;
465
+ Ok ( ( ) )
466
+ } ,
467
+ res => res,
468
+ }
469
+ }
470
+
415
471
pub ( super ) fn retry_payment_with_route < K : Deref , F > (
416
472
& self , route : & Route , payment_id : PaymentId , keys_manager : & K , best_block_height : u32 ,
417
- send_payment_along_path : F
473
+ send_payment_along_path : & F
418
474
) -> Result < ( ) , PaymentSendFailure >
419
475
where
420
476
K :: Target : KeysInterface ,
0 commit comments