hopr_transport_network/
config.rs

1use std::time::Duration;
2
3use serde::{Deserialize, Serialize};
4use smart_default::SmartDefault;
5use validator::Validate;
6
7/// Network quality threshold since when a node is considered
8/// available enough to be used
9pub const DEFAULT_NETWORK_OFFLINE_QUALITY_THRESHOLD: f64 = 0.0;
10pub const DEFAULT_NETWORK_BAD_QUALITY_THRESHOLD: f64 = 0.1;
11pub const DEFAULT_NETWORK_QUALITY_STEP: f64 = 0.1;
12pub const DEFAULT_NETWORK_QUALITY_AVERAGE_WINDOW_SIZE: u32 = 25;
13pub const DEFAULT_NETWORK_BACKOFF_EXPONENT: f64 = 1.5;
14pub const DEFAULT_NETWORK_BACKOFF_MIN: f64 = 2.0;
15
16pub const DEFAULT_AUTO_PATH_QUALITY_THRESHOLD: f64 = 0.95;
17
18pub const DEFAULT_MAX_FIRST_HOP_LATENCY_THRESHOLD: Duration = Duration::from_millis(250);
19
20pub const DEFAULT_CANNOT_DIAL_PENALTY: Duration = Duration::from_secs(60 * 60); // 1 hour
21
22/// Configuration for the [`crate::network::Network`] object
23#[derive(Debug, Clone, Copy, Serialize, Deserialize, SmartDefault, PartialEq)]
24#[serde(deny_unknown_fields)]
25pub struct NetworkConfig {
26    /// Backoff will multiply minimum delay, it will be half the actual minimum value
27    #[serde(default = "duration_1_s", with = "humantime_serde")]
28    #[default(duration_1_s())]
29    pub min_delay: Duration,
30
31    /// Maximum delay
32    #[serde(default = "duration_5_min", with = "humantime_serde")]
33    #[default(duration_5_min())]
34    pub max_delay: Duration,
35
36    #[serde(default = "quality_bad_threshold")]
37    #[default(quality_bad_threshold())]
38    pub quality_bad_threshold: f64,
39
40    #[serde(default = "quality_offline_threshold")]
41    #[default(quality_offline_threshold())]
42    pub quality_offline_threshold: f64,
43
44    #[serde(default = "node_score_auto_path_threshold")]
45    #[default(node_score_auto_path_threshold())]
46    pub node_score_auto_path_threshold: f64,
47
48    #[serde(default = "max_first_hop_latency_threshold", with = "humantime_serde")]
49    #[default(max_first_hop_latency_threshold())]
50    pub max_first_hop_latency_threshold: Option<Duration>,
51
52    #[serde(default = "quality_step")]
53    #[default(quality_step())]
54    pub quality_step: f64,
55
56    #[serde(default = "quality_average_window_size")]
57    #[default(quality_average_window_size())]
58    pub quality_avg_window_size: u32,
59
60    #[serde(default = "duration_2_min", with = "humantime_serde")]
61    #[default(duration_2_min())]
62    pub ignore_timeframe: Duration,
63
64    #[serde(default = "backoff_exponent")]
65    #[default(backoff_exponent())]
66    pub backoff_exponent: f64,
67
68    #[serde(default = "backoff_min")]
69    #[default(backoff_min())]
70    pub backoff_min: f64,
71
72    #[serde(default = "backoff_max")]
73    #[default(backoff_max())]
74    pub backoff_max: f64,
75
76    #[serde(default)]
77    pub allow_private_addresses_in_store: bool,
78}
79
80impl Validate for NetworkConfig {
81    fn validate(&self) -> std::result::Result<(), validator::ValidationErrors> {
82        let mut errors = validator::ValidationErrors::new();
83
84        if self.min_delay >= self.max_delay {
85            errors.add(
86                "min_delay and max_delay",
87                validator::ValidationError::new("min_delay must be less than max_delay"),
88            );
89        }
90
91        // #[validate(range(min = 0.0, max = 1.0))]
92        if !(0.0..=1.0).contains(&self.quality_bad_threshold) {
93            errors.add(
94                "quality_bad_threshold",
95                validator::ValidationError::new("quality_bad_threshold must be between 0 and 1"),
96            );
97        }
98
99        if !(0.0..=1.0).contains(&self.node_score_auto_path_threshold) {
100            errors.add(
101                "node_score_auto_path_threshold",
102                validator::ValidationError::new("node_score_auto_path_threshold must be between 0 and 1"),
103            );
104        }
105
106        // #[validate(range(min = 0.0, max = 1.0))]
107        if !(0.0..=1.0).contains(&self.quality_offline_threshold) {
108            errors.add(
109                "quality_offline_threshold",
110                validator::ValidationError::new("quality_offline_threshold must be between 0 and 1"),
111            );
112        }
113
114        if self.quality_bad_threshold < self.quality_offline_threshold {
115            errors.add(
116                "quality_bad_threshold and quality_offline_threshold",
117                validator::ValidationError::new("quality_bad_threshold must be greater than quality_offline_threshold"),
118            );
119        }
120
121        // #[validate(range(min = 0.0, max = 1.0))]
122        if !(0.0..=1.0).contains(&self.quality_step) {
123            errors.add(
124                "quality_step",
125                validator::ValidationError::new("quality_step must be between 0 and 1"),
126            );
127        }
128
129        // #[validate(range(min = 1_u32))]
130        if self.quality_avg_window_size < 1 {
131            errors.add(
132                "quality_avg_window_size",
133                validator::ValidationError::new("quality_avg_window_size must be greater than 0"),
134            );
135        }
136
137        // #[validate(range(min = 0.0))]
138        if self.backoff_min < 0.0 {
139            errors.add(
140                "backoff_min",
141                validator::ValidationError::new("backoff_min must be greater or equal 0"),
142            );
143        }
144
145        if self.backoff_min >= self.backoff_max {
146            errors.add(
147                "backoff_min and backoff_max",
148                validator::ValidationError::new("backoff_min must be less than backoff_max"),
149            );
150        }
151
152        if errors.is_empty() { Ok(()) } else { Err(errors) }
153    }
154}
155
156#[inline]
157fn duration_1_s() -> Duration {
158    Duration::from_secs(1)
159}
160
161#[inline]
162fn duration_5_min() -> Duration {
163    Duration::from_secs(300)
164}
165
166#[inline]
167fn quality_bad_threshold() -> f64 {
168    DEFAULT_NETWORK_BAD_QUALITY_THRESHOLD
169}
170
171#[inline]
172fn quality_offline_threshold() -> f64 {
173    DEFAULT_NETWORK_OFFLINE_QUALITY_THRESHOLD
174}
175
176#[inline]
177fn node_score_auto_path_threshold() -> f64 {
178    DEFAULT_AUTO_PATH_QUALITY_THRESHOLD
179}
180
181#[inline]
182fn max_first_hop_latency_threshold() -> Option<Duration> {
183    Some(DEFAULT_MAX_FIRST_HOP_LATENCY_THRESHOLD)
184}
185
186#[inline]
187fn quality_step() -> f64 {
188    DEFAULT_NETWORK_QUALITY_STEP
189}
190
191#[inline]
192fn quality_average_window_size() -> u32 {
193    DEFAULT_NETWORK_QUALITY_AVERAGE_WINDOW_SIZE
194}
195
196#[inline]
197fn duration_2_min() -> Duration {
198    Duration::from_secs(2 * 60)
199}
200
201#[inline]
202fn backoff_exponent() -> f64 {
203    DEFAULT_NETWORK_BACKOFF_EXPONENT
204}
205
206#[inline]
207fn backoff_min() -> f64 {
208    DEFAULT_NETWORK_BACKOFF_MIN
209}
210
211#[inline]
212fn backoff_max() -> f64 {
213    duration_5_min().as_millis() as f64 / duration_1_s().as_millis() as f64
214}