@@ -22,6 +22,8 @@ use crate::ln::features::Bolt12InvoiceFeatures;
22
22
use crate :: ln:: onion_utils;
23
23
use crate :: ln:: onion_utils:: { DecodedOnionFailure , HTLCFailReason } ;
24
24
use crate :: offers:: invoice:: Bolt12Invoice ;
25
+ use crate :: offers:: invoice_request:: InvoiceRequest ;
26
+ use crate :: offers:: nonce:: Nonce ;
25
27
use crate :: routing:: router:: { BlindedTail , InFlightHtlcs , Path , PaymentParameters , Route , RouteParameters , Router } ;
26
28
use crate :: sign:: { EntropySource , NodeSigner , Recipient } ;
27
29
use crate :: util:: errors:: APIError ;
@@ -33,6 +35,7 @@ use crate::util::ser::ReadableArgs;
33
35
34
36
use core:: fmt:: { self , Display , Formatter } ;
35
37
use core:: ops:: Deref ;
38
+ use core:: sync:: atomic:: { AtomicBool , Ordering } ;
36
39
use core:: time:: Duration ;
37
40
38
41
use crate :: prelude:: * ;
@@ -54,6 +57,7 @@ pub(crate) enum PendingOutboundPayment {
54
57
expiration : StaleExpiration ,
55
58
retry_strategy : Retry ,
56
59
max_total_routing_fee_msat : Option < u64 > ,
60
+ retryable_invoice_request : Option < RetryableInvoiceRequest >
57
61
} ,
58
62
InvoiceReceived {
59
63
payment_hash : PaymentHash ,
@@ -101,6 +105,16 @@ pub(crate) enum PendingOutboundPayment {
101
105
} ,
102
106
}
103
107
108
+ pub ( crate ) struct RetryableInvoiceRequest {
109
+ pub ( crate ) invoice_request : InvoiceRequest ,
110
+ pub ( crate ) nonce : Nonce ,
111
+ }
112
+
113
+ impl_writeable_tlv_based ! ( RetryableInvoiceRequest , {
114
+ ( 0 , invoice_request, required) ,
115
+ ( 2 , nonce, required) ,
116
+ } ) ;
117
+
104
118
impl PendingOutboundPayment {
105
119
fn increment_attempts ( & mut self ) {
106
120
if let PendingOutboundPayment :: Retryable { attempts, .. } = self {
@@ -684,13 +698,19 @@ pub(super) struct SendAlongPathArgs<'a> {
684
698
685
699
pub ( super ) struct OutboundPayments {
686
700
pub ( super ) pending_outbound_payments : Mutex < HashMap < PaymentId , PendingOutboundPayment > > ,
687
- pub ( super ) retry_lock : Mutex < ( ) > ,
701
+ awaiting_invoice : AtomicBool ,
702
+ retry_lock : Mutex < ( ) > ,
688
703
}
689
704
690
705
impl OutboundPayments {
691
- pub ( super ) fn new ( ) -> Self {
706
+ pub ( super ) fn new ( pending_outbound_payments : HashMap < PaymentId , PendingOutboundPayment > ) -> Self {
707
+ let has_invoice_requests = pending_outbound_payments. values ( ) . any ( |payment| {
708
+ matches ! ( payment, PendingOutboundPayment :: AwaitingInvoice { retryable_invoice_request: Some ( _) , .. } )
709
+ } ) ;
710
+
692
711
Self {
693
- pending_outbound_payments : Mutex :: new ( new_hash_map ( ) ) ,
712
+ pending_outbound_payments : Mutex :: new ( pending_outbound_payments) ,
713
+ awaiting_invoice : AtomicBool :: new ( has_invoice_requests) ,
694
714
retry_lock : Mutex :: new ( ( ) ) ,
695
715
}
696
716
}
@@ -1411,16 +1431,20 @@ impl OutboundPayments {
1411
1431
1412
1432
pub ( super ) fn add_new_awaiting_invoice (
1413
1433
& self , payment_id : PaymentId , expiration : StaleExpiration , retry_strategy : Retry ,
1414
- max_total_routing_fee_msat : Option < u64 >
1434
+ max_total_routing_fee_msat : Option < u64 > , retryable_invoice_request : Option < RetryableInvoiceRequest >
1415
1435
) -> Result < ( ) , ( ) > {
1416
1436
let mut pending_outbounds = self . pending_outbound_payments . lock ( ) . unwrap ( ) ;
1417
1437
match pending_outbounds. entry ( payment_id) {
1418
1438
hash_map:: Entry :: Occupied ( _) => Err ( ( ) ) ,
1419
1439
hash_map:: Entry :: Vacant ( entry) => {
1440
+ retryable_invoice_request. as_ref ( ) . map ( |_|
1441
+ self . awaiting_invoice . store ( true , Ordering :: Release )
1442
+ ) ;
1420
1443
entry. insert ( PendingOutboundPayment :: AwaitingInvoice {
1421
1444
expiration,
1422
1445
retry_strategy,
1423
1446
max_total_routing_fee_msat,
1447
+ retryable_invoice_request,
1424
1448
} ) ;
1425
1449
1426
1450
Ok ( ( ) )
@@ -1892,6 +1916,31 @@ impl OutboundPayments {
1892
1916
pub fn clear_pending_payments ( & self ) {
1893
1917
self . pending_outbound_payments . lock ( ) . unwrap ( ) . clear ( )
1894
1918
}
1919
+
1920
+ pub fn release_invoice_requests_awaiting_invoice ( & self ) -> Vec < ( PaymentId , RetryableInvoiceRequest ) > {
1921
+ if !self . awaiting_invoice . load ( Ordering :: Acquire ) {
1922
+ return vec ! [ ] ;
1923
+ }
1924
+
1925
+ let mut pending_outbound_payments = self . pending_outbound_payments . lock ( ) . unwrap ( ) ;
1926
+ let invoice_requests = pending_outbound_payments
1927
+ . iter_mut ( )
1928
+ . filter_map ( |( payment_id, payment) | {
1929
+ if let PendingOutboundPayment :: AwaitingInvoice {
1930
+ retryable_invoice_request, ..
1931
+ } = payment {
1932
+ retryable_invoice_request. take ( ) . map ( |retryable_invoice_request| {
1933
+ ( * payment_id, retryable_invoice_request)
1934
+ } )
1935
+ } else {
1936
+ None
1937
+ }
1938
+ } )
1939
+ . collect ( ) ;
1940
+
1941
+ self . awaiting_invoice . store ( false , Ordering :: Release ) ;
1942
+ invoice_requests
1943
+ }
1895
1944
}
1896
1945
1897
1946
/// Returns whether a payment with the given [`PaymentHash`] and [`PaymentId`] is, in fact, a
@@ -1947,6 +1996,7 @@ impl_writeable_tlv_based_enum_upgradable!(PendingOutboundPayment,
1947
1996
( 0 , expiration, required) ,
1948
1997
( 2 , retry_strategy, required) ,
1949
1998
( 4 , max_total_routing_fee_msat, option) ,
1999
+ ( 5 , retryable_invoice_request, option) ,
1950
2000
} ,
1951
2001
( 7 , InvoiceReceived ) => {
1952
2002
( 0 , payment_hash, required) ,
@@ -1977,6 +2027,7 @@ mod tests {
1977
2027
use crate :: routing:: router:: { InFlightHtlcs , Path , PaymentParameters , Route , RouteHop , RouteParameters } ;
1978
2028
use crate :: sync:: { Arc , Mutex , RwLock } ;
1979
2029
use crate :: util:: errors:: APIError ;
2030
+ use crate :: util:: hash_tables:: new_hash_map;
1980
2031
use crate :: util:: test_utils;
1981
2032
1982
2033
use alloc:: collections:: VecDeque ;
@@ -2011,7 +2062,7 @@ mod tests {
2011
2062
}
2012
2063
#[ cfg( feature = "std" ) ]
2013
2064
fn do_fails_paying_after_expiration ( on_retry : bool ) {
2014
- let outbound_payments = OutboundPayments :: new ( ) ;
2065
+ let outbound_payments = OutboundPayments :: new ( new_hash_map ( ) ) ;
2015
2066
let logger = test_utils:: TestLogger :: new ( ) ;
2016
2067
let network_graph = Arc :: new ( NetworkGraph :: new ( Network :: Testnet , & logger) ) ;
2017
2068
let scorer = RwLock :: new ( test_utils:: TestScorer :: new ( ) ) ;
@@ -2055,7 +2106,7 @@ mod tests {
2055
2106
do_find_route_error ( true ) ;
2056
2107
}
2057
2108
fn do_find_route_error ( on_retry : bool ) {
2058
- let outbound_payments = OutboundPayments :: new ( ) ;
2109
+ let outbound_payments = OutboundPayments :: new ( new_hash_map ( ) ) ;
2059
2110
let logger = test_utils:: TestLogger :: new ( ) ;
2060
2111
let network_graph = Arc :: new ( NetworkGraph :: new ( Network :: Testnet , & logger) ) ;
2061
2112
let scorer = RwLock :: new ( test_utils:: TestScorer :: new ( ) ) ;
@@ -2094,7 +2145,7 @@ mod tests {
2094
2145
2095
2146
#[ test]
2096
2147
fn initial_send_payment_path_failed_evs ( ) {
2097
- let outbound_payments = OutboundPayments :: new ( ) ;
2148
+ let outbound_payments = OutboundPayments :: new ( new_hash_map ( ) ) ;
2098
2149
let logger = test_utils:: TestLogger :: new ( ) ;
2099
2150
let network_graph = Arc :: new ( NetworkGraph :: new ( Network :: Testnet , & logger) ) ;
2100
2151
let scorer = RwLock :: new ( test_utils:: TestScorer :: new ( ) ) ;
@@ -2176,7 +2227,7 @@ mod tests {
2176
2227
#[ test]
2177
2228
fn removes_stale_awaiting_invoice_using_absolute_timeout ( ) {
2178
2229
let pending_events = Mutex :: new ( VecDeque :: new ( ) ) ;
2179
- let outbound_payments = OutboundPayments :: new ( ) ;
2230
+ let outbound_payments = OutboundPayments :: new ( new_hash_map ( ) ) ;
2180
2231
let payment_id = PaymentId ( [ 0 ; 32 ] ) ;
2181
2232
let absolute_expiry = 100 ;
2182
2233
let tick_interval = 10 ;
@@ -2185,7 +2236,7 @@ mod tests {
2185
2236
assert ! ( !outbound_payments. has_pending_payments( ) ) ;
2186
2237
assert ! (
2187
2238
outbound_payments. add_new_awaiting_invoice(
2188
- payment_id, expiration, Retry :: Attempts ( 0 ) , None
2239
+ payment_id, expiration, Retry :: Attempts ( 0 ) , None , None ,
2189
2240
) . is_ok( )
2190
2241
) ;
2191
2242
assert ! ( outbound_payments. has_pending_payments( ) ) ;
@@ -2215,30 +2266,30 @@ mod tests {
2215
2266
2216
2267
assert ! (
2217
2268
outbound_payments. add_new_awaiting_invoice(
2218
- payment_id, expiration, Retry :: Attempts ( 0 ) , None
2269
+ payment_id, expiration, Retry :: Attempts ( 0 ) , None , None ,
2219
2270
) . is_ok( )
2220
2271
) ;
2221
2272
assert ! ( outbound_payments. has_pending_payments( ) ) ;
2222
2273
2223
2274
assert ! (
2224
2275
outbound_payments. add_new_awaiting_invoice(
2225
- payment_id, expiration, Retry :: Attempts ( 0 ) , None
2276
+ payment_id, expiration, Retry :: Attempts ( 0 ) , None , None ,
2226
2277
) . is_err( )
2227
2278
) ;
2228
2279
}
2229
2280
2230
2281
#[ test]
2231
2282
fn removes_stale_awaiting_invoice_using_timer_ticks ( ) {
2232
2283
let pending_events = Mutex :: new ( VecDeque :: new ( ) ) ;
2233
- let outbound_payments = OutboundPayments :: new ( ) ;
2284
+ let outbound_payments = OutboundPayments :: new ( new_hash_map ( ) ) ;
2234
2285
let payment_id = PaymentId ( [ 0 ; 32 ] ) ;
2235
2286
let timer_ticks = 3 ;
2236
2287
let expiration = StaleExpiration :: TimerTicks ( timer_ticks) ;
2237
2288
2238
2289
assert ! ( !outbound_payments. has_pending_payments( ) ) ;
2239
2290
assert ! (
2240
2291
outbound_payments. add_new_awaiting_invoice(
2241
- payment_id, expiration, Retry :: Attempts ( 0 ) , None
2292
+ payment_id, expiration, Retry :: Attempts ( 0 ) , None , None ,
2242
2293
) . is_ok( )
2243
2294
) ;
2244
2295
assert ! ( outbound_payments. has_pending_payments( ) ) ;
@@ -2268,29 +2319,29 @@ mod tests {
2268
2319
2269
2320
assert ! (
2270
2321
outbound_payments. add_new_awaiting_invoice(
2271
- payment_id, expiration, Retry :: Attempts ( 0 ) , None
2322
+ payment_id, expiration, Retry :: Attempts ( 0 ) , None , None ,
2272
2323
) . is_ok( )
2273
2324
) ;
2274
2325
assert ! ( outbound_payments. has_pending_payments( ) ) ;
2275
2326
2276
2327
assert ! (
2277
2328
outbound_payments. add_new_awaiting_invoice(
2278
- payment_id, expiration, Retry :: Attempts ( 0 ) , None
2329
+ payment_id, expiration, Retry :: Attempts ( 0 ) , None , None ,
2279
2330
) . is_err( )
2280
2331
) ;
2281
2332
}
2282
2333
2283
2334
#[ test]
2284
2335
fn removes_abandoned_awaiting_invoice ( ) {
2285
2336
let pending_events = Mutex :: new ( VecDeque :: new ( ) ) ;
2286
- let outbound_payments = OutboundPayments :: new ( ) ;
2337
+ let outbound_payments = OutboundPayments :: new ( new_hash_map ( ) ) ;
2287
2338
let payment_id = PaymentId ( [ 0 ; 32 ] ) ;
2288
2339
let expiration = StaleExpiration :: AbsoluteTimeout ( Duration :: from_secs ( 100 ) ) ;
2289
2340
2290
2341
assert ! ( !outbound_payments. has_pending_payments( ) ) ;
2291
2342
assert ! (
2292
2343
outbound_payments. add_new_awaiting_invoice(
2293
- payment_id, expiration, Retry :: Attempts ( 0 ) , None
2344
+ payment_id, expiration, Retry :: Attempts ( 0 ) , None , None ,
2294
2345
) . is_ok( )
2295
2346
) ;
2296
2347
assert ! ( outbound_payments. has_pending_payments( ) ) ;
@@ -2320,13 +2371,13 @@ mod tests {
2320
2371
let keys_manager = test_utils:: TestKeysInterface :: new ( & [ 0 ; 32 ] , Network :: Testnet ) ;
2321
2372
2322
2373
let pending_events = Mutex :: new ( VecDeque :: new ( ) ) ;
2323
- let outbound_payments = OutboundPayments :: new ( ) ;
2374
+ let outbound_payments = OutboundPayments :: new ( new_hash_map ( ) ) ;
2324
2375
let payment_id = PaymentId ( [ 0 ; 32 ] ) ;
2325
2376
let expiration = StaleExpiration :: AbsoluteTimeout ( Duration :: from_secs ( 100 ) ) ;
2326
2377
2327
2378
assert ! (
2328
2379
outbound_payments. add_new_awaiting_invoice(
2329
- payment_id, expiration, Retry :: Attempts ( 0 ) , None
2380
+ payment_id, expiration, Retry :: Attempts ( 0 ) , None , None ,
2330
2381
) . is_ok( )
2331
2382
) ;
2332
2383
assert ! ( outbound_payments. has_pending_payments( ) ) ;
@@ -2373,7 +2424,7 @@ mod tests {
2373
2424
let keys_manager = test_utils:: TestKeysInterface :: new ( & [ 0 ; 32 ] , Network :: Testnet ) ;
2374
2425
2375
2426
let pending_events = Mutex :: new ( VecDeque :: new ( ) ) ;
2376
- let outbound_payments = OutboundPayments :: new ( ) ;
2427
+ let outbound_payments = OutboundPayments :: new ( new_hash_map ( ) ) ;
2377
2428
let payment_id = PaymentId ( [ 0 ; 32 ] ) ;
2378
2429
let expiration = StaleExpiration :: AbsoluteTimeout ( Duration :: from_secs ( 100 ) ) ;
2379
2430
@@ -2390,7 +2441,7 @@ mod tests {
2390
2441
assert ! (
2391
2442
outbound_payments. add_new_awaiting_invoice(
2392
2443
payment_id, expiration, Retry :: Attempts ( 0 ) ,
2393
- Some ( invoice. amount_msats( ) / 100 + 50_000 )
2444
+ Some ( invoice. amount_msats( ) / 100 + 50_000 ) , None ,
2394
2445
) . is_ok( )
2395
2446
) ;
2396
2447
assert ! ( outbound_payments. has_pending_payments( ) ) ;
@@ -2434,7 +2485,7 @@ mod tests {
2434
2485
let keys_manager = test_utils:: TestKeysInterface :: new ( & [ 0 ; 32 ] , Network :: Testnet ) ;
2435
2486
2436
2487
let pending_events = Mutex :: new ( VecDeque :: new ( ) ) ;
2437
- let outbound_payments = OutboundPayments :: new ( ) ;
2488
+ let outbound_payments = OutboundPayments :: new ( new_hash_map ( ) ) ;
2438
2489
let payment_id = PaymentId ( [ 0 ; 32 ] ) ;
2439
2490
let expiration = StaleExpiration :: AbsoluteTimeout ( Duration :: from_secs ( 100 ) ) ;
2440
2491
@@ -2490,7 +2541,7 @@ mod tests {
2490
2541
2491
2542
assert ! (
2492
2543
outbound_payments. add_new_awaiting_invoice(
2493
- payment_id, expiration, Retry :: Attempts ( 0 ) , Some ( 1234 )
2544
+ payment_id, expiration, Retry :: Attempts ( 0 ) , Some ( 1234 ) , None ,
2494
2545
) . is_ok( )
2495
2546
) ;
2496
2547
assert ! ( outbound_payments. has_pending_payments( ) ) ;
0 commit comments