[feat] Socks5 and Native client: run with hardcoded topology (#3866)
* allow running clients using hardcoded topology * fixed sdk/lib/socks5-listener build * fixed nym-connect build * allow for both snake_case and camelCase deserialization
This commit is contained in:
committed by
GitHub
parent
6b161700f6
commit
63b0658c65
Generated
+7
@@ -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]]
|
||||
|
||||
@@ -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<PathBuf>,
|
||||
}
|
||||
|
||||
impl SocketClient {
|
||||
pub fn new(config: Config) -> Self {
|
||||
SocketClient { config }
|
||||
pub fn new(config: Config, custom_mixnet: Option<PathBuf>) -> 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)
|
||||
}
|
||||
|
||||
@@ -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<Vec<url::Url>>,
|
||||
|
||||
/// 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<Vec<url::Url>>,
|
||||
|
||||
@@ -65,6 +73,10 @@ pub(crate) struct Init {
|
||||
#[clap(long)]
|
||||
host: Option<IpAddr>,
|
||||
|
||||
/// Path to .json file containing custom network specification.
|
||||
#[clap(long, group = "network", hide = true)]
|
||||
custom_mixnet: Option<PathBuf>,
|
||||
|
||||
/// 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}"))?
|
||||
|
||||
@@ -84,8 +84,8 @@ pub(crate) async fn execute(args: Cli) -> Result<(), Box<dyn Error + Send + Sync
|
||||
let bin_name = "nym-native-client";
|
||||
|
||||
match args.command {
|
||||
Commands::Init(m) => 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),
|
||||
|
||||
@@ -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<Vec<url::Url>>,
|
||||
|
||||
/// 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<Vec<url::Url>>,
|
||||
|
||||
@@ -46,6 +52,10 @@ pub(crate) struct Run {
|
||||
#[clap(long)]
|
||||
host: Option<IpAddr>,
|
||||
|
||||
/// Path to .json file containing custom network specification.
|
||||
#[clap(long, group = "network", hide = true)]
|
||||
custom_mixnet: Option<PathBuf>,
|
||||
|
||||
/// 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<dyn Error + Send + Sync>> {
|
||||
pub(crate) async fn execute(args: Run) -> Result<(), Box<dyn Error + Send + Sync>> {
|
||||
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<dyn Error + Send + Syn
|
||||
return Err(Box::new(ClientError::FailedLocalVersionCheck));
|
||||
}
|
||||
|
||||
SocketClient::new(config).run_socket_forever().await
|
||||
SocketClient::new(config, args.custom_mixnet)
|
||||
.run_socket_forever()
|
||||
.await
|
||||
}
|
||||
|
||||
@@ -230,8 +230,7 @@ impl ServerResponse {
|
||||
|
||||
let error_kind = ErrorKind::try_from(b[1])?;
|
||||
|
||||
let message_len =
|
||||
u64::from_be_bytes(b[2..2 + size_of::<u64>()].as_ref().try_into().unwrap());
|
||||
let message_len = u64::from_be_bytes(b[2..2 + size_of::<u64>()].try_into().unwrap());
|
||||
let message = &b[2 + size_of::<u64>()..];
|
||||
if message.len() as u64 != message_len {
|
||||
return Err(error::Error::new(
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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<u16>,
|
||||
|
||||
/// Path to .json file containing custom network specification.
|
||||
#[clap(long, group = "network", hide = true)]
|
||||
custom_mixnet: Option<PathBuf>,
|
||||
|
||||
/// 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}"))?
|
||||
|
||||
@@ -87,8 +87,8 @@ pub(crate) async fn execute(args: Cli) -> Result<(), Box<dyn Error + Send + Sync
|
||||
let bin_name = "nym-socks5-client";
|
||||
|
||||
match args.command {
|
||||
Commands::Init(m) => 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),
|
||||
|
||||
@@ -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<Vec<url::Url>>,
|
||||
|
||||
/// Comma separated list of rest endpoints of the Nym APIs
|
||||
#[clap(long, value_delimiter = ',')]
|
||||
#[clap(long, value_delimiter = ',', group = "network")]
|
||||
nym_apis: Option<Vec<url::Url>>,
|
||||
|
||||
/// Port for the socket to listen on
|
||||
#[clap(short, long)]
|
||||
port: Option<u16>,
|
||||
|
||||
/// Path to .json file containing custom network specification.
|
||||
#[clap(long, group = "network", group = "routing", hide = true)]
|
||||
custom_mixnet: Option<PathBuf>,
|
||||
|
||||
/// 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<CountryGroup>,
|
||||
|
||||
/// 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<dyn std::error::Error + Send + Sync>> {
|
||||
pub(crate) async fn execute(args: Run) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||
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<dyn std::error::Error
|
||||
let storage =
|
||||
OnDiskPersistent::from_paths(config.storage_paths.common_paths, &config.core.base.debug)
|
||||
.await?;
|
||||
NymClient::new(config.core, storage).run_forever().await
|
||||
NymClient::new(config.core, storage, args.custom_mixnet)
|
||||
.run_forever()
|
||||
.await
|
||||
}
|
||||
|
||||
@@ -40,7 +40,7 @@ nym-gateway-requests = { path = "../../gateway/gateway-requests" }
|
||||
nym-nonexhaustive-delayqueue = { path = "../nonexhaustive-delayqueue" }
|
||||
nym-sphinx = { path = "../nymsphinx" }
|
||||
nym-pemstore = { path = "../pemstore" }
|
||||
nym-topology = { path = "../topology" }
|
||||
nym-topology = { path = "../topology", features = ["serializable"] }
|
||||
nym-validator-client = { path = "../client-libs/validator-client", default-features = false }
|
||||
nym-task = { path = "../task" }
|
||||
nym-credential-storage = { path = "../credential-storage" }
|
||||
|
||||
@@ -44,7 +44,9 @@ use nym_sphinx::receiver::{ReconstructedMessage, SphinxMessageReceiver};
|
||||
use nym_task::connections::{ConnectionCommandReceiver, ConnectionCommandSender, LaneQueueLengths};
|
||||
use nym_task::{TaskClient, TaskManager};
|
||||
use nym_topology::provider_trait::TopologyProvider;
|
||||
use nym_topology::HardcodedTopologyProvider;
|
||||
use nym_validator_client::nyxd::contract_traits::DkgQueryClient;
|
||||
use std::path::Path;
|
||||
use std::sync::Arc;
|
||||
use url::Url;
|
||||
|
||||
@@ -178,11 +180,13 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn with_gateway_setup(mut self, setup: GatewaySetup) -> Self {
|
||||
self.setup_method = setup;
|
||||
self
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn with_topology_provider(
|
||||
mut self,
|
||||
provider: Box<dyn TopologyProvider + Send + Sync>,
|
||||
@@ -191,6 +195,15 @@ where
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_stored_topology<P: AsRef<Path>>(
|
||||
mut self,
|
||||
file: P,
|
||||
) -> Result<Self, ClientCoreError> {
|
||||
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 {
|
||||
|
||||
@@ -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<S> {
|
||||
storage: S,
|
||||
|
||||
setup_method: GatewaySetup,
|
||||
|
||||
/// Optional path to a .json file containing standalone network details.
|
||||
custom_mixnet: Option<PathBuf>,
|
||||
}
|
||||
|
||||
impl<S> NymClient<S>
|
||||
@@ -68,11 +72,12 @@ where
|
||||
<S::GatewayDetailsStore as GatewayDetailsStore>::StorageError: Sync + Send,
|
||||
<S::KeyStore as KeyStore>::StorageError: Send + Sync,
|
||||
{
|
||||
pub fn new(config: Config, storage: S) -> Self {
|
||||
pub fn new(config: Config, storage: S, custom_mixnet: Option<PathBuf>) -> 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;
|
||||
|
||||
@@ -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"]
|
||||
provider-trait = ["async-trait"]
|
||||
wasm-serde-types = ["tsify", "wasm-bindgen", "wasm-utils"]
|
||||
serializable = ["serde", "nym-config", "serde_json"]
|
||||
@@ -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<P: AsRef<std::path::Path>>(path: P) -> std::io::Result<Self> {
|
||||
let file = std::fs::File::open(path)?;
|
||||
serde_json::from_reader(file).map_err(Into::into)
|
||||
}
|
||||
|
||||
pub fn from_detailed(
|
||||
mix_details: Vec<MixNodeDetails>,
|
||||
gateway_bonds: Vec<GatewayBond>,
|
||||
@@ -171,6 +186,10 @@ impl NymTopology {
|
||||
&self.gateways
|
||||
}
|
||||
|
||||
pub fn get_gateways(&self) -> Vec<gateway::Node> {
|
||||
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<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
crate::serde::SerializableNymTopology::from(self.clone()).serialize(serializer)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "serializable")]
|
||||
impl<'de> Deserialize<'de> for NymTopology {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
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<MixNodeDetails>,
|
||||
gateway_bonds: Vec<GatewayBond>,
|
||||
|
||||
@@ -22,6 +22,11 @@ pub struct HardcodedTopologyProvider {
|
||||
}
|
||||
|
||||
impl HardcodedTopologyProvider {
|
||||
#[cfg(feature = "serializable")]
|
||||
pub fn new_from_file<P: AsRef<std::path::Path>>(path: P) -> std::io::Result<Self> {
|
||||
NymTopology::new_from_file(path).map(Self::new)
|
||||
}
|
||||
|
||||
pub fn new(topology: NymTopology) -> Self {
|
||||
HardcodedTopologyProvider { topology }
|
||||
}
|
||||
|
||||
@@ -0,0 +1,238 @@
|
||||
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// 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<SerializableTopologyError> 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<MixLayer, Vec<SerializableMixNode>>,
|
||||
pub gateways: Vec<SerializableGateway>,
|
||||
}
|
||||
|
||||
impl TryFrom<SerializableNymTopology> for NymTopology {
|
||||
type Error = SerializableTopologyError;
|
||||
|
||||
fn try_from(value: SerializableNymTopology) -> Result<Self, Self::Error> {
|
||||
let mut converted_mixes = BTreeMap::new();
|
||||
|
||||
for (layer, nodes) in value.mixnodes {
|
||||
let layer_nodes = nodes
|
||||
.into_iter()
|
||||
.map(TryInto::try_into)
|
||||
.collect::<Result<_, _>>()?;
|
||||
|
||||
converted_mixes.insert(layer, layer_nodes);
|
||||
}
|
||||
|
||||
let gateways = value
|
||||
.gateways
|
||||
.into_iter()
|
||||
.map(TryInto::try_into)
|
||||
.collect::<Result<_, _>>()?;
|
||||
|
||||
Ok(NymTopology::new(converted_mixes, gateways))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<NymTopology> 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<u16>,
|
||||
|
||||
#[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<String>,
|
||||
}
|
||||
|
||||
impl TryFrom<SerializableMixNode> for mix::Node {
|
||||
type Error = SerializableTopologyError;
|
||||
|
||||
fn try_from(value: SerializableMixNode) -> Result<Self, Self::Error> {
|
||||
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<u16>,
|
||||
|
||||
#[cfg_attr(feature = "wasm-serde-types", tsify(optional))]
|
||||
#[serde(alias = "clients_port")]
|
||||
pub clients_port: Option<u16>,
|
||||
|
||||
#[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<String>,
|
||||
}
|
||||
|
||||
impl TryFrom<SerializableGateway> for gateway::Node {
|
||||
type Error = SerializableTopologyError;
|
||||
|
||||
fn try_from(value: SerializableGateway) -> Result<Self, Self::Error> {
|
||||
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()),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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" }
|
||||
|
||||
@@ -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<AnonymousSenderTag, WasmCoreError>
|
||||
|
||||
pub async fn current_network_topology_async(
|
||||
nym_api_url: String,
|
||||
) -> Result<WasmNymTopology, WasmCoreError> {
|
||||
) -> Result<SerializableNymTopology, WasmCoreError> {
|
||||
let url: Url = match nym_api_url.parse() {
|
||||
Ok(url) => url,
|
||||
Err(source) => {
|
||||
|
||||
@@ -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<WasmTopologyError> 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<MixLayer, Vec<WasmMixNode>>,
|
||||
gateways: Vec<WasmGateway>,
|
||||
}
|
||||
|
||||
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<WasmNymTopology> for NymTopology {
|
||||
type Error = WasmTopologyError;
|
||||
|
||||
fn try_from(value: WasmNymTopology) -> Result<Self, Self::Error> {
|
||||
let mut converted_mixes = BTreeMap::new();
|
||||
|
||||
for (layer, nodes) in value.mixnodes {
|
||||
let layer_nodes = nodes
|
||||
.into_iter()
|
||||
.map(TryInto::try_into)
|
||||
.collect::<Result<_, _>>()?;
|
||||
|
||||
converted_mixes.insert(layer, layer_nodes);
|
||||
}
|
||||
|
||||
let gateways = value
|
||||
.gateways
|
||||
.into_iter()
|
||||
.map(TryInto::try_into)
|
||||
.collect::<Result<_, _>>()?;
|
||||
|
||||
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<NymTopology> 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<u16>,
|
||||
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<String>,
|
||||
}
|
||||
|
||||
impl TryFrom<WasmMixNode> for mix::Node {
|
||||
type Error = WasmTopologyError;
|
||||
|
||||
fn try_from(value: WasmMixNode) -> Result<Self, Self::Error> {
|
||||
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<u16>,
|
||||
|
||||
#[tsify(optional)]
|
||||
pub clients_port: Option<u16>,
|
||||
pub identity_key: String,
|
||||
pub sphinx_key: String,
|
||||
|
||||
#[tsify(optional)]
|
||||
pub version: Option<String>,
|
||||
}
|
||||
|
||||
impl TryFrom<WasmGateway> for gateway::Node {
|
||||
type Error = WasmTopologyError;
|
||||
|
||||
fn try_from(value: WasmGateway) -> Result<Self, Self::Error> {
|
||||
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()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Generated
+3
@@ -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",
|
||||
]
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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==
|
||||
|
||||
@@ -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<IdentityKey>,
|
||||
) -> Result<NymClientBuilder, WasmClientError> {
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
|
||||
@@ -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<ClientInput> {
|
||||
|
||||
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<ClientState> {
|
||||
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<ClientState> {
|
||||
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()),
|
||||
}
|
||||
})
|
||||
|
||||
@@ -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<String>,
|
||||
|
||||
#[tsify(optional)]
|
||||
topology: Option<WasmNymTopology>,
|
||||
topology: Option<SerializableNymTopology>,
|
||||
|
||||
#[tsify(optional)]
|
||||
gateway: Option<String>,
|
||||
|
||||
Reference in New Issue
Block a user