@@ -52,6 +52,8 @@ use crate::ln::onion_utils;
52
52
use crate :: ln:: onion_utils:: HTLCFailReason ;
53
53
use crate :: ln:: msgs:: { ChannelMessageHandler , DecodeError , LightningError , MAX_VALUE_MSAT } ;
54
54
use crate :: ln:: payment_retry:: { PaymentAttempts , Retry } ;
55
+ #[ cfg( feature = "std" ) ]
56
+ use crate :: ln:: payment_retry:: has_expired;
55
57
use crate :: ln:: wire:: Encode ;
56
58
use crate :: chain:: keysinterface:: { Sign , KeysInterface , KeysManager , Recipient } ;
57
59
use crate :: util:: config:: { UserConfig , ChannelConfig } ;
@@ -2607,6 +2609,47 @@ impl<M: Deref, T: Deref, K: Deref, F: Deref, R: Deref, L: Deref> ChannelManager<
2607
2609
self . send_payment_internal ( route, payment_hash, payment_secret, None , payment_id, None , onion_session_privs)
2608
2610
}
2609
2611
2612
+ /// Similar to [`ChannelManager::send_payment`], but will automatically find a route based on
2613
+ /// `route_params` and retry failed payment paths based on `retry_strategy`.
2614
+ pub fn send_payment_with_retry ( & self , payment_hash : PaymentHash , payment_secret : & Option < PaymentSecret > , payment_id : PaymentId , route_params : RouteParameters , retry_strategy : Retry ) -> Result < ( ) , PaymentSendFailure > {
2615
+ #[ cfg( feature = "std" ) ] {
2616
+ if has_expired ( & route_params) {
2617
+ log_trace ! ( self . logger, "Invoice expired prior to send for payment {}" , log_bytes!( payment_hash. 0 ) ) ;
2618
+ return Err ( PaymentSendFailure :: ParameterError ( APIError :: APIMisuseError { err : format ! ( "Invoice expired prior to send for payment {}" , log_bytes!( payment_hash. 0 ) ) } ) ) ;
2619
+ }
2620
+ }
2621
+
2622
+ let route = self . router . find_route (
2623
+ & self . get_our_node_id ( ) , & route_params, Some ( & self . list_usable_channels ( ) . iter ( ) . collect :: < Vec < _ > > ( ) ) ,
2624
+ self . compute_inflight_htlcs ( )
2625
+ ) . map_err ( |e| PaymentSendFailure :: ParameterError ( APIError :: APIMisuseError {
2626
+ err : format ! ( "Failed to find a route for payment {}: {:?}" , log_bytes!( payment_id. 0 ) , e) , // TODO: add APIError::RouteNotFound
2627
+ } ) ) ?;
2628
+
2629
+ log_trace ! ( self . logger, "Attempting to send payment with id {} and hash {} over route {}" , log_bytes!( payment_id. 0 ) , log_bytes!( payment_hash. 0 ) , log_route!( route) ) ;
2630
+ let onion_session_privs = self . add_new_pending_payment ( payment_hash, * payment_secret, payment_id, & route, retry_strategy) ?;
2631
+ match self . send_payment_internal ( & route, payment_hash, payment_secret, None , payment_id, None , onion_session_privs) {
2632
+ Err ( PaymentSendFailure :: AllFailedResendSafe ( _) ) => {
2633
+ self . retry_payment_auto_route ( payment_id, route_params)
2634
+ } ,
2635
+ Err ( PaymentSendFailure :: PartialFailure { failed_paths_retry, .. } ) => {
2636
+ if let Some ( retry_data) = failed_paths_retry {
2637
+ // Some paths were sent, even if we failed to send the full MPP value our recipient may
2638
+ // misbehave and claim the funds, at which point we have to consider the payment sent, so
2639
+ // return `Ok()` here, ignoring any retry errors.
2640
+ let _ = self . retry_payment_auto_route ( payment_id, retry_data) ;
2641
+ Ok ( ( ) )
2642
+ } else {
2643
+ // This may happen if we send a payment and some paths fail, but only due to a temporary
2644
+ // monitor failure or the like, implying they're really in-flight, but we haven't sent the
2645
+ // initial HTLC-Add messages yet.
2646
+ Ok ( ( ) )
2647
+ }
2648
+ } ,
2649
+ res => res,
2650
+ }
2651
+ }
2652
+
2610
2653
#[ cfg( test) ]
2611
2654
pub ( crate ) fn test_add_new_pending_payment ( & self , payment_hash : PaymentHash , payment_secret : Option < PaymentSecret > , payment_id : PaymentId , route : & Route ) -> Result < Vec < [ u8 ; 32 ] > , PaymentSendFailure > {
2612
2655
self . add_new_pending_payment ( payment_hash, payment_secret, payment_id, route, Retry :: Attempts ( 0 ) )
@@ -2732,16 +2775,58 @@ impl<M: Deref, T: Deref, K: Deref, F: Deref, R: Deref, L: Deref> ChannelManager<
2732
2775
} else { None } ,
2733
2776
} )
2734
2777
} else if has_err {
2735
- // If we failed to send any paths, we should remove the new PaymentId from the
2736
- // `pending_outbound_payments` map, as the user isn't expected to `abandon_payment`.
2737
- let removed = self . pending_outbound_payments . lock ( ) . unwrap ( ) . remove ( & payment_id) . is_some ( ) ;
2738
- debug_assert ! ( removed, "We should always have a pending payment to remove here" ) ;
2778
+ if !self . pending_outbound_payments . lock ( ) . unwrap ( ) . get ( & payment_id)
2779
+ . map_or ( false , |payment| payment. is_retryable ( ) )
2780
+ {
2781
+ // If we failed to send any paths, we should remove the new PaymentId from the
2782
+ // `pending_outbound_payments` map, as the user isn't expected to `abandon_payment`.
2783
+ let removed = self . pending_outbound_payments . lock ( ) . unwrap ( ) . remove ( & payment_id) . is_some ( ) ;
2784
+ debug_assert ! ( removed, "We should always have a pending payment to remove here" ) ;
2785
+ }
2739
2786
Err ( PaymentSendFailure :: AllFailedResendSafe ( results. drain ( ..) . map ( |r| r. unwrap_err ( ) ) . collect ( ) ) )
2740
2787
} else {
2741
2788
Ok ( ( ) )
2742
2789
}
2743
2790
}
2744
2791
2792
+ fn retry_payment_auto_route ( & self , payment_id : PaymentId , route_params : RouteParameters ) -> Result < ( ) , PaymentSendFailure > {
2793
+ #[ cfg( feature = "std" ) ] {
2794
+ if has_expired ( & route_params) {
2795
+ return Err ( PaymentSendFailure :: ParameterError ( APIError :: APIMisuseError {
2796
+ err : format ! ( "Invoice expired for payment id {}; not retrying" , log_bytes!( payment_id. 0 ) ) ,
2797
+ } ) )
2798
+ }
2799
+ }
2800
+
2801
+ self . pending_outbound_payments . lock ( ) . unwrap ( ) . get_mut ( & payment_id) . map ( |pmt| pmt. increment_attempts ( ) ) ;
2802
+ if !self . pending_outbound_payments . lock ( ) . unwrap ( ) . get ( & payment_id)
2803
+ . map_or ( false , |payment| payment. is_retryable ( ) )
2804
+ {
2805
+ return Err ( PaymentSendFailure :: ParameterError ( APIError :: APIMisuseError {
2806
+ err : format ! ( "Payment {} is not retryable" , log_bytes!( payment_id. 0 ) ) ,
2807
+ } ) )
2808
+ }
2809
+
2810
+ let route = self . router . find_route (
2811
+ & self . get_our_node_id ( ) , & route_params, Some ( & self . list_usable_channels ( ) . iter ( ) . collect :: < Vec < _ > > ( ) ) ,
2812
+ self . compute_inflight_htlcs ( )
2813
+ ) . map_err ( |e| PaymentSendFailure :: ParameterError ( APIError :: APIMisuseError {
2814
+ err : format ! ( "Failed to find a route for payment {}: {:?}" , log_bytes!( payment_id. 0 ) , e) , // TODO: add APIError::RouteNotFound
2815
+ } ) ) ?;
2816
+
2817
+ match self . retry_payment ( & route, payment_id) {
2818
+ Err ( PaymentSendFailure :: AllFailedResendSafe ( _) ) => {
2819
+ self . retry_payment_auto_route ( payment_id, route_params)
2820
+ } ,
2821
+ Err ( PaymentSendFailure :: PartialFailure { failed_paths_retry : Some ( retry) , .. } ) => {
2822
+ // Always return Ok for the same reason as noted in send_payment_with_retry.
2823
+ let _ = self . retry_payment_auto_route ( payment_id, retry) ;
2824
+ Ok ( ( ) )
2825
+ } ,
2826
+ res => res,
2827
+ }
2828
+ }
2829
+
2745
2830
/// Retries a payment along the given [`Route`].
2746
2831
///
2747
2832
/// Errors returned are a superset of those returned from [`send_payment`], so see
@@ -3600,6 +3685,17 @@ impl<M: Deref, T: Deref, K: Deref, F: Deref, R: Deref, L: Deref> ChannelManager<
3600
3685
}
3601
3686
}
3602
3687
}
3688
+ {
3689
+ let mut retryable_htlcs = Vec :: new ( ) ;
3690
+ mem:: swap ( & mut retryable_htlcs, & mut self . retryable_htlcs . lock ( ) . unwrap ( ) ) ;
3691
+ for ( payment_id, params) in retryable_htlcs {
3692
+ // TODO: do we need to generate a PendingHTLCsForwardable event?
3693
+ if let Err ( e) = self . retry_payment_auto_route ( payment_id, params) {
3694
+ log_trace ! ( self . logger, "Errored retrying payment, marking as abandoned: {:?}" , e) ;
3695
+ self . abandon_payment ( payment_id) ;
3696
+ }
3697
+ }
3698
+ }
3603
3699
3604
3700
for ( htlc_source, payment_hash, failure_reason, destination) in failed_forwards. drain ( ..) {
3605
3701
self . fail_htlc_backwards_internal ( & htlc_source, & payment_hash, & failure_reason, destination) ;
@@ -3966,7 +4062,8 @@ impl<M: Deref, T: Deref, K: Deref, F: Deref, R: Deref, L: Deref> ChannelManager<
3966
4062
let mut outbounds = self . pending_outbound_payments . lock ( ) . unwrap ( ) ;
3967
4063
let mut all_paths_failed = false ;
3968
4064
let mut full_failure_ev = None ;
3969
- if let hash_map:: Entry :: Occupied ( mut payment) = outbounds. entry ( * payment_id) {
4065
+ let mut pending_retry_ev = None ;
4066
+ let attempts_remaining = if let hash_map:: Entry :: Occupied ( mut payment) = outbounds. entry ( * payment_id) {
3970
4067
if !payment. get_mut ( ) . remove ( & session_priv_bytes, Some ( & path) ) {
3971
4068
log_trace ! ( self . logger, "Received duplicative fail for HTLC with payment_hash {}" , log_bytes!( payment_hash. 0 ) ) ;
3972
4069
return ;
@@ -3975,6 +4072,7 @@ impl<M: Deref, T: Deref, K: Deref, F: Deref, R: Deref, L: Deref> ChannelManager<
3975
4072
log_trace ! ( self . logger, "Received failure of HTLC with payment_hash {} after payment completion" , log_bytes!( payment_hash. 0 ) ) ;
3976
4073
return ;
3977
4074
}
4075
+ let is_retryable = payment. get ( ) . is_retryable ( ) ;
3978
4076
if payment. get ( ) . remaining_parts ( ) == 0 {
3979
4077
all_paths_failed = true ;
3980
4078
if payment. get ( ) . abandoned ( ) {
@@ -3985,10 +4083,11 @@ impl<M: Deref, T: Deref, K: Deref, F: Deref, R: Deref, L: Deref> ChannelManager<
3985
4083
payment. remove ( ) ;
3986
4084
}
3987
4085
}
4086
+ is_retryable
3988
4087
} else {
3989
4088
log_trace ! ( self . logger, "Received duplicative fail for HTLC with payment_hash {}" , log_bytes!( payment_hash. 0 ) ) ;
3990
4089
return ;
3991
- }
4090
+ } ;
3992
4091
let mut retry = if let Some ( payment_params_data) = payment_params {
3993
4092
let path_last_hop = path. last ( ) . expect ( "Outbound payments must have had a valid path" ) ;
3994
4093
Some ( RouteParameters {
@@ -4027,6 +4126,15 @@ impl<M: Deref, T: Deref, K: Deref, F: Deref, R: Deref, L: Deref> ChannelManager<
4027
4126
if let Some ( scid) = short_channel_id {
4028
4127
retry. as_mut ( ) . map ( |r| r. payment_params . previously_failed_channels . push ( scid) ) ;
4029
4128
}
4129
+ if payment_retryable && attempts_remaining {
4130
+ if let Some ( retry_params) = & retry {
4131
+ debug_assert ! ( full_failure_ev. is_none( ) ) ;
4132
+ pending_retry_ev = Some ( events:: Event :: PendingHTLCsForwardable {
4133
+ time_forwardable : Duration :: from_millis ( MIN_HTLC_RELAY_HOLDING_CELL_MILLIS ) ,
4134
+ } ) ;
4135
+ self . retryable_htlcs . lock ( ) . unwrap ( ) . push ( ( * payment_id, retry_params. clone ( ) ) ) ;
4136
+ }
4137
+ }
4030
4138
events:: Event :: PaymentPathFailed {
4031
4139
payment_id : Some ( * payment_id) ,
4032
4140
payment_hash : payment_hash. clone ( ) ,
@@ -4046,6 +4154,7 @@ impl<M: Deref, T: Deref, K: Deref, F: Deref, R: Deref, L: Deref> ChannelManager<
4046
4154
let mut pending_events = self . pending_events . lock ( ) . unwrap ( ) ;
4047
4155
pending_events. push ( path_failure) ;
4048
4156
if let Some ( ev) = full_failure_ev { pending_events. push ( ev) ; }
4157
+ if let Some ( ev) = pending_retry_ev { pending_events. push ( ev) ; }
4049
4158
} ,
4050
4159
HTLCSource :: PreviousHopData ( HTLCPreviousHopData { ref short_channel_id, ref htlc_id, ref incoming_packet_shared_secret, ref phantom_shared_secret, ref outpoint } ) => {
4051
4160
log_trace ! ( self . logger, "Failing HTLC with payment_hash {} backwards from us with {:?}" , log_bytes!( payment_hash. 0 ) , onion_error) ;
0 commit comments