@@ -527,9 +527,9 @@ impl OutboundPayments {
527527 let mut retry_id_route_params = None ;
528528 for ( pmt_id, pmt) in outbounds. iter_mut ( ) {
529529 if pmt. is_auto_retryable_now ( ) {
530- if let PendingOutboundPayment :: Retryable { payment_hash , pending_amt_msat, total_msat, payment_params : Some ( params) , .. } = pmt {
530+ if let PendingOutboundPayment :: Retryable { pending_amt_msat, total_msat, payment_params : Some ( params) , .. } = pmt {
531531 if pending_amt_msat < total_msat {
532- retry_id_route_params = Some ( ( * pmt_id, * payment_hash , RouteParameters {
532+ retry_id_route_params = Some ( ( * pmt_id, RouteParameters {
533533 final_value_msat : * total_msat - * pending_amt_msat,
534534 final_cltv_expiry_delta :
535535 if let Some ( delta) = params. final_cltv_expiry_delta { delta }
@@ -545,8 +545,8 @@ impl OutboundPayments {
545545 }
546546 }
547547 core:: mem:: drop ( outbounds) ;
548- if let Some ( ( payment_id, payment_hash , route_params) ) = retry_id_route_params {
549- self . retry_payment_internal ( payment_id, payment_hash , route_params, router, first_hops ( ) , & inflight_htlcs, entropy_source, node_signer, best_block_height, logger, pending_events, & send_payment_along_path)
548+ if let Some ( ( payment_id, route_params) ) = retry_id_route_params {
549+ self . retry_payment_internal ( payment_id, route_params, router, first_hops ( ) , & inflight_htlcs, entropy_source, node_signer, best_block_height, logger, pending_events, & send_payment_along_path)
550550 } else { break }
551551 }
552552
@@ -619,10 +619,10 @@ impl OutboundPayments {
619619 }
620620
621621 fn retry_payment_internal < R : Deref , NS : Deref , ES : Deref , IH , SP , L : Deref > (
622- & self , payment_id : PaymentId , payment_hash : PaymentHash , route_params : RouteParameters ,
623- router : & R , first_hops : Vec < ChannelDetails > , inflight_htlcs : & IH , entropy_source : & ES ,
624- node_signer : & NS , best_block_height : u32 , logger : & L ,
625- pending_events : & Mutex < Vec < events :: Event > > , send_payment_along_path : & SP ,
622+ & self , payment_id : PaymentId , route_params : RouteParameters , router : & R ,
623+ first_hops : Vec < ChannelDetails > , inflight_htlcs : & IH , entropy_source : & ES , node_signer : & NS ,
624+ best_block_height : u32 , logger : & L , pending_events : & Mutex < Vec < events :: Event > > ,
625+ send_payment_along_path : & SP ,
626626 )
627627 where
628628 R :: Target : Router ,
@@ -652,9 +652,81 @@ impl OutboundPayments {
652652 return
653653 }
654654 } ;
655+ for path in route. paths . iter ( ) {
656+ if path. len ( ) == 0 {
657+ log_error ! ( logger, "length-0 path in route" ) ;
658+ self . abandon_payment ( payment_id, pending_events) ;
659+ return
660+ }
661+ }
655662
656- let res = self . retry_payment_with_route ( & route, payment_id, entropy_source, node_signer,
657- best_block_height, send_payment_along_path) ;
663+ const RETRY_OVERFLOW_PERCENTAGE : u64 = 10 ;
664+ let mut onion_session_privs = Vec :: with_capacity ( route. paths . len ( ) ) ;
665+ for _ in 0 ..route. paths . len ( ) {
666+ onion_session_privs. push ( entropy_source. get_secure_random_bytes ( ) ) ;
667+ }
668+
669+ macro_rules! abandon_with_entry {
670+ ( $payment_id: expr, $payment_hash: expr, $payment: expr, $pending_events: expr) => {
671+ if $payment. get_mut( ) . mark_abandoned( ) . is_ok( ) && $payment. get( ) . remaining_parts( ) == 0 {
672+ $pending_events. lock( ) . unwrap( ) . push( events:: Event :: PaymentFailed {
673+ payment_id: $payment_id,
674+ payment_hash: $payment_hash,
675+ } ) ;
676+ $payment. remove( ) ;
677+ }
678+ }
679+ }
680+ let ( total_msat, payment_hash, payment_secret, keysend_preimage) = {
681+ let mut outbounds = self . pending_outbound_payments . lock ( ) . unwrap ( ) ;
682+ match outbounds. entry ( payment_id) {
683+ hash_map:: Entry :: Occupied ( mut payment) => {
684+ let res = match payment. get ( ) {
685+ PendingOutboundPayment :: Retryable {
686+ total_msat, payment_hash, keysend_preimage, payment_secret, pending_amt_msat, ..
687+ } => {
688+ let retry_amt_msat: u64 = route. paths . iter ( ) . map ( |path| path. last ( ) . unwrap ( ) . fee_msat ) . sum ( ) ;
689+ if retry_amt_msat + * pending_amt_msat > * total_msat * ( 100 + RETRY_OVERFLOW_PERCENTAGE ) / 100 {
690+ log_error ! ( logger, "retry_amt_msat of {} will put pending_amt_msat (currently: {}) more than 10% over total_payment_amt_msat of {}" , retry_amt_msat, pending_amt_msat, total_msat) ;
691+ let payment_hash = * payment_hash;
692+ abandon_with_entry ! ( payment_id, payment_hash, payment, pending_events) ;
693+ return
694+ }
695+ ( * total_msat, * payment_hash, * payment_secret, * keysend_preimage)
696+ } ,
697+ PendingOutboundPayment :: Legacy { .. } => {
698+ log_error ! ( logger, "Unable to retry payments that were initially sent on LDK versions prior to 0.0.102" ) ;
699+ return
700+ } ,
701+ PendingOutboundPayment :: Fulfilled { .. } => {
702+ log_error ! ( logger, "Payment already completed" ) ;
703+ return
704+ } ,
705+ PendingOutboundPayment :: Abandoned { .. } => {
706+ log_error ! ( logger, "Payment already abandoned (with some HTLCs still pending)" ) ;
707+ return
708+ } ,
709+ } ;
710+ if !payment. get ( ) . is_retryable_now ( ) {
711+ log_error ! ( logger, "Retries exhausted for payment id {}" , log_bytes!( payment_id. 0 ) ) ;
712+ abandon_with_entry ! ( payment_id, res. 1 , payment, pending_events) ;
713+ return
714+ }
715+ payment. get_mut ( ) . increment_attempts ( ) ;
716+ for ( path, session_priv_bytes) in route. paths . iter ( ) . zip ( onion_session_privs. iter ( ) ) {
717+ assert ! ( payment. get_mut( ) . insert( * session_priv_bytes, path) ) ;
718+ }
719+ res
720+ } ,
721+ hash_map:: Entry :: Vacant ( _) => {
722+ log_error ! ( logger, "Payment with ID {} not found" , log_bytes!( payment_id. 0 ) ) ;
723+ return
724+ }
725+ }
726+ } ;
727+ let res = self . pay_route_internal ( & route, payment_hash, & payment_secret, keysend_preimage,
728+ payment_id, Some ( total_msat) , onion_session_privs, node_signer, best_block_height,
729+ & send_payment_along_path) ;
658730 log_info ! ( logger, "Result retrying payment id {}: {:?}" , log_bytes!( payment_id. 0 ) , res) ;
659731 if let Err ( e) = res {
660732 self . handle_pay_route_err ( e, payment_id, payment_hash, route, route_params, router, first_hops, inflight_htlcs, entropy_source, node_signer, best_block_height, logger, pending_events, send_payment_along_path) ;
@@ -679,14 +751,14 @@ impl OutboundPayments {
679751 match err {
680752 PaymentSendFailure :: AllFailedResendSafe ( errs) => {
681753 Self :: push_payment_path_failed_evs ( payment_id, payment_hash, route. paths , errs. into_iter ( ) . map ( |e| Err ( e) ) , pending_events) ;
682- self . retry_payment_internal ( payment_id, payment_hash , route_params, router, first_hops, inflight_htlcs, entropy_source, node_signer, best_block_height, logger, pending_events, send_payment_along_path) ;
754+ self . retry_payment_internal ( payment_id, route_params, router, first_hops, inflight_htlcs, entropy_source, node_signer, best_block_height, logger, pending_events, send_payment_along_path) ;
683755 } ,
684756 PaymentSendFailure :: PartialFailure { failed_paths_retry : Some ( retry) , results, .. } => {
685757 Self :: push_payment_path_failed_evs ( payment_id, payment_hash, route. paths , results. into_iter ( ) , pending_events) ;
686758 // Some paths were sent, even if we failed to send the full MPP value our recipient may
687759 // misbehave and claim the funds, at which point we have to consider the payment sent, so
688760 // return `Ok()` here, ignoring any retry errors.
689- self . retry_payment_internal ( payment_id, payment_hash , retry, router, first_hops, inflight_htlcs, entropy_source, node_signer, best_block_height, logger, pending_events, send_payment_along_path) ;
761+ self . retry_payment_internal ( payment_id, retry, router, first_hops, inflight_htlcs, entropy_source, node_signer, best_block_height, logger, pending_events, send_payment_along_path) ;
690762 } ,
691763 PaymentSendFailure :: PartialFailure { failed_paths_retry : None , .. } => {
692764 // This may happen if we send a payment and some paths fail, but only due to a temporary
@@ -736,82 +808,6 @@ impl OutboundPayments {
736808 }
737809 }
738810
739- pub ( super ) fn retry_payment_with_route < ES : Deref , NS : Deref , F > (
740- & self , route : & Route , payment_id : PaymentId , entropy_source : & ES , node_signer : & NS , best_block_height : u32 ,
741- send_payment_along_path : F
742- ) -> Result < ( ) , PaymentSendFailure >
743- where
744- ES :: Target : EntropySource ,
745- NS :: Target : NodeSigner ,
746- F : Fn ( & Vec < RouteHop > , & Option < PaymentParameters > , & PaymentHash , & Option < PaymentSecret > , u64 ,
747- u32 , PaymentId , & Option < PaymentPreimage > , [ u8 ; 32 ] ) -> Result < ( ) , APIError >
748- {
749- const RETRY_OVERFLOW_PERCENTAGE : u64 = 10 ;
750- for path in route. paths . iter ( ) {
751- if path. len ( ) == 0 {
752- return Err ( PaymentSendFailure :: ParameterError ( APIError :: APIMisuseError {
753- err : "length-0 path in route" . to_string ( )
754- } ) )
755- }
756- }
757-
758- let mut onion_session_privs = Vec :: with_capacity ( route. paths . len ( ) ) ;
759- for _ in 0 ..route. paths . len ( ) {
760- onion_session_privs. push ( entropy_source. get_secure_random_bytes ( ) ) ;
761- }
762-
763- let ( total_msat, payment_hash, payment_secret, keysend_preimage) = {
764- let mut outbounds = self . pending_outbound_payments . lock ( ) . unwrap ( ) ;
765- match outbounds. get_mut ( & payment_id) {
766- Some ( payment) => {
767- let res = match payment {
768- PendingOutboundPayment :: Retryable {
769- total_msat, payment_hash, keysend_preimage, payment_secret, pending_amt_msat, ..
770- } => {
771- let retry_amt_msat: u64 = route. paths . iter ( ) . map ( |path| path. last ( ) . unwrap ( ) . fee_msat ) . sum ( ) ;
772- if retry_amt_msat + * pending_amt_msat > * total_msat * ( 100 + RETRY_OVERFLOW_PERCENTAGE ) / 100 {
773- return Err ( PaymentSendFailure :: ParameterError ( APIError :: APIMisuseError {
774- err : format ! ( "retry_amt_msat of {} will put pending_amt_msat (currently: {}) more than 10% over total_payment_amt_msat of {}" , retry_amt_msat, pending_amt_msat, total_msat) . to_string ( )
775- } ) )
776- }
777- ( * total_msat, * payment_hash, * payment_secret, * keysend_preimage)
778- } ,
779- PendingOutboundPayment :: Legacy { .. } => {
780- return Err ( PaymentSendFailure :: ParameterError ( APIError :: APIMisuseError {
781- err : "Unable to retry payments that were initially sent on LDK versions prior to 0.0.102" . to_string ( )
782- } ) )
783- } ,
784- PendingOutboundPayment :: Fulfilled { .. } => {
785- return Err ( PaymentSendFailure :: ParameterError ( APIError :: APIMisuseError {
786- err : "Payment already completed" . to_owned ( )
787- } ) ) ;
788- } ,
789- PendingOutboundPayment :: Abandoned { .. } => {
790- return Err ( PaymentSendFailure :: ParameterError ( APIError :: APIMisuseError {
791- err : "Payment already abandoned (with some HTLCs still pending)" . to_owned ( )
792- } ) ) ;
793- } ,
794- } ;
795- if !payment. is_retryable_now ( ) {
796- return Err ( PaymentSendFailure :: ParameterError ( APIError :: APIMisuseError {
797- err : format ! ( "Retries exhausted for payment id {}" , log_bytes!( payment_id. 0 ) ) ,
798- } ) )
799- }
800- payment. increment_attempts ( ) ;
801- for ( path, session_priv_bytes) in route. paths . iter ( ) . zip ( onion_session_privs. iter ( ) ) {
802- assert ! ( payment. insert( * session_priv_bytes, path) ) ;
803- }
804- res
805- } ,
806- None =>
807- return Err ( PaymentSendFailure :: ParameterError ( APIError :: APIMisuseError {
808- err : format ! ( "Payment with ID {} not found" , log_bytes!( payment_id. 0 ) ) ,
809- } ) ) ,
810- }
811- } ;
812- self . pay_route_internal ( route, payment_hash, & payment_secret, keysend_preimage, payment_id, Some ( total_msat) , onion_session_privs, node_signer, best_block_height, & send_payment_along_path)
813- }
814-
815811 pub ( super ) fn send_probe < ES : Deref , NS : Deref , F > (
816812 & self , hops : Vec < RouteHop > , probing_cookie_secret : [ u8 ; 32 ] , entropy_source : & ES ,
817813 node_signer : & NS , best_block_height : u32 , send_payment_along_path : F
@@ -1403,8 +1399,8 @@ mod tests {
14031399 & Route { paths : vec ! [ ] , payment_params : None } , Some ( Retry :: Attempts ( 1 ) ) ,
14041400 Some ( expired_route_params. payment_params . clone ( ) ) , & & keys_manager, 0 ) . unwrap ( ) ;
14051401 outbound_payments. retry_payment_internal (
1406- PaymentId ( [ 0 ; 32 ] ) , PaymentHash ( [ 0 ; 32 ] ) , expired_route_params, & & router, vec ! [ ] ,
1407- & || InFlightHtlcs :: new ( ) , & & keys_manager, & & keys_manager, 0 , & & logger, & pending_events,
1402+ PaymentId ( [ 0 ; 32 ] ) , expired_route_params, & & router, vec ! [ ] , & || InFlightHtlcs :: new ( ) ,
1403+ & & keys_manager, & & keys_manager, 0 , & & logger, & pending_events,
14081404 & |_, _, _, _, _, _, _, _, _| Ok ( ( ) ) ) ;
14091405 let events = pending_events. lock ( ) . unwrap ( ) ;
14101406 assert_eq ! ( events. len( ) , 1 ) ;
@@ -1449,8 +1445,8 @@ mod tests {
14491445 & Route { paths : vec ! [ ] , payment_params : None } , Some ( Retry :: Attempts ( 1 ) ) ,
14501446 Some ( route_params. payment_params . clone ( ) ) , & & keys_manager, 0 ) . unwrap ( ) ;
14511447 outbound_payments. retry_payment_internal (
1452- PaymentId ( [ 0 ; 32 ] ) , PaymentHash ( [ 0 ; 32 ] ) , route_params, & & router, vec ! [ ] ,
1453- & || InFlightHtlcs :: new ( ) , & & keys_manager, & & keys_manager, 0 , & & logger, & pending_events,
1448+ PaymentId ( [ 0 ; 32 ] ) , route_params, & & router, vec ! [ ] , & || InFlightHtlcs :: new ( ) ,
1449+ & & keys_manager, & & keys_manager, 0 , & & logger, & pending_events,
14541450 & |_, _, _, _, _, _, _, _, _| Ok ( ( ) ) ) ;
14551451 let events = pending_events. lock ( ) . unwrap ( ) ;
14561452 assert_eq ! ( events. len( ) , 1 ) ;
0 commit comments