Skip to content

Commit

Permalink
Drop half-life-based bucket decay in update_history_buckets
Browse files Browse the repository at this point in the history
Because we decay the bucket information in the background, there's
not much reason to try to decay them immediately prior to updating,
and in removing that we can also clean up a good bit of dead code,
which we do here.
  • Loading branch information
TheBlueMatt committed Nov 29, 2023
1 parent 4cc9ad3 commit 0498a13
Showing 1 changed file with 37 additions and 56 deletions.
93 changes: 37 additions & 56 deletions lightning/src/routing/scoring.rs
Original file line number Diff line number Diff line change
Expand Up @@ -807,7 +807,6 @@ struct DirectedChannelLiquidity<L: Deref<Target = u64>, BRT: Deref<Target = Hist
capacity_msat: u64,
last_updated: T,
offset_history_last_updated: T,
decay_params: ProbabilisticScoringDecayParameters,
}

impl<G: Deref<Target = NetworkGraph<L>>, L: Deref> ProbabilisticScorer<G, L> where L::Target: Logger {
Expand Down Expand Up @@ -839,7 +838,7 @@ impl<G: Deref<Target = NetworkGraph<L>>, L: Deref> ProbabilisticScorer<G, L> whe
let log_direction = |source, target| {
if let Some((directed_info, _)) = chan_debug.as_directed_to(target) {
let amt = directed_info.effective_capacity().as_msat();
let dir_liq = liq.as_directed(source, target, amt, self.decay_params);
let dir_liq = liq.as_directed(source, target, amt);

let min_buckets = &dir_liq.liquidity_history.min_liquidity_offset_history.buckets;
let max_buckets = &dir_liq.liquidity_history.max_liquidity_offset_history.buckets;
Expand Down Expand Up @@ -891,7 +890,7 @@ impl<G: Deref<Target = NetworkGraph<L>>, L: Deref> ProbabilisticScorer<G, L> whe
if let Some(liq) = self.channel_liquidities.get(&scid) {
if let Some((directed_info, source)) = chan.as_directed_to(target) {
let amt = directed_info.effective_capacity().as_msat();
let dir_liq = liq.as_directed(source, target, amt, self.decay_params);
let dir_liq = liq.as_directed(source, target, amt);
return Some((dir_liq.min_liquidity_msat(), dir_liq.max_liquidity_msat()));
}
}
Expand Down Expand Up @@ -933,7 +932,7 @@ impl<G: Deref<Target = NetworkGraph<L>>, L: Deref> ProbabilisticScorer<G, L> whe
if let Some(liq) = self.channel_liquidities.get(&scid) {
if let Some((directed_info, source)) = chan.as_directed_to(target) {
let amt = directed_info.effective_capacity().as_msat();
let dir_liq = liq.as_directed(source, target, amt, self.decay_params);
let dir_liq = liq.as_directed(source, target, amt);

let min_buckets = dir_liq.liquidity_history.min_liquidity_offset_history.buckets;
let mut max_buckets = dir_liq.liquidity_history.max_liquidity_offset_history.buckets;
Expand Down Expand Up @@ -964,7 +963,7 @@ impl<G: Deref<Target = NetworkGraph<L>>, L: Deref> ProbabilisticScorer<G, L> whe
if let Some(liq) = self.channel_liquidities.get(&scid) {
if let Some((directed_info, source)) = chan.as_directed_to(target) {
let capacity_msat = directed_info.effective_capacity().as_msat();
let dir_liq = liq.as_directed(source, target, capacity_msat, self.decay_params);
let dir_liq = liq.as_directed(source, target, capacity_msat);

return dir_liq.liquidity_history.calculate_success_probability_times_billion(
&params, amount_msat, capacity_msat
Expand All @@ -991,7 +990,7 @@ impl ChannelLiquidity {
/// Returns a view of the channel liquidity directed from `source` to `target` assuming
/// `capacity_msat`.
fn as_directed(
&self, source: &NodeId, target: &NodeId, capacity_msat: u64, decay_params: ProbabilisticScoringDecayParameters
&self, source: &NodeId, target: &NodeId, capacity_msat: u64,
) -> DirectedChannelLiquidity<&u64, &HistoricalBucketRangeTracker, &Duration> {
let (min_liquidity_offset_msat, max_liquidity_offset_msat, min_liquidity_offset_history, max_liquidity_offset_history) =
if source < target {
Expand All @@ -1012,14 +1011,13 @@ impl ChannelLiquidity {
capacity_msat,
last_updated: &self.last_updated,
offset_history_last_updated: &self.offset_history_last_updated,
decay_params: decay_params,
}
}

/// Returns a mutable view of the channel liquidity directed from `source` to `target` assuming
/// `capacity_msat`.
fn as_directed_mut(
&mut self, source: &NodeId, target: &NodeId, capacity_msat: u64, decay_params: ProbabilisticScoringDecayParameters
&mut self, source: &NodeId, target: &NodeId, capacity_msat: u64,
) -> DirectedChannelLiquidity<&mut u64, &mut HistoricalBucketRangeTracker, &mut Duration> {
let (min_liquidity_offset_msat, max_liquidity_offset_msat, min_liquidity_offset_history, max_liquidity_offset_history) =
if source < target {
Expand All @@ -1040,7 +1038,6 @@ impl ChannelLiquidity {
capacity_msat,
last_updated: &mut self.last_updated,
offset_history_last_updated: &mut self.offset_history_last_updated,
decay_params: decay_params,
}
}

Expand Down Expand Up @@ -1290,14 +1287,6 @@ DirectedChannelLiquidity<L, BRT, T> {
/// state"), we allow the caller to set an offset applied to our liquidity bounds which
/// represents the amount of the successful payment we just made.
fn update_history_buckets(&mut self, bucket_offset_msat: u64, duration_since_epoch: Duration) {
let half_lives =
duration_since_epoch.checked_sub(*self.offset_history_last_updated)
.unwrap_or(Duration::ZERO).as_secs()
.checked_div(self.decay_params.historical_no_updates_half_life.as_secs())
.map(|v| v.try_into().unwrap_or(u32::max_value())).unwrap_or(u32::max_value());
self.liquidity_history.min_liquidity_offset_history.time_decay_data(half_lives);
self.liquidity_history.max_liquidity_offset_history.time_decay_data(half_lives);

self.liquidity_history.min_liquidity_offset_history.track_datapoint(
*self.min_liquidity_offset_msat + bucket_offset_msat, self.capacity_msat
);
Expand Down Expand Up @@ -1363,7 +1352,7 @@ impl<G: Deref<Target = NetworkGraph<L>>, L: Deref> ScoreLookUp for Probabilistic
self.channel_liquidities
.get(&short_channel_id)
.unwrap_or(&ChannelLiquidity::new(Duration::ZERO))
.as_directed(source, target, capacity_msat, self.decay_params)
.as_directed(source, target, capacity_msat)
.penalty_msat(amount_msat, score_params)
.saturating_add(anti_probing_penalty_msat)
.saturating_add(base_penalty_msat)
Expand Down Expand Up @@ -1393,14 +1382,14 @@ impl<G: Deref<Target = NetworkGraph<L>>, L: Deref> ScoreUpdate for Probabilistic
self.channel_liquidities
.entry(hop.short_channel_id)
.or_insert_with(|| ChannelLiquidity::new(duration_since_epoch))
.as_directed_mut(source, &target, capacity_msat, self.decay_params)
.as_directed_mut(source, &target, capacity_msat)
.failed_at_channel(amount_msat, duration_since_epoch,
format_args!("SCID {}, towards {:?}", hop.short_channel_id, target), &self.logger);
} else {
self.channel_liquidities
.entry(hop.short_channel_id)
.or_insert_with(|| ChannelLiquidity::new(duration_since_epoch))
.as_directed_mut(source, &target, capacity_msat, self.decay_params)
.as_directed_mut(source, &target, capacity_msat)
.failed_downstream(amount_msat, duration_since_epoch,
format_args!("SCID {}, towards {:?}", hop.short_channel_id, target), &self.logger);
}
Expand Down Expand Up @@ -1429,7 +1418,7 @@ impl<G: Deref<Target = NetworkGraph<L>>, L: Deref> ScoreUpdate for Probabilistic
self.channel_liquidities
.entry(hop.short_channel_id)
.or_insert_with(|| ChannelLiquidity::new(duration_since_epoch))
.as_directed_mut(source, &target, capacity_msat, self.decay_params)
.as_directed_mut(source, &target, capacity_msat)
.successful(amount_msat, duration_since_epoch,
format_args!("SCID {}, towards {:?}", hop.short_channel_id, target), &self.logger);
} else {
Expand Down Expand Up @@ -1951,14 +1940,6 @@ mod bucketed_history {
self.buckets[bucket] = self.buckets[bucket].saturating_add(BUCKET_FIXED_POINT_ONE);
}
}
/// Decay all buckets by the given number of half-lives. Used to more aggressively remove old
/// datapoints as we receive newer information.
#[inline]
pub(super) fn time_decay_data(&mut self, half_lives: u32) {
for e in self.buckets.iter_mut() {
*e = e.checked_shr(half_lives).unwrap_or(0);
}
}
}

impl_writeable_tlv_based!(HistoricalBucketRangeTracker, { (0, buckets, required) });
Expand Down Expand Up @@ -2354,52 +2335,52 @@ mod tests {
// Update minimum liquidity.

let liquidity = scorer.channel_liquidities.get(&42).unwrap()
.as_directed(&source, &target, 1_000, decay_params);
.as_directed(&source, &target, 1_000);
assert_eq!(liquidity.min_liquidity_msat(), 100);
assert_eq!(liquidity.max_liquidity_msat(), 300);

let liquidity = scorer.channel_liquidities.get(&42).unwrap()
.as_directed(&target, &source, 1_000, decay_params);
.as_directed(&target, &source, 1_000);
assert_eq!(liquidity.min_liquidity_msat(), 700);
assert_eq!(liquidity.max_liquidity_msat(), 900);

scorer.channel_liquidities.get_mut(&42).unwrap()
.as_directed_mut(&source, &target, 1_000, decay_params)
.as_directed_mut(&source, &target, 1_000)
.set_min_liquidity_msat(200, Duration::ZERO);

let liquidity = scorer.channel_liquidities.get(&42).unwrap()
.as_directed(&source, &target, 1_000, decay_params);
.as_directed(&source, &target, 1_000);
assert_eq!(liquidity.min_liquidity_msat(), 200);
assert_eq!(liquidity.max_liquidity_msat(), 300);

let liquidity = scorer.channel_liquidities.get(&42).unwrap()
.as_directed(&target, &source, 1_000, decay_params);
.as_directed(&target, &source, 1_000);
assert_eq!(liquidity.min_liquidity_msat(), 700);
assert_eq!(liquidity.max_liquidity_msat(), 800);

// Update maximum liquidity.

let liquidity = scorer.channel_liquidities.get(&43).unwrap()
.as_directed(&target, &recipient, 1_000, decay_params);
.as_directed(&target, &recipient, 1_000);
assert_eq!(liquidity.min_liquidity_msat(), 700);
assert_eq!(liquidity.max_liquidity_msat(), 900);

let liquidity = scorer.channel_liquidities.get(&43).unwrap()
.as_directed(&recipient, &target, 1_000, decay_params);
.as_directed(&recipient, &target, 1_000);
assert_eq!(liquidity.min_liquidity_msat(), 100);
assert_eq!(liquidity.max_liquidity_msat(), 300);

scorer.channel_liquidities.get_mut(&43).unwrap()
.as_directed_mut(&target, &recipient, 1_000, decay_params)
.as_directed_mut(&target, &recipient, 1_000)
.set_max_liquidity_msat(200, Duration::ZERO);

let liquidity = scorer.channel_liquidities.get(&43).unwrap()
.as_directed(&target, &recipient, 1_000, decay_params);
.as_directed(&target, &recipient, 1_000);
assert_eq!(liquidity.min_liquidity_msat(), 0);
assert_eq!(liquidity.max_liquidity_msat(), 200);

let liquidity = scorer.channel_liquidities.get(&43).unwrap()
.as_directed(&recipient, &target, 1_000, decay_params);
.as_directed(&recipient, &target, 1_000);
assert_eq!(liquidity.min_liquidity_msat(), 800);
assert_eq!(liquidity.max_liquidity_msat(), 1000);
}
Expand All @@ -2425,42 +2406,42 @@ mod tests {

// Check initial bounds.
let liquidity = scorer.channel_liquidities.get(&42).unwrap()
.as_directed(&source, &target, 1_000, decay_params);
.as_directed(&source, &target, 1_000);
assert_eq!(liquidity.min_liquidity_msat(), 400);
assert_eq!(liquidity.max_liquidity_msat(), 800);

let liquidity = scorer.channel_liquidities.get(&42).unwrap()
.as_directed(&target, &source, 1_000, decay_params);
.as_directed(&target, &source, 1_000);
assert_eq!(liquidity.min_liquidity_msat(), 200);
assert_eq!(liquidity.max_liquidity_msat(), 600);

// Reset from source to target.
scorer.channel_liquidities.get_mut(&42).unwrap()
.as_directed_mut(&source, &target, 1_000, decay_params)
.as_directed_mut(&source, &target, 1_000)
.set_min_liquidity_msat(900, Duration::ZERO);

let liquidity = scorer.channel_liquidities.get(&42).unwrap()
.as_directed(&source, &target, 1_000, decay_params);
.as_directed(&source, &target, 1_000);
assert_eq!(liquidity.min_liquidity_msat(), 900);
assert_eq!(liquidity.max_liquidity_msat(), 1_000);

let liquidity = scorer.channel_liquidities.get(&42).unwrap()
.as_directed(&target, &source, 1_000, decay_params);
.as_directed(&target, &source, 1_000);
assert_eq!(liquidity.min_liquidity_msat(), 0);
assert_eq!(liquidity.max_liquidity_msat(), 100);

// Reset from target to source.
scorer.channel_liquidities.get_mut(&42).unwrap()
.as_directed_mut(&target, &source, 1_000, decay_params)
.as_directed_mut(&target, &source, 1_000)
.set_min_liquidity_msat(400, Duration::ZERO);

let liquidity = scorer.channel_liquidities.get(&42).unwrap()
.as_directed(&source, &target, 1_000, decay_params);
.as_directed(&source, &target, 1_000);
assert_eq!(liquidity.min_liquidity_msat(), 0);
assert_eq!(liquidity.max_liquidity_msat(), 600);

let liquidity = scorer.channel_liquidities.get(&42).unwrap()
.as_directed(&target, &source, 1_000, decay_params);
.as_directed(&target, &source, 1_000);
assert_eq!(liquidity.min_liquidity_msat(), 400);
assert_eq!(liquidity.max_liquidity_msat(), 1_000);
}
Expand All @@ -2486,42 +2467,42 @@ mod tests {

// Check initial bounds.
let liquidity = scorer.channel_liquidities.get(&42).unwrap()
.as_directed(&source, &target, 1_000, decay_params);
.as_directed(&source, &target, 1_000);
assert_eq!(liquidity.min_liquidity_msat(), 400);
assert_eq!(liquidity.max_liquidity_msat(), 800);

let liquidity = scorer.channel_liquidities.get(&42).unwrap()
.as_directed(&target, &source, 1_000, decay_params);
.as_directed(&target, &source, 1_000);
assert_eq!(liquidity.min_liquidity_msat(), 200);
assert_eq!(liquidity.max_liquidity_msat(), 600);

// Reset from source to target.
scorer.channel_liquidities.get_mut(&42).unwrap()
.as_directed_mut(&source, &target, 1_000, decay_params)
.as_directed_mut(&source, &target, 1_000)
.set_max_liquidity_msat(300, Duration::ZERO);

let liquidity = scorer.channel_liquidities.get(&42).unwrap()
.as_directed(&source, &target, 1_000, decay_params);
.as_directed(&source, &target, 1_000);
assert_eq!(liquidity.min_liquidity_msat(), 0);
assert_eq!(liquidity.max_liquidity_msat(), 300);

let liquidity = scorer.channel_liquidities.get(&42).unwrap()
.as_directed(&target, &source, 1_000, decay_params);
.as_directed(&target, &source, 1_000);
assert_eq!(liquidity.min_liquidity_msat(), 700);
assert_eq!(liquidity.max_liquidity_msat(), 1_000);

// Reset from target to source.
scorer.channel_liquidities.get_mut(&42).unwrap()
.as_directed_mut(&target, &source, 1_000, decay_params)
.as_directed_mut(&target, &source, 1_000)
.set_max_liquidity_msat(600, Duration::ZERO);

let liquidity = scorer.channel_liquidities.get(&42).unwrap()
.as_directed(&source, &target, 1_000, decay_params);
.as_directed(&source, &target, 1_000);
assert_eq!(liquidity.min_liquidity_msat(), 400);
assert_eq!(liquidity.max_liquidity_msat(), 1_000);

let liquidity = scorer.channel_liquidities.get(&42).unwrap()
.as_directed(&target, &source, 1_000, decay_params);
.as_directed(&target, &source, 1_000);
assert_eq!(liquidity.min_liquidity_msat(), 0);
assert_eq!(liquidity.max_liquidity_msat(), 600);
}
Expand Down Expand Up @@ -3464,7 +3445,7 @@ mod tests {
scorer.payment_path_failed(&path, 43, Duration::ZERO);

let liquidity = scorer.channel_liquidities.get(&42).unwrap()
.as_directed(&source, &target, 1_000, decay_params);
.as_directed(&source, &target, 1_000);
assert_eq!(liquidity.min_liquidity_msat(), 256);
assert_eq!(liquidity.max_liquidity_msat(), 768);
}
Expand Down

0 comments on commit 0498a13

Please sign in to comment.