@@ -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
}
@@ -626,7 +639,7 @@ impl OutboundPayments {
626
639
let mut outbounds = self . pending_outbound_payments . lock ( ) . unwrap ( ) ;
627
640
outbounds. retain ( |pmt_id, pmt| {
628
641
let mut retain = true ;
629
- if !pmt. is_auto_retryable_now ( ) && pmt. remaining_parts ( ) == 0 {
642
+ if !pmt. is_auto_retryable_now ( ) && pmt. remaining_parts ( ) == 0 && !pmt . is_awaiting_invoice ( ) {
630
643
pmt. mark_abandoned ( PaymentFailureReason :: RetriesExhausted ) ;
631
644
if let PendingOutboundPayment :: Abandoned { payment_hash, reason, .. } = pmt {
632
645
pending_events. lock ( ) . unwrap ( ) . push_back ( ( events:: Event :: PaymentFailed {
@@ -644,7 +657,8 @@ impl OutboundPayments {
644
657
pub ( super ) fn needs_abandon ( & self ) -> bool {
645
658
let outbounds = self . pending_outbound_payments . lock ( ) . unwrap ( ) ;
646
659
outbounds. iter ( ) . any ( |( _, pmt) |
647
- !pmt. is_auto_retryable_now ( ) && pmt. remaining_parts ( ) == 0 && !pmt. is_fulfilled ( ) )
660
+ !pmt. is_auto_retryable_now ( ) && pmt. remaining_parts ( ) == 0 && !pmt. is_fulfilled ( ) &&
661
+ !pmt. is_awaiting_invoice ( ) )
648
662
}
649
663
650
664
/// Errors immediately on [`RetryableSendFailure`] error conditions. Otherwise, further errors may
@@ -779,6 +793,10 @@ impl OutboundPayments {
779
793
log_error ! ( logger, "Unable to retry payments that were initially sent on LDK versions prior to 0.0.102" ) ;
780
794
return
781
795
} ,
796
+ PendingOutboundPayment :: AwaitingInvoice { .. } => {
797
+ log_error ! ( logger, "Payment not yet sent" ) ;
798
+ return
799
+ } ,
782
800
PendingOutboundPayment :: Fulfilled { .. } => {
783
801
log_error ! ( logger, "Payment already completed" ) ;
784
802
return
@@ -951,37 +969,44 @@ impl OutboundPayments {
951
969
keysend_preimage : Option < PaymentPreimage > , route : & Route , retry_strategy : Option < Retry > ,
952
970
payment_params : Option < PaymentParameters > , entropy_source : & ES , best_block_height : u32
953
971
) -> Result < Vec < [ u8 ; 32 ] > , PaymentSendFailure > where ES :: Target : EntropySource {
972
+ let mut pending_outbounds = self . pending_outbound_payments . lock ( ) . unwrap ( ) ;
973
+ let entry = pending_outbounds. entry ( payment_id) ;
974
+ if let hash_map:: Entry :: Occupied ( entry) = & entry {
975
+ if let PendingOutboundPayment :: AwaitingInvoice { .. } = entry. get ( ) { } else {
976
+ return Err ( PaymentSendFailure :: DuplicatePayment )
977
+ }
978
+ }
979
+
954
980
let mut onion_session_privs = Vec :: with_capacity ( route. paths . len ( ) ) ;
955
981
for _ in 0 ..route. paths . len ( ) {
956
982
onion_session_privs. push ( entropy_source. get_secure_random_bytes ( ) ) ;
957
983
}
958
984
959
- let mut pending_outbounds = self . pending_outbound_payments . lock ( ) . unwrap ( ) ;
960
- match pending_outbounds. entry ( payment_id) {
961
- hash_map:: Entry :: Occupied ( _) => Err ( PaymentSendFailure :: DuplicatePayment ) ,
962
- hash_map:: Entry :: Vacant ( entry) => {
963
- let payment = entry. insert ( PendingOutboundPayment :: Retryable {
964
- retry_strategy,
965
- attempts : PaymentAttempts :: new ( ) ,
966
- payment_params,
967
- session_privs : HashSet :: new ( ) ,
968
- pending_amt_msat : 0 ,
969
- pending_fee_msat : Some ( 0 ) ,
970
- payment_hash,
971
- payment_secret : recipient_onion. payment_secret ,
972
- payment_metadata : recipient_onion. payment_metadata ,
973
- keysend_preimage,
974
- starting_block_height : best_block_height,
975
- total_msat : route. get_total_amount ( ) ,
976
- } ) ;
977
-
978
- for ( path, session_priv_bytes) in route. paths . iter ( ) . zip ( onion_session_privs. iter ( ) ) {
979
- assert ! ( payment. insert( * session_priv_bytes, path) ) ;
980
- }
985
+ let mut payment = PendingOutboundPayment :: Retryable {
986
+ retry_strategy,
987
+ attempts : PaymentAttempts :: new ( ) ,
988
+ payment_params,
989
+ session_privs : HashSet :: new ( ) ,
990
+ pending_amt_msat : 0 ,
991
+ pending_fee_msat : Some ( 0 ) ,
992
+ payment_hash,
993
+ payment_secret : recipient_onion. payment_secret ,
994
+ payment_metadata : recipient_onion. payment_metadata ,
995
+ keysend_preimage,
996
+ starting_block_height : best_block_height,
997
+ total_msat : route. get_total_amount ( ) ,
998
+ } ;
981
999
982
- Ok ( onion_session_privs)
983
- } ,
1000
+ for ( path, session_priv_bytes) in route. paths . iter ( ) . zip ( onion_session_privs. iter ( ) ) {
1001
+ assert ! ( payment. insert( * session_priv_bytes, path) ) ;
1002
+ }
1003
+
1004
+ match entry {
1005
+ hash_map:: Entry :: Occupied ( mut entry) => { entry. insert ( payment) ; } ,
1006
+ hash_map:: Entry :: Vacant ( entry) => { entry. insert ( payment) ; } ,
984
1007
}
1008
+
1009
+ Ok ( onion_session_privs)
985
1010
}
986
1011
987
1012
fn pay_route_internal < NS : Deref , F > (
@@ -1188,19 +1213,19 @@ impl OutboundPayments {
1188
1213
}
1189
1214
}
1190
1215
1191
- pub ( super ) fn remove_stale_resolved_payments ( & self ,
1192
- pending_events : & Mutex < VecDeque < ( events:: Event , Option < EventCompletionAction > ) > > )
1216
+ pub ( super ) fn remove_stale_payments (
1217
+ & self , pending_events : & Mutex < VecDeque < ( events:: Event , Option < EventCompletionAction > ) > > )
1193
1218
{
1194
- // If an outbound payment was completed, and no pending HTLCs remain, we should remove it
1195
- // from the map. However, if we did that immediately when the last payment HTLC is claimed,
1196
- // this could race the user making a duplicate send_payment call and our idempotency
1197
- // guarantees would be violated. Instead, we wait a few timer ticks to do the actual
1198
- // removal. This should be more than sufficient to ensure the idempotency of any
1199
- // `send_payment` calls that were made at the same time the `PaymentSent` event was being
1200
- // processed.
1201
1219
let mut pending_outbound_payments = self . pending_outbound_payments . lock ( ) . unwrap ( ) ;
1202
- let pending_events = pending_events. lock ( ) . unwrap ( ) ;
1220
+ let mut pending_events = pending_events. lock ( ) . unwrap ( ) ;
1203
1221
pending_outbound_payments. retain ( |payment_id, payment| {
1222
+ // If an outbound payment was completed, and no pending HTLCs remain, we should remove it
1223
+ // from the map. However, if we did that immediately when the last payment HTLC is claimed,
1224
+ // this could race the user making a duplicate send_payment call and our idempotency
1225
+ // guarantees would be violated. Instead, we wait a few timer ticks to do the actual
1226
+ // removal. This should be more than sufficient to ensure the idempotency of any
1227
+ // `send_payment` calls that were made at the same time the `PaymentSent` event was being
1228
+ // processed.
1204
1229
if let PendingOutboundPayment :: Fulfilled { session_privs, timer_ticks_without_htlcs, .. } = payment {
1205
1230
let mut no_remaining_entries = session_privs. is_empty ( ) ;
1206
1231
if no_remaining_entries {
@@ -1225,6 +1250,16 @@ impl OutboundPayments {
1225
1250
* timer_ticks_without_htlcs = 0 ;
1226
1251
true
1227
1252
}
1253
+ } else if let PendingOutboundPayment :: AwaitingInvoice { timer_ticks_without_response, .. } = payment {
1254
+ * timer_ticks_without_response += 1 ;
1255
+ if * timer_ticks_without_response <= INVOICE_REQUEST_TIMEOUT_TICKS {
1256
+ true
1257
+ } else {
1258
+ pending_events. push_back (
1259
+ ( events:: Event :: InvoiceRequestFailed { payment_id : * payment_id } , None )
1260
+ ) ;
1261
+ false
1262
+ }
1228
1263
} else { true }
1229
1264
} ) ;
1230
1265
}
@@ -1429,6 +1464,9 @@ impl_writeable_tlv_based_enum_upgradable!(PendingOutboundPayment,
1429
1464
( 1 , reason, option) ,
1430
1465
( 2 , payment_hash, required) ,
1431
1466
} ,
1467
+ ( 5 , AwaitingInvoice ) => {
1468
+ ( 0 , timer_ticks_without_response, required) ,
1469
+ } ,
1432
1470
) ;
1433
1471
1434
1472
#[ cfg( test) ]
0 commit comments