From 16edca21b04acdbae8d1d1de593e06d6b32cf341 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C4=99drzej=20Stuczy=C5=84ski?= Date: Mon, 14 Oct 2024 11:41:36 +0100 Subject: [PATCH 01/11] allow to optionally skip state migration --- .../mixnet-contract/src/msg.rs | 1 + contracts/mixnet/src/contract.rs | 12 ++++++++---- .../testnet-manager/src/manager/network_init.rs | 1 + 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/common/cosmwasm-smart-contracts/mixnet-contract/src/msg.rs b/common/cosmwasm-smart-contracts/mixnet-contract/src/msg.rs index 06caec5376..0e728aaf63 100644 --- a/common/cosmwasm-smart-contracts/mixnet-contract/src/msg.rs +++ b/common/cosmwasm-smart-contracts/mixnet-contract/src/msg.rs @@ -830,4 +830,5 @@ pub enum QueryMsg { #[cw_serde] pub struct MigrateMsg { pub vesting_contract_address: Option, + pub unsafe_skip_state_updates: Option, } diff --git a/contracts/mixnet/src/contract.rs b/contracts/mixnet/src/contract.rs index b3e3cc5df2..25bca25919 100644 --- a/contracts/mixnet/src/contract.rs +++ b/contracts/mixnet/src/contract.rs @@ -576,11 +576,15 @@ pub fn migrate( set_build_information!(deps.storage)?; cw2::ensure_from_older_version(deps.storage, CONTRACT_NAME, CONTRACT_VERSION)?; - // remove all family-related things - crate::queued_migrations::families_purge(deps.branch())?; + let skip_state_updates = msg.unsafe_skip_state_updates.unwrap_or(false); - // prepare the ground for using nym-nodes rather than standalone mixnodes/gateways - migrate_to_nym_nodes_usage(deps.branch(), &msg)?; + if !skip_state_updates { + // remove all family-related things + crate::queued_migrations::families_purge(deps.branch())?; + + // prepare the ground for using nym-nodes rather than standalone mixnodes/gateways + migrate_to_nym_nodes_usage(deps.branch(), &msg)?; + } // due to circular dependency on contract addresses (i.e. mixnet contract requiring vesting contract address // and vesting contract requiring the mixnet contract address), if we ever want to deploy any new fresh diff --git a/tools/internal/testnet-manager/src/manager/network_init.rs b/tools/internal/testnet-manager/src/manager/network_init.rs index bdbf39cf32..b298f9b981 100644 --- a/tools/internal/testnet-manager/src/manager/network_init.rs +++ b/tools/internal/testnet-manager/src/manager/network_init.rs @@ -109,6 +109,7 @@ impl NetworkManager { ) -> Result { Ok(nym_mixnet_contract_common::MigrateMsg { vesting_contract_address: Some(ctx.network.contracts.vesting.address()?.to_string()), + unsafe_skip_state_updates: Some(true), }) } From c14481bb777fc4433f1ac714c770435259b277b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C4=99drzej=20Stuczy=C5=84ski?= Date: Mon, 14 Oct 2024 14:50:36 +0100 Subject: [PATCH 02/11] allow nym-api to control bind address with CLI --- nym-api/src/support/cli/init.rs | 6 ++++++ nym-api/src/support/cli/run.rs | 6 ++++++ nym-api/src/support/config/mod.rs | 3 +++ nym-api/src/support/config/override.rs | 7 +++++++ 4 files changed, 22 insertions(+) diff --git a/nym-api/src/support/cli/init.rs b/nym-api/src/support/cli/init.rs index 10ce41b6f9..a51933f150 100644 --- a/nym-api/src/support/cli/init.rs +++ b/nym-api/src/support/cli/init.rs @@ -4,6 +4,7 @@ use crate::support::config::default_config_filepath; use crate::support::config::helpers::initialise_new; use anyhow::bail; +use std::net::SocketAddr; #[derive(clap::Args, Debug)] pub(crate) struct Args { @@ -51,6 +52,11 @@ pub(crate) struct Args { /// Set this nym api to work in a enabled credentials that would attempt to use gateway with the bandwidth credential requirement #[clap(long, requires = "enable_monitor")] pub(crate) monitor_credentials_mode: bool, + + /// Socket address this api will use for binding its http API. + /// default: `127.0.0.1:8080` in `debug` builds and `0.0.0.0:8080` in `release` + #[clap(long)] + pub(crate) bind_address: Option, // #[clap(short, long, default_value_t = OutputFormat::default())] // output: OutputFormat, } diff --git a/nym-api/src/support/cli/run.rs b/nym-api/src/support/cli/run.rs index 08e8d49f94..c3fabc81e1 100644 --- a/nym-api/src/support/cli/run.rs +++ b/nym-api/src/support/cli/run.rs @@ -35,6 +35,7 @@ use nym_config::defaults::NymNetworkDetails; use nym_sphinx::receiver::SphinxMessageReceiver; use nym_task::TaskManager; use nym_validator_client::nyxd::Coin; +use std::net::SocketAddr; use std::sync::Arc; use tokio_util::sync::CancellationToken; use tracing::{error, info}; @@ -86,6 +87,11 @@ pub(crate) struct Args { /// default: None - config value will be used instead #[clap(long)] pub(crate) monitor_credentials_mode: Option, + + /// Socket address this api will use for binding its http API. + /// default: `127.0.0.1:8080` in `debug` builds and `0.0.0.0:8080` in `release` + #[clap(long)] + pub(crate) bind_address: Option, } async fn start_nym_api_tasks_axum(config: &Config) -> anyhow::Result { diff --git a/nym-api/src/support/config/mod.rs b/nym-api/src/support/config/mod.rs index 235464dc0a..8d1809668f 100644 --- a/nym-api/src/support/config/mod.rs +++ b/nym-api/src/support/config/mod.rs @@ -169,6 +169,9 @@ impl Config { if let Some(monitor_credentials_mode) = args.monitor_credentials_mode { self.network_monitor.debug.disabled_credentials_mode = !monitor_credentials_mode } + if let Some(http_bind_address) = args.bind_address { + self.base.bind_address = http_bind_address + } self } diff --git a/nym-api/src/support/config/override.rs b/nym-api/src/support/config/override.rs index dea892d2a9..059d0f8136 100644 --- a/nym-api/src/support/config/override.rs +++ b/nym-api/src/support/config/override.rs @@ -2,6 +2,7 @@ // SPDX-License-Identifier: GPL-3.0-only use crate::support::cli::{init, run}; +use std::net::SocketAddr; // Configuration that can be overridden. pub(crate) struct OverrideConfig { @@ -26,6 +27,10 @@ pub(crate) struct OverrideConfig { /// Set this nym api to work in a enabled credentials that would attempt to use gateway with the bandwidth credential requirement pub(crate) monitor_credentials_mode: Option, + + /// Socket address this api will use for binding its http API. + /// default: `127.0.0.1:8080` in `debug` builds and `0.0.0.0:8080` in `release` + pub(crate) bind_address: Option, } impl From for OverrideConfig { @@ -38,6 +43,7 @@ impl From for OverrideConfig { enable_zk_nym: Some(args.enable_zk_nym), announce_address: args.announce_address, monitor_credentials_mode: Some(args.monitor_credentials_mode), + bind_address: args.bind_address, } } } @@ -52,6 +58,7 @@ impl From for OverrideConfig { enable_zk_nym: args.enable_zk_nym, announce_address: args.announce_address, monitor_credentials_mode: args.monitor_credentials_mode, + bind_address: args.bind_address, } } } From 11f6db5304e0a1ca2c2d9fa3823bd666cb70ce94 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C4=99drzej=20Stuczy=C5=84ski?= Date: Mon, 14 Oct 2024 14:51:02 +0100 Subject: [PATCH 03/11] fixed compatibility with 'skimmed' endpoints by making "no_legacy" argument optional --- nym-api/src/nym_nodes/handlers/unstable/mod.rs | 4 ++-- nym-api/src/nym_nodes/handlers/unstable/skimmed.rs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/nym-api/src/nym_nodes/handlers/unstable/mod.rs b/nym-api/src/nym_nodes/handlers/unstable/mod.rs index add55ec427..a9110a599d 100644 --- a/nym-api/src/nym_nodes/handlers/unstable/mod.rs +++ b/nym-api/src/nym_nodes/handlers/unstable/mod.rs @@ -81,7 +81,7 @@ struct NodesParamsWithRole { role: Option, semver_compatibility: Option, - no_legacy: bool, + no_legacy: Option, page: Option, per_page: Option, } @@ -89,7 +89,7 @@ struct NodesParamsWithRole { #[derive(Debug, Deserialize, utoipa::IntoParams)] struct NodesParams { semver_compatibility: Option, - no_legacy: bool, + no_legacy: Option, page: Option, per_page: Option, } diff --git a/nym-api/src/nym_nodes/handlers/unstable/skimmed.rs b/nym-api/src/nym_nodes/handlers/unstable/skimmed.rs index df263d2e06..53dace0e09 100644 --- a/nym-api/src/nym_nodes/handlers/unstable/skimmed.rs +++ b/nym-api/src/nym_nodes/handlers/unstable/skimmed.rs @@ -143,7 +143,7 @@ where ); // 5. if we allow legacy nodes, repeat the procedure for them, otherwise return just nym-nodes - if query_params.no_legacy { + if let Some(true) = query_params.no_legacy { // min of all caches let refreshed_at = refreshed_at([ rewarded_set.timestamp(), From e87b00bce5fd56aadc1522876e2ba0314c95c299 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C4=99drzej=20Stuczy=C5=84ski?= Date: Mon, 14 Oct 2024 15:14:12 +0100 Subject: [PATCH 04/11] add the nym-nodes count to refresher log --- nym-api/src/nym_contract_cache/cache/refresher.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/nym-api/src/nym_contract_cache/cache/refresher.rs b/nym-api/src/nym_contract_cache/cache/refresher.rs index a46ef92afd..0e9e6f45f9 100644 --- a/nym-api/src/nym_contract_cache/cache/refresher.rs +++ b/nym-api/src/nym_contract_cache/cache/refresher.rs @@ -180,9 +180,10 @@ impl NymContractCacheRefresher { let contract_info = self.get_nym_contracts_info().await?; info!( - "Updating validator cache. There are {} mixnodes and {} gateways", + "Updating validator cache. There are {} [legacy] mixnodes, {} [legacy] gateways and {} nym nodes", mixnodes.len(), gateways.len(), + nym_nodes.len(), ); self.cache From 652f2db5c02ea16e8882c23e65086e45d537fe72 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C4=99drzej=20Stuczy=C5=84ski?= Date: Mon, 14 Oct 2024 17:55:00 +0100 Subject: [PATCH 05/11] exposed announce ports to nym-node CLI --- nym-node/src/cli/helpers.rs | 24 ++++++++++++++++++++++++ nym-node/src/env.rs | 2 ++ 2 files changed, 26 insertions(+) diff --git a/nym-node/src/cli/helpers.rs b/nym-node/src/cli/helpers.rs index 02a2b9ce6c..cabbd6d621 100644 --- a/nym-node/src/cli/helpers.rs +++ b/nym-node/src/cli/helpers.rs @@ -188,6 +188,15 @@ pub(crate) struct MixnetArgs { )] pub(crate) mixnet_bind_address: Option, + /// If applicable, custom port announced in the self-described API that other clients and nodes + /// will use. + /// Useful when the node is behind a proxy. + #[clap( + long, + env = NYMNODE_MIXNET_ANNOUNCE_PORT_ARG + )] + pub(crate) mixnet_announce_port: Option, + /// Addresses to nym APIs from which the node gets the view of the network. #[clap( long, @@ -223,6 +232,9 @@ impl MixnetArgs { if let Some(bind_address) = self.mixnet_bind_address { section.bind_address = bind_address } + if let Some(mixnet_announce_port) = self.mixnet_announce_port { + section.announce_port = Some(mixnet_announce_port) + } if let Some(nym_api_urls) = self.nym_api_urls { section.nym_api_urls = nym_api_urls } @@ -321,6 +333,15 @@ pub(crate) struct MixnodeArgs { env = NYMNODE_VERLOC_BIND_ADDRESS_ARG )] pub(crate) verloc_bind_address: Option, + + /// If applicable, custom port announced in the self-described API that other clients and nodes + /// will use. + /// Useful when the node is behind a proxy. + #[clap( + long, + env = NYMNODE_VERLOC_ANNOUNCE_PORT_ARG + )] + pub(crate) verloc_announce_port: Option, } impl MixnodeArgs { @@ -336,6 +357,9 @@ impl MixnodeArgs { if let Some(bind_address) = self.verloc_bind_address { section.verloc.bind_address = bind_address } + if let Some(announce_port) = self.verloc_announce_port { + section.verloc.announce_port = Some(announce_port) + } section } } diff --git a/nym-node/src/env.rs b/nym-node/src/env.rs index 6067c94aa7..d9b03a4b3e 100644 --- a/nym-node/src/env.rs +++ b/nym-node/src/env.rs @@ -35,6 +35,7 @@ pub mod vars { // mixnet: pub const NYMNODE_MIXNET_BIND_ADDRESS_ARG: &str = "NYMNODE_MIXNET_BIND_ADDRESS"; + pub const NYMNODE_MIXNET_ANNOUNCE_PORT_ARG: &str = "NYMNODE_MIXNET_ANNOUNCE_PORT"; pub const NYMNODE_NYM_APIS_ARG: &str = "NYMNODE_NYM_APIS"; pub const NYMNODE_NYXD_URLS_ARG: &str = "NYMNODE_NYXD"; pub const NYMNODE_UNSAFE_DISABLE_NOISE: &str = "UNSAFE_DISABLE_NOISE"; @@ -48,6 +49,7 @@ pub mod vars { // mixnode: pub const NYMNODE_VERLOC_BIND_ADDRESS_ARG: &str = "NYMNODE_VERLOC_BIND_ADDRESS"; + pub const NYMNODE_VERLOC_ANNOUNCE_PORT_ARG: &str = "NYMNODE_VERLOC_ANNOUNCE_PORT"; // entry gateway: pub const NYMNODE_ENTRY_BIND_ADDRESS_ARG: &str = "NYMNODE_ENTRY_BIND_ADDRESS"; From 27775a29c480f250e5a03e30b78c95ebbc0cd670 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C4=99drzej=20Stuczy=C5=84ski?= Date: Mon, 14 Oct 2024 18:12:09 +0100 Subject: [PATCH 06/11] added additional logs when refreshing self-described cache --- nym-api/src/node_describe_cache/mod.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/nym-api/src/node_describe_cache/mod.rs b/nym-api/src/node_describe_cache/mod.rs index e92a3ebe5b..d8e0b3c32b 100644 --- a/nym-api/src/node_describe_cache/mod.rs +++ b/nym-api/src/node_describe_cache/mod.rs @@ -20,7 +20,7 @@ use std::collections::HashMap; use std::net::SocketAddr; use std::time::Duration; use thiserror::Error; -use tracing::{debug, error}; +use tracing::{debug, error, info}; mod query_helpers; @@ -389,6 +389,8 @@ impl CacheItemProvider for NodeDescriptionProvider { .collect::>() .await; + info!("refreshed self described data for {} nodes", nodes.len()); + Ok(DescribedNodes { nodes }) } } From 07138696667258c95bf2ac7db5515806f06edc12 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C4=99drzej=20Stuczy=C5=84ski?= Date: Mon, 14 Oct 2024 18:12:27 +0100 Subject: [PATCH 07/11] fixed swagger route arguments for skimmed endpoints --- .../src/nym_nodes/handlers/unstable/skimmed.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/nym-api/src/nym_nodes/handlers/unstable/skimmed.rs b/nym-api/src/nym_nodes/handlers/unstable/skimmed.rs index 53dace0e09..a4aba882cf 100644 --- a/nym-api/src/nym_nodes/handlers/unstable/skimmed.rs +++ b/nym-api/src/nym_nodes/handlers/unstable/skimmed.rs @@ -221,7 +221,7 @@ pub(super) async fn deprecated_gateways_basic( (status = 200, body = CachedNodesResponse) ) )] -#[deprecated(note = "use '/v1/unstable/nym-nodes/mixnodes/skimmed/active' instead")] +#[deprecated(note = "use '/v1/unstable/nym-nodes/skimmed/mixnodes/active' instead")] pub(super) async fn deprecated_mixnodes_basic( state: State, query_params: Query, @@ -335,7 +335,7 @@ pub(super) async fn nodes_basic_all( #[utoipa::path( tag = "Unstable Nym Nodes", get, - params(NodesParamsWithRole), + params(NodesParams), path = "/active", context_path = "/v1/unstable/nym-nodes/skimmed", responses( @@ -387,7 +387,7 @@ async fn mixnodes_basic( #[utoipa::path( tag = "Unstable Nym Nodes", get, - params(NodesParamsWithRole), + params(NodesParams), path = "/mixnodes/all", context_path = "/v1/unstable/nym-nodes/skimmed", responses( @@ -406,7 +406,7 @@ pub(super) async fn mixnodes_basic_all( #[utoipa::path( tag = "Unstable Nym Nodes", get, - params(NodesParamsWithRole), + params(NodesParams), path = "/mixnodes/active", context_path = "/v1/unstable/nym-nodes/skimmed", responses( @@ -444,7 +444,7 @@ async fn entry_gateways_basic( #[utoipa::path( tag = "Unstable Nym Nodes", get, - params(NodesParamsWithRole), + params(NodesParams), path = "/entry-gateways/active", context_path = "/v1/unstable/nym-nodes/skimmed", responses( @@ -463,7 +463,7 @@ pub(super) async fn entry_gateways_basic_active( #[utoipa::path( tag = "Unstable Nym Nodes", get, - params(NodesParamsWithRole), + params(NodesParams), path = "/entry-gateways/all", context_path = "/v1/unstable/nym-nodes/skimmed", responses( @@ -501,7 +501,7 @@ async fn exit_gateways_basic( #[utoipa::path( tag = "Unstable Nym Nodes", get, - params(NodesParamsWithRole), + params(NodesParams), path = "/exit-gateways/active", context_path = "/v1/unstable/nym-nodes/skimmed", responses( @@ -520,7 +520,7 @@ pub(super) async fn exit_gateways_basic_active( #[utoipa::path( tag = "Unstable Nym Nodes", get, - params(NodesParamsWithRole), + params(NodesParams), path = "/exit-gateways/all", context_path = "/v1/unstable/nym-nodes/skimmed", responses( From d04331a5dfc542aac1ba167baac555ecae290dbb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C4=99drzej=20Stuczy=C5=84ski?= Date: Mon, 14 Oct 2024 18:12:56 +0100 Subject: [PATCH 08/11] updated clients to use 'new' endpoints --- .../topology_control/geo_aware_provider.rs | 15 +++- .../topology_control/nym_api_provider.rs | 5 +- common/client-core/src/init/helpers.rs | 21 ++--- .../validator-client/src/client.rs | 66 +++++++++++++++ .../validator-client/src/nym_api/mod.rs | 83 +++++++++++++++++++ common/wasm/client-core/src/helpers.rs | 6 +- .../examples/custom_topology_provider.rs | 4 +- 7 files changed, 175 insertions(+), 25 deletions(-) diff --git a/common/client-core/src/client/topology_control/geo_aware_provider.rs b/common/client-core/src/client/topology_control/geo_aware_provider.rs index 9967e1a705..660acdf749 100644 --- a/common/client-core/src/client/topology_control/geo_aware_provider.rs +++ b/common/client-core/src/client/topology_control/geo_aware_provider.rs @@ -110,7 +110,11 @@ impl GeoAwareTopologyProvider { } async fn get_topology(&self) -> Option { - let mixnodes = match self.validator_client.get_basic_mixnodes(None).await { + let mixnodes = match self + .validator_client + .get_basic_active_mixing_assigned_nodes(Some(self.client_version.clone())) + .await + { Err(err) => { error!("failed to get network mixnodes - {err}"); return None; @@ -118,7 +122,11 @@ impl GeoAwareTopologyProvider { Ok(mixes) => mixes, }; - let gateways = match self.validator_client.get_basic_gateways(None).await { + let gateways = match self + .validator_client + .get_all_basic_entry_assigned_nodes(Some(self.client_version.clone())) + .await + { Err(err) => { error!("failed to get network gateways - {err}"); return None; @@ -185,8 +193,7 @@ impl GeoAwareTopologyProvider { .filter(|m| filtered_mixnode_ids.contains(&m.node_id)) .collect::>(); - let topology = nym_topology_from_basic_info(&mixnodes, &gateways) - .filter_system_version(&self.client_version); + let topology = nym_topology_from_basic_info(&mixnodes, &gateways); // TODO: return real error type check_layer_integrity(topology.clone()).ok()?; diff --git a/common/client-core/src/client/topology_control/nym_api_provider.rs b/common/client-core/src/client/topology_control/nym_api_provider.rs index 3a00f462bd..c2b2dd9003 100644 --- a/common/client-core/src/client/topology_control/nym_api_provider.rs +++ b/common/client-core/src/client/topology_control/nym_api_provider.rs @@ -98,7 +98,7 @@ impl NymApiTopologyProvider { async fn get_current_compatible_topology(&mut self) -> Option { let mixnodes = match self .validator_client - .get_basic_mixnodes(Some(self.client_version.clone())) + .get_basic_active_mixing_assigned_nodes(Some(self.client_version.clone())) .await { Err(err) => { @@ -110,7 +110,7 @@ impl NymApiTopologyProvider { let gateways = match self .validator_client - .get_basic_gateways(Some(self.client_version.clone())) + .get_all_basic_entry_assigned_nodes(Some(self.client_version.clone())) .await { Err(err) => { @@ -134,7 +134,6 @@ impl NymApiTopologyProvider { g.performance.round_to_integer() >= self.config.min_gateway_performance }), ); - if let Err(err) = self.check_layer_distribution(&topology) { warn!("The current filtered active topology has extremely skewed layer distribution. It cannot be used: {err}"); self.use_next_nym_api(); diff --git a/common/client-core/src/init/helpers.rs b/common/client-core/src/init/helpers.rs index ac2b01bf6f..8e90f30240 100644 --- a/common/client-core/src/init/helpers.rs +++ b/common/client-core/src/init/helpers.rs @@ -7,7 +7,7 @@ use futures::{SinkExt, StreamExt}; use log::{debug, info, trace, warn}; use nym_crypto::asymmetric::identity; use nym_gateway_client::GatewayClient; -use nym_topology::{filter::VersionFilterable, gateway, mix}; +use nym_topology::{gateway, mix}; use nym_validator_client::client::IdentityKeyRef; use nym_validator_client::UserAgent; use rand::{seq::SliceRandom, Rng}; @@ -94,7 +94,7 @@ pub async fn current_gateways( log::debug!("Fetching list of gateways from: {nym_api}"); - let gateways = client.get_basic_gateways(None).await?; + let gateways = client.get_all_basic_entry_assigned_nodes(None).await?; log::debug!("Found {} gateways", gateways.len()); log::trace!("Gateways: {:#?}", gateways); @@ -102,17 +102,12 @@ pub async fn current_gateways( .iter() .filter_map(|gateway| gateway.try_into().ok()) .collect::>(); - log::debug!("Ater checking validity: {}", valid_gateways.len()); + log::debug!("After checking validity: {}", valid_gateways.len()); log::trace!("Valid gateways: {:#?}", valid_gateways); - // we were always filtering by version so I'm not removing that 'feature' - let filtered_gateways = valid_gateways.filter_by_version(env!("CARGO_PKG_VERSION")); - log::debug!("After filtering for version: {}", filtered_gateways.len()); - log::trace!("Filtered gateways: {:#?}", filtered_gateways); + log::info!("nym-api reports {} valid gateways", valid_gateways.len()); - log::info!("nym-api reports {} valid gateways", filtered_gateways.len()); - - Ok(filtered_gateways) + Ok(valid_gateways) } pub async fn current_mixnodes( @@ -126,15 +121,13 @@ pub async fn current_mixnodes( log::trace!("Fetching list of mixnodes from: {nym_api}"); - let mixnodes = client.get_basic_mixnodes(None).await?; + let mixnodes = client.get_basic_active_mixing_assigned_nodes(None).await?; let valid_mixnodes = mixnodes .iter() .filter_map(|mixnode| mixnode.try_into().ok()) .collect::>(); - // we were always filtering by version so I'm not removing that 'feature' - let filtered_mixnodes = valid_mixnodes.filter_by_version(env!("CARGO_PKG_VERSION")); - Ok(filtered_mixnodes) + Ok(valid_mixnodes) } #[cfg(not(target_arch = "wasm32"))] diff --git a/common/client-libs/validator-client/src/client.rs b/common/client-libs/validator-client/src/client.rs index fc68ae748c..b8375abdbd 100644 --- a/common/client-libs/validator-client/src/client.rs +++ b/common/client-libs/validator-client/src/client.rs @@ -283,6 +283,7 @@ impl NymApiClient { self.nym_api.change_base_url(new_endpoint); } + #[deprecated(note = "use get_basic_active_mixing_assigned_nodes instead")] pub async fn get_basic_mixnodes( &self, semver_compatibility: Option, @@ -294,6 +295,7 @@ impl NymApiClient { .nodes) } + #[deprecated(note = "use get_all_basic_entry_assigned_nodes instead")] pub async fn get_basic_gateways( &self, semver_compatibility: Option, @@ -305,6 +307,70 @@ impl NymApiClient { .nodes) } + /// retrieve basic information for nodes are capable of operating as an entry gateway + /// this includes legacy gateways and nym-nodes + pub async fn get_all_basic_entry_assigned_nodes( + &self, + semver_compatibility: Option, + ) -> Result, ValidatorClientError> { + // TODO: deal with paging in macro or some helper function or something, because it's the same pattern everywhere + let mut page = 0; + let mut nodes = Vec::new(); + + loop { + let mut res = self + .nym_api + .get_all_basic_entry_assigned_nodes( + semver_compatibility.clone(), + false, + Some(page), + None, + ) + .await?; + + nodes.append(&mut res.nodes.data); + if nodes.len() < res.nodes.pagination.total { + page += 1 + } else { + break; + } + } + + Ok(nodes) + } + + /// retrieve basic information for nodes that got assigned 'mixing' node in this epoch + /// this includes legacy mixnodes and nym-nodes + pub async fn get_basic_active_mixing_assigned_nodes( + &self, + semver_compatibility: Option, + ) -> Result, ValidatorClientError> { + // TODO: deal with paging in macro or some helper function or something, because it's the same pattern everywhere + let mut page = 0; + let mut nodes = Vec::new(); + + loop { + let mut res = self + .nym_api + .get_basic_active_mixing_assigned_nodes( + semver_compatibility.clone(), + false, + Some(page), + None, + ) + .await?; + + nodes.append(&mut res.nodes.data); + if nodes.len() < res.nodes.pagination.total { + page += 1 + } else { + break; + } + } + + Ok(nodes) + } + pub async fn get_cached_active_mixnodes( &self, ) -> Result, ValidatorClientError> { diff --git a/common/client-libs/validator-client/src/nym_api/mod.rs b/common/client-libs/validator-client/src/nym_api/mod.rs index a664a503ab..9660e470c7 100644 --- a/common/client-libs/validator-client/src/nym_api/mod.rs +++ b/common/client-libs/validator-client/src/nym_api/mod.rs @@ -13,6 +13,7 @@ use nym_api_requests::ecash::VerificationKeyResponse; use nym_api_requests::models::{ AnnotationResponse, LegacyDescribedMixNode, NodePerformanceResponse, }; +use nym_api_requests::nym_nodes::PaginatedCachedNodesResponse; pub use nym_api_requests::{ ecash::{ models::{ @@ -164,6 +165,88 @@ pub trait NymApiClientExt: ApiClient { .await } + /// retrieve basic information for nodes are capable of operating as an entry gateway + /// this includes legacy gateways and nym-nodes + async fn get_all_basic_entry_assigned_nodes( + &self, + semver_compatibility: Option, + no_legacy: bool, + page: Option, + per_page: Option, + ) -> Result, NymAPIError> { + let mut params = Vec::new(); + + if let Some(arg) = &semver_compatibility { + params.push(("semver_compatibility", arg.clone())) + } + + if no_legacy { + params.push(("no_legacy", "true".to_string())) + } + + if let Some(page) = page { + params.push(("page", page.to_string())) + } + + if let Some(per_page) = per_page { + params.push(("per_page", per_page.to_string())) + } + + self.get_json( + &[ + routes::API_VERSION, + "unstable", + "nym-nodes", + "skimmed", + "entry-gateways", + "all", + ], + ¶ms, + ) + .await + } + + /// retrieve basic information for nodes that got assigned 'mixing' node in this epoch + /// this includes legacy mixnodes and nym-nodes + async fn get_basic_active_mixing_assigned_nodes( + &self, + semver_compatibility: Option, + no_legacy: bool, + page: Option, + per_page: Option, + ) -> Result, NymAPIError> { + let mut params = Vec::new(); + + if let Some(arg) = &semver_compatibility { + params.push(("semver_compatibility", arg.clone())) + } + + if no_legacy { + params.push(("no_legacy", "true".to_string())) + } + + if let Some(page) = page { + params.push(("page", page.to_string())) + } + + if let Some(per_page) = per_page { + params.push(("per_page", per_page.to_string())) + } + + self.get_json( + &[ + routes::API_VERSION, + "unstable", + "nym-nodes", + "skimmed", + "mixnodes", + "active", + ], + ¶ms, + ) + .await + } + async fn get_active_mixnodes(&self) -> Result, NymAPIError> { self.get_json( &[routes::API_VERSION, routes::MIXNODES, routes::ACTIVE], diff --git a/common/wasm/client-core/src/helpers.rs b/common/wasm/client-core/src/helpers.rs index 3eafcbd623..41b203d1b5 100644 --- a/common/wasm/client-core/src/helpers.rs +++ b/common/wasm/client-core/src/helpers.rs @@ -67,8 +67,10 @@ pub async fn current_network_topology_async( }; let api_client = NymApiClient::new(url); - let mixnodes = api_client.get_basic_mixnodes(None).await?; - let gateways = api_client.get_basic_gateways(None).await?; + let mixnodes = api_client + .get_basic_active_mixing_assigned_nodes(None) + .await?; + let gateways = api_client.get_all_basic_entry_assigned_nodes(None).await?; Ok(NymTopology::from_basic(&mixnodes, &gateways).into()) } diff --git a/sdk/rust/nym-sdk/examples/custom_topology_provider.rs b/sdk/rust/nym-sdk/examples/custom_topology_provider.rs index 6737c2dcae..7b22a4f584 100644 --- a/sdk/rust/nym-sdk/examples/custom_topology_provider.rs +++ b/sdk/rust/nym-sdk/examples/custom_topology_provider.rs @@ -21,7 +21,7 @@ impl MyTopologyProvider { async fn get_topology(&self) -> NymTopology { let mixnodes = self .validator_client - .get_basic_mixnodes(None) + .get_basic_active_mixing_assigned_nodes(None) .await .unwrap(); @@ -35,7 +35,7 @@ impl MyTopologyProvider { let gateways = self .validator_client - .get_basic_gateways(None) + .get_all_basic_entry_assigned_nodes(None) .await .unwrap(); From 3320da206065552e94ecc474025522f00bedaf6f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C4=99drzej=20Stuczy=C5=84ski?= Date: Mon, 14 Oct 2024 18:13:10 +0100 Subject: [PATCH 09/11] fixed testnet-manager tool to work with the updated binaries --- .../testnet-manager/src/manager/dkg_skip.rs | 6 --- .../testnet-manager/src/manager/local_apis.rs | 5 +- .../src/manager/local_nodes.rs | 53 ++++++++++--------- .../testnet-manager/src/manager/node.rs | 43 +++------------ 4 files changed, 38 insertions(+), 69 deletions(-) diff --git a/tools/internal/testnet-manager/src/manager/dkg_skip.rs b/tools/internal/testnet-manager/src/manager/dkg_skip.rs index d09e219228..a132ea6950 100644 --- a/tools/internal/testnet-manager/src/manager/dkg_skip.rs +++ b/tools/internal/testnet-manager/src/manager/dkg_skip.rs @@ -77,12 +77,6 @@ impl<'a> PemStorableKey for FakeDkgKey<'a> { } } -impl EcashSignerWithPaths { - pub(crate) fn api_port(&self) -> u16 { - self.data.endpoint.port().unwrap() - } -} - struct DkgSkipCtx<'a> { progress: ProgressTracker, network: &'a LoadedNetwork, diff --git a/tools/internal/testnet-manager/src/manager/local_apis.rs b/tools/internal/testnet-manager/src/manager/local_apis.rs index 0351ce4d2b..631f6117f2 100644 --- a/tools/internal/testnet-manager/src/manager/local_apis.rs +++ b/tools/internal/testnet-manager/src/manager/local_apis.rs @@ -91,6 +91,8 @@ impl NetworkManager { "--enable-zk-nym", "--announce-address", info.data.endpoint.as_ref(), + "--bind-address", + &format!("0.0.0.0:{}", info.data.endpoint.port().unwrap()), ]) .stdin(Stdio::null()) .stderr(Stdio::null()) @@ -163,11 +165,10 @@ impl NetworkManager { let mut cmds = Vec::new(); for signer in &ctx.signers { - let port = signer.api_port(); let id = ctx.signer_id(signer); cmds.push(format!( - "ROCKET_PORT={port} {bin_canon_display} -c {env_canon_display} run --id {id}" + "{bin_canon_display} -c {env_canon_display} run --id {id}" )); } Ok(RunCommands(cmds)) diff --git a/tools/internal/testnet-manager/src/manager/local_nodes.rs b/tools/internal/testnet-manager/src/manager/local_nodes.rs index 9492de53c8..dc19d44436 100644 --- a/tools/internal/testnet-manager/src/manager/local_nodes.rs +++ b/tools/internal/testnet-manager/src/manager/local_nodes.rs @@ -161,6 +161,10 @@ impl NetworkManager { &format!("127.0.0.1:{verloc_port}"), "--entry-bind-address", &format!("127.0.0.1:{clients_port}"), + "--mixnet-announce-port", + &mix_port.to_string(), + "--verloc-announce-port", + &verloc_port.to_string(), "--mnemonic", &Zeroizing::new(node.owner.mnemonic.to_string()), "--local", @@ -203,11 +207,7 @@ impl NetworkManager { ctx.set_pb_message(format!("generating bonding signature for node {id}...")); - let msg = if is_gateway { - node.gateway_bonding_payload() - } else { - node.mixnode_bonding_payload() - }; + let msg = node.bonding_payload(); let child = Command::new(&ctx.nym_node_binary) .args([ @@ -318,28 +318,20 @@ impl NetworkManager { let owner = ctx.signing_node_owner(node)?; - let (bonding_fut, typ) = if is_gateway { - ( - owner.bond_gateway( - node.gateway(), - node.bonding_signature(), - node.pledge().into(), - None, - ), - "gateway", - ) + let typ = if is_gateway { + "gateway [as nym-node]" } else { - ( - owner.bond_mixnode( - node.mixnode(), - node.cost_params(), - node.bonding_signature(), - node.pledge().into(), - None, - ), - "mixnode", - ) + "mixnode [as nym-node]" }; + + let bonding_fut = owner.bond_nymnode( + node.bonding_nym_node(), + node.cost_params(), + node.bonding_signature(), + node.pledge().into(), + None, + ); + let res = ctx.async_with_progress(bonding_fut).await?; ctx.println(format!( "\t{id} ({typ}) bonded in transaction: {}", @@ -376,6 +368,7 @@ impl NetworkManager { style("[4/5]").bold().dim() )); + // this could be batched in a single tx, but that's too much effort for now let rewarder = ctx.signing_rewarder()?; ctx.set_pb_message("starting epoch transition..."); @@ -386,6 +379,16 @@ impl NetworkManager { let fut = rewarder.reconcile_epoch_events(None, None); ctx.async_with_progress(fut).await?; + ctx.set_pb_message("finally assigning the active set... exit..."); + let fut = rewarder.assign_roles( + RoleAssignment { + role: Role::ExitGateway, + nodes: vec![], + }, + None, + ); + ctx.async_with_progress(fut).await?; + ctx.set_pb_message("finally assigning the active set... entry..."); let fut = rewarder.assign_roles( RoleAssignment { diff --git a/tools/internal/testnet-manager/src/manager/node.rs b/tools/internal/testnet-manager/src/manager/node.rs index 3cf3443c24..d744057f32 100644 --- a/tools/internal/testnet-manager/src/manager/node.rs +++ b/tools/internal/testnet-manager/src/manager/node.rs @@ -5,10 +5,7 @@ use crate::manager::contract::Account; use nym_coconut_dkg_common::types::Addr; use nym_contracts_common::signing::MessageSignature; use nym_contracts_common::Percent; -use nym_mixnet_contract_common::{ - construct_gateway_bonding_sign_payload, construct_mixnode_bonding_sign_payload, Gateway, - MixNode, NodeCostParams, -}; +use nym_mixnet_contract_common::{construct_nym_node_bonding_sign_payload, NodeCostParams}; use nym_validator_client::nyxd::CosmWasmCoin; pub(crate) struct NymNode { @@ -44,27 +41,11 @@ impl NymNode { CosmWasmCoin::new(100_000000, "unym") } - pub(crate) fn gateway(&self) -> Gateway { - Gateway { + pub(crate) fn bonding_nym_node(&self) -> nym_mixnet_contract_common::NymNode { + nym_mixnet_contract_common::NymNode { host: "127.0.0.1".to_string(), - mix_port: self.mix_port, - clients_port: self.clients_port, - location: "foomp".to_string(), - sphinx_key: self.sphinx_key.clone(), + custom_http_port: Some(self.http_port), identity_key: self.identity_key.clone(), - version: self.version.clone(), - } - } - - pub(crate) fn mixnode(&self) -> MixNode { - MixNode { - host: "127.0.0.1".to_string(), - mix_port: self.mix_port, - verloc_port: self.verloc_port, - http_api_port: self.http_port, - sphinx_key: self.sphinx_key.clone(), - identity_key: self.identity_key.clone(), - version: self.version.clone(), } } @@ -80,24 +61,14 @@ impl NymNode { self.bonding_signature.parse().unwrap() } - pub(crate) fn mixnode_bonding_payload(&self) -> String { - let payload = construct_mixnode_bonding_sign_payload( + pub(crate) fn bonding_payload(&self) -> String { + let payload = construct_nym_node_bonding_sign_payload( 0, Addr::unchecked(self.owner.address.to_string()), self.pledge(), - self.mixnode(), + self.bonding_nym_node(), self.cost_params(), ); payload.to_base58_string().unwrap() } - - pub(crate) fn gateway_bonding_payload(&self) -> String { - let payload = construct_gateway_bonding_sign_payload( - 0, - Addr::unchecked(self.owner.address.to_string()), - self.pledge(), - self.gateway(), - ); - payload.to_base58_string().unwrap() - } } From 01db51e4925613bea9c8baf2647bc892f4021324 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C4=99drzej=20Stuczy=C5=84ski?= Date: Mon, 14 Oct 2024 18:52:19 +0100 Subject: [PATCH 10/11] updated mixnet schema --- contracts/mixnet/schema/nym-mixnet-contract.json | 6 ++++++ contracts/mixnet/schema/raw/migrate.json | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/contracts/mixnet/schema/nym-mixnet-contract.json b/contracts/mixnet/schema/nym-mixnet-contract.json index bf25ebfd76..7d43c71228 100644 --- a/contracts/mixnet/schema/nym-mixnet-contract.json +++ b/contracts/mixnet/schema/nym-mixnet-contract.json @@ -3212,6 +3212,12 @@ "title": "MigrateMsg", "type": "object", "properties": { + "unsafe_skip_state_updates": { + "type": [ + "boolean", + "null" + ] + }, "vesting_contract_address": { "type": [ "string", diff --git a/contracts/mixnet/schema/raw/migrate.json b/contracts/mixnet/schema/raw/migrate.json index e9962aaf92..57f0d2acdb 100644 --- a/contracts/mixnet/schema/raw/migrate.json +++ b/contracts/mixnet/schema/raw/migrate.json @@ -3,6 +3,12 @@ "title": "MigrateMsg", "type": "object", "properties": { + "unsafe_skip_state_updates": { + "type": [ + "boolean", + "null" + ] + }, "vesting_contract_address": { "type": [ "string", From ca4523025e9d21b95d6587d104ce80d8e6e22b8a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C4=99drzej=20Stuczy=C5=84ski?= Date: Mon, 14 Oct 2024 19:16:13 +0100 Subject: [PATCH 11/11] missing update to the integration test --- contracts/mixnet-vesting-integration-tests/src/support/setup.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/contracts/mixnet-vesting-integration-tests/src/support/setup.rs b/contracts/mixnet-vesting-integration-tests/src/support/setup.rs index e360777a94..5c4b08e1d4 100644 --- a/contracts/mixnet-vesting-integration-tests/src/support/setup.rs +++ b/contracts/mixnet-vesting-integration-tests/src/support/setup.rs @@ -464,6 +464,7 @@ pub fn instantiate_contracts( mixnet_contract_address.clone(), &nym_mixnet_contract_common::MigrateMsg { vesting_contract_address: Some(vesting_contract_address.to_string()), + unsafe_skip_state_updates: None, }, mixnet_code_id, )