use tor_units::{
BoundedInt32, IntegerDays, IntegerMilliseconds, IntegerMinutes, IntegerSeconds, Percentage,
SendMeVersion,
};
pub const CHANNEL_PADDING_TIMEOUT_UPPER_BOUND: i32 = 60_000;
pub trait FromInt32Saturating {
fn from_saturating(val: i32) -> Self;
fn from_checked(val: i32) -> Result<Self, tor_units::Error>
where
Self: Sized;
}
impl FromInt32Saturating for i32 {
fn from_saturating(val: i32) -> Self {
val
}
fn from_checked(val: i32) -> Result<Self, tor_units::Error>
where
Self: Sized,
{
Ok(val)
}
}
impl<const L: i32, const H: i32> FromInt32Saturating for BoundedInt32<L, H> {
fn from_saturating(val: i32) -> Self {
Self::saturating_new(val)
}
fn from_checked(val: i32) -> Result<Self, tor_units::Error>
where
Self: Sized,
{
Self::checked_new(val)
}
}
impl<T: Copy + Into<f64> + FromInt32Saturating> FromInt32Saturating for Percentage<T> {
fn from_saturating(val: i32) -> Self {
Self::new(T::from_saturating(val))
}
fn from_checked(val: i32) -> Result<Self, tor_units::Error>
where
Self: Sized,
{
Ok(Self::new(T::from_checked(val)?))
}
}
impl<T: FromInt32Saturating + TryInto<u64>> FromInt32Saturating for IntegerMilliseconds<T> {
fn from_saturating(val: i32) -> Self {
Self::new(T::from_saturating(val))
}
fn from_checked(val: i32) -> Result<Self, tor_units::Error>
where
Self: Sized,
{
Ok(Self::new(T::from_checked(val)?))
}
}
impl<T: FromInt32Saturating + TryInto<u64>> FromInt32Saturating for IntegerSeconds<T> {
fn from_saturating(val: i32) -> Self {
Self::new(T::from_saturating(val))
}
fn from_checked(val: i32) -> Result<Self, tor_units::Error>
where
Self: Sized,
{
Ok(Self::new(T::from_checked(val)?))
}
}
impl<T: FromInt32Saturating + TryInto<u64>> FromInt32Saturating for IntegerMinutes<T> {
fn from_saturating(val: i32) -> Self {
Self::new(T::from_saturating(val))
}
fn from_checked(val: i32) -> Result<Self, tor_units::Error>
where
Self: Sized,
{
Ok(Self::new(T::from_checked(val)?))
}
}
impl<T: FromInt32Saturating + TryInto<u64>> FromInt32Saturating for IntegerDays<T> {
fn from_saturating(val: i32) -> Self {
Self::new(T::from_saturating(val))
}
fn from_checked(val: i32) -> Result<Self, tor_units::Error>
where
Self: Sized,
{
Ok(Self::new(T::from_checked(val)?))
}
}
impl FromInt32Saturating for SendMeVersion {
fn from_saturating(val: i32) -> Self {
Self::new(val.clamp(0, 255) as u8)
}
fn from_checked(val: i32) -> Result<Self, tor_units::Error>
where
Self: Sized,
{
let val = BoundedInt32::<0, 255>::checked_new(val)?;
Ok(Self::new(val.get() as u8))
}
}
macro_rules! declare_net_parameters {
{
$(#[$s_meta:meta])* $s_v:vis struct $s_name:ident {
$(
$(#[$p_meta:meta])* $p_v:vis
$p_name:ident : $p_type:ty
= ($p_dflt:expr) from $p_string:literal
),*
$( , )?
}
} =>
{
$(#[$s_meta])* $s_v struct $s_name {
$(
$(#[$p_meta])* $p_v $p_name : $p_type
),*
}
impl $s_name {
fn default_values() -> Result<Self, tor_units::Error> {
Ok(Self {
$( $p_name : $p_dflt.try_into()? ),*
})
}
fn set_saturating(&mut self, key: &str, val: i32) -> bool {
match key {
$( $p_string => self.$p_name = {
type T = $p_type;
match T::from_checked(val) {
Ok(v) => v,
Err(e) => {
tracing::warn!("For key {key}, clamping out of range value: {e:?}");
T::from_saturating(val)
}
}
}, )*
_ => return false,
}
true
}
}
}
}
declare_net_parameters! {
#[derive(Clone, Debug)]
#[non_exhaustive]
pub struct NetParameters {
pub bw_weight_scale: BoundedInt32<1, { i32::MAX }> = (10_000)
from "bwweightscale",
pub cbt_learning_disabled: BoundedInt32<0, 1> = (0)
from "cbtdisabled",
pub cbt_num_xm_modes: BoundedInt32<1, 20> = (10)
from "cbtnummodes",
pub cbt_success_count: BoundedInt32<3, 1_000> = (20)
from "cbtrecentcount",
pub cbt_max_timeouts: BoundedInt32<3, 10_000> = (18)
from "cbtmaxtimeouts",
pub cbt_min_circs_for_estimate: BoundedInt32<1, 10_000> = (100)
from "cbtmincircs",
pub cbt_timeout_quantile: Percentage<BoundedInt32<10, 99>> = (80)
from "cbtquantile",
pub cbt_abandon_quantile: Percentage<BoundedInt32<10, 99>> = (99)
from "cbtclosequantile",
pub cbt_min_timeout: IntegerMilliseconds<BoundedInt32<10, { i32::MAX }>> = (10)
from "cbtmintimeout",
pub cbt_initial_timeout: IntegerMilliseconds<BoundedInt32<10, { i32::MAX }>> = (60_000)
from "cbtinitialtimeout",
pub cbt_testing_delay: IntegerSeconds<BoundedInt32<1, { i32::MAX }>> = (10)
from "cbttestfreq",
pub cbt_max_open_circuits_for_testing: BoundedInt32<0, 14> = (10)
from "cbtmaxopencircs",
pub cc_alg: BoundedInt32<0, 2> = (2)
from "cc_alg",
pub cc_cwnd_full_gap: BoundedInt32<0, { i16::MAX as i32 }> = (4444)
from "cc_cwnd_full_gap",
pub cc_cwnd_full_minpct: Percentage<BoundedInt32<0, 100>> = (25)
from "cc_cwnd_full_minpct",
pub cc_cwnd_full_per_cwnd: BoundedInt32<0, 1> = (1)
from "cc_cwnd_full_per_cwnd",
pub cc_cwnd_init: BoundedInt32<31, 10_000> = (4 * 31)
from "cc_cwnd_init",
pub cc_cwnd_inc_pct_ss: Percentage<BoundedInt32<1, 500>> = (50)
from "cc_cwnd_inc_pct_ss",
pub cc_cwnd_inc: BoundedInt32<1, 1000> = (31)
from "cc_cwnd_inc",
pub cc_cwnd_inc_rate: BoundedInt32<1, 250> = (1)
from "cc_cwnd_inc_rate",
pub cc_cwnd_min: BoundedInt32<31, 1000> = (31)
from "cc_cwnd_min",
pub cc_cwnd_max: BoundedInt32<500, { i32::MAX }> = (i32::MAX)
from "cc_cwnd_max",
pub cc_ewma_cwnd_pct: Percentage<BoundedInt32<1, 255>> = (50)
from "cc_ewma_cwnd_pct",
pub cc_ewma_max: BoundedInt32<2, { i32::MAX }> = (10)
from "cc_ewma_max",
pub cc_ewma_ss: BoundedInt32<2, { i32::MAX }> = (2)
from "cc_ewma_ss",
pub cc_rtt_reset_pct: Percentage<BoundedInt32<0, 100>> = (100)
from "cc_rtt_reset_pct",
pub cc_sendme_inc: BoundedInt32<1, 254> = (31)
from "cc_sendme_inc",
pub cc_ss_max: BoundedInt32<500, { i32::MAX }> = (5000)
from "cc_ss_max",
pub cc_vegas_alpha_exit: BoundedInt32<0, 1000> = (3 * 62)
from "cc_vegas_alpha_exit",
pub cc_vegas_beta_exit: BoundedInt32<0, 1000> = (4 * 62)
from "cc_vegas_beta_exit",
pub cc_vegas_delta_exit: BoundedInt32<0, 1000> = (5 * 62)
from "cc_vegas_delta_exit",
pub cc_vegas_gamma_exit: BoundedInt32<0, 1000> = (3 * 62)
from "cc_vegas_gamma_exit",
pub cc_vegas_alpha_onion: BoundedInt32<0, 1000> = (3 * 62)
from "cc_vegas_alpha_onion",
pub cc_vegas_beta_onion: BoundedInt32<0, 1000> = (6 * 62)
from "cc_vegas_beta_onion",
pub cc_vegas_delta_onion: BoundedInt32<0, 1000> = (7 * 62)
from "cc_vegas_delta_onion",
pub cc_vegas_gamma_onion: BoundedInt32<0, 1000> = (4 * 62)
from "cc_vegas_gamma_onion",
pub cc_vegas_sscap_exit: BoundedInt32<100, { i32::MAX }> = (600)
from "cc_sscap_exit",
pub cc_vegas_sscap_onion: BoundedInt32<100, { i32::MAX }> = (475)
from "cc_sscap_onion",
pub cc_xoff_client: BoundedInt32<1, 10_000> = (500)
from "cc_xoff_client",
pub cc_xoff_exit: BoundedInt32<1, 10_000> = (500)
from "cc_xoff_exit",
pub cc_xon_rate: BoundedInt32<1, 5000> = (500)
from "cc_xon_rate",
pub cc_xon_change_pct: BoundedInt32<1, 99> = (25)
from "cc_xon_change_pct",
pub cc_xon_ewma_cnt: BoundedInt32<2, 100> = (2)
from "cc_xon_ewma_cnt",
pub circuit_window: BoundedInt32<100, 1000> = (1_000)
from "circwindow",
pub circuit_priority_half_life: IntegerMilliseconds<BoundedInt32<1, { i32::MAX }>> = (30_000)
from "CircuitPriorityHalflifeMsec",
pub extend_by_ed25519_id: BoundedInt32<0, 1> = (0)
from "ExtendByEd25519ID",
pub guard_meaningful_restriction: Percentage<BoundedInt32<1,100>> = (20)
from "guard-meaningful-restriction-percent",
pub guard_extreme_restriction: Percentage<BoundedInt32<1,100>> = (1)
from "guard-extreme-restriction-percent",
pub guard_lifetime_unconfirmed: IntegerDays<BoundedInt32<1, 3650>> = (120)
from "guard-lifetime-days",
pub guard_lifetime_confirmed: IntegerDays<BoundedInt32<1, 3650>> = (60)
from "guard-confirmed-min-lifetime-days",
pub guard_internet_likely_down: IntegerSeconds<BoundedInt32<1, {i32::MAX}>> = (600)
from "guard-internet-likely-down-interval",
pub guard_max_sample_size: BoundedInt32<1, {i32::MAX}> = (60)
from "guard-max-sample-size",
pub guard_max_sample_threshold: Percentage<BoundedInt32<1,100>> = (20)
from "guard-max-sample-threshold",
pub guard_filtered_min_sample_size: BoundedInt32<1,{i32::MAX}> = (20)
from "guard-min-filtered-sample-size",
pub guard_n_primary: BoundedInt32<1,{i32::MAX}> = (3)
from "guard-n-primary-guards",
pub guard_use_parallelism: BoundedInt32<1, {i32::MAX}> = (1)
from "guard-n-primary-guards-to-use",
pub guard_dir_use_parallelism: BoundedInt32<1, {i32::MAX}> = (3)
from "guard-n-primary-dir-guards-to-use",
pub guard_nonprimary_connect_timeout: IntegerSeconds<BoundedInt32<1,{i32::MAX}>> = (15)
from "guard-nonprimary-guard-connect-timeout",
pub guard_nonprimary_idle_timeout: IntegerSeconds<BoundedInt32<1,{i32::MAX}>> = (600)
from "guard-nonprimary-guard-idle-timeout",
pub guard_remove_unlisted_after: IntegerDays<BoundedInt32<1,3650>> = (20)
from "guard-remove-unlisted-guards-after-days",
pub min_circuit_path_threshold: Percentage<BoundedInt32<25, 95>> = (60)
from "min_paths_for_circs_pct",
pub nf_ito_low: IntegerMilliseconds<BoundedInt32<0, CHANNEL_PADDING_TIMEOUT_UPPER_BOUND>> = (1500)
from "nf_ito_low",
pub nf_ito_high: IntegerMilliseconds<BoundedInt32<0, CHANNEL_PADDING_TIMEOUT_UPPER_BOUND>> = (9500)
from "nf_ito_high",
pub nf_ito_low_reduced: IntegerMilliseconds<BoundedInt32<0, CHANNEL_PADDING_TIMEOUT_UPPER_BOUND>> = (9000)
from "nf_ito_low_reduced",
pub nf_ito_high_reduced: IntegerMilliseconds<BoundedInt32<0, CHANNEL_PADDING_TIMEOUT_UPPER_BOUND>> = (14000)
from "nf_ito_high_reduced",
pub sendme_accept_min_version: SendMeVersion = (0)
from "sendme_accept_min_version",
pub sendme_emit_min_version: SendMeVersion = (0)
from "sendme_emit_min_version",
pub unused_client_circ_timeout: IntegerSeconds<BoundedInt32<60, 86_400>> = (30*60)
from "nf_conntimeout_clients",
pub unused_client_circ_timeout_while_learning_cbt: IntegerSeconds<BoundedInt32<10, 60_000>> = (3*60)
from "cbtlearntimeout",
pub hs_introcirc_requests_min: BoundedInt32<0, {i32::MAX}> = (16384)
from "hs_intro_min_introduce2",
pub hs_introcirc_requests_max: BoundedInt32<0, {i32::MAX}> = (32768)
from "hs_intro_max_introduce2",
pub hs_intro_min_lifetime: IntegerSeconds<BoundedInt32<0, {i32::MAX}>> = (18 * 60 * 60)
from "hs_intro_min_lifetime",
pub hs_intro_max_lifetime: IntegerSeconds<BoundedInt32<0, {i32::MAX}>> = (24 * 60 * 60)
from "hs_intro_max_lifetime",
pub hs_intro_num_extra_intropoints: BoundedInt32<0, 128> = (2)
from "hs_intro_num_extra",
pub hsdir_dl_max_reply_cells: BoundedInt32<2, 2304> = (110)
from "hsdir_dl_max_reply_cells",
pub hsdir_ul_max_reply_cells: BoundedInt32<2, 1024> = (8)
from "hsdir_ul_max_reply_cells",
pub hsdir_timeperiod_length: IntegerMinutes<BoundedInt32<5, 14400>> = (1440)
from "hsdir_interval",
pub hsdir_n_replicas: BoundedInt32<1, 16> = (2)
from "hsdir_n_replicas",
pub hsdir_spread_fetch: BoundedInt32<1, 128> = (3)
from "hsdir_spread_fetch",
pub hsdir_spread_store: BoundedInt32<1,128> = (4)
from "hsdir_spread_store",
pub hsdir_max_desc_size: BoundedInt32<1, {i32::MAX}> = (50_000)
from "HSV3MaxDescriptorSize",
pub hs_service_rendezvous_failures_max: BoundedInt32<1, 10> = (2)
from "hs_service_max_rdv_failures",
pub hs_intro_dos_enabled: BoundedInt32<0, 1> = (0)
from "HiddenServiceEnableIntroDoSDefense",
pub hs_intro_dos_max_burst: BoundedInt32<0, {i32::MAX}> = (200)
from "HiddenServiceEnableIntroDoSBurstPerSec",
pub hs_intro_dos_rate: BoundedInt32<0, {i32::MAX}> = (25)
from "HiddenServiceEnableIntroDoSRatePerSec",
pub hs_pow_v1_max_effort: BoundedInt32<0, {i32::MAX}> = (10_000)
from "HiddenServiceProofOfWorkV1MaxEffort",
pub hs_pow_v1_service_intro_timeout: IntegerSeconds<BoundedInt32<1, {i32::MAX}>> = (300)
from "HiddenServiceProofOfWorkV1ServiceIntroTimeoutSeconds",
pub hs_pow_v1_default_decay_adjustment: Percentage<BoundedInt32<0, 99>> = (0)
from "HiddenServiceProofOfWorkV1ServiceDefaultDecayAdjustment",
pub vanguards_enabled: BoundedInt32<0, 2> = (1)
from "vanguards-enabled",
pub vanguards_hs_service: BoundedInt32<0, 2> = (2)
from "vanguards-hs-service",
pub guard_hs_l2_number: BoundedInt32<1, {i32::MAX}> = (4)
from "guard-hs-l2-number",
pub guard_hs_l2_lifetime_min: IntegerSeconds<BoundedInt32<1, {i32::MAX}>> = (86400)
from "guard-hs-l2-lifetime-min",
pub guard_hs_l2_lifetime_max: IntegerSeconds<BoundedInt32<1, {i32::MAX}>> = (1036800)
from "guard-hs-l2-lifetime-max",
pub guard_hs_l3_number: BoundedInt32<1, {i32::MAX}> = (8)
from "guard-hs-l3-number",
pub guard_hs_l3_lifetime_min: IntegerSeconds<BoundedInt32<1, {i32::MAX}>> = (3600)
from "guard-hs-l3-lifetime-min",
pub guard_hs_l3_lifetime_max: IntegerSeconds<BoundedInt32<1, {i32::MAX}>> = (172800)
from "guard-hs-l3-lifetime-max",
pub kist_enabled: BoundedInt32<0, 1> = (0)
from "kist-enabled",
pub kist_tcp_notsent_lowat: BoundedInt32<1, {i32::MAX}> = (1)
from "kist-tcp-notsent-lowat",
pub use_family_lists: BoundedInt32<0,1> = (1)
from "use-family-lists",
pub use_family_ids: BoundedInt32<0,1> = (1)
from "use-family-ids",
}
}
impl Default for NetParameters {
fn default() -> Self {
NetParameters::default_values().expect("Default parameters were out-of-bounds")
}
}
impl AsRef<NetParameters> for NetParameters {
fn as_ref(&self) -> &NetParameters {
self
}
}
impl NetParameters {
pub fn from_map(p: &tor_netdoc::doc::netstatus::NetParams<i32>) -> Self {
let mut params = NetParameters::default();
let unrecognized = params.saturating_update(p.iter());
for u in unrecognized {
tracing::debug!("Ignored unrecognized net param: {u}");
}
params
}
pub(crate) fn saturating_update<'a, S>(
&mut self,
iter: impl Iterator<Item = (S, &'a i32)>,
) -> Vec<S>
where
S: AsRef<str>,
{
let mut unrecognized = Vec::new();
for (k, v) in iter {
if !self.set_saturating(k.as_ref(), *v) {
unrecognized.push(k);
}
}
unrecognized
}
}
#[cfg(test)]
#[allow(clippy::many_single_char_names)]
#[allow(clippy::cognitive_complexity)]
mod test {
#![allow(clippy::bool_assert_comparison)]
#![allow(clippy::clone_on_copy)]
#![allow(clippy::dbg_macro)]
#![allow(clippy::mixed_attributes_style)]
#![allow(clippy::print_stderr)]
#![allow(clippy::print_stdout)]
#![allow(clippy::single_char_pattern)]
#![allow(clippy::unwrap_used)]
#![allow(clippy::unchecked_time_subtraction)]
#![allow(clippy::useless_vec)]
#![allow(clippy::needless_pass_by_value)]
use super::*;
use std::string::String;
#[test]
fn empty_list() {
let mut x = NetParameters::default();
let y = Vec::<(&String, &i32)>::new();
let u = x.saturating_update(y.into_iter());
assert!(u.is_empty());
}
#[test]
fn unknown_parameter() {
let mut x = NetParameters::default();
let mut y = Vec::<(&String, &i32)>::new();
let k = &String::from("This_is_not_a_real_key");
let v = &456;
y.push((k, v));
let u = x.saturating_update(y.into_iter());
assert_eq!(u, vec![&String::from("This_is_not_a_real_key")]);
}
#[test]
fn single_good_parameter() {
let mut x = NetParameters::default();
let mut y = Vec::<(&String, &i32)>::new();
let k = &String::from("min_paths_for_circs_pct");
let v = &54;
y.push((k, v));
let z = x.saturating_update(y.into_iter());
assert!(z.is_empty());
assert_eq!(x.min_circuit_path_threshold.as_percent().get(), 54);
}
#[test]
fn multiple_good_parameters() {
let mut x = NetParameters::default();
let mut y = Vec::<(&String, &i32)>::new();
let k = &String::from("min_paths_for_circs_pct");
let v = &54;
y.push((k, v));
let k = &String::from("circwindow");
let v = &900;
y.push((k, v));
let z = x.saturating_update(y.into_iter());
assert!(z.is_empty());
assert_eq!(x.min_circuit_path_threshold.as_percent().get(), 54);
assert_eq!(x.circuit_window.get(), 900);
}
#[test]
fn good_out_of_range() {
let mut x = NetParameters::default();
let mut y = Vec::<(&String, &i32)>::new();
let k = &String::from("sendme_accept_min_version");
let v = &30;
y.push((k, v));
let k = &String::from("min_paths_for_circs_pct");
let v = &255;
y.push((k, v));
let z = x.saturating_update(y.into_iter());
assert!(z.is_empty());
assert_eq!(x.sendme_accept_min_version.get(), 30);
assert_eq!(x.min_circuit_path_threshold.as_percent().get(), 95);
}
#[test]
fn good_invalid_rep() {
let mut x = NetParameters::default();
let mut y = Vec::<(&String, &i32)>::new();
let k = &String::from("sendme_accept_min_version");
let v = &30;
y.push((k, v));
let k = &String::from("min_paths_for_circs_pct");
let v = &9000;
y.push((k, v));
let z = x.saturating_update(y.into_iter());
assert!(z.is_empty());
assert_eq!(x.sendme_accept_min_version.get(), 30);
assert_eq!(x.min_circuit_path_threshold.as_percent().get(), 95);
}
#[test]
fn good_unknown() {
let mut x = NetParameters::default();
let mut y = Vec::<(&String, &i32)>::new();
let k = &String::from("sendme_accept_min_version");
let v = &30;
y.push((k, v));
let k = &String::from("not_a_real_parameter");
let v = &9000;
y.push((k, v));
let z = x.saturating_update(y.into_iter());
assert_eq!(z, vec![&String::from("not_a_real_parameter")]);
assert_eq!(x.sendme_accept_min_version.get(), 30);
}
#[test]
fn from_consensus() {
let mut p = NetParameters::default();
let mut mp: std::collections::HashMap<String, i32> = std::collections::HashMap::new();
mp.insert("bwweightscale".to_string(), 70);
mp.insert("min_paths_for_circs_pct".to_string(), 45);
mp.insert("im_a_little_teapot".to_string(), 1);
mp.insert("circwindow".to_string(), 99999);
mp.insert("ExtendByEd25519ID".to_string(), 1);
let z = p.saturating_update(mp.iter());
assert_eq!(z, vec![&String::from("im_a_little_teapot")]);
assert_eq!(p.bw_weight_scale.get(), 70);
assert_eq!(p.min_circuit_path_threshold.as_percent().get(), 45);
let b_val: bool = p.extend_by_ed25519_id.into();
assert!(b_val);
}
#[test]
fn all_parameters() {
use std::time::Duration;
let mut p = NetParameters::default();
let mp = [
("bwweightscale", 10),
("cbtdisabled", 1),
("cbtnummodes", 11),
("cbtrecentcount", 12),
("cbtmaxtimeouts", 13),
("cbtmincircs", 5),
("cbtquantile", 61),
("cbtclosequantile", 15),
("cbtlearntimeout", 1900),
("cbtmintimeout", 2020),
("cbtinitialtimeout", 2050),
("cbttestfreq", 110),
("cbtmaxopencircs", 14),
("circwindow", 999),
("CircuitPriorityHalflifeMsec", 222),
("guard-lifetime-days", 36),
("guard-confirmed-min-lifetime-days", 37),
("guard-internet-likely-down-interval", 38),
("guard-max-sample-size", 39),
("guard-max-sample-threshold", 40),
("guard-min-filtered-sample-size", 41),
("guard-n-primary-guards", 42),
("guard-n-primary-guards-to-use", 43),
("guard-n-primary-dir-guards-to-use", 44),
("guard-nonprimary-guard-connect-timeout", 45),
("guard-nonprimary-guard-idle-timeout", 46),
("guard-remove-unlisted-guards-after-days", 47),
("guard-meaningful-restriction-percent", 12),
("guard-extreme-restriction-percent", 3),
("ExtendByEd25519ID", 0),
("min_paths_for_circs_pct", 51),
("nf_conntimeout_clients", 606),
("nf_ito_low", 1_000),
("nf_ito_high", 20_000),
("nf_ito_low_reduced", 3_000),
("nf_ito_high_reduced", 40_000),
("sendme_accept_min_version", 31),
("sendme_emit_min_version", 32),
];
let ignored = p.saturating_update(mp.iter().map(|(a, b)| (a, b)));
assert!(ignored.is_empty());
assert_eq!(p.bw_weight_scale.get(), 10);
assert!(bool::from(p.cbt_learning_disabled));
assert_eq!(p.cbt_num_xm_modes.get(), 11);
assert_eq!(p.cbt_success_count.get(), 12);
assert_eq!(p.cbt_max_timeouts.get(), 13);
assert_eq!(p.cbt_min_circs_for_estimate.get(), 5);
assert_eq!(p.cbt_timeout_quantile.as_percent().get(), 61);
assert_eq!(p.cbt_abandon_quantile.as_percent().get(), 15);
assert_eq!(p.nf_ito_low.as_millis().get(), 1_000);
assert_eq!(p.nf_ito_high.as_millis().get(), 20_000);
assert_eq!(p.nf_ito_low_reduced.as_millis().get(), 3_000);
assert_eq!(p.nf_ito_high_reduced.as_millis().get(), 40_000);
assert_eq!(
Duration::try_from(p.unused_client_circ_timeout_while_learning_cbt).unwrap(),
Duration::from_secs(1900)
);
assert_eq!(
Duration::try_from(p.cbt_min_timeout).unwrap(),
Duration::from_millis(2020)
);
assert_eq!(
Duration::try_from(p.cbt_initial_timeout).unwrap(),
Duration::from_millis(2050)
);
assert_eq!(
Duration::try_from(p.cbt_testing_delay).unwrap(),
Duration::from_secs(110)
);
assert_eq!(p.cbt_max_open_circuits_for_testing.get(), 14);
assert_eq!(p.circuit_window.get(), 999);
assert_eq!(
Duration::try_from(p.circuit_priority_half_life).unwrap(),
Duration::from_millis(222)
);
assert!(!bool::from(p.extend_by_ed25519_id));
assert_eq!(p.min_circuit_path_threshold.as_percent().get(), 51);
assert_eq!(
Duration::try_from(p.unused_client_circ_timeout).unwrap(),
Duration::from_secs(606)
);
assert_eq!(p.sendme_accept_min_version.get(), 31);
assert_eq!(p.sendme_emit_min_version.get(), 32);
assert_eq!(
Duration::try_from(p.guard_lifetime_unconfirmed).unwrap(),
Duration::from_secs(86400 * 36)
);
assert_eq!(
Duration::try_from(p.guard_lifetime_confirmed).unwrap(),
Duration::from_secs(86400 * 37)
);
assert_eq!(
Duration::try_from(p.guard_internet_likely_down).unwrap(),
Duration::from_secs(38)
);
assert_eq!(p.guard_max_sample_size.get(), 39);
assert_eq!(p.guard_max_sample_threshold.as_percent().get(), 40);
assert_eq!(p.guard_filtered_min_sample_size.get(), 41);
assert_eq!(p.guard_n_primary.get(), 42);
assert_eq!(p.guard_use_parallelism.get(), 43);
assert_eq!(p.guard_dir_use_parallelism.get(), 44);
assert_eq!(
Duration::try_from(p.guard_nonprimary_connect_timeout).unwrap(),
Duration::from_secs(45)
);
assert_eq!(
Duration::try_from(p.guard_nonprimary_idle_timeout).unwrap(),
Duration::from_secs(46)
);
assert_eq!(
Duration::try_from(p.guard_remove_unlisted_after).unwrap(),
Duration::from_secs(86400 * 47)
);
assert_eq!(p.guard_meaningful_restriction.as_percent().get(), 12);
assert_eq!(p.guard_extreme_restriction.as_percent().get(), 3);
}
}