diff --git a/clients/native/src/client/config/mod.rs b/clients/native/src/client/config/mod.rs index 91eb21875b..6e7a41bc5d 100644 --- a/clients/native/src/client/config/mod.rs +++ b/clients/native/src/client/config/mod.rs @@ -25,6 +25,7 @@ pub mod old_config_v1_1_13; pub mod old_config_v1_1_20; pub mod old_config_v1_1_20_2; pub mod old_config_v1_1_33; +pub mod old_config_v1_1_54; mod persistence; mod template; diff --git a/clients/native/src/client/config/old_config_v1_1_33.rs b/clients/native/src/client/config/old_config_v1_1_33.rs index 02ed7218d1..75f36202d5 100644 --- a/clients/native/src/client/config/old_config_v1_1_33.rs +++ b/clients/native/src/client/config/old_config_v1_1_33.rs @@ -2,7 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 use crate::client::config::persistence::ClientPaths; -use crate::client::config::{default_config_filepath, Config, Socket, SocketType}; +use crate::client::config::{default_config_filepath, Socket, SocketType}; use crate::error::ClientError; use nym_bin_common::logging::LoggingSettings; use nym_client_core::config::disk_persistence::old_v1_1_33::CommonClientPathsV1_1_33; @@ -14,6 +14,8 @@ use std::io; use std::net::{IpAddr, Ipv4Addr}; use std::path::Path; +use super::old_config_v1_1_54::ConfigV1_1_54; + #[derive(Debug, Deserialize, PartialEq, Eq, Serialize, Clone)] pub struct ClientPathsV1_1_33 { #[serde(flatten)] @@ -33,6 +35,21 @@ pub struct ConfigV1_1_33 { pub logging: LoggingSettings, } +impl TryFrom for ConfigV1_1_54 { + type Error = ClientError; + + fn try_from(value: ConfigV1_1_33) -> Result { + Ok(ConfigV1_1_54 { + base: value.base.into(), + socket: value.socket.into(), + storage_paths: ClientPaths { + common_paths: value.storage_paths.common_paths.upgrade_default()?, + }, + logging: value.logging, + }) + } +} + impl ConfigV1_1_33 { pub fn read_from_toml_file>(path: P) -> io::Result { read_config_from_toml_file(path) @@ -41,17 +58,6 @@ impl ConfigV1_1_33 { pub fn read_from_default_path>(id: P) -> io::Result { Self::read_from_toml_file(default_config_filepath(id)) } - - pub fn try_upgrade(self) -> Result { - Ok(Config { - base: self.base.into(), - socket: self.socket.into(), - storage_paths: ClientPaths { - common_paths: self.storage_paths.common_paths.upgrade_default()?, - }, - logging: self.logging, - }) - } } #[derive(Debug, Deserialize, PartialEq, Eq, Serialize, Clone, Copy)] diff --git a/clients/native/src/client/config/old_config_v1_1_54.rs b/clients/native/src/client/config/old_config_v1_1_54.rs new file mode 100644 index 0000000000..b3eb36080a --- /dev/null +++ b/clients/native/src/client/config/old_config_v1_1_54.rs @@ -0,0 +1,41 @@ +use std::{io, path::Path}; + +use nym_bin_common::logging::LoggingSettings; +use nym_client_core::config::old_config_v1_1_54::ConfigV1_1_54 as BaseConfigV1_1_54; +use nym_config::read_config_from_toml_file; +use serde::{Deserialize, Serialize}; + +use crate::error::ClientError; + +use super::{default_config_filepath, persistence::ClientPaths, Config, Socket}; + +#[derive(Debug, Deserialize, PartialEq, Serialize, Clone)] +pub struct ConfigV1_1_54 { + #[serde(flatten)] + pub base: BaseConfigV1_1_54, + + pub socket: Socket, + + pub storage_paths: ClientPaths, + + pub logging: LoggingSettings, +} + +impl ConfigV1_1_54 { + pub fn read_from_toml_file>(path: P) -> io::Result { + read_config_from_toml_file(path) + } + + pub fn read_from_default_path>(id: P) -> io::Result { + Self::read_from_toml_file(default_config_filepath(id)) + } + + pub fn try_upgrade(self) -> Result { + Ok(Config { + base: self.base.into(), + socket: self.socket, + storage_paths: self.storage_paths, + logging: self.logging, + }) + } +} diff --git a/clients/native/src/client/config/template.rs b/clients/native/src/client/config/template.rs index 922f95b63c..1c5dfcf0b8 100644 --- a/clients/native/src/client/config/template.rs +++ b/clients/native/src/client/config/template.rs @@ -92,10 +92,6 @@ host = '{{ socket.host }}' [debug] -[debug.traffic] -average_packet_delay = '{{ debug.traffic.average_packet_delay }}' -message_sending_average_delay = '{{ debug.traffic.message_sending_average_delay }}' - [debug.acknowledgements] average_ack_delay = '{{ debug.acknowledgements.average_ack_delay }}' diff --git a/clients/native/src/commands/mod.rs b/clients/native/src/commands/mod.rs index 4be73f95ca..5ab7a7b989 100644 --- a/clients/native/src/commands/mod.rs +++ b/clients/native/src/commands/mod.rs @@ -5,6 +5,7 @@ use crate::client::config::old_config_v1_1_13::OldConfigV1_1_13; use crate::client::config::old_config_v1_1_20::ConfigV1_1_20; use crate::client::config::old_config_v1_1_20_2::ConfigV1_1_20_2; use crate::client::config::old_config_v1_1_33::ConfigV1_1_33; +use crate::client::config::old_config_v1_1_54::ConfigV1_1_54; use crate::client::config::{BaseClientConfig, Config}; use crate::commands::ecash::Ecash; use crate::error::ClientError; @@ -177,7 +178,8 @@ async fn try_upgrade_v1_1_13_config(id: &str) -> Result { let updated_step2: ConfigV1_1_20_2 = updated_step1.into(); let (updated_step3, gateway_config) = updated_step2.upgrade()?; let old_paths = updated_step3.storage_paths.clone(); - let updated = updated_step3.try_upgrade()?; + let updated_step4: ConfigV1_1_54 = updated_step3.try_into()?; + let updated = updated_step4.try_upgrade()?; v1_1_33::migrate_gateway_details( &old_paths.common_paths, @@ -205,7 +207,8 @@ async fn try_upgrade_v1_1_20_config(id: &str) -> Result { let updated_step1: ConfigV1_1_20_2 = old_config.into(); let (updated_step2, gateway_config) = updated_step1.upgrade()?; let old_paths = updated_step2.storage_paths.clone(); - let updated = updated_step2.try_upgrade()?; + let updated_step3: ConfigV1_1_54 = updated_step2.try_into()?; + let updated = updated_step3.try_upgrade()?; v1_1_33::migrate_gateway_details( &old_paths.common_paths, @@ -229,7 +232,8 @@ async fn try_upgrade_v1_1_20_2_config(id: &str) -> Result { let (updated_step1, gateway_config) = old_config.upgrade()?; let old_paths = updated_step1.storage_paths.clone(); - let updated = updated_step1.try_upgrade()?; + let updated_step2: ConfigV1_1_54 = updated_step1.try_into()?; + let updated = updated_step2.try_upgrade()?; v1_1_33::migrate_gateway_details( &old_paths.common_paths, @@ -252,7 +256,8 @@ async fn try_upgrade_v1_1_33_config(id: &str) -> Result { info!("It is going to get updated to the current specification."); let old_paths = old_config.storage_paths.clone(); - let updated = old_config.try_upgrade()?; + let updated_step1: ConfigV1_1_54 = old_config.try_into()?; + let updated = updated_step1.try_upgrade()?; v1_1_33::migrate_gateway_details( &old_paths.common_paths, @@ -265,6 +270,22 @@ async fn try_upgrade_v1_1_33_config(id: &str) -> Result { Ok(true) } +async fn try_upgrade_v1_1_54_config(id: &str) -> Result { + // explicitly load it as v1.1.54 (which is incompatible with the current one, i.e. +1.1.55) + let Ok(old_config) = ConfigV1_1_54::read_from_default_path(id) else { + // if we failed to load it, there might have been nothing to upgrade + // or maybe it was an even older file. in either way. just ignore it and carry on with our day + return Ok(false); + }; + info!("It seems the client is using <= v1.1.54 config template."); + info!("It is going to get updated to the current specification."); + + let updated = old_config.try_upgrade()?; + + updated.save_to_default_location()?; + Ok(true) +} + async fn try_upgrade_config(id: &str) -> Result<(), ClientError> { if try_upgrade_v1_1_13_config(id).await? { return Ok(()); @@ -278,6 +299,9 @@ async fn try_upgrade_config(id: &str) -> Result<(), ClientError> { if try_upgrade_v1_1_33_config(id).await? { return Ok(()); } + if try_upgrade_v1_1_54_config(id).await? { + return Ok(()); + } Ok(()) } diff --git a/clients/socks5/src/commands/mod.rs b/clients/socks5/src/commands/mod.rs index 0d16638164..7e821a4a60 100644 --- a/clients/socks5/src/commands/mod.rs +++ b/clients/socks5/src/commands/mod.rs @@ -7,6 +7,7 @@ use crate::config::old_config_v1_1_20::ConfigV1_1_20; use crate::config::old_config_v1_1_20_2::ConfigV1_1_20_2; use crate::config::old_config_v1_1_30::ConfigV1_1_30; use crate::config::old_config_v1_1_33::ConfigV1_1_33; +use crate::config::old_config_v1_1_54::ConfigV1_1_54; use crate::config::{BaseClientConfig, Config}; use crate::error::Socks5ClientError; use clap::CommandFactory; @@ -204,15 +205,16 @@ async fn try_upgrade_v1_1_13_config(id: &str) -> Result let old_paths = updated_step3.storage_paths.clone(); let updated_step4: ConfigV1_1_33 = updated_step3.into(); - let updated = updated_step4.try_upgrade()?; + let updated_step5: ConfigV1_1_54 = updated_step4.try_into()?; v1_1_33::migrate_gateway_details( &old_paths.common_paths, - &updated.storage_paths.common_paths, + &updated_step5.storage_paths.common_paths, Some(gateway_config), ) .await?; + let updated = updated_step5.try_upgrade()?; updated.save_to_default_location()?; Ok(true) } @@ -234,15 +236,16 @@ async fn try_upgrade_v1_1_20_config(id: &str) -> Result let old_paths = updated_step2.storage_paths.clone(); let updated_step3: ConfigV1_1_33 = updated_step2.into(); - let updated = updated_step3.try_upgrade()?; + let updated_step4: ConfigV1_1_54 = updated_step3.try_into()?; v1_1_33::migrate_gateway_details( &old_paths.common_paths, - &updated.storage_paths.common_paths, + &updated_step4.storage_paths.common_paths, Some(gateway_config), ) .await?; + let updated = updated_step4.try_upgrade()?; updated.save_to_default_location()?; Ok(true) } @@ -261,15 +264,17 @@ async fn try_upgrade_v1_1_20_2_config(id: &str) -> Result Result let old_paths = old_config.storage_paths.clone(); let updated_step1: ConfigV1_1_33 = old_config.into(); - let updated = updated_step1.try_upgrade()?; + let updated_step2: ConfigV1_1_54 = updated_step1.try_into()?; v1_1_33::migrate_gateway_details( &old_paths.common_paths, - &updated.storage_paths.common_paths, + &updated_step2.storage_paths.common_paths, None, ) .await?; + let updated = updated_step2.try_upgrade()?; updated.save_to_default_location()?; Ok(true) } @@ -312,15 +318,32 @@ async fn try_upgrade_v1_1_33_config(id: &str) -> Result let old_paths = old_config.storage_paths.clone(); - let updated = old_config.try_upgrade()?; + let updated_step1: ConfigV1_1_54 = old_config.try_into()?; v1_1_33::migrate_gateway_details( &old_paths.common_paths, - &updated.storage_paths.common_paths, + &updated_step1.storage_paths.common_paths, None, ) .await?; + let updated = updated_step1.try_upgrade()?; + updated.save_to_default_location()?; + Ok(true) +} + +async fn try_upgrade_v1_1_54_config(id: &str) -> Result { + // explicitly load it as v1.1.54 (which is incompatible with the current one, i.e. +1.1.55) + let Ok(old_config) = ConfigV1_1_54::read_from_default_path(id) else { + // if we failed to load it, there might have been nothing to upgrade + // or maybe it was an even older file. in either way. just ignore it and carry on with our day + return Ok(false); + }; + info!("It seems the client is using <= v1.1.54 config template."); + info!("It is going to get updated to the current specification."); + + let updated = old_config.try_upgrade()?; + updated.save_to_default_location()?; Ok(true) } @@ -341,6 +364,9 @@ async fn try_upgrade_config(id: &str) -> Result<(), Socks5ClientError> { if try_upgrade_v1_1_33_config(id).await? { return Ok(()); } + if try_upgrade_v1_1_54_config(id).await? { + return Ok(()); + } Ok(()) } diff --git a/clients/socks5/src/config/mod.rs b/clients/socks5/src/config/mod.rs index 5f2f07d64d..62726d15bd 100644 --- a/clients/socks5/src/config/mod.rs +++ b/clients/socks5/src/config/mod.rs @@ -25,6 +25,7 @@ pub mod old_config_v1_1_20; pub mod old_config_v1_1_20_2; pub mod old_config_v1_1_30; pub mod old_config_v1_1_33; +pub mod old_config_v1_1_54; mod persistence; mod template; diff --git a/clients/socks5/src/config/old_config_v1_1_33.rs b/clients/socks5/src/config/old_config_v1_1_33.rs index fb14259bf4..c139de9f6d 100644 --- a/clients/socks5/src/config/old_config_v1_1_33.rs +++ b/clients/socks5/src/config/old_config_v1_1_33.rs @@ -1,7 +1,7 @@ // Copyright 2024 - Nym Technologies SA // SPDX-License-Identifier: Apache-2.0 -use crate::config::{default_config_filepath, Config, SocksClientPaths}; +use crate::config::{default_config_filepath, SocksClientPaths}; use crate::error::Socks5ClientError; use nym_bin_common::logging::LoggingSettings; use nym_client_core::config::disk_persistence::old_v1_1_33::CommonClientPathsV1_1_33; @@ -11,6 +11,8 @@ use serde::{Deserialize, Serialize}; use std::io; use std::path::Path; +use super::old_config_v1_1_54::ConfigV1_1_54; + #[derive(Clone, Debug, Deserialize, PartialEq, Serialize)] pub struct SocksClientPathsV1_1_33 { #[serde(flatten)] @@ -28,6 +30,20 @@ pub struct ConfigV1_1_33 { pub logging: LoggingSettings, } +impl TryFrom for ConfigV1_1_54 { + type Error = Socks5ClientError; + + fn try_from(value: ConfigV1_1_33) -> Result { + Ok(ConfigV1_1_54 { + core: value.core.into(), + storage_paths: SocksClientPaths { + common_paths: value.storage_paths.common_paths.upgrade_default()?, + }, + logging: value.logging, + }) + } +} + impl ConfigV1_1_33 { pub fn read_from_toml_file>(path: P) -> io::Result { read_config_from_toml_file(path) @@ -36,14 +52,4 @@ impl ConfigV1_1_33 { pub fn read_from_default_path>(id: P) -> io::Result { Self::read_from_toml_file(default_config_filepath(id)) } - - pub fn try_upgrade(self) -> Result { - Ok(Config { - core: self.core.into(), - storage_paths: SocksClientPaths { - common_paths: self.storage_paths.common_paths.upgrade_default()?, - }, - logging: self.logging, - }) - } } diff --git a/clients/socks5/src/config/old_config_v1_1_54.rs b/clients/socks5/src/config/old_config_v1_1_54.rs new file mode 100644 index 0000000000..ebe7166fa5 --- /dev/null +++ b/clients/socks5/src/config/old_config_v1_1_54.rs @@ -0,0 +1,39 @@ +use std::{io, path::Path}; + +use nym_bin_common::logging::LoggingSettings; +use nym_config::read_config_from_toml_file; +use nym_socks5_client_core::config::old_config_v1_1_54::ConfigV1_1_54 as CoreConfigV1_1_54; +use serde::{Deserialize, Serialize}; + +use crate::config::Config; +use crate::error::Socks5ClientError; + +use super::{default_config_filepath, SocksClientPaths}; + +#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)] +#[serde(deny_unknown_fields)] +pub struct ConfigV1_1_54 { + pub core: CoreConfigV1_1_54, + + pub storage_paths: SocksClientPaths, + + pub logging: LoggingSettings, +} + +impl ConfigV1_1_54 { + pub fn read_from_toml_file>(path: P) -> io::Result { + read_config_from_toml_file(path) + } + + pub fn read_from_default_path>(id: P) -> io::Result { + Self::read_from_toml_file(default_config_filepath(id)) + } + + pub fn try_upgrade(self) -> Result { + Ok(Config { + core: self.core.into(), + storage_paths: self.storage_paths, + logging: self.logging, + }) + } +} diff --git a/clients/socks5/src/config/template.rs b/clients/socks5/src/config/template.rs index 2a9a2791bd..f170834342 100644 --- a/clients/socks5/src/config/template.rs +++ b/clients/socks5/src/config/template.rs @@ -98,10 +98,6 @@ send_anonymously = {{ core.socks5.send_anonymously }} [core.debug] -[core.debug.traffic] -average_packet_delay = '{{ core.debug.traffic.average_packet_delay }}' -message_sending_average_delay = '{{ core.debug.traffic.message_sending_average_delay }}' - [core.debug.acknowledgements] average_ack_delay = '{{ core.debug.acknowledgements.average_ack_delay }}' diff --git a/common/client-core/config-types/src/lib.rs b/common/client-core/config-types/src/lib.rs index 404b9fff83..81c47b4219 100644 --- a/common/client-core/config-types/src/lib.rs +++ b/common/client-core/config-types/src/lib.rs @@ -23,7 +23,7 @@ const DEFAULT_ACK_WAIT_MULTIPLIER: f64 = 1.5; const DEFAULT_ACK_WAIT_ADDITION: Duration = Duration::from_millis(1_500); const DEFAULT_LOOP_COVER_STREAM_AVERAGE_DELAY: Duration = Duration::from_millis(200); const DEFAULT_MESSAGE_STREAM_AVERAGE_DELAY: Duration = Duration::from_millis(20); -const DEFAULT_AVERAGE_PACKET_DELAY: Duration = Duration::from_millis(50); +const DEFAULT_AVERAGE_PACKET_DELAY: Duration = Duration::from_millis(15); const DEFAULT_TOPOLOGY_REFRESH_RATE: Duration = Duration::from_secs(5 * 60); // every 5min const DEFAULT_TOPOLOGY_RESOLUTION_TIMEOUT: Duration = Duration::from_millis(5_000); @@ -376,14 +376,12 @@ pub struct Traffic { /// sent packet is going to be delayed at any given mix node. /// So for a packet going through three mix nodes, on average, it will take three times this value /// until the packet reaches its destination. - #[serde(with = "humantime_serde")] pub average_packet_delay: Duration, /// The parameter of Poisson distribution determining how long, on average, /// it is going to take another 'real traffic stream' message to be sent. /// If no real packets are available and cover traffic is enabled, /// a loop cover message is sent instead in order to preserve the rate. - #[serde(with = "humantime_serde")] pub message_sending_average_delay: Duration, /// Controls whether the main packet stream constantly produces packets according to the predefined diff --git a/common/client-core/config-types/src/old/mod.rs b/common/client-core/config-types/src/old/mod.rs index 80b49b41be..2ce1ebdda4 100644 --- a/common/client-core/config-types/src/old/mod.rs +++ b/common/client-core/config-types/src/old/mod.rs @@ -6,6 +6,7 @@ pub mod v2; pub mod v3; pub mod v4; pub mod v5; +pub mod v6; // aliases for backwards compatibility pub use v1 as old_config_v1_1_13; @@ -13,3 +14,4 @@ pub use v2 as old_config_v1_1_20; pub use v3 as old_config_v1_1_20_2; pub use v4 as old_config_v1_1_30; pub use v5 as old_config_v1_1_33; +pub use v6 as old_config_v1_1_54; diff --git a/common/client-core/config-types/src/old/v5.rs b/common/client-core/config-types/src/old/v5.rs index 117e9dcf32..caebd2f4f3 100644 --- a/common/client-core/config-types/src/old/v5.rs +++ b/common/client-core/config-types/src/old/v5.rs @@ -1,16 +1,14 @@ // Copyright 2024 - Nym Technologies SA // SPDX-License-Identifier: Apache-2.0 -use crate::{ - Acknowledgements, Client, Config, CoverTraffic, DebugConfig, GatewayConnection, ReplySurbs, - Topology, Traffic, -}; use nym_sphinx_addressing::Recipient; use nym_sphinx_params::{PacketSize, PacketType}; use serde::{Deserialize, Serialize}; use std::time::Duration; use url::Url; +use super::v6::*; + // 'DEBUG' const DEFAULT_ACK_WAIT_MULTIPLIER: f64 = 1.5; @@ -87,18 +85,18 @@ pub struct ConfigV5 { pub debug: DebugConfigV5, } -impl From for Config { +impl From for ConfigV6 { fn from(value: ConfigV5) -> Self { - Config { - client: Client { + ConfigV6 { + client: ClientV6 { version: value.client.version, id: value.client.id, disabled_credentials_mode: value.client.disabled_credentials_mode, nyxd_urls: value.client.nyxd_urls, nym_api_urls: value.client.nym_api_urls, }, - debug: DebugConfig { - traffic: Traffic { + debug: DebugConfigV6 { + traffic: TrafficV6 { average_packet_delay: value.debug.traffic.average_packet_delay, message_sending_average_delay: value .debug @@ -113,7 +111,7 @@ impl From for Config { packet_type: value.debug.traffic.packet_type, ..Default::default() }, - cover_traffic: CoverTraffic { + cover_traffic: CoverTrafficV6 { loop_cover_traffic_average_delay: value .debug .cover_traffic @@ -127,18 +125,18 @@ impl From for Config { .cover_traffic .disable_loop_cover_traffic_stream, }, - gateway_connection: GatewayConnection { + gateway_connection: GatewayConnectionV6 { gateway_response_timeout: value .debug .gateway_connection .gateway_response_timeout, }, - acknowledgements: Acknowledgements { + acknowledgements: AcknowledgementsV6 { average_ack_delay: value.debug.acknowledgements.average_ack_delay, ack_wait_multiplier: value.debug.acknowledgements.ack_wait_multiplier, ack_wait_addition: value.debug.acknowledgements.ack_wait_addition, }, - topology: Topology { + topology: TopologyV6 { topology_refresh_rate: value.debug.topology.topology_refresh_rate, topology_resolution_timeout: value.debug.topology.topology_resolution_timeout, disable_refreshing: value.debug.topology.disable_refreshing, @@ -148,7 +146,7 @@ impl From for Config { .max_startup_gateway_waiting_period, ..Default::default() }, - reply_surbs: ReplySurbs { + reply_surbs: ReplySurbsV6 { minimum_reply_surb_storage_threshold: value .debug .reply_surbs diff --git a/common/client-core/config-types/src/old/v6.rs b/common/client-core/config-types/src/old/v6.rs new file mode 100644 index 0000000000..0f01db2a62 --- /dev/null +++ b/common/client-core/config-types/src/old/v6.rs @@ -0,0 +1,623 @@ +// Copyright 2024 - Nym Technologies SA +// SPDX-License-Identifier: Apache-2.0 + +use crate::{ + Acknowledgements, Client, Config, CoverTraffic, DebugConfig, ForgetMe, GatewayConnection, + RememberMe, ReplySurbs, StatsReporting, Topology, Traffic, +}; +use nym_config::serde_helpers::{de_maybe_stringified, ser_maybe_stringified}; +use nym_sphinx_addressing::Recipient; +use nym_sphinx_params::{PacketSize, PacketType}; +use nym_statistics_common::types::SessionType; +use serde::{Deserialize, Serialize}; +use std::time::Duration; +use url::Url; + +// 'DEBUG' +const DEFAULT_ACK_WAIT_MULTIPLIER: f64 = 1.5; + +const DEFAULT_ACK_WAIT_ADDITION: Duration = Duration::from_millis(1_500); +const DEFAULT_LOOP_COVER_STREAM_AVERAGE_DELAY: Duration = Duration::from_millis(200); +const DEFAULT_MESSAGE_STREAM_AVERAGE_DELAY: Duration = Duration::from_millis(20); +const DEFAULT_AVERAGE_PACKET_DELAY: Duration = Duration::from_millis(15); +const DEFAULT_TOPOLOGY_REFRESH_RATE: Duration = Duration::from_secs(5 * 60); // every 5min +const DEFAULT_TOPOLOGY_RESOLUTION_TIMEOUT: Duration = Duration::from_millis(5_000); + +// the same values as our current (10.06.24) blacklist +const DEFAULT_MIN_MIXNODE_PERFORMANCE: u8 = 50; +const DEFAULT_MIN_GATEWAY_PERFORMANCE: u8 = 50; + +const DEFAULT_MAX_STARTUP_GATEWAY_WAITING_PERIOD: Duration = Duration::from_secs(70 * 60); // 70min -> full epoch (1h) + a bit of overhead + +// Set this to a high value for now, so that we don't risk sporadic timeouts that might cause +// bought bandwidth tokens to not have time to be spent; Once we remove the gateway from the +// bandwidth bridging protocol, we can come back to a smaller timeout value +const DEFAULT_GATEWAY_RESPONSE_TIMEOUT: Duration = Duration::from_secs(5 * 60); + +const DEFAULT_COVER_TRAFFIC_PRIMARY_SIZE_RATIO: f64 = 0.70; + +// reply-surbs related: + +// define when to request +// clients/client-core/src/client/replies/reply_storage/surb_storage.rs +const DEFAULT_MINIMUM_REPLY_SURB_STORAGE_THRESHOLD: usize = 10; +const DEFAULT_MAXIMUM_REPLY_SURB_STORAGE_THRESHOLD: usize = 200; +const DEFAULT_MINIMUM_REPLY_SURB_THRESHOLD_BUFFER: usize = 0; + +// define how much to request at once +// clients/client-core/src/client/replies/reply_controller.rs +const DEFAULT_MINIMUM_REPLY_SURB_REQUEST_SIZE: u32 = 10; +const DEFAULT_MAXIMUM_REPLY_SURB_REQUEST_SIZE: u32 = 50; + +const DEFAULT_MAXIMUM_ALLOWED_SURB_REQUEST_SIZE: u32 = 500; + +const DEFAULT_MAXIMUM_REPLY_SURB_REREQUEST_WAITING_PERIOD: Duration = Duration::from_secs(10); +const DEFAULT_MAXIMUM_REPLY_SURB_DROP_WAITING_PERIOD: Duration = Duration::from_secs(5 * 60); + +// 12 hours +const DEFAULT_MAXIMUM_REPLY_SURB_AGE: Duration = Duration::from_secs(12 * 60 * 60); + +// 24 hours +const DEFAULT_MAXIMUM_REPLY_KEY_AGE: Duration = Duration::from_secs(24 * 60 * 60); + +// stats reporting related + +/// Time interval between reporting statistics to the given provider if it exists +const STATS_REPORT_INTERVAL_SECS: Duration = Duration::from_secs(300); + +// aliases for backwards compatibility +pub type ConfigV1_1_54 = ConfigV6; +pub type ClientV1_1_54 = ClientV6; +pub type DebugConfigV1_1_54 = DebugConfigV6; + +pub type TrafficV1_1_54 = TrafficV6; +pub type CoverTrafficV1_1_54 = CoverTrafficV6; +pub type GatewayConnectionV1_1_54 = GatewayConnectionV6; +pub type AcknowledgementsV1_1_54 = AcknowledgementsV6; +pub type TopologyV1_1_54 = TopologyV6; +pub type ReplySurbsV1_1_54 = ReplySurbsV6; + +#[derive(Debug, Clone, Deserialize, PartialEq, Serialize)] +#[serde(deny_unknown_fields)] +pub struct ConfigV6 { + pub client: ClientV6, + + #[serde(default)] + pub debug: DebugConfigV6, +} + +impl From for Config { + fn from(value: ConfigV6) -> Self { + Config { + client: Client { + version: value.client.version, + id: value.client.id, + disabled_credentials_mode: value.client.disabled_credentials_mode, + nyxd_urls: value.client.nyxd_urls, + nym_api_urls: value.client.nym_api_urls, + }, + debug: DebugConfig { + traffic: Traffic { + average_packet_delay: DEFAULT_AVERAGE_PACKET_DELAY, + message_sending_average_delay: value + .debug + .traffic + .message_sending_average_delay, + disable_main_poisson_packet_distribution: value + .debug + .traffic + .disable_main_poisson_packet_distribution, + primary_packet_size: value.debug.traffic.primary_packet_size, + secondary_packet_size: value.debug.traffic.secondary_packet_size, + packet_type: value.debug.traffic.packet_type, + deterministic_route_selection: value + .debug + .traffic + .deterministic_route_selection, + maximum_number_of_retransmissions: value + .debug + .traffic + .maximum_number_of_retransmissions, + use_legacy_sphinx_format: value.debug.traffic.use_legacy_sphinx_format, + disable_mix_hops: value.debug.traffic.disable_mix_hops, + }, + cover_traffic: CoverTraffic { + loop_cover_traffic_average_delay: value + .debug + .cover_traffic + .loop_cover_traffic_average_delay, + cover_traffic_primary_size_ratio: value + .debug + .cover_traffic + .cover_traffic_primary_size_ratio, + disable_loop_cover_traffic_stream: value + .debug + .cover_traffic + .disable_loop_cover_traffic_stream, + }, + gateway_connection: GatewayConnection { + gateway_response_timeout: value + .debug + .gateway_connection + .gateway_response_timeout, + }, + acknowledgements: Acknowledgements { + average_ack_delay: value.debug.acknowledgements.average_ack_delay, + ack_wait_multiplier: value.debug.acknowledgements.ack_wait_multiplier, + ack_wait_addition: value.debug.acknowledgements.ack_wait_addition, + }, + topology: Topology { + topology_refresh_rate: value.debug.topology.topology_refresh_rate, + topology_resolution_timeout: value.debug.topology.topology_resolution_timeout, + disable_refreshing: value.debug.topology.disable_refreshing, + max_startup_gateway_waiting_period: value + .debug + .topology + .max_startup_gateway_waiting_period, + minimum_mixnode_performance: value.debug.topology.minimum_mixnode_performance, + minimum_gateway_performance: value.debug.topology.minimum_gateway_performance, + use_extended_topology: value.debug.topology.use_extended_topology, + ignore_egress_epoch_role: value.debug.topology.ignore_egress_epoch_role, + ignore_ingress_epoch_role: value.debug.topology.ignore_ingress_epoch_role, + }, + reply_surbs: ReplySurbs { + minimum_reply_surb_storage_threshold: value + .debug + .reply_surbs + .minimum_reply_surb_storage_threshold, + maximum_reply_surb_storage_threshold: value + .debug + .reply_surbs + .maximum_reply_surb_storage_threshold, + minimum_reply_surb_request_size: value + .debug + .reply_surbs + .minimum_reply_surb_request_size, + maximum_reply_surb_request_size: value + .debug + .reply_surbs + .maximum_reply_surb_request_size, + maximum_allowed_reply_surb_request_size: value + .debug + .reply_surbs + .maximum_allowed_reply_surb_request_size, + maximum_reply_surb_rerequest_waiting_period: value + .debug + .reply_surbs + .maximum_reply_surb_rerequest_waiting_period, + maximum_reply_surb_drop_waiting_period: value + .debug + .reply_surbs + .maximum_reply_surb_drop_waiting_period, + maximum_reply_surb_age: value.debug.reply_surbs.maximum_reply_surb_age, + maximum_reply_key_age: value.debug.reply_surbs.maximum_reply_key_age, + surb_mix_hops: value.debug.reply_surbs.surb_mix_hops, + minimum_reply_surb_threshold_buffer: value + .debug + .reply_surbs + .minimum_reply_surb_threshold_buffer, + fresh_sender_tags: value.debug.reply_surbs.fresh_sender_tags, + }, + stats_reporting: StatsReporting { + enabled: value.debug.stats_reporting.enabled, + provider_address: value.debug.stats_reporting.provider_address, + reporting_interval: value.debug.stats_reporting.reporting_interval, + }, + forget_me: ForgetMe { + client: value.debug.forget_me.client, + stats: value.debug.forget_me.stats, + }, + remember_me: RememberMe { + stats: value.debug.remember_me.stats, + session_type: value.debug.remember_me.session_type.into(), + }, + }, + } + } +} + +#[derive(Debug, Clone, Deserialize, PartialEq, Eq, Serialize)] +// note: the deny_unknown_fields is VITAL here to allow upgrades from v1.1.20_2 +#[serde(deny_unknown_fields)] +pub struct ClientV6 { + /// Version of the client for which this configuration was created. + pub version: String, + + /// ID specifies the human readable ID of this particular client. + pub id: String, + + /// Indicates whether this client is running in a disabled credentials mode, thus attempting + /// to claim bandwidth without presenting bandwidth credentials. + // TODO: this should be moved to `debug.gateway_connection` + #[serde(default)] + pub disabled_credentials_mode: bool, + + /// Addresses to nyxd validators via which the client can communicate with the chain. + #[serde(alias = "validator_urls")] + pub nyxd_urls: Vec, + + /// Addresses to APIs running on validator from which the client gets the view of the network. + #[serde(alias = "validator_api_urls")] + pub nym_api_urls: Vec, +} + +#[derive(Debug, Clone, Copy, Deserialize, PartialEq, Serialize)] +#[serde(default, deny_unknown_fields)] +pub struct TrafficV6 { + /// The parameter of Poisson distribution determining how long, on average, + /// sent packet is going to be delayed at any given mix node. + /// So for a packet going through three mix nodes, on average, it will take three times this value + /// until the packet reaches its destination. + #[serde(with = "humantime_serde")] + pub average_packet_delay: Duration, + + /// The parameter of Poisson distribution determining how long, on average, + /// it is going to take another 'real traffic stream' message to be sent. + /// If no real packets are available and cover traffic is enabled, + /// a loop cover message is sent instead in order to preserve the rate. + #[serde(with = "humantime_serde")] + pub message_sending_average_delay: Duration, + + /// Controls whether the main packet stream constantly produces packets according to the predefined + /// poisson distribution. + pub disable_main_poisson_packet_distribution: bool, + + /// Specify whether route selection should be determined by the packet header. + pub deterministic_route_selection: bool, + + /// Specify how many times particular packet can be retransmitted + /// None - no limit + pub maximum_number_of_retransmissions: Option, + + /// Specifies the packet size used for sent messages. + /// Do not override it unless you understand the consequences of that change. + pub primary_packet_size: PacketSize, + + /// Specifies the optional auxiliary packet size for optimizing message streams. + /// Note that its use decreases overall anonymity. + /// Do not set it unless you understand the consequences of that change. + pub secondary_packet_size: Option, + + /// Specify whether any constructed sphinx packets should use the legacy format, + /// where the payload keys are explicitly attached rather than using the seeds + /// this affects any forward packets, acks and reply surbs + /// this flag should remain disabled until sufficient number of nodes on the network has upgraded + /// and support updated format. + /// in the case of reply surbs, the recipient must also understand the new encoding + pub use_legacy_sphinx_format: bool, + + pub packet_type: PacketType, + + /// Indicates whether to mix hops or not. If mix hops are enabled, traffic + /// will be routed as usual, to the entry gateway, through three mix nodes, egressing + /// through the exit gateway. If mix hops are disabled, traffic will be routed directly + /// from the entry gateway to the exit gateway, bypassing the mix nodes. + pub disable_mix_hops: bool, +} + +impl Default for TrafficV6 { + fn default() -> Self { + TrafficV6 { + average_packet_delay: DEFAULT_AVERAGE_PACKET_DELAY, + message_sending_average_delay: DEFAULT_MESSAGE_STREAM_AVERAGE_DELAY, + disable_main_poisson_packet_distribution: false, + deterministic_route_selection: false, + maximum_number_of_retransmissions: None, + primary_packet_size: PacketSize::RegularPacket, + secondary_packet_size: None, + packet_type: PacketType::Mix, + + // we should use the legacy format until sufficient number of nodes understand the + // improved encoding + use_legacy_sphinx_format: true, + disable_mix_hops: false, + } + } +} + +#[derive(Debug, Clone, Copy, Deserialize, PartialEq, Serialize)] +#[serde(default, deny_unknown_fields)] +pub struct CoverTrafficV6 { + /// The parameter of Poisson distribution determining how long, on average, + /// it is going to take for another loop cover traffic message to be sent. + #[serde(with = "humantime_serde")] + pub loop_cover_traffic_average_delay: Duration, + + /// Specifies the ratio of `primary_packet_size` to `secondary_packet_size` used in cover traffic. + /// Only applicable if `secondary_packet_size` is enabled. + pub cover_traffic_primary_size_ratio: f64, + + /// Controls whether the dedicated loop cover traffic stream should be enabled. + /// (and sending packets, on average, every [Self::loop_cover_traffic_average_delay]) + pub disable_loop_cover_traffic_stream: bool, +} + +impl Default for CoverTrafficV6 { + fn default() -> Self { + CoverTrafficV6 { + loop_cover_traffic_average_delay: DEFAULT_LOOP_COVER_STREAM_AVERAGE_DELAY, + cover_traffic_primary_size_ratio: DEFAULT_COVER_TRAFFIC_PRIMARY_SIZE_RATIO, + disable_loop_cover_traffic_stream: false, + } + } +} + +#[derive(Debug, Clone, Copy, Deserialize, PartialEq, Serialize)] +#[serde(default, deny_unknown_fields)] +pub struct GatewayConnectionV6 { + /// How long we're willing to wait for a response to a message sent to the gateway, + /// before giving up on it. + #[serde(with = "humantime_serde")] + pub gateway_response_timeout: Duration, +} + +impl Default for GatewayConnectionV6 { + fn default() -> Self { + GatewayConnectionV6 { + gateway_response_timeout: DEFAULT_GATEWAY_RESPONSE_TIMEOUT, + } + } +} + +#[derive(Debug, Clone, Copy, Deserialize, PartialEq, Serialize)] +#[serde(default, deny_unknown_fields)] +pub struct AcknowledgementsV6 { + /// The parameter of Poisson distribution determining how long, on average, + /// sent acknowledgement is going to be delayed at any given mix node. + /// So for an ack going through three mix nodes, on average, it will take three times this value + /// until the packet reaches its destination. + #[serde(with = "humantime_serde")] + pub average_ack_delay: Duration, + + /// Value multiplied with the expected round trip time of an acknowledgement packet before + /// it is assumed it was lost and retransmission of the data packet happens. + /// In an ideal network with 0 latency, this value would have been 1. + pub ack_wait_multiplier: f64, + + /// Value added to the expected round trip time of an acknowledgement packet before + /// it is assumed it was lost and retransmission of the data packet happens. + /// In an ideal network with 0 latency, this value would have been 0. + #[serde(with = "humantime_serde")] + pub ack_wait_addition: Duration, +} + +impl Default for AcknowledgementsV6 { + fn default() -> Self { + AcknowledgementsV6 { + average_ack_delay: DEFAULT_AVERAGE_PACKET_DELAY, + ack_wait_multiplier: DEFAULT_ACK_WAIT_MULTIPLIER, + ack_wait_addition: DEFAULT_ACK_WAIT_ADDITION, + } + } +} + +#[derive(Debug, Clone, Copy, Deserialize, PartialEq, Serialize)] +#[serde(default, deny_unknown_fields)] +pub struct TopologyV6 { + /// The uniform delay every which clients are querying the directory server + /// to try to obtain a compatible network topology to send sphinx packets through. + #[serde(with = "humantime_serde")] + pub topology_refresh_rate: Duration, + + /// During topology refresh, test packets are sent through every single possible network + /// path. This timeout determines waiting period until it is decided that the packet + /// did not reach its destination. + #[serde(with = "humantime_serde")] + pub topology_resolution_timeout: Duration, + + /// Specifies whether the client should not refresh the network topology after obtaining + /// the first valid instance. + /// Supersedes `topology_refresh_rate_ms`. + pub disable_refreshing: bool, + + /// Defines how long the client is going to wait on startup for its gateway to come online, + /// before abandoning the procedure. + #[serde(with = "humantime_serde")] + pub max_startup_gateway_waiting_period: Duration, + + /// Specifies a minimum performance of a mixnode that is used on route construction. + /// This setting is only applicable when `NymApi` topology is used. + pub minimum_mixnode_performance: u8, + + /// Specifies a minimum performance of a gateway that is used on route construction. + /// This setting is only applicable when `NymApi` topology is used. + pub minimum_gateway_performance: u8, + + /// Specifies whether this client should attempt to retrieve all available network nodes + /// as opposed to just active mixnodes/gateways. + pub use_extended_topology: bool, + + /// Specifies whether this client should ignore the current epoch role of the target egress node + /// when constructing the final hop packets. + pub ignore_egress_epoch_role: bool, + + /// Specifies whether this client should ignore the current epoch role of the ingress node + /// when attempting to establish new connection + pub ignore_ingress_epoch_role: bool, +} + +impl Default for TopologyV6 { + fn default() -> Self { + TopologyV6 { + topology_refresh_rate: DEFAULT_TOPOLOGY_REFRESH_RATE, + topology_resolution_timeout: DEFAULT_TOPOLOGY_RESOLUTION_TIMEOUT, + disable_refreshing: false, + max_startup_gateway_waiting_period: DEFAULT_MAX_STARTUP_GATEWAY_WAITING_PERIOD, + minimum_mixnode_performance: DEFAULT_MIN_MIXNODE_PERFORMANCE, + minimum_gateway_performance: DEFAULT_MIN_GATEWAY_PERFORMANCE, + use_extended_topology: false, + + ignore_egress_epoch_role: true, + ignore_ingress_epoch_role: true, + } + } +} + +#[derive(Debug, Clone, Copy, Deserialize, PartialEq, Serialize)] +#[serde(default, deny_unknown_fields)] +pub struct ReplySurbsV6 { + /// Defines the minimum number of reply surbs the client wants to keep in its storage at all times. + /// It can only allow to go below that value if its to request additional reply surbs. + pub minimum_reply_surb_storage_threshold: usize, + + /// Defines the maximum number of reply surbs the client wants to keep in its storage at any times. + pub maximum_reply_surb_storage_threshold: usize, + + /// Defines the soft threshold ontop of the minimum reply surb storage threshold for when the client + /// should proactively request additional reply surbs. + pub minimum_reply_surb_threshold_buffer: usize, + + /// Defines the minimum number of reply surbs the client would request. + pub minimum_reply_surb_request_size: u32, + + /// Defines the maximum number of reply surbs the client would request. + pub maximum_reply_surb_request_size: u32, + + /// Defines the maximum number of reply surbs a remote party is allowed to request from this client at once. + pub maximum_allowed_reply_surb_request_size: u32, + + /// Defines maximum amount of time the client is going to wait for reply surbs before explicitly asking + /// for more even though in theory they wouldn't need to. + #[serde(with = "humantime_serde")] + pub maximum_reply_surb_rerequest_waiting_period: Duration, + + /// Defines maximum amount of time the client is going to wait for reply surbs before + /// deciding it's never going to get them and would drop all pending messages + #[serde(with = "humantime_serde")] + pub maximum_reply_surb_drop_waiting_period: Duration, + + /// Defines maximum amount of time given reply surb is going to be valid for. + /// This is going to be superseded by key rotation once implemented. + #[serde(with = "humantime_serde")] + pub maximum_reply_surb_age: Duration, + + /// Defines maximum amount of time given reply key is going to be valid for. + /// This is going to be superseded by key rotation once implemented. + #[serde(with = "humantime_serde")] + pub maximum_reply_key_age: Duration, + + /// Specifies the number of mixnet hops the packet should go through. If not specified, then + /// the default value is used. + pub surb_mix_hops: Option, + + /// Specifies if we should reset all the sender tags on startup + pub fresh_sender_tags: bool, +} + +impl Default for ReplySurbsV6 { + fn default() -> Self { + ReplySurbsV6 { + minimum_reply_surb_storage_threshold: DEFAULT_MINIMUM_REPLY_SURB_STORAGE_THRESHOLD, + maximum_reply_surb_storage_threshold: DEFAULT_MAXIMUM_REPLY_SURB_STORAGE_THRESHOLD, + minimum_reply_surb_threshold_buffer: DEFAULT_MINIMUM_REPLY_SURB_THRESHOLD_BUFFER, + minimum_reply_surb_request_size: DEFAULT_MINIMUM_REPLY_SURB_REQUEST_SIZE, + maximum_reply_surb_request_size: DEFAULT_MAXIMUM_REPLY_SURB_REQUEST_SIZE, + maximum_allowed_reply_surb_request_size: DEFAULT_MAXIMUM_ALLOWED_SURB_REQUEST_SIZE, + maximum_reply_surb_rerequest_waiting_period: + DEFAULT_MAXIMUM_REPLY_SURB_REREQUEST_WAITING_PERIOD, + maximum_reply_surb_drop_waiting_period: DEFAULT_MAXIMUM_REPLY_SURB_DROP_WAITING_PERIOD, + maximum_reply_surb_age: DEFAULT_MAXIMUM_REPLY_SURB_AGE, + maximum_reply_key_age: DEFAULT_MAXIMUM_REPLY_KEY_AGE, + surb_mix_hops: None, + fresh_sender_tags: false, + } + } +} + +#[derive(Debug, Default, Clone, Copy, Deserialize, PartialEq, Serialize)] +#[serde(default, deny_unknown_fields)] +pub struct DebugConfigV6 { + /// Defines all configuration options related to traffic streams. + pub traffic: TrafficV6, + + /// Defines all configuration options related to cover traffic stream(s). + pub cover_traffic: CoverTrafficV6, + + /// Defines all configuration options related to the gateway connection. + pub gateway_connection: GatewayConnectionV6, + + /// Defines all configuration options related to acknowledgements, such as delays or wait timeouts. + pub acknowledgements: AcknowledgementsV6, + + /// Defines all configuration options related topology, such as refresh rates or timeouts. + pub topology: TopologyV6, + + /// Defines all configuration options related to reply SURBs. + pub reply_surbs: ReplySurbsV6, + + /// Defines all configuration options related to stats reporting. + pub stats_reporting: StatsReportingV6, + + /// Defines all configuration options related to the forget me flag. + pub forget_me: ForgetMeV6, + + /// Defines all configuration options related to the remember me flag. + pub remember_me: RememberMeV6, +} + +#[derive(Debug, Clone, Copy, Deserialize, PartialEq, Serialize)] +#[serde(default, deny_unknown_fields)] +pub struct StatsReportingV6 { + /// Is stats reporting enabled + pub enabled: bool, + + /// Address of the stats collector. If this is none, no reporting will happen, regardless of `enabled` + #[serde( + serialize_with = "ser_maybe_stringified", + deserialize_with = "de_maybe_stringified" + )] + pub provider_address: Option, + + /// With what frequence will statistics be sent + #[serde(with = "humantime_serde")] + pub reporting_interval: Duration, +} + +impl Default for StatsReportingV6 { + fn default() -> Self { + StatsReportingV6 { + enabled: true, + provider_address: None, + reporting_interval: STATS_REPORT_INTERVAL_SECS, + } + } +} + +#[derive(Clone, Default, Debug, Deserialize, PartialEq, Serialize, Copy)] +pub struct ForgetMeV6 { + client: bool, + stats: bool, +} + +#[derive(Clone, Default, Debug, Deserialize, PartialEq, Serialize, Copy)] +pub struct RememberMeV6 { + /// Signal that this client should be accounted for in the stats + stats: bool, + + /// Type of the session to remember, if it should be remembered + session_type: SessionTypeV6, +} + +#[derive(PartialEq, Copy, Clone, Serialize, Deserialize, Default, Debug)] +pub enum SessionTypeV6 { + Vpn, + Mixnet, + Wasm, + Native, + Socks5, + #[default] + Unknown, +} + +impl From for SessionType { + fn from(value: SessionTypeV6) -> Self { + match value { + SessionTypeV6::Vpn => Self::Vpn, + SessionTypeV6::Mixnet => Self::Mixnet, + SessionTypeV6::Wasm => Self::Wasm, + SessionTypeV6::Native => Self::Native, + SessionTypeV6::Socks5 => Self::Socks5, + SessionTypeV6::Unknown => Self::Unknown, + } + } +} diff --git a/common/client-core/src/config/mod.rs b/common/client-core/src/config/mod.rs index 69c30c69ae..0705a93c3a 100644 --- a/common/client-core/src/config/mod.rs +++ b/common/client-core/src/config/mod.rs @@ -4,6 +4,6 @@ pub use nym_client_core_config_types::disk_persistence; pub use nym_client_core_config_types::old::{ old_config_v1_1_13, old_config_v1_1_20, old_config_v1_1_20_2, old_config_v1_1_30, - old_config_v1_1_33, + old_config_v1_1_33, old_config_v1_1_54, }; pub use nym_client_core_config_types::*; diff --git a/common/socks5-client-core/src/config/mod.rs b/common/socks5-client-core/src/config/mod.rs index 4767eabcdd..9c5e504f1b 100644 --- a/common/socks5-client-core/src/config/mod.rs +++ b/common/socks5-client-core/src/config/mod.rs @@ -13,6 +13,7 @@ use std::str::FromStr; pub mod old_config_v1_1_20_2; pub mod old_config_v1_1_30; pub mod old_config_v1_1_33; +pub mod old_config_v1_1_54; pub use nym_service_providers_common::interface::ProviderInterfaceVersion; pub use nym_socks5_requests::Socks5ProtocolVersion; diff --git a/common/socks5-client-core/src/config/old_config_v1_1_33.rs b/common/socks5-client-core/src/config/old_config_v1_1_33.rs index 715b9d108a..b493cf9113 100644 --- a/common/socks5-client-core/src/config/old_config_v1_1_33.rs +++ b/common/socks5-client-core/src/config/old_config_v1_1_33.rs @@ -1,7 +1,8 @@ // Copyright 2024 - Nym Technologies SA // SPDX-License-Identifier: Apache-2.0 -use super::{Config, Socks5, Socks5Debug}; +use super::old_config_v1_1_54::ConfigV1_1_54; +use super::{Socks5, Socks5Debug}; pub use nym_client_core::config::old_config_v1_1_33::ConfigV1_1_33 as BaseClientConfigV1_1_33; use serde::{Deserialize, Serialize}; use std::fmt::Debug; @@ -23,9 +24,9 @@ pub struct ConfigV1_1_33 { pub socks5: Socks5V1_1_33, } -impl From for Config { +impl From for ConfigV1_1_54 { fn from(value: ConfigV1_1_33) -> Self { - Config { + ConfigV1_1_54 { base: value.base.into(), socks5: value.socks5.into(), } diff --git a/common/socks5-client-core/src/config/old_config_v1_1_54.rs b/common/socks5-client-core/src/config/old_config_v1_1_54.rs new file mode 100644 index 0000000000..262e21ab2c --- /dev/null +++ b/common/socks5-client-core/src/config/old_config_v1_1_54.rs @@ -0,0 +1,23 @@ +use super::Config; +pub use nym_client_core::config::old_config_v1_1_54::ConfigV1_1_54 as BaseClientConfigV1_1_54; +use serde::{Deserialize, Serialize}; + +use super::Socks5; + +#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)] +#[serde(deny_unknown_fields)] +pub struct ConfigV1_1_54 { + #[serde(flatten)] + pub base: BaseClientConfigV1_1_54, + + pub socks5: Socks5, +} + +impl From for Config { + fn from(value: ConfigV1_1_54) -> Self { + Config { + base: value.base.into(), + socks5: value.socks5, + } + } +} diff --git a/service-providers/authenticator/src/config/helpers.rs b/service-providers/authenticator/src/config/helpers.rs index a529d50ae3..35a3e51159 100644 --- a/service-providers/authenticator/src/config/helpers.rs +++ b/service-providers/authenticator/src/config/helpers.rs @@ -1,13 +1,32 @@ // Copyright 2024 - Nym Technologies SA // SPDX-License-Identifier: Apache-2.0 -use log::trace; +use log::{info, trace}; use std::path::Path; -use crate::error::AuthenticatorError; +use crate::{config::old_config_v1_1_54::ConfigV1_1_54, error::AuthenticatorError}; -pub async fn try_upgrade_config>(_config_path: P) -> Result<(), AuthenticatorError> { +async fn try_upgrade_v1_1_54_config>(id: P) -> Result { + // explicitly load it as v1.1.54 (which is incompatible with the current one, i.e. +1.1.55) + let Ok(old_config) = ConfigV1_1_54::read_from_default_path(id) else { + // if we failed to load it, there might have been nothing to upgrade + // or maybe it was an even older file. in either way. just ignore it and carry on with our day + return Ok(false); + }; + info!("It seems the client is using <= v1.1.54 config template."); + info!("It is going to get updated to the current specification."); + + let updated = old_config.try_upgrade()?; + + updated.save_to_default_location()?; + Ok(true) +} + +pub async fn try_upgrade_config>(id: P) -> Result<(), AuthenticatorError> { trace!("Attempting to upgrade config"); + if try_upgrade_v1_1_54_config(id).await? { + return Ok(()); + } Ok(()) } diff --git a/service-providers/authenticator/src/config/mod.rs b/service-providers/authenticator/src/config/mod.rs index 4b2d11fae9..90c4a0be60 100644 --- a/service-providers/authenticator/src/config/mod.rs +++ b/service-providers/authenticator/src/config/mod.rs @@ -24,6 +24,7 @@ use std::{ use template::CONFIG_TEMPLATE; pub mod helpers; +pub mod old_config_v1_1_54; pub mod persistence; pub mod template; diff --git a/service-providers/authenticator/src/config/old_config_v1_1_54.rs b/service-providers/authenticator/src/config/old_config_v1_1_54.rs new file mode 100644 index 0000000000..2cbb3d6c4f --- /dev/null +++ b/service-providers/authenticator/src/config/old_config_v1_1_54.rs @@ -0,0 +1,43 @@ +use std::{io, path::Path}; + +use nym_bin_common::logging::LoggingSettings; +pub use nym_client_core::config::old_config_v1_1_54::ConfigV1_1_54 as BaseConfigV1_1_54; +use nym_config::read_config_from_toml_file; +use serde::{Deserialize, Serialize}; + +use crate::{config::Config, error::AuthenticatorError}; + +use super::{default_config_filepath, Authenticator, AuthenticatorPaths}; + +#[derive(Debug, Clone, Deserialize, PartialEq, Serialize)] +#[serde(deny_unknown_fields)] +pub struct ConfigV1_1_54 { + #[serde(flatten)] + pub base: BaseConfigV1_1_54, + + #[serde(default)] + pub authenticator: Authenticator, + + pub storage_paths: AuthenticatorPaths, + + pub logging: LoggingSettings, +} + +impl ConfigV1_1_54 { + pub fn read_from_toml_file>(path: P) -> io::Result { + read_config_from_toml_file(path) + } + + pub fn read_from_default_path>(id: P) -> io::Result { + Self::read_from_toml_file(default_config_filepath(id)) + } + + pub fn try_upgrade(self) -> Result { + Ok(Config { + base: self.base.into(), + authenticator: self.authenticator, + storage_paths: self.storage_paths, + logging: self.logging, + }) + } +} diff --git a/service-providers/authenticator/src/config/template.rs b/service-providers/authenticator/src/config/template.rs index d4b7eb7aa6..d8b30f2227 100644 --- a/service-providers/authenticator/src/config/template.rs +++ b/service-providers/authenticator/src/config/template.rs @@ -85,10 +85,6 @@ unknown_list_location = '{{ storage_paths.unknown_list_location }}' [debug] -[debug.traffic] -average_packet_delay = '{{ debug.traffic.average_packet_delay }}' -message_sending_average_delay = '{{ debug.traffic.message_sending_average_delay }}' - [debug.acknowledgements] average_ack_delay = '{{ debug.acknowledgements.average_ack_delay }}' diff --git a/service-providers/ip-packet-router/src/cli/mod.rs b/service-providers/ip-packet-router/src/cli/mod.rs index 11c2a0e049..d322984773 100644 --- a/service-providers/ip-packet-router/src/cli/mod.rs +++ b/service-providers/ip-packet-router/src/cli/mod.rs @@ -4,7 +4,7 @@ use log::error; use nym_bin_common::bin_info; use nym_bin_common::completions::{fig_generate, ArgShell}; use nym_client_core::cli_helpers::CliClient; -use nym_ip_packet_router::config::helpers::try_upgrade_config; +use nym_ip_packet_router::config::helpers::{try_upgrade_config, try_upgrade_config_by_id}; use nym_ip_packet_router::config::{BaseClientConfig, Config}; use nym_ip_packet_router::error::IpPacketRouterError; use std::sync::OnceLock; @@ -151,7 +151,7 @@ async fn try_load_current_config(id: &str) -> Result cfg, diff --git a/service-providers/ip-packet-router/src/config/helpers.rs b/service-providers/ip-packet-router/src/config/helpers.rs index 6dd7209b87..5ca4a04f03 100644 --- a/service-providers/ip-packet-router/src/config/helpers.rs +++ b/service-providers/ip-packet-router/src/config/helpers.rs @@ -3,6 +3,7 @@ use crate::config::default_config_filepath; use crate::config::old_config_v1::ConfigV1; +use crate::config::old_config_v2::ConfigV2; use crate::error::IpPacketRouterError; use log::{info, trace}; use nym_client_core::cli_helpers::CliClientConfig; @@ -22,22 +23,45 @@ async fn try_upgrade_v1_config>( info!("It is going to get updated to the current specification."); let old_paths = old_config.storage_paths.clone(); - let updated = old_config.try_upgrade()?; + let updated_step1: ConfigV2 = old_config.try_into()?; v1_1_33::migrate_gateway_details( &old_paths.common_paths, - &updated.storage_paths.common_paths, + &updated_step1.storage_paths.common_paths, None, ) .await?; + let updated = updated_step1.try_upgrade()?; + + updated.save_to(config_path)?; + Ok(true) +} + +async fn try_upgrade_v2_config>( + config_path: P, +) -> Result { + // explicitly load it as v2 (which is incompatible with the current one) + let Ok(old_config) = ConfigV2::read_from_toml_file(config_path.as_ref()) else { + // if we failed to load it, there might have been nothing to upgrade + // or maybe it was an even older file. in either way. just ignore it and carry on with our day + return Ok(false); + }; + info!("It seems the client is using v2 config template."); + info!("It is going to get updated to the current specification."); + + let updated = old_config.try_upgrade()?; + updated.save_to(config_path)?; Ok(true) } pub async fn try_upgrade_config>(config_path: P) -> Result<(), IpPacketRouterError> { trace!("Attempting to upgrade config"); - if try_upgrade_v1_config(config_path).await? { + if try_upgrade_v1_config(config_path.as_ref()).await? { + return Ok(()); + } + if try_upgrade_v2_config(config_path).await? { return Ok(()); } diff --git a/service-providers/ip-packet-router/src/config/mod.rs b/service-providers/ip-packet-router/src/config/mod.rs index 1f7aad3cc2..a3968200f3 100644 --- a/service-providers/ip-packet-router/src/config/mod.rs +++ b/service-providers/ip-packet-router/src/config/mod.rs @@ -22,6 +22,7 @@ use self::template::CONFIG_TEMPLATE; pub mod helpers; pub mod old_config_v1; +pub mod old_config_v2; mod persistence; mod template; diff --git a/service-providers/ip-packet-router/src/config/old_config_v1.rs b/service-providers/ip-packet-router/src/config/old_config_v1.rs index b7cddacf00..f6f2863085 100644 --- a/service-providers/ip-packet-router/src/config/old_config_v1.rs +++ b/service-providers/ip-packet-router/src/config/old_config_v1.rs @@ -2,7 +2,6 @@ // SPDX-License-Identifier: GPL-3.0-only use crate::config::persistence::IpPacketRouterPaths; -use crate::config::Config; use crate::config::{default_config_filepath, IpPacketRouter}; use crate::error::IpPacketRouterError; use nym_bin_common::logging::LoggingSettings; @@ -16,6 +15,8 @@ use std::io; use std::path::{Path, PathBuf}; use url::Url; +use super::old_config_v2::ConfigV2; + #[derive(Debug, Deserialize, PartialEq, Eq, Serialize, Clone)] pub struct IpPacketRouterPathsV1 { #[serde(flatten)] @@ -39,6 +40,22 @@ pub struct ConfigV1 { pub logging: LoggingSettings, } +impl TryFrom for ConfigV2 { + type Error = IpPacketRouterError; + + fn try_from(value: ConfigV1) -> Result { + Ok(ConfigV2 { + base: value.base.into(), + ip_packet_router: value.ip_packet_router.into(), + storage_paths: IpPacketRouterPaths { + common_paths: value.storage_paths.common_paths.upgrade_default()?, + ip_packet_router_description: value.storage_paths.ip_packet_router_description, + }, + logging: value.logging, + }) + } +} + impl ConfigV1 { pub fn read_from_toml_file>(path: P) -> io::Result { read_config_from_toml_file(path) @@ -47,18 +64,6 @@ impl ConfigV1 { pub fn read_from_default_path>(id: P) -> io::Result { Self::read_from_toml_file(default_config_filepath(id)) } - - pub fn try_upgrade(self) -> Result { - Ok(Config { - base: self.base.into(), - ip_packet_router: self.ip_packet_router.into(), - storage_paths: IpPacketRouterPaths { - common_paths: self.storage_paths.common_paths.upgrade_default()?, - ip_packet_router_description: self.storage_paths.ip_packet_router_description, - }, - logging: self.logging, - }) - } } #[derive(Debug, Clone, Deserialize, PartialEq, Serialize)] diff --git a/service-providers/ip-packet-router/src/config/old_config_v2.rs b/service-providers/ip-packet-router/src/config/old_config_v2.rs new file mode 100644 index 0000000000..9a1f91f11f --- /dev/null +++ b/service-providers/ip-packet-router/src/config/old_config_v2.rs @@ -0,0 +1,42 @@ +use std::{io, path::Path}; + +use crate::{config::Config, error::IpPacketRouterError}; +use nym_bin_common::logging::LoggingSettings; +use nym_client_core::config::old_config_v1_1_54::ConfigV1_1_54 as BaseConfigV1_1_54; +use nym_config::read_config_from_toml_file; +use serde::{Deserialize, Serialize}; + +use super::{default_config_filepath, IpPacketRouter, IpPacketRouterPaths}; + +#[derive(Debug, Clone, Deserialize, PartialEq, Serialize)] +#[serde(deny_unknown_fields)] +pub struct ConfigV2 { + #[serde(flatten)] + pub base: BaseConfigV1_1_54, + + #[serde(default)] + pub ip_packet_router: IpPacketRouter, + + pub storage_paths: IpPacketRouterPaths, + + pub logging: LoggingSettings, +} + +impl ConfigV2 { + pub fn read_from_toml_file>(path: P) -> io::Result { + read_config_from_toml_file(path) + } + + pub fn read_from_default_path>(id: P) -> io::Result { + Self::read_from_toml_file(default_config_filepath(id)) + } + + pub fn try_upgrade(self) -> Result { + Ok(Config { + base: self.base.into(), + ip_packet_router: self.ip_packet_router, + storage_paths: self.storage_paths, + logging: self.logging, + }) + } +} diff --git a/service-providers/ip-packet-router/src/config/template.rs b/service-providers/ip-packet-router/src/config/template.rs index 5338b4b497..b40456dbe0 100644 --- a/service-providers/ip-packet-router/src/config/template.rs +++ b/service-providers/ip-packet-router/src/config/template.rs @@ -88,10 +88,6 @@ ip_packet_router_description = '{{ storage_paths.ip_packet_router_description }} [debug] -[debug.traffic] -average_packet_delay = '{{ debug.traffic.average_packet_delay }}' -message_sending_average_delay = '{{ debug.traffic.message_sending_average_delay }}' - [debug.acknowledgements] average_ack_delay = '{{ debug.acknowledgements.average_ack_delay }}' diff --git a/service-providers/network-requester/src/config/helpers.rs b/service-providers/network-requester/src/config/helpers.rs index 2b29776dea..3655b9ea76 100644 --- a/service-providers/network-requester/src/config/helpers.rs +++ b/service-providers/network-requester/src/config/helpers.rs @@ -2,11 +2,12 @@ // SPDX-License-Identifier: Apache-2.0 use crate::config::default_config_filepath; -use crate::config::old::v5::ConfigV5; +use crate::config::old::v6::ConfigV6; use crate::config::old_config_v1_1_13::OldConfigV1; use crate::config::old_config_v1_1_20::ConfigV2; use crate::config::old_config_v1_1_20_2::ConfigV3; use crate::config::old_config_v1_1_33::ConfigV4; +use crate::config::old_config_v1_1_54::ConfigV5; use crate::config::Config; use crate::error::NetworkRequesterError; use log::{info, trace}; @@ -42,7 +43,8 @@ async fn try_upgrade_v1_config>( ) .await?; - let updated: Config = updated_step4.into(); + let updated_step5: ConfigV6 = updated_step4.into(); + let updated: Config = updated_step5.into(); updated.save_to(config_path)?; Ok(true) @@ -76,7 +78,8 @@ async fn try_upgrade_v2_config>( ) .await?; - let updated: Config = updated_step3.into(); + let updated_step4: ConfigV6 = updated_step3.into(); + let updated: Config = updated_step4.into(); updated.save_to(config_path)?; Ok(true) @@ -107,7 +110,8 @@ async fn try_upgrade_v3_config>( ) .await?; - let updated: Config = updated_step2.into(); + let updated_step3: ConfigV6 = updated_step2.into(); + let updated: Config = updated_step3.into(); updated.save_to(config_path)?; Ok(true) @@ -137,7 +141,8 @@ async fn try_upgrade_v4_config>( ) .await?; - let updated: Config = updated_step1.into(); + let updated_step2: ConfigV6 = updated_step1.into(); + let updated: Config = updated_step2.into(); updated.save_to(config_path)?; Ok(true) @@ -155,6 +160,25 @@ async fn try_upgrade_v5_config>( info!("It seems the client is using <= v5 config template."); info!("It is going to get updated to the current specification."); + let updated_step1: ConfigV6 = old_config.into(); + let updated: Config = updated_step1.into(); + updated.save_to(config_path)?; + + Ok(true) +} + +async fn try_upgrade_v6_config>( + config_path: P, +) -> Result { + // explicitly load it as v6 (which is incompatible with the current one) + let Ok(old_config) = ConfigV6::read_from_toml_file(config_path.as_ref()) else { + // if we failed to load it, there might have been nothing to upgrade + // or maybe it was an even older file. in either way. just ignore it and carry on with our day + return Ok(false); + }; + info!("It seems the client is using <= v6 config template."); + info!("It is going to get updated to the current specification."); + let updated: Config = old_config.into(); updated.save_to(config_path)?; @@ -177,7 +201,10 @@ pub async fn try_upgrade_config>( if try_upgrade_v4_config(config_path.as_ref()).await? { return Ok(()); } - if try_upgrade_v5_config(config_path).await? { + if try_upgrade_v5_config(config_path.as_ref()).await? { + return Ok(()); + } + if try_upgrade_v6_config(config_path).await? { return Ok(()); } diff --git a/service-providers/network-requester/src/config/mod.rs b/service-providers/network-requester/src/config/mod.rs index 4fdb5170a2..6284186c95 100644 --- a/service-providers/network-requester/src/config/mod.rs +++ b/service-providers/network-requester/src/config/mod.rs @@ -32,6 +32,7 @@ pub use old::v1 as old_config_v1_1_13; pub use old::v2 as old_config_v1_1_20; pub use old::v3 as old_config_v1_1_20_2; pub use old::v4 as old_config_v1_1_33; +pub use old::v5 as old_config_v1_1_54; const DEFAULT_NETWORK_REQUESTERS_DIR: &str = "network-requester"; diff --git a/service-providers/network-requester/src/config/old/mod.rs b/service-providers/network-requester/src/config/old/mod.rs index 3a529cd6c0..4eae34bac2 100644 --- a/service-providers/network-requester/src/config/old/mod.rs +++ b/service-providers/network-requester/src/config/old/mod.rs @@ -6,3 +6,4 @@ pub mod v2; pub mod v3; pub mod v4; pub mod v5; +pub mod v6; diff --git a/service-providers/network-requester/src/config/old/v5.rs b/service-providers/network-requester/src/config/old/v5.rs index d02a540548..d8b4c6d99d 100644 --- a/service-providers/network-requester/src/config/old/v5.rs +++ b/service-providers/network-requester/src/config/old/v5.rs @@ -3,10 +3,9 @@ use crate::config::persistence::old::v3::NetworkRequesterPathsV3; use crate::config::persistence::NetworkRequesterPaths; -use crate::config::Config; use crate::config::{default_config_filepath, Debug, NetworkRequester}; use nym_bin_common::logging::LoggingSettings; -use nym_client_core::config::Config as BaseClientConfig; +use nym_client_core::config::old_config_v1_1_54::ConfigV1_1_54 as BaseConfigV1_1_54; use nym_config::read_config_from_toml_file; use nym_config::serde_helpers::de_maybe_stringified; use nym_network_defaults::mainnet; @@ -16,6 +15,8 @@ use std::path::Path; use std::time::Duration; use url::Url; +use super::v6::ConfigV6; + pub const DEFAULT_STANDARD_LIST_UPDATE_INTERVAL: Duration = Duration::from_secs(30 * 60); #[derive(Debug, Clone, Deserialize, PartialEq, Serialize)] @@ -27,7 +28,7 @@ pub struct ConfigV5 { // and then just make type alias for the current one, i.e. `type Config = ConfigV2`. // then in 'old' configs we could simply use the underlying type as opposed to the alias for easier upgrades. #[serde(flatten)] - pub base: BaseClientConfig, + pub base: BaseConfigV1_1_54, #[serde(default)] pub network_requester: NetworkRequesterV5, @@ -51,10 +52,10 @@ impl ConfigV5 { } } -impl From for Config { +impl From for ConfigV6 { fn from(value: ConfigV5) -> Self { - Config { - base: value.base, + ConfigV6 { + base: value.base.into(), network_requester: value.network_requester.into(), storage_paths: NetworkRequesterPaths { common_paths: value.storage_paths.common_paths, diff --git a/service-providers/network-requester/src/config/old/v6.rs b/service-providers/network-requester/src/config/old/v6.rs new file mode 100644 index 0000000000..f50e4ddb77 --- /dev/null +++ b/service-providers/network-requester/src/config/old/v6.rs @@ -0,0 +1,50 @@ +use std::{io, path::Path}; + +use nym_bin_common::logging::LoggingSettings; +use nym_client_core::config::Config as BaseClientConfig; +use nym_config::read_config_from_toml_file; +use serde::{Deserialize, Serialize}; + +use crate::config::{ + default_config_filepath, Config, Debug, NetworkRequester, NetworkRequesterPaths, +}; + +#[derive(Debug, Clone, Deserialize, PartialEq, Serialize)] +#[serde(deny_unknown_fields)] +pub struct ConfigV6 { + #[serde(flatten)] + pub base: BaseClientConfig, + + #[serde(default)] + pub network_requester: NetworkRequester, + + pub storage_paths: NetworkRequesterPaths, + + #[serde(default)] + pub network_requester_debug: Debug, + + pub logging: LoggingSettings, +} + +impl ConfigV6 { + pub fn read_from_toml_file>(path: P) -> io::Result { + read_config_from_toml_file(path) + } + + #[allow(dead_code)] + pub fn read_from_default_path>(id: P) -> io::Result { + Self::read_from_toml_file(default_config_filepath(id)) + } +} + +impl From for Config { + fn from(value: ConfigV6) -> Self { + Config { + base: value.base, + network_requester: value.network_requester, + storage_paths: value.storage_paths, + network_requester_debug: value.network_requester_debug, + logging: value.logging, + } + } +} diff --git a/service-providers/network-requester/src/config/template.rs b/service-providers/network-requester/src/config/template.rs index 053dca47d4..ac1f52f37b 100644 --- a/service-providers/network-requester/src/config/template.rs +++ b/service-providers/network-requester/src/config/template.rs @@ -101,10 +101,6 @@ upstream_exit_policy_url = '{{ network_requester.upstream_exit_policy_url }}' [debug] -[debug.traffic] -average_packet_delay = '{{ debug.traffic.average_packet_delay }}' -message_sending_average_delay = '{{ debug.traffic.message_sending_average_delay }}' - [debug.acknowledgements] average_ack_delay = '{{ debug.acknowledgements.average_ack_delay }}'