@@ -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 ;
@@ -32,6 +34,7 @@ use crate::util::ser::ReadableArgs;
32
34
33
35
use core:: fmt:: { self , Display , Formatter } ;
34
36
use core:: ops:: Deref ;
37
+ use core:: sync:: atomic:: { AtomicBool , Ordering } ;
35
38
use core:: time:: Duration ;
36
39
37
40
use crate :: prelude:: * ;
@@ -53,6 +56,7 @@ pub(crate) enum PendingOutboundPayment {
53
56
expiration : StaleExpiration ,
54
57
retry_strategy : Retry ,
55
58
max_total_routing_fee_msat : Option < u64 > ,
59
+ retryable_invoice_request : Option < RetryableInvoiceRequest >
56
60
} ,
57
61
InvoiceReceived {
58
62
payment_hash : PaymentHash ,
@@ -100,6 +104,16 @@ pub(crate) enum PendingOutboundPayment {
100
104
} ,
101
105
}
102
106
107
+ pub ( crate ) struct RetryableInvoiceRequest {
108
+ pub ( crate ) invoice_request : InvoiceRequest ,
109
+ pub ( crate ) nonce : Nonce ,
110
+ }
111
+
112
+ impl_writeable_tlv_based ! ( RetryableInvoiceRequest , {
113
+ ( 0 , invoice_request, required) ,
114
+ ( 2 , nonce, required) ,
115
+ } ) ;
116
+
103
117
impl PendingOutboundPayment {
104
118
fn increment_attempts ( & mut self ) {
105
119
if let PendingOutboundPayment :: Retryable { attempts, .. } = self {
@@ -666,13 +680,19 @@ pub(super) struct SendAlongPathArgs<'a> {
666
680
667
681
pub ( super ) struct OutboundPayments {
668
682
pub ( super ) pending_outbound_payments : Mutex < HashMap < PaymentId , PendingOutboundPayment > > ,
669
- pub ( super ) retry_lock : Mutex < ( ) > ,
683
+ awaiting_invoice : AtomicBool ,
684
+ retry_lock : Mutex < ( ) > ,
670
685
}
671
686
672
687
impl OutboundPayments {
673
- pub ( super ) fn new ( ) -> Self {
688
+ pub ( super ) fn new ( pending_outbound_payments : HashMap < PaymentId , PendingOutboundPayment > ) -> Self {
689
+ let has_invoice_requests = pending_outbound_payments. values ( ) . any ( |payment| {
690
+ matches ! ( payment, PendingOutboundPayment :: AwaitingInvoice { retryable_invoice_request: Some ( _) , .. } )
691
+ } ) ;
692
+
674
693
Self {
675
- pending_outbound_payments : Mutex :: new ( new_hash_map ( ) ) ,
694
+ pending_outbound_payments : Mutex :: new ( pending_outbound_payments) ,
695
+ awaiting_invoice : AtomicBool :: new ( has_invoice_requests) ,
676
696
retry_lock : Mutex :: new ( ( ) ) ,
677
697
}
678
698
}
@@ -1393,16 +1413,20 @@ impl OutboundPayments {
1393
1413
1394
1414
pub ( super ) fn add_new_awaiting_invoice (
1395
1415
& self , payment_id : PaymentId , expiration : StaleExpiration , retry_strategy : Retry ,
1396
- max_total_routing_fee_msat : Option < u64 >
1416
+ max_total_routing_fee_msat : Option < u64 > , retryable_invoice_request : Option < RetryableInvoiceRequest >
1397
1417
) -> Result < ( ) , ( ) > {
1398
1418
let mut pending_outbounds = self . pending_outbound_payments . lock ( ) . unwrap ( ) ;
1399
1419
match pending_outbounds. entry ( payment_id) {
1400
1420
hash_map:: Entry :: Occupied ( _) => Err ( ( ) ) ,
1401
1421
hash_map:: Entry :: Vacant ( entry) => {
1422
+ if retryable_invoice_request. is_some ( ) {
1423
+ self . awaiting_invoice . store ( true , Ordering :: Release ) ;
1424
+ }
1402
1425
entry. insert ( PendingOutboundPayment :: AwaitingInvoice {
1403
1426
expiration,
1404
1427
retry_strategy,
1405
1428
max_total_routing_fee_msat,
1429
+ retryable_invoice_request,
1406
1430
} ) ;
1407
1431
1408
1432
Ok ( ( ) )
@@ -1874,6 +1898,31 @@ impl OutboundPayments {
1874
1898
pub fn clear_pending_payments ( & self ) {
1875
1899
self . pending_outbound_payments . lock ( ) . unwrap ( ) . clear ( )
1876
1900
}
1901
+
1902
+ pub fn release_invoice_requests_awaiting_invoice ( & self ) -> Vec < ( PaymentId , RetryableInvoiceRequest ) > {
1903
+ if !self . awaiting_invoice . load ( Ordering :: Acquire ) {
1904
+ return vec ! [ ] ;
1905
+ }
1906
+
1907
+ let mut pending_outbound_payments = self . pending_outbound_payments . lock ( ) . unwrap ( ) ;
1908
+ let invoice_requests = pending_outbound_payments
1909
+ . iter_mut ( )
1910
+ . filter_map ( |( payment_id, payment) | {
1911
+ if let PendingOutboundPayment :: AwaitingInvoice {
1912
+ retryable_invoice_request, ..
1913
+ } = payment {
1914
+ retryable_invoice_request. take ( ) . map ( |retryable_invoice_request| {
1915
+ ( * payment_id, retryable_invoice_request)
1916
+ } )
1917
+ } else {
1918
+ None
1919
+ }
1920
+ } )
1921
+ . collect ( ) ;
1922
+
1923
+ self . awaiting_invoice . store ( false , Ordering :: Release ) ;
1924
+ invoice_requests
1925
+ }
1877
1926
}
1878
1927
1879
1928
/// Returns whether a payment with the given [`PaymentHash`] and [`PaymentId`] is, in fact, a
@@ -1929,6 +1978,7 @@ impl_writeable_tlv_based_enum_upgradable!(PendingOutboundPayment,
1929
1978
( 0 , expiration, required) ,
1930
1979
( 2 , retry_strategy, required) ,
1931
1980
( 4 , max_total_routing_fee_msat, option) ,
1981
+ ( 5 , retryable_invoice_request, option) ,
1932
1982
} ,
1933
1983
( 7 , InvoiceReceived ) => {
1934
1984
( 0 , payment_hash, required) ,
@@ -1959,6 +2009,7 @@ mod tests {
1959
2009
use crate :: routing:: router:: { InFlightHtlcs , Path , PaymentParameters , Route , RouteHop , RouteParameters } ;
1960
2010
use crate :: sync:: { Arc , Mutex , RwLock } ;
1961
2011
use crate :: util:: errors:: APIError ;
2012
+ use crate :: util:: hash_tables:: new_hash_map;
1962
2013
use crate :: util:: test_utils;
1963
2014
1964
2015
use alloc:: collections:: VecDeque ;
@@ -1993,7 +2044,7 @@ mod tests {
1993
2044
}
1994
2045
#[ cfg( feature = "std" ) ]
1995
2046
fn do_fails_paying_after_expiration ( on_retry : bool ) {
1996
- let outbound_payments = OutboundPayments :: new ( ) ;
2047
+ let outbound_payments = OutboundPayments :: new ( new_hash_map ( ) ) ;
1997
2048
let logger = test_utils:: TestLogger :: new ( ) ;
1998
2049
let network_graph = Arc :: new ( NetworkGraph :: new ( Network :: Testnet , & logger) ) ;
1999
2050
let scorer = RwLock :: new ( test_utils:: TestScorer :: new ( ) ) ;
@@ -2037,7 +2088,7 @@ mod tests {
2037
2088
do_find_route_error ( true ) ;
2038
2089
}
2039
2090
fn do_find_route_error ( on_retry : bool ) {
2040
- let outbound_payments = OutboundPayments :: new ( ) ;
2091
+ let outbound_payments = OutboundPayments :: new ( new_hash_map ( ) ) ;
2041
2092
let logger = test_utils:: TestLogger :: new ( ) ;
2042
2093
let network_graph = Arc :: new ( NetworkGraph :: new ( Network :: Testnet , & logger) ) ;
2043
2094
let scorer = RwLock :: new ( test_utils:: TestScorer :: new ( ) ) ;
@@ -2076,7 +2127,7 @@ mod tests {
2076
2127
2077
2128
#[ test]
2078
2129
fn initial_send_payment_path_failed_evs ( ) {
2079
- let outbound_payments = OutboundPayments :: new ( ) ;
2130
+ let outbound_payments = OutboundPayments :: new ( new_hash_map ( ) ) ;
2080
2131
let logger = test_utils:: TestLogger :: new ( ) ;
2081
2132
let network_graph = Arc :: new ( NetworkGraph :: new ( Network :: Testnet , & logger) ) ;
2082
2133
let scorer = RwLock :: new ( test_utils:: TestScorer :: new ( ) ) ;
@@ -2158,7 +2209,7 @@ mod tests {
2158
2209
#[ test]
2159
2210
fn removes_stale_awaiting_invoice_using_absolute_timeout ( ) {
2160
2211
let pending_events = Mutex :: new ( VecDeque :: new ( ) ) ;
2161
- let outbound_payments = OutboundPayments :: new ( ) ;
2212
+ let outbound_payments = OutboundPayments :: new ( new_hash_map ( ) ) ;
2162
2213
let payment_id = PaymentId ( [ 0 ; 32 ] ) ;
2163
2214
let absolute_expiry = 100 ;
2164
2215
let tick_interval = 10 ;
@@ -2167,7 +2218,7 @@ mod tests {
2167
2218
assert ! ( !outbound_payments. has_pending_payments( ) ) ;
2168
2219
assert ! (
2169
2220
outbound_payments. add_new_awaiting_invoice(
2170
- payment_id, expiration, Retry :: Attempts ( 0 ) , None
2221
+ payment_id, expiration, Retry :: Attempts ( 0 ) , None , None ,
2171
2222
) . is_ok( )
2172
2223
) ;
2173
2224
assert ! ( outbound_payments. has_pending_payments( ) ) ;
@@ -2197,30 +2248,30 @@ mod tests {
2197
2248
2198
2249
assert ! (
2199
2250
outbound_payments. add_new_awaiting_invoice(
2200
- payment_id, expiration, Retry :: Attempts ( 0 ) , None
2251
+ payment_id, expiration, Retry :: Attempts ( 0 ) , None , None ,
2201
2252
) . is_ok( )
2202
2253
) ;
2203
2254
assert ! ( outbound_payments. has_pending_payments( ) ) ;
2204
2255
2205
2256
assert ! (
2206
2257
outbound_payments. add_new_awaiting_invoice(
2207
- payment_id, expiration, Retry :: Attempts ( 0 ) , None
2258
+ payment_id, expiration, Retry :: Attempts ( 0 ) , None , None ,
2208
2259
) . is_err( )
2209
2260
) ;
2210
2261
}
2211
2262
2212
2263
#[ test]
2213
2264
fn removes_stale_awaiting_invoice_using_timer_ticks ( ) {
2214
2265
let pending_events = Mutex :: new ( VecDeque :: new ( ) ) ;
2215
- let outbound_payments = OutboundPayments :: new ( ) ;
2266
+ let outbound_payments = OutboundPayments :: new ( new_hash_map ( ) ) ;
2216
2267
let payment_id = PaymentId ( [ 0 ; 32 ] ) ;
2217
2268
let timer_ticks = 3 ;
2218
2269
let expiration = StaleExpiration :: TimerTicks ( timer_ticks) ;
2219
2270
2220
2271
assert ! ( !outbound_payments. has_pending_payments( ) ) ;
2221
2272
assert ! (
2222
2273
outbound_payments. add_new_awaiting_invoice(
2223
- payment_id, expiration, Retry :: Attempts ( 0 ) , None
2274
+ payment_id, expiration, Retry :: Attempts ( 0 ) , None , None ,
2224
2275
) . is_ok( )
2225
2276
) ;
2226
2277
assert ! ( outbound_payments. has_pending_payments( ) ) ;
@@ -2250,29 +2301,29 @@ mod tests {
2250
2301
2251
2302
assert ! (
2252
2303
outbound_payments. add_new_awaiting_invoice(
2253
- payment_id, expiration, Retry :: Attempts ( 0 ) , None
2304
+ payment_id, expiration, Retry :: Attempts ( 0 ) , None , None ,
2254
2305
) . is_ok( )
2255
2306
) ;
2256
2307
assert ! ( outbound_payments. has_pending_payments( ) ) ;
2257
2308
2258
2309
assert ! (
2259
2310
outbound_payments. add_new_awaiting_invoice(
2260
- payment_id, expiration, Retry :: Attempts ( 0 ) , None
2311
+ payment_id, expiration, Retry :: Attempts ( 0 ) , None , None ,
2261
2312
) . is_err( )
2262
2313
) ;
2263
2314
}
2264
2315
2265
2316
#[ test]
2266
2317
fn removes_abandoned_awaiting_invoice ( ) {
2267
2318
let pending_events = Mutex :: new ( VecDeque :: new ( ) ) ;
2268
- let outbound_payments = OutboundPayments :: new ( ) ;
2319
+ let outbound_payments = OutboundPayments :: new ( new_hash_map ( ) ) ;
2269
2320
let payment_id = PaymentId ( [ 0 ; 32 ] ) ;
2270
2321
let expiration = StaleExpiration :: AbsoluteTimeout ( Duration :: from_secs ( 100 ) ) ;
2271
2322
2272
2323
assert ! ( !outbound_payments. has_pending_payments( ) ) ;
2273
2324
assert ! (
2274
2325
outbound_payments. add_new_awaiting_invoice(
2275
- payment_id, expiration, Retry :: Attempts ( 0 ) , None
2326
+ payment_id, expiration, Retry :: Attempts ( 0 ) , None , None ,
2276
2327
) . is_ok( )
2277
2328
) ;
2278
2329
assert ! ( outbound_payments. has_pending_payments( ) ) ;
@@ -2302,13 +2353,13 @@ mod tests {
2302
2353
let keys_manager = test_utils:: TestKeysInterface :: new ( & [ 0 ; 32 ] , Network :: Testnet ) ;
2303
2354
2304
2355
let pending_events = Mutex :: new ( VecDeque :: new ( ) ) ;
2305
- let outbound_payments = OutboundPayments :: new ( ) ;
2356
+ let outbound_payments = OutboundPayments :: new ( new_hash_map ( ) ) ;
2306
2357
let payment_id = PaymentId ( [ 0 ; 32 ] ) ;
2307
2358
let expiration = StaleExpiration :: AbsoluteTimeout ( Duration :: from_secs ( 100 ) ) ;
2308
2359
2309
2360
assert ! (
2310
2361
outbound_payments. add_new_awaiting_invoice(
2311
- payment_id, expiration, Retry :: Attempts ( 0 ) , None
2362
+ payment_id, expiration, Retry :: Attempts ( 0 ) , None , None ,
2312
2363
) . is_ok( )
2313
2364
) ;
2314
2365
assert ! ( outbound_payments. has_pending_payments( ) ) ;
@@ -2355,7 +2406,7 @@ mod tests {
2355
2406
let keys_manager = test_utils:: TestKeysInterface :: new ( & [ 0 ; 32 ] , Network :: Testnet ) ;
2356
2407
2357
2408
let pending_events = Mutex :: new ( VecDeque :: new ( ) ) ;
2358
- let outbound_payments = OutboundPayments :: new ( ) ;
2409
+ let outbound_payments = OutboundPayments :: new ( new_hash_map ( ) ) ;
2359
2410
let payment_id = PaymentId ( [ 0 ; 32 ] ) ;
2360
2411
let expiration = StaleExpiration :: AbsoluteTimeout ( Duration :: from_secs ( 100 ) ) ;
2361
2412
@@ -2372,7 +2423,7 @@ mod tests {
2372
2423
assert ! (
2373
2424
outbound_payments. add_new_awaiting_invoice(
2374
2425
payment_id, expiration, Retry :: Attempts ( 0 ) ,
2375
- Some ( invoice. amount_msats( ) / 100 + 50_000 )
2426
+ Some ( invoice. amount_msats( ) / 100 + 50_000 ) , None ,
2376
2427
) . is_ok( )
2377
2428
) ;
2378
2429
assert ! ( outbound_payments. has_pending_payments( ) ) ;
@@ -2416,7 +2467,7 @@ mod tests {
2416
2467
let keys_manager = test_utils:: TestKeysInterface :: new ( & [ 0 ; 32 ] , Network :: Testnet ) ;
2417
2468
2418
2469
let pending_events = Mutex :: new ( VecDeque :: new ( ) ) ;
2419
- let outbound_payments = OutboundPayments :: new ( ) ;
2470
+ let outbound_payments = OutboundPayments :: new ( new_hash_map ( ) ) ;
2420
2471
let payment_id = PaymentId ( [ 0 ; 32 ] ) ;
2421
2472
let expiration = StaleExpiration :: AbsoluteTimeout ( Duration :: from_secs ( 100 ) ) ;
2422
2473
@@ -2472,7 +2523,7 @@ mod tests {
2472
2523
2473
2524
assert ! (
2474
2525
outbound_payments. add_new_awaiting_invoice(
2475
- payment_id, expiration, Retry :: Attempts ( 0 ) , Some ( 1234 )
2526
+ payment_id, expiration, Retry :: Attempts ( 0 ) , Some ( 1234 ) , None ,
2476
2527
) . is_ok( )
2477
2528
) ;
2478
2529
assert ! ( outbound_payments. has_pending_payments( ) ) ;
0 commit comments