@@ -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:: 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 ,
@@ -107,6 +110,12 @@ impl PendingOutboundPayment {
107
110
params. previously_failed_channels . push ( scid) ;
108
111
}
109
112
}
113
+ fn is_awaiting_invoice ( & self ) -> bool {
114
+ match self {
115
+ PendingOutboundPayment :: AwaitingInvoice { .. } => true ,
116
+ _ => false ,
117
+ }
118
+ }
110
119
pub ( super ) fn is_fulfilled ( & self ) -> bool {
111
120
match self {
112
121
PendingOutboundPayment :: Fulfilled { .. } => true ,
@@ -129,6 +138,7 @@ impl PendingOutboundPayment {
129
138
fn payment_hash ( & self ) -> Option < PaymentHash > {
130
139
match self {
131
140
PendingOutboundPayment :: Legacy { .. } => None ,
141
+ PendingOutboundPayment :: AwaitingInvoice { .. } => None ,
132
142
PendingOutboundPayment :: Retryable { payment_hash, .. } => Some ( * payment_hash) ,
133
143
PendingOutboundPayment :: Fulfilled { payment_hash, .. } => * payment_hash,
134
144
PendingOutboundPayment :: Abandoned { payment_hash, .. } => Some ( * payment_hash) ,
@@ -141,8 +151,8 @@ impl PendingOutboundPayment {
141
151
PendingOutboundPayment :: Legacy { session_privs } |
142
152
PendingOutboundPayment :: Retryable { session_privs, .. } |
143
153
PendingOutboundPayment :: Fulfilled { session_privs, .. } |
144
- PendingOutboundPayment :: Abandoned { session_privs, .. }
145
- => session_privs ,
154
+ PendingOutboundPayment :: Abandoned { session_privs, .. } => session_privs ,
155
+ PendingOutboundPayment :: AwaitingInvoice { .. } => return ,
146
156
} ) ;
147
157
let payment_hash = self . payment_hash ( ) ;
148
158
* self = PendingOutboundPayment :: Fulfilled { session_privs, payment_hash, timer_ticks_without_htlcs : 0 } ;
@@ -168,7 +178,8 @@ impl PendingOutboundPayment {
168
178
PendingOutboundPayment :: Fulfilled { session_privs, .. } |
169
179
PendingOutboundPayment :: Abandoned { session_privs, .. } => {
170
180
session_privs. remove ( session_priv)
171
- }
181
+ } ,
182
+ PendingOutboundPayment :: AwaitingInvoice { .. } => false ,
172
183
} ;
173
184
if remove_res {
174
185
if let PendingOutboundPayment :: Retryable { ref mut pending_amt_msat, ref mut pending_fee_msat, .. } = self {
@@ -188,6 +199,7 @@ impl PendingOutboundPayment {
188
199
PendingOutboundPayment :: Retryable { session_privs, .. } => {
189
200
session_privs. insert ( session_priv)
190
201
}
202
+ PendingOutboundPayment :: AwaitingInvoice { .. } => false ,
191
203
PendingOutboundPayment :: Fulfilled { .. } => false ,
192
204
PendingOutboundPayment :: Abandoned { .. } => false ,
193
205
} ;
@@ -209,7 +221,8 @@ impl PendingOutboundPayment {
209
221
PendingOutboundPayment :: Fulfilled { session_privs, .. } |
210
222
PendingOutboundPayment :: Abandoned { session_privs, .. } => {
211
223
session_privs. len ( )
212
- }
224
+ } ,
225
+ PendingOutboundPayment :: AwaitingInvoice { .. } => 0 ,
213
226
}
214
227
}
215
228
}
@@ -619,7 +632,7 @@ impl OutboundPayments {
619
632
let mut outbounds = self . pending_outbound_payments . lock ( ) . unwrap ( ) ;
620
633
outbounds. retain ( |pmt_id, pmt| {
621
634
let mut retain = true ;
622
- if !pmt. is_auto_retryable_now ( ) && pmt. remaining_parts ( ) == 0 {
635
+ if !pmt. is_auto_retryable_now ( ) && pmt. remaining_parts ( ) == 0 && !pmt . is_awaiting_invoice ( ) {
623
636
pmt. mark_abandoned ( PaymentFailureReason :: RetriesExhausted ) ;
624
637
if let PendingOutboundPayment :: Abandoned { payment_hash, reason, .. } = pmt {
625
638
pending_events. lock ( ) . unwrap ( ) . push_back ( ( events:: Event :: PaymentFailed {
@@ -637,7 +650,8 @@ impl OutboundPayments {
637
650
pub ( super ) fn needs_abandon ( & self ) -> bool {
638
651
let outbounds = self . pending_outbound_payments . lock ( ) . unwrap ( ) ;
639
652
outbounds. iter ( ) . any ( |( _, pmt) |
640
- !pmt. is_auto_retryable_now ( ) && pmt. remaining_parts ( ) == 0 && !pmt. is_fulfilled ( ) )
653
+ !pmt. is_auto_retryable_now ( ) && pmt. remaining_parts ( ) == 0 && !pmt. is_fulfilled ( ) &&
654
+ !pmt. is_awaiting_invoice ( ) )
641
655
}
642
656
643
657
/// Errors immediately on [`RetryableSendFailure`] error conditions. Otherwise, further errors may
@@ -774,6 +788,10 @@ impl OutboundPayments {
774
788
log_error ! ( logger, "Unable to retry payments that were initially sent on LDK versions prior to 0.0.102" ) ;
775
789
return
776
790
} ,
791
+ PendingOutboundPayment :: AwaitingInvoice { .. } => {
792
+ log_error ! ( logger, "Payment not yet sent" ) ;
793
+ return
794
+ } ,
777
795
PendingOutboundPayment :: Fulfilled { .. } => {
778
796
log_error ! ( logger, "Payment already completed" ) ;
779
797
return
@@ -1185,19 +1203,19 @@ impl OutboundPayments {
1185
1203
}
1186
1204
}
1187
1205
1188
- pub ( super ) fn remove_stale_resolved_payments ( & self ,
1189
- pending_events : & Mutex < VecDeque < ( events:: Event , Option < EventCompletionAction > ) > > )
1206
+ pub ( super ) fn remove_stale_payments (
1207
+ & self , pending_events : & Mutex < VecDeque < ( events:: Event , Option < EventCompletionAction > ) > > )
1190
1208
{
1191
- // If an outbound payment was completed, and no pending HTLCs remain, we should remove it
1192
- // from the map. However, if we did that immediately when the last payment HTLC is claimed,
1193
- // this could race the user making a duplicate send_payment call and our idempotency
1194
- // guarantees would be violated. Instead, we wait a few timer ticks to do the actual
1195
- // removal. This should be more than sufficient to ensure the idempotency of any
1196
- // `send_payment` calls that were made at the same time the `PaymentSent` event was being
1197
- // processed.
1198
1209
let mut pending_outbound_payments = self . pending_outbound_payments . lock ( ) . unwrap ( ) ;
1199
- let pending_events = pending_events. lock ( ) . unwrap ( ) ;
1210
+ let mut pending_events = pending_events. lock ( ) . unwrap ( ) ;
1200
1211
pending_outbound_payments. retain ( |payment_id, payment| {
1212
+ // If an outbound payment was completed, and no pending HTLCs remain, we should remove it
1213
+ // from the map. However, if we did that immediately when the last payment HTLC is claimed,
1214
+ // this could race the user making a duplicate send_payment call and our idempotency
1215
+ // guarantees would be violated. Instead, we wait a few timer ticks to do the actual
1216
+ // removal. This should be more than sufficient to ensure the idempotency of any
1217
+ // `send_payment` calls that were made at the same time the `PaymentSent` event was being
1218
+ // processed.
1201
1219
if let PendingOutboundPayment :: Fulfilled { session_privs, timer_ticks_without_htlcs, .. } = payment {
1202
1220
let mut no_remaining_entries = session_privs. is_empty ( ) ;
1203
1221
if no_remaining_entries {
@@ -1222,6 +1240,16 @@ impl OutboundPayments {
1222
1240
* timer_ticks_without_htlcs = 0 ;
1223
1241
true
1224
1242
}
1243
+ } else if let PendingOutboundPayment :: AwaitingInvoice { timer_ticks_without_response, .. } = payment {
1244
+ * timer_ticks_without_response += 1 ;
1245
+ if * timer_ticks_without_response <= INVOICE_REQUEST_TIMEOUT_TICKS {
1246
+ true
1247
+ } else {
1248
+ pending_events. push_back (
1249
+ ( events:: Event :: InvoiceRequestFailed { payment_id : * payment_id } , None )
1250
+ ) ;
1251
+ false
1252
+ }
1225
1253
} else { true }
1226
1254
} ) ;
1227
1255
}
@@ -1426,6 +1454,9 @@ impl_writeable_tlv_based_enum_upgradable!(PendingOutboundPayment,
1426
1454
( 1 , reason, option) ,
1427
1455
( 2 , payment_hash, required) ,
1428
1456
} ,
1457
+ ( 5 , AwaitingInvoice ) => {
1458
+ ( 0 , timer_ticks_without_response, required) ,
1459
+ } ,
1429
1460
) ;
1430
1461
1431
1462
#[ cfg( test) ]
0 commit comments