@@ -527,9 +527,9 @@ impl OutboundPayments {
527
527
let mut retry_id_route_params = None ;
528
528
for ( pmt_id, pmt) in outbounds. iter_mut ( ) {
529
529
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 {
531
531
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 {
533
533
final_value_msat : * total_msat - * pending_amt_msat,
534
534
final_cltv_expiry_delta :
535
535
if let Some ( delta) = params. final_cltv_expiry_delta { delta }
@@ -545,8 +545,8 @@ impl OutboundPayments {
545
545
}
546
546
}
547
547
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)
550
550
} else { break }
551
551
}
552
552
@@ -619,10 +619,10 @@ impl OutboundPayments {
619
619
}
620
620
621
621
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 ,
626
626
)
627
627
where
628
628
R :: Target : Router ,
@@ -652,9 +652,81 @@ impl OutboundPayments {
652
652
return
653
653
}
654
654
} ;
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
+ }
655
662
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) ;
658
730
log_info ! ( logger, "Result retrying payment id {}: {:?}" , log_bytes!( payment_id. 0 ) , res) ;
659
731
if let Err ( e) = res {
660
732
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 {
679
751
match err {
680
752
PaymentSendFailure :: AllFailedResendSafe ( errs) => {
681
753
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) ;
683
755
} ,
684
756
PaymentSendFailure :: PartialFailure { failed_paths_retry : Some ( retry) , results, .. } => {
685
757
Self :: push_payment_path_failed_evs ( payment_id, payment_hash, route. paths , results. into_iter ( ) , pending_events) ;
686
758
// Some paths were sent, even if we failed to send the full MPP value our recipient may
687
759
// misbehave and claim the funds, at which point we have to consider the payment sent, so
688
760
// 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) ;
690
762
} ,
691
763
PaymentSendFailure :: PartialFailure { failed_paths_retry : None , .. } => {
692
764
// This may happen if we send a payment and some paths fail, but only due to a temporary
@@ -736,82 +808,6 @@ impl OutboundPayments {
736
808
}
737
809
}
738
810
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
-
815
811
pub ( super ) fn send_probe < ES : Deref , NS : Deref , F > (
816
812
& self , hops : Vec < RouteHop > , probing_cookie_secret : [ u8 ; 32 ] , entropy_source : & ES ,
817
813
node_signer : & NS , best_block_height : u32 , send_payment_along_path : F
@@ -1403,8 +1399,8 @@ mod tests {
1403
1399
& Route { paths : vec ! [ ] , payment_params : None } , Some ( Retry :: Attempts ( 1 ) ) ,
1404
1400
Some ( expired_route_params. payment_params . clone ( ) ) , & & keys_manager, 0 ) . unwrap ( ) ;
1405
1401
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,
1408
1404
& |_, _, _, _, _, _, _, _, _| Ok ( ( ) ) ) ;
1409
1405
let events = pending_events. lock ( ) . unwrap ( ) ;
1410
1406
assert_eq ! ( events. len( ) , 1 ) ;
@@ -1449,8 +1445,8 @@ mod tests {
1449
1445
& Route { paths : vec ! [ ] , payment_params : None } , Some ( Retry :: Attempts ( 1 ) ) ,
1450
1446
Some ( route_params. payment_params . clone ( ) ) , & & keys_manager, 0 ) . unwrap ( ) ;
1451
1447
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,
1454
1450
& |_, _, _, _, _, _, _, _, _| Ok ( ( ) ) ) ;
1455
1451
let events = pending_events. lock ( ) . unwrap ( ) ;
1456
1452
assert_eq ! ( events. len( ) , 1 ) ;
0 commit comments