@@ -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,7 +1431,7 @@ 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) {
@@ -1421,7 +1441,9 @@ impl OutboundPayments {
1421
1441
expiration,
1422
1442
retry_strategy,
1423
1443
max_total_routing_fee_msat,
1444
+ retryable_invoice_request,
1424
1445
} ) ;
1446
+ self . awaiting_invoice . store ( true , Ordering :: Release ) ;
1425
1447
1426
1448
Ok ( ( ) )
1427
1449
} ,
@@ -1892,6 +1914,31 @@ impl OutboundPayments {
1892
1914
pub fn clear_pending_payments ( & self ) {
1893
1915
self . pending_outbound_payments . lock ( ) . unwrap ( ) . clear ( )
1894
1916
}
1917
+
1918
+ pub fn release_invoice_requests_awaiting_invoice ( & self ) -> Vec < ( PaymentId , RetryableInvoiceRequest ) > {
1919
+ if !self . awaiting_invoice . load ( Ordering :: Acquire ) {
1920
+ return vec ! [ ] ;
1921
+ }
1922
+
1923
+ let mut pending_outbound_payments = self . pending_outbound_payments . lock ( ) . unwrap ( ) ;
1924
+ let invoice_requests = pending_outbound_payments
1925
+ . iter_mut ( )
1926
+ . filter_map ( |( payment_id, payment) | {
1927
+ if let PendingOutboundPayment :: AwaitingInvoice {
1928
+ retryable_invoice_request, ..
1929
+ } = payment {
1930
+ retryable_invoice_request. take ( ) . map ( |retryable_invoice_request| {
1931
+ ( * payment_id, retryable_invoice_request)
1932
+ } )
1933
+ } else {
1934
+ None
1935
+ }
1936
+ } )
1937
+ . collect ( ) ;
1938
+
1939
+ self . awaiting_invoice . store ( false , Ordering :: Release ) ;
1940
+ invoice_requests
1941
+ }
1895
1942
}
1896
1943
1897
1944
/// Returns whether a payment with the given [`PaymentHash`] and [`PaymentId`] is, in fact, a
@@ -1947,6 +1994,7 @@ impl_writeable_tlv_based_enum_upgradable!(PendingOutboundPayment,
1947
1994
( 0 , expiration, required) ,
1948
1995
( 2 , retry_strategy, required) ,
1949
1996
( 4 , max_total_routing_fee_msat, option) ,
1997
+ ( 5 , retryable_invoice_request, option) ,
1950
1998
} ,
1951
1999
( 7 , InvoiceReceived ) => {
1952
2000
( 0 , payment_hash, required) ,
@@ -1977,6 +2025,7 @@ mod tests {
1977
2025
use crate :: routing:: router:: { InFlightHtlcs , Path , PaymentParameters , Route , RouteHop , RouteParameters } ;
1978
2026
use crate :: sync:: { Arc , Mutex , RwLock } ;
1979
2027
use crate :: util:: errors:: APIError ;
2028
+ use crate :: util:: hash_tables:: new_hash_map;
1980
2029
use crate :: util:: test_utils;
1981
2030
1982
2031
use alloc:: collections:: VecDeque ;
@@ -2011,7 +2060,7 @@ mod tests {
2011
2060
}
2012
2061
#[ cfg( feature = "std" ) ]
2013
2062
fn do_fails_paying_after_expiration ( on_retry : bool ) {
2014
- let outbound_payments = OutboundPayments :: new ( ) ;
2063
+ let outbound_payments = OutboundPayments :: new ( new_hash_map ( ) ) ;
2015
2064
let logger = test_utils:: TestLogger :: new ( ) ;
2016
2065
let network_graph = Arc :: new ( NetworkGraph :: new ( Network :: Testnet , & logger) ) ;
2017
2066
let scorer = RwLock :: new ( test_utils:: TestScorer :: new ( ) ) ;
@@ -2055,7 +2104,7 @@ mod tests {
2055
2104
do_find_route_error ( true ) ;
2056
2105
}
2057
2106
fn do_find_route_error ( on_retry : bool ) {
2058
- let outbound_payments = OutboundPayments :: new ( ) ;
2107
+ let outbound_payments = OutboundPayments :: new ( new_hash_map ( ) ) ;
2059
2108
let logger = test_utils:: TestLogger :: new ( ) ;
2060
2109
let network_graph = Arc :: new ( NetworkGraph :: new ( Network :: Testnet , & logger) ) ;
2061
2110
let scorer = RwLock :: new ( test_utils:: TestScorer :: new ( ) ) ;
@@ -2094,7 +2143,7 @@ mod tests {
2094
2143
2095
2144
#[ test]
2096
2145
fn initial_send_payment_path_failed_evs ( ) {
2097
- let outbound_payments = OutboundPayments :: new ( ) ;
2146
+ let outbound_payments = OutboundPayments :: new ( new_hash_map ( ) ) ;
2098
2147
let logger = test_utils:: TestLogger :: new ( ) ;
2099
2148
let network_graph = Arc :: new ( NetworkGraph :: new ( Network :: Testnet , & logger) ) ;
2100
2149
let scorer = RwLock :: new ( test_utils:: TestScorer :: new ( ) ) ;
@@ -2176,7 +2225,7 @@ mod tests {
2176
2225
#[ test]
2177
2226
fn removes_stale_awaiting_invoice_using_absolute_timeout ( ) {
2178
2227
let pending_events = Mutex :: new ( VecDeque :: new ( ) ) ;
2179
- let outbound_payments = OutboundPayments :: new ( ) ;
2228
+ let outbound_payments = OutboundPayments :: new ( new_hash_map ( ) ) ;
2180
2229
let payment_id = PaymentId ( [ 0 ; 32 ] ) ;
2181
2230
let absolute_expiry = 100 ;
2182
2231
let tick_interval = 10 ;
@@ -2185,7 +2234,7 @@ mod tests {
2185
2234
assert ! ( !outbound_payments. has_pending_payments( ) ) ;
2186
2235
assert ! (
2187
2236
outbound_payments. add_new_awaiting_invoice(
2188
- payment_id, expiration, Retry :: Attempts ( 0 ) , None
2237
+ payment_id, expiration, Retry :: Attempts ( 0 ) , None , None ,
2189
2238
) . is_ok( )
2190
2239
) ;
2191
2240
assert ! ( outbound_payments. has_pending_payments( ) ) ;
@@ -2215,30 +2264,30 @@ mod tests {
2215
2264
2216
2265
assert ! (
2217
2266
outbound_payments. add_new_awaiting_invoice(
2218
- payment_id, expiration, Retry :: Attempts ( 0 ) , None
2267
+ payment_id, expiration, Retry :: Attempts ( 0 ) , None , None ,
2219
2268
) . is_ok( )
2220
2269
) ;
2221
2270
assert ! ( outbound_payments. has_pending_payments( ) ) ;
2222
2271
2223
2272
assert ! (
2224
2273
outbound_payments. add_new_awaiting_invoice(
2225
- payment_id, expiration, Retry :: Attempts ( 0 ) , None
2274
+ payment_id, expiration, Retry :: Attempts ( 0 ) , None , None ,
2226
2275
) . is_err( )
2227
2276
) ;
2228
2277
}
2229
2278
2230
2279
#[ test]
2231
2280
fn removes_stale_awaiting_invoice_using_timer_ticks ( ) {
2232
2281
let pending_events = Mutex :: new ( VecDeque :: new ( ) ) ;
2233
- let outbound_payments = OutboundPayments :: new ( ) ;
2282
+ let outbound_payments = OutboundPayments :: new ( new_hash_map ( ) ) ;
2234
2283
let payment_id = PaymentId ( [ 0 ; 32 ] ) ;
2235
2284
let timer_ticks = 3 ;
2236
2285
let expiration = StaleExpiration :: TimerTicks ( timer_ticks) ;
2237
2286
2238
2287
assert ! ( !outbound_payments. has_pending_payments( ) ) ;
2239
2288
assert ! (
2240
2289
outbound_payments. add_new_awaiting_invoice(
2241
- payment_id, expiration, Retry :: Attempts ( 0 ) , None
2290
+ payment_id, expiration, Retry :: Attempts ( 0 ) , None , None ,
2242
2291
) . is_ok( )
2243
2292
) ;
2244
2293
assert ! ( outbound_payments. has_pending_payments( ) ) ;
@@ -2268,29 +2317,29 @@ mod tests {
2268
2317
2269
2318
assert ! (
2270
2319
outbound_payments. add_new_awaiting_invoice(
2271
- payment_id, expiration, Retry :: Attempts ( 0 ) , None
2320
+ payment_id, expiration, Retry :: Attempts ( 0 ) , None , None ,
2272
2321
) . is_ok( )
2273
2322
) ;
2274
2323
assert ! ( outbound_payments. has_pending_payments( ) ) ;
2275
2324
2276
2325
assert ! (
2277
2326
outbound_payments. add_new_awaiting_invoice(
2278
- payment_id, expiration, Retry :: Attempts ( 0 ) , None
2327
+ payment_id, expiration, Retry :: Attempts ( 0 ) , None , None ,
2279
2328
) . is_err( )
2280
2329
) ;
2281
2330
}
2282
2331
2283
2332
#[ test]
2284
2333
fn removes_abandoned_awaiting_invoice ( ) {
2285
2334
let pending_events = Mutex :: new ( VecDeque :: new ( ) ) ;
2286
- let outbound_payments = OutboundPayments :: new ( ) ;
2335
+ let outbound_payments = OutboundPayments :: new ( new_hash_map ( ) ) ;
2287
2336
let payment_id = PaymentId ( [ 0 ; 32 ] ) ;
2288
2337
let expiration = StaleExpiration :: AbsoluteTimeout ( Duration :: from_secs ( 100 ) ) ;
2289
2338
2290
2339
assert ! ( !outbound_payments. has_pending_payments( ) ) ;
2291
2340
assert ! (
2292
2341
outbound_payments. add_new_awaiting_invoice(
2293
- payment_id, expiration, Retry :: Attempts ( 0 ) , None
2342
+ payment_id, expiration, Retry :: Attempts ( 0 ) , None , None ,
2294
2343
) . is_ok( )
2295
2344
) ;
2296
2345
assert ! ( outbound_payments. has_pending_payments( ) ) ;
@@ -2320,13 +2369,13 @@ mod tests {
2320
2369
let keys_manager = test_utils:: TestKeysInterface :: new ( & [ 0 ; 32 ] , Network :: Testnet ) ;
2321
2370
2322
2371
let pending_events = Mutex :: new ( VecDeque :: new ( ) ) ;
2323
- let outbound_payments = OutboundPayments :: new ( ) ;
2372
+ let outbound_payments = OutboundPayments :: new ( new_hash_map ( ) ) ;
2324
2373
let payment_id = PaymentId ( [ 0 ; 32 ] ) ;
2325
2374
let expiration = StaleExpiration :: AbsoluteTimeout ( Duration :: from_secs ( 100 ) ) ;
2326
2375
2327
2376
assert ! (
2328
2377
outbound_payments. add_new_awaiting_invoice(
2329
- payment_id, expiration, Retry :: Attempts ( 0 ) , None
2378
+ payment_id, expiration, Retry :: Attempts ( 0 ) , None , None ,
2330
2379
) . is_ok( )
2331
2380
) ;
2332
2381
assert ! ( outbound_payments. has_pending_payments( ) ) ;
@@ -2373,7 +2422,7 @@ mod tests {
2373
2422
let keys_manager = test_utils:: TestKeysInterface :: new ( & [ 0 ; 32 ] , Network :: Testnet ) ;
2374
2423
2375
2424
let pending_events = Mutex :: new ( VecDeque :: new ( ) ) ;
2376
- let outbound_payments = OutboundPayments :: new ( ) ;
2425
+ let outbound_payments = OutboundPayments :: new ( new_hash_map ( ) ) ;
2377
2426
let payment_id = PaymentId ( [ 0 ; 32 ] ) ;
2378
2427
let expiration = StaleExpiration :: AbsoluteTimeout ( Duration :: from_secs ( 100 ) ) ;
2379
2428
@@ -2390,7 +2439,7 @@ mod tests {
2390
2439
assert ! (
2391
2440
outbound_payments. add_new_awaiting_invoice(
2392
2441
payment_id, expiration, Retry :: Attempts ( 0 ) ,
2393
- Some ( invoice. amount_msats( ) / 100 + 50_000 )
2442
+ Some ( invoice. amount_msats( ) / 100 + 50_000 ) , None ,
2394
2443
) . is_ok( )
2395
2444
) ;
2396
2445
assert ! ( outbound_payments. has_pending_payments( ) ) ;
@@ -2434,7 +2483,7 @@ mod tests {
2434
2483
let keys_manager = test_utils:: TestKeysInterface :: new ( & [ 0 ; 32 ] , Network :: Testnet ) ;
2435
2484
2436
2485
let pending_events = Mutex :: new ( VecDeque :: new ( ) ) ;
2437
- let outbound_payments = OutboundPayments :: new ( ) ;
2486
+ let outbound_payments = OutboundPayments :: new ( new_hash_map ( ) ) ;
2438
2487
let payment_id = PaymentId ( [ 0 ; 32 ] ) ;
2439
2488
let expiration = StaleExpiration :: AbsoluteTimeout ( Duration :: from_secs ( 100 ) ) ;
2440
2489
@@ -2490,7 +2539,7 @@ mod tests {
2490
2539
2491
2540
assert ! (
2492
2541
outbound_payments. add_new_awaiting_invoice(
2493
- payment_id, expiration, Retry :: Attempts ( 0 ) , Some ( 1234 )
2542
+ payment_id, expiration, Retry :: Attempts ( 0 ) , Some ( 1234 ) , None ,
2494
2543
) . is_ok( )
2495
2544
) ;
2496
2545
assert ! ( outbound_payments. has_pending_payments( ) ) ;
0 commit comments