Skip to content

Commit 72f0331

Browse files
committed
Use Duration based time info in scoring rather than Time
In the coming commits, the `T: Time` bound on `ProbabilisticScorer` will be removed. In order to enable that, we need to switch over to using the `ScoreUpdate`-provided current time (as a `Duration` since the unix epoch), making the `T` bound entirely unused.
1 parent 050c7ab commit 72f0331

File tree

1 file changed

+62
-85
lines changed

1 file changed

+62
-85
lines changed

lightning/src/routing/scoring.rs

Lines changed: 62 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -493,7 +493,8 @@ where L::Target: Logger {
493493
decay_params: ProbabilisticScoringDecayParameters,
494494
network_graph: G,
495495
logger: L,
496-
channel_liquidities: HashMap<u64, ChannelLiquidity<T>>,
496+
channel_liquidities: HashMap<u64, ChannelLiquidity>,
497+
_unused_time: core::marker::PhantomData<T>,
497498
}
498499

499500
/// Parameters for configuring [`ProbabilisticScorer`].
@@ -797,7 +798,7 @@ impl ProbabilisticScoringDecayParameters {
797798
/// Direction is defined in terms of [`NodeId`] partial ordering, where the source node is the
798799
/// first node in the ordering of the channel's counterparties. Thus, swapping the two liquidity
799800
/// offset fields gives the opposite direction.
800-
struct ChannelLiquidity<T: Time> {
801+
struct ChannelLiquidity {
801802
/// Lower channel liquidity bound in terms of an offset from zero.
802803
min_liquidity_offset_msat: u64,
803804

@@ -807,23 +808,22 @@ struct ChannelLiquidity<T: Time> {
807808
min_liquidity_offset_history: HistoricalBucketRangeTracker,
808809
max_liquidity_offset_history: HistoricalBucketRangeTracker,
809810

810-
/// Time when the liquidity bounds were last modified.
811-
last_updated: T,
811+
/// Time when the liquidity bounds were last modified as an offset since the unix epoch.
812+
last_updated: Duration,
812813

813-
/// Time when the historical liquidity bounds were last modified.
814-
offset_history_last_updated: T,
814+
/// Time when the historical liquidity bounds were last modified as an offset against the unix
815+
/// epoch.
816+
offset_history_last_updated: Duration,
815817
}
816818

817-
/// A snapshot of [`ChannelLiquidity`] in one direction assuming a certain channel capacity and
818-
/// decayed with a given half life.
819-
struct DirectedChannelLiquidity<L: Deref<Target = u64>, BRT: Deref<Target = HistoricalBucketRangeTracker>, T: Time, U: Deref<Target = T>> {
819+
/// A snapshot of [`ChannelLiquidity`] in one direction assuming a certain channel capacity.
820+
struct DirectedChannelLiquidity<L: Deref<Target = u64>, BRT: Deref<Target = HistoricalBucketRangeTracker>, T: Deref<Target = Duration>> {
820821
min_liquidity_offset_msat: L,
821822
max_liquidity_offset_msat: L,
822823
liquidity_history: HistoricalMinMaxBuckets<BRT>,
823824
capacity_msat: u64,
824-
last_updated: U,
825-
offset_history_last_updated: U,
826-
now: T,
825+
last_updated: T,
826+
offset_history_last_updated: T,
827827
decay_params: ProbabilisticScoringDecayParameters,
828828
}
829829

@@ -836,11 +836,12 @@ impl<G: Deref<Target = NetworkGraph<L>>, L: Deref, T: Time> ProbabilisticScorerU
836836
network_graph,
837837
logger,
838838
channel_liquidities: HashMap::new(),
839+
_unused_time: core::marker::PhantomData,
839840
}
840841
}
841842

842843
#[cfg(test)]
843-
fn with_channel(mut self, short_channel_id: u64, liquidity: ChannelLiquidity<T>) -> Self {
844+
fn with_channel(mut self, short_channel_id: u64, liquidity: ChannelLiquidity) -> Self {
844845
assert!(self.channel_liquidities.insert(short_channel_id, liquidity).is_none());
845846
self
846847
}
@@ -993,24 +994,23 @@ impl<G: Deref<Target = NetworkGraph<L>>, L: Deref, T: Time> ProbabilisticScorerU
993994
}
994995
}
995996

996-
impl<T: Time> ChannelLiquidity<T> {
997-
#[inline]
998-
fn new() -> Self {
997+
impl ChannelLiquidity {
998+
fn new(last_updated: Duration) -> Self {
999999
Self {
10001000
min_liquidity_offset_msat: 0,
10011001
max_liquidity_offset_msat: 0,
10021002
min_liquidity_offset_history: HistoricalBucketRangeTracker::new(),
10031003
max_liquidity_offset_history: HistoricalBucketRangeTracker::new(),
1004-
last_updated: T::now(),
1005-
offset_history_last_updated: T::now(),
1004+
last_updated,
1005+
offset_history_last_updated: last_updated,
10061006
}
10071007
}
10081008

10091009
/// Returns a view of the channel liquidity directed from `source` to `target` assuming
10101010
/// `capacity_msat`.
10111011
fn as_directed(
10121012
&self, source: &NodeId, target: &NodeId, capacity_msat: u64, decay_params: ProbabilisticScoringDecayParameters
1013-
) -> DirectedChannelLiquidity<&u64, &HistoricalBucketRangeTracker, T, &T> {
1013+
) -> DirectedChannelLiquidity<&u64, &HistoricalBucketRangeTracker, &Duration> {
10141014
let (min_liquidity_offset_msat, max_liquidity_offset_msat, min_liquidity_offset_history, max_liquidity_offset_history) =
10151015
if source < target {
10161016
(&self.min_liquidity_offset_msat, &self.max_liquidity_offset_msat,
@@ -1030,7 +1030,6 @@ impl<T: Time> ChannelLiquidity<T> {
10301030
capacity_msat,
10311031
last_updated: &self.last_updated,
10321032
offset_history_last_updated: &self.offset_history_last_updated,
1033-
now: T::now(),
10341033
decay_params: decay_params,
10351034
}
10361035
}
@@ -1039,7 +1038,7 @@ impl<T: Time> ChannelLiquidity<T> {
10391038
/// `capacity_msat`.
10401039
fn as_directed_mut(
10411040
&mut self, source: &NodeId, target: &NodeId, capacity_msat: u64, decay_params: ProbabilisticScoringDecayParameters
1042-
) -> DirectedChannelLiquidity<&mut u64, &mut HistoricalBucketRangeTracker, T, &mut T> {
1041+
) -> DirectedChannelLiquidity<&mut u64, &mut HistoricalBucketRangeTracker, &mut Duration> {
10431042
let (min_liquidity_offset_msat, max_liquidity_offset_msat, min_liquidity_offset_history, max_liquidity_offset_history) =
10441043
if source < target {
10451044
(&mut self.min_liquidity_offset_msat, &mut self.max_liquidity_offset_msat,
@@ -1059,7 +1058,6 @@ impl<T: Time> ChannelLiquidity<T> {
10591058
capacity_msat,
10601059
last_updated: &mut self.last_updated,
10611060
offset_history_last_updated: &mut self.offset_history_last_updated,
1062-
now: T::now(),
10631061
decay_params: decay_params,
10641062
}
10651063
}
@@ -1070,7 +1068,7 @@ impl<T: Time> ChannelLiquidity<T> {
10701068
) -> u64 {
10711069
let half_life = decay_params.liquidity_offset_half_life.as_secs_f64();
10721070
if half_life != 0.0 {
1073-
let elapsed_time = T::now().duration_since(self.last_updated).as_secs_f64();
1071+
let elapsed_time = duration_since_epoch.saturating_sub(self.last_updated).as_secs_f64();
10741072
((offset as f64) * powf64(0.5, elapsed_time / half_life)) as u64
10751073
} else {
10761074
0
@@ -1159,7 +1157,8 @@ fn success_probability(
11591157
(numerator, denominator)
11601158
}
11611159

1162-
impl<L: Deref<Target = u64>, BRT: Deref<Target = HistoricalBucketRangeTracker>, T: Time, U: Deref<Target = T>> DirectedChannelLiquidity< L, BRT, T, U> {
1160+
impl<L: Deref<Target = u64>, BRT: Deref<Target = HistoricalBucketRangeTracker>, T: Deref<Target = Duration>>
1161+
DirectedChannelLiquidity< L, BRT, T> {
11631162
/// Returns a liquidity penalty for routing the given HTLC `amount_msat` through the channel in
11641163
/// this direction.
11651164
fn penalty_msat(&self, amount_msat: u64, score_params: &ProbabilisticScoringFeeParameters) -> u64 {
@@ -1267,7 +1266,8 @@ impl<L: Deref<Target = u64>, BRT: Deref<Target = HistoricalBucketRangeTracker>,
12671266
}
12681267
}
12691268

1270-
impl<L: DerefMut<Target = u64>, BRT: DerefMut<Target = HistoricalBucketRangeTracker>, T: Time, U: DerefMut<Target = T>> DirectedChannelLiquidity<L, BRT, T, U> {
1269+
impl<L: DerefMut<Target = u64>, BRT: DerefMut<Target = HistoricalBucketRangeTracker>, T: DerefMut<Target = Duration>>
1270+
DirectedChannelLiquidity<L, BRT, T> {
12711271
/// Adjusts the channel liquidity balance bounds when failing to route `amount_msat`.
12721272
fn failed_at_channel<Log: Deref>(
12731273
&mut self, amount_msat: u64, duration_since_epoch: Duration, chan_descr: fmt::Arguments, logger: &Log
@@ -1313,7 +1313,9 @@ impl<L: DerefMut<Target = u64>, BRT: DerefMut<Target = HistoricalBucketRangeTrac
13131313
/// state"), we allow the caller to set an offset applied to our liquidity bounds which
13141314
/// represents the amount of the successful payment we just made.
13151315
fn update_history_buckets(&mut self, bucket_offset_msat: u64, duration_since_epoch: Duration) {
1316-
let half_lives = self.now.duration_since(*self.offset_history_last_updated).as_secs()
1316+
let half_lives =
1317+
duration_since_epoch.checked_sub(*self.offset_history_last_updated)
1318+
.unwrap_or(Duration::ZERO).as_secs()
13171319
.checked_div(self.decay_params.historical_no_updates_half_life.as_secs())
13181320
.map(|v| v.try_into().unwrap_or(u32::max_value())).unwrap_or(u32::max_value());
13191321
self.liquidity_history.min_liquidity_offset_history.time_decay_data(half_lives);
@@ -1327,29 +1329,25 @@ impl<L: DerefMut<Target = u64>, BRT: DerefMut<Target = HistoricalBucketRangeTrac
13271329
self.liquidity_history.max_liquidity_offset_history.track_datapoint(
13281330
max_liquidity_offset_msat.saturating_sub(bucket_offset_msat), self.capacity_msat
13291331
);
1330-
*self.offset_history_last_updated = self.now;
1332+
*self.offset_history_last_updated = duration_since_epoch;
13311333
}
13321334

13331335
/// Adjusts the lower bound of the channel liquidity balance in this direction.
13341336
fn set_min_liquidity_msat(&mut self, amount_msat: u64, duration_since_epoch: Duration) {
13351337
*self.min_liquidity_offset_msat = amount_msat;
1336-
*self.max_liquidity_offset_msat = if amount_msat > self.max_liquidity_msat() {
1337-
0
1338-
} else {
1339-
self.decayed_offset_msat(*self.max_liquidity_offset_msat)
1340-
};
1341-
*self.last_updated = self.now;
1338+
if amount_msat > self.max_liquidity_msat() {
1339+
*self.max_liquidity_offset_msat = 0;
1340+
}
1341+
*self.last_updated = duration_since_epoch;
13421342
}
13431343

13441344
/// Adjusts the upper bound of the channel liquidity balance in this direction.
13451345
fn set_max_liquidity_msat(&mut self, amount_msat: u64, duration_since_epoch: Duration) {
13461346
*self.max_liquidity_offset_msat = self.capacity_msat.checked_sub(amount_msat).unwrap_or(0);
1347-
*self.min_liquidity_offset_msat = if amount_msat < self.min_liquidity_msat() {
1348-
0
1349-
} else {
1350-
self.decayed_offset_msat(*self.min_liquidity_offset_msat)
1351-
};
1352-
*self.last_updated = self.now;
1347+
if amount_msat < *self.min_liquidity_offset_msat {
1348+
*self.min_liquidity_offset_msat = 0;
1349+
}
1350+
*self.last_updated = duration_since_epoch;
13531351
}
13541352
}
13551353

@@ -1396,7 +1394,7 @@ impl<G: Deref<Target = NetworkGraph<L>>, L: Deref, T: Time> ScoreLookUp for Prob
13961394
let capacity_msat = usage.effective_capacity.as_msat();
13971395
self.channel_liquidities
13981396
.get(&scid)
1399-
.unwrap_or(&ChannelLiquidity::new())
1397+
.unwrap_or(&ChannelLiquidity::new(Duration::ZERO))
14001398
.as_directed(&source, &target, capacity_msat, self.decay_params)
14011399
.penalty_msat(amount_msat, score_params)
14021400
.saturating_add(anti_probing_penalty_msat)
@@ -1426,14 +1424,14 @@ impl<G: Deref<Target = NetworkGraph<L>>, L: Deref, T: Time> ScoreUpdate for Prob
14261424
if at_failed_channel {
14271425
self.channel_liquidities
14281426
.entry(hop.short_channel_id)
1429-
.or_insert_with(ChannelLiquidity::new)
1427+
.or_insert_with(|| ChannelLiquidity::new(duration_since_epoch))
14301428
.as_directed_mut(source, &target, capacity_msat, self.decay_params)
14311429
.failed_at_channel(amount_msat, duration_since_epoch,
14321430
format_args!("SCID {}, towards {:?}", hop.short_channel_id, target), &self.logger);
14331431
} else {
14341432
self.channel_liquidities
14351433
.entry(hop.short_channel_id)
1436-
.or_insert_with(ChannelLiquidity::new)
1434+
.or_insert_with(|| ChannelLiquidity::new(duration_since_epoch))
14371435
.as_directed_mut(source, &target, capacity_msat, self.decay_params)
14381436
.failed_downstream(amount_msat, duration_since_epoch,
14391437
format_args!("SCID {}, towards {:?}", hop.short_channel_id, target), &self.logger);
@@ -1462,7 +1460,7 @@ impl<G: Deref<Target = NetworkGraph<L>>, L: Deref, T: Time> ScoreUpdate for Prob
14621460
let capacity_msat = channel.effective_capacity().as_msat();
14631461
self.channel_liquidities
14641462
.entry(hop.short_channel_id)
1465-
.or_insert_with(ChannelLiquidity::new)
1463+
.or_insert_with(|| ChannelLiquidity::new(duration_since_epoch))
14661464
.as_directed_mut(source, &target, capacity_msat, self.decay_params)
14671465
.successful(amount_msat, duration_since_epoch,
14681466
format_args!("SCID {}, towards {:?}", hop.short_channel_id, target), &self.logger);
@@ -1488,10 +1486,10 @@ impl<G: Deref<Target = NetworkGraph<L>>, L: Deref, T: Time> ScoreUpdate for Prob
14881486
liquidity.decayed_offset(liquidity.min_liquidity_offset_msat, duration_since_epoch, decay_params);
14891487
liquidity.max_liquidity_offset_msat =
14901488
liquidity.decayed_offset(liquidity.max_liquidity_offset_msat, duration_since_epoch, decay_params);
1491-
liquidity.last_updated = T::now();
1489+
liquidity.last_updated = duration_since_epoch;
14921490

14931491
let elapsed_time =
1494-
T::now().duration_since(liquidity.offset_history_last_updated);
1492+
duration_since_epoch.saturating_sub(liquidity.offset_history_last_updated);
14951493
if elapsed_time > decay_params.historical_no_updates_half_life {
14961494
let half_life = decay_params.historical_no_updates_half_life.as_secs_f64();
14971495
if half_life != 0.0 {
@@ -1502,7 +1500,7 @@ impl<G: Deref<Target = NetworkGraph<L>>, L: Deref, T: Time> ScoreUpdate for Prob
15021500
for bucket in liquidity.max_liquidity_offset_history.buckets.iter_mut() {
15031501
*bucket = ((*bucket as u64) * 1024 / divisor) as u16;
15041502
}
1505-
liquidity.offset_history_last_updated = T::now();
1503+
liquidity.offset_history_last_updated = duration_since_epoch;
15061504
}
15071505
}
15081506
liquidity.min_liquidity_offset_msat != 0 || liquidity.max_liquidity_offset_msat != 0 ||
@@ -2125,31 +2123,29 @@ ReadableArgs<(ProbabilisticScoringDecayParameters, G, L)> for ProbabilisticScore
21252123
network_graph,
21262124
logger,
21272125
channel_liquidities,
2126+
_unused_time: core::marker::PhantomData,
21282127
})
21292128
}
21302129
}
21312130

2132-
impl<T: Time> Writeable for ChannelLiquidity<T> {
2131+
impl Writeable for ChannelLiquidity {
21332132
#[inline]
21342133
fn write<W: Writer>(&self, w: &mut W) -> Result<(), io::Error> {
2135-
let offset_history_duration_since_epoch =
2136-
T::duration_since_epoch() - self.offset_history_last_updated.elapsed();
2137-
let duration_since_epoch = T::duration_since_epoch() - self.last_updated.elapsed();
21382134
write_tlv_fields!(w, {
21392135
(0, self.min_liquidity_offset_msat, required),
21402136
// 1 was the min_liquidity_offset_history in octile form
21412137
(2, self.max_liquidity_offset_msat, required),
21422138
// 3 was the max_liquidity_offset_history in octile form
2143-
(4, duration_since_epoch, required),
2139+
(4, self.last_updated, required),
21442140
(5, Some(self.min_liquidity_offset_history), option),
21452141
(7, Some(self.max_liquidity_offset_history), option),
2146-
(9, offset_history_duration_since_epoch, required),
2142+
(9, self.offset_history_last_updated, required),
21472143
});
21482144
Ok(())
21492145
}
21502146
}
21512147

2152-
impl<T: Time> Readable for ChannelLiquidity<T> {
2148+
impl Readable for ChannelLiquidity {
21532149
#[inline]
21542150
fn read<R: Read>(r: &mut R) -> Result<Self, DecodeError> {
21552151
let mut min_liquidity_offset_msat = 0;
@@ -2158,36 +2154,18 @@ impl<T: Time> Readable for ChannelLiquidity<T> {
21582154
let mut legacy_max_liq_offset_history: Option<LegacyHistoricalBucketRangeTracker> = None;
21592155
let mut min_liquidity_offset_history: Option<HistoricalBucketRangeTracker> = None;
21602156
let mut max_liquidity_offset_history: Option<HistoricalBucketRangeTracker> = None;
2161-
let mut duration_since_epoch = Duration::from_secs(0);
2162-
let mut offset_history_duration_since_epoch = None;
2157+
let mut last_updated = Duration::from_secs(0);
2158+
let mut offset_history_last_updated = None;
21632159
read_tlv_fields!(r, {
21642160
(0, min_liquidity_offset_msat, required),
21652161
(1, legacy_min_liq_offset_history, option),
21662162
(2, max_liquidity_offset_msat, required),
21672163
(3, legacy_max_liq_offset_history, option),
2168-
(4, duration_since_epoch, required),
2164+
(4, last_updated, required),
21692165
(5, min_liquidity_offset_history, option),
21702166
(7, max_liquidity_offset_history, option),
2171-
(9, offset_history_duration_since_epoch, option),
2167+
(9, offset_history_last_updated, option),
21722168
});
2173-
// On rust prior to 1.60 `Instant::duration_since` will panic if time goes backwards.
2174-
// We write `last_updated` as wallclock time even though its ultimately an `Instant` (which
2175-
// is a time from a monotonic clock usually represented as an offset against boot time).
2176-
// Thus, we have to construct an `Instant` by subtracting the difference in wallclock time
2177-
// from the one that was written. However, because `Instant` can panic if we construct one
2178-
// in the future, we must handle wallclock time jumping backwards, which we do by simply
2179-
// using `Instant::now()` in that case.
2180-
let wall_clock_now = T::duration_since_epoch();
2181-
let now = T::now();
2182-
let last_updated = if wall_clock_now > duration_since_epoch {
2183-
now - (wall_clock_now - duration_since_epoch)
2184-
} else { now };
2185-
2186-
let offset_history_duration_since_epoch =
2187-
offset_history_duration_since_epoch.unwrap_or(duration_since_epoch);
2188-
let offset_history_last_updated = if wall_clock_now > offset_history_duration_since_epoch {
2189-
now - (wall_clock_now - offset_history_duration_since_epoch)
2190-
} else { now };
21912169

21922170
if min_liquidity_offset_history.is_none() {
21932171
if let Some(legacy_buckets) = legacy_min_liq_offset_history {
@@ -2209,7 +2187,7 @@ impl<T: Time> Readable for ChannelLiquidity<T> {
22092187
min_liquidity_offset_history: min_liquidity_offset_history.unwrap(),
22102188
max_liquidity_offset_history: max_liquidity_offset_history.unwrap(),
22112189
last_updated,
2212-
offset_history_last_updated,
2190+
offset_history_last_updated: offset_history_last_updated.unwrap_or(last_updated),
22132191
})
22142192
}
22152193
}
@@ -2219,7 +2197,6 @@ mod tests {
22192197
use super::{ChannelLiquidity, HistoricalBucketRangeTracker, ProbabilisticScoringFeeParameters, ProbabilisticScoringDecayParameters, ProbabilisticScorerUsingTime};
22202198
use crate::blinded_path::{BlindedHop, BlindedPath};
22212199
use crate::util::config::UserConfig;
2222-
use crate::util::time::Time;
22232200
use crate::util::time::tests::SinceEpoch;
22242201

22252202
use crate::ln::channelmanager;
@@ -2384,8 +2361,8 @@ mod tests {
23842361
#[test]
23852362
fn liquidity_bounds_directed_from_lowest_node_id() {
23862363
let logger = TestLogger::new();
2387-
let last_updated = SinceEpoch::now();
2388-
let offset_history_last_updated = SinceEpoch::now();
2364+
let last_updated = Duration::ZERO;
2365+
let offset_history_last_updated = Duration::ZERO;
23892366
let network_graph = network_graph(&logger);
23902367
let decay_params = ProbabilisticScoringDecayParameters::default();
23912368
let mut scorer = ProbabilisticScorer::new(decay_params, &network_graph, &logger)
@@ -2465,8 +2442,8 @@ mod tests {
24652442
#[test]
24662443
fn resets_liquidity_upper_bound_when_crossed_by_lower_bound() {
24672444
let logger = TestLogger::new();
2468-
let last_updated = SinceEpoch::now();
2469-
let offset_history_last_updated = SinceEpoch::now();
2445+
let last_updated = Duration::ZERO;
2446+
let offset_history_last_updated = Duration::ZERO;
24702447
let network_graph = network_graph(&logger);
24712448
let decay_params = ProbabilisticScoringDecayParameters::default();
24722449
let mut scorer = ProbabilisticScorer::new(decay_params, &network_graph, &logger)
@@ -2526,8 +2503,8 @@ mod tests {
25262503
#[test]
25272504
fn resets_liquidity_lower_bound_when_crossed_by_upper_bound() {
25282505
let logger = TestLogger::new();
2529-
let last_updated = SinceEpoch::now();
2530-
let offset_history_last_updated = SinceEpoch::now();
2506+
let last_updated = Duration::ZERO;
2507+
let offset_history_last_updated = Duration::ZERO;
25312508
let network_graph = network_graph(&logger);
25322509
let decay_params = ProbabilisticScoringDecayParameters::default();
25332510
let mut scorer = ProbabilisticScorer::new(decay_params, &network_graph, &logger)
@@ -2639,8 +2616,8 @@ mod tests {
26392616
#[test]
26402617
fn constant_penalty_outside_liquidity_bounds() {
26412618
let logger = TestLogger::new();
2642-
let last_updated = SinceEpoch::now();
2643-
let offset_history_last_updated = SinceEpoch::now();
2619+
let last_updated = Duration::ZERO;
2620+
let offset_history_last_updated = Duration::ZERO;
26442621
let network_graph = network_graph(&logger);
26452622
let params = ProbabilisticScoringFeeParameters {
26462623
liquidity_penalty_multiplier_msat: 1_000,

0 commit comments

Comments
 (0)