@@ -16,6 +16,7 @@ use bitcoin::secp256k1::{self, Secp256k1, SecretKey};
1616use crate :: chain:: keysinterface:: { EntropySource , NodeSigner , Recipient } ;
1717use crate :: ln:: { PaymentHash , PaymentPreimage , PaymentSecret } ;
1818use crate :: ln:: channelmanager:: { ChannelDetails , HTLCSource , IDEMPOTENCY_TIMEOUT_TICKS , MIN_HTLC_RELAY_HOLDING_CELL_MILLIS , PaymentId } ;
19+ use crate :: ln:: channelmanager:: MIN_FINAL_CLTV_EXPIRY_DELTA as LDK_DEFAULT_MIN_FINAL_CLTV_EXPIRY_DELTA ;
1920use crate :: ln:: msgs:: DecodeError ;
2021use crate :: ln:: onion_utils:: HTLCFailReason ;
2122use crate :: routing:: router:: { InFlightHtlcs , PaymentParameters , Route , RouteHop , RouteParameters , RoutePath , Router } ;
@@ -43,7 +44,7 @@ pub(crate) enum PendingOutboundPayment {
4344 Retryable {
4445 retry_strategy : Option < Retry > ,
4546 attempts : PaymentAttempts ,
46- route_params : Option < RouteParameters > ,
47+ payment_params : Option < PaymentParameters > ,
4748 session_privs : HashSet < [ u8 ; 32 ] > ,
4849 payment_hash : PaymentHash ,
4950 payment_secret : Option < PaymentSecret > ,
@@ -102,9 +103,17 @@ impl PendingOutboundPayment {
102103 _ => false ,
103104 }
104105 }
106+ fn payment_parameters ( & mut self ) -> Option < & mut PaymentParameters > {
107+ match self {
108+ PendingOutboundPayment :: Retryable { payment_params : Some ( ref mut params) , .. } => {
109+ Some ( params)
110+ } ,
111+ _ => None ,
112+ }
113+ }
105114 pub fn insert_previously_failed_scid ( & mut self , scid : u64 ) {
106- if let PendingOutboundPayment :: Retryable { route_params : Some ( params) , .. } = self {
107- params. payment_params . previously_failed_channels . push ( scid) ;
115+ if let PendingOutboundPayment :: Retryable { payment_params : Some ( params) , .. } = self {
116+ params. previously_failed_channels . push ( scid) ;
108117 }
109118 }
110119 pub ( super ) fn is_fulfilled ( & self ) -> bool {
@@ -474,9 +483,18 @@ impl OutboundPayments {
474483 let mut retry_id_route_params = None ;
475484 for ( pmt_id, pmt) in outbounds. iter_mut ( ) {
476485 if pmt. is_auto_retryable_now ( ) {
477- if let PendingOutboundPayment :: Retryable { pending_amt_msat, total_msat, route_params : Some ( params) , .. } = pmt {
486+ if let PendingOutboundPayment :: Retryable { pending_amt_msat, total_msat, payment_params : Some ( params) , .. } = pmt {
478487 if pending_amt_msat < total_msat {
479- retry_id_route_params = Some ( ( * pmt_id, params. clone ( ) ) ) ;
488+ retry_id_route_params = Some ( ( * pmt_id, RouteParameters {
489+ final_value_msat : * total_msat - * pending_amt_msat,
490+ final_cltv_expiry_delta :
491+ if let Some ( delta) = params. final_cltv_expiry_delta { delta }
492+ else {
493+ debug_assert ! ( false , "We always set the final_cltv_expiry_delta when a path fails" ) ;
494+ LDK_DEFAULT_MIN_FINAL_CLTV_EXPIRY_DELTA . into ( )
495+ } ,
496+ payment_params : params. clone ( ) ,
497+ } ) ) ;
480498 break
481499 }
482500 }
@@ -522,7 +540,7 @@ impl OutboundPayments {
522540 } ) ) ?;
523541
524542 let res = if let Some ( ( payment_hash, payment_secret, retry_strategy) ) = initial_send_info {
525- let onion_session_privs = self . add_new_pending_payment ( payment_hash, * payment_secret, payment_id, & route, Some ( retry_strategy) , Some ( route_params. clone ( ) ) , entropy_source, best_block_height) ?;
543+ let onion_session_privs = self . add_new_pending_payment ( payment_hash, * payment_secret, payment_id, & route, Some ( retry_strategy) , Some ( route_params. payment_params . clone ( ) ) , entropy_source, best_block_height) ?;
526544 self . pay_route_internal ( & route, payment_hash, payment_secret, None , payment_id, None , onion_session_privs, node_signer, best_block_height, send_payment_along_path)
527545 } else {
528546 self . retry_payment_with_route ( & route, payment_id, entropy_source, node_signer, best_block_height, send_payment_along_path)
@@ -672,7 +690,7 @@ impl OutboundPayments {
672690
673691 pub ( super ) fn add_new_pending_payment < ES : Deref > (
674692 & self , payment_hash : PaymentHash , payment_secret : Option < PaymentSecret > , payment_id : PaymentId ,
675- route : & Route , retry_strategy : Option < Retry > , route_params : Option < RouteParameters > ,
693+ route : & Route , retry_strategy : Option < Retry > , payment_params : Option < PaymentParameters > ,
676694 entropy_source : & ES , best_block_height : u32
677695 ) -> Result < Vec < [ u8 ; 32 ] > , PaymentSendFailure > where ES :: Target : EntropySource {
678696 let mut onion_session_privs = Vec :: with_capacity ( route. paths . len ( ) ) ;
@@ -687,7 +705,7 @@ impl OutboundPayments {
687705 let payment = entry. insert ( PendingOutboundPayment :: Retryable {
688706 retry_strategy,
689707 attempts : PaymentAttempts :: new ( ) ,
690- route_params ,
708+ payment_params ,
691709 session_privs : HashSet :: new ( ) ,
692710 pending_amt_msat : 0 ,
693711 pending_fee_msat : Some ( 0 ) ,
@@ -965,6 +983,7 @@ impl OutboundPayments {
965983 let mut all_paths_failed = false ;
966984 let mut full_failure_ev = None ;
967985 let mut pending_retry_ev = None ;
986+ let mut retry = None ;
968987 let attempts_remaining = if let hash_map:: Entry :: Occupied ( mut payment) = outbounds. entry ( * payment_id) {
969988 if !payment. get_mut ( ) . remove ( & session_priv_bytes, Some ( & path) ) {
970989 log_trace ! ( logger, "Received duplicative fail for HTLC with payment_hash {}" , log_bytes!( payment_hash. 0 ) ) ;
@@ -978,6 +997,33 @@ impl OutboundPayments {
978997 if let Some ( scid) = short_channel_id {
979998 payment. get_mut ( ) . insert_previously_failed_scid ( scid) ;
980999 }
1000+
1001+ // We want to move towards only using the `PaymentParameters` in the outbound payments
1002+ // map. However, for backwards-compatibility, we still need to support passing the
1003+ // `PaymentParameters` data that was shoved in the HTLC (and given to us via
1004+ // `payment_params`) back to the user.
1005+ let path_last_hop = path. last ( ) . expect ( "Outbound payments must have had a valid path" ) ;
1006+ if let Some ( params) = payment. get_mut ( ) . payment_parameters ( ) {
1007+ if params. final_cltv_expiry_delta . is_none ( ) {
1008+ // This should be rare, but a user could provide None for the payment data, and
1009+ // we need it when we go to retry the payment, so fill it in.
1010+ params. final_cltv_expiry_delta = Some ( path_last_hop. cltv_expiry_delta ) ;
1011+ }
1012+ retry = Some ( RouteParameters {
1013+ payment_params : params. clone ( ) ,
1014+ final_value_msat : path_last_hop. fee_msat ,
1015+ final_cltv_expiry_delta : params. final_cltv_expiry_delta . unwrap ( ) ,
1016+ } ) ;
1017+ } else if let Some ( params) = payment_params {
1018+ retry = Some ( RouteParameters {
1019+ payment_params : params. clone ( ) ,
1020+ final_value_msat : path_last_hop. fee_msat ,
1021+ final_cltv_expiry_delta :
1022+ if let Some ( delta) = params. final_cltv_expiry_delta { delta }
1023+ else { path_last_hop. cltv_expiry_delta } ,
1024+ } ) ;
1025+ }
1026+
9811027 if payment. get ( ) . remaining_parts ( ) == 0 {
9821028 all_paths_failed = true ;
9831029 if payment. get ( ) . abandoned ( ) {
@@ -994,16 +1040,6 @@ impl OutboundPayments {
9941040 return
9951041 } ;
9961042 core:: mem:: drop ( outbounds) ;
997- let mut retry = if let Some ( payment_params_data) = payment_params {
998- let path_last_hop = path. last ( ) . expect ( "Outbound payments must have had a valid path" ) ;
999- Some ( RouteParameters {
1000- payment_params : payment_params_data. clone ( ) ,
1001- final_value_msat : path_last_hop. fee_msat ,
1002- final_cltv_expiry_delta :
1003- if let Some ( delta) = payment_params_data. final_cltv_expiry_delta { delta }
1004- else { path_last_hop. cltv_expiry_delta } ,
1005- } )
1006- } else { None } ;
10071043 log_trace ! ( logger, "Failing outbound payment HTLC with payment_hash {}" , log_bytes!( payment_hash. 0 ) ) ;
10081044
10091045 let path_failure = {
@@ -1115,13 +1151,13 @@ impl_writeable_tlv_based_enum_upgradable!(PendingOutboundPayment,
11151151 ( 0 , session_privs, required) ,
11161152 ( 1 , pending_fee_msat, option) ,
11171153 ( 2 , payment_hash, required) ,
1118- ( not_written , retry_strategy , ( static_value , None ) ) ,
1154+ ( 3 , payment_params , option ) ,
11191155 ( 4 , payment_secret, option) ,
1120- ( not_written, attempts, ( static_value, PaymentAttempts :: new( ) ) ) ,
11211156 ( 6 , total_msat, required) ,
1122- ( not_written, route_params, ( static_value, None ) ) ,
11231157 ( 8 , pending_amt_msat, required) ,
11241158 ( 10 , starting_block_height, required) ,
1159+ ( not_written, retry_strategy, ( static_value, None ) ) ,
1160+ ( not_written, attempts, ( static_value, PaymentAttempts :: new( ) ) ) ,
11251161 } ,
11261162 ( 3 , Abandoned ) => {
11271163 ( 0 , session_privs, required) ,
@@ -1212,7 +1248,7 @@ mod tests {
12121248
12131249 let err = if on_retry {
12141250 outbound_payments. add_new_pending_payment ( PaymentHash ( [ 0 ; 32 ] ) , None , PaymentId ( [ 0 ; 32 ] ) ,
1215- & Route { paths : vec ! [ ] , payment_params : None } , Some ( Retry :: Attempts ( 1 ) ) , Some ( route_params. clone ( ) ) ,
1251+ & Route { paths : vec ! [ ] , payment_params : None } , Some ( Retry :: Attempts ( 1 ) ) , Some ( route_params. payment_params . clone ( ) ) ,
12161252 & & keys_manager, 0 ) . unwrap ( ) ;
12171253 outbound_payments. pay_internal (
12181254 PaymentId ( [ 0 ; 32 ] ) , None , route_params, & & router, vec ! [ ] , InFlightHtlcs :: new ( ) ,
0 commit comments