@@ -22,6 +22,8 @@ use crate::ln::features::Bolt12InvoiceFeatures;
2222use crate :: ln:: onion_utils;
2323use crate :: ln:: onion_utils:: { DecodedOnionFailure , HTLCFailReason } ;
2424use crate :: offers:: invoice:: Bolt12Invoice ;
25+ use crate :: offers:: invoice_request:: InvoiceRequest ;
26+ use crate :: offers:: nonce:: Nonce ;
2527use crate :: routing:: router:: { BlindedTail , InFlightHtlcs , Path , PaymentParameters , Route , RouteParameters , Router } ;
2628use crate :: sign:: { EntropySource , NodeSigner , Recipient } ;
2729use crate :: util:: errors:: APIError ;
@@ -32,6 +34,7 @@ use crate::util::ser::ReadableArgs;
3234
3335use core:: fmt:: { self , Display , Formatter } ;
3436use core:: ops:: Deref ;
37+ use core:: sync:: atomic:: { AtomicBool , Ordering } ;
3538use core:: time:: Duration ;
3639
3740use crate :: prelude:: * ;
@@ -53,6 +56,7 @@ pub(crate) enum PendingOutboundPayment {
5356 expiration : StaleExpiration ,
5457 retry_strategy : Retry ,
5558 max_total_routing_fee_msat : Option < u64 > ,
59+ retryable_invoice_request : Option < RetryableInvoiceRequest >
5660 } ,
5761 InvoiceReceived {
5862 payment_hash : PaymentHash ,
@@ -100,6 +104,16 @@ pub(crate) enum PendingOutboundPayment {
100104 } ,
101105}
102106
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+
103117impl PendingOutboundPayment {
104118 fn increment_attempts ( & mut self ) {
105119 if let PendingOutboundPayment :: Retryable { attempts, .. } = self {
@@ -666,13 +680,19 @@ pub(super) struct SendAlongPathArgs<'a> {
666680
667681pub ( super ) struct OutboundPayments {
668682 pub ( super ) pending_outbound_payments : Mutex < HashMap < PaymentId , PendingOutboundPayment > > ,
669- pub ( super ) retry_lock : Mutex < ( ) > ,
683+ awaiting_invoice : AtomicBool ,
684+ retry_lock : Mutex < ( ) > ,
670685}
671686
672687impl 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+
674693 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) ,
676696 retry_lock : Mutex :: new ( ( ) ) ,
677697 }
678698 }
@@ -1393,16 +1413,20 @@ impl OutboundPayments {
13931413
13941414 pub ( super ) fn add_new_awaiting_invoice (
13951415 & 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 >
13971417 ) -> Result < ( ) , ( ) > {
13981418 let mut pending_outbounds = self . pending_outbound_payments . lock ( ) . unwrap ( ) ;
13991419 match pending_outbounds. entry ( payment_id) {
14001420 hash_map:: Entry :: Occupied ( _) => Err ( ( ) ) ,
14011421 hash_map:: Entry :: Vacant ( entry) => {
1422+ if retryable_invoice_request. is_some ( ) {
1423+ self . awaiting_invoice . store ( true , Ordering :: Release ) ;
1424+ }
14021425 entry. insert ( PendingOutboundPayment :: AwaitingInvoice {
14031426 expiration,
14041427 retry_strategy,
14051428 max_total_routing_fee_msat,
1429+ retryable_invoice_request,
14061430 } ) ;
14071431
14081432 Ok ( ( ) )
@@ -1874,6 +1898,31 @@ impl OutboundPayments {
18741898 pub fn clear_pending_payments ( & self ) {
18751899 self . pending_outbound_payments . lock ( ) . unwrap ( ) . clear ( )
18761900 }
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+ }
18771926}
18781927
18791928/// 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,
19291978 ( 0 , expiration, required) ,
19301979 ( 2 , retry_strategy, required) ,
19311980 ( 4 , max_total_routing_fee_msat, option) ,
1981+ ( 5 , retryable_invoice_request, option) ,
19321982 } ,
19331983 ( 7 , InvoiceReceived ) => {
19341984 ( 0 , payment_hash, required) ,
@@ -1959,6 +2009,7 @@ mod tests {
19592009 use crate :: routing:: router:: { InFlightHtlcs , Path , PaymentParameters , Route , RouteHop , RouteParameters } ;
19602010 use crate :: sync:: { Arc , Mutex , RwLock } ;
19612011 use crate :: util:: errors:: APIError ;
2012+ use crate :: util:: hash_tables:: new_hash_map;
19622013 use crate :: util:: test_utils;
19632014
19642015 use alloc:: collections:: VecDeque ;
@@ -1993,7 +2044,7 @@ mod tests {
19932044 }
19942045 #[ cfg( feature = "std" ) ]
19952046 fn do_fails_paying_after_expiration ( on_retry : bool ) {
1996- let outbound_payments = OutboundPayments :: new ( ) ;
2047+ let outbound_payments = OutboundPayments :: new ( new_hash_map ( ) ) ;
19972048 let logger = test_utils:: TestLogger :: new ( ) ;
19982049 let network_graph = Arc :: new ( NetworkGraph :: new ( Network :: Testnet , & logger) ) ;
19992050 let scorer = RwLock :: new ( test_utils:: TestScorer :: new ( ) ) ;
@@ -2037,7 +2088,7 @@ mod tests {
20372088 do_find_route_error ( true ) ;
20382089 }
20392090 fn do_find_route_error ( on_retry : bool ) {
2040- let outbound_payments = OutboundPayments :: new ( ) ;
2091+ let outbound_payments = OutboundPayments :: new ( new_hash_map ( ) ) ;
20412092 let logger = test_utils:: TestLogger :: new ( ) ;
20422093 let network_graph = Arc :: new ( NetworkGraph :: new ( Network :: Testnet , & logger) ) ;
20432094 let scorer = RwLock :: new ( test_utils:: TestScorer :: new ( ) ) ;
@@ -2076,7 +2127,7 @@ mod tests {
20762127
20772128 #[ test]
20782129 fn initial_send_payment_path_failed_evs ( ) {
2079- let outbound_payments = OutboundPayments :: new ( ) ;
2130+ let outbound_payments = OutboundPayments :: new ( new_hash_map ( ) ) ;
20802131 let logger = test_utils:: TestLogger :: new ( ) ;
20812132 let network_graph = Arc :: new ( NetworkGraph :: new ( Network :: Testnet , & logger) ) ;
20822133 let scorer = RwLock :: new ( test_utils:: TestScorer :: new ( ) ) ;
@@ -2158,7 +2209,7 @@ mod tests {
21582209 #[ test]
21592210 fn removes_stale_awaiting_invoice_using_absolute_timeout ( ) {
21602211 let pending_events = Mutex :: new ( VecDeque :: new ( ) ) ;
2161- let outbound_payments = OutboundPayments :: new ( ) ;
2212+ let outbound_payments = OutboundPayments :: new ( new_hash_map ( ) ) ;
21622213 let payment_id = PaymentId ( [ 0 ; 32 ] ) ;
21632214 let absolute_expiry = 100 ;
21642215 let tick_interval = 10 ;
@@ -2167,7 +2218,7 @@ mod tests {
21672218 assert ! ( !outbound_payments. has_pending_payments( ) ) ;
21682219 assert ! (
21692220 outbound_payments. add_new_awaiting_invoice(
2170- payment_id, expiration, Retry :: Attempts ( 0 ) , None
2221+ payment_id, expiration, Retry :: Attempts ( 0 ) , None , None ,
21712222 ) . is_ok( )
21722223 ) ;
21732224 assert ! ( outbound_payments. has_pending_payments( ) ) ;
@@ -2197,30 +2248,30 @@ mod tests {
21972248
21982249 assert ! (
21992250 outbound_payments. add_new_awaiting_invoice(
2200- payment_id, expiration, Retry :: Attempts ( 0 ) , None
2251+ payment_id, expiration, Retry :: Attempts ( 0 ) , None , None ,
22012252 ) . is_ok( )
22022253 ) ;
22032254 assert ! ( outbound_payments. has_pending_payments( ) ) ;
22042255
22052256 assert ! (
22062257 outbound_payments. add_new_awaiting_invoice(
2207- payment_id, expiration, Retry :: Attempts ( 0 ) , None
2258+ payment_id, expiration, Retry :: Attempts ( 0 ) , None , None ,
22082259 ) . is_err( )
22092260 ) ;
22102261 }
22112262
22122263 #[ test]
22132264 fn removes_stale_awaiting_invoice_using_timer_ticks ( ) {
22142265 let pending_events = Mutex :: new ( VecDeque :: new ( ) ) ;
2215- let outbound_payments = OutboundPayments :: new ( ) ;
2266+ let outbound_payments = OutboundPayments :: new ( new_hash_map ( ) ) ;
22162267 let payment_id = PaymentId ( [ 0 ; 32 ] ) ;
22172268 let timer_ticks = 3 ;
22182269 let expiration = StaleExpiration :: TimerTicks ( timer_ticks) ;
22192270
22202271 assert ! ( !outbound_payments. has_pending_payments( ) ) ;
22212272 assert ! (
22222273 outbound_payments. add_new_awaiting_invoice(
2223- payment_id, expiration, Retry :: Attempts ( 0 ) , None
2274+ payment_id, expiration, Retry :: Attempts ( 0 ) , None , None ,
22242275 ) . is_ok( )
22252276 ) ;
22262277 assert ! ( outbound_payments. has_pending_payments( ) ) ;
@@ -2250,29 +2301,29 @@ mod tests {
22502301
22512302 assert ! (
22522303 outbound_payments. add_new_awaiting_invoice(
2253- payment_id, expiration, Retry :: Attempts ( 0 ) , None
2304+ payment_id, expiration, Retry :: Attempts ( 0 ) , None , None ,
22542305 ) . is_ok( )
22552306 ) ;
22562307 assert ! ( outbound_payments. has_pending_payments( ) ) ;
22572308
22582309 assert ! (
22592310 outbound_payments. add_new_awaiting_invoice(
2260- payment_id, expiration, Retry :: Attempts ( 0 ) , None
2311+ payment_id, expiration, Retry :: Attempts ( 0 ) , None , None ,
22612312 ) . is_err( )
22622313 ) ;
22632314 }
22642315
22652316 #[ test]
22662317 fn removes_abandoned_awaiting_invoice ( ) {
22672318 let pending_events = Mutex :: new ( VecDeque :: new ( ) ) ;
2268- let outbound_payments = OutboundPayments :: new ( ) ;
2319+ let outbound_payments = OutboundPayments :: new ( new_hash_map ( ) ) ;
22692320 let payment_id = PaymentId ( [ 0 ; 32 ] ) ;
22702321 let expiration = StaleExpiration :: AbsoluteTimeout ( Duration :: from_secs ( 100 ) ) ;
22712322
22722323 assert ! ( !outbound_payments. has_pending_payments( ) ) ;
22732324 assert ! (
22742325 outbound_payments. add_new_awaiting_invoice(
2275- payment_id, expiration, Retry :: Attempts ( 0 ) , None
2326+ payment_id, expiration, Retry :: Attempts ( 0 ) , None , None ,
22762327 ) . is_ok( )
22772328 ) ;
22782329 assert ! ( outbound_payments. has_pending_payments( ) ) ;
@@ -2302,13 +2353,13 @@ mod tests {
23022353 let keys_manager = test_utils:: TestKeysInterface :: new ( & [ 0 ; 32 ] , Network :: Testnet ) ;
23032354
23042355 let pending_events = Mutex :: new ( VecDeque :: new ( ) ) ;
2305- let outbound_payments = OutboundPayments :: new ( ) ;
2356+ let outbound_payments = OutboundPayments :: new ( new_hash_map ( ) ) ;
23062357 let payment_id = PaymentId ( [ 0 ; 32 ] ) ;
23072358 let expiration = StaleExpiration :: AbsoluteTimeout ( Duration :: from_secs ( 100 ) ) ;
23082359
23092360 assert ! (
23102361 outbound_payments. add_new_awaiting_invoice(
2311- payment_id, expiration, Retry :: Attempts ( 0 ) , None
2362+ payment_id, expiration, Retry :: Attempts ( 0 ) , None , None ,
23122363 ) . is_ok( )
23132364 ) ;
23142365 assert ! ( outbound_payments. has_pending_payments( ) ) ;
@@ -2355,7 +2406,7 @@ mod tests {
23552406 let keys_manager = test_utils:: TestKeysInterface :: new ( & [ 0 ; 32 ] , Network :: Testnet ) ;
23562407
23572408 let pending_events = Mutex :: new ( VecDeque :: new ( ) ) ;
2358- let outbound_payments = OutboundPayments :: new ( ) ;
2409+ let outbound_payments = OutboundPayments :: new ( new_hash_map ( ) ) ;
23592410 let payment_id = PaymentId ( [ 0 ; 32 ] ) ;
23602411 let expiration = StaleExpiration :: AbsoluteTimeout ( Duration :: from_secs ( 100 ) ) ;
23612412
@@ -2372,7 +2423,7 @@ mod tests {
23722423 assert ! (
23732424 outbound_payments. add_new_awaiting_invoice(
23742425 payment_id, expiration, Retry :: Attempts ( 0 ) ,
2375- Some ( invoice. amount_msats( ) / 100 + 50_000 )
2426+ Some ( invoice. amount_msats( ) / 100 + 50_000 ) , None ,
23762427 ) . is_ok( )
23772428 ) ;
23782429 assert ! ( outbound_payments. has_pending_payments( ) ) ;
@@ -2416,7 +2467,7 @@ mod tests {
24162467 let keys_manager = test_utils:: TestKeysInterface :: new ( & [ 0 ; 32 ] , Network :: Testnet ) ;
24172468
24182469 let pending_events = Mutex :: new ( VecDeque :: new ( ) ) ;
2419- let outbound_payments = OutboundPayments :: new ( ) ;
2470+ let outbound_payments = OutboundPayments :: new ( new_hash_map ( ) ) ;
24202471 let payment_id = PaymentId ( [ 0 ; 32 ] ) ;
24212472 let expiration = StaleExpiration :: AbsoluteTimeout ( Duration :: from_secs ( 100 ) ) ;
24222473
@@ -2472,7 +2523,7 @@ mod tests {
24722523
24732524 assert ! (
24742525 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 ,
24762527 ) . is_ok( )
24772528 ) ;
24782529 assert ! ( outbound_payments. has_pending_payments( ) ) ;
0 commit comments