@@ -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,8 @@ 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 { .. } => false ,
173
193
} ;
174
194
if remove_res {
175
195
if let PendingOutboundPayment :: Retryable { ref mut pending_amt_msat, ref mut pending_fee_msat, .. } = self {
@@ -189,6 +209,7 @@ impl PendingOutboundPayment {
189
209
PendingOutboundPayment :: Retryable { session_privs, .. } => {
190
210
session_privs. insert ( session_priv)
191
211
}
212
+ PendingOutboundPayment :: AwaitingInvoice { .. } => false ,
192
213
PendingOutboundPayment :: Fulfilled { .. } => false ,
193
214
PendingOutboundPayment :: Abandoned { .. } => false ,
194
215
} ;
@@ -210,7 +231,8 @@ impl PendingOutboundPayment {
210
231
PendingOutboundPayment :: Fulfilled { session_privs, .. } |
211
232
PendingOutboundPayment :: Abandoned { session_privs, .. } => {
212
233
session_privs. len ( )
213
- }
234
+ } ,
235
+ PendingOutboundPayment :: AwaitingInvoice { .. } => 0 ,
214
236
}
215
237
}
216
238
}
@@ -679,7 +701,7 @@ impl OutboundPayments {
679
701
let mut outbounds = self . pending_outbound_payments . lock ( ) . unwrap ( ) ;
680
702
outbounds. retain ( |pmt_id, pmt| {
681
703
let mut retain = true ;
682
- if !pmt. is_auto_retryable_now ( ) && pmt. remaining_parts ( ) == 0 {
704
+ if !pmt. is_auto_retryable_now ( ) && pmt. remaining_parts ( ) == 0 && !pmt . is_awaiting_invoice ( ) {
683
705
pmt. mark_abandoned ( PaymentFailureReason :: RetriesExhausted ) ;
684
706
if let PendingOutboundPayment :: Abandoned { payment_hash, reason, .. } = pmt {
685
707
pending_events. lock ( ) . unwrap ( ) . push_back ( ( events:: Event :: PaymentFailed {
@@ -697,7 +719,8 @@ impl OutboundPayments {
697
719
pub ( super ) fn needs_abandon ( & self ) -> bool {
698
720
let outbounds = self . pending_outbound_payments . lock ( ) . unwrap ( ) ;
699
721
outbounds. iter ( ) . any ( |( _, pmt) |
700
- !pmt. is_auto_retryable_now ( ) && pmt. remaining_parts ( ) == 0 && !pmt. is_fulfilled ( ) )
722
+ !pmt. is_auto_retryable_now ( ) && pmt. remaining_parts ( ) == 0 && !pmt. is_fulfilled ( ) &&
723
+ !pmt. is_awaiting_invoice ( ) )
701
724
}
702
725
703
726
/// Errors immediately on [`RetryableSendFailure`] error conditions. Otherwise, further errors may
@@ -845,6 +868,10 @@ impl OutboundPayments {
845
868
log_error ! ( logger, "Unable to retry payments that were initially sent on LDK versions prior to 0.0.102" ) ;
846
869
return
847
870
} ,
871
+ PendingOutboundPayment :: AwaitingInvoice { .. } => {
872
+ log_error ! ( logger, "Payment not yet sent" ) ;
873
+ return
874
+ } ,
848
875
PendingOutboundPayment :: Fulfilled { .. } => {
849
876
log_error ! ( logger, "Payment already completed" ) ;
850
877
return
@@ -1051,6 +1078,21 @@ impl OutboundPayments {
1051
1078
}
1052
1079
}
1053
1080
1081
+ #[ allow( unused) ]
1082
+ pub ( super ) fn add_new_awaiting_invoice ( & self , payment_id : PaymentId ) -> Result < ( ) , ( ) > {
1083
+ let mut pending_outbounds = self . pending_outbound_payments . lock ( ) . unwrap ( ) ;
1084
+ match pending_outbounds. entry ( payment_id) {
1085
+ hash_map:: Entry :: Occupied ( _) => Err ( ( ) ) ,
1086
+ hash_map:: Entry :: Vacant ( entry) => {
1087
+ entry. insert ( PendingOutboundPayment :: AwaitingInvoice {
1088
+ timer_ticks_without_response : 0 ,
1089
+ } ) ;
1090
+
1091
+ Ok ( ( ) )
1092
+ } ,
1093
+ }
1094
+ }
1095
+
1054
1096
fn pay_route_internal < NS : Deref , F > (
1055
1097
& self , route : & Route , payment_hash : PaymentHash , recipient_onion : RecipientOnionFields ,
1056
1098
keysend_preimage : Option < PaymentPreimage > , payment_id : PaymentId , recv_value_msat : Option < u64 > ,
@@ -1256,19 +1298,19 @@ impl OutboundPayments {
1256
1298
}
1257
1299
}
1258
1300
1259
- pub ( super ) fn remove_stale_resolved_payments ( & self ,
1260
- pending_events : & Mutex < VecDeque < ( events:: Event , Option < EventCompletionAction > ) > > )
1301
+ pub ( super ) fn remove_stale_payments (
1302
+ & self , pending_events : & Mutex < VecDeque < ( events:: Event , Option < EventCompletionAction > ) > > )
1261
1303
{
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
1304
let mut pending_outbound_payments = self . pending_outbound_payments . lock ( ) . unwrap ( ) ;
1270
- let pending_events = pending_events. lock ( ) . unwrap ( ) ;
1305
+ let mut pending_events = pending_events. lock ( ) . unwrap ( ) ;
1271
1306
pending_outbound_payments. retain ( |payment_id, payment| {
1307
+ // If an outbound payment was completed, and no pending HTLCs remain, we should remove it
1308
+ // from the map. However, if we did that immediately when the last payment HTLC is claimed,
1309
+ // this could race the user making a duplicate send_payment call and our idempotency
1310
+ // guarantees would be violated. Instead, we wait a few timer ticks to do the actual
1311
+ // removal. This should be more than sufficient to ensure the idempotency of any
1312
+ // `send_payment` calls that were made at the same time the `PaymentSent` event was being
1313
+ // processed.
1272
1314
if let PendingOutboundPayment :: Fulfilled { session_privs, timer_ticks_without_htlcs, .. } = payment {
1273
1315
let mut no_remaining_entries = session_privs. is_empty ( ) ;
1274
1316
if no_remaining_entries {
@@ -1293,6 +1335,16 @@ impl OutboundPayments {
1293
1335
* timer_ticks_without_htlcs = 0 ;
1294
1336
true
1295
1337
}
1338
+ } else if let PendingOutboundPayment :: AwaitingInvoice { timer_ticks_without_response, .. } = payment {
1339
+ * timer_ticks_without_response += 1 ;
1340
+ if * timer_ticks_without_response <= INVOICE_REQUEST_TIMEOUT_TICKS {
1341
+ true
1342
+ } else {
1343
+ pending_events. push_back (
1344
+ ( events:: Event :: InvoiceRequestFailed { payment_id : * payment_id } , None )
1345
+ ) ;
1346
+ false
1347
+ }
1296
1348
} else { true }
1297
1349
} ) ;
1298
1350
}
@@ -1438,6 +1490,11 @@ impl OutboundPayments {
1438
1490
} , None ) ) ;
1439
1491
payment. remove ( ) ;
1440
1492
}
1493
+ } else if let PendingOutboundPayment :: AwaitingInvoice { .. } = payment. get ( ) {
1494
+ pending_events. lock ( ) . unwrap ( ) . push_back ( ( events:: Event :: InvoiceRequestFailed {
1495
+ payment_id,
1496
+ } , None ) ) ;
1497
+ payment. remove ( ) ;
1441
1498
}
1442
1499
}
1443
1500
}
@@ -1501,6 +1558,9 @@ impl_writeable_tlv_based_enum_upgradable!(PendingOutboundPayment,
1501
1558
( 1 , reason, option) ,
1502
1559
( 2 , payment_hash, required) ,
1503
1560
} ,
1561
+ ( 5 , AwaitingInvoice ) => {
1562
+ ( 0 , timer_ticks_without_response, required) ,
1563
+ } ,
1504
1564
) ;
1505
1565
1506
1566
#[ cfg( test) ]
0 commit comments