Skip to content

Commit e7df074

Browse files
committed
f - use system/block time instead of ticks for removing stale AwaitingInvoice
1 parent 7e98017 commit e7df074

File tree

2 files changed

+53
-55
lines changed

2 files changed

+53
-55
lines changed

lightning/src/ln/channelmanager.rs

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5017,7 +5017,18 @@ where
50175017
self.finish_close_channel(shutdown_res);
50185018
}
50195019

5020-
self.pending_outbound_payments.remove_stale_payments(&self.pending_events);
5020+
#[cfg(feature = "std")]
5021+
let duration_since_epoch = std::time::SystemTime::now()
5022+
.duration_since(std::time::SystemTime::UNIX_EPOCH)
5023+
.expect("SystemTime::now() should come after SystemTime::UNIX_EPOCH");
5024+
#[cfg(not(feature = "std"))]
5025+
let duration_since_epoch = Duration::from_secs(
5026+
self.highest_seen_timestamp.load(Ordering::Acquire).saturating_sub(7200) as u64
5027+
);
5028+
5029+
self.pending_outbound_payments.remove_stale_payments(
5030+
duration_since_epoch, &self.pending_events
5031+
);
50215032

50225033
// Technically we don't need to do this here, but if we have holding cell entries in a
50235034
// channel that need freeing, it's better to do that here and block a background task

lightning/src/ln/outbound_payment.rs

Lines changed: 41 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ use crate::util::ser::ReadableArgs;
2929

3030
use core::fmt::{self, Display, Formatter};
3131
use core::ops::Deref;
32+
use core::time::Duration;
3233

3334
use crate::prelude::*;
3435
use crate::sync::Mutex;
@@ -39,20 +40,14 @@ use crate::sync::Mutex;
3940
/// [`ChannelManager::timer_tick_occurred`]: crate::ln::channelmanager::ChannelManager::timer_tick_occurred
4041
pub(crate) const IDEMPOTENCY_TIMEOUT_TICKS: u8 = 7;
4142

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: Option<u64> = Some(3);
47-
4843
/// Stores the session_priv for each part of a payment that is still pending. For versions 0.0.102
4944
/// and later, also stores information for retrying the payment.
5045
pub(crate) enum PendingOutboundPayment {
5146
Legacy {
5247
session_privs: HashSet<[u8; 32]>,
5348
},
5449
AwaitingInvoice {
55-
timer_ticks_without_response_remaining: Option<u64>,
50+
absolute_expiry: Duration,
5651
retry_strategy: Retry,
5752
max_total_routing_fee_msat: Option<u64>,
5853
},
@@ -1273,36 +1268,17 @@ impl OutboundPayments {
12731268
(payment, onion_session_privs)
12741269
}
12751270

1276-
#[allow(unused)]
1277-
pub(super) fn add_new_awaiting_invoice_for_offer(
1278-
&self, payment_id: PaymentId, retry_strategy: Retry, max_total_routing_fee_msat: Option<u64>
1279-
) -> Result<(), ()> {
1280-
self.add_new_awaiting_invoice(
1281-
payment_id, retry_strategy, max_total_routing_fee_msat, INVOICE_REQUEST_TIMEOUT_TICKS
1282-
)
1283-
}
1284-
1285-
#[allow(unused)]
1286-
pub(super) fn add_new_awaiting_invoice_for_refund(
1287-
&self, payment_id: PaymentId, retry_strategy: Retry,
1288-
max_total_routing_fee_msat: Option<u64>, timer_ticks_before_expiration: Option<u64>
1289-
) -> Result<(), ()> {
1290-
self.add_new_awaiting_invoice(
1291-
payment_id, retry_strategy, max_total_routing_fee_msat, timer_ticks_before_expiration
1292-
)
1293-
}
1294-
12951271
#[allow(unused)]
12961272
fn add_new_awaiting_invoice(
1297-
&self, payment_id: PaymentId, retry_strategy: Retry,
1298-
max_total_routing_fee_msat: Option<u64>, timer_ticks_before_expiration: Option<u64>
1273+
&self, payment_id: PaymentId, absolute_expiry: Duration, retry_strategy: Retry,
1274+
max_total_routing_fee_msat: Option<u64>
12991275
) -> Result<(), ()> {
13001276
let mut pending_outbounds = self.pending_outbound_payments.lock().unwrap();
13011277
match pending_outbounds.entry(payment_id) {
13021278
hash_map::Entry::Occupied(_) => Err(()),
13031279
hash_map::Entry::Vacant(entry) => {
13041280
entry.insert(PendingOutboundPayment::AwaitingInvoice {
1305-
timer_ticks_without_response_remaining: timer_ticks_before_expiration,
1281+
absolute_expiry,
13061282
retry_strategy,
13071283
max_total_routing_fee_msat,
13081284
});
@@ -1531,22 +1507,23 @@ impl OutboundPayments {
15311507
}
15321508

15331509
pub(super) fn remove_stale_payments(
1534-
&self, pending_events: &Mutex<VecDeque<(events::Event, Option<EventCompletionAction>)>>)
1510+
&self, duration_since_epoch: Duration,
1511+
pending_events: &Mutex<VecDeque<(events::Event, Option<EventCompletionAction>)>>)
15351512
{
15361513
let mut pending_outbound_payments = self.pending_outbound_payments.lock().unwrap();
15371514
#[cfg(not(invreqfailed))]
15381515
let pending_events = pending_events.lock().unwrap();
15391516
#[cfg(invreqfailed)]
15401517
let mut pending_events = pending_events.lock().unwrap();
1541-
pending_outbound_payments.retain(|payment_id, payment| {
1518+
pending_outbound_payments.retain(|payment_id, payment| match payment {
15421519
// If an outbound payment was completed, and no pending HTLCs remain, we should remove it
15431520
// from the map. However, if we did that immediately when the last payment HTLC is claimed,
15441521
// this could race the user making a duplicate send_payment call and our idempotency
15451522
// guarantees would be violated. Instead, we wait a few timer ticks to do the actual
15461523
// removal. This should be more than sufficient to ensure the idempotency of any
15471524
// `send_payment` calls that were made at the same time the `PaymentSent` event was being
15481525
// processed.
1549-
if let PendingOutboundPayment::Fulfilled { session_privs, timer_ticks_without_htlcs, .. } = payment {
1526+
PendingOutboundPayment::Fulfilled { session_privs, timer_ticks_without_htlcs, .. } => {
15501527
let mut no_remaining_entries = session_privs.is_empty();
15511528
if no_remaining_entries {
15521529
for (ev, _) in pending_events.iter() {
@@ -1570,11 +1547,9 @@ impl OutboundPayments {
15701547
*timer_ticks_without_htlcs = 0;
15711548
true
15721549
}
1573-
} else if let PendingOutboundPayment::AwaitingInvoice {
1574-
timer_ticks_without_response_remaining: Some(timer_ticks_remaining), ..
1575-
} = payment {
1576-
if *timer_ticks_remaining > 0 {
1577-
*timer_ticks_remaining -= 1;
1550+
},
1551+
PendingOutboundPayment::AwaitingInvoice { absolute_expiry, .. } => {
1552+
if duration_since_epoch < *absolute_expiry {
15781553
true
15791554
} else {
15801555
#[cfg(invreqfailed)]
@@ -1583,7 +1558,8 @@ impl OutboundPayments {
15831558
);
15841559
false
15851560
}
1586-
} else { true }
1561+
},
1562+
_ => true,
15871563
});
15881564
}
15891565

@@ -1800,7 +1776,7 @@ impl_writeable_tlv_based_enum_upgradable!(PendingOutboundPayment,
18001776
(2, payment_hash, required),
18011777
},
18021778
(5, AwaitingInvoice) => {
1803-
(0, timer_ticks_without_response_remaining, option),
1779+
(0, absolute_expiry, required),
18041780
(2, retry_strategy, required),
18051781
(4, max_total_routing_fee_msat, option),
18061782
},
@@ -1816,14 +1792,14 @@ mod tests {
18161792
use bitcoin::network::constants::Network;
18171793
use bitcoin::secp256k1::{PublicKey, Secp256k1, SecretKey};
18181794

1795+
use core::time::Duration;
1796+
18191797
use crate::events::{Event, PathFailure, PaymentFailureReason};
18201798
use crate::ln::PaymentHash;
18211799
use crate::ln::channelmanager::{PaymentId, RecipientOnionFields};
18221800
use crate::ln::features::{ChannelFeatures, NodeFeatures};
18231801
use crate::ln::msgs::{ErrorAction, LightningError};
18241802
use crate::ln::outbound_payment::{Bolt12PaymentError, OutboundPayments, Retry, RetryableSendFailure};
1825-
#[cfg(invreqfailed)]
1826-
use crate::ln::outbound_payment::INVOICE_REQUEST_TIMEOUT_TICKS;
18271803
use crate::offers::invoice::DEFAULT_RELATIVE_EXPIRY;
18281804
use crate::offers::offer::OfferBuilder;
18291805
use crate::offers::test_utils::*;
@@ -2033,22 +2009,28 @@ mod tests {
20332009
let pending_events = Mutex::new(VecDeque::new());
20342010
let outbound_payments = OutboundPayments::new();
20352011
let payment_id = PaymentId([0; 32]);
2012+
let absolute_expiry = 100;
2013+
let tick_interval = 10;
20362014

20372015
assert!(!outbound_payments.has_pending_payments());
20382016
assert!(
20392017
outbound_payments.add_new_awaiting_invoice(
2040-
payment_id, Retry::Attempts(0), None, INVOICE_REQUEST_TIMEOUT_TICKS
2018+
payment_id, Duration::from_secs(absolute_expiry), Retry::Attempts(0), None
20412019
).is_ok()
20422020
);
20432021
assert!(outbound_payments.has_pending_payments());
20442022

2045-
for _ in 0..INVOICE_REQUEST_TIMEOUT_TICKS.unwrap() {
2046-
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+
20472027
assert!(outbound_payments.has_pending_payments());
20482028
assert!(pending_events.lock().unwrap().is_empty());
20492029
}
20502030

2051-
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+
20522034
assert!(!outbound_payments.has_pending_payments());
20532035
assert!(!pending_events.lock().unwrap().is_empty());
20542036
assert_eq!(
@@ -2059,14 +2041,14 @@ mod tests {
20592041

20602042
assert!(
20612043
outbound_payments.add_new_awaiting_invoice(
2062-
payment_id, Retry::Attempts(0), None, INVOICE_REQUEST_TIMEOUT_TICKS
2044+
payment_id, Duration::from_secs(absolute_expiry + 1), Retry::Attempts(0), None
20632045
).is_ok()
20642046
);
20652047
assert!(outbound_payments.has_pending_payments());
20662048

20672049
assert!(
20682050
outbound_payments.add_new_awaiting_invoice(
2069-
payment_id, Retry::Attempts(0), None, INVOICE_REQUEST_TIMEOUT_TICKS
2051+
payment_id, Duration::from_secs(absolute_expiry + 1), Retry::Attempts(0), None
20702052
).is_err()
20712053
);
20722054
}
@@ -2077,11 +2059,12 @@ mod tests {
20772059
let pending_events = Mutex::new(VecDeque::new());
20782060
let outbound_payments = OutboundPayments::new();
20792061
let payment_id = PaymentId([0; 32]);
2062+
let absolute_expiry = 100;
20802063

20812064
assert!(!outbound_payments.has_pending_payments());
20822065
assert!(
20832066
outbound_payments.add_new_awaiting_invoice(
2084-
payment_id, Retry::Attempts(0), None, INVOICE_REQUEST_TIMEOUT_TICKS
2067+
payment_id, Duration::from_secs(absolute_expiry), Retry::Attempts(0), None
20852068
).is_ok()
20862069
);
20872070
assert!(outbound_payments.has_pending_payments());
@@ -2110,10 +2093,11 @@ mod tests {
21102093
let pending_events = Mutex::new(VecDeque::new());
21112094
let outbound_payments = OutboundPayments::new();
21122095
let payment_id = PaymentId([0; 32]);
2096+
let absolute_expiry = 100;
21132097

21142098
assert!(
21152099
outbound_payments.add_new_awaiting_invoice(
2116-
payment_id, Retry::Attempts(0), None, INVOICE_REQUEST_TIMEOUT_TICKS
2100+
payment_id, Duration::from_secs(absolute_expiry), Retry::Attempts(0), None
21172101
).is_ok()
21182102
);
21192103
assert!(outbound_payments.has_pending_payments());
@@ -2160,6 +2144,7 @@ mod tests {
21602144
let pending_events = Mutex::new(VecDeque::new());
21612145
let outbound_payments = OutboundPayments::new();
21622146
let payment_id = PaymentId([0; 32]);
2147+
let absolute_expiry = 100;
21632148

21642149
let invoice = OfferBuilder::new("foo".into(), recipient_pubkey())
21652150
.amount_msats(1000)
@@ -2173,8 +2158,8 @@ mod tests {
21732158

21742159
assert!(
21752160
outbound_payments.add_new_awaiting_invoice(
2176-
payment_id, Retry::Attempts(0), Some(invoice.amount_msats() / 100 + 50_000),
2177-
INVOICE_REQUEST_TIMEOUT_TICKS
2161+
payment_id, Duration::from_secs(absolute_expiry), Retry::Attempts(0),
2162+
Some(invoice.amount_msats() / 100 + 50_000)
21782163
).is_ok()
21792164
);
21802165
assert!(outbound_payments.has_pending_payments());
@@ -2218,6 +2203,7 @@ mod tests {
22182203
let pending_events = Mutex::new(VecDeque::new());
22192204
let outbound_payments = OutboundPayments::new();
22202205
let payment_id = PaymentId([0; 32]);
2206+
let absolute_expiry = 100;
22212207

22222208
let invoice = OfferBuilder::new("foo".into(), recipient_pubkey())
22232209
.amount_msats(1000)
@@ -2231,8 +2217,8 @@ mod tests {
22312217

22322218
assert!(
22332219
outbound_payments.add_new_awaiting_invoice(
2234-
payment_id, Retry::Attempts(0), Some(invoice.amount_msats() / 100 + 50_000),
2235-
INVOICE_REQUEST_TIMEOUT_TICKS
2220+
payment_id, Duration::from_secs(absolute_expiry), Retry::Attempts(0),
2221+
Some(invoice.amount_msats() / 100 + 50_000)
22362222
).is_ok()
22372223
);
22382224
assert!(outbound_payments.has_pending_payments());
@@ -2276,6 +2262,7 @@ mod tests {
22762262
let pending_events = Mutex::new(VecDeque::new());
22772263
let outbound_payments = OutboundPayments::new();
22782264
let payment_id = PaymentId([0; 32]);
2265+
let absolute_expiry = 100;
22792266

22802267
let invoice = OfferBuilder::new("foo".into(), recipient_pubkey())
22812268
.amount_msats(1000)
@@ -2328,7 +2315,7 @@ mod tests {
23282315

23292316
assert!(
23302317
outbound_payments.add_new_awaiting_invoice(
2331-
payment_id, Retry::Attempts(0), Some(1234), INVOICE_REQUEST_TIMEOUT_TICKS
2318+
payment_id, Duration::from_secs(absolute_expiry), Retry::Attempts(0), Some(1234)
23322319
).is_ok()
23332320
);
23342321
assert!(outbound_payments.has_pending_payments());

0 commit comments

Comments
 (0)