@@ -29,6 +29,7 @@ use crate::util::ser::ReadableArgs;
29
29
30
30
use core:: fmt:: { self , Display , Formatter } ;
31
31
use core:: ops:: Deref ;
32
+ use core:: time:: Duration ;
32
33
33
34
use crate :: prelude:: * ;
34
35
use crate :: sync:: Mutex ;
@@ -39,20 +40,14 @@ use crate::sync::Mutex;
39
40
/// [`ChannelManager::timer_tick_occurred`]: crate::ln::channelmanager::ChannelManager::timer_tick_occurred
40
41
pub ( crate ) const IDEMPOTENCY_TIMEOUT_TICKS : u8 = 7 ;
41
42
42
- /// The number of ticks of [`ChannelManager::timer_tick_occurred`] until an invoice request without
43
- /// a response is timed out.
44
- ///
45
- /// [`ChannelManager::timer_tick_occurred`]: crate::ln::channelmanager::ChannelManager::timer_tick_occurred
46
- const INVOICE_REQUEST_TIMEOUT_TICKS : u8 = 3 ;
47
-
48
43
/// Stores the session_priv for each part of a payment that is still pending. For versions 0.0.102
49
44
/// and later, also stores information for retrying the payment.
50
45
pub ( crate ) enum PendingOutboundPayment {
51
46
Legacy {
52
47
session_privs : HashSet < [ u8 ; 32 ] > ,
53
48
} ,
54
49
AwaitingInvoice {
55
- timer_ticks_without_response : u8 ,
50
+ absolute_expiry : Duration ,
56
51
retry_strategy : Retry ,
57
52
max_total_routing_fee_msat : Option < u64 > ,
58
53
} ,
@@ -1274,15 +1269,16 @@ impl OutboundPayments {
1274
1269
}
1275
1270
1276
1271
#[ allow( unused) ]
1277
- pub ( super ) fn add_new_awaiting_invoice (
1278
- & self , payment_id : PaymentId , retry_strategy : Retry , max_total_routing_fee_msat : Option < u64 >
1272
+ fn add_new_awaiting_invoice (
1273
+ & self , payment_id : PaymentId , absolute_expiry : Duration , retry_strategy : Retry ,
1274
+ max_total_routing_fee_msat : Option < u64 >
1279
1275
) -> Result < ( ) , ( ) > {
1280
1276
let mut pending_outbounds = self . pending_outbound_payments . lock ( ) . unwrap ( ) ;
1281
1277
match pending_outbounds. entry ( payment_id) {
1282
1278
hash_map:: Entry :: Occupied ( _) => Err ( ( ) ) ,
1283
1279
hash_map:: Entry :: Vacant ( entry) => {
1284
1280
entry. insert ( PendingOutboundPayment :: AwaitingInvoice {
1285
- timer_ticks_without_response : 0 ,
1281
+ absolute_expiry ,
1286
1282
retry_strategy,
1287
1283
max_total_routing_fee_msat,
1288
1284
} ) ;
@@ -1511,22 +1507,23 @@ impl OutboundPayments {
1511
1507
}
1512
1508
1513
1509
pub ( super ) fn remove_stale_payments (
1514
- & self , pending_events : & Mutex < VecDeque < ( events:: Event , Option < EventCompletionAction > ) > > )
1510
+ & self , duration_since_epoch : Duration ,
1511
+ pending_events : & Mutex < VecDeque < ( events:: Event , Option < EventCompletionAction > ) > > )
1515
1512
{
1516
1513
let mut pending_outbound_payments = self . pending_outbound_payments . lock ( ) . unwrap ( ) ;
1517
1514
#[ cfg( not( invreqfailed) ) ]
1518
1515
let pending_events = pending_events. lock ( ) . unwrap ( ) ;
1519
1516
#[ cfg( invreqfailed) ]
1520
1517
let mut pending_events = pending_events. lock ( ) . unwrap ( ) ;
1521
- pending_outbound_payments. retain ( |payment_id, payment| {
1518
+ pending_outbound_payments. retain ( |payment_id, payment| match payment {
1522
1519
// If an outbound payment was completed, and no pending HTLCs remain, we should remove it
1523
1520
// from the map. However, if we did that immediately when the last payment HTLC is claimed,
1524
1521
// this could race the user making a duplicate send_payment call and our idempotency
1525
1522
// guarantees would be violated. Instead, we wait a few timer ticks to do the actual
1526
1523
// removal. This should be more than sufficient to ensure the idempotency of any
1527
1524
// `send_payment` calls that were made at the same time the `PaymentSent` event was being
1528
1525
// processed.
1529
- if let PendingOutboundPayment :: Fulfilled { session_privs, timer_ticks_without_htlcs, .. } = payment {
1526
+ PendingOutboundPayment :: Fulfilled { session_privs, timer_ticks_without_htlcs, .. } => {
1530
1527
let mut no_remaining_entries = session_privs. is_empty ( ) ;
1531
1528
if no_remaining_entries {
1532
1529
for ( ev, _) in pending_events. iter ( ) {
@@ -1550,9 +1547,9 @@ impl OutboundPayments {
1550
1547
* timer_ticks_without_htlcs = 0 ;
1551
1548
true
1552
1549
}
1553
- } else if let PendingOutboundPayment :: AwaitingInvoice { timer_ticks_without_response , .. } = payment {
1554
- * timer_ticks_without_response += 1 ;
1555
- if * timer_ticks_without_response <= INVOICE_REQUEST_TIMEOUT_TICKS {
1550
+ } ,
1551
+ PendingOutboundPayment :: AwaitingInvoice { absolute_expiry , .. } => {
1552
+ if duration_since_epoch < * absolute_expiry {
1556
1553
true
1557
1554
} else {
1558
1555
#[ cfg( invreqfailed) ]
@@ -1561,7 +1558,8 @@ impl OutboundPayments {
1561
1558
) ;
1562
1559
false
1563
1560
}
1564
- } else { true }
1561
+ } ,
1562
+ _ => true ,
1565
1563
} ) ;
1566
1564
}
1567
1565
@@ -1778,7 +1776,7 @@ impl_writeable_tlv_based_enum_upgradable!(PendingOutboundPayment,
1778
1776
( 2 , payment_hash, required) ,
1779
1777
} ,
1780
1778
( 5 , AwaitingInvoice ) => {
1781
- ( 0 , timer_ticks_without_response , required) ,
1779
+ ( 0 , absolute_expiry , required) ,
1782
1780
( 2 , retry_strategy, required) ,
1783
1781
( 4 , max_total_routing_fee_msat, option) ,
1784
1782
} ,
@@ -1794,14 +1792,14 @@ mod tests {
1794
1792
use bitcoin:: network:: constants:: Network ;
1795
1793
use bitcoin:: secp256k1:: { PublicKey , Secp256k1 , SecretKey } ;
1796
1794
1795
+ use core:: time:: Duration ;
1796
+
1797
1797
use crate :: events:: { Event , PathFailure , PaymentFailureReason } ;
1798
1798
use crate :: ln:: PaymentHash ;
1799
1799
use crate :: ln:: channelmanager:: { PaymentId , RecipientOnionFields } ;
1800
1800
use crate :: ln:: features:: { ChannelFeatures , NodeFeatures } ;
1801
1801
use crate :: ln:: msgs:: { ErrorAction , LightningError } ;
1802
1802
use crate :: ln:: outbound_payment:: { Bolt12PaymentError , OutboundPayments , Retry , RetryableSendFailure } ;
1803
- #[ cfg( invreqfailed) ]
1804
- use crate :: ln:: outbound_payment:: INVOICE_REQUEST_TIMEOUT_TICKS ;
1805
1803
use crate :: offers:: invoice:: DEFAULT_RELATIVE_EXPIRY ;
1806
1804
use crate :: offers:: offer:: OfferBuilder ;
1807
1805
use crate :: offers:: test_utils:: * ;
@@ -2011,20 +2009,28 @@ mod tests {
2011
2009
let pending_events = Mutex :: new ( VecDeque :: new ( ) ) ;
2012
2010
let outbound_payments = OutboundPayments :: new ( ) ;
2013
2011
let payment_id = PaymentId ( [ 0 ; 32 ] ) ;
2012
+ let absolute_expiry = 100 ;
2013
+ let tick_interval = 10 ;
2014
2014
2015
2015
assert ! ( !outbound_payments. has_pending_payments( ) ) ;
2016
2016
assert ! (
2017
- outbound_payments. add_new_awaiting_invoice( payment_id, Retry :: Attempts ( 0 ) , None ) . is_ok( )
2017
+ outbound_payments. add_new_awaiting_invoice(
2018
+ payment_id, Duration :: from_secs( absolute_expiry) , Retry :: Attempts ( 0 ) , None
2019
+ ) . is_ok( )
2018
2020
) ;
2019
2021
assert ! ( outbound_payments. has_pending_payments( ) ) ;
2020
2022
2021
- for _ in 0 ..INVOICE_REQUEST_TIMEOUT_TICKS {
2022
- outbound_payments. remove_stale_payments ( & pending_events) ;
2023
+ for seconds_since_epoch in ( 0 ..absolute_expiry) . step_by ( tick_interval) {
2024
+ let duration_since_epoch = Duration :: from_secs ( seconds_since_epoch) ;
2025
+ outbound_payments. remove_stale_payments ( duration_since_epoch, & pending_events) ;
2026
+
2023
2027
assert ! ( outbound_payments. has_pending_payments( ) ) ;
2024
2028
assert ! ( pending_events. lock( ) . unwrap( ) . is_empty( ) ) ;
2025
2029
}
2026
2030
2027
- outbound_payments. remove_stale_payments ( & pending_events) ;
2031
+ let duration_since_epoch = Duration :: from_secs ( absolute_expiry) ;
2032
+ outbound_payments. remove_stale_payments ( duration_since_epoch, & pending_events) ;
2033
+
2028
2034
assert ! ( !outbound_payments. has_pending_payments( ) ) ;
2029
2035
assert ! ( !pending_events. lock( ) . unwrap( ) . is_empty( ) ) ;
2030
2036
assert_eq ! (
@@ -2034,13 +2040,16 @@ mod tests {
2034
2040
assert ! ( pending_events. lock( ) . unwrap( ) . is_empty( ) ) ;
2035
2041
2036
2042
assert ! (
2037
- outbound_payments. add_new_awaiting_invoice( payment_id, Retry :: Attempts ( 0 ) , None ) . is_ok( )
2043
+ outbound_payments. add_new_awaiting_invoice(
2044
+ payment_id, Duration :: from_secs( absolute_expiry + 1 ) , Retry :: Attempts ( 0 ) , None
2045
+ ) . is_ok( )
2038
2046
) ;
2039
2047
assert ! ( outbound_payments. has_pending_payments( ) ) ;
2040
2048
2041
2049
assert ! (
2042
- outbound_payments. add_new_awaiting_invoice( payment_id, Retry :: Attempts ( 0 ) , None )
2043
- . is_err( )
2050
+ outbound_payments. add_new_awaiting_invoice(
2051
+ payment_id, Duration :: from_secs( absolute_expiry + 1 ) , Retry :: Attempts ( 0 ) , None
2052
+ ) . is_err( )
2044
2053
) ;
2045
2054
}
2046
2055
@@ -2050,10 +2059,13 @@ mod tests {
2050
2059
let pending_events = Mutex :: new ( VecDeque :: new ( ) ) ;
2051
2060
let outbound_payments = OutboundPayments :: new ( ) ;
2052
2061
let payment_id = PaymentId ( [ 0 ; 32 ] ) ;
2062
+ let absolute_expiry = 100 ;
2053
2063
2054
2064
assert ! ( !outbound_payments. has_pending_payments( ) ) ;
2055
2065
assert ! (
2056
- outbound_payments. add_new_awaiting_invoice( payment_id, Retry :: Attempts ( 0 ) , None ) . is_ok( )
2066
+ outbound_payments. add_new_awaiting_invoice(
2067
+ payment_id, Duration :: from_secs( absolute_expiry) , Retry :: Attempts ( 0 ) , None
2068
+ ) . is_ok( )
2057
2069
) ;
2058
2070
assert ! ( outbound_payments. has_pending_payments( ) ) ;
2059
2071
@@ -2081,9 +2093,12 @@ mod tests {
2081
2093
let pending_events = Mutex :: new ( VecDeque :: new ( ) ) ;
2082
2094
let outbound_payments = OutboundPayments :: new ( ) ;
2083
2095
let payment_id = PaymentId ( [ 0 ; 32 ] ) ;
2096
+ let absolute_expiry = 100 ;
2084
2097
2085
2098
assert ! (
2086
- outbound_payments. add_new_awaiting_invoice( payment_id, Retry :: Attempts ( 0 ) , None ) . is_ok( )
2099
+ outbound_payments. add_new_awaiting_invoice(
2100
+ payment_id, Duration :: from_secs( absolute_expiry) , Retry :: Attempts ( 0 ) , None
2101
+ ) . is_ok( )
2087
2102
) ;
2088
2103
assert ! ( outbound_payments. has_pending_payments( ) ) ;
2089
2104
@@ -2129,6 +2144,7 @@ mod tests {
2129
2144
let pending_events = Mutex :: new ( VecDeque :: new ( ) ) ;
2130
2145
let outbound_payments = OutboundPayments :: new ( ) ;
2131
2146
let payment_id = PaymentId ( [ 0 ; 32 ] ) ;
2147
+ let absolute_expiry = 100 ;
2132
2148
2133
2149
let invoice = OfferBuilder :: new ( "foo" . into ( ) , recipient_pubkey ( ) )
2134
2150
. amount_msats ( 1000 )
@@ -2140,9 +2156,11 @@ mod tests {
2140
2156
. build ( ) . unwrap ( )
2141
2157
. sign ( recipient_sign) . unwrap ( ) ;
2142
2158
2143
- assert ! ( outbound_payments. add_new_awaiting_invoice(
2144
- payment_id, Retry :: Attempts ( 0 ) , Some ( invoice. amount_msats( ) / 100 + 50_000 ) )
2145
- . is_ok( )
2159
+ assert ! (
2160
+ outbound_payments. add_new_awaiting_invoice(
2161
+ payment_id, Duration :: from_secs( absolute_expiry) , Retry :: Attempts ( 0 ) ,
2162
+ Some ( invoice. amount_msats( ) / 100 + 50_000 )
2163
+ ) . is_ok( )
2146
2164
) ;
2147
2165
assert ! ( outbound_payments. has_pending_payments( ) ) ;
2148
2166
@@ -2185,6 +2203,7 @@ mod tests {
2185
2203
let pending_events = Mutex :: new ( VecDeque :: new ( ) ) ;
2186
2204
let outbound_payments = OutboundPayments :: new ( ) ;
2187
2205
let payment_id = PaymentId ( [ 0 ; 32 ] ) ;
2206
+ let absolute_expiry = 100 ;
2188
2207
2189
2208
let invoice = OfferBuilder :: new ( "foo" . into ( ) , recipient_pubkey ( ) )
2190
2209
. amount_msats ( 1000 )
@@ -2196,9 +2215,11 @@ mod tests {
2196
2215
. build ( ) . unwrap ( )
2197
2216
. sign ( recipient_sign) . unwrap ( ) ;
2198
2217
2199
- assert ! ( outbound_payments. add_new_awaiting_invoice(
2200
- payment_id, Retry :: Attempts ( 0 ) , Some ( invoice. amount_msats( ) / 100 + 50_000 ) )
2201
- . is_ok( )
2218
+ assert ! (
2219
+ outbound_payments. add_new_awaiting_invoice(
2220
+ payment_id, Duration :: from_secs( absolute_expiry) , Retry :: Attempts ( 0 ) ,
2221
+ Some ( invoice. amount_msats( ) / 100 + 50_000 )
2222
+ ) . is_ok( )
2202
2223
) ;
2203
2224
assert ! ( outbound_payments. has_pending_payments( ) ) ;
2204
2225
@@ -2241,6 +2262,7 @@ mod tests {
2241
2262
let pending_events = Mutex :: new ( VecDeque :: new ( ) ) ;
2242
2263
let outbound_payments = OutboundPayments :: new ( ) ;
2243
2264
let payment_id = PaymentId ( [ 0 ; 32 ] ) ;
2265
+ let absolute_expiry = 100 ;
2244
2266
2245
2267
let invoice = OfferBuilder :: new ( "foo" . into ( ) , recipient_pubkey ( ) )
2246
2268
. amount_msats ( 1000 )
@@ -2292,7 +2314,9 @@ mod tests {
2292
2314
assert ! ( pending_events. lock( ) . unwrap( ) . is_empty( ) ) ;
2293
2315
2294
2316
assert ! (
2295
- outbound_payments. add_new_awaiting_invoice( payment_id, Retry :: Attempts ( 0 ) , Some ( 1234 ) ) . is_ok( )
2317
+ outbound_payments. add_new_awaiting_invoice(
2318
+ payment_id, Duration :: from_secs( absolute_expiry) , Retry :: Attempts ( 0 ) , Some ( 1234 )
2319
+ ) . is_ok( )
2296
2320
) ;
2297
2321
assert ! ( outbound_payments. has_pending_payments( ) ) ;
2298
2322
0 commit comments