@@ -929,7 +929,16 @@ pub enum PaymentSendFailure {
929929 /// as they will result in over-/re-payment. These HTLCs all either successfully sent (in the
930930 /// case of Ok(())) or will send once channel_monitor_updated is called on the next-hop channel
931931 /// with the latest update_id.
932- PartialFailure ( Vec < Result < ( ) , APIError > > ) ,
932+ PartialFailure {
933+ /// The errors themselves, in the same order as the route hops.
934+ results : Vec < Result < ( ) , APIError > > ,
935+ /// If some paths failed without irrevocably committing to the new HTLC(s), this will
936+ /// contain a [`RouteParameters`] object which can be used to calculate a new route that
937+ /// will pay all remaining unpaid balance.
938+ failed_paths_retry : Option < RouteParameters > ,
939+ /// The payment id for the payment, which is now at least partially pending.
940+ payment_id : PaymentId ,
941+ } ,
933942}
934943
935944macro_rules! handle_error {
@@ -2218,19 +2227,35 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
22182227 }
22192228 let mut has_ok = false ;
22202229 let mut has_err = false ;
2221- for res in results. iter ( ) {
2230+ let mut pending_amt_unsent = 0 ;
2231+ let mut max_unsent_cltv_delta = 0 ;
2232+ for ( res, path) in results. iter ( ) . zip ( route. paths . iter ( ) ) {
22222233 if res. is_ok ( ) { has_ok = true ; }
22232234 if res. is_err ( ) { has_err = true ; }
22242235 if let & Err ( APIError :: MonitorUpdateFailed ) = res {
22252236 // MonitorUpdateFailed is inherently unsafe to retry, so we call it a
22262237 // PartialFailure.
22272238 has_err = true ;
22282239 has_ok = true ;
2229- 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 ) ;
22302243 }
22312244 }
22322245 if has_err && has_ok {
2233- 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+ } )
22342259 } else if has_err {
22352260 Err ( PaymentSendFailure :: AllFailedRetrySafe ( results. drain ( ..) . map ( |r| r. unwrap_err ( ) ) . collect ( ) ) )
22362261 } else {
0 commit comments