diff --git a/Cargo.lock b/Cargo.lock index 9f7e5c0042..bd4608b55d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7102,6 +7102,7 @@ dependencies = [ "nym-sphinx", "nym-topology", "pretty_env_logger", + "rand 0.7.3", "serde", "serde_json", "tap", @@ -7392,6 +7393,7 @@ dependencies = [ "bs58 0.4.0", "log", "nym-bin-common", + "nym-config", "nym-crypto", "nym-mixnet-contract-common", "nym-sphinx-addressing", @@ -7399,7 +7401,12 @@ dependencies = [ "nym-sphinx-types", "rand 0.7.3", "semver 0.11.0", + "serde", + "serde_json", "thiserror", + "tsify", + "wasm-bindgen", + "wasm-utils", ] [[package]] diff --git a/clients/native/src/client/mod.rs b/clients/native/src/client/mod.rs index 6f3982038f..1e47ec9bf4 100644 --- a/clients/native/src/client/mod.rs +++ b/clients/native/src/client/mod.rs @@ -21,6 +21,7 @@ use nym_task::connections::TransmissionLane; use nym_task::TaskManager; use nym_validator_client::QueryHttpRpcNyxdClient; use std::error::Error; +use std::path::PathBuf; use tokio::sync::watch::error::SendError; pub use nym_sphinx::addressing::clients::Recipient; @@ -34,11 +35,17 @@ pub struct SocketClient { /// Client configuration options, including, among other things, packet sending rates, /// key filepaths, etc. config: Config, + + /// Optional path to a .json file containing standalone network details. + custom_mixnet: Option, } impl SocketClient { - pub fn new(config: Config) -> Self { - SocketClient { config } + pub fn new(config: Config, custom_mixnet: Option) -> Self { + SocketClient { + config, + custom_mixnet, + } } fn start_websocket_listener( @@ -109,7 +116,11 @@ impl SocketClient { let storage = self.initialise_storage().await?; - let base_client = BaseClientBuilder::new(&self.config.base, storage, dkg_query_client); + let mut base_client = BaseClientBuilder::new(&self.config.base, storage, dkg_query_client); + + if let Some(custom_mixnet) = &self.custom_mixnet { + base_client = base_client.with_stored_topology(custom_mixnet)?; + } Ok(base_client) } diff --git a/clients/native/src/commands/init.rs b/clients/native/src/commands/init.rs index d61b31b52d..784ffe8c74 100644 --- a/clients/native/src/commands/init.rs +++ b/clients/native/src/commands/init.rs @@ -15,12 +15,15 @@ use nym_bin_common::output_format::OutputFormat; use nym_client_core::client::base_client::storage::gateway_details::OnDiskGatewayDetails; use nym_client_core::client::key_manager::persistence::OnDiskKeys; use nym_client_core::config::GatewayEndpointConfig; +use nym_client_core::init::helpers::current_gateways; use nym_client_core::init::GatewaySetup; use nym_crypto::asymmetric::identity; use nym_sphinx::addressing::clients::Recipient; +use nym_topology::NymTopology; use serde::Serialize; use std::fmt::Display; use std::net::IpAddr; +use std::path::PathBuf; use std::{fs, io}; use tap::TapFallible; @@ -49,7 +52,12 @@ pub(crate) struct Init { nyxd_urls: Option>, /// Comma separated list of rest endpoints of the API validators - #[clap(long, alias = "api_validators", value_delimiter = ',')] + #[clap( + long, + alias = "api_validators", + value_delimiter = ',', + group = "network" + )] // the alias here is included for backwards compatibility (1.1.4 and before) nym_apis: Option>, @@ -65,6 +73,10 @@ pub(crate) struct Init { #[clap(long)] host: Option, + /// Path to .json file containing custom network specification. + #[clap(long, group = "network", hide = true)] + custom_mixnet: Option, + /// Mostly debug-related option to increase default traffic rate so that you would not need to /// modify config post init #[clap(long, hide = true)] @@ -130,7 +142,7 @@ fn init_paths(id: &str) -> io::Result<()> { fs::create_dir_all(default_config_directory(id)) } -pub(crate) async fn execute(args: &Init) -> Result<(), ClientError> { +pub(crate) async fn execute(args: Init) -> Result<(), ClientError> { eprintln!("Initialising client..."); let id = &args.id; @@ -173,12 +185,25 @@ pub(crate) async fn execute(args: &Init) -> Result<(), ClientError> { let key_store = OnDiskKeys::new(config.storage_paths.common_paths.keys.clone()); let details_store = OnDiskGatewayDetails::new(&config.storage_paths.common_paths.gateway_details); - let init_details = nym_client_core::init::setup_gateway( + + let network_gateways = if let Some(hardcoded_topology) = args + .custom_mixnet + .map(NymTopology::new_from_file) + .transpose()? + { + // hardcoded_topology + hardcoded_topology.get_gateways() + } else { + let mut rng = rand::thread_rng(); + current_gateways(&mut rng, &config.base.client.nym_api_urls).await? + }; + + let init_details = nym_client_core::init::setup_gateway_from( gateway_setup, &key_store, &details_store, register_gateway, - Some(&config.base.client.nym_api_urls), + Some(&network_gateways), ) .await .tap_err(|err| eprintln!("Failed to setup gateway\nError: {err}"))? diff --git a/clients/native/src/commands/mod.rs b/clients/native/src/commands/mod.rs index e1896bcfb6..4c440c4d99 100644 --- a/clients/native/src/commands/mod.rs +++ b/clients/native/src/commands/mod.rs @@ -84,8 +84,8 @@ pub(crate) async fn execute(args: Cli) -> Result<(), Box init::execute(&m).await?, - Commands::Run(m) => run::execute(&m).await?, + Commands::Init(m) => init::execute(m).await?, + Commands::Run(m) => run::execute(m).await?, Commands::BuildInfo(m) => build_info::execute(m), Commands::Completions(s) => s.generate(&mut Cli::command(), bin_name), Commands::GenerateFigSpec => fig_generate(&mut Cli::command(), bin_name), diff --git a/clients/native/src/commands/run.rs b/clients/native/src/commands/run.rs index 23cf54588b..8a61f8147c 100644 --- a/clients/native/src/commands/run.rs +++ b/clients/native/src/commands/run.rs @@ -13,6 +13,7 @@ use nym_bin_common::version_checker::is_minor_version_compatible; use nym_crypto::asymmetric::identity; use std::error::Error; use std::net::IpAddr; +use std::path::PathBuf; #[derive(Args, Clone)] pub(crate) struct Run { @@ -25,7 +26,12 @@ pub(crate) struct Run { nyxd_urls: Option>, /// Comma separated list of rest endpoints of the API validators - #[clap(long, alias = "api_validators", value_delimiter = ',')] + #[clap( + long, + alias = "api_validators", + value_delimiter = ',', + group = "network" + )] // the alias here is included for backwards compatibility (1.1.4 and before) nym_apis: Option>, @@ -46,6 +52,10 @@ pub(crate) struct Run { #[clap(long)] host: Option, + /// Path to .json file containing custom network specification. + #[clap(long, group = "network", hide = true)] + custom_mixnet: Option, + /// Mostly debug-related option to increase default traffic rate so that you would not need to /// modify config post init #[clap(long, hide = true)] @@ -95,7 +105,7 @@ fn version_check(cfg: &Config) -> bool { } } -pub(crate) async fn execute(args: &Run) -> Result<(), Box> { +pub(crate) async fn execute(args: Run) -> Result<(), Box> { eprintln!("Starting client {}...", args.id); let mut config = try_load_current_config(&args.id)?; @@ -106,5 +116,7 @@ pub(crate) async fn execute(args: &Run) -> Result<(), Box()].as_ref().try_into().unwrap()); + let message_len = u64::from_be_bytes(b[2..2 + size_of::()].try_into().unwrap()); let message = &b[2 + size_of::()..]; if message.len() as u64 != message_len { return Err(error::Error::new( diff --git a/clients/socks5/Cargo.toml b/clients/socks5/Cargo.toml index 03b6fcf5e9..17f5d17074 100644 --- a/clients/socks5/Cargo.toml +++ b/clients/socks5/Cargo.toml @@ -16,6 +16,7 @@ serde_json = { workspace = true } tap = "1.0.1" thiserror = { workspace = true } tokio = { version = "1.24.1", features = ["rt-multi-thread", "net", "signal"] } +rand = "0.7.3" url = { workspace = true } # internal diff --git a/clients/socks5/src/commands/init.rs b/clients/socks5/src/commands/init.rs index 77782ed262..4672b0dae9 100644 --- a/clients/socks5/src/commands/init.rs +++ b/clients/socks5/src/commands/init.rs @@ -14,11 +14,14 @@ use nym_bin_common::output_format::OutputFormat; use nym_client_core::client::base_client::storage::gateway_details::OnDiskGatewayDetails; use nym_client_core::client::key_manager::persistence::OnDiskKeys; use nym_client_core::config::GatewayEndpointConfig; +use nym_client_core::init::helpers::current_gateways; use nym_client_core::init::GatewaySetup; use nym_crypto::asymmetric::identity; use nym_sphinx::addressing::clients::Recipient; +use nym_topology::NymTopology; use serde::Serialize; use std::fmt::Display; +use std::path::PathBuf; use std::{fs, io}; use tap::TapFallible; @@ -68,6 +71,10 @@ pub(crate) struct Init { #[clap(short, long)] port: Option, + /// Path to .json file containing custom network specification. + #[clap(long, group = "network", hide = true)] + custom_mixnet: Option, + /// Mostly debug-related option to increase default traffic rate so that you would not need to /// modify config post init #[clap(long, hide = true)] @@ -138,7 +145,7 @@ fn init_paths(id: &str) -> io::Result<()> { fs::create_dir_all(default_config_directory(id)) } -pub(crate) async fn execute(args: &Init) -> Result<(), Socks5ClientError> { +pub(crate) async fn execute(args: Init) -> Result<(), Socks5ClientError> { eprintln!("Initialising client..."); let id = &args.id; @@ -185,12 +192,25 @@ pub(crate) async fn execute(args: &Init) -> Result<(), Socks5ClientError> { let key_store = OnDiskKeys::new(config.storage_paths.common_paths.keys.clone()); let details_store = OnDiskGatewayDetails::new(&config.storage_paths.common_paths.gateway_details); - let init_details = nym_client_core::init::setup_gateway( + + let network_gateways = if let Some(hardcoded_topology) = args + .custom_mixnet + .map(NymTopology::new_from_file) + .transpose()? + { + // hardcoded_topology + hardcoded_topology.get_gateways() + } else { + let mut rng = rand::thread_rng(); + current_gateways(&mut rng, &config.core.base.client.nym_api_urls).await? + }; + + let init_details = nym_client_core::init::setup_gateway_from( gateway_setup, &key_store, &details_store, register_gateway, - Some(&config.core.base.client.nym_api_urls), + Some(&network_gateways), ) .await .tap_err(|err| eprintln!("Failed to setup gateway\nError: {err}"))? diff --git a/clients/socks5/src/commands/mod.rs b/clients/socks5/src/commands/mod.rs index f9e876015d..b071ed5574 100644 --- a/clients/socks5/src/commands/mod.rs +++ b/clients/socks5/src/commands/mod.rs @@ -87,8 +87,8 @@ pub(crate) async fn execute(args: Cli) -> Result<(), Box init::execute(&m).await?, - Commands::Run(m) => run::execute(&m).await?, + Commands::Init(m) => init::execute(m).await?, + Commands::Run(m) => run::execute(m).await?, Commands::BuildInfo(m) => build_info::execute(m), Commands::Completions(s) => s.generate(&mut Cli::command(), bin_name), Commands::GenerateFigSpec => fig_generate(&mut Cli::command(), bin_name), diff --git a/clients/socks5/src/commands/run.rs b/clients/socks5/src/commands/run.rs index 8dd289e2bf..46bd9cd361 100644 --- a/clients/socks5/src/commands/run.rs +++ b/clients/socks5/src/commands/run.rs @@ -15,6 +15,7 @@ use nym_client_core::client::topology_control::geo_aware_provider::CountryGroup; use nym_crypto::asymmetric::identity; use nym_socks5_client_core::NymClient; use nym_sphinx::addressing::clients::Recipient; +use std::path::PathBuf; #[derive(Args, Clone)] pub(crate) struct Run { @@ -45,13 +46,17 @@ pub(crate) struct Run { nyxd_urls: Option>, /// Comma separated list of rest endpoints of the Nym APIs - #[clap(long, value_delimiter = ',')] + #[clap(long, value_delimiter = ',', group = "network")] nym_apis: Option>, /// Port for the socket to listen on #[clap(short, long)] port: Option, + /// Path to .json file containing custom network specification. + #[clap(long, group = "network", group = "routing", hide = true)] + custom_mixnet: Option, + /// Mostly debug-related option to increase default traffic rate so that you would not need to /// modify config post init #[clap(long, hide = true)] @@ -62,7 +67,7 @@ pub(crate) struct Run { no_cover: bool, /// Set geo-aware mixnode selection when sending mixnet traffic, for experiments only. - #[clap(long, hide = true, value_parser = validate_country_group)] + #[clap(long, hide = true, value_parser = validate_country_group, group="routing")] geo_routing: Option, /// Enable medium mixnet traffic, for experiments only. @@ -124,7 +129,7 @@ fn version_check(cfg: &Config) -> bool { } } -pub(crate) async fn execute(args: &Run) -> Result<(), Box> { +pub(crate) async fn execute(args: Run) -> Result<(), Box> { eprintln!("Starting client {}...", args.id); let mut config = try_load_current_config(&args.id)?; @@ -138,5 +143,7 @@ pub(crate) async fn execute(args: &Run) -> Result<(), Box Self { self.setup_method = setup; self } + #[must_use] pub fn with_topology_provider( mut self, provider: Box, @@ -191,6 +195,15 @@ where self } + pub fn with_stored_topology>( + mut self, + file: P, + ) -> Result { + self.custom_topology_provider = + Some(Box::new(HardcodedTopologyProvider::new_from_file(file)?)); + Ok(self) + } + // note: do **NOT** make this method public as its only valid usage is from within `start_base` // because it relies on the crypto keys being already loaded fn mix_address(details: &InitialisationDetails) -> Recipient { diff --git a/common/socks5-client-core/src/lib.rs b/common/socks5-client-core/src/lib.rs index 74d27b69ed..44b7b42821 100644 --- a/common/socks5-client-core/src/lib.rs +++ b/common/socks5-client-core/src/lib.rs @@ -26,6 +26,7 @@ use nym_sphinx::params::PacketType; use nym_task::{TaskClient, TaskManager}; use std::error::Error; +use std::path::PathBuf; pub mod config; pub mod error; @@ -57,6 +58,9 @@ pub struct NymClient { storage: S, setup_method: GatewaySetup, + + /// Optional path to a .json file containing standalone network details. + custom_mixnet: Option, } impl NymClient @@ -68,11 +72,12 @@ where ::StorageError: Sync + Send, ::StorageError: Send + Sync, { - pub fn new(config: Config, storage: S) -> Self { + pub fn new(config: Config, storage: S, custom_mixnet: Option) -> Self { NymClient { config, storage, setup_method: GatewaySetup::MustLoad, + custom_mixnet, } } @@ -210,10 +215,14 @@ where Some(default_query_dkg_client_from_config(&self.config.base)) }; - let base_builder = + let mut base_builder = BaseClientBuilder::new(&self.config.base, self.storage, dkg_query_client) .with_gateway_setup(self.setup_method); + if let Some(custom_mixnet) = &self.custom_mixnet { + base_builder = base_builder.with_stored_topology(custom_mixnet)?; + } + let packet_type = self.config.base.debug.traffic.packet_type; let mut started_client = base_builder.start_base().await?; let self_address = started_client.address; diff --git a/common/topology/Cargo.toml b/common/topology/Cargo.toml index e6d35a509c..079429cc69 100644 --- a/common/topology/Cargo.toml +++ b/common/topology/Cargo.toml @@ -19,6 +19,14 @@ thiserror = "1.0.37" async-trait = { workspace = true, optional = true } semver = "0.11" +# 'serializable' feature +serde = { workspace = true, features = ["derive"], optional = true } +serde_json = { workspace = true, optional = true } + +# 'wasm-serde-types' feature +tsify = { workspace = true, features = ["js"], optional = true } +wasm-bindgen = { workspace = true, optional = true } + ## internal nym-crypto = { path = "../crypto", features = ["sphinx", "outfox"] } nym-mixnet-contract-common = { path = "../cosmwasm-smart-contracts/mixnet-contract" } @@ -27,6 +35,14 @@ nym-sphinx-types = { path = "../nymsphinx/types", features = ["sphinx", "outfox" nym-sphinx-routing = { path = "../nymsphinx/routing" } nym-bin-common = { path = "../bin-common" } +# 'serializable' feature +nym-config = { path = "../config", optional = true } + +# 'wasm-serde-types' feature +wasm-utils = { path = "../wasm/utils", default-features = false, optional = true } + [features] default = ["provider-trait"] -provider-trait = ["async-trait"] \ No newline at end of file +provider-trait = ["async-trait"] +wasm-serde-types = ["tsify", "wasm-bindgen", "wasm-utils"] +serializable = ["serde", "nym-config", "serde_json"] \ No newline at end of file diff --git a/common/topology/src/lib.rs b/common/topology/src/lib.rs index 8c2a06cbfa..b9b740997e 100644 --- a/common/topology/src/lib.rs +++ b/common/topology/src/lib.rs @@ -17,6 +17,9 @@ use std::io; use std::net::{IpAddr, SocketAddr, ToSocketAddrs}; use std::str::FromStr; +#[cfg(feature = "serializable")] +use ::serde::{Deserialize, Deserializer, Serialize, Serializer}; + pub mod error; pub mod filter; pub mod gateway; @@ -26,6 +29,12 @@ pub mod random_route_provider; #[cfg(feature = "provider-trait")] pub mod provider_trait; +#[cfg(feature = "serializable")] +pub(crate) mod serde; + +#[cfg(feature = "serializable")] +pub use crate::serde::{SerializableNymTopology, SerializableTopologyError}; + #[cfg(feature = "provider-trait")] pub use provider_trait::{HardcodedTopologyProvider, TopologyProvider}; @@ -110,6 +119,12 @@ impl NymTopology { NymTopology { mixes, gateways } } + #[cfg(feature = "serializable")] + pub fn new_from_file>(path: P) -> std::io::Result { + let file = std::fs::File::open(path)?; + serde_json::from_reader(file).map_err(Into::into) + } + pub fn from_detailed( mix_details: Vec, gateway_bonds: Vec, @@ -171,6 +186,10 @@ impl NymTopology { &self.gateways } + pub fn get_gateways(&self) -> Vec { + self.gateways.clone() + } + pub fn get_gateway(&self, gateway_identity: &NodeIdentity) -> Option<&gateway::Node> { self.gateways .iter() @@ -350,6 +369,27 @@ impl NymTopology { } } +#[cfg(feature = "serializable")] +impl Serialize for NymTopology { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + crate::serde::SerializableNymTopology::from(self.clone()).serialize(serializer) + } +} + +#[cfg(feature = "serializable")] +impl<'de> Deserialize<'de> for NymTopology { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + let serializable = crate::serde::SerializableNymTopology::deserialize(deserializer)?; + serializable.try_into().map_err(::serde::de::Error::custom) + } +} + pub fn nym_topology_from_detailed( mix_details: Vec, gateway_bonds: Vec, diff --git a/common/topology/src/provider_trait.rs b/common/topology/src/provider_trait.rs index 562cfaa5f7..0dddecf2cb 100644 --- a/common/topology/src/provider_trait.rs +++ b/common/topology/src/provider_trait.rs @@ -22,6 +22,11 @@ pub struct HardcodedTopologyProvider { } impl HardcodedTopologyProvider { + #[cfg(feature = "serializable")] + pub fn new_from_file>(path: P) -> std::io::Result { + NymTopology::new_from_file(path).map(Self::new) + } + pub fn new(topology: NymTopology) -> Self { HardcodedTopologyProvider { topology } } diff --git a/common/topology/src/serde.rs b/common/topology/src/serde.rs new file mode 100644 index 0000000000..3750a8f064 --- /dev/null +++ b/common/topology/src/serde.rs @@ -0,0 +1,238 @@ +// Copyright 2023 - Nym Technologies SA +// SPDX-License-Identifier: Apache-2.0 + +use crate::gateway::GatewayConversionError; +use crate::mix::MixnodeConversionError; +use crate::{gateway, mix, MixLayer, NymTopology}; +use nym_config::defaults::{DEFAULT_CLIENT_LISTENING_PORT, DEFAULT_MIX_LISTENING_PORT}; +use nym_crypto::asymmetric::{encryption, identity}; +use serde::{Deserialize, Serialize}; +use std::collections::BTreeMap; +use thiserror::Error; + +#[cfg(feature = "wasm-serde-types")] +use tsify::Tsify; + +#[cfg(feature = "wasm-serde-types")] +use wasm_bindgen::{prelude::wasm_bindgen, JsValue}; + +#[cfg(feature = "wasm-serde-types")] +use wasm_utils::error::simple_js_error; + +#[derive(Debug, Error)] +pub enum SerializableTopologyError { + #[error("got invalid mix layer {value}. Expected 1, 2 or 3.")] + InvalidMixLayer { value: u8 }, + + #[error(transparent)] + GatewayConversion(#[from] GatewayConversionError), + + #[error(transparent)] + MixnodeConversion(#[from] MixnodeConversionError), + + #[error("The provided mixnode map was malformed: {msg}")] + MalformedMixnodeMap { msg: String }, + + #[error("The provided gateway list was malformed: {msg}")] + MalformedGatewayList { msg: String }, +} + +#[cfg(feature = "wasm-serde-types")] +impl From for JsValue { + fn from(value: SerializableTopologyError) -> Self { + simple_js_error(value.to_string()) + } +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +#[cfg_attr(feature = "wasm-serde-types", derive(Tsify))] +#[cfg_attr(feature = "wasm-serde-types", tsify(into_wasm_abi, from_wasm_abi))] +#[serde(rename_all = "camelCase")] +#[serde(deny_unknown_fields)] +pub struct SerializableNymTopology { + pub mixnodes: BTreeMap>, + pub gateways: Vec, +} + +impl TryFrom for NymTopology { + type Error = SerializableTopologyError; + + fn try_from(value: SerializableNymTopology) -> Result { + let mut converted_mixes = BTreeMap::new(); + + for (layer, nodes) in value.mixnodes { + let layer_nodes = nodes + .into_iter() + .map(TryInto::try_into) + .collect::>()?; + + converted_mixes.insert(layer, layer_nodes); + } + + let gateways = value + .gateways + .into_iter() + .map(TryInto::try_into) + .collect::>()?; + + Ok(NymTopology::new(converted_mixes, gateways)) + } +} + +impl From for SerializableNymTopology { + fn from(value: NymTopology) -> Self { + SerializableNymTopology { + mixnodes: value + .mixes() + .iter() + .map(|(&l, nodes)| (l, nodes.iter().map(Into::into).collect())) + .collect(), + gateways: value.gateways().iter().map(Into::into).collect(), + } + } +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +#[cfg_attr(feature = "wasm-serde-types", derive(Tsify))] +#[cfg_attr(feature = "wasm-serde-types", tsify(into_wasm_abi, from_wasm_abi))] +#[serde(rename_all = "camelCase")] +#[serde(deny_unknown_fields)] +pub struct SerializableMixNode { + // this is a `MixId` but due to typescript issue, we're using u32 directly. + #[serde(alias = "mix_id")] + pub mix_id: u32, + + pub owner: String, + + pub host: String, + + #[cfg_attr(feature = "wasm-serde-types", tsify(optional))] + #[serde(alias = "mix_port")] + pub mix_port: Option, + + #[serde(alias = "identity_key")] + pub identity_key: String, + + #[serde(alias = "sphinx_key")] + pub sphinx_key: String, + + // this is a `MixLayer` but due to typescript issue, we're using u8 directly. + pub layer: u8, + + #[cfg_attr(feature = "wasm-serde-types", tsify(optional))] + pub version: Option, +} + +impl TryFrom for mix::Node { + type Error = SerializableTopologyError; + + fn try_from(value: SerializableMixNode) -> Result { + let host = mix::Node::parse_host(&value.host)?; + + let mix_port = value.mix_port.unwrap_or(DEFAULT_MIX_LISTENING_PORT); + let version = value.version.map(|v| v.as_str().into()).unwrap_or_default(); + + // try to completely resolve the host in the mix situation to avoid doing it every + // single time we want to construct a path + let mix_host = mix::Node::extract_mix_host(&host, mix_port)?; + + Ok(mix::Node { + mix_id: value.mix_id, + owner: value.owner, + host, + mix_host, + identity_key: identity::PublicKey::from_base58_string(&value.identity_key) + .map_err(MixnodeConversionError::from)?, + sphinx_key: encryption::PublicKey::from_base58_string(&value.sphinx_key) + .map_err(MixnodeConversionError::from)?, + layer: mix::Layer::try_from(value.layer) + .map_err(|_| SerializableTopologyError::InvalidMixLayer { value: value.layer })?, + version, + }) + } +} + +impl<'a> From<&'a mix::Node> for SerializableMixNode { + fn from(value: &'a mix::Node) -> Self { + SerializableMixNode { + mix_id: value.mix_id, + owner: value.owner.clone(), + host: value.host.to_string(), + mix_port: Some(value.mix_host.port()), + identity_key: value.identity_key.to_base58_string(), + sphinx_key: value.sphinx_key.to_base58_string(), + layer: value.layer.into(), + version: Some(value.version.to_string()), + } + } +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +#[cfg_attr(feature = "wasm-serde-types", derive(Tsify))] +#[cfg_attr(feature = "wasm-serde-types", tsify(into_wasm_abi, from_wasm_abi))] +#[serde(rename_all = "camelCase")] +#[serde(deny_unknown_fields)] +pub struct SerializableGateway { + pub owner: String, + + pub host: String, + + #[cfg_attr(feature = "wasm-serde-types", tsify(optional))] + #[serde(alias = "mix_port")] + pub mix_port: Option, + + #[cfg_attr(feature = "wasm-serde-types", tsify(optional))] + #[serde(alias = "clients_port")] + pub clients_port: Option, + + #[serde(alias = "identity_key")] + pub identity_key: String, + + #[serde(alias = "sphinx_key")] + pub sphinx_key: String, + + #[cfg_attr(feature = "wasm-serde-types", tsify(optional))] + pub version: Option, +} + +impl TryFrom for gateway::Node { + type Error = SerializableTopologyError; + + fn try_from(value: SerializableGateway) -> Result { + let host = gateway::Node::parse_host(&value.host)?; + + let mix_port = value.mix_port.unwrap_or(DEFAULT_MIX_LISTENING_PORT); + let clients_port = value.clients_port.unwrap_or(DEFAULT_CLIENT_LISTENING_PORT); + let version = value.version.map(|v| v.as_str().into()).unwrap_or_default(); + + // try to completely resolve the host in the mix situation to avoid doing it every + // single time we want to construct a path + let mix_host = gateway::Node::extract_mix_host(&host, mix_port)?; + + Ok(gateway::Node { + owner: value.owner, + host, + mix_host, + clients_port, + identity_key: identity::PublicKey::from_base58_string(&value.identity_key) + .map_err(GatewayConversionError::from)?, + sphinx_key: encryption::PublicKey::from_base58_string(&value.sphinx_key) + .map_err(GatewayConversionError::from)?, + version, + }) + } +} + +impl<'a> From<&'a gateway::Node> for SerializableGateway { + fn from(value: &'a gateway::Node) -> Self { + SerializableGateway { + owner: value.owner.clone(), + host: value.host.to_string(), + mix_port: Some(value.mix_host.port()), + clients_port: Some(value.clients_port), + identity_key: value.identity_key.to_base58_string(), + sphinx_key: value.sphinx_key.to_base58_string(), + version: Some(value.version.to_string()), + } + } +} diff --git a/common/wasm/client-core/Cargo.toml b/common/wasm/client-core/Cargo.toml index 82f03573ba..38a9e3f5f9 100644 --- a/common/wasm/client-core/Cargo.toml +++ b/common/wasm/client-core/Cargo.toml @@ -30,7 +30,7 @@ nym-gateway-client = { path = "../../client-libs/gateway-client", default-featur nym-sphinx = { path = "../../nymsphinx" } nym-sphinx-acknowledgements = { path = "../../nymsphinx/acknowledgements", features = ["serde"]} nym-task = { path = "../../task" } -nym-topology = { path = "../../topology" } +nym-topology = { path = "../../topology", features = ["serializable", "wasm-serde-types"] } nym-validator-client = { path = "../../client-libs/validator-client", default-features = false } wasm-utils = { path = "../utils" } wasm-storage = { path = "../storage" } diff --git a/common/wasm/client-core/src/helpers.rs b/common/wasm/client-core/src/helpers.rs index e6aacfe2b7..4c86cf0cfa 100644 --- a/common/wasm/client-core/src/helpers.rs +++ b/common/wasm/client-core/src/helpers.rs @@ -4,7 +4,6 @@ use crate::error::WasmCoreError; use crate::storage::wasm_client_traits::WasmClientStorage; use crate::storage::ClientStorage; -use crate::topology::WasmNymTopology; use js_sys::Promise; use nym_client_core::client::replies::reply_storage::browser_backend; use nym_client_core::config; @@ -12,7 +11,7 @@ use nym_client_core::init::helpers::current_gateways; use nym_client_core::init::{setup_gateway_from, GatewaySetup, InitialisationResult}; use nym_sphinx::addressing::clients::Recipient; use nym_sphinx::anonymous_replies::requests::AnonymousSenderTag; -use nym_topology::{gateway, NymTopology}; +use nym_topology::{gateway, NymTopology, SerializableNymTopology}; use nym_validator_client::client::IdentityKey; use nym_validator_client::NymApiClient; use rand::thread_rng; @@ -52,7 +51,7 @@ pub fn parse_sender_tag(tag: &str) -> Result pub async fn current_network_topology_async( nym_api_url: String, -) -> Result { +) -> Result { let url: Url = match nym_api_url.parse() { Ok(url) => url, Err(source) => { diff --git a/common/wasm/client-core/src/topology.rs b/common/wasm/client-core/src/topology.rs index ab6ee353d3..a4fb2f5665 100644 --- a/common/wasm/client-core/src/topology.rs +++ b/common/wasm/client-core/src/topology.rs @@ -2,55 +2,27 @@ // SPDX-License-Identifier: Apache-2.0 use nym_client_core::config::GatewayEndpointConfig; -use nym_config::defaults::{DEFAULT_CLIENT_LISTENING_PORT, DEFAULT_MIX_LISTENING_PORT}; -use nym_crypto::asymmetric::{encryption, identity}; -use nym_topology::gateway::GatewayConversionError; -use nym_topology::mix::{Layer, MixnodeConversionError}; -use nym_topology::{gateway, mix, MixLayer, NymTopology}; +pub use nym_topology::SerializableNymTopology; +use nym_topology::SerializableTopologyError; use nym_validator_client::client::IdentityKeyRef; -use serde::{Deserialize, Serialize}; -use std::collections::BTreeMap; -use thiserror::Error; -use tsify::Tsify; -use wasm_bindgen::{prelude::wasm_bindgen, JsValue}; use wasm_utils::console_log; -use wasm_utils::error::simple_js_error; -#[derive(Debug, Error)] -pub enum WasmTopologyError { - #[error("got invalid mix layer {value}. Expected 1, 2 or 3.")] - InvalidMixLayer { value: u8 }, +// redeclare this as a type alias for easy of use +pub type WasmTopologyError = SerializableTopologyError; - #[error(transparent)] - GatewayConversion(#[from] GatewayConversionError), +// helper trait to define extra functionality on the external type that we used to have here before +pub trait SerializableTopologyExt { + fn print(&self); - #[error(transparent)] - MixnodeConversion(#[from] MixnodeConversionError), - - #[error("The provided mixnode map was malformed: {msg}")] - MalformedMixnodeMap { msg: String }, - - #[error("The provided gateway list was malformed: {msg}")] - MalformedGatewayList { msg: String }, -} - -impl From for JsValue { - fn from(value: WasmTopologyError) -> Self { - simple_js_error(value.to_string()) + fn ensure_contains(&self, gateway_config: &GatewayEndpointConfig) -> bool { + self.ensure_contains_gateway_id(&gateway_config.gateway_id) } + + fn ensure_contains_gateway_id(&self, gateway_id: IdentityKeyRef) -> bool; } -// serde helper, not intended to be used directly -#[derive(Tsify, Debug, Clone, Serialize, Deserialize)] -#[tsify(into_wasm_abi, from_wasm_abi)] -#[serde(rename_all = "camelCase")] -pub struct WasmNymTopology { - mixnodes: BTreeMap>, - gateways: Vec, -} - -impl WasmNymTopology { - pub fn print(&self) { +impl SerializableTopologyExt for SerializableNymTopology { + fn print(&self) { if !self.mixnodes.is_empty() { console_log!("mixnodes:"); for (layer, nodes) in &self.mixnodes { @@ -74,178 +46,8 @@ impl WasmNymTopology { console_log!("NO GATEWAYS") } } -} -impl TryFrom for NymTopology { - type Error = WasmTopologyError; - - fn try_from(value: WasmNymTopology) -> Result { - let mut converted_mixes = BTreeMap::new(); - - for (layer, nodes) in value.mixnodes { - let layer_nodes = nodes - .into_iter() - .map(TryInto::try_into) - .collect::>()?; - - converted_mixes.insert(layer, layer_nodes); - } - - let gateways = value - .gateways - .into_iter() - .map(TryInto::try_into) - .collect::>()?; - - Ok(NymTopology::new(converted_mixes, gateways)) - } -} - -impl WasmNymTopology { - pub fn ensure_contains(&self, gateway_config: &GatewayEndpointConfig) -> bool { - self.ensure_contains_gateway_id(&gateway_config.gateway_id) - } - - pub fn ensure_contains_gateway_id(&self, gateway_id: IdentityKeyRef) -> bool { + fn ensure_contains_gateway_id(&self, gateway_id: IdentityKeyRef) -> bool { self.gateways.iter().any(|g| g.identity_key == gateway_id) } } - -impl From for WasmNymTopology { - fn from(value: NymTopology) -> Self { - WasmNymTopology { - mixnodes: value - .mixes() - .iter() - .map(|(&l, nodes)| (l, nodes.iter().map(Into::into).collect())) - .collect(), - gateways: value.gateways().iter().map(Into::into).collect(), - } - } -} - -#[derive(Tsify, Debug, Clone, Serialize, Deserialize)] -#[tsify(into_wasm_abi, from_wasm_abi)] -#[serde(rename_all = "camelCase")] -pub struct WasmMixNode { - // this is a `MixId` but due to typescript issue, we're using u32 directly. - pub mix_id: u32, - pub owner: String, - pub host: String, - - #[tsify(optional)] - pub mix_port: Option, - pub identity_key: String, - pub sphinx_key: String, - - // this is a `MixLayer` but due to typescript issue, we're using u8 directly. - pub layer: u8, - - #[tsify(optional)] - pub version: Option, -} - -impl TryFrom for mix::Node { - type Error = WasmTopologyError; - - fn try_from(value: WasmMixNode) -> Result { - let host = mix::Node::parse_host(&value.host)?; - - let mix_port = value.mix_port.unwrap_or(DEFAULT_MIX_LISTENING_PORT); - let version = value.version.map(|v| v.as_str().into()).unwrap_or_default(); - - // try to completely resolve the host in the mix situation to avoid doing it every - // single time we want to construct a path - let mix_host = mix::Node::extract_mix_host(&host, mix_port)?; - - Ok(mix::Node { - mix_id: value.mix_id, - owner: value.owner, - host, - mix_host, - identity_key: identity::PublicKey::from_base58_string(&value.identity_key) - .map_err(MixnodeConversionError::from)?, - sphinx_key: encryption::PublicKey::from_base58_string(&value.sphinx_key) - .map_err(MixnodeConversionError::from)?, - layer: Layer::try_from(value.layer) - .map_err(|_| WasmTopologyError::InvalidMixLayer { value: value.layer })?, - version, - }) - } -} - -impl<'a> From<&'a mix::Node> for WasmMixNode { - fn from(value: &'a mix::Node) -> Self { - WasmMixNode { - mix_id: value.mix_id, - owner: value.owner.clone(), - host: value.host.to_string(), - mix_port: Some(value.mix_host.port()), - identity_key: value.identity_key.to_base58_string(), - sphinx_key: value.sphinx_key.to_base58_string(), - layer: value.layer.into(), - version: Some(value.version.to_string()), - } - } -} - -#[derive(Tsify, Debug, Clone, Serialize, Deserialize)] -#[tsify(into_wasm_abi, from_wasm_abi)] -#[serde(rename_all = "camelCase")] -pub struct WasmGateway { - pub owner: String, - pub host: String, - - #[tsify(optional)] - pub mix_port: Option, - - #[tsify(optional)] - pub clients_port: Option, - pub identity_key: String, - pub sphinx_key: String, - - #[tsify(optional)] - pub version: Option, -} - -impl TryFrom for gateway::Node { - type Error = WasmTopologyError; - - fn try_from(value: WasmGateway) -> Result { - let host = gateway::Node::parse_host(&value.host)?; - - let mix_port = value.mix_port.unwrap_or(DEFAULT_MIX_LISTENING_PORT); - let clients_port = value.clients_port.unwrap_or(DEFAULT_CLIENT_LISTENING_PORT); - let version = value.version.map(|v| v.as_str().into()).unwrap_or_default(); - - // try to completely resolve the host in the mix situation to avoid doing it every - // single time we want to construct a path - let mix_host = gateway::Node::extract_mix_host(&host, mix_port)?; - - Ok(gateway::Node { - owner: value.owner, - host, - mix_host, - clients_port, - identity_key: identity::PublicKey::from_base58_string(&value.identity_key) - .map_err(GatewayConversionError::from)?, - sphinx_key: encryption::PublicKey::from_base58_string(&value.sphinx_key) - .map_err(GatewayConversionError::from)?, - version, - }) - } -} - -impl<'a> From<&'a gateway::Node> for WasmGateway { - fn from(value: &'a gateway::Node) -> Self { - WasmGateway { - owner: value.owner.clone(), - host: value.host.to_string(), - mix_port: Some(value.mix_host.port()), - clients_port: Some(value.clients_port), - identity_key: value.identity_key.to_base58_string(), - sphinx_key: value.sphinx_key.to_base58_string(), - version: Some(value.version.to_string()), - } - } -} diff --git a/nym-connect/desktop/Cargo.lock b/nym-connect/desktop/Cargo.lock index 632e47acec..2fd6ee3069 100644 --- a/nym-connect/desktop/Cargo.lock +++ b/nym-connect/desktop/Cargo.lock @@ -4604,6 +4604,7 @@ dependencies = [ "bs58 0.4.0", "log", "nym-bin-common", + "nym-config", "nym-crypto", "nym-mixnet-contract-common", "nym-sphinx-addressing", @@ -4611,6 +4612,8 @@ dependencies = [ "nym-sphinx-types", "rand 0.7.3", "semver 0.11.0", + "serde", + "serde_json", "thiserror", ] diff --git a/nym-connect/desktop/src-tauri/src/tasks.rs b/nym-connect/desktop/src-tauri/src/tasks.rs index b18cb8277d..454ecc55c8 100644 --- a/nym-connect/desktop/src-tauri/src/tasks.rs +++ b/nym-connect/desktop/src-tauri/src/tasks.rs @@ -113,7 +113,7 @@ pub async fn start_nym_socks5_client( let result = tokio::runtime::Runtime::new() .expect("Failed to create runtime for SOCKS5 client") .block_on(async move { - let socks5_client = Socks5NymClient::new(config.core, storage); + let socks5_client = Socks5NymClient::new(config.core, storage, None); socks5_client .run_and_listen(socks5_ctrl_rx, socks5_status_tx) diff --git a/sdk/lib/socks5-listener/src/lib.rs b/sdk/lib/socks5-listener/src/lib.rs index 7c199d5f09..74b785d9a0 100644 --- a/sdk/lib/socks5-listener/src/lib.rs +++ b/sdk/lib/socks5-listener/src/lib.rs @@ -264,7 +264,7 @@ where let config = load_or_generate_base_config(storage_dir, client_id, service_provider).await?; let storage = MobileClientStorage::new(&config); - let socks5_client = Socks5NymClient::new(config.core, storage) + let socks5_client = Socks5NymClient::new(config.core, storage, None) .with_gateway_setup(GatewaySetup::New { by_latency: false }); eprintln!("starting the socks5 client"); diff --git a/wasm/client/internal-dev/yarn.lock b/wasm/client/internal-dev/yarn.lock index 3555ea6145..d74175fc43 100644 --- a/wasm/client/internal-dev/yarn.lock +++ b/wasm/client/internal-dev/yarn.lock @@ -74,7 +74,7 @@ fastq "^1.6.0" "@nymproject/nym-client-wasm@file:../../../dist/wasm/client": - version "1.1.1" + version "1.2.0-rc.2" "@types/body-parser@*": version "1.19.2" @@ -445,11 +445,6 @@ array-flatten@^2.1.2: resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-2.1.2.tgz#24ef80a28c1a893617e2149b0c6d0d788293b099" integrity sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ== -array-union@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/array-union/-/array-union-3.0.1.tgz#da52630d327f8b88cfbfb57728e2af5cd9b6b975" - integrity sha512-1OvF9IbWwaeiM9VhzYXVQacMibxpXOMYVNIvMtKRyX9SImBXpKcFr8XvFDeEslCyuH/t6KRt7HEO94AlP8Iatw== - balanced-match@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" @@ -642,14 +637,14 @@ cookie@0.5.0: resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.5.0.tgz#d1f5d71adec6558c58f389987c366aa47e994f8b" integrity sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw== -copy-webpack-plugin@^10.2.4: - version "10.2.4" - resolved "https://registry.yarnpkg.com/copy-webpack-plugin/-/copy-webpack-plugin-10.2.4.tgz#6c854be3fdaae22025da34b9112ccf81c63308fe" - integrity sha512-xFVltahqlsRcyyJqQbDY6EYTtyQZF9rf+JPjwHObLdPFMEISqkFkr7mFoVOC6BfYS/dNThyoQKvziugm+OnwBg== +copy-webpack-plugin@^11.0.0: + version "11.0.0" + resolved "https://registry.yarnpkg.com/copy-webpack-plugin/-/copy-webpack-plugin-11.0.0.tgz#96d4dbdb5f73d02dd72d0528d1958721ab72e04a" + integrity sha512-fX2MWpamkW0hZxMEg0+mYnA40LTosOSa5TqZ9GYIBzyJa9C3QUaMPSE2xAi/buNr8u89SfD9wHSQVBzrRa/SOQ== dependencies: - fast-glob "^3.2.7" + fast-glob "^3.2.11" glob-parent "^6.0.1" - globby "^12.0.2" + globby "^13.1.1" normalize-path "^3.0.0" schema-utils "^4.0.0" serialize-javascript "^6.0.0" @@ -873,10 +868,10 @@ fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== -fast-glob@^3.2.7: - version "3.2.12" - resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.12.tgz#7f39ec99c2e6ab030337142da9e0c18f37afae80" - integrity sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w== +fast-glob@^3.2.11, fast-glob@^3.3.0: + version "3.3.1" + resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.1.tgz#784b4e897340f3dbbef17413b3f11acf03c874c4" + integrity sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg== dependencies: "@nodelib/fs.stat" "^2.0.2" "@nodelib/fs.walk" "^1.2.3" @@ -1016,15 +1011,14 @@ glob@^7.1.3: once "^1.3.0" path-is-absolute "^1.0.0" -globby@^12.0.2: - version "12.2.0" - resolved "https://registry.yarnpkg.com/globby/-/globby-12.2.0.tgz#2ab8046b4fba4ff6eede835b29f678f90e3d3c22" - integrity sha512-wiSuFQLZ+urS9x2gGPl1H5drc5twabmm4m2gTR27XDFyjUHJUNsS8o/2aKyIF6IoBaR630atdher0XJ5g6OMmA== +globby@^13.1.1: + version "13.2.2" + resolved "https://registry.yarnpkg.com/globby/-/globby-13.2.2.tgz#63b90b1bf68619c2135475cbd4e71e66aa090592" + integrity sha512-Y1zNGV+pzQdh7H39l9zgB4PJqjRNqydvdYCDG4HFXM4XuvSaQQlEc91IU1yALL8gUTDomgBAfz3XJdmUS+oo0w== dependencies: - array-union "^3.0.1" dir-glob "^3.0.1" - fast-glob "^3.2.7" - ignore "^5.1.9" + fast-glob "^3.3.0" + ignore "^5.2.4" merge2 "^1.4.1" slash "^4.0.0" @@ -1138,7 +1132,7 @@ iconv-lite@0.4.24: dependencies: safer-buffer ">= 2.1.2 < 3" -ignore@^5.1.9: +ignore@^5.2.4: version "5.2.4" resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.2.4.tgz#a291c0c6178ff1b960befe47fcdec301674a6324" integrity sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ== diff --git a/wasm/client/src/client.rs b/wasm/client/src/client.rs index e736d972b2..6488903e96 100644 --- a/wasm/client/src/client.rs +++ b/wasm/client/src/client.rs @@ -24,7 +24,7 @@ use wasm_client_core::nym_task::connections::TransmissionLane; use wasm_client_core::nym_task::TaskManager; use wasm_client_core::storage::core_client_traits::FullWasmClientStorage; use wasm_client_core::storage::ClientStorage; -use wasm_client_core::topology::WasmNymTopology; +use wasm_client_core::topology::{SerializableNymTopology, SerializableTopologyExt}; use wasm_client_core::{ HardcodedTopologyProvider, IdentityKey, NymTopology, PacketType, QueryReqwestRpcNyxdClient, TopologyProvider, @@ -95,7 +95,7 @@ impl NymClientBuilder { // NOTE: you most likely want to use `[NymNodeTester]` instead. #[cfg(feature = "node-tester")] pub fn new_tester( - topology: WasmNymTopology, + topology: SerializableNymTopology, on_message: js_sys::Function, gateway: Option, ) -> Result { @@ -315,7 +315,7 @@ impl NymClient { .mix_test_request(test_id, mixnode_identity, num_test_packets) } - pub fn change_hardcoded_topology(&self, topology: WasmNymTopology) -> Promise { + pub fn change_hardcoded_topology(&self, topology: SerializableNymTopology) -> Promise { self.client_state.change_hardcoded_topology(topology) } diff --git a/wasm/client/src/helpers.rs b/wasm/client/src/helpers.rs index c4c234c880..16650294c7 100644 --- a/wasm/client/src/helpers.rs +++ b/wasm/client/src/helpers.rs @@ -8,7 +8,7 @@ use wasm_bindgen_futures::future_to_promise; use wasm_client_core::client::base_client::{ClientInput, ClientState}; use wasm_client_core::client::inbound_messages::InputMessage; use wasm_client_core::error::WasmCoreError; -use wasm_client_core::topology::WasmNymTopology; +use wasm_client_core::topology::SerializableNymTopology; use wasm_client_core::{MixLayer, NymTopology}; use wasm_utils::error::simple_js_error; use wasm_utils::{check_promise_result, console_log}; @@ -36,7 +36,7 @@ pub struct NymClientTestRequest { #[cfg(feature = "node-tester")] #[wasm_bindgen] impl NymClientTestRequest { - pub fn injectable_topology(&self) -> WasmNymTopology { + pub fn injectable_topology(&self) -> SerializableNymTopology { self.testable_topology.clone().into() } } @@ -78,7 +78,7 @@ impl InputSender for Arc { pub(crate) trait WasmTopologyExt { /// Changes the current network topology to the provided value. - fn change_hardcoded_topology(&self, topology: WasmNymTopology) -> Promise; + fn change_hardcoded_topology(&self, topology: SerializableNymTopology) -> Promise; /// Returns the current network topology. fn current_topology(&self) -> Promise; @@ -99,7 +99,7 @@ pub(crate) trait WasmTopologyTestExt { } impl WasmTopologyExt for Arc { - fn change_hardcoded_topology(&self, topology: WasmNymTopology) -> Promise { + fn change_hardcoded_topology(&self, topology: SerializableNymTopology) -> Promise { let nym_topology: NymTopology = check_promise_result!(topology.try_into()); let this = Arc::clone(self); @@ -116,10 +116,10 @@ impl WasmTopologyExt for Arc { let this = Arc::clone(self); future_to_promise(async move { match this.topology_accessor.current_topology().await { - Some(topology) => Ok(serde_wasm_bindgen::to_value(&WasmNymTopology::from( + Some(topology) => Ok(serde_wasm_bindgen::to_value(&SerializableNymTopology::from( topology, )) - .expect("WasmNymTopology failed serialization")), + .expect("SerializableNymTopology failed serialization")), None => Err(WasmCoreError::UnavailableNetworkTopology.into()), } }) diff --git a/wasm/node-tester/src/tester.rs b/wasm/node-tester/src/tester.rs index 5a5d7f5f34..b7fb1aa714 100644 --- a/wasm/node-tester/src/tester.rs +++ b/wasm/node-tester/src/tester.rs @@ -24,7 +24,7 @@ use wasm_client_core::helpers::{ current_network_topology_async, setup_from_topology, EphemeralCredentialStorage, }; use wasm_client_core::storage::ClientStorage; -use wasm_client_core::topology::WasmNymTopology; +use wasm_client_core::topology::SerializableNymTopology; use wasm_client_core::{ nym_task, BandwidthController, GatewayClient, IdentityKey, InitialisationDetails, InitialisationResult, ManagedKeys, NodeIdentity, NymTopology, QueryReqwestRpcNyxdClient, @@ -95,7 +95,7 @@ pub struct NymNodeTesterOpts { nym_api: Option, #[tsify(optional)] - topology: Option, + topology: Option, #[tsify(optional)] gateway: Option,