Skip to main content

hopr_ct_full_network/
priority.rs

1use crate::ProberConfig;
2
3/// Maximum staleness (in seconds) used to cap the staleness factor.
4const MAX_STALENESS_SECS: f64 = 300.0;
5
6/// Computes the probing priority for an immediate neighbor edge.
7///
8/// Higher values mean the peer should be probed sooner. Combines:
9/// - **Staleness**: time since the edge was last measured (capped at [`MAX_STALENESS_SECS`])
10/// - **Inverse quality**: `1.0 - score`, so worse edges get higher priority
11/// - **Base**: ensures even well-measured, recently-probed peers get some chance
12///
13/// Peers with no edge observations receive maximum priority.
14pub(crate) fn immediate_probe_priority(
15    score: f64,
16    last_update: std::time::Duration,
17    now: std::time::Duration,
18    cfg: &ProberConfig,
19) -> f64 {
20    let staleness_secs = if last_update.is_zero() {
21        MAX_STALENESS_SECS
22    } else {
23        now.saturating_sub(last_update).as_secs_f64().min(MAX_STALENESS_SECS)
24    };
25    let normalized_staleness = staleness_secs / MAX_STALENESS_SECS;
26    let inverse_quality = 1.0 - score.clamp(0.0, 1.0);
27
28    cfg.staleness_weight * normalized_staleness + cfg.quality_weight * inverse_quality + cfg.base_priority
29}
30
31#[cfg(test)]
32mod tests {
33    use super::*;
34
35    #[test]
36    fn maximal_for_unobserved_peers() {
37        let cfg = ProberConfig::default();
38        let now = std::time::Duration::from_secs(1000);
39
40        let priority = immediate_probe_priority(0.0, std::time::Duration::ZERO, now, &cfg);
41        let max_priority = cfg.staleness_weight + cfg.quality_weight + cfg.base_priority;
42
43        assert!(
44            (priority - max_priority).abs() < 1e-9,
45            "unobserved peer priority {priority} should equal max {max_priority}"
46        );
47    }
48
49    #[test]
50    fn increases_with_staleness() {
51        let cfg = ProberConfig::default();
52        let now = std::time::Duration::from_secs(10000);
53        let score = 0.5;
54
55        let recent = immediate_probe_priority(score, now - std::time::Duration::from_secs(10), now, &cfg);
56        let stale = immediate_probe_priority(score, now - std::time::Duration::from_secs(3000), now, &cfg);
57
58        assert!(
59            stale > recent,
60            "staler peer ({stale}) should have higher priority than recently probed ({recent})"
61        );
62    }
63
64    #[test]
65    fn increases_with_lower_score() {
66        let cfg = ProberConfig::default();
67        let now = std::time::Duration::from_secs(1000);
68        let last_update = now - std::time::Duration::from_secs(100);
69
70        let good = immediate_probe_priority(0.9, last_update, now, &cfg);
71        let bad = immediate_probe_priority(0.1, last_update, now, &cfg);
72
73        assert!(
74            bad > good,
75            "low-score peer ({bad}) should have higher priority than high-score ({good})"
76        );
77    }
78}