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