@@ -928,7 +928,16 @@ pub enum PaymentSendFailure {
928
928
/// as they will result in over-/re-payment. These HTLCs all either successfully sent (in the
929
929
/// case of Ok(())) or will send once channel_monitor_updated is called on the next-hop channel
930
930
/// with the latest update_id.
931
- PartialFailure ( Vec < Result < ( ) , APIError > > ) ,
931
+ PartialFailure {
932
+ /// The errors themselves, in the same order as the route hops.
933
+ results : Vec < Result < ( ) , APIError > > ,
934
+ /// If some paths failed without irrevocably committing to the new HTLC(s), this will
935
+ /// contain a [`RouteParameters`] object which can be used to calculate a new route that
936
+ /// will pay all remaining unpaid balance.
937
+ failed_paths_retry : Option < RouteParameters > ,
938
+ /// The payment id for the payment, which is now at least partially pending.
939
+ payment_id : PaymentId ,
940
+ } ,
932
941
}
933
942
934
943
macro_rules! handle_error {
@@ -2217,7 +2226,9 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
2217
2226
}
2218
2227
let mut has_ok = false ;
2219
2228
let mut has_err = false ;
2220
- for res in results. iter ( ) {
2229
+ let mut pending_amt_unsent = 0 ;
2230
+ let mut max_unsent_cltv_delta = 0 ;
2231
+ for ( res, path) in results. iter ( ) . zip ( route. paths . iter ( ) ) {
2221
2232
if res. is_ok ( ) { has_ok = true ; }
2222
2233
if res. is_err ( ) { has_err = true ; }
2223
2234
if let & Err ( APIError :: MonitorUpdateFailed ) = res {
@@ -2226,10 +2237,25 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
2226
2237
has_err = true ;
2227
2238
has_ok = true ;
2228
2239
break ;
2240
+ } else if res. is_err ( ) {
2241
+ pending_amt_unsent += path. last ( ) . unwrap ( ) . fee_msat ;
2242
+ max_unsent_cltv_delta = cmp:: max ( max_unsent_cltv_delta, path. last ( ) . unwrap ( ) . cltv_expiry_delta ) ;
2229
2243
}
2230
2244
}
2231
2245
if has_err && has_ok {
2232
- Err ( PaymentSendFailure :: PartialFailure ( results) )
2246
+ Err ( PaymentSendFailure :: PartialFailure {
2247
+ results,
2248
+ payment_id,
2249
+ failed_paths_retry : if pending_amt_unsent != 0 {
2250
+ if let Some ( payee) = & route. payee {
2251
+ Some ( RouteParameters {
2252
+ payee : payee. clone ( ) ,
2253
+ final_value_msat : pending_amt_unsent,
2254
+ final_cltv_expiry_delta : max_unsent_cltv_delta,
2255
+ } )
2256
+ } else { None }
2257
+ } else { None } ,
2258
+ } )
2233
2259
} else if has_err {
2234
2260
Err ( PaymentSendFailure :: AllFailedRetrySafe ( results. drain ( ..) . map ( |r| r. unwrap_err ( ) ) . collect ( ) ) )
2235
2261
} else {
0 commit comments