Skip to content

Commit 613b681

Browse files
committed
report peers below score threshold
1 parent eb6faf0 commit 613b681

File tree

3 files changed

+85
-0
lines changed

3 files changed

+85
-0
lines changed

protocols/gossipsub/src/behaviour.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,8 @@ pub enum Event {
164164
/// The types and amounts of failed messages that are occurring for this peer.
165165
failed_messages: FailedMessages,
166166
},
167+
/// A Peer is below the score threshold.
168+
LowScorePeers { peer_ids: Vec<PeerId> },
167169
}
168170

169171
/// A data structure for storing configuration for publishing messages. See [`MessageAuthenticity`]
@@ -2152,7 +2154,9 @@ where
21522154
let mesh_outbound_min = self.config.mesh_outbound_min_for_topic(topic_hash);
21532155

21542156
// drop all peers with negative score, without PX
2157+
// report peers below the score report threshold.
21552158
let mut removed_peers = 0;
2159+
let mut peers_to_report = vec![];
21562160
peers.retain(|peer_id| {
21572161
let peer_score = scores.get(peer_id).map(|r| r.score).unwrap_or_default();
21582162
// Record the score per mesh
@@ -2161,6 +2165,12 @@ where
21612165
metrics.observe_mesh_peers_score(topic_hash, peer_score);
21622166
}
21632167

2168+
if let Some(threshold) = self.config.score_report_threshold() {
2169+
if peer_score < threshold {
2170+
peers_to_report.push(*peer_id);
2171+
}
2172+
}
2173+
21642174
if peer_score < 0.0 {
21652175
tracing::debug!(
21662176
peer=%peer_id,
@@ -2179,6 +2189,13 @@ where
21792189
true
21802190
});
21812191

2192+
if !peers_to_report.is_empty() {
2193+
self.events
2194+
.push_back(ToSwarm::GenerateEvent(Event::LowScorePeers {
2195+
peer_ids: peers_to_report,
2196+
}));
2197+
}
2198+
21822199
#[cfg(feature = "metrics")]
21832200
if let Some(m) = self.metrics.as_mut() {
21842201
m.peers_removed(topic_hash, Churn::BadScore, removed_peers)

protocols/gossipsub/src/behaviour/tests.rs

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6787,3 +6787,55 @@ fn test_validation_message_size_within_topic_specific() {
67876787
_ => panic!("Unexpected event"),
67886788
}
67896789
}
6790+
6791+
#[test]
6792+
fn test_low_score_peer_is_reported() {
6793+
let score_report_threshold = -5.0;
6794+
6795+
let config = ConfigBuilder::default()
6796+
.score_report_threshold(score_report_threshold)
6797+
.build()
6798+
.expect("valid config");
6799+
6800+
let (mut gs, peers, _receivers, _topics) = inject_nodes1()
6801+
.peer_no(3)
6802+
.topics(vec!["test".into()])
6803+
.to_subscribe(true)
6804+
.gs_config(config)
6805+
.scoring(Some((
6806+
PeerScoreParams::default(),
6807+
PeerScoreThresholds::default(),
6808+
)))
6809+
.create_network();
6810+
6811+
// Reduce the score of the first peer below the threshold
6812+
gs.as_peer_score_mut().add_penalty(&peers[0], 10);
6813+
6814+
// Reduce the score of the second peer below the threshold
6815+
gs.as_peer_score_mut().add_penalty(&peers[1], 8);
6816+
6817+
// Verify initial scores are below threshold
6818+
assert!(gs.as_peer_score_mut().score_report(&peers[0]).score < score_report_threshold);
6819+
assert!(gs.as_peer_score_mut().score_report(&peers[1]).score < score_report_threshold);
6820+
assert!(gs.as_peer_score_mut().score_report(&peers[2]).score >= score_report_threshold);
6821+
6822+
// Trigger a heartbeat which should generate the LowScorePeers event
6823+
gs.heartbeat();
6824+
6825+
// Check for the LowScorePeers event
6826+
let low_score_event = gs
6827+
.events
6828+
.iter()
6829+
.find(|event| matches!(event, ToSwarm::GenerateEvent(Event::LowScorePeers { .. })))
6830+
.unwrap();
6831+
6832+
match low_score_event {
6833+
ToSwarm::GenerateEvent(Event::LowScorePeers { peer_ids }) => {
6834+
assert_eq!(peer_ids.len(), 2);
6835+
assert!(peer_ids.contains(&peers[0]));
6836+
assert!(peer_ids.contains(&peers[1]));
6837+
assert!(!peer_ids.contains(&peers[2]));
6838+
}
6839+
_ => unreachable!(),
6840+
}
6841+
}

protocols/gossipsub/src/config.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,7 @@ pub struct Config {
133133
connection_handler_forward_duration: Duration,
134134
idontwant_message_size_threshold: usize,
135135
idontwant_on_publish: bool,
136+
score_report_threshold: Option<f64>,
136137
topic_configuration: TopicConfigs,
137138
}
138139

@@ -482,6 +483,12 @@ impl Config {
482483
pub fn idontwant_on_publish(&self) -> bool {
483484
self.idontwant_on_publish
484485
}
486+
487+
/// Score threshold below which peers should be reported. If set to None, no peer reporting
488+
/// based on score will occur. Default is None.
489+
pub fn score_report_threshold(&self) -> Option<f64> {
490+
self.score_report_threshold
491+
}
485492
}
486493

487494
impl Default for Config {
@@ -552,6 +559,7 @@ impl Default for ConfigBuilder {
552559
connection_handler_forward_duration: Duration::from_secs(1),
553560
idontwant_message_size_threshold: 1000,
554561
idontwant_on_publish: false,
562+
score_report_threshold: None,
555563
topic_configuration: TopicConfigs::default(),
556564
},
557565
invalid_protocol: false,
@@ -1056,6 +1064,14 @@ impl ConfigBuilder {
10561064
self
10571065
}
10581066

1067+
/// Sets the score threshold below which peers should be reported.
1068+
/// When set, the behaviour will report peers whose score falls below this threshold.
1069+
/// Default is None (no reporting).
1070+
pub fn score_report_threshold(&mut self, threshold: f64) -> &mut Self {
1071+
self.config.score_report_threshold = Some(threshold);
1072+
self
1073+
}
1074+
10591075
/// The topic configuration sets mesh parameter sizes for a given topic. Notes on default
10601076
/// below.
10611077
///

0 commit comments

Comments
 (0)