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_timeperiod_length: IntegerMinutes<BoundedInt32<5, 14400>> = (1440)
517 from "hsdir_interval",
518
519 pub hsdir_n_replicas: BoundedInt32<1, 16> = (2)
522 from "hsdir_n_replicas",
523
524 pub hsdir_spread_fetch: BoundedInt32<1, 128> = (3)
527 from "hsdir_spread_fetch",
528
529 pub hsdir_spread_store: BoundedInt32<1,128> = (4)
532 from "hsdir_spread_store",
533
534 pub hsdir_max_desc_size: BoundedInt32<1, {i32::MAX}> = (50_000)
536 from "HSV3MaxDescriptorSize",
537
538 pub hs_service_rendezvous_failures_max: BoundedInt32<1, 10> = (2)
541 from "hs_service_max_rdv_failures",
542
543 pub hs_intro_dos_enabled: BoundedInt32<0, 1> = (0)
548 from "HiddenServiceEnableIntroDoSDefense",
549
550 pub hs_intro_dos_max_burst: BoundedInt32<0, {i32::MAX}> = (200)
556 from "HiddenServiceEnableIntroDoSBurstPerSec",
557
558 pub hs_intro_dos_rate: BoundedInt32<0, {i32::MAX}> = (25)
564 from "HiddenServiceEnableIntroDoSRatePerSec",
565
566 pub vanguards_enabled: BoundedInt32<0, 2> = (1)
577 from "vanguards-enabled",
578
579 pub vanguards_hs_service: BoundedInt32<0, 2> = (2)
592 from "vanguards-hs-service",
593
594 pub guard_hs_l2_number: BoundedInt32<1, {i32::MAX}> = (4)
599 from "guard-hs-l2-number",
600
601 pub guard_hs_l2_lifetime_min: IntegerSeconds<BoundedInt32<1, {i32::MAX}>> = (86400)
606 from "guard-hs-l2-lifetime-min",
607
608 pub guard_hs_l2_lifetime_max: IntegerSeconds<BoundedInt32<1, {i32::MAX}>> = (1036800)
613 from "guard-hs-l2-lifetime-max",
614
615 pub guard_hs_l3_number: BoundedInt32<1, {i32::MAX}> = (8)
620 from "guard-hs-l3-number",
621
622 pub guard_hs_l3_lifetime_min: IntegerSeconds<BoundedInt32<1, {i32::MAX}>> = (3600)
627 from "guard-hs-l3-lifetime-min",
628
629 pub guard_hs_l3_lifetime_max: IntegerSeconds<BoundedInt32<1, {i32::MAX}>> = (172800)
634 from "guard-hs-l3-lifetime-max",
635
636 pub kist_enabled: BoundedInt32<0, 1> = (0)
647 from "kist-enabled",
648
649 pub kist_tcp_notsent_lowat: BoundedInt32<1, {i32::MAX}> = (1)
660 from "kist-tcp-notsent-lowat",
661
662 pub use_family_lists: BoundedInt32<0,1> = (1)
665 from "use-family-lists",
666
667 pub use_family_ids: BoundedInt32<0,1> = (1)
670 from "use-family-ids",
671}
672
673}
674
675impl Default for NetParameters {
676 fn default() -> Self {
677 NetParameters::default_values().expect("Default parameters were out-of-bounds")
678 }
679}
680
681impl AsRef<NetParameters> for NetParameters {
684 fn as_ref(&self) -> &NetParameters {
685 self
686 }
687}
688
689impl NetParameters {
690 pub fn from_map(p: &tor_netdoc::doc::netstatus::NetParams<i32>) -> Self {
694 let mut params = NetParameters::default();
695 let unrecognized = params.saturating_update(p.iter());
696 for u in unrecognized {
697 tracing::debug!("Ignored unrecognized net param: {u}");
698 }
699 params
700 }
701
702 pub(crate) fn saturating_update<'a, S>(
707 &mut self,
708 iter: impl Iterator<Item = (S, &'a i32)>,
709 ) -> Vec<S>
710 where
711 S: AsRef<str>,
712 {
713 let mut unrecognized = Vec::new();
714 for (k, v) in iter {
715 if !self.set_saturating(k.as_ref(), *v) {
716 unrecognized.push(k);
717 }
718 }
719 unrecognized
720 }
721}
722
723#[cfg(test)]
724#[allow(clippy::many_single_char_names)]
725#[allow(clippy::unwrap_used)]
726#[allow(clippy::cognitive_complexity)]
727mod test {
728 #![allow(clippy::bool_assert_comparison)]
730 #![allow(clippy::clone_on_copy)]
731 #![allow(clippy::dbg_macro)]
732 #![allow(clippy::mixed_attributes_style)]
733 #![allow(clippy::print_stderr)]
734 #![allow(clippy::print_stdout)]
735 #![allow(clippy::single_char_pattern)]
736 #![allow(clippy::unwrap_used)]
737 #![allow(clippy::unchecked_duration_subtraction)]
738 #![allow(clippy::useless_vec)]
739 #![allow(clippy::needless_pass_by_value)]
740 use super::*;
742 use std::string::String;
743
744 #[test]
745 fn empty_list() {
746 let mut x = NetParameters::default();
747 let y = Vec::<(&String, &i32)>::new();
748 let u = x.saturating_update(y.into_iter());
749 assert!(u.is_empty());
750 }
751
752 #[test]
753 fn unknown_parameter() {
754 let mut x = NetParameters::default();
755 let mut y = Vec::<(&String, &i32)>::new();
756 let k = &String::from("This_is_not_a_real_key");
757 let v = &456;
758 y.push((k, v));
759 let u = x.saturating_update(y.into_iter());
760 assert_eq!(u, vec![&String::from("This_is_not_a_real_key")]);
761 }
762
763 #[test]
767 fn single_good_parameter() {
768 let mut x = NetParameters::default();
769 let mut y = Vec::<(&String, &i32)>::new();
770 let k = &String::from("min_paths_for_circs_pct");
771 let v = &54;
772 y.push((k, v));
773 let z = x.saturating_update(y.into_iter());
774 assert!(z.is_empty());
775 assert_eq!(x.min_circuit_path_threshold.as_percent().get(), 54);
776 }
777
778 #[test]
779 fn multiple_good_parameters() {
780 let mut x = NetParameters::default();
781 let mut y = Vec::<(&String, &i32)>::new();
782 let k = &String::from("min_paths_for_circs_pct");
783 let v = &54;
784 y.push((k, v));
785 let k = &String::from("circwindow");
786 let v = &900;
787 y.push((k, v));
788 let z = x.saturating_update(y.into_iter());
789 assert!(z.is_empty());
790 assert_eq!(x.min_circuit_path_threshold.as_percent().get(), 54);
791 assert_eq!(x.circuit_window.get(), 900);
792 }
793
794 #[test]
795 fn good_out_of_range() {
796 let mut x = NetParameters::default();
797 let mut y = Vec::<(&String, &i32)>::new();
798 let k = &String::from("sendme_accept_min_version");
799 let v = &30;
800 y.push((k, v));
801 let k = &String::from("min_paths_for_circs_pct");
802 let v = &255;
803 y.push((k, v));
804 let z = x.saturating_update(y.into_iter());
805 assert!(z.is_empty());
806 assert_eq!(x.sendme_accept_min_version.get(), 30);
807 assert_eq!(x.min_circuit_path_threshold.as_percent().get(), 95);
808 }
809
810 #[test]
811 fn good_invalid_rep() {
812 let mut x = NetParameters::default();
813 let mut y = Vec::<(&String, &i32)>::new();
814 let k = &String::from("sendme_accept_min_version");
815 let v = &30;
816 y.push((k, v));
817 let k = &String::from("min_paths_for_circs_pct");
818 let v = &9000;
819 y.push((k, v));
820 let z = x.saturating_update(y.into_iter());
821 assert!(z.is_empty());
822 assert_eq!(x.sendme_accept_min_version.get(), 30);
823 assert_eq!(x.min_circuit_path_threshold.as_percent().get(), 95);
824 }
825
826 #[test]
829 fn good_unknown() {
830 let mut x = NetParameters::default();
831 let mut y = Vec::<(&String, &i32)>::new();
832 let k = &String::from("sendme_accept_min_version");
833 let v = &30;
834 y.push((k, v));
835 let k = &String::from("not_a_real_parameter");
836 let v = &9000;
837 y.push((k, v));
838 let z = x.saturating_update(y.into_iter());
839 assert_eq!(z, vec![&String::from("not_a_real_parameter")]);
840 assert_eq!(x.sendme_accept_min_version.get(), 30);
841 }
842
843 #[test]
844 fn from_consensus() {
845 let mut p = NetParameters::default();
846 let mut mp: std::collections::HashMap<String, i32> = std::collections::HashMap::new();
847 mp.insert("bwweightscale".to_string(), 70);
848 mp.insert("min_paths_for_circs_pct".to_string(), 45);
849 mp.insert("im_a_little_teapot".to_string(), 1);
850 mp.insert("circwindow".to_string(), 99999);
851 mp.insert("ExtendByEd25519ID".to_string(), 1);
852
853 let z = p.saturating_update(mp.iter());
854 assert_eq!(z, vec![&String::from("im_a_little_teapot")]);
855
856 assert_eq!(p.bw_weight_scale.get(), 70);
857 assert_eq!(p.min_circuit_path_threshold.as_percent().get(), 45);
858 let b_val: bool = p.extend_by_ed25519_id.into();
859 assert!(b_val);
860 }
861
862 #[test]
863 fn all_parameters() {
864 use std::time::Duration;
865 let mut p = NetParameters::default();
866 let mp = [
867 ("bwweightscale", 10),
868 ("cbtdisabled", 1),
869 ("cbtnummodes", 11),
870 ("cbtrecentcount", 12),
871 ("cbtmaxtimeouts", 13),
872 ("cbtmincircs", 5),
873 ("cbtquantile", 61),
874 ("cbtclosequantile", 15),
875 ("cbtlearntimeout", 1900),
876 ("cbtmintimeout", 2020),
877 ("cbtinitialtimeout", 2050),
878 ("cbttestfreq", 110),
879 ("cbtmaxopencircs", 14),
880 ("circwindow", 999),
881 ("CircuitPriorityHalflifeMsec", 222),
882 ("guard-lifetime-days", 36),
883 ("guard-confirmed-min-lifetime-days", 37),
884 ("guard-internet-likely-down-interval", 38),
885 ("guard-max-sample-size", 39),
886 ("guard-max-sample-threshold", 40),
887 ("guard-min-filtered-sample-size", 41),
888 ("guard-n-primary-guards", 42),
889 ("guard-n-primary-guards-to-use", 43),
890 ("guard-n-primary-dir-guards-to-use", 44),
891 ("guard-nonprimary-guard-connect-timeout", 45),
892 ("guard-nonprimary-guard-idle-timeout", 46),
893 ("guard-remove-unlisted-guards-after-days", 47),
894 ("guard-meaningful-restriction-percent", 12),
895 ("guard-extreme-restriction-percent", 3),
896 ("ExtendByEd25519ID", 0),
897 ("min_paths_for_circs_pct", 51),
898 ("nf_conntimeout_clients", 606),
899 ("nf_ito_low", 1_000),
900 ("nf_ito_high", 20_000),
901 ("nf_ito_low_reduced", 3_000),
902 ("nf_ito_high_reduced", 40_000),
903 ("sendme_accept_min_version", 31),
904 ("sendme_emit_min_version", 32),
905 ];
906 let ignored = p.saturating_update(mp.iter().map(|(a, b)| (a, b)));
907 assert!(ignored.is_empty());
908
909 assert_eq!(p.bw_weight_scale.get(), 10);
910 assert!(bool::from(p.cbt_learning_disabled));
911 assert_eq!(p.cbt_num_xm_modes.get(), 11);
912 assert_eq!(p.cbt_success_count.get(), 12);
913 assert_eq!(p.cbt_max_timeouts.get(), 13);
914 assert_eq!(p.cbt_min_circs_for_estimate.get(), 5);
915 assert_eq!(p.cbt_timeout_quantile.as_percent().get(), 61);
916 assert_eq!(p.cbt_abandon_quantile.as_percent().get(), 15);
917 assert_eq!(p.nf_ito_low.as_millis().get(), 1_000);
918 assert_eq!(p.nf_ito_high.as_millis().get(), 20_000);
919 assert_eq!(p.nf_ito_low_reduced.as_millis().get(), 3_000);
920 assert_eq!(p.nf_ito_high_reduced.as_millis().get(), 40_000);
921 assert_eq!(
922 Duration::try_from(p.unused_client_circ_timeout_while_learning_cbt).unwrap(),
923 Duration::from_secs(1900)
924 );
925 assert_eq!(
926 Duration::try_from(p.cbt_min_timeout).unwrap(),
927 Duration::from_millis(2020)
928 );
929 assert_eq!(
930 Duration::try_from(p.cbt_initial_timeout).unwrap(),
931 Duration::from_millis(2050)
932 );
933 assert_eq!(
934 Duration::try_from(p.cbt_testing_delay).unwrap(),
935 Duration::from_secs(110)
936 );
937 assert_eq!(p.cbt_max_open_circuits_for_testing.get(), 14);
938 assert_eq!(p.circuit_window.get(), 999);
939 assert_eq!(
940 Duration::try_from(p.circuit_priority_half_life).unwrap(),
941 Duration::from_millis(222)
942 );
943 assert!(!bool::from(p.extend_by_ed25519_id));
944 assert_eq!(p.min_circuit_path_threshold.as_percent().get(), 51);
945 assert_eq!(
946 Duration::try_from(p.unused_client_circ_timeout).unwrap(),
947 Duration::from_secs(606)
948 );
949 assert_eq!(p.sendme_accept_min_version.get(), 31);
950 assert_eq!(p.sendme_emit_min_version.get(), 32);
951
952 assert_eq!(
953 Duration::try_from(p.guard_lifetime_unconfirmed).unwrap(),
954 Duration::from_secs(86400 * 36)
955 );
956 assert_eq!(
957 Duration::try_from(p.guard_lifetime_confirmed).unwrap(),
958 Duration::from_secs(86400 * 37)
959 );
960 assert_eq!(
961 Duration::try_from(p.guard_internet_likely_down).unwrap(),
962 Duration::from_secs(38)
963 );
964 assert_eq!(p.guard_max_sample_size.get(), 39);
965 assert_eq!(p.guard_max_sample_threshold.as_percent().get(), 40);
966 assert_eq!(p.guard_filtered_min_sample_size.get(), 41);
967 assert_eq!(p.guard_n_primary.get(), 42);
968 assert_eq!(p.guard_use_parallelism.get(), 43);
969 assert_eq!(p.guard_dir_use_parallelism.get(), 44);
970 assert_eq!(
971 Duration::try_from(p.guard_nonprimary_connect_timeout).unwrap(),
972 Duration::from_secs(45)
973 );
974 assert_eq!(
975 Duration::try_from(p.guard_nonprimary_idle_timeout).unwrap(),
976 Duration::from_secs(46)
977 );
978 assert_eq!(
979 Duration::try_from(p.guard_remove_unlisted_after).unwrap(),
980 Duration::from_secs(86400 * 47)
981 );
982 assert_eq!(p.guard_meaningful_restriction.as_percent().get(), 12);
983 assert_eq!(p.guard_extreme_restriction.as_percent().get(), 3);
984 }
985}