hopr_transport_network/
config.rs1use std::time::Duration;
2
3use serde::{Deserialize, Serialize};
4use serde_with::{DurationSeconds, serde_as};
5use smart_default::SmartDefault;
6use validator::Validate;
7
8pub const DEFAULT_NETWORK_OFFLINE_QUALITY_THRESHOLD: f64 = 0.0;
11pub const DEFAULT_NETWORK_BAD_QUALITY_THRESHOLD: f64 = 0.1;
12pub const DEFAULT_NETWORK_QUALITY_STEP: f64 = 0.1;
13pub const DEFAULT_NETWORK_QUALITY_AVERAGE_WINDOW_SIZE: u32 = 25;
14pub const DEFAULT_NETWORK_BACKOFF_EXPONENT: f64 = 1.5;
15pub const DEFAULT_NETWORK_BACKOFF_MIN: f64 = 2.0;
16
17pub const DEFAULT_AUTO_PATH_QUALITY_THRESHOLD: f64 = 0.95;
18
19pub const DEFAULT_MAX_FIRST_HOP_LATENCY_THRESHOLD: Duration = Duration::from_millis(250);
20
21#[serde_as]
23#[derive(Debug, Clone, Serialize, Deserialize, SmartDefault, PartialEq)]
24#[serde(deny_unknown_fields)]
25pub struct NetworkConfig {
26 #[serde_as(as = "DurationSeconds<u64>")]
28 #[serde(default = "duration_1_s")]
29 #[default(duration_1_s())]
30 pub min_delay: Duration,
31
32 #[serde_as(as = "DurationSeconds<u64>")]
34 #[serde(default = "duration_5_min")]
35 #[default(duration_5_min())]
36 pub max_delay: Duration,
37
38 #[serde(default = "quality_bad_threshold")]
39 #[default(quality_bad_threshold())]
40 pub quality_bad_threshold: f64,
41
42 #[serde(default = "quality_offline_threshold")]
43 #[default(quality_offline_threshold())]
44 pub quality_offline_threshold: f64,
45
46 #[serde(default = "node_score_auto_path_threshold")]
47 #[default(node_score_auto_path_threshold())]
48 pub node_score_auto_path_threshold: f64,
49
50 #[serde(default = "max_first_hop_latency_threshold")]
51 #[default(max_first_hop_latency_threshold())]
52 pub max_first_hop_latency_threshold: Option<Duration>,
53
54 #[serde(default = "quality_step")]
55 #[default(quality_step())]
56 pub quality_step: f64,
57
58 #[serde(default = "quality_average_window_size")]
59 #[default(quality_average_window_size())]
60 pub quality_avg_window_size: u32,
61
62 #[serde_as(as = "DurationSeconds<u64>")]
63 #[serde(default = "duration_2_min")]
64 #[default(duration_2_min())]
65 pub ignore_timeframe: Duration,
66
67 #[serde(default = "backoff_exponent")]
68 #[default(backoff_exponent())]
69 pub backoff_exponent: f64,
70
71 #[serde(default = "backoff_min")]
72 #[default(backoff_min())]
73 pub backoff_min: f64,
74
75 #[serde(default = "backoff_max")]
76 #[default(backoff_max())]
77 pub backoff_max: f64,
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 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 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 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 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 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}