Skip to content

Commit 63b0658

Browse files
authored
[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
1 parent 6b16170 commit 63b0658

File tree

27 files changed

+480
-279
lines changed

27 files changed

+480
-279
lines changed

Cargo.lock

Lines changed: 7 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

clients/native/src/client/mod.rs

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ use nym_task::connections::TransmissionLane;
2121
use nym_task::TaskManager;
2222
use nym_validator_client::QueryHttpRpcNyxdClient;
2323
use std::error::Error;
24+
use std::path::PathBuf;
2425
use tokio::sync::watch::error::SendError;
2526

2627
pub use nym_sphinx::addressing::clients::Recipient;
@@ -34,11 +35,17 @@ pub struct SocketClient {
3435
/// Client configuration options, including, among other things, packet sending rates,
3536
/// key filepaths, etc.
3637
config: Config,
38+
39+
/// Optional path to a .json file containing standalone network details.
40+
custom_mixnet: Option<PathBuf>,
3741
}
3842

3943
impl SocketClient {
40-
pub fn new(config: Config) -> Self {
41-
SocketClient { config }
44+
pub fn new(config: Config, custom_mixnet: Option<PathBuf>) -> Self {
45+
SocketClient {
46+
config,
47+
custom_mixnet,
48+
}
4249
}
4350

4451
fn start_websocket_listener(
@@ -109,7 +116,11 @@ impl SocketClient {
109116

110117
let storage = self.initialise_storage().await?;
111118

112-
let base_client = BaseClientBuilder::new(&self.config.base, storage, dkg_query_client);
119+
let mut base_client = BaseClientBuilder::new(&self.config.base, storage, dkg_query_client);
120+
121+
if let Some(custom_mixnet) = &self.custom_mixnet {
122+
base_client = base_client.with_stored_topology(custom_mixnet)?;
123+
}
113124

114125
Ok(base_client)
115126
}

clients/native/src/commands/init.rs

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,15 @@ use nym_bin_common::output_format::OutputFormat;
1515
use nym_client_core::client::base_client::storage::gateway_details::OnDiskGatewayDetails;
1616
use nym_client_core::client::key_manager::persistence::OnDiskKeys;
1717
use nym_client_core::config::GatewayEndpointConfig;
18+
use nym_client_core::init::helpers::current_gateways;
1819
use nym_client_core::init::GatewaySetup;
1920
use nym_crypto::asymmetric::identity;
2021
use nym_sphinx::addressing::clients::Recipient;
22+
use nym_topology::NymTopology;
2123
use serde::Serialize;
2224
use std::fmt::Display;
2325
use std::net::IpAddr;
26+
use std::path::PathBuf;
2427
use std::{fs, io};
2528
use tap::TapFallible;
2629

@@ -49,7 +52,12 @@ pub(crate) struct Init {
4952
nyxd_urls: Option<Vec<url::Url>>,
5053

5154
/// Comma separated list of rest endpoints of the API validators
52-
#[clap(long, alias = "api_validators", value_delimiter = ',')]
55+
#[clap(
56+
long,
57+
alias = "api_validators",
58+
value_delimiter = ',',
59+
group = "network"
60+
)]
5361
// the alias here is included for backwards compatibility (1.1.4 and before)
5462
nym_apis: Option<Vec<url::Url>>,
5563

@@ -65,6 +73,10 @@ pub(crate) struct Init {
6573
#[clap(long)]
6674
host: Option<IpAddr>,
6775

76+
/// Path to .json file containing custom network specification.
77+
#[clap(long, group = "network", hide = true)]
78+
custom_mixnet: Option<PathBuf>,
79+
6880
/// Mostly debug-related option to increase default traffic rate so that you would not need to
6981
/// modify config post init
7082
#[clap(long, hide = true)]
@@ -130,7 +142,7 @@ fn init_paths(id: &str) -> io::Result<()> {
130142
fs::create_dir_all(default_config_directory(id))
131143
}
132144

133-
pub(crate) async fn execute(args: &Init) -> Result<(), ClientError> {
145+
pub(crate) async fn execute(args: Init) -> Result<(), ClientError> {
134146
eprintln!("Initialising client...");
135147

136148
let id = &args.id;
@@ -173,12 +185,25 @@ pub(crate) async fn execute(args: &Init) -> Result<(), ClientError> {
173185
let key_store = OnDiskKeys::new(config.storage_paths.common_paths.keys.clone());
174186
let details_store =
175187
OnDiskGatewayDetails::new(&config.storage_paths.common_paths.gateway_details);
176-
let init_details = nym_client_core::init::setup_gateway(
188+
189+
let network_gateways = if let Some(hardcoded_topology) = args
190+
.custom_mixnet
191+
.map(NymTopology::new_from_file)
192+
.transpose()?
193+
{
194+
// hardcoded_topology
195+
hardcoded_topology.get_gateways()
196+
} else {
197+
let mut rng = rand::thread_rng();
198+
current_gateways(&mut rng, &config.base.client.nym_api_urls).await?
199+
};
200+
201+
let init_details = nym_client_core::init::setup_gateway_from(
177202
gateway_setup,
178203
&key_store,
179204
&details_store,
180205
register_gateway,
181-
Some(&config.base.client.nym_api_urls),
206+
Some(&network_gateways),
182207
)
183208
.await
184209
.tap_err(|err| eprintln!("Failed to setup gateway\nError: {err}"))?

clients/native/src/commands/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -84,8 +84,8 @@ pub(crate) async fn execute(args: Cli) -> Result<(), Box<dyn Error + Send + Sync
8484
let bin_name = "nym-native-client";
8585

8686
match args.command {
87-
Commands::Init(m) => init::execute(&m).await?,
88-
Commands::Run(m) => run::execute(&m).await?,
87+
Commands::Init(m) => init::execute(m).await?,
88+
Commands::Run(m) => run::execute(m).await?,
8989
Commands::BuildInfo(m) => build_info::execute(m),
9090
Commands::Completions(s) => s.generate(&mut Cli::command(), bin_name),
9191
Commands::GenerateFigSpec => fig_generate(&mut Cli::command(), bin_name),

clients/native/src/commands/run.rs

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ use nym_bin_common::version_checker::is_minor_version_compatible;
1313
use nym_crypto::asymmetric::identity;
1414
use std::error::Error;
1515
use std::net::IpAddr;
16+
use std::path::PathBuf;
1617

1718
#[derive(Args, Clone)]
1819
pub(crate) struct Run {
@@ -25,7 +26,12 @@ pub(crate) struct Run {
2526
nyxd_urls: Option<Vec<url::Url>>,
2627

2728
/// Comma separated list of rest endpoints of the API validators
28-
#[clap(long, alias = "api_validators", value_delimiter = ',')]
29+
#[clap(
30+
long,
31+
alias = "api_validators",
32+
value_delimiter = ',',
33+
group = "network"
34+
)]
2935
// the alias here is included for backwards compatibility (1.1.4 and before)
3036
nym_apis: Option<Vec<url::Url>>,
3137

@@ -46,6 +52,10 @@ pub(crate) struct Run {
4652
#[clap(long)]
4753
host: Option<IpAddr>,
4854

55+
/// Path to .json file containing custom network specification.
56+
#[clap(long, group = "network", hide = true)]
57+
custom_mixnet: Option<PathBuf>,
58+
4959
/// Mostly debug-related option to increase default traffic rate so that you would not need to
5060
/// modify config post init
5161
#[clap(long, hide = true)]
@@ -95,7 +105,7 @@ fn version_check(cfg: &Config) -> bool {
95105
}
96106
}
97107

98-
pub(crate) async fn execute(args: &Run) -> Result<(), Box<dyn Error + Send + Sync>> {
108+
pub(crate) async fn execute(args: Run) -> Result<(), Box<dyn Error + Send + Sync>> {
99109
eprintln!("Starting client {}...", args.id);
100110

101111
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
106116
return Err(Box::new(ClientError::FailedLocalVersionCheck));
107117
}
108118

109-
SocketClient::new(config).run_socket_forever().await
119+
SocketClient::new(config, args.custom_mixnet)
120+
.run_socket_forever()
121+
.await
110122
}

clients/native/websocket-requests/src/responses.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -230,8 +230,7 @@ impl ServerResponse {
230230

231231
let error_kind = ErrorKind::try_from(b[1])?;
232232

233-
let message_len =
234-
u64::from_be_bytes(b[2..2 + size_of::<u64>()].as_ref().try_into().unwrap());
233+
let message_len = u64::from_be_bytes(b[2..2 + size_of::<u64>()].try_into().unwrap());
235234
let message = &b[2 + size_of::<u64>()..];
236235
if message.len() as u64 != message_len {
237236
return Err(error::Error::new(

clients/socks5/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ serde_json = { workspace = true }
1616
tap = "1.0.1"
1717
thiserror = { workspace = true }
1818
tokio = { version = "1.24.1", features = ["rt-multi-thread", "net", "signal"] }
19+
rand = "0.7.3"
1920
url = { workspace = true }
2021

2122
# internal

clients/socks5/src/commands/init.rs

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,14 @@ use nym_bin_common::output_format::OutputFormat;
1414
use nym_client_core::client::base_client::storage::gateway_details::OnDiskGatewayDetails;
1515
use nym_client_core::client::key_manager::persistence::OnDiskKeys;
1616
use nym_client_core::config::GatewayEndpointConfig;
17+
use nym_client_core::init::helpers::current_gateways;
1718
use nym_client_core::init::GatewaySetup;
1819
use nym_crypto::asymmetric::identity;
1920
use nym_sphinx::addressing::clients::Recipient;
21+
use nym_topology::NymTopology;
2022
use serde::Serialize;
2123
use std::fmt::Display;
24+
use std::path::PathBuf;
2225
use std::{fs, io};
2326
use tap::TapFallible;
2427

@@ -68,6 +71,10 @@ pub(crate) struct Init {
6871
#[clap(short, long)]
6972
port: Option<u16>,
7073

74+
/// Path to .json file containing custom network specification.
75+
#[clap(long, group = "network", hide = true)]
76+
custom_mixnet: Option<PathBuf>,
77+
7178
/// Mostly debug-related option to increase default traffic rate so that you would not need to
7279
/// modify config post init
7380
#[clap(long, hide = true)]
@@ -138,7 +145,7 @@ fn init_paths(id: &str) -> io::Result<()> {
138145
fs::create_dir_all(default_config_directory(id))
139146
}
140147

141-
pub(crate) async fn execute(args: &Init) -> Result<(), Socks5ClientError> {
148+
pub(crate) async fn execute(args: Init) -> Result<(), Socks5ClientError> {
142149
eprintln!("Initialising client...");
143150

144151
let id = &args.id;
@@ -185,12 +192,25 @@ pub(crate) async fn execute(args: &Init) -> Result<(), Socks5ClientError> {
185192
let key_store = OnDiskKeys::new(config.storage_paths.common_paths.keys.clone());
186193
let details_store =
187194
OnDiskGatewayDetails::new(&config.storage_paths.common_paths.gateway_details);
188-
let init_details = nym_client_core::init::setup_gateway(
195+
196+
let network_gateways = if let Some(hardcoded_topology) = args
197+
.custom_mixnet
198+
.map(NymTopology::new_from_file)
199+
.transpose()?
200+
{
201+
// hardcoded_topology
202+
hardcoded_topology.get_gateways()
203+
} else {
204+
let mut rng = rand::thread_rng();
205+
current_gateways(&mut rng, &config.core.base.client.nym_api_urls).await?
206+
};
207+
208+
let init_details = nym_client_core::init::setup_gateway_from(
189209
gateway_setup,
190210
&key_store,
191211
&details_store,
192212
register_gateway,
193-
Some(&config.core.base.client.nym_api_urls),
213+
Some(&network_gateways),
194214
)
195215
.await
196216
.tap_err(|err| eprintln!("Failed to setup gateway\nError: {err}"))?

clients/socks5/src/commands/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -87,8 +87,8 @@ pub(crate) async fn execute(args: Cli) -> Result<(), Box<dyn Error + Send + Sync
8787
let bin_name = "nym-socks5-client";
8888

8989
match args.command {
90-
Commands::Init(m) => init::execute(&m).await?,
91-
Commands::Run(m) => run::execute(&m).await?,
90+
Commands::Init(m) => init::execute(m).await?,
91+
Commands::Run(m) => run::execute(m).await?,
9292
Commands::BuildInfo(m) => build_info::execute(m),
9393
Commands::Completions(s) => s.generate(&mut Cli::command(), bin_name),
9494
Commands::GenerateFigSpec => fig_generate(&mut Cli::command(), bin_name),

clients/socks5/src/commands/run.rs

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ use nym_client_core::client::topology_control::geo_aware_provider::CountryGroup;
1515
use nym_crypto::asymmetric::identity;
1616
use nym_socks5_client_core::NymClient;
1717
use nym_sphinx::addressing::clients::Recipient;
18+
use std::path::PathBuf;
1819

1920
#[derive(Args, Clone)]
2021
pub(crate) struct Run {
@@ -45,13 +46,17 @@ pub(crate) struct Run {
4546
nyxd_urls: Option<Vec<url::Url>>,
4647

4748
/// Comma separated list of rest endpoints of the Nym APIs
48-
#[clap(long, value_delimiter = ',')]
49+
#[clap(long, value_delimiter = ',', group = "network")]
4950
nym_apis: Option<Vec<url::Url>>,
5051

5152
/// Port for the socket to listen on
5253
#[clap(short, long)]
5354
port: Option<u16>,
5455

56+
/// Path to .json file containing custom network specification.
57+
#[clap(long, group = "network", group = "routing", hide = true)]
58+
custom_mixnet: Option<PathBuf>,
59+
5560
/// Mostly debug-related option to increase default traffic rate so that you would not need to
5661
/// modify config post init
5762
#[clap(long, hide = true)]
@@ -62,7 +67,7 @@ pub(crate) struct Run {
6267
no_cover: bool,
6368

6469
/// Set geo-aware mixnode selection when sending mixnet traffic, for experiments only.
65-
#[clap(long, hide = true, value_parser = validate_country_group)]
70+
#[clap(long, hide = true, value_parser = validate_country_group, group="routing")]
6671
geo_routing: Option<CountryGroup>,
6772

6873
/// Enable medium mixnet traffic, for experiments only.
@@ -124,7 +129,7 @@ fn version_check(cfg: &Config) -> bool {
124129
}
125130
}
126131

127-
pub(crate) async fn execute(args: &Run) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
132+
pub(crate) async fn execute(args: Run) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
128133
eprintln!("Starting client {}...", args.id);
129134

130135
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
138143
let storage =
139144
OnDiskPersistent::from_paths(config.storage_paths.common_paths, &config.core.base.debug)
140145
.await?;
141-
NymClient::new(config.core, storage).run_forever().await
146+
NymClient::new(config.core, storage, args.custom_mixnet)
147+
.run_forever()
148+
.await
142149
}

common/client-core/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ nym-gateway-requests = { path = "../../gateway/gateway-requests" }
4040
nym-nonexhaustive-delayqueue = { path = "../nonexhaustive-delayqueue" }
4141
nym-sphinx = { path = "../nymsphinx" }
4242
nym-pemstore = { path = "../pemstore" }
43-
nym-topology = { path = "../topology" }
43+
nym-topology = { path = "../topology", features = ["serializable"] }
4444
nym-validator-client = { path = "../client-libs/validator-client", default-features = false }
4545
nym-task = { path = "../task" }
4646
nym-credential-storage = { path = "../credential-storage" }

0 commit comments

Comments
 (0)