@@ -32,12 +32,21 @@ use core::ops::Deref;
3232use crate :: prelude:: * ;
3333use crate :: sync:: Mutex ;
3434
35+ /// The number of ticks of [`ChannelManager::timer_tick_occurred`] until an invoice request without
36+ /// a response is timed out.
37+ ///
38+ /// [`ChannelManager::timer_tick_occurred`]: crate::ln::channelmanager::ChannelManager::timer_tick_occurred
39+ const INVOICE_REQUEST_TIMEOUT_TICKS : u8 = 3 ;
40+
3541/// Stores the session_priv for each part of a payment that is still pending. For versions 0.0.102
3642/// and later, also stores information for retrying the payment.
3743pub ( crate ) enum PendingOutboundPayment {
3844 Legacy {
3945 session_privs : HashSet < [ u8 ; 32 ] > ,
4046 } ,
47+ AwaitingInvoice {
48+ timer_ticks_without_response : u8 ,
49+ } ,
4150 Retryable {
4251 retry_strategy : Option < Retry > ,
4352 attempts : PaymentAttempts ,
@@ -108,6 +117,12 @@ impl PendingOutboundPayment {
108117 params. previously_failed_channels . push ( scid) ;
109118 }
110119 }
120+ fn is_awaiting_invoice ( & self ) -> bool {
121+ match self {
122+ PendingOutboundPayment :: AwaitingInvoice { .. } => true ,
123+ _ => false ,
124+ }
125+ }
111126 pub ( super ) fn is_fulfilled ( & self ) -> bool {
112127 match self {
113128 PendingOutboundPayment :: Fulfilled { .. } => true ,
@@ -130,6 +145,7 @@ impl PendingOutboundPayment {
130145 fn payment_hash ( & self ) -> Option < PaymentHash > {
131146 match self {
132147 PendingOutboundPayment :: Legacy { .. } => None ,
148+ PendingOutboundPayment :: AwaitingInvoice { .. } => None ,
133149 PendingOutboundPayment :: Retryable { payment_hash, .. } => Some ( * payment_hash) ,
134150 PendingOutboundPayment :: Fulfilled { payment_hash, .. } => * payment_hash,
135151 PendingOutboundPayment :: Abandoned { payment_hash, .. } => Some ( * payment_hash) ,
@@ -142,8 +158,11 @@ impl PendingOutboundPayment {
142158 PendingOutboundPayment :: Legacy { session_privs } |
143159 PendingOutboundPayment :: Retryable { session_privs, .. } |
144160 PendingOutboundPayment :: Fulfilled { session_privs, .. } |
145- PendingOutboundPayment :: Abandoned { session_privs, .. }
146- => session_privs,
161+ PendingOutboundPayment :: Abandoned { session_privs, .. } => session_privs,
162+ PendingOutboundPayment :: AwaitingInvoice { .. } => {
163+ debug_assert ! ( false ) ;
164+ return ;
165+ } ,
147166 } ) ;
148167 let payment_hash = self . payment_hash ( ) ;
149168 * self = PendingOutboundPayment :: Fulfilled { session_privs, payment_hash, timer_ticks_without_htlcs : 0 } ;
@@ -169,7 +188,11 @@ impl PendingOutboundPayment {
169188 PendingOutboundPayment :: Fulfilled { session_privs, .. } |
170189 PendingOutboundPayment :: Abandoned { session_privs, .. } => {
171190 session_privs. remove ( session_priv)
172- }
191+ } ,
192+ PendingOutboundPayment :: AwaitingInvoice { .. } => {
193+ debug_assert ! ( false ) ;
194+ false
195+ } ,
173196 } ;
174197 if remove_res {
175198 if let PendingOutboundPayment :: Retryable { ref mut pending_amt_msat, ref mut pending_fee_msat, .. } = self {
@@ -189,6 +212,10 @@ impl PendingOutboundPayment {
189212 PendingOutboundPayment :: Retryable { session_privs, .. } => {
190213 session_privs. insert ( session_priv)
191214 }
215+ PendingOutboundPayment :: AwaitingInvoice { .. } => {
216+ debug_assert ! ( false ) ;
217+ false
218+ } ,
192219 PendingOutboundPayment :: Fulfilled { .. } => false ,
193220 PendingOutboundPayment :: Abandoned { .. } => false ,
194221 } ;
@@ -210,7 +237,8 @@ impl PendingOutboundPayment {
210237 PendingOutboundPayment :: Fulfilled { session_privs, .. } |
211238 PendingOutboundPayment :: Abandoned { session_privs, .. } => {
212239 session_privs. len ( )
213- }
240+ } ,
241+ PendingOutboundPayment :: AwaitingInvoice { .. } => 0 ,
214242 }
215243 }
216244}
@@ -679,7 +707,7 @@ impl OutboundPayments {
679707 let mut outbounds = self . pending_outbound_payments . lock ( ) . unwrap ( ) ;
680708 outbounds. retain ( |pmt_id, pmt| {
681709 let mut retain = true ;
682- if !pmt. is_auto_retryable_now ( ) && pmt. remaining_parts ( ) == 0 {
710+ if !pmt. is_auto_retryable_now ( ) && pmt. remaining_parts ( ) == 0 && !pmt . is_awaiting_invoice ( ) {
683711 pmt. mark_abandoned ( PaymentFailureReason :: RetriesExhausted ) ;
684712 if let PendingOutboundPayment :: Abandoned { payment_hash, reason, .. } = pmt {
685713 pending_events. lock ( ) . unwrap ( ) . push_back ( ( events:: Event :: PaymentFailed {
@@ -697,7 +725,8 @@ impl OutboundPayments {
697725 pub ( super ) fn needs_abandon ( & self ) -> bool {
698726 let outbounds = self . pending_outbound_payments . lock ( ) . unwrap ( ) ;
699727 outbounds. iter ( ) . any ( |( _, pmt) |
700- !pmt. is_auto_retryable_now ( ) && pmt. remaining_parts ( ) == 0 && !pmt. is_fulfilled ( ) )
728+ !pmt. is_auto_retryable_now ( ) && pmt. remaining_parts ( ) == 0 && !pmt. is_fulfilled ( ) &&
729+ !pmt. is_awaiting_invoice ( ) )
701730 }
702731
703732 /// Errors immediately on [`RetryableSendFailure`] error conditions. Otherwise, further errors may
@@ -845,6 +874,10 @@ impl OutboundPayments {
845874 log_error ! ( logger, "Unable to retry payments that were initially sent on LDK versions prior to 0.0.102" ) ;
846875 return
847876 } ,
877+ PendingOutboundPayment :: AwaitingInvoice { .. } => {
878+ log_error ! ( logger, "Payment not yet sent" ) ;
879+ return
880+ } ,
848881 PendingOutboundPayment :: Fulfilled { .. } => {
849882 log_error ! ( logger, "Payment already completed" ) ;
850883 return
@@ -1051,6 +1084,21 @@ impl OutboundPayments {
10511084 }
10521085 }
10531086
1087+ #[ allow( unused) ]
1088+ pub ( super ) fn add_new_awaiting_invoice ( & self , payment_id : PaymentId ) -> Result < ( ) , ( ) > {
1089+ let mut pending_outbounds = self . pending_outbound_payments . lock ( ) . unwrap ( ) ;
1090+ match pending_outbounds. entry ( payment_id) {
1091+ hash_map:: Entry :: Occupied ( _) => Err ( ( ) ) ,
1092+ hash_map:: Entry :: Vacant ( entry) => {
1093+ entry. insert ( PendingOutboundPayment :: AwaitingInvoice {
1094+ timer_ticks_without_response : 0 ,
1095+ } ) ;
1096+
1097+ Ok ( ( ) )
1098+ } ,
1099+ }
1100+ }
1101+
10541102 fn pay_route_internal < NS : Deref , F > (
10551103 & self , route : & Route , payment_hash : PaymentHash , recipient_onion : RecipientOnionFields ,
10561104 keysend_preimage : Option < PaymentPreimage > , payment_id : PaymentId , recv_value_msat : Option < u64 > ,
@@ -1256,19 +1304,19 @@ impl OutboundPayments {
12561304 }
12571305 }
12581306
1259- pub ( super ) fn remove_stale_resolved_payments ( & self ,
1260- pending_events : & Mutex < VecDeque < ( events:: Event , Option < EventCompletionAction > ) > > )
1307+ pub ( super ) fn remove_stale_payments (
1308+ & self , pending_events : & Mutex < VecDeque < ( events:: Event , Option < EventCompletionAction > ) > > )
12611309 {
1262- // If an outbound payment was completed, and no pending HTLCs remain, we should remove it
1263- // from the map. However, if we did that immediately when the last payment HTLC is claimed,
1264- // this could race the user making a duplicate send_payment call and our idempotency
1265- // guarantees would be violated. Instead, we wait a few timer ticks to do the actual
1266- // removal. This should be more than sufficient to ensure the idempotency of any
1267- // `send_payment` calls that were made at the same time the `PaymentSent` event was being
1268- // processed.
12691310 let mut pending_outbound_payments = self . pending_outbound_payments . lock ( ) . unwrap ( ) ;
1270- let pending_events = pending_events. lock ( ) . unwrap ( ) ;
1311+ let mut pending_events = pending_events. lock ( ) . unwrap ( ) ;
12711312 pending_outbound_payments. retain ( |payment_id, payment| {
1313+ // If an outbound payment was completed, and no pending HTLCs remain, we should remove it
1314+ // from the map. However, if we did that immediately when the last payment HTLC is claimed,
1315+ // this could race the user making a duplicate send_payment call and our idempotency
1316+ // guarantees would be violated. Instead, we wait a few timer ticks to do the actual
1317+ // removal. This should be more than sufficient to ensure the idempotency of any
1318+ // `send_payment` calls that were made at the same time the `PaymentSent` event was being
1319+ // processed.
12721320 if let PendingOutboundPayment :: Fulfilled { session_privs, timer_ticks_without_htlcs, .. } = payment {
12731321 let mut no_remaining_entries = session_privs. is_empty ( ) ;
12741322 if no_remaining_entries {
@@ -1293,6 +1341,16 @@ impl OutboundPayments {
12931341 * timer_ticks_without_htlcs = 0 ;
12941342 true
12951343 }
1344+ } else if let PendingOutboundPayment :: AwaitingInvoice { timer_ticks_without_response, .. } = payment {
1345+ * timer_ticks_without_response += 1 ;
1346+ if * timer_ticks_without_response <= INVOICE_REQUEST_TIMEOUT_TICKS {
1347+ true
1348+ } else {
1349+ pending_events. push_back (
1350+ ( events:: Event :: InvoiceRequestFailed { payment_id : * payment_id } , None )
1351+ ) ;
1352+ false
1353+ }
12961354 } else { true }
12971355 } ) ;
12981356 }
@@ -1438,6 +1496,11 @@ impl OutboundPayments {
14381496 } , None ) ) ;
14391497 payment. remove ( ) ;
14401498 }
1499+ } else if let PendingOutboundPayment :: AwaitingInvoice { .. } = payment. get ( ) {
1500+ pending_events. lock ( ) . unwrap ( ) . push_back ( ( events:: Event :: InvoiceRequestFailed {
1501+ payment_id,
1502+ } , None ) ) ;
1503+ payment. remove ( ) ;
14411504 }
14421505 }
14431506 }
@@ -1501,6 +1564,9 @@ impl_writeable_tlv_based_enum_upgradable!(PendingOutboundPayment,
15011564 ( 1 , reason, option) ,
15021565 ( 2 , payment_hash, required) ,
15031566 } ,
1567+ ( 5 , AwaitingInvoice ) => {
1568+ ( 0 , timer_ticks_without_response, required) ,
1569+ } ,
15041570) ;
15051571
15061572#[ cfg( test) ]
0 commit comments