Merge pull request #1212 from TheBlueMatt/2021-12-timeout-graph

Add a method to prune stale channels from NetworkGraph
This commit is contained in:
Matt Corallo 2021-12-16 23:04:00 +00:00 committed by GitHub
commit cec8ce0fcb
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 372 additions and 502 deletions

View file

@ -11,7 +11,7 @@ edition = "2018"
[dependencies] [dependencies]
bitcoin = "0.27" bitcoin = "0.27"
lightning = { version = "0.0.103", path = "../lightning", features = ["allow_wallclock_use"] } lightning = { version = "0.0.103", path = "../lightning", features = ["std"] }
lightning-persister = { version = "0.0.103", path = "../lightning-persister" } lightning-persister = { version = "0.0.103", path = "../lightning-persister" }
[dev-dependencies] [dev-dependencies]

View file

@ -34,6 +34,8 @@ use std::ops::Deref;
/// [`ChannelManager`] persistence should be done in the background. /// [`ChannelManager`] persistence should be done in the background.
/// * Calling [`ChannelManager::timer_tick_occurred`] and [`PeerManager::timer_tick_occurred`] /// * Calling [`ChannelManager::timer_tick_occurred`] and [`PeerManager::timer_tick_occurred`]
/// at the appropriate intervals. /// at the appropriate intervals.
/// * Calling [`NetworkGraph::remove_stale_channels`] (if a [`NetGraphMsgHandler`] is provided to
/// [`BackgroundProcessor::start`]).
/// ///
/// It will also call [`PeerManager::process_events`] periodically though this shouldn't be relied /// It will also call [`PeerManager::process_events`] periodically though this shouldn't be relied
/// upon as doing so may result in high latency. /// upon as doing so may result in high latency.
@ -68,6 +70,9 @@ const PING_TIMER: u64 = 30;
#[cfg(test)] #[cfg(test)]
const PING_TIMER: u64 = 1; const PING_TIMER: u64 = 1;
/// Prune the network graph of stale entries hourly.
const NETWORK_PRUNE_TIMER: u64 = 60 * 60;
/// Trait which handles persisting a [`ChannelManager`] to disk. /// Trait which handles persisting a [`ChannelManager`] to disk.
/// ///
/// [`ChannelManager`]: lightning::ln::channelmanager::ChannelManager /// [`ChannelManager`]: lightning::ln::channelmanager::ChannelManager
@ -203,13 +208,16 @@ impl BackgroundProcessor {
let stop_thread = Arc::new(AtomicBool::new(false)); let stop_thread = Arc::new(AtomicBool::new(false));
let stop_thread_clone = stop_thread.clone(); let stop_thread_clone = stop_thread.clone();
let handle = thread::spawn(move || -> Result<(), std::io::Error> { let handle = thread::spawn(move || -> Result<(), std::io::Error> {
let event_handler = DecoratingEventHandler { event_handler, net_graph_msg_handler }; let event_handler = DecoratingEventHandler { event_handler, net_graph_msg_handler: net_graph_msg_handler.as_ref().map(|t| t.deref()) };
log_trace!(logger, "Calling ChannelManager's timer_tick_occurred on startup"); log_trace!(logger, "Calling ChannelManager's timer_tick_occurred on startup");
channel_manager.timer_tick_occurred(); channel_manager.timer_tick_occurred();
let mut last_freshness_call = Instant::now(); let mut last_freshness_call = Instant::now();
let mut last_ping_call = Instant::now(); let mut last_ping_call = Instant::now();
let mut last_prune_call = Instant::now();
let mut have_pruned = false;
loop { loop {
peer_manager.process_events(); peer_manager.process_events();
channel_manager.process_pending_events(&event_handler); channel_manager.process_pending_events(&event_handler);
@ -247,6 +255,19 @@ impl BackgroundProcessor {
peer_manager.timer_tick_occurred(); peer_manager.timer_tick_occurred();
last_ping_call = Instant::now(); last_ping_call = Instant::now();
} }
// Note that we want to run a graph prune once not long after startup before
// falling back to our usual hourly prunes. This avoids short-lived clients never
// pruning their network graph. We run once 60 seconds after startup before
// continuing our normal cadence.
if last_prune_call.elapsed().as_secs() > if have_pruned { NETWORK_PRUNE_TIMER } else { 60 } {
if let Some(ref handler) = net_graph_msg_handler {
log_trace!(logger, "Pruning network graph of stale entries");
handler.network_graph().remove_stale_channels();
last_prune_call = Instant::now();
have_pruned = true;
}
}
} }
}); });
Self { stop_thread: stop_thread_clone, thread_handle: Some(handle) } Self { stop_thread: stop_thread_clone, thread_handle: Some(handle) }

View file

@ -11,7 +11,6 @@ Still missing tons of error-handling. See GitHub issues for suggested projects i
""" """
[features] [features]
allow_wallclock_use = []
fuzztarget = ["bitcoin/fuzztarget", "regex"] fuzztarget = ["bitcoin/fuzztarget", "regex"]
# Internal test utilities exposed to other repo crates # Internal test utilities exposed to other repo crates
_test_utils = ["hex", "regex", "bitcoin/bitcoinconsensus"] _test_utils = ["hex", "regex", "bitcoin/bitcoinconsensus"]
@ -53,6 +52,3 @@ secp256k1 = { version = "0.20.2", default-features = false, features = ["alloc"]
version = "0.27" version = "0.27"
default-features = false default-features = false
features = ["bitcoinconsensus", "secp-recovery"] features = ["bitcoinconsensus", "secp-recovery"]
[package.metadata.docs.rs]
features = ["allow_wallclock_use"] # When https://github.com/rust-lang/rust/issues/43781 complies with our MSVR, we can add nice banners in the docs for the methods behind this feature-gate.

View file

@ -67,10 +67,11 @@ use io::{Cursor, Read};
use sync::{Arc, Condvar, Mutex, MutexGuard, RwLock, RwLockReadGuard}; use sync::{Arc, Condvar, Mutex, MutexGuard, RwLock, RwLockReadGuard};
use core::sync::atomic::{AtomicUsize, Ordering}; use core::sync::atomic::{AtomicUsize, Ordering};
use core::time::Duration; use core::time::Duration;
#[cfg(any(test, feature = "allow_wallclock_use"))]
use std::time::Instant;
use core::ops::Deref; use core::ops::Deref;
#[cfg(any(test, feature = "std"))]
use std::time::Instant;
// We hold various information about HTLC relay in the HTLC objects in Channel itself: // We hold various information about HTLC relay in the HTLC objects in Channel itself:
// //
// Upon receipt of an HTLC from a peer, we'll give it a PendingHTLCStatus indicating if it should // Upon receipt of an HTLC from a peer, we'll give it a PendingHTLCStatus indicating if it should
@ -5110,8 +5111,9 @@ where
/// indicating whether persistence is necessary. Only one listener on /// indicating whether persistence is necessary. Only one listener on
/// `await_persistable_update` or `await_persistable_update_timeout` is guaranteed to be woken /// `await_persistable_update` or `await_persistable_update_timeout` is guaranteed to be woken
/// up. /// up.
/// Note that the feature `allow_wallclock_use` must be enabled to use this function. ///
#[cfg(any(test, feature = "allow_wallclock_use"))] /// Note that this method is not available with the `no-std` feature.
#[cfg(any(test, feature = "std"))]
pub fn await_persistable_update_timeout(&self, max_wait: Duration) -> bool { pub fn await_persistable_update_timeout(&self, max_wait: Duration) -> bool {
self.persistence_notifier.wait_timeout(max_wait) self.persistence_notifier.wait_timeout(max_wait)
} }
@ -5406,7 +5408,7 @@ impl PersistenceNotifier {
} }
} }
#[cfg(any(test, feature = "allow_wallclock_use"))] #[cfg(any(test, feature = "std"))]
fn wait_timeout(&self, max_wait: Duration) -> bool { fn wait_timeout(&self, max_wait: Duration) -> bool {
let current_time = Instant::now(); let current_time = Instant::now();
loop { loop {

File diff suppressed because it is too large Load diff