hopr_transport_network/
config.rs1use serde::{Deserialize, Serialize};
2use serde_with::{serde_as, DurationSeconds};
3use smart_default::SmartDefault;
4use std::time::Duration;
5use validator::Validate;
6
7pub 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(100);
19
20#[serde_as]
22#[derive(Debug, Clone, Serialize, Deserialize, SmartDefault, PartialEq)]
23#[serde(deny_unknown_fields)]
24pub struct NetworkConfig {
25 #[serde_as(as = "DurationSeconds<u64>")]
27 #[serde(default = "duration_1_s")]
28 #[default(duration_1_s())]
29 pub min_delay: Duration,
30
31 #[serde_as(as = "DurationSeconds<u64>")]
33 #[serde(default = "duration_5_min")]
34 #[default(duration_5_min())]
35 pub max_delay: Duration,
36
37 #[serde(default = "quality_bad_threshold")]
38 #[default(quality_bad_threshold())]
39 pub quality_bad_threshold: f64,
40
41 #[serde(default = "quality_offline_threshold")]
42 #[default(quality_offline_threshold())]
43 pub quality_offline_threshold: f64,
44
45 #[serde(default = "node_score_auto_path_threshold")]
46 #[default(node_score_auto_path_threshold())]
47 pub node_score_auto_path_threshold: f64,
48
49 #[serde(default = "max_first_hop_latency_threshold")]
50 #[default(max_first_hop_latency_threshold())]
51 pub max_first_hop_latency_threshold: Option<Duration>,
52
53 #[serde(default = "quality_step")]
54 #[default(quality_step())]
55 pub quality_step: f64,
56
57 #[serde(default = "quality_average_window_size")]
58 #[default(quality_average_window_size())]
59 pub quality_avg_window_size: u32,
60
61 #[serde_as(as = "DurationSeconds<u64>")]
62 #[serde(default = "duration_2_min")]
63 #[default(duration_2_min())]
64 pub ignore_timeframe: Duration,
65
66 #[serde(default = "backoff_exponent")]
67 #[default(backoff_exponent())]
68 pub backoff_exponent: f64,
69
70 #[serde(default = "backoff_min")]
71 #[default(backoff_min())]
72 pub backoff_min: f64,
73
74 #[serde(default = "backoff_max")]
75 #[default(backoff_max())]
76 pub backoff_max: f64,
77}
78
79impl Validate for NetworkConfig {
80 fn validate(&self) -> std::result::Result<(), validator::ValidationErrors> {
81 let mut errors = validator::ValidationErrors::new();
82
83 if self.min_delay >= self.max_delay {
84 errors.add(
85 "min_delay and max_delay",
86 validator::ValidationError::new("min_delay must be less than max_delay"),
87 );
88 }
89
90 if !(0.0..=1.0).contains(&self.quality_bad_threshold) {
92 errors.add(
93 "quality_bad_threshold",
94 validator::ValidationError::new("quality_bad_threshold must be between 0 and 1"),
95 );
96 }
97
98 if !(0.0..=1.0).contains(&self.node_score_auto_path_threshold) {
99 errors.add(
100 "node_score_auto_path_threshold",
101 validator::ValidationError::new("node_score_auto_path_threshold must be between 0 and 1"),
102 );
103 }
104
105 if !(0.0..=1.0).contains(&self.quality_offline_threshold) {
107 errors.add(
108 "quality_offline_threshold",
109 validator::ValidationError::new("quality_offline_threshold must be between 0 and 1"),
110 );
111 }
112
113 if self.quality_bad_threshold < self.quality_offline_threshold {
114 errors.add(
115 "quality_bad_threshold and quality_offline_threshold",
116 validator::ValidationError::new("quality_bad_threshold must be greater than quality_offline_threshold"),
117 );
118 }
119
120 if !(0.0..=1.0).contains(&self.quality_step) {
122 errors.add(
123 "quality_step",
124 validator::ValidationError::new("quality_step must be between 0 and 1"),
125 );
126 }
127
128 if self.quality_avg_window_size < 1 {
130 errors.add(
131 "quality_avg_window_size",
132 validator::ValidationError::new("quality_avg_window_size must be greater than 0"),
133 );
134 }
135
136 if self.backoff_min >= self.backoff_max {
137 errors.add(
138 "backoff_min and backoff_max",
139 validator::ValidationError::new("backoff_min must be less than backoff_max"),
140 );
141 }
142
143 if errors.is_empty() {
144 Ok(())
145 } else {
146 Err(errors)
147 }
148 }
149}
150
151#[inline]
152fn duration_1_s() -> Duration {
153 Duration::from_secs(1)
154}
155
156#[inline]
157fn duration_5_min() -> Duration {
158 Duration::from_secs(300)
159}
160
161#[inline]
162fn quality_bad_threshold() -> f64 {
163 DEFAULT_NETWORK_BAD_QUALITY_THRESHOLD
164}
165
166#[inline]
167fn quality_offline_threshold() -> f64 {
168 DEFAULT_NETWORK_OFFLINE_QUALITY_THRESHOLD
169}
170
171#[inline]
172fn node_score_auto_path_threshold() -> f64 {
173 DEFAULT_AUTO_PATH_QUALITY_THRESHOLD
174}
175
176#[inline]
177fn max_first_hop_latency_threshold() -> Option<Duration> {
178 Some(DEFAULT_MAX_FIRST_HOP_LATENCY_THRESHOLD)
179}
180
181#[inline]
182fn quality_step() -> f64 {
183 DEFAULT_NETWORK_QUALITY_STEP
184}
185
186#[inline]
187fn quality_average_window_size() -> u32 {
188 DEFAULT_NETWORK_QUALITY_AVERAGE_WINDOW_SIZE
189}
190
191#[inline]
192fn duration_2_min() -> Duration {
193 Duration::from_secs(2 * 60)
194}
195
196#[inline]
197fn backoff_exponent() -> f64 {
198 DEFAULT_NETWORK_BACKOFF_EXPONENT
199}
200
201#[inline]
202fn backoff_min() -> f64 {
203 DEFAULT_NETWORK_BACKOFF_MIN
204}
205
206#[inline]
207fn backoff_max() -> f64 {
208 duration_5_min().as_millis() as f64 / duration_1_s().as_millis() as f64
209}