Skip to content

Commit db42038

Browse files
committed
report peers below score threshold
1 parent f203c3d commit db42038

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`]
@@ -2139,7 +2141,9 @@ where
21392141
let mesh_outbound_min = self.config.mesh_outbound_min_for_topic(topic_hash);
21402142

21412143
// drop all peers with negative score, without PX
2144+
// report peers below the score report threshold.
21422145
let mut removed_peers = 0;
2146+
let mut peers_to_report = vec![];
21432147
peers.retain(|peer_id| {
21442148
let peer_score = scores.get(peer_id).map(|r| r.score).unwrap_or_default();
21452149
// Record the score per mesh
@@ -2148,6 +2152,12 @@ where
21482152
metrics.observe_mesh_peers_score(topic_hash, peer_score);
21492153
}
21502154

2155+
if let Some(threshold) = self.config.score_report_threshold() {
2156+
if peer_score < threshold {
2157+
peers_to_report.push(*peer_id);
2158+
}
2159+
}
2160+
21512161
if peer_score < 0.0 {
21522162
tracing::debug!(
21532163
peer=%peer_id,
@@ -2166,6 +2176,13 @@ where
21662176
true
21672177
});
21682178

2179+
if !peers_to_report.is_empty() {
2180+
self.events
2181+
.push_back(ToSwarm::GenerateEvent(Event::LowScorePeers {
2182+
peer_ids: peers_to_report,
2183+
}));
2184+
}
2185+
21692186
#[cfg(feature = "metrics")]
21702187
if let Some(m) = self.metrics.as_mut() {
21712188
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
@@ -132,6 +132,7 @@ pub struct Config {
132132
connection_handler_forward_duration: Duration,
133133
idontwant_message_size_threshold: usize,
134134
idontwant_on_publish: bool,
135+
score_report_threshold: Option<f64>,
135136
topic_configuration: TopicConfigs,
136137
}
137138

@@ -476,6 +477,12 @@ impl Config {
476477
pub fn idontwant_on_publish(&self) -> bool {
477478
self.idontwant_on_publish
478479
}
480+
481+
/// Score threshold below which peers should be reported. If set to None, no peer reporting
482+
/// based on score will occur. Default is None.
483+
pub fn score_report_threshold(&self) -> Option<f64> {
484+
self.score_report_threshold
485+
}
479486
}
480487

481488
impl Default for Config {
@@ -545,6 +552,7 @@ impl Default for ConfigBuilder {
545552
connection_handler_forward_duration: Duration::from_secs(1),
546553
idontwant_message_size_threshold: 1000,
547554
idontwant_on_publish: false,
555+
score_report_threshold: None,
548556
topic_configuration: TopicConfigs::default(),
549557
},
550558
invalid_protocol: false,
@@ -1040,6 +1048,14 @@ impl ConfigBuilder {
10401048
self
10411049
}
10421050

1051+
/// Sets the score threshold below which peers should be reported.
1052+
/// When set, the behaviour will report peers whose score falls below this threshold.
1053+
/// Default is None (no reporting).
1054+
pub fn score_report_threshold(&mut self, threshold: f64) -> &mut Self {
1055+
self.config.score_report_threshold = Some(threshold);
1056+
self
1057+
}
1058+
10431059
/// The topic configuration sets mesh parameter sizes for a given topic. Notes on default
10441060
/// below.
10451061
///

0 commit comments

Comments
 (0)