From b84842a9048dcfc1d8d21e1db73e1961b4b175b0 Mon Sep 17 00:00:00 2001 From: Matt Corallo Date: Mon, 2 Oct 2023 19:14:26 +0000 Subject: [PATCH] Add a scoring decay method to the `ScoreUpdate` trait Rather than relying on fetching the current time during routefinding, here we introduce a new trait method to `ScoreUpdate` to do so. This largely mirrors what we do with the `NetworkGraph`, and allows us to take on much more expensive operations (floating point exponentiation) in our decaying. --- lightning-background-processor/src/lib.rs | 21 +++++++++++++++++++-- lightning/src/routing/scoring.rs | 18 ++++++++++++++++++ lightning/src/util/test_utils.rs | 2 ++ 3 files changed, 39 insertions(+), 2 deletions(-) diff --git a/lightning-background-processor/src/lib.rs b/lightning-background-processor/src/lib.rs index 416f8d7b6d0..1d5899682b3 100644 --- a/lightning-background-processor/src/lib.rs +++ b/lightning-background-processor/src/lib.rs @@ -294,6 +294,7 @@ macro_rules! define_run_body { let mut last_scorer_persist_call = $get_timer(SCORER_PERSIST_TIMER); let mut last_rebroadcast_call = $get_timer(REBROADCAST_TIMER); let mut have_pruned = false; + let mut have_decayed_scorer = false; loop { $process_channel_manager_events; @@ -401,9 +402,24 @@ macro_rules! define_run_body { last_prune_call = $get_timer(prune_timer); } + if !have_decayed_scorer { + if let Some(ref scorer) = $scorer { + if let Some(duration_since_epoch) = $time_fetch() { + log_trace!($logger, "Calling time_passed on scorer at startup"); + scorer.write_lock().time_passed(duration_since_epoch); + } + } + have_decayed_scorer = true; + } + if $timer_elapsed(&mut last_scorer_persist_call, SCORER_PERSIST_TIMER) { if let Some(ref scorer) = $scorer { - log_trace!($logger, "Persisting scorer"); + if let Some(duration_since_epoch) = $time_fetch() { + log_trace!($logger, "Calling time_passed and persisting scorer"); + scorer.write_lock().time_passed(duration_since_epoch); + } else { + log_trace!($logger, "Persisting scorer"); + } if let Err(e) = $persister.persist_scorer(&scorer) { log_error!($logger, "Error: Failed to persist scorer, check your disk and permissions {}", e) } @@ -1208,6 +1224,7 @@ mod tests { } } } + fn time_passed(&mut self, _: Duration) {} } #[cfg(c_bindings)] @@ -1616,7 +1633,7 @@ mod tests { loop { let log_entries = nodes[0].logger.lines.lock().unwrap(); - let expected_log = "Persisting scorer".to_string(); + let expected_log = "Calling time_passed and persisting scorer".to_string(); if log_entries.get(&("lightning_background_processor", expected_log)).is_some() { break } diff --git a/lightning/src/routing/scoring.rs b/lightning/src/routing/scoring.rs index 92ebb979cf7..ee6d515bc0e 100644 --- a/lightning/src/routing/scoring.rs +++ b/lightning/src/routing/scoring.rs @@ -120,6 +120,12 @@ pub trait ScoreUpdate { /// Handles updating channel penalties after a probe over the given path succeeded. fn probe_successful(&mut self, path: &Path, duration_since_epoch: Duration); + + /// Scorers may wish to reduce their certainty of channel liquidity information over time. + /// Thus, this method is provided to allow scorers to observe the passage of time - the holder + /// of this object should call this method regularly (generally via the + /// `lightning-background-processor` crate). + fn time_passed(&mut self, duration_since_epoch: Duration); } /// A trait which can both lookup and update routing channel penalty scores. @@ -160,6 +166,10 @@ impl> ScoreUpdate for T { fn probe_successful(&mut self, path: &Path, duration_since_epoch: Duration) { self.deref_mut().probe_successful(path, duration_since_epoch) } + + fn time_passed(&mut self, duration_since_epoch: Duration) { + self.deref_mut().time_passed(duration_since_epoch) + } } } } @@ -361,6 +371,10 @@ impl<'a, T: Score> ScoreUpdate for MultiThreadedScoreLockWrite<'a, T> { fn probe_successful(&mut self, path: &Path, duration_since_epoch: Duration) { self.0.probe_successful(path, duration_since_epoch) } + + fn time_passed(&mut self, duration_since_epoch: Duration) { + self.0.time_passed(duration_since_epoch) + } } @@ -406,6 +420,8 @@ impl ScoreUpdate for FixedPenaltyScorer { fn probe_failed(&mut self, _path: &Path, _short_channel_id: u64, _duration_since_epoch: Duration) {} fn probe_successful(&mut self, _path: &Path, _duration_since_epoch: Duration) {} + + fn time_passed(&mut self, _duration_since_epoch: Duration) {} } impl Writeable for FixedPenaltyScorer { @@ -1463,6 +1479,8 @@ impl>, L: Deref, T: Time> ScoreUpdate for Prob fn probe_successful(&mut self, path: &Path, duration_since_epoch: Duration) { self.payment_path_failed(path, u64::max_value(), duration_since_epoch) } + + fn time_passed(&mut self, _duration_since_epoch: Duration) {} } #[cfg(c_bindings)] diff --git a/lightning/src/util/test_utils.rs b/lightning/src/util/test_utils.rs index c6561863e09..805806dc346 100644 --- a/lightning/src/util/test_utils.rs +++ b/lightning/src/util/test_utils.rs @@ -1357,6 +1357,8 @@ impl ScoreUpdate for TestScorer { fn probe_failed(&mut self, _actual_path: &Path, _: u64, _duration_since_epoch: Duration) {} fn probe_successful(&mut self, _actual_path: &Path, _duration_since_epoch: Duration) {} + + fn time_passed(&mut self, _duration_since_epoch: Duration) {} } impl Drop for TestScorer {