1use tor_units::{
22 BoundedInt32, IntegerDays, IntegerMilliseconds, IntegerMinutes, IntegerSeconds, Percentage,
23 SendMeVersion,
24};
25
26pub const CHANNEL_PADDING_TIMEOUT_UPPER_BOUND: i32 = 60_000;
37
38pub trait FromInt32Saturating {
40 fn from_saturating(val: i32) -> Self;
46
47 fn from_checked(val: i32) -> Result<Self, tor_units::Error>
51 where
52 Self: Sized;
53}
54
55impl FromInt32Saturating for i32 {
56 fn from_saturating(val: i32) -> Self {
57 val
58 }
59
60 fn from_checked(val: i32) -> Result<Self, tor_units::Error>
61 where
62 Self: Sized,
63 {
64 Ok(val)
65 }
66}
67impl<const L: i32, const H: i32> FromInt32Saturating for BoundedInt32<L, H> {
68 fn from_saturating(val: i32) -> Self {
69 Self::saturating_new(val)
70 }
71
72 fn from_checked(val: i32) -> Result<Self, tor_units::Error>
73 where
74 Self: Sized,
75 {
76 Self::checked_new(val)
77 }
78}
79impl<T: Copy + Into<f64> + FromInt32Saturating> FromInt32Saturating for Percentage<T> {
80 fn from_saturating(val: i32) -> Self {
81 Self::new(T::from_saturating(val))
82 }
83
84 fn from_checked(val: i32) -> Result<Self, tor_units::Error>
85 where
86 Self: Sized,
87 {
88 Ok(Self::new(T::from_checked(val)?))
89 }
90}
91impl<T: FromInt32Saturating + TryInto<u64>> FromInt32Saturating for IntegerMilliseconds<T> {
92 fn from_saturating(val: i32) -> Self {
93 Self::new(T::from_saturating(val))
94 }
95
96 fn from_checked(val: i32) -> Result<Self, tor_units::Error>
97 where
98 Self: Sized,
99 {
100 Ok(Self::new(T::from_checked(val)?))
101 }
102}
103impl<T: FromInt32Saturating + TryInto<u64>> FromInt32Saturating for IntegerSeconds<T> {
104 fn from_saturating(val: i32) -> Self {
105 Self::new(T::from_saturating(val))
106 }
107
108 fn from_checked(val: i32) -> Result<Self, tor_units::Error>
109 where
110 Self: Sized,
111 {
112 Ok(Self::new(T::from_checked(val)?))
113 }
114}
115impl<T: FromInt32Saturating + TryInto<u64>> FromInt32Saturating for IntegerMinutes<T> {
116 fn from_saturating(val: i32) -> Self {
117 Self::new(T::from_saturating(val))
118 }
119
120 fn from_checked(val: i32) -> Result<Self, tor_units::Error>
121 where
122 Self: Sized,
123 {
124 Ok(Self::new(T::from_checked(val)?))
125 }
126}
127impl<T: FromInt32Saturating + TryInto<u64>> FromInt32Saturating for IntegerDays<T> {
128 fn from_saturating(val: i32) -> Self {
129 Self::new(T::from_saturating(val))
130 }
131
132 fn from_checked(val: i32) -> Result<Self, tor_units::Error>
133 where
134 Self: Sized,
135 {
136 Ok(Self::new(T::from_checked(val)?))
137 }
138}
139impl FromInt32Saturating for SendMeVersion {
140 fn from_saturating(val: i32) -> Self {
141 Self::new(val.clamp(0, 255) as u8)
142 }
143
144 fn from_checked(val: i32) -> Result<Self, tor_units::Error>
145 where
146 Self: Sized,
147 {
148 let val = BoundedInt32::<0, 255>::checked_new(val)?;
149 Ok(Self::new(val.get() as u8))
150 }
151}
152
153macro_rules! declare_net_parameters {
159 {
160 $(#[$s_meta:meta])* $s_v:vis struct $s_name:ident {
161 $(
162 $(#[$p_meta:meta])* $p_v:vis
163 $p_name:ident : $p_type:ty
164 = ($p_dflt:expr) from $p_string:literal
165 ),*
166 $( , )?
167 }
168 } =>
169 {
170 $(#[$s_meta])* $s_v struct $s_name {
171 $(
172 $(#[$p_meta])* $p_v $p_name : $p_type
173 ),*
174 }
175
176 impl $s_name {
177 fn default_values() -> Result<Self, tor_units::Error> {
182 Ok(Self {
183 $( $p_name : $p_dflt.try_into()? ),*
184 })
185 }
186 fn set_saturating(&mut self, key: &str, val: i32) -> bool {
193 match key {
194 $( $p_string => self.$p_name = {
195 type T = $p_type;
196 match T::from_checked(val) {
197 Ok(v) => v,
198 Err(e) => {
199 tracing::warn!("For key {key}, clamping out of range value: {e:?}");
200 T::from_saturating(val)
201 }
202 }
203 }, )*
204 _ => return false,
205 }
206 true
207 }
208 }
209 }
210}
211
212declare_net_parameters! {
213
214#[derive(Clone, Debug)]
217#[non_exhaustive]
218pub struct NetParameters {
219 pub bw_weight_scale: BoundedInt32<1, { i32::MAX }> = (10_000)
221 from "bwweightscale",
222 pub cbt_learning_disabled: BoundedInt32<0, 1> = (0)
224 from "cbtdisabled",
225 pub cbt_num_xm_modes: BoundedInt32<1, 20> = (10)
228 from "cbtnummodes",
229 pub cbt_success_count: BoundedInt32<3, 1_000> = (20)
232 from "cbtrecentcount",
233 pub cbt_max_timeouts: BoundedInt32<3, 10_000> = (18)
236 from "cbtmaxtimeouts",
237 pub cbt_min_circs_for_estimate: BoundedInt32<1, 10_000> = (100)
240 from "cbtmincircs",
241 pub cbt_timeout_quantile: Percentage<BoundedInt32<10, 99>> = (80)
247 from "cbtquantile",
248 pub cbt_abandon_quantile: Percentage<BoundedInt32<10, 99>> = (99)
251 from "cbtclosequantile",
252 pub cbt_min_timeout: IntegerMilliseconds<BoundedInt32<10, { i32::MAX }>> = (10)
254 from "cbtmintimeout",
255 pub cbt_initial_timeout: IntegerMilliseconds<BoundedInt32<10, { i32::MAX }>> = (60_000)
258 from "cbtinitialtimeout",
259 pub cbt_testing_delay: IntegerSeconds<BoundedInt32<1, { i32::MAX }>> = (10)
263 from "cbttestfreq",
264 pub cbt_max_open_circuits_for_testing: BoundedInt32<0, 14> = (10)
268 from "cbtmaxopencircs",
269
270 pub cc_alg: BoundedInt32<0, 2> = (0)
277 from "cc_alg",
278
279 pub cc_cwnd_full_gap: BoundedInt32<0, { i16::MAX as i32 }> = (4444)
282 from "cc_cwnd_full_gap",
283 pub cc_cwnd_full_minpct: Percentage<BoundedInt32<0, 100>> = (25)
285 from "cc_cwnd_full_minpct",
286 pub cc_cwnd_full_per_cwnd: BoundedInt32<0, 1> = (1)
288 from "cc_cwnd_full_per_cwnd",
289
290 pub cc_cwnd_init: BoundedInt32<31, 10_000> = (4 * 31)
292 from "cc_cwnd_init",
293 pub cc_cwnd_inc_pct_ss: Percentage<BoundedInt32<1, 500>> = (50)
296 from "cc_cwnd_inc_pct_ss",
297 pub cc_cwnd_inc: BoundedInt32<1, 1000> = (31)
300 from "cc_cwnd_inc",
301 pub cc_cwnd_inc_rate: BoundedInt32<1, 250> = (1)
304 from "cc_cwnd_inc_rate",
305 pub cc_cwnd_min: BoundedInt32<31, 1000> = (31)
307 from "cc_cwnd_min",
308 pub cc_cwnd_max: BoundedInt32<500, { i32::MAX }> = (i32::MAX)
310 from "cc_cwnd_max",
311
312 pub cc_ewma_cwnd_pct: Percentage<BoundedInt32<1, 255>> = (50)
318 from "cc_ewma_cwnd_pct",
319 pub cc_ewma_max: BoundedInt32<2, { i32::MAX }> = (10)
321 from "cc_ewma_max",
322 pub cc_ewma_ss: BoundedInt32<2, { i32::MAX }> = (2)
324 from "cc_ewma_ss",
325 pub cc_rtt_reset_pct: Percentage<BoundedInt32<0, 100>> = (100)
328 from "cc_rtt_reset_pct",
329 pub cc_sendme_inc: BoundedInt32<1, 254> = (31)
331 from "cc_sendme_inc",
332 pub cc_ss_max: BoundedInt32<500, { i32::MAX }> = (5000)
334 from "cc_ss_max",
335
336 pub cc_vegas_alpha_exit: BoundedInt32<0, 1000> = (3 * 62)
338 from "cc_vegas_alpha_exit",
339 pub cc_vegas_beta_exit: BoundedInt32<0, 1000> = (4 * 62)
341 from "cc_vegas_beta_exit",
342 pub cc_vegas_delta_exit: BoundedInt32<0, 1000> = (5 * 62)
344 from "cc_vegas_delta_exit",
345 pub cc_vegas_gamma_exit: BoundedInt32<0, 1000> = (3 * 62)
347 from "cc_vegas_gamma_exit",
348
349 pub cc_vegas_alpha_onion: BoundedInt32<0, 1000> = (3 * 62)
351 from "cc_vegas_alpha_onion",
352 pub cc_vegas_beta_onion: BoundedInt32<0, 1000> = (6 * 62)
354 from "cc_vegas_beta_onion",
355 pub cc_vegas_delta_onion: BoundedInt32<0, 1000> = (7 * 62)
357 from "cc_vegas_delta_onion",
358 pub cc_vegas_gamma_onion: BoundedInt32<0, 1000> = (4 * 62)
360 from "cc_vegas_gamma_onion",
361
362 pub cc_vegas_sscap_exit: BoundedInt32<100, { i32::MAX }> = (600)
365 from "cc_sscap_exit",
366 pub cc_vegas_sscap_onion: BoundedInt32<100, { i32::MAX }> = (475)
369 from "cc_sscap_onion",
370
371 pub circuit_window: BoundedInt32<100, 1000> = (1_000)
373 from "circwindow",
374 pub circuit_priority_half_life: IntegerMilliseconds<BoundedInt32<1, { i32::MAX }>> = (30_000)
376 from "CircuitPriorityHalflifeMsec",
377 pub extend_by_ed25519_id: BoundedInt32<0, 1> = (0)
379 from "ExtendByEd25519ID",
380
381 pub guard_meaningful_restriction: Percentage<BoundedInt32<1,100>> = (20)
385 from "guard-meaningful-restriction-percent",
386
387 pub guard_extreme_restriction: Percentage<BoundedInt32<1,100>> = (1)
390 from "guard-extreme-restriction-percent",
391
392 pub guard_lifetime_unconfirmed: IntegerDays<BoundedInt32<1, 3650>> = (120)
395 from "guard-lifetime-days",
396
397 pub guard_lifetime_confirmed: IntegerDays<BoundedInt32<1, 3650>> = (60)
400 from "guard-confirmed-min-lifetime-days",
401
402 pub guard_internet_likely_down: IntegerSeconds<BoundedInt32<1, {i32::MAX}>> = (600)
406 from "guard-internet-likely-down-interval",
407 pub guard_max_sample_size: BoundedInt32<1, {i32::MAX}> = (60)
410 from "guard-max-sample-size",
411 pub guard_max_sample_threshold: Percentage<BoundedInt32<1,100>> = (20)
414 from "guard-max-sample-threshold",
415
416 pub guard_filtered_min_sample_size: BoundedInt32<1,{i32::MAX}> = (20)
420 from "guard-min-filtered-sample-size",
421
422 pub guard_n_primary: BoundedInt32<1,{i32::MAX}> = (3)
425 from "guard-n-primary-guards",
426 pub guard_use_parallelism: BoundedInt32<1, {i32::MAX}> = (1)
429 from "guard-n-primary-guards-to-use",
430 pub guard_dir_use_parallelism: BoundedInt32<1, {i32::MAX}> = (3)
434 from "guard-n-primary-dir-guards-to-use",
435
436 pub guard_nonprimary_connect_timeout: IntegerSeconds<BoundedInt32<1,{i32::MAX}>> = (15)
440 from "guard-nonprimary-guard-connect-timeout",
441 pub guard_nonprimary_idle_timeout: IntegerSeconds<BoundedInt32<1,{i32::MAX}>> = (600)
444 from "guard-nonprimary-guard-idle-timeout",
445 pub guard_remove_unlisted_after: IntegerDays<BoundedInt32<1,3650>> = (20)
448 from "guard-remove-unlisted-guards-after-days",
449
450
451 pub min_circuit_path_threshold: Percentage<BoundedInt32<25, 95>> = (60)
453 from "min_paths_for_circs_pct",
454
455 pub nf_ito_low: IntegerMilliseconds<BoundedInt32<0, CHANNEL_PADDING_TIMEOUT_UPPER_BOUND>> = (1500)
459 from "nf_ito_low",
460 pub nf_ito_high: IntegerMilliseconds<BoundedInt32<0, CHANNEL_PADDING_TIMEOUT_UPPER_BOUND>> = (9500)
462 from "nf_ito_high",
463 pub nf_ito_low_reduced: IntegerMilliseconds<BoundedInt32<0, CHANNEL_PADDING_TIMEOUT_UPPER_BOUND>> = (9000)
465 from "nf_ito_low_reduced",
466 pub nf_ito_high_reduced: IntegerMilliseconds<BoundedInt32<0, CHANNEL_PADDING_TIMEOUT_UPPER_BOUND>> = (14000)
468 from "nf_ito_high_reduced",
469
470 pub sendme_accept_min_version: SendMeVersion = (0)
472 from "sendme_accept_min_version",
473 pub sendme_emit_min_version: SendMeVersion = (0)
475 from "sendme_emit_min_version",
476
477 pub unused_client_circ_timeout: IntegerSeconds<BoundedInt32<60, 86_400>> = (30*60)
480 from "nf_conntimeout_clients",
481 pub unused_client_circ_timeout_while_learning_cbt: IntegerSeconds<BoundedInt32<10, 60_000>> = (3*60)
484 from "cbtlearntimeout",
485
486 pub hs_introcirc_requests_min: BoundedInt32<0, {i32::MAX}> = (16384)
490 from "hs_intro_min_introduce2",
491
492 pub hs_introcirc_requests_max: BoundedInt32<0, {i32::MAX}> = (32768)
496 from "hs_intro_max_introduce2",
497
498 pub hs_intro_min_lifetime: IntegerSeconds<BoundedInt32<0, {i32::MAX}>> = (18 * 60 * 60)
500 from "hs_intro_min_lifetime",
501
502 pub hs_intro_max_lifetime: IntegerSeconds<BoundedInt32<0, {i32::MAX}>> = (24 * 60 * 60)
504 from "hs_intro_max_lifetime",
505
506 pub hs_intro_num_extra_intropoints: BoundedInt32<0, 128> = (2)
509 from "hs_intro_num_extra",
510
511 pub hsdir_dl_max_reply_cells: BoundedInt32<2, 2304> = (110)
514 from "hsdir_dl_max_reply_cells",
515
516 pub hsdir_ul_max_reply_cells: BoundedInt32<2, 1024> = (8)
519 from "hsdir_ul_max_reply_cells",
520
521 pub hsdir_timeperiod_length: IntegerMinutes<BoundedInt32<5, 14400>> = (1440)
527 from "hsdir_interval",
528
529 pub hsdir_n_replicas: BoundedInt32<1, 16> = (2)
532 from "hsdir_n_replicas",
533
534 pub hsdir_spread_fetch: BoundedInt32<1, 128> = (3)
537 from "hsdir_spread_fetch",
538
539 pub hsdir_spread_store: BoundedInt32<1,128> = (4)
542 from "hsdir_spread_store",
543
544 pub hsdir_max_desc_size: BoundedInt32<1, {i32::MAX}> = (50_000)
546 from "HSV3MaxDescriptorSize",
547
548 pub hs_service_rendezvous_failures_max: BoundedInt32<1, 10> = (2)
551 from "hs_service_max_rdv_failures",
552
553 pub hs_intro_dos_enabled: BoundedInt32<0, 1> = (0)
558 from "HiddenServiceEnableIntroDoSDefense",
559
560 pub hs_intro_dos_max_burst: BoundedInt32<0, {i32::MAX}> = (200)
566 from "HiddenServiceEnableIntroDoSBurstPerSec",
567
568 pub hs_intro_dos_rate: BoundedInt32<0, {i32::MAX}> = (25)
574 from "HiddenServiceEnableIntroDoSRatePerSec",
575
576 pub vanguards_enabled: BoundedInt32<0, 2> = (1)
587 from "vanguards-enabled",
588
589 pub vanguards_hs_service: BoundedInt32<0, 2> = (2)
602 from "vanguards-hs-service",
603
604 pub guard_hs_l2_number: BoundedInt32<1, {i32::MAX}> = (4)
609 from "guard-hs-l2-number",
610
611 pub guard_hs_l2_lifetime_min: IntegerSeconds<BoundedInt32<1, {i32::MAX}>> = (86400)
616 from "guard-hs-l2-lifetime-min",
617
618 pub guard_hs_l2_lifetime_max: IntegerSeconds<BoundedInt32<1, {i32::MAX}>> = (1036800)
623 from "guard-hs-l2-lifetime-max",
624
625 pub guard_hs_l3_number: BoundedInt32<1, {i32::MAX}> = (8)
630 from "guard-hs-l3-number",
631
632 pub guard_hs_l3_lifetime_min: IntegerSeconds<BoundedInt32<1, {i32::MAX}>> = (3600)
637 from "guard-hs-l3-lifetime-min",
638
639 pub guard_hs_l3_lifetime_max: IntegerSeconds<BoundedInt32<1, {i32::MAX}>> = (172800)
644 from "guard-hs-l3-lifetime-max",
645
646 pub kist_enabled: BoundedInt32<0, 1> = (0)
657 from "kist-enabled",
658
659 pub kist_tcp_notsent_lowat: BoundedInt32<1, {i32::MAX}> = (1)
670 from "kist-tcp-notsent-lowat",
671
672 pub use_family_lists: BoundedInt32<0,1> = (1)
675 from "use-family-lists",
676
677 pub use_family_ids: BoundedInt32<0,1> = (1)
680 from "use-family-ids",
681}
682
683}
684
685impl Default for NetParameters {
686 fn default() -> Self {
687 NetParameters::default_values().expect("Default parameters were out-of-bounds")
688 }
689}
690
691impl AsRef<NetParameters> for NetParameters {
694 fn as_ref(&self) -> &NetParameters {
695 self
696 }
697}
698
699impl NetParameters {
700 pub fn from_map(p: &tor_netdoc::doc::netstatus::NetParams<i32>) -> Self {
704 let mut params = NetParameters::default();
705 let unrecognized = params.saturating_update(p.iter());
706 for u in unrecognized {
707 tracing::debug!("Ignored unrecognized net param: {u}");
708 }
709 params
710 }
711
712 pub(crate) fn saturating_update<'a, S>(
717 &mut self,
718 iter: impl Iterator<Item = (S, &'a i32)>,
719 ) -> Vec<S>
720 where
721 S: AsRef<str>,
722 {
723 let mut unrecognized = Vec::new();
724 for (k, v) in iter {
725 if !self.set_saturating(k.as_ref(), *v) {
726 unrecognized.push(k);
727 }
728 }
729 unrecognized
730 }
731}
732
733#[cfg(test)]
734#[allow(clippy::many_single_char_names)]
735#[allow(clippy::unwrap_used)]
736#[allow(clippy::cognitive_complexity)]
737mod test {
738 #![allow(clippy::bool_assert_comparison)]
740 #![allow(clippy::clone_on_copy)]
741 #![allow(clippy::dbg_macro)]
742 #![allow(clippy::mixed_attributes_style)]
743 #![allow(clippy::print_stderr)]
744 #![allow(clippy::print_stdout)]
745 #![allow(clippy::single_char_pattern)]
746 #![allow(clippy::unwrap_used)]
747 #![allow(clippy::unchecked_duration_subtraction)]
748 #![allow(clippy::useless_vec)]
749 #![allow(clippy::needless_pass_by_value)]
750 use super::*;
752 use std::string::String;
753
754 #[test]
755 fn empty_list() {
756 let mut x = NetParameters::default();
757 let y = Vec::<(&String, &i32)>::new();
758 let u = x.saturating_update(y.into_iter());
759 assert!(u.is_empty());
760 }
761
762 #[test]
763 fn unknown_parameter() {
764 let mut x = NetParameters::default();
765 let mut y = Vec::<(&String, &i32)>::new();
766 let k = &String::from("This_is_not_a_real_key");
767 let v = &456;
768 y.push((k, v));
769 let u = x.saturating_update(y.into_iter());
770 assert_eq!(u, vec![&String::from("This_is_not_a_real_key")]);
771 }
772
773 #[test]
777 fn single_good_parameter() {
778 let mut x = NetParameters::default();
779 let mut y = Vec::<(&String, &i32)>::new();
780 let k = &String::from("min_paths_for_circs_pct");
781 let v = &54;
782 y.push((k, v));
783 let z = x.saturating_update(y.into_iter());
784 assert!(z.is_empty());
785 assert_eq!(x.min_circuit_path_threshold.as_percent().get(), 54);
786 }
787
788 #[test]
789 fn multiple_good_parameters() {
790 let mut x = NetParameters::default();
791 let mut y = Vec::<(&String, &i32)>::new();
792 let k = &String::from("min_paths_for_circs_pct");
793 let v = &54;
794 y.push((k, v));
795 let k = &String::from("circwindow");
796 let v = &900;
797 y.push((k, v));
798 let z = x.saturating_update(y.into_iter());
799 assert!(z.is_empty());
800 assert_eq!(x.min_circuit_path_threshold.as_percent().get(), 54);
801 assert_eq!(x.circuit_window.get(), 900);
802 }
803
804 #[test]
805 fn good_out_of_range() {
806 let mut x = NetParameters::default();
807 let mut y = Vec::<(&String, &i32)>::new();
808 let k = &String::from("sendme_accept_min_version");
809 let v = &30;
810 y.push((k, v));
811 let k = &String::from("min_paths_for_circs_pct");
812 let v = &255;
813 y.push((k, v));
814 let z = x.saturating_update(y.into_iter());
815 assert!(z.is_empty());
816 assert_eq!(x.sendme_accept_min_version.get(), 30);
817 assert_eq!(x.min_circuit_path_threshold.as_percent().get(), 95);
818 }
819
820 #[test]
821 fn good_invalid_rep() {
822 let mut x = NetParameters::default();
823 let mut y = Vec::<(&String, &i32)>::new();
824 let k = &String::from("sendme_accept_min_version");
825 let v = &30;
826 y.push((k, v));
827 let k = &String::from("min_paths_for_circs_pct");
828 let v = &9000;
829 y.push((k, v));
830 let z = x.saturating_update(y.into_iter());
831 assert!(z.is_empty());
832 assert_eq!(x.sendme_accept_min_version.get(), 30);
833 assert_eq!(x.min_circuit_path_threshold.as_percent().get(), 95);
834 }
835
836 #[test]
839 fn good_unknown() {
840 let mut x = NetParameters::default();
841 let mut y = Vec::<(&String, &i32)>::new();
842 let k = &String::from("sendme_accept_min_version");
843 let v = &30;
844 y.push((k, v));
845 let k = &String::from("not_a_real_parameter");
846 let v = &9000;
847 y.push((k, v));
848 let z = x.saturating_update(y.into_iter());
849 assert_eq!(z, vec![&String::from("not_a_real_parameter")]);
850 assert_eq!(x.sendme_accept_min_version.get(), 30);
851 }
852
853 #[test]
854 fn from_consensus() {
855 let mut p = NetParameters::default();
856 let mut mp: std::collections::HashMap<String, i32> = std::collections::HashMap::new();
857 mp.insert("bwweightscale".to_string(), 70);
858 mp.insert("min_paths_for_circs_pct".to_string(), 45);
859 mp.insert("im_a_little_teapot".to_string(), 1);
860 mp.insert("circwindow".to_string(), 99999);
861 mp.insert("ExtendByEd25519ID".to_string(), 1);
862
863 let z = p.saturating_update(mp.iter());
864 assert_eq!(z, vec![&String::from("im_a_little_teapot")]);
865
866 assert_eq!(p.bw_weight_scale.get(), 70);
867 assert_eq!(p.min_circuit_path_threshold.as_percent().get(), 45);
868 let b_val: bool = p.extend_by_ed25519_id.into();
869 assert!(b_val);
870 }
871
872 #[test]
873 fn all_parameters() {
874 use std::time::Duration;
875 let mut p = NetParameters::default();
876 let mp = [
877 ("bwweightscale", 10),
878 ("cbtdisabled", 1),
879 ("cbtnummodes", 11),
880 ("cbtrecentcount", 12),
881 ("cbtmaxtimeouts", 13),
882 ("cbtmincircs", 5),
883 ("cbtquantile", 61),
884 ("cbtclosequantile", 15),
885 ("cbtlearntimeout", 1900),
886 ("cbtmintimeout", 2020),
887 ("cbtinitialtimeout", 2050),
888 ("cbttestfreq", 110),
889 ("cbtmaxopencircs", 14),
890 ("circwindow", 999),
891 ("CircuitPriorityHalflifeMsec", 222),
892 ("guard-lifetime-days", 36),
893 ("guard-confirmed-min-lifetime-days", 37),
894 ("guard-internet-likely-down-interval", 38),
895 ("guard-max-sample-size", 39),
896 ("guard-max-sample-threshold", 40),
897 ("guard-min-filtered-sample-size", 41),
898 ("guard-n-primary-guards", 42),
899 ("guard-n-primary-guards-to-use", 43),
900 ("guard-n-primary-dir-guards-to-use", 44),
901 ("guard-nonprimary-guard-connect-timeout", 45),
902 ("guard-nonprimary-guard-idle-timeout", 46),
903 ("guard-remove-unlisted-guards-after-days", 47),
904 ("guard-meaningful-restriction-percent", 12),
905 ("guard-extreme-restriction-percent", 3),
906 ("ExtendByEd25519ID", 0),
907 ("min_paths_for_circs_pct", 51),
908 ("nf_conntimeout_clients", 606),
909 ("nf_ito_low", 1_000),
910 ("nf_ito_high", 20_000),
911 ("nf_ito_low_reduced", 3_000),
912 ("nf_ito_high_reduced", 40_000),
913 ("sendme_accept_min_version", 31),
914 ("sendme_emit_min_version", 32),
915 ];
916 let ignored = p.saturating_update(mp.iter().map(|(a, b)| (a, b)));
917 assert!(ignored.is_empty());
918
919 assert_eq!(p.bw_weight_scale.get(), 10);
920 assert!(bool::from(p.cbt_learning_disabled));
921 assert_eq!(p.cbt_num_xm_modes.get(), 11);
922 assert_eq!(p.cbt_success_count.get(), 12);
923 assert_eq!(p.cbt_max_timeouts.get(), 13);
924 assert_eq!(p.cbt_min_circs_for_estimate.get(), 5);
925 assert_eq!(p.cbt_timeout_quantile.as_percent().get(), 61);
926 assert_eq!(p.cbt_abandon_quantile.as_percent().get(), 15);
927 assert_eq!(p.nf_ito_low.as_millis().get(), 1_000);
928 assert_eq!(p.nf_ito_high.as_millis().get(), 20_000);
929 assert_eq!(p.nf_ito_low_reduced.as_millis().get(), 3_000);
930 assert_eq!(p.nf_ito_high_reduced.as_millis().get(), 40_000);
931 assert_eq!(
932 Duration::try_from(p.unused_client_circ_timeout_while_learning_cbt).unwrap(),
933 Duration::from_secs(1900)
934 );
935 assert_eq!(
936 Duration::try_from(p.cbt_min_timeout).unwrap(),
937 Duration::from_millis(2020)
938 );
939 assert_eq!(
940 Duration::try_from(p.cbt_initial_timeout).unwrap(),
941 Duration::from_millis(2050)
942 );
943 assert_eq!(
944 Duration::try_from(p.cbt_testing_delay).unwrap(),
945 Duration::from_secs(110)
946 );
947 assert_eq!(p.cbt_max_open_circuits_for_testing.get(), 14);
948 assert_eq!(p.circuit_window.get(), 999);
949 assert_eq!(
950 Duration::try_from(p.circuit_priority_half_life).unwrap(),
951 Duration::from_millis(222)
952 );
953 assert!(!bool::from(p.extend_by_ed25519_id));
954 assert_eq!(p.min_circuit_path_threshold.as_percent().get(), 51);
955 assert_eq!(
956 Duration::try_from(p.unused_client_circ_timeout).unwrap(),
957 Duration::from_secs(606)
958 );
959 assert_eq!(p.sendme_accept_min_version.get(), 31);
960 assert_eq!(p.sendme_emit_min_version.get(), 32);
961
962 assert_eq!(
963 Duration::try_from(p.guard_lifetime_unconfirmed).unwrap(),
964 Duration::from_secs(86400 * 36)
965 );
966 assert_eq!(
967 Duration::try_from(p.guard_lifetime_confirmed).unwrap(),
968 Duration::from_secs(86400 * 37)
969 );
970 assert_eq!(
971 Duration::try_from(p.guard_internet_likely_down).unwrap(),
972 Duration::from_secs(38)
973 );
974 assert_eq!(p.guard_max_sample_size.get(), 39);
975 assert_eq!(p.guard_max_sample_threshold.as_percent().get(), 40);
976 assert_eq!(p.guard_filtered_min_sample_size.get(), 41);
977 assert_eq!(p.guard_n_primary.get(), 42);
978 assert_eq!(p.guard_use_parallelism.get(), 43);
979 assert_eq!(p.guard_dir_use_parallelism.get(), 44);
980 assert_eq!(
981 Duration::try_from(p.guard_nonprimary_connect_timeout).unwrap(),
982 Duration::from_secs(45)
983 );
984 assert_eq!(
985 Duration::try_from(p.guard_nonprimary_idle_timeout).unwrap(),
986 Duration::from_secs(46)
987 );
988 assert_eq!(
989 Duration::try_from(p.guard_remove_unlisted_after).unwrap(),
990 Duration::from_secs(86400 * 47)
991 );
992 assert_eq!(p.guard_meaningful_restriction.as_percent().get(), 12);
993 assert_eq!(p.guard_extreme_restriction.as_percent().get(), 3);
994 }
995}