@@ -16,7 +16,7 @@ use bitcoin::secp256k1::{self, Secp256k1, SecretKey};
16
16
use crate :: sign:: { EntropySource , NodeSigner , Recipient } ;
17
17
use crate :: events:: { self , PaymentFailureReason } ;
18
18
use crate :: ln:: { PaymentHash , PaymentPreimage , PaymentSecret } ;
19
- use crate :: ln:: channelmanager:: { ChannelDetails , EventCompletionAction , HTLCSource , IDEMPOTENCY_TIMEOUT_TICKS , PaymentId } ;
19
+ use crate :: ln:: channelmanager:: { ChannelDetails , EventCompletionAction , HTLCSource , IDEMPOTENCY_TIMEOUT_TICKS , INVOICE_REQUEST_TIMEOUT_TICKS , PaymentId } ;
20
20
use crate :: ln:: onion_utils:: { DecodedOnionFailure , HTLCFailReason } ;
21
21
use crate :: routing:: router:: { InFlightHtlcs , Path , PaymentParameters , Route , RouteParameters , Router } ;
22
22
use crate :: util:: errors:: APIError ;
@@ -38,6 +38,9 @@ pub(crate) enum PendingOutboundPayment {
38
38
Legacy {
39
39
session_privs : HashSet < [ u8 ; 32 ] > ,
40
40
} ,
41
+ AwaitingInvoice {
42
+ timer_ticks_without_response : u8 ,
43
+ } ,
41
44
Retryable {
42
45
retry_strategy : Option < Retry > ,
43
46
attempts : PaymentAttempts ,
@@ -108,6 +111,12 @@ impl PendingOutboundPayment {
108
111
params. previously_failed_channels . push ( scid) ;
109
112
}
110
113
}
114
+ fn is_awaiting_invoice ( & self ) -> bool {
115
+ match self {
116
+ PendingOutboundPayment :: AwaitingInvoice { .. } => true ,
117
+ _ => false ,
118
+ }
119
+ }
111
120
pub ( super ) fn is_fulfilled ( & self ) -> bool {
112
121
match self {
113
122
PendingOutboundPayment :: Fulfilled { .. } => true ,
@@ -130,6 +139,7 @@ impl PendingOutboundPayment {
130
139
fn payment_hash ( & self ) -> Option < PaymentHash > {
131
140
match self {
132
141
PendingOutboundPayment :: Legacy { .. } => None ,
142
+ PendingOutboundPayment :: AwaitingInvoice { .. } => None ,
133
143
PendingOutboundPayment :: Retryable { payment_hash, .. } => Some ( * payment_hash) ,
134
144
PendingOutboundPayment :: Fulfilled { payment_hash, .. } => * payment_hash,
135
145
PendingOutboundPayment :: Abandoned { payment_hash, .. } => Some ( * payment_hash) ,
@@ -142,8 +152,11 @@ impl PendingOutboundPayment {
142
152
PendingOutboundPayment :: Legacy { session_privs } |
143
153
PendingOutboundPayment :: Retryable { session_privs, .. } |
144
154
PendingOutboundPayment :: Fulfilled { session_privs, .. } |
145
- PendingOutboundPayment :: Abandoned { session_privs, .. }
146
- => session_privs,
155
+ PendingOutboundPayment :: Abandoned { session_privs, .. } => session_privs,
156
+ PendingOutboundPayment :: AwaitingInvoice { .. } => {
157
+ debug_assert ! ( false ) ;
158
+ return ;
159
+ } ,
147
160
} ) ;
148
161
let payment_hash = self . payment_hash ( ) ;
149
162
* self = PendingOutboundPayment :: Fulfilled { session_privs, payment_hash, timer_ticks_without_htlcs : 0 } ;
@@ -169,7 +182,8 @@ impl PendingOutboundPayment {
169
182
PendingOutboundPayment :: Fulfilled { session_privs, .. } |
170
183
PendingOutboundPayment :: Abandoned { session_privs, .. } => {
171
184
session_privs. remove ( session_priv)
172
- }
185
+ } ,
186
+ PendingOutboundPayment :: AwaitingInvoice { .. } => false ,
173
187
} ;
174
188
if remove_res {
175
189
if let PendingOutboundPayment :: Retryable { ref mut pending_amt_msat, ref mut pending_fee_msat, .. } = self {
@@ -189,6 +203,7 @@ impl PendingOutboundPayment {
189
203
PendingOutboundPayment :: Retryable { session_privs, .. } => {
190
204
session_privs. insert ( session_priv)
191
205
}
206
+ PendingOutboundPayment :: AwaitingInvoice { .. } => false ,
192
207
PendingOutboundPayment :: Fulfilled { .. } => false ,
193
208
PendingOutboundPayment :: Abandoned { .. } => false ,
194
209
} ;
@@ -210,7 +225,8 @@ impl PendingOutboundPayment {
210
225
PendingOutboundPayment :: Fulfilled { session_privs, .. } |
211
226
PendingOutboundPayment :: Abandoned { session_privs, .. } => {
212
227
session_privs. len ( )
213
- }
228
+ } ,
229
+ PendingOutboundPayment :: AwaitingInvoice { .. } => 0 ,
214
230
}
215
231
}
216
232
}
@@ -679,7 +695,7 @@ impl OutboundPayments {
679
695
let mut outbounds = self . pending_outbound_payments . lock ( ) . unwrap ( ) ;
680
696
outbounds. retain ( |pmt_id, pmt| {
681
697
let mut retain = true ;
682
- if !pmt. is_auto_retryable_now ( ) && pmt. remaining_parts ( ) == 0 {
698
+ if !pmt. is_auto_retryable_now ( ) && pmt. remaining_parts ( ) == 0 && !pmt . is_awaiting_invoice ( ) {
683
699
pmt. mark_abandoned ( PaymentFailureReason :: RetriesExhausted ) ;
684
700
if let PendingOutboundPayment :: Abandoned { payment_hash, reason, .. } = pmt {
685
701
pending_events. lock ( ) . unwrap ( ) . push_back ( ( events:: Event :: PaymentFailed {
@@ -697,7 +713,8 @@ impl OutboundPayments {
697
713
pub ( super ) fn needs_abandon ( & self ) -> bool {
698
714
let outbounds = self . pending_outbound_payments . lock ( ) . unwrap ( ) ;
699
715
outbounds. iter ( ) . any ( |( _, pmt) |
700
- !pmt. is_auto_retryable_now ( ) && pmt. remaining_parts ( ) == 0 && !pmt. is_fulfilled ( ) )
716
+ !pmt. is_auto_retryable_now ( ) && pmt. remaining_parts ( ) == 0 && !pmt. is_fulfilled ( ) &&
717
+ !pmt. is_awaiting_invoice ( ) )
701
718
}
702
719
703
720
/// Errors immediately on [`RetryableSendFailure`] error conditions. Otherwise, further errors may
@@ -845,6 +862,10 @@ impl OutboundPayments {
845
862
log_error ! ( logger, "Unable to retry payments that were initially sent on LDK versions prior to 0.0.102" ) ;
846
863
return
847
864
} ,
865
+ PendingOutboundPayment :: AwaitingInvoice { .. } => {
866
+ log_error ! ( logger, "Payment not yet sent" ) ;
867
+ return
868
+ } ,
848
869
PendingOutboundPayment :: Fulfilled { .. } => {
849
870
log_error ! ( logger, "Payment already completed" ) ;
850
871
return
@@ -1051,6 +1072,21 @@ impl OutboundPayments {
1051
1072
}
1052
1073
}
1053
1074
1075
+ #[ allow( unused) ]
1076
+ pub ( super ) fn add_new_awaiting_invoice ( & self , payment_id : PaymentId ) -> Result < ( ) , ( ) > {
1077
+ let mut pending_outbounds = self . pending_outbound_payments . lock ( ) . unwrap ( ) ;
1078
+ match pending_outbounds. entry ( payment_id) {
1079
+ hash_map:: Entry :: Occupied ( _) => Err ( ( ) ) ,
1080
+ hash_map:: Entry :: Vacant ( entry) => {
1081
+ entry. insert ( PendingOutboundPayment :: AwaitingInvoice {
1082
+ timer_ticks_without_response : 0 ,
1083
+ } ) ;
1084
+
1085
+ Ok ( ( ) )
1086
+ } ,
1087
+ }
1088
+ }
1089
+
1054
1090
fn pay_route_internal < NS : Deref , F > (
1055
1091
& self , route : & Route , payment_hash : PaymentHash , recipient_onion : RecipientOnionFields ,
1056
1092
keysend_preimage : Option < PaymentPreimage > , payment_id : PaymentId , recv_value_msat : Option < u64 > ,
@@ -1256,19 +1292,19 @@ impl OutboundPayments {
1256
1292
}
1257
1293
}
1258
1294
1259
- pub ( super ) fn remove_stale_resolved_payments ( & self ,
1260
- pending_events : & Mutex < VecDeque < ( events:: Event , Option < EventCompletionAction > ) > > )
1295
+ pub ( super ) fn remove_stale_payments (
1296
+ & self , pending_events : & Mutex < VecDeque < ( events:: Event , Option < EventCompletionAction > ) > > )
1261
1297
{
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
1298
let mut pending_outbound_payments = self . pending_outbound_payments . lock ( ) . unwrap ( ) ;
1270
- let pending_events = pending_events. lock ( ) . unwrap ( ) ;
1299
+ let mut pending_events = pending_events. lock ( ) . unwrap ( ) ;
1271
1300
pending_outbound_payments. retain ( |payment_id, payment| {
1301
+ // If an outbound payment was completed, and no pending HTLCs remain, we should remove it
1302
+ // from the map. However, if we did that immediately when the last payment HTLC is claimed,
1303
+ // this could race the user making a duplicate send_payment call and our idempotency
1304
+ // guarantees would be violated. Instead, we wait a few timer ticks to do the actual
1305
+ // removal. This should be more than sufficient to ensure the idempotency of any
1306
+ // `send_payment` calls that were made at the same time the `PaymentSent` event was being
1307
+ // processed.
1272
1308
if let PendingOutboundPayment :: Fulfilled { session_privs, timer_ticks_without_htlcs, .. } = payment {
1273
1309
let mut no_remaining_entries = session_privs. is_empty ( ) ;
1274
1310
if no_remaining_entries {
@@ -1293,6 +1329,16 @@ impl OutboundPayments {
1293
1329
* timer_ticks_without_htlcs = 0 ;
1294
1330
true
1295
1331
}
1332
+ } else if let PendingOutboundPayment :: AwaitingInvoice { timer_ticks_without_response, .. } = payment {
1333
+ * timer_ticks_without_response += 1 ;
1334
+ if * timer_ticks_without_response <= INVOICE_REQUEST_TIMEOUT_TICKS {
1335
+ true
1336
+ } else {
1337
+ pending_events. push_back (
1338
+ ( events:: Event :: InvoiceRequestFailed { payment_id : * payment_id } , None )
1339
+ ) ;
1340
+ false
1341
+ }
1296
1342
} else { true }
1297
1343
} ) ;
1298
1344
}
@@ -1501,6 +1547,9 @@ impl_writeable_tlv_based_enum_upgradable!(PendingOutboundPayment,
1501
1547
( 1 , reason, option) ,
1502
1548
( 2 , payment_hash, required) ,
1503
1549
} ,
1550
+ ( 5 , AwaitingInvoice ) => {
1551
+ ( 0 , timer_ticks_without_response, required) ,
1552
+ } ,
1504
1553
) ;
1505
1554
1506
1555
#[ cfg( test) ]
0 commit comments