-
Notifications
You must be signed in to change notification settings - Fork 132
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(census): keep track of liveness checks #1575
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,109 @@ | ||||||||||||||
use std::{ | ||||||||||||||
collections::VecDeque, | ||||||||||||||
time::{Duration, Instant}, | ||||||||||||||
}; | ||||||||||||||
|
||||||||||||||
use discv5::Enr; | ||||||||||||||
use ethportal_api::types::distance::{Distance, Metric, XorMetric}; | ||||||||||||||
use tracing::error; | ||||||||||||||
|
||||||||||||||
#[derive(Debug, Clone)] | ||||||||||||||
pub struct LivenessCheck { | ||||||||||||||
success: bool, | ||||||||||||||
#[allow(dead_code)] | ||||||||||||||
timestamp: Instant, | ||||||||||||||
} | ||||||||||||||
|
||||||||||||||
#[allow(dead_code)] | ||||||||||||||
#[derive(Debug, Clone)] | ||||||||||||||
pub struct OfferEvent { | ||||||||||||||
success: bool, | ||||||||||||||
timestamp: Instant, | ||||||||||||||
content_value_size: usize, | ||||||||||||||
duration: Duration, | ||||||||||||||
} | ||||||||||||||
|
||||||||||||||
#[derive(Debug)] | ||||||||||||||
/// Stores information about peer and its most recent interactions. | ||||||||||||||
pub struct Peer { | ||||||||||||||
enr: Enr, | ||||||||||||||
radius: Distance, | ||||||||||||||
/// Liveness checks, ordered from most recent (index `0`), to the earliest. | ||||||||||||||
/// | ||||||||||||||
/// Contains at most [Self::MAX_LIVENESS_CHECKS] entries. | ||||||||||||||
liveness_checks: VecDeque<LivenessCheck>, | ||||||||||||||
} | ||||||||||||||
|
||||||||||||||
impl Peer { | ||||||||||||||
/// The maximum number of liveness checks that we store. Value chosen arbitrarily. | ||||||||||||||
const MAX_LIVENESS_CHECKS: usize = 10; | ||||||||||||||
|
||||||||||||||
pub fn new(enr: Enr) -> Self { | ||||||||||||||
Self { | ||||||||||||||
enr, | ||||||||||||||
radius: Distance::ZERO, | ||||||||||||||
liveness_checks: VecDeque::with_capacity(Self::MAX_LIVENESS_CHECKS + 1), | ||||||||||||||
} | ||||||||||||||
} | ||||||||||||||
|
||||||||||||||
pub fn enr(&self) -> Enr { | ||||||||||||||
self.enr.clone() | ||||||||||||||
} | ||||||||||||||
|
||||||||||||||
/// Returns true if latest liveness check was successful and content is within radius. | ||||||||||||||
pub fn is_interested_in_content(&self, content_id: &[u8; 32]) -> bool { | ||||||||||||||
// check that most recent liveness check was successful | ||||||||||||||
if !self | ||||||||||||||
.liveness_checks | ||||||||||||||
.front() | ||||||||||||||
.is_some_and(|liveness_check| liveness_check.success) | ||||||||||||||
{ | ||||||||||||||
return false; | ||||||||||||||
} | ||||||||||||||
|
||||||||||||||
let distance = XorMetric::distance(&self.enr.node_id().raw(), content_id); | ||||||||||||||
distance <= self.radius | ||||||||||||||
} | ||||||||||||||
|
||||||||||||||
/// Returns true if all latest [Self::MAX_LIVENESS_CHECKS] liveness checks failed. | ||||||||||||||
pub fn is_obsolete(&self) -> bool { | ||||||||||||||
if self.liveness_checks.len() < Self::MAX_LIVENESS_CHECKS { | ||||||||||||||
return false; | ||||||||||||||
} | ||||||||||||||
self.liveness_checks | ||||||||||||||
.iter() | ||||||||||||||
.all(|liveness_check| !liveness_check.success) | ||||||||||||||
} | ||||||||||||||
|
||||||||||||||
pub fn record_successful_liveness_check(&mut self, enr: &Enr, radius: Distance) { | ||||||||||||||
if self.enr.seq() > enr.seq() { | ||||||||||||||
error!( | ||||||||||||||
"successful_liveness_check: received outdated enr: {enr} (existing enr: {})", | ||||||||||||||
self.enr.seq() | ||||||||||||||
); | ||||||||||||||
} else { | ||||||||||||||
self.enr = enr.clone(); | ||||||||||||||
} | ||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
it probably doesn't matter, but wouldn't we only need to do the clone if a updated enr was given, which should be fairly infrequent so we might as well avoid the clone There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I changed function signature so it accepts |
||||||||||||||
self.radius = radius; | ||||||||||||||
self.liveness_checks.push_front(LivenessCheck { | ||||||||||||||
success: true, | ||||||||||||||
timestamp: Instant::now(), | ||||||||||||||
}); | ||||||||||||||
self.purge(); | ||||||||||||||
} | ||||||||||||||
|
||||||||||||||
pub fn record_failed_liveness_check(&mut self) { | ||||||||||||||
self.liveness_checks.push_front(LivenessCheck { | ||||||||||||||
success: false, | ||||||||||||||
timestamp: Instant::now(), | ||||||||||||||
}); | ||||||||||||||
self.purge(); | ||||||||||||||
} | ||||||||||||||
|
||||||||||||||
/// Removes oldest liveness checks and offer events, if we exceeded capacity. | ||||||||||||||
fn purge(&mut self) { | ||||||||||||||
if self.liveness_checks.len() > Self::MAX_LIVENESS_CHECKS { | ||||||||||||||
self.liveness_checks.drain(Self::MAX_LIVENESS_CHECKS..); | ||||||||||||||
} | ||||||||||||||
} | ||||||||||||||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am assuming the possibility that
new_peers
can be negative is a feature to display we lost peers? Because isn't there a case whereending_peers
can be less thenstarting_peers
i.e. if more peers were removed then added?This doesn't really look like an issue, just wanted to point it out.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was thinking about it and concluded that it shouldn't happen. Unless there is some weird race-condition and/or Census is performing very badly.
But, you are right, it's technically possible. It's also possible that we change logic in the future and forget to update and this would panic (or difference no longer means that these are added).
So I updated the code to not panic and changed the message.