@@ -524,9 +524,9 @@ impl OutboundPayments {
524
524
let mut retry_id_route_params = None ;
525
525
for ( pmt_id, pmt) in outbounds. iter_mut ( ) {
526
526
if pmt. is_auto_retryable_now ( ) {
527
- if let PendingOutboundPayment :: Retryable { payment_hash , pending_amt_msat, total_msat, payment_params : Some ( params) , .. } = pmt {
527
+ if let PendingOutboundPayment :: Retryable { pending_amt_msat, total_msat, payment_params : Some ( params) , .. } = pmt {
528
528
if pending_amt_msat < total_msat {
529
- retry_id_route_params = Some ( ( * pmt_id, * payment_hash , RouteParameters {
529
+ retry_id_route_params = Some ( ( * pmt_id, RouteParameters {
530
530
final_value_msat : * total_msat - * pending_amt_msat,
531
531
final_cltv_expiry_delta :
532
532
if let Some ( delta) = params. final_cltv_expiry_delta { delta }
@@ -542,8 +542,8 @@ impl OutboundPayments {
542
542
}
543
543
}
544
544
core:: mem:: drop ( outbounds) ;
545
- if let Some ( ( payment_id, payment_hash , route_params) ) = retry_id_route_params {
546
- 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)
545
+ if let Some ( ( payment_id, route_params) ) = retry_id_route_params {
546
+ 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)
547
547
} else { break }
548
548
}
549
549
@@ -616,10 +616,10 @@ impl OutboundPayments {
616
616
}
617
617
618
618
fn retry_payment_internal < R : Deref , NS : Deref , ES : Deref , IH , SP , L : Deref > (
619
- & self , payment_id : PaymentId , payment_hash : PaymentHash , route_params : RouteParameters ,
620
- router : & R , first_hops : Vec < ChannelDetails > , inflight_htlcs : & IH , entropy_source : & ES ,
621
- node_signer : & NS , best_block_height : u32 , logger : & L ,
622
- pending_events : & Mutex < Vec < events :: Event > > , send_payment_along_path : & SP ,
619
+ & self , payment_id : PaymentId , route_params : RouteParameters , router : & R ,
620
+ first_hops : Vec < ChannelDetails > , inflight_htlcs : & IH , entropy_source : & ES , node_signer : & NS ,
621
+ best_block_height : u32 , logger : & L , pending_events : & Mutex < Vec < events :: Event > > ,
622
+ send_payment_along_path : & SP ,
623
623
)
624
624
where
625
625
R :: Target : Router ,
@@ -649,9 +649,81 @@ impl OutboundPayments {
649
649
return
650
650
}
651
651
} ;
652
+ for path in route. paths . iter ( ) {
653
+ if path. len ( ) == 0 {
654
+ log_error ! ( logger, "length-0 path in route" ) ;
655
+ self . abandon_payment ( payment_id, pending_events) ;
656
+ return
657
+ }
658
+ }
652
659
653
- let res = self . retry_payment_with_route ( & route, payment_id, entropy_source, node_signer,
654
- best_block_height, send_payment_along_path) ;
660
+ const RETRY_OVERFLOW_PERCENTAGE : u64 = 10 ;
661
+ let mut onion_session_privs = Vec :: with_capacity ( route. paths . len ( ) ) ;
662
+ for _ in 0 ..route. paths . len ( ) {
663
+ onion_session_privs. push ( entropy_source. get_secure_random_bytes ( ) ) ;
664
+ }
665
+
666
+ macro_rules! abandon_with_entry {
667
+ ( $payment_id: expr, $payment_hash: expr, $payment: expr, $pending_events: expr) => {
668
+ if $payment. get_mut( ) . mark_abandoned( ) . is_ok( ) && $payment. get( ) . remaining_parts( ) == 0 {
669
+ $pending_events. lock( ) . unwrap( ) . push( events:: Event :: PaymentFailed {
670
+ payment_id: $payment_id,
671
+ payment_hash: $payment_hash,
672
+ } ) ;
673
+ $payment. remove( ) ;
674
+ }
675
+ }
676
+ }
677
+ let ( total_msat, payment_hash, payment_secret, keysend_preimage) = {
678
+ let mut outbounds = self . pending_outbound_payments . lock ( ) . unwrap ( ) ;
679
+ match outbounds. entry ( payment_id) {
680
+ hash_map:: Entry :: Occupied ( mut payment) => {
681
+ let res = match payment. get ( ) {
682
+ PendingOutboundPayment :: Retryable {
683
+ total_msat, payment_hash, keysend_preimage, payment_secret, pending_amt_msat, ..
684
+ } => {
685
+ let retry_amt_msat: u64 = route. paths . iter ( ) . map ( |path| path. last ( ) . unwrap ( ) . fee_msat ) . sum ( ) ;
686
+ if retry_amt_msat + * pending_amt_msat > * total_msat * ( 100 + RETRY_OVERFLOW_PERCENTAGE ) / 100 {
687
+ 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) ;
688
+ let payment_hash = * payment_hash;
689
+ abandon_with_entry ! ( payment_id, payment_hash, payment, pending_events) ;
690
+ return
691
+ }
692
+ ( * total_msat, * payment_hash, * payment_secret, * keysend_preimage)
693
+ } ,
694
+ PendingOutboundPayment :: Legacy { .. } => {
695
+ log_error ! ( logger, "Unable to retry payments that were initially sent on LDK versions prior to 0.0.102" ) ;
696
+ return
697
+ } ,
698
+ PendingOutboundPayment :: Fulfilled { .. } => {
699
+ log_error ! ( logger, "Payment already completed" ) ;
700
+ return
701
+ } ,
702
+ PendingOutboundPayment :: Abandoned { .. } => {
703
+ log_error ! ( logger, "Payment already abandoned (with some HTLCs still pending)" ) ;
704
+ return
705
+ } ,
706
+ } ;
707
+ if !payment. get ( ) . is_retryable_now ( ) {
708
+ log_error ! ( logger, "Retries exhausted for payment id {}" , log_bytes!( payment_id. 0 ) ) ;
709
+ abandon_with_entry ! ( payment_id, res. 1 , payment, pending_events) ;
710
+ return
711
+ }
712
+ payment. get_mut ( ) . increment_attempts ( ) ;
713
+ for ( path, session_priv_bytes) in route. paths . iter ( ) . zip ( onion_session_privs. iter ( ) ) {
714
+ assert ! ( payment. get_mut( ) . insert( * session_priv_bytes, path) ) ;
715
+ }
716
+ res
717
+ } ,
718
+ hash_map:: Entry :: Vacant ( _) => {
719
+ log_error ! ( logger, "Payment with ID {} not found" , log_bytes!( payment_id. 0 ) ) ;
720
+ return
721
+ }
722
+ }
723
+ } ;
724
+ let res = self . pay_route_internal ( & route, payment_hash, & payment_secret, keysend_preimage,
725
+ payment_id, Some ( total_msat) , onion_session_privs, node_signer, best_block_height,
726
+ & send_payment_along_path) ;
655
727
log_info ! ( logger, "Result retrying payment id {}: {:?}" , log_bytes!( payment_id. 0 ) , res) ;
656
728
if let Err ( e) = res {
657
729
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) ;
@@ -676,14 +748,14 @@ impl OutboundPayments {
676
748
match err {
677
749
PaymentSendFailure :: AllFailedResendSafe ( errs) => {
678
750
Self :: push_payment_path_failed_evs ( payment_id, payment_hash, route. paths , errs. into_iter ( ) . map ( |e| Err ( e) ) , pending_events) ;
679
- 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) ;
751
+ 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) ;
680
752
} ,
681
753
PaymentSendFailure :: PartialFailure { failed_paths_retry : Some ( retry) , results, .. } => {
682
754
Self :: push_payment_path_failed_evs ( payment_id, payment_hash, route. paths , results. into_iter ( ) , pending_events) ;
683
755
// Some paths were sent, even if we failed to send the full MPP value our recipient may
684
756
// misbehave and claim the funds, at which point we have to consider the payment sent, so
685
757
// return `Ok()` here, ignoring any retry errors.
686
- 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) ;
758
+ 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) ;
687
759
} ,
688
760
PaymentSendFailure :: PartialFailure { failed_paths_retry : None , .. } => {
689
761
// This may happen if we send a payment and some paths fail, but only due to a temporary
@@ -733,82 +805,6 @@ impl OutboundPayments {
733
805
}
734
806
}
735
807
736
- pub ( super ) fn retry_payment_with_route < ES : Deref , NS : Deref , F > (
737
- & self , route : & Route , payment_id : PaymentId , entropy_source : & ES , node_signer : & NS , best_block_height : u32 ,
738
- send_payment_along_path : F
739
- ) -> Result < ( ) , PaymentSendFailure >
740
- where
741
- ES :: Target : EntropySource ,
742
- NS :: Target : NodeSigner ,
743
- F : Fn ( & Vec < RouteHop > , & Option < PaymentParameters > , & PaymentHash , & Option < PaymentSecret > , u64 ,
744
- u32 , PaymentId , & Option < PaymentPreimage > , [ u8 ; 32 ] ) -> Result < ( ) , APIError >
745
- {
746
- const RETRY_OVERFLOW_PERCENTAGE : u64 = 10 ;
747
- for path in route. paths . iter ( ) {
748
- if path. len ( ) == 0 {
749
- return Err ( PaymentSendFailure :: ParameterError ( APIError :: APIMisuseError {
750
- err : "length-0 path in route" . to_string ( )
751
- } ) )
752
- }
753
- }
754
-
755
- let mut onion_session_privs = Vec :: with_capacity ( route. paths . len ( ) ) ;
756
- for _ in 0 ..route. paths . len ( ) {
757
- onion_session_privs. push ( entropy_source. get_secure_random_bytes ( ) ) ;
758
- }
759
-
760
- let ( total_msat, payment_hash, payment_secret, keysend_preimage) = {
761
- let mut outbounds = self . pending_outbound_payments . lock ( ) . unwrap ( ) ;
762
- match outbounds. get_mut ( & payment_id) {
763
- Some ( payment) => {
764
- let res = match payment {
765
- PendingOutboundPayment :: Retryable {
766
- total_msat, payment_hash, keysend_preimage, payment_secret, pending_amt_msat, ..
767
- } => {
768
- let retry_amt_msat: u64 = route. paths . iter ( ) . map ( |path| path. last ( ) . unwrap ( ) . fee_msat ) . sum ( ) ;
769
- if retry_amt_msat + * pending_amt_msat > * total_msat * ( 100 + RETRY_OVERFLOW_PERCENTAGE ) / 100 {
770
- return Err ( PaymentSendFailure :: ParameterError ( APIError :: APIMisuseError {
771
- 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 ( )
772
- } ) )
773
- }
774
- ( * total_msat, * payment_hash, * payment_secret, * keysend_preimage)
775
- } ,
776
- PendingOutboundPayment :: Legacy { .. } => {
777
- return Err ( PaymentSendFailure :: ParameterError ( APIError :: APIMisuseError {
778
- err : "Unable to retry payments that were initially sent on LDK versions prior to 0.0.102" . to_string ( )
779
- } ) )
780
- } ,
781
- PendingOutboundPayment :: Fulfilled { .. } => {
782
- return Err ( PaymentSendFailure :: ParameterError ( APIError :: APIMisuseError {
783
- err : "Payment already completed" . to_owned ( )
784
- } ) ) ;
785
- } ,
786
- PendingOutboundPayment :: Abandoned { .. } => {
787
- return Err ( PaymentSendFailure :: ParameterError ( APIError :: APIMisuseError {
788
- err : "Payment already abandoned (with some HTLCs still pending)" . to_owned ( )
789
- } ) ) ;
790
- } ,
791
- } ;
792
- if !payment. is_retryable_now ( ) {
793
- return Err ( PaymentSendFailure :: ParameterError ( APIError :: APIMisuseError {
794
- err : format ! ( "Retries exhausted for payment id {}" , log_bytes!( payment_id. 0 ) ) ,
795
- } ) )
796
- }
797
- payment. increment_attempts ( ) ;
798
- for ( path, session_priv_bytes) in route. paths . iter ( ) . zip ( onion_session_privs. iter ( ) ) {
799
- assert ! ( payment. insert( * session_priv_bytes, path) ) ;
800
- }
801
- res
802
- } ,
803
- None =>
804
- return Err ( PaymentSendFailure :: ParameterError ( APIError :: APIMisuseError {
805
- err : format ! ( "Payment with ID {} not found" , log_bytes!( payment_id. 0 ) ) ,
806
- } ) ) ,
807
- }
808
- } ;
809
- 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)
810
- }
811
-
812
808
pub ( super ) fn send_probe < ES : Deref , NS : Deref , F > (
813
809
& self , hops : Vec < RouteHop > , probing_cookie_secret : [ u8 ; 32 ] , entropy_source : & ES ,
814
810
node_signer : & NS , best_block_height : u32 , send_payment_along_path : F
@@ -1400,8 +1396,8 @@ mod tests {
1400
1396
& Route { paths : vec ! [ ] , payment_params : None } , Some ( Retry :: Attempts ( 1 ) ) ,
1401
1397
Some ( expired_route_params. payment_params . clone ( ) ) , & & keys_manager, 0 ) . unwrap ( ) ;
1402
1398
outbound_payments. retry_payment_internal (
1403
- PaymentId ( [ 0 ; 32 ] ) , PaymentHash ( [ 0 ; 32 ] ) , expired_route_params, & & router, vec ! [ ] ,
1404
- & || InFlightHtlcs :: new ( ) , & & keys_manager, & & keys_manager, 0 , & & logger, & pending_events,
1399
+ PaymentId ( [ 0 ; 32 ] ) , expired_route_params, & & router, vec ! [ ] , & || InFlightHtlcs :: new ( ) ,
1400
+ & & keys_manager, & & keys_manager, 0 , & & logger, & pending_events,
1405
1401
& |_, _, _, _, _, _, _, _, _| Ok ( ( ) ) ) ;
1406
1402
let events = pending_events. lock ( ) . unwrap ( ) ;
1407
1403
assert_eq ! ( events. len( ) , 1 ) ;
@@ -1446,8 +1442,8 @@ mod tests {
1446
1442
& Route { paths : vec ! [ ] , payment_params : None } , Some ( Retry :: Attempts ( 1 ) ) ,
1447
1443
Some ( route_params. payment_params . clone ( ) ) , & & keys_manager, 0 ) . unwrap ( ) ;
1448
1444
outbound_payments. retry_payment_internal (
1449
- PaymentId ( [ 0 ; 32 ] ) , PaymentHash ( [ 0 ; 32 ] ) , route_params, & & router, vec ! [ ] ,
1450
- & || InFlightHtlcs :: new ( ) , & & keys_manager, & & keys_manager, 0 , & & logger, & pending_events,
1445
+ PaymentId ( [ 0 ; 32 ] ) , route_params, & & router, vec ! [ ] , & || InFlightHtlcs :: new ( ) ,
1446
+ & & keys_manager, & & keys_manager, 0 , & & logger, & pending_events,
1451
1447
& |_, _, _, _, _, _, _, _, _| Ok ( ( ) ) ) ;
1452
1448
let events = pending_events. lock ( ) . unwrap ( ) ;
1453
1449
assert_eq ! ( events. len( ) , 1 ) ;
0 commit comments