@@ -32,12 +32,21 @@ use core::ops::Deref;
32
32
use crate :: prelude:: * ;
33
33
use crate :: sync:: Mutex ;
34
34
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
+
35
41
/// Stores the session_priv for each part of a payment that is still pending. For versions 0.0.102
36
42
/// and later, also stores information for retrying the payment.
37
43
pub ( crate ) enum PendingOutboundPayment {
38
44
Legacy {
39
45
session_privs : HashSet < [ u8 ; 32 ] > ,
40
46
} ,
47
+ AwaitingInvoice {
48
+ timer_ticks_without_response : u8 ,
49
+ } ,
41
50
Retryable {
42
51
retry_strategy : Option < Retry > ,
43
52
attempts : PaymentAttempts ,
@@ -108,6 +117,12 @@ impl PendingOutboundPayment {
108
117
params. previously_failed_channels . push ( scid) ;
109
118
}
110
119
}
120
+ fn is_awaiting_invoice ( & self ) -> bool {
121
+ match self {
122
+ PendingOutboundPayment :: AwaitingInvoice { .. } => true ,
123
+ _ => false ,
124
+ }
125
+ }
111
126
pub ( super ) fn is_fulfilled ( & self ) -> bool {
112
127
match self {
113
128
PendingOutboundPayment :: Fulfilled { .. } => true ,
@@ -130,6 +145,7 @@ impl PendingOutboundPayment {
130
145
fn payment_hash ( & self ) -> Option < PaymentHash > {
131
146
match self {
132
147
PendingOutboundPayment :: Legacy { .. } => None ,
148
+ PendingOutboundPayment :: AwaitingInvoice { .. } => None ,
133
149
PendingOutboundPayment :: Retryable { payment_hash, .. } => Some ( * payment_hash) ,
134
150
PendingOutboundPayment :: Fulfilled { payment_hash, .. } => * payment_hash,
135
151
PendingOutboundPayment :: Abandoned { payment_hash, .. } => Some ( * payment_hash) ,
@@ -142,8 +158,11 @@ impl PendingOutboundPayment {
142
158
PendingOutboundPayment :: Legacy { session_privs } |
143
159
PendingOutboundPayment :: Retryable { session_privs, .. } |
144
160
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
+ } ,
147
166
} ) ;
148
167
let payment_hash = self . payment_hash ( ) ;
149
168
* self = PendingOutboundPayment :: Fulfilled { session_privs, payment_hash, timer_ticks_without_htlcs : 0 } ;
@@ -169,7 +188,11 @@ impl PendingOutboundPayment {
169
188
PendingOutboundPayment :: Fulfilled { session_privs, .. } |
170
189
PendingOutboundPayment :: Abandoned { session_privs, .. } => {
171
190
session_privs. remove ( session_priv)
172
- }
191
+ } ,
192
+ PendingOutboundPayment :: AwaitingInvoice { .. } => {
193
+ debug_assert ! ( false ) ;
194
+ false
195
+ } ,
173
196
} ;
174
197
if remove_res {
175
198
if let PendingOutboundPayment :: Retryable { ref mut pending_amt_msat, ref mut pending_fee_msat, .. } = self {
@@ -189,6 +212,10 @@ impl PendingOutboundPayment {
189
212
PendingOutboundPayment :: Retryable { session_privs, .. } => {
190
213
session_privs. insert ( session_priv)
191
214
}
215
+ PendingOutboundPayment :: AwaitingInvoice { .. } => {
216
+ debug_assert ! ( false ) ;
217
+ false
218
+ } ,
192
219
PendingOutboundPayment :: Fulfilled { .. } => false ,
193
220
PendingOutboundPayment :: Abandoned { .. } => false ,
194
221
} ;
@@ -210,7 +237,8 @@ impl PendingOutboundPayment {
210
237
PendingOutboundPayment :: Fulfilled { session_privs, .. } |
211
238
PendingOutboundPayment :: Abandoned { session_privs, .. } => {
212
239
session_privs. len ( )
213
- }
240
+ } ,
241
+ PendingOutboundPayment :: AwaitingInvoice { .. } => 0 ,
214
242
}
215
243
}
216
244
}
@@ -679,7 +707,7 @@ impl OutboundPayments {
679
707
let mut outbounds = self . pending_outbound_payments . lock ( ) . unwrap ( ) ;
680
708
outbounds. retain ( |pmt_id, pmt| {
681
709
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 ( ) {
683
711
pmt. mark_abandoned ( PaymentFailureReason :: RetriesExhausted ) ;
684
712
if let PendingOutboundPayment :: Abandoned { payment_hash, reason, .. } = pmt {
685
713
pending_events. lock ( ) . unwrap ( ) . push_back ( ( events:: Event :: PaymentFailed {
@@ -697,7 +725,8 @@ impl OutboundPayments {
697
725
pub ( super ) fn needs_abandon ( & self ) -> bool {
698
726
let outbounds = self . pending_outbound_payments . lock ( ) . unwrap ( ) ;
699
727
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 ( ) )
701
730
}
702
731
703
732
/// Errors immediately on [`RetryableSendFailure`] error conditions. Otherwise, further errors may
@@ -845,6 +874,10 @@ impl OutboundPayments {
845
874
log_error ! ( logger, "Unable to retry payments that were initially sent on LDK versions prior to 0.0.102" ) ;
846
875
return
847
876
} ,
877
+ PendingOutboundPayment :: AwaitingInvoice { .. } => {
878
+ log_error ! ( logger, "Payment not yet sent" ) ;
879
+ return
880
+ } ,
848
881
PendingOutboundPayment :: Fulfilled { .. } => {
849
882
log_error ! ( logger, "Payment already completed" ) ;
850
883
return
@@ -1051,6 +1084,21 @@ impl OutboundPayments {
1051
1084
}
1052
1085
}
1053
1086
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
+
1054
1102
fn pay_route_internal < NS : Deref , F > (
1055
1103
& self , route : & Route , payment_hash : PaymentHash , recipient_onion : RecipientOnionFields ,
1056
1104
keysend_preimage : Option < PaymentPreimage > , payment_id : PaymentId , recv_value_msat : Option < u64 > ,
@@ -1256,19 +1304,19 @@ impl OutboundPayments {
1256
1304
}
1257
1305
}
1258
1306
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 > ) > > )
1261
1309
{
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.
1269
1310
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 ( ) ;
1271
1312
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.
1272
1320
if let PendingOutboundPayment :: Fulfilled { session_privs, timer_ticks_without_htlcs, .. } = payment {
1273
1321
let mut no_remaining_entries = session_privs. is_empty ( ) ;
1274
1322
if no_remaining_entries {
@@ -1293,6 +1341,16 @@ impl OutboundPayments {
1293
1341
* timer_ticks_without_htlcs = 0 ;
1294
1342
true
1295
1343
}
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
+ }
1296
1354
} else { true }
1297
1355
} ) ;
1298
1356
}
@@ -1438,6 +1496,11 @@ impl OutboundPayments {
1438
1496
} , None ) ) ;
1439
1497
payment. remove ( ) ;
1440
1498
}
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 ( ) ;
1441
1504
}
1442
1505
}
1443
1506
}
@@ -1501,6 +1564,9 @@ impl_writeable_tlv_based_enum_upgradable!(PendingOutboundPayment,
1501
1564
( 1 , reason, option) ,
1502
1565
( 2 , payment_hash, required) ,
1503
1566
} ,
1567
+ ( 5 , AwaitingInvoice ) => {
1568
+ ( 0 , timer_ticks_without_response, required) ,
1569
+ } ,
1504
1570
) ;
1505
1571
1506
1572
#[ cfg( test) ]
0 commit comments