From fb85de9ab635dd2135229f06d8440b8ea3fe2625 Mon Sep 17 00:00:00 2001 From: benedettadavico Date: Fri, 16 Jan 2026 10:12:01 +0100 Subject: [PATCH 1/5] bump versions --- Cargo.lock | 14 +++++++------- clients/native/Cargo.toml | 2 +- clients/socks5/Cargo.toml | 2 +- nym-api/Cargo.toml | 2 +- nym-node/Cargo.toml | 2 +- service-providers/network-requester/Cargo.toml | 2 +- tools/nym-cli/Cargo.toml | 2 +- tools/nymvisor/Cargo.toml | 2 +- 8 files changed, 14 insertions(+), 14 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 35d8872605..f1f9d20e03 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5205,7 +5205,7 @@ dependencies = [ [[package]] name = "nym-api" -version = "1.1.71" +version = "1.1.72" dependencies = [ "anyhow", "async-trait", @@ -5428,7 +5428,7 @@ dependencies = [ [[package]] name = "nym-cli" -version = "1.1.68" +version = "1.1.69" dependencies = [ "anyhow", "base64 0.22.1", @@ -5511,7 +5511,7 @@ dependencies = [ [[package]] name = "nym-client" -version = "1.1.68" +version = "1.1.69" dependencies = [ "bs58", "clap", @@ -6903,7 +6903,7 @@ dependencies = [ [[package]] name = "nym-network-requester" -version = "1.1.69" +version = "1.1.70" dependencies = [ "addr", "anyhow", @@ -6953,7 +6953,7 @@ dependencies = [ [[package]] name = "nym-node" -version = "1.23.0" +version = "1.24.0" dependencies = [ "anyhow", "arc-swap", @@ -7493,7 +7493,7 @@ dependencies = [ [[package]] name = "nym-socks5-client" -version = "1.1.68" +version = "1.1.69" dependencies = [ "bs58", "clap", @@ -8234,7 +8234,7 @@ dependencies = [ [[package]] name = "nymvisor" -version = "0.1.33" +version = "0.1.34" dependencies = [ "anyhow", "bytes", diff --git a/clients/native/Cargo.toml b/clients/native/Cargo.toml index 026f483626..55617ac5ba 100644 --- a/clients/native/Cargo.toml +++ b/clients/native/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "nym-client" -version = "1.1.68" +version = "1.1.69" authors = ["Dave Hrycyszyn ", "Jędrzej Stuczyński "] description = "Implementation of the Nym Client" edition = "2021" diff --git a/clients/socks5/Cargo.toml b/clients/socks5/Cargo.toml index 500dd6cc6a..1a5a431f50 100644 --- a/clients/socks5/Cargo.toml +++ b/clients/socks5/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "nym-socks5-client" -version = "1.1.68" +version = "1.1.69" authors = ["Dave Hrycyszyn "] description = "A SOCKS5 localhost proxy that converts incoming messages to Sphinx and sends them to a Nym address" edition = "2021" diff --git a/nym-api/Cargo.toml b/nym-api/Cargo.toml index c7037d32f9..e4e094a39b 100644 --- a/nym-api/Cargo.toml +++ b/nym-api/Cargo.toml @@ -4,7 +4,7 @@ [package] name = "nym-api" license = "GPL-3.0" -version = "1.1.71" +version = "1.1.72" authors.workspace = true edition = "2021" rust-version.workspace = true diff --git a/nym-node/Cargo.toml b/nym-node/Cargo.toml index f8467cdd3c..fd5ffbd12b 100644 --- a/nym-node/Cargo.toml +++ b/nym-node/Cargo.toml @@ -3,7 +3,7 @@ [package] name = "nym-node" -version = "1.23.0" +version = "1.24.0" authors.workspace = true repository.workspace = true homepage.workspace = true diff --git a/service-providers/network-requester/Cargo.toml b/service-providers/network-requester/Cargo.toml index 2c11e6ea3f..1c30f17c30 100644 --- a/service-providers/network-requester/Cargo.toml +++ b/service-providers/network-requester/Cargo.toml @@ -4,7 +4,7 @@ [package] name = "nym-network-requester" license = "GPL-3.0" -version = "1.1.69" +version = "1.1.70" authors.workspace = true edition.workspace = true rust-version = "1.85" diff --git a/tools/nym-cli/Cargo.toml b/tools/nym-cli/Cargo.toml index 1a8aa016eb..56ab89f71b 100644 --- a/tools/nym-cli/Cargo.toml +++ b/tools/nym-cli/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "nym-cli" -version = "1.1.68" +version = "1.1.69" authors.workspace = true edition = "2021" license.workspace = true diff --git a/tools/nymvisor/Cargo.toml b/tools/nymvisor/Cargo.toml index 7329119eb9..03914ea8c4 100644 --- a/tools/nymvisor/Cargo.toml +++ b/tools/nymvisor/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "nymvisor" -version = "0.1.33" +version = "0.1.34" authors.workspace = true repository.workspace = true homepage.workspace = true From 036ae5c6dc80a72578beeb69dc4cc167fbe5d019 Mon Sep 17 00:00:00 2001 From: jmwample Date: Fri, 16 Jan 2026 15:01:08 -0700 Subject: [PATCH 2/5] apply configured api urls via env --- Cargo.lock | 2 + common/network-defaults/Cargo.toml | 4 +- common/network-defaults/src/mainnet.rs | 11 +++++ common/network-defaults/src/network.rs | 63 +++++++++++++++++++----- common/network-defaults/src/var_names.rs | 2 + 5 files changed, 68 insertions(+), 14 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f1f9d20e03..1dda35940c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6862,6 +6862,8 @@ dependencies = [ "regex", "schemars 0.8.22", "serde", + "serde_json", + "tracing", "url", "utoipa", ] diff --git a/common/network-defaults/Cargo.toml b/common/network-defaults/Cargo.toml index d8cbc36711..1287d2a7e4 100644 --- a/common/network-defaults/Cargo.toml +++ b/common/network-defaults/Cargo.toml @@ -12,6 +12,8 @@ dotenvy = { workspace = true, optional = true } log = { workspace = true, optional = true } schemars = { workspace = true, features = ["preserve_order"], optional = true } serde = { workspace = true, features = ["derive"], optional = true } +serde_json = {workspace = true, optional = true } +tracing = {workspace = true, optional = true } url = { workspace = true, optional = true } utoipa = { workspace = true, optional = true } @@ -20,7 +22,7 @@ utoipa = { workspace = true, optional = true } [features] default = ["env", "network"] -env = ["dotenvy", "log"] +env = ["dotenvy", "log", "serde_json", "tracing"] network = ["schemars", "serde", "url"] utoipa = [ "dep:utoipa" ] diff --git a/common/network-defaults/src/mainnet.rs b/common/network-defaults/src/mainnet.rs index 8e253a77b7..c4b81aa2db 100644 --- a/common/network-defaults/src/mainnet.rs +++ b/common/network-defaults/src/mainnet.rs @@ -72,6 +72,12 @@ pub const NYM_VPN_APIS: &[ApiUrlConst] = &[ }, ]; +fn serialize_api_urls(urls: &[ApiUrlConst]) -> String { + serde_json::to_string(urls) + .inspect_err(|e| tracing::warn!("failed to serialize nym_api_urls for env: {e}")) + .unwrap_or(String::new()) +} + // I'm making clippy mad on purpose, because that url HAS TO be updated and deployed before merging pub const EXIT_POLICY_URL: &str = "https://nymtech.net/.wellknown/network-requester/exit-policy.txt"; @@ -162,9 +168,11 @@ pub fn export_to_env() { ); set_var_to_default(var_names::NYXD, NYXD_URL); set_var_to_default(var_names::NYM_API, NYM_API); + set_var_to_default(var_names::NYM_APIS, &serialize_api_urls(NYM_APIS)); set_var_to_default(var_names::NYXD_WEBSOCKET, NYXD_WS); set_var_to_default(var_names::EXIT_POLICY_URL, EXIT_POLICY_URL); set_var_to_default(var_names::NYM_VPN_API, NYM_VPN_API); + set_var_to_default(var_names::NYM_VPN_APIS, &serialize_api_urls(NYM_VPN_APIS)); set_var_to_default( var_names::UPGRADE_MODE_ATTESTATION_URL, UPGRADE_MODE_ATTESTATION_URL, @@ -211,6 +219,9 @@ pub fn export_to_env_if_not_set() { ); set_var_conditionally_to_default(var_names::NYXD, NYXD_URL); set_var_conditionally_to_default(var_names::NYM_API, NYM_API); + set_var_conditionally_to_default(var_names::NYM_APIS, &serialize_api_urls(NYM_APIS)); + set_var_conditionally_to_default(var_names::NYM_VPN_API, NYM_VPN_API); + set_var_conditionally_to_default(var_names::NYM_VPN_APIS, &serialize_api_urls(NYM_VPN_APIS)); set_var_conditionally_to_default(var_names::NYXD_WEBSOCKET, NYXD_WS); set_var_conditionally_to_default(var_names::EXIT_POLICY_URL, EXIT_POLICY_URL); set_var_conditionally_to_default( diff --git a/common/network-defaults/src/network.rs b/common/network-defaults/src/network.rs index 23ca16dddf..d6f3a66125 100644 --- a/common/network-defaults/src/network.rs +++ b/common/network-defaults/src/network.rs @@ -7,6 +7,13 @@ use serde::{Deserialize, Serialize}; use std::ops::Not; use url::Url; +#[cfg(feature = "env")] +use crate::var_names; +#[cfg(feature = "env")] +use std::env::{VarError, var}; +#[cfg(feature = "env")] +use std::ffi::OsStr; + #[derive(Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize, JsonSchema)] #[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))] pub struct ChainDetails { @@ -55,7 +62,7 @@ pub struct ApiUrl { pub front_hosts: Option>, } -#[derive(Copy, Clone)] +#[derive(Copy, Clone, Debug, Serialize)] pub struct ApiUrlConst<'a> { pub url: &'a str, pub front_hosts: Option<&'a [&'a str]>, @@ -106,10 +113,6 @@ impl NymNetworkDetails { #[cfg(feature = "env")] pub fn new_from_env() -> Self { - use crate::var_names; - use std::env::{VarError, var}; - use std::ffi::OsStr; - fn get_optional_env>(env: K) -> Option { match var(env) { Ok(var) => { @@ -125,6 +128,11 @@ impl NymNetworkDetails { } let nym_api = var(var_names::NYM_API).expect("nym api not set"); + let nym_api_urls = try_parse_api_urls(var_names::NYM_APIS).unwrap_or(vec![ApiUrl { + url: nym_api.clone(), + front_hosts: None, + }]); + let nym_vpn_api_urls = try_parse_api_urls(var_names::NYM_VPN_APIS); NymNetworkDetails::new_empty() .with_network_name(var(var_names::NETWORK_NAME).expect("network name not set")) @@ -161,10 +169,8 @@ impl NymNetworkDetails { .with_multisig_contract(get_optional_env(var_names::MULTISIG_CONTRACT_ADDRESS)) .with_coconut_dkg_contract(get_optional_env(var_names::COCONUT_DKG_CONTRACT_ADDRESS)) .with_nym_vpn_api_url(get_optional_env(var_names::NYM_VPN_API)) - .with_nym_api_urls(Some(vec![ApiUrl { - url: nym_api, - front_hosts: None, - }])) + .with_nym_vpn_api_urls(nym_vpn_api_urls) + .with_nym_api_urls(nym_api_urls) } pub fn new_mainnet() -> Self { @@ -218,6 +224,9 @@ impl NymNetworkDetails { } } unsafe { + let nym_api_urls = self.nym_api_urls(); + let nym_vpn_api_urls = self.nym_vpn_api_urls(); + set_var(var_names::NETWORK_NAME, self.network_name); set_var(var_names::BECH32_PREFIX, self.chain_details.bech32_account_prefix); @@ -243,9 +252,9 @@ impl NymNetworkDetails { set_optional_var(var_names::COCONUT_DKG_CONTRACT_ADDRESS, self.contracts.coconut_dkg_contract_address); set_optional_var(var_names::NYM_VPN_API, self.nym_vpn_api_url); + set_optional_var(var_names::NYM_APIS, nym_vpn_api_urls); + } - - } pub fn default_gas_price_amount(&self) -> f64 { @@ -355,8 +364,14 @@ impl NymNetworkDetails { } #[must_use] - pub fn with_nym_api_urls(mut self, urls: Option>) -> Self { - self.nym_api_urls = urls; + pub fn with_nym_api_urls(mut self, urls: Vec) -> Self { + self.nym_api_urls = Some(urls); + self + } + + #[must_use] + pub fn with_nym_vpn_api_urls(mut self, urls: Option>) -> Self { + self.nym_vpn_api_urls = urls; self } @@ -366,6 +381,28 @@ impl NymNetworkDetails { .expect("the provided nym-vpn api url is invalid!") }) } + + #[cfg(feature = "env")] + fn nym_api_urls(&self) -> Option { + serde_json::to_string(self.nym_api_urls.as_deref()?) + .inspect_err(|e| tracing::warn!("failed to serialize nym_api_urls for env: {e}")) + .ok() + } + + #[cfg(feature = "env")] + fn nym_vpn_api_urls(&self) -> Option { + serde_json::to_string(self.nym_vpn_api_urls.as_deref()?) + .inspect_err(|e| tracing::warn!("failed to serialize nym_vpn_api_urls for env: {e}")) + .ok() + } +} + +#[cfg(feature = "env")] +fn try_parse_api_urls(k: impl AsRef) -> Option> { + let raw = var(k).ok()?; + serde_json::from_str(&raw) + .inspect_err(|e| tracing::warn!("failed to parse api urls from env \"{raw:?}\": {e}")) + .ok() } #[derive(Debug, Copy, Serialize, Deserialize, Clone, PartialEq, Eq)] diff --git a/common/network-defaults/src/var_names.rs b/common/network-defaults/src/var_names.rs index 897937b0fe..4bfb1d5877 100644 --- a/common/network-defaults/src/var_names.rs +++ b/common/network-defaults/src/var_names.rs @@ -21,9 +21,11 @@ pub const COCONUT_DKG_CONTRACT_ADDRESS: &str = "COCONUT_DKG_CONTRACT_ADDRESS"; pub const REWARDING_VALIDATOR_ADDRESS: &str = "REWARDING_VALIDATOR_ADDRESS"; pub const NYXD: &str = "NYXD"; pub const NYM_API: &str = "NYM_API"; +pub const NYM_APIS: &str = "NYM_APIS"; pub const NYXD_WEBSOCKET: &str = "NYXD_WS"; pub const EXIT_POLICY_URL: &str = "EXIT_POLICY"; pub const NYM_VPN_API: &str = "NYM_VPN_API"; +pub const NYM_VPN_APIS: &str = "NYM_VPN_APIS"; pub const CLIENT_STATS_COLLECTION_PROVIDER: &str = "CLIENT_STATS_COLLECTION_PROVIDER"; pub const UPGRADE_MODE_ATTESTATION_URL: &str = "UPGRADE_MODE_ATTESTATION_URL"; pub const UPGRADE_MODE_ATTESTER_ED25519_BS58_PUBKEY: &str = "UPGRADE_MODE_ATTESTER_ED25519_PUBKEY"; From 377c22f283a3b787d148886f7f1f0e1bee402208 Mon Sep 17 00:00:00 2001 From: jmwample Date: Fri, 16 Jan 2026 15:11:04 -0700 Subject: [PATCH 3/5] minor fixes --- common/network-defaults/src/mainnet.rs | 2 +- common/network-defaults/src/network.rs | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/common/network-defaults/src/mainnet.rs b/common/network-defaults/src/mainnet.rs index c4b81aa2db..c5dd02aaab 100644 --- a/common/network-defaults/src/mainnet.rs +++ b/common/network-defaults/src/mainnet.rs @@ -75,7 +75,7 @@ pub const NYM_VPN_APIS: &[ApiUrlConst] = &[ fn serialize_api_urls(urls: &[ApiUrlConst]) -> String { serde_json::to_string(urls) .inspect_err(|e| tracing::warn!("failed to serialize nym_api_urls for env: {e}")) - .unwrap_or(String::new()) + .unwrap_or_default() } // I'm making clippy mad on purpose, because that url HAS TO be updated and deployed before merging diff --git a/common/network-defaults/src/network.rs b/common/network-defaults/src/network.rs index d6f3a66125..c85101b690 100644 --- a/common/network-defaults/src/network.rs +++ b/common/network-defaults/src/network.rs @@ -252,7 +252,8 @@ impl NymNetworkDetails { set_optional_var(var_names::COCONUT_DKG_CONTRACT_ADDRESS, self.contracts.coconut_dkg_contract_address); set_optional_var(var_names::NYM_VPN_API, self.nym_vpn_api_url); - set_optional_var(var_names::NYM_APIS, nym_vpn_api_urls); + set_optional_var(var_names::NYM_VPN_APIS, nym_vpn_api_urls); + set_optional_var(var_names::NYM_APIS, nym_api_urls); } } From 52c47a950e876ef13d16acae3b415a587b6145e3 Mon Sep 17 00:00:00 2001 From: jmwample Date: Tue, 20 Jan 2026 09:21:55 -0700 Subject: [PATCH 4/5] env feature locking to protect contracts --- common/network-defaults/src/mainnet.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/common/network-defaults/src/mainnet.rs b/common/network-defaults/src/mainnet.rs index c5dd02aaab..4465875b36 100644 --- a/common/network-defaults/src/mainnet.rs +++ b/common/network-defaults/src/mainnet.rs @@ -72,6 +72,7 @@ pub const NYM_VPN_APIS: &[ApiUrlConst] = &[ }, ]; +#[cfg(feature = "env")] fn serialize_api_urls(urls: &[ApiUrlConst]) -> String { serde_json::to_string(urls) .inspect_err(|e| tracing::warn!("failed to serialize nym_api_urls for env: {e}")) From b5d1e6a93ff85e41b2ab0ba4d5732ec1308fa13d Mon Sep 17 00:00:00 2001 From: benedettadavico Date: Fri, 23 Jan 2026 17:24:48 +0100 Subject: [PATCH 5/5] ack fix --- common/nymsphinx/framing/src/processing.rs | 35 ++++++++-------------- 1 file changed, 12 insertions(+), 23 deletions(-) diff --git a/common/nymsphinx/framing/src/processing.rs b/common/nymsphinx/framing/src/processing.rs index e482ad1927..afaba392dd 100644 --- a/common/nymsphinx/framing/src/processing.rs +++ b/common/nymsphinx/framing/src/processing.rs @@ -14,7 +14,7 @@ use nym_sphinx_types::{ }; use std::fmt::Display; use thiserror::Error; -use tracing::{debug, trace}; +use tracing::{debug, info, trace}; #[derive(Debug)] pub enum MixProcessingResultData { @@ -364,28 +364,17 @@ fn split_into_ack_and_message( | PacketSize::ExtendedPacket32 | PacketSize::OutfoxRegularPacket => { trace!("received a normal packet!"); - cfg_if::cfg_if! { - if #[cfg(feature = "no-mix-acks")] { - let _ = packet_type; - let _ = key_rotation; - - // AIDEV-NOTE: When no-mix-acks is enabled, skip ack extraction entirely. - // The full payload (including ack portion) is returned as the message. - Ok((None, data)) - } else { - let (ack_data, message) = split_hop_data_into_ack_and_message(data, packet_type)?; - let (ack_first_hop, ack_packet) = - match SurbAck::try_recover_first_hop_packet(&ack_data, packet_type) { - Ok((first_hop, packet)) => (first_hop, packet), - Err(err) => { - tracing::info!("Failed to recover first hop from ack data: {err}"); - return Err(err.into()); - } - }; - let forward_ack = MixPacket::new(ack_first_hop, ack_packet, packet_type, key_rotation); - Ok((Some(forward_ack), message)) - } - } + let (ack_data, message) = split_hop_data_into_ack_and_message(data, packet_type)?; + let (ack_first_hop, ack_packet) = + match SurbAck::try_recover_first_hop_packet(&ack_data, packet_type) { + Ok((first_hop, packet)) => (first_hop, packet), + Err(err) => { + info!("Failed to recover first hop from ack data: {err}"); + return Err(err.into()); + } + }; + let forward_ack = MixPacket::new(ack_first_hop, ack_packet, packet_type, key_rotation); + Ok((Some(forward_ack), message)) } } }