params.rs
1 //! Implements a usable view of Tor network parameters. 2 //! 3 //! The Tor consensus document contains a number of 'network 4 //! parameters', which are integer-valued items voted on by the 5 //! directory authorities. They are used to tune the behavior of 6 //! numerous aspects of the network. 7 //! A set of Tor network parameters 8 //! 9 //! The Tor consensus document contains a number of 'network 10 //! parameters', which are integer-valued items voted on by the 11 //! directory authorities. These parameters are used to tune the 12 //! behavior of numerous aspects of the network. 13 //! 14 //! This type differs from 15 //! [`NetParams`](tor_netdoc::doc::netstatus::NetParams) in that it 16 //! only exposes a set of parameters recognized by arti. In return 17 //! for this restriction, it makes sure that the values it gives are 18 //! in range, and provides default values for any parameters that are 19 //! missing. 20 21 use tor_units::{ 22 BoundedInt32, IntegerDays, IntegerMilliseconds, IntegerMinutes, IntegerSeconds, Percentage, 23 SendMeVersion, 24 }; 25 26 /// Upper limit for channel padding timeouts 27 /// 28 /// This is just a safety catch which might help prevent integer overflow, 29 /// and also might prevent a client getting permantently stuck in a state 30 /// where it ought to send padding but never does. 31 /// 32 /// The actual value is stolen from C Tor as per 33 /// <https://gitlab.torproject.org/tpo/core/arti/-/merge_requests/586#note_2813638> 34 /// pending an update to the specifications 35 /// <https://gitlab.torproject.org/tpo/core/torspec/-/issues/120> 36 pub const CHANNEL_PADDING_TIMEOUT_UPPER_BOUND: i32 = 60_000; 37 38 /// An object that can be constructed from an i32, with saturating semantics. 39 pub trait FromInt32Saturating { 40 /// Construct an instance of this object from `val`. 41 /// 42 /// If `val` is too low, treat it as the lowest value that would be 43 /// valid. If `val` is too high, treat it as the highest value that 44 /// would be valid. 45 fn from_saturating(val: i32) -> Self; 46 } 47 48 impl FromInt32Saturating for i32 { 49 fn from_saturating(val: i32) -> Self { 50 val 51 } 52 } 53 impl<const L: i32, const H: i32> FromInt32Saturating for BoundedInt32<L, H> { 54 fn from_saturating(val: i32) -> Self { 55 Self::saturating_new(val) 56 } 57 } 58 impl<T: Copy + Into<f64> + FromInt32Saturating> FromInt32Saturating for Percentage<T> { 59 fn from_saturating(val: i32) -> Self { 60 Self::new(T::from_saturating(val)) 61 } 62 } 63 impl<T: FromInt32Saturating + TryInto<u64>> FromInt32Saturating for IntegerMilliseconds<T> { 64 fn from_saturating(val: i32) -> Self { 65 Self::new(T::from_saturating(val)) 66 } 67 } 68 impl<T: FromInt32Saturating + TryInto<u64>> FromInt32Saturating for IntegerSeconds<T> { 69 fn from_saturating(val: i32) -> Self { 70 Self::new(T::from_saturating(val)) 71 } 72 } 73 impl<T: FromInt32Saturating + TryInto<u64>> FromInt32Saturating for IntegerMinutes<T> { 74 fn from_saturating(val: i32) -> Self { 75 Self::new(T::from_saturating(val)) 76 } 77 } 78 impl<T: FromInt32Saturating + TryInto<u64>> FromInt32Saturating for IntegerDays<T> { 79 fn from_saturating(val: i32) -> Self { 80 Self::new(T::from_saturating(val)) 81 } 82 } 83 impl FromInt32Saturating for SendMeVersion { 84 fn from_saturating(val: i32) -> Self { 85 Self::new(val.clamp(0, 255) as u8) 86 } 87 } 88 89 /// A macro to help us declare the net parameters object. It lets us 90 /// put the information about each parameter in just one place, even 91 /// though it will later get split between the struct declaration, the 92 /// Default implementation, and the implementation of 93 /// `saturating_update_override`. 94 macro_rules! declare_net_parameters { 95 { 96 $(#[$s_meta:meta])* $s_v:vis struct $s_name:ident { 97 $( 98 $(#[$p_meta:meta])* $p_v:vis 99 $p_name:ident : $p_type:ty 100 = ($p_dflt:expr) from $p_string:literal 101 ),* 102 $( , )? 103 } 104 } => 105 { 106 $(#[$s_meta])* $s_v struct $s_name { 107 $( 108 $(#[$p_meta])* $p_v $p_name : $p_type 109 ),* 110 } 111 112 impl $s_name { 113 /// Try to construct an instance of with its default values. 114 /// 115 /// (This should always succeed, unless one of the default values 116 /// is out-of-bounds for the type.) 117 fn default_values() -> Result<Self, tor_units::Error> { 118 Ok(Self { 119 $( $p_name : $p_dflt.try_into()? ),* 120 }) 121 } 122 /// Replace the current value for the parameter identified in the 123 /// consensus with `key` with a new value `val`. 124 /// 125 /// Uses saturating semantics if the new value is out-of-range. 126 /// 127 /// Returns true if the key was recognized, and false otherwise. 128 fn set_saturating(&mut self, key: &str, val: i32) -> bool { 129 match key { 130 $( $p_string => self.$p_name = { 131 type T = $p_type; 132 T::from_saturating(val) 133 }, )* 134 _ => return false, 135 } 136 true 137 } 138 } 139 } 140 } 141 142 declare_net_parameters! { 143 144 /// This structure holds recognized configuration parameters. All values are type-safe, 145 /// and where applicable clamped to be within range. 146 #[derive(Clone, Debug)] 147 #[non_exhaustive] 148 pub struct NetParameters { 149 /// A weighting factor for bandwidth calculations 150 pub bw_weight_scale: BoundedInt32<1, { i32::MAX }> = (10_000) 151 from "bwweightscale", 152 /// If true, do not attempt to learn circuit-build timeouts at all. 153 pub cbt_learning_disabled: BoundedInt32<0, 1> = (0) 154 from "cbtdisabled", 155 /// Number of histograms bins to consider when estimating Xm for a 156 /// Pareto-based circuit timeout estimator. 157 pub cbt_num_xm_modes: BoundedInt32<1, 20> = (10) 158 from "cbtnummodes", 159 /// How many recent circuit success/timeout statuses do we remember 160 /// when trying to tell if our circuit timeouts are too low? 161 pub cbt_success_count: BoundedInt32<3, 1_000> = (20) 162 from "cbtrecentcount", 163 /// How many timeouts (in the last `cbt_success_count` observations) 164 /// indicates that our circuit timeouts are too low? 165 pub cbt_max_timeouts: BoundedInt32<3, 10_000> = (18) 166 from "cbtmaxtimeouts", 167 /// Smallest number of circuit build times we have to view in order to use 168 /// our Pareto-based circuit timeout estimator. 169 pub cbt_min_circs_for_estimate: BoundedInt32<1, 10_000> = (100) 170 from "cbtmincircs", 171 /// Quantile to use when determining the correct circuit timeout value 172 /// with our Pareto estimator. 173 /// 174 /// (We continue building circuits after this timeout, but only 175 /// for build-time measurement purposes.) 176 pub cbt_timeout_quantile: Percentage<BoundedInt32<10, 99>> = (80) 177 from "cbtquantile", 178 /// Quantile to use when determining when to abandon circuits completely 179 /// with our Pareto estimator. 180 pub cbt_abandon_quantile: Percentage<BoundedInt32<10, 99>> = (99) 181 from "cbtclosequantile", 182 /// Lowest permissible timeout value for Pareto timeout estimator. 183 pub cbt_min_timeout: IntegerMilliseconds<BoundedInt32<10, { i32::MAX }>> = (10) 184 from "cbtmintimeout", 185 /// Timeout value to use for our Pareto timeout estimator when we have 186 /// no initial estimate. 187 pub cbt_initial_timeout: IntegerMilliseconds<BoundedInt32<10, { i32::MAX }>> = (60_000) 188 from "cbtinitialtimeout", 189 /// When we don't have a good build-time estimate yet, how long 190 /// (in seconds) do we wait between trying to launch build-time 191 /// testing circuits through the network? 192 pub cbt_testing_delay: IntegerSeconds<BoundedInt32<1, { i32::MAX }>> = (10) 193 from "cbttestfreq", 194 /// How many circuits can be open before we will no longer 195 /// consider launching testing circuits to learn average build 196 /// times? 197 pub cbt_max_open_circuits_for_testing: BoundedInt32<0, 14> = (10) 198 from "cbtmaxopencircs", 199 200 /// The maximum cell window size? 201 pub circuit_window: BoundedInt32<100, 1000> = (1_000) 202 from "circwindow", 203 /// The decay parameter for circuit priority 204 pub circuit_priority_half_life: IntegerMilliseconds<BoundedInt32<1, { i32::MAX }>> = (30_000) 205 from "CircuitPriorityHalflifeMsec", 206 /// Whether to perform circuit extensions by Ed25519 ID 207 pub extend_by_ed25519_id: BoundedInt32<0, 1> = (0) 208 from "ExtendByEd25519ID", 209 210 /// If we have excluded so many possible guards that the 211 /// available fraction is below this threshold, we should use a different 212 /// guard sample. 213 pub guard_meaningful_restriction: Percentage<BoundedInt32<1,100>> = (20) 214 from "guard-meaningful-restriction-percent", 215 216 /// We should warn the user if they have excluded so many guards 217 /// that the available fraction is below this threshold. 218 pub guard_extreme_restriction: Percentage<BoundedInt32<1,100>> = (1) 219 from "guard-extreme-restriction-percent", 220 221 /// How long should we keep an unconfirmed guard (one we have not 222 /// contacted) before removing it from the guard sample? 223 pub guard_lifetime_unconfirmed: IntegerDays<BoundedInt32<1, 3650>> = (120) 224 from "guard-lifetime-days", 225 226 /// How long should we keep a _confirmed_ guard (one we have contacted) 227 /// before removing it from the guard sample? 228 pub guard_lifetime_confirmed: IntegerDays<BoundedInt32<1, 3650>> = (60) 229 from "guard-confirmed-min-lifetime-days", 230 231 /// If all circuits have failed for this interval, then treat the internet 232 /// as "probably down", and treat any guard failures in that interval 233 /// as unproven. 234 pub guard_internet_likely_down: IntegerSeconds<BoundedInt32<1, {i32::MAX}>> = (600) 235 from "guard-internet-likely-down-interval", 236 /// Largest number of guards that a client should try to maintain in 237 /// a sample of possible guards. 238 pub guard_max_sample_size: BoundedInt32<1, {i32::MAX}> = (60) 239 from "guard-max-sample-size", 240 /// Largest fraction of guard bandwidth on the network that a client 241 /// should try to remain in a sample of possible guards. 242 pub guard_max_sample_threshold: Percentage<BoundedInt32<1,100>> = (20) 243 from "guard-max-sample-threshold", 244 245 /// If the client ever has fewer than this many guards in their sample, 246 /// after filtering out unusable guards, they should try to add more guards 247 /// to the sample (if allowed). 248 pub guard_filtered_min_sample_size: BoundedInt32<1,{i32::MAX}> = (20) 249 from "guard-min-filtered-sample-size", 250 251 /// The number of confirmed guards that the client should treat as 252 /// "primary guards". 253 pub guard_n_primary: BoundedInt32<1,{i32::MAX}> = (3) 254 from "guard-n-primary-guards", 255 /// The number of primary guards that the client should use in parallel. 256 /// Other primary guards won't get used unless earlier ones are down. 257 pub guard_use_parallelism: BoundedInt32<1, {i32::MAX}> = (1) 258 from "guard-n-primary-guards-to-use", 259 /// The number of primary guards that the client should use in 260 /// parallel. Other primary directory guards won't get used 261 /// unless earlier ones are down. 262 pub guard_dir_use_parallelism: BoundedInt32<1, {i32::MAX}> = (3) 263 from "guard-n-primary-dir-guards-to-use", 264 265 /// When trying to confirm nonprimary guards, if a guard doesn't 266 /// answer for more than this long in seconds, treat any lower- 267 /// priority guards as possibly usable. 268 pub guard_nonprimary_connect_timeout: IntegerSeconds<BoundedInt32<1,{i32::MAX}>> = (15) 269 from "guard-nonprimary-guard-connect-timeout", 270 /// When trying to confirm nonprimary guards, if a guard doesn't 271 /// answer for more than _this_ long in seconds, treat it as down. 272 pub guard_nonprimary_idle_timeout: IntegerSeconds<BoundedInt32<1,{i32::MAX}>> = (600) 273 from "guard-nonprimary-guard-idle-timeout", 274 /// If a guard has been unlisted in the consensus for at least this 275 /// long, remove it from the consensus. 276 pub guard_remove_unlisted_after: IntegerDays<BoundedInt32<1,3650>> = (20) 277 from "guard-remove-unlisted-guards-after-days", 278 279 280 /// The minimum threshold for circuit patch construction 281 pub min_circuit_path_threshold: Percentage<BoundedInt32<25, 95>> = (60) 282 from "min_paths_for_circs_pct", 283 284 /// Channel padding, low end of random padding interval, milliseconds 285 /// 286 /// `nf_ito` stands for "netflow inactive timeout". 287 pub nf_ito_low: IntegerMilliseconds<BoundedInt32<0, CHANNEL_PADDING_TIMEOUT_UPPER_BOUND>> = (1500) 288 from "nf_ito_low", 289 /// Channel padding, high end of random padding interval, milliseconds 290 pub nf_ito_high: IntegerMilliseconds<BoundedInt32<0, CHANNEL_PADDING_TIMEOUT_UPPER_BOUND>> = (9500) 291 from "nf_ito_high", 292 /// Channel padding, low end of random padding interval (reduced padding) milliseconds 293 pub nf_ito_low_reduced: IntegerMilliseconds<BoundedInt32<0, CHANNEL_PADDING_TIMEOUT_UPPER_BOUND>> = (9000) 294 from "nf_ito_low_reduced", 295 /// Channel padding, high end of random padding interval (reduced padding) , milliseconds 296 pub nf_ito_high_reduced: IntegerMilliseconds<BoundedInt32<0, CHANNEL_PADDING_TIMEOUT_UPPER_BOUND>> = (14000) 297 from "nf_ito_high_reduced", 298 299 /// The minimum sendme version to accept. 300 pub sendme_accept_min_version: SendMeVersion = (0) 301 from "sendme_accept_min_version", 302 /// The minimum sendme version to transmit. 303 pub sendme_emit_min_version: SendMeVersion = (0) 304 from "sendme_emit_min_version", 305 306 /// How long should never-used client circuits stay available, 307 /// in the steady state? 308 pub unused_client_circ_timeout: IntegerSeconds<BoundedInt32<60, 86_400>> = (30*60) 309 from "nf_conntimeout_clients", 310 /// When we're learning circuit timeouts, how long should never-used client 311 /// circuits stay available? 312 pub unused_client_circ_timeout_while_learning_cbt: IntegerSeconds<BoundedInt32<10, 60_000>> = (3*60) 313 from "cbtlearntimeout", 314 315 /// The minimum number of SENDME acks required to estimate RTT and/or bandwidth. 316 pub cc_min_sendme_acks: BoundedInt32<2, 20> = (5) 317 from "cc_bwe_min", 318 /// The "N" parameter in N-EWMA smoothing of RTT and/or bandwidth estimation, specified as a 319 /// percentage of the number of SENDME acks in a congestion window. 320 /// 321 /// A percentage over 100% indicates smoothing with more than one congestion window's worth 322 /// of SENDMEs. 323 pub cc_ewma_n_by_sendme_acks: Percentage<BoundedInt32<1, 255>> = (50) 324 from "cc_ewma_cwnd_pct", 325 /// The maximum value of the "N" parameter in N-EWMA smoothing of RTT and/or bandwidth 326 /// estimation. 327 pub cc_ewma_n_max: BoundedInt32<2, {i32::MAX}> = (10) 328 from "cc_ewma_max", 329 /// How many cells a SENDME acks under the congestion-control regime. 330 pub cc_sendme_cell_ack_count: BoundedInt32<1, 255> = (31) 331 from "cc_sendme_inc", 332 /// How often we update our congestion window, per congestion window worth of packets. 333 /// (For example, if this is 2, we will update the window twice every window.) 334 pub cc_cwnd_inc_rate: BoundedInt32<1, 250> = (1) 335 from "cc_cwnd_inc_rate", 336 337 /// Lower bound on the number of INTRODUCE2 cells to allow per introduction 338 /// circuit before the service decides to rotate to a new introduction 339 /// circuit. 340 pub hs_introcirc_requests_min: BoundedInt32<0, {i32::MAX}> = (16384) 341 from "hs_intro_min_introduce2", 342 343 /// Upper bound on the number of INTRODUCE2 cells to allow per introduction 344 /// circuit before the service decides to rotate to a new introduction 345 /// circuit. 346 pub hs_introcirc_requests_max: BoundedInt32<0, {i32::MAX}> = (32768) 347 from "hs_intro_max_introduce2", 348 349 /// Lower bound on the lifetime of an introduction point. 350 pub hs_intro_min_lifetime: IntegerSeconds<BoundedInt32<0, {i32::MAX}>> = (18 * 60 * 60) 351 from "hs_intro_min_lifetime", 352 353 /// Upper bound on the lifetime of an introduction point. 354 pub hs_intro_max_lifetime: IntegerSeconds<BoundedInt32<0, {i32::MAX}>> = (24 * 60 * 60) 355 from "hs_intro_max_lifetime", 356 357 /// Number of "extra" introduction points that an onion service is allowed 358 /// to open based on demand. 359 pub hs_intro_num_extra_intropoints: BoundedInt32<0, 128> = (2) 360 from "hs_intro_num_extra", 361 362 /// The duration of a time period, as used in the onion service directory 363 /// protocol. 364 /// 365 /// During each "time period", each onion service gets a different blinded 366 /// ID, and the hash ring gets a new layout. 367 pub hsdir_timeperiod_length: IntegerMinutes<BoundedInt32<30, 14400>> = (1440) 368 from "hsdir_interval", 369 370 /// The number of positions at the hash ring where an onion service 371 /// descriptor should be stored. 372 pub hsdir_n_replicas: BoundedInt32<1, 16> = (2) 373 from "hsdir_n_replicas", 374 375 /// The number of HSDir instances, at each position in the hash ring, that 376 /// should be considered when downloading an onion service descriptor. 377 pub hsdir_spread_fetch: BoundedInt32<1, 128> = (3) 378 from "hsdir_spread_fetch", 379 380 /// The number of HSDir instances, at each position in the hash ring, that 381 /// should be considered when uploading an onion service descriptor. 382 pub hsdir_spread_store: BoundedInt32<1,128> = (4) 383 from "hsdir_spread_store", 384 385 /// Largest allowable v3 onion service size (in bytes). 386 pub hsdir_max_desc_size: BoundedInt32<1, {i32::MAX}> = (50_000) 387 from "HSV3MaxDescriptorSize", 388 389 /// Largest number of failures to rendezvous that an onion service should 390 /// allow for a request. 391 pub hs_service_rendezvous_failures_max: BoundedInt32<1, 10> = (2) 392 from "hs_service_max_rdv_failures", 393 394 /// If set to 1, introduction points use the INTRODUCE1 rate limiting 395 /// defense when no `DosParams` are sent. 396 /// 397 /// See <https://spec.torproject.org/param-spec.html#HiddenServiceEnableIntroDoSDefense> 398 pub hs_intro_dos_enabled: BoundedInt32<0, 1> = (0) 399 from "HiddenServiceEnableIntroDoSDefense", 400 401 /// Default _rate_ value for an introduction point to use for INTRODUCE1 rate 402 /// limiting when no `DosParams` value is sent, in messages per second. 403 /// 404 /// See 405 /// <https://spec.torproject.org/param-spec.html#HiddenServiceEnableIntroDoSBurstPerSec> 406 pub hs_intro_dos_max_burst: BoundedInt32<0, {i32::MAX}> = (200) 407 from "HiddenServiceEnableIntroDoSBurstPerSec", 408 409 /// Default _burst_ value for an introduction point to use for INTRODUCE1 rate 410 /// limiting when no `DosParams` value is sent. 411 /// 412 /// See 413 /// <https://spec.torproject.org/param-spec.html#HiddenServiceEnableIntroDoSRatePerSec> 414 pub hs_intro_dos_rate: BoundedInt32<0, {i32::MAX}> = (25) 415 from "HiddenServiceEnableIntroDoSRatePerSec", 416 417 /// The type of vanguards to use by default when building onion service circuits: 418 /// 419 /// ```text 420 /// 0: No vanguards. 421 /// 1: Lite vanguards. 422 /// 2: Full vanguards. 423 /// ``` 424 /// 425 /// See 426 /// <https://spec.torproject.org/param-spec.html#vanguards> 427 pub vanguards_enabled: BoundedInt32<0, 2> = (1) 428 from "vanguards-enabled", 429 430 /// If higher than `vanguards-enabled`, 431 /// and we are running an onion service, 432 /// we use this level for all our onion service circuits: 433 /// 434 /// ```text 435 /// 0: No vanguards. 436 /// 1: Lite vanguards. 437 /// 2: Full vanguards. 438 /// ``` 439 /// 440 /// See 441 /// <https://spec.torproject.org/param-spec.html#vanguards> 442 pub vanguards_hs_service: BoundedInt32<0, 2> = (2) 443 from "vanguards-hs-service", 444 445 /// The number of vanguards in the L2 vanguard set. 446 /// 447 /// See 448 /// <https://spec.torproject.org/param-spec.html#vanguards> 449 pub guard_hs_l2_number: BoundedInt32<1, {i32::MAX}> = (4) 450 from "guard-hs-l2-number", 451 452 /// The minimum lifetime of L2 vanguards. 453 /// 454 /// See 455 /// <https://spec.torproject.org/param-spec.html#vanguards> 456 pub guard_hs_l2_lifetime_min: IntegerSeconds<BoundedInt32<1, {i32::MAX}>> = (86400) 457 from "guard-hs-l2-lifetime-min", 458 459 /// The maximum lifetime of L2 vanguards. 460 /// 461 /// See 462 /// <https://spec.torproject.org/param-spec.html#vanguards> 463 pub guard_hs_l2_lifetime_max: IntegerSeconds<BoundedInt32<1, {i32::MAX}>> = (1036800) 464 from "guard-hs-l2-lifetime-max", 465 466 /// The number of vanguards in the L3 vanguard set. 467 /// 468 /// See 469 /// <https://spec.torproject.org/param-spec.html#vanguards> 470 pub guard_hs_l3_number: BoundedInt32<1, {i32::MAX}> = (8) 471 from "guard-hs-l3-number", 472 473 /// The minimum lifetime of L3 vanguards. 474 /// 475 /// See 476 /// <https://spec.torproject.org/param-spec.html#vanguards> 477 pub guard_hs_l3_lifetime_min: IntegerSeconds<BoundedInt32<1, {i32::MAX}>> = (3600) 478 from "guard-hs-l3-lifetime-min", 479 480 /// The maximum lifetime of L3 vanguards. 481 /// 482 /// See 483 /// <https://spec.torproject.org/param-spec.html#vanguards> 484 pub guard_hs_l3_lifetime_max: IntegerSeconds<BoundedInt32<1, {i32::MAX}>> = (172800) 485 from "guard-hs-l3-lifetime-max", 486 } 487 488 } 489 490 impl Default for NetParameters { 491 fn default() -> Self { 492 NetParameters::default_values().expect("Default parameters were out-of-bounds") 493 } 494 } 495 496 // This impl is a bit silly, but it makes the `params` method on NetDirProvider 497 // work out. 498 impl AsRef<NetParameters> for NetParameters { 499 fn as_ref(&self) -> &NetParameters { 500 self 501 } 502 } 503 504 impl NetParameters { 505 /// Construct a new NetParameters from a given list of key=value parameters. 506 /// 507 /// Unrecognized parameters are ignored. 508 pub fn from_map(p: &tor_netdoc::doc::netstatus::NetParams<i32>) -> Self { 509 let mut params = NetParameters::default(); 510 let _ = params.saturating_update(p.iter()); 511 params 512 } 513 514 /// Replace a list of parameters, using the logic of 515 /// `set_saturating`. 516 /// 517 /// Return a vector of the parameter names we didn't recognize. 518 pub(crate) fn saturating_update<'a, S>( 519 &mut self, 520 iter: impl Iterator<Item = (S, &'a i32)>, 521 ) -> Vec<S> 522 where 523 S: AsRef<str>, 524 { 525 let mut unrecognized = Vec::new(); 526 for (k, v) in iter { 527 if !self.set_saturating(k.as_ref(), *v) { 528 unrecognized.push(k); 529 } 530 } 531 unrecognized 532 } 533 } 534 535 #[cfg(test)] 536 #[allow(clippy::many_single_char_names)] 537 #[allow(clippy::unwrap_used)] 538 #[allow(clippy::cognitive_complexity)] 539 mod test { 540 // @@ begin test lint list maintained by maint/add_warning @@ 541 #![allow(clippy::bool_assert_comparison)] 542 #![allow(clippy::clone_on_copy)] 543 #![allow(clippy::dbg_macro)] 544 #![allow(clippy::mixed_attributes_style)] 545 #![allow(clippy::print_stderr)] 546 #![allow(clippy::print_stdout)] 547 #![allow(clippy::single_char_pattern)] 548 #![allow(clippy::unwrap_used)] 549 #![allow(clippy::unchecked_duration_subtraction)] 550 #![allow(clippy::useless_vec)] 551 #![allow(clippy::needless_pass_by_value)] 552 //! <!-- @@ end test lint list maintained by maint/add_warning @@ --> 553 use super::*; 554 use std::string::String; 555 556 #[test] 557 fn empty_list() { 558 let mut x = NetParameters::default(); 559 let y = Vec::<(&String, &i32)>::new(); 560 let u = x.saturating_update(y.into_iter()); 561 assert!(u.is_empty()); 562 } 563 564 #[test] 565 fn unknown_parameter() { 566 let mut x = NetParameters::default(); 567 let mut y = Vec::<(&String, &i32)>::new(); 568 let k = &String::from("This_is_not_a_real_key"); 569 let v = &456; 570 y.push((k, v)); 571 let u = x.saturating_update(y.into_iter()); 572 assert_eq!(u, vec![&String::from("This_is_not_a_real_key")]); 573 } 574 575 // #[test] 576 // fn duplicate_parameter() {} 577 578 #[test] 579 fn single_good_parameter() { 580 let mut x = NetParameters::default(); 581 let mut y = Vec::<(&String, &i32)>::new(); 582 let k = &String::from("min_paths_for_circs_pct"); 583 let v = &54; 584 y.push((k, v)); 585 let z = x.saturating_update(y.into_iter()); 586 assert!(z.is_empty()); 587 assert_eq!(x.min_circuit_path_threshold.as_percent().get(), 54); 588 } 589 590 #[test] 591 fn multiple_good_parameters() { 592 let mut x = NetParameters::default(); 593 let mut y = Vec::<(&String, &i32)>::new(); 594 let k = &String::from("min_paths_for_circs_pct"); 595 let v = &54; 596 y.push((k, v)); 597 let k = &String::from("circwindow"); 598 let v = &900; 599 y.push((k, v)); 600 let z = x.saturating_update(y.into_iter()); 601 assert!(z.is_empty()); 602 assert_eq!(x.min_circuit_path_threshold.as_percent().get(), 54); 603 assert_eq!(x.circuit_window.get(), 900); 604 } 605 606 #[test] 607 fn good_out_of_range() { 608 let mut x = NetParameters::default(); 609 let mut y = Vec::<(&String, &i32)>::new(); 610 let k = &String::from("sendme_accept_min_version"); 611 let v = &30; 612 y.push((k, v)); 613 let k = &String::from("min_paths_for_circs_pct"); 614 let v = &255; 615 y.push((k, v)); 616 let z = x.saturating_update(y.into_iter()); 617 assert!(z.is_empty()); 618 assert_eq!(x.sendme_accept_min_version.get(), 30); 619 assert_eq!(x.min_circuit_path_threshold.as_percent().get(), 95); 620 } 621 622 #[test] 623 fn good_invalid_rep() { 624 let mut x = NetParameters::default(); 625 let mut y = Vec::<(&String, &i32)>::new(); 626 let k = &String::from("sendme_accept_min_version"); 627 let v = &30; 628 y.push((k, v)); 629 let k = &String::from("min_paths_for_circs_pct"); 630 let v = &9000; 631 y.push((k, v)); 632 let z = x.saturating_update(y.into_iter()); 633 assert!(z.is_empty()); 634 assert_eq!(x.sendme_accept_min_version.get(), 30); 635 assert_eq!(x.min_circuit_path_threshold.as_percent().get(), 95); 636 } 637 638 // #[test] 639 // fn good_duplicate() {} 640 #[test] 641 fn good_unknown() { 642 let mut x = NetParameters::default(); 643 let mut y = Vec::<(&String, &i32)>::new(); 644 let k = &String::from("sendme_accept_min_version"); 645 let v = &30; 646 y.push((k, v)); 647 let k = &String::from("not_a_real_parameter"); 648 let v = &9000; 649 y.push((k, v)); 650 let z = x.saturating_update(y.into_iter()); 651 assert_eq!(z, vec![&String::from("not_a_real_parameter")]); 652 assert_eq!(x.sendme_accept_min_version.get(), 30); 653 } 654 655 #[test] 656 fn from_consensus() { 657 let mut p = NetParameters::default(); 658 let mut mp: std::collections::HashMap<String, i32> = std::collections::HashMap::new(); 659 mp.insert("bwweightscale".to_string(), 70); 660 mp.insert("min_paths_for_circs_pct".to_string(), 45); 661 mp.insert("im_a_little_teapot".to_string(), 1); 662 mp.insert("circwindow".to_string(), 99999); 663 mp.insert("ExtendByEd25519ID".to_string(), 1); 664 665 let z = p.saturating_update(mp.iter()); 666 assert_eq!(z, vec![&String::from("im_a_little_teapot")]); 667 668 assert_eq!(p.bw_weight_scale.get(), 70); 669 assert_eq!(p.min_circuit_path_threshold.as_percent().get(), 45); 670 let b_val: bool = p.extend_by_ed25519_id.into(); 671 assert!(b_val); 672 } 673 674 #[test] 675 // TODO remove when this upstream bug is fixed 676 /// https://github.com/rust-lang/rust-clippy/issues/11764 677 #[allow(clippy::map_identity)] 678 fn all_parameters() { 679 use std::time::Duration; 680 let mut p = NetParameters::default(); 681 let mp = [ 682 ("bwweightscale", 10), 683 ("cbtdisabled", 1), 684 ("cbtnummodes", 11), 685 ("cbtrecentcount", 12), 686 ("cbtmaxtimeouts", 13), 687 ("cbtmincircs", 5), 688 ("cbtquantile", 61), 689 ("cbtclosequantile", 15), 690 ("cbtlearntimeout", 1900), 691 ("cbtmintimeout", 2020), 692 ("cbtinitialtimeout", 2050), 693 ("cbttestfreq", 110), 694 ("cbtmaxopencircs", 14), 695 ("circwindow", 999), 696 ("CircuitPriorityHalflifeMsec", 222), 697 ("guard-lifetime-days", 36), 698 ("guard-confirmed-min-lifetime-days", 37), 699 ("guard-internet-likely-down-interval", 38), 700 ("guard-max-sample-size", 39), 701 ("guard-max-sample-threshold", 40), 702 ("guard-min-filtered-sample-size", 41), 703 ("guard-n-primary-guards", 42), 704 ("guard-n-primary-guards-to-use", 43), 705 ("guard-n-primary-dir-guards-to-use", 44), 706 ("guard-nonprimary-guard-connect-timeout", 45), 707 ("guard-nonprimary-guard-idle-timeout", 46), 708 ("guard-remove-unlisted-guards-after-days", 47), 709 ("guard-meaningful-restriction-percent", 12), 710 ("guard-extreme-restriction-percent", 3), 711 ("ExtendByEd25519ID", 0), 712 ("min_paths_for_circs_pct", 51), 713 ("nf_conntimeout_clients", 606), 714 ("nf_ito_low", 1_000), 715 ("nf_ito_high", 20_000), 716 ("nf_ito_low_reduced", 3_000), 717 ("nf_ito_high_reduced", 40_000), 718 ("sendme_accept_min_version", 31), 719 ("sendme_emit_min_version", 32), 720 ]; 721 let ignored = p.saturating_update(mp.iter().map(|(a, b)| (a, b))); 722 assert!(ignored.is_empty()); 723 724 assert_eq!(p.bw_weight_scale.get(), 10); 725 assert!(bool::from(p.cbt_learning_disabled)); 726 assert_eq!(p.cbt_num_xm_modes.get(), 11); 727 assert_eq!(p.cbt_success_count.get(), 12); 728 assert_eq!(p.cbt_max_timeouts.get(), 13); 729 assert_eq!(p.cbt_min_circs_for_estimate.get(), 5); 730 assert_eq!(p.cbt_timeout_quantile.as_percent().get(), 61); 731 assert_eq!(p.cbt_abandon_quantile.as_percent().get(), 15); 732 assert_eq!(p.nf_ito_low.as_millis().get(), 1_000); 733 assert_eq!(p.nf_ito_high.as_millis().get(), 20_000); 734 assert_eq!(p.nf_ito_low_reduced.as_millis().get(), 3_000); 735 assert_eq!(p.nf_ito_high_reduced.as_millis().get(), 40_000); 736 assert_eq!( 737 Duration::try_from(p.unused_client_circ_timeout_while_learning_cbt).unwrap(), 738 Duration::from_secs(1900) 739 ); 740 assert_eq!( 741 Duration::try_from(p.cbt_min_timeout).unwrap(), 742 Duration::from_millis(2020) 743 ); 744 assert_eq!( 745 Duration::try_from(p.cbt_initial_timeout).unwrap(), 746 Duration::from_millis(2050) 747 ); 748 assert_eq!( 749 Duration::try_from(p.cbt_testing_delay).unwrap(), 750 Duration::from_secs(110) 751 ); 752 assert_eq!(p.cbt_max_open_circuits_for_testing.get(), 14); 753 assert_eq!(p.circuit_window.get(), 999); 754 assert_eq!( 755 Duration::try_from(p.circuit_priority_half_life).unwrap(), 756 Duration::from_millis(222) 757 ); 758 assert!(!bool::from(p.extend_by_ed25519_id)); 759 assert_eq!(p.min_circuit_path_threshold.as_percent().get(), 51); 760 assert_eq!( 761 Duration::try_from(p.unused_client_circ_timeout).unwrap(), 762 Duration::from_secs(606) 763 ); 764 assert_eq!(p.sendme_accept_min_version.get(), 31); 765 assert_eq!(p.sendme_emit_min_version.get(), 32); 766 767 assert_eq!( 768 Duration::try_from(p.guard_lifetime_unconfirmed).unwrap(), 769 Duration::from_secs(86400 * 36) 770 ); 771 assert_eq!( 772 Duration::try_from(p.guard_lifetime_confirmed).unwrap(), 773 Duration::from_secs(86400 * 37) 774 ); 775 assert_eq!( 776 Duration::try_from(p.guard_internet_likely_down).unwrap(), 777 Duration::from_secs(38) 778 ); 779 assert_eq!(p.guard_max_sample_size.get(), 39); 780 assert_eq!(p.guard_max_sample_threshold.as_percent().get(), 40); 781 assert_eq!(p.guard_filtered_min_sample_size.get(), 41); 782 assert_eq!(p.guard_n_primary.get(), 42); 783 assert_eq!(p.guard_use_parallelism.get(), 43); 784 assert_eq!(p.guard_dir_use_parallelism.get(), 44); 785 assert_eq!( 786 Duration::try_from(p.guard_nonprimary_connect_timeout).unwrap(), 787 Duration::from_secs(45) 788 ); 789 assert_eq!( 790 Duration::try_from(p.guard_nonprimary_idle_timeout).unwrap(), 791 Duration::from_secs(46) 792 ); 793 assert_eq!( 794 Duration::try_from(p.guard_remove_unlisted_after).unwrap(), 795 Duration::from_secs(86400 * 47) 796 ); 797 assert_eq!(p.guard_meaningful_restriction.as_percent().get(), 12); 798 assert_eq!(p.guard_extreme_restriction.as_percent().get(), 3); 799 } 800 }