Files
nym/gateway/src/node/mod.rs
T
Jędrzej Stuczyński 46c67440bb Mixnode stress testing (#6575)
* Squashing the mix stress testing branch (#6575)

reduced chain watcher per block log severity

update network monitors contract semver to 1.0.0

fix build issues

fix mixnet client dropping initial packet on egress reconnection

adjusted logs for network monitor agent

changed default testing interval to 2h

refresh NM contract information

explicit return type for batch submission

for mixnet listener task to get scheduled before beginning connectivity test

make sure to always use canonical ip for network monitor noise keys

feat: NMv3: make agents decide egress port (#6746)

add config v12->v13 config migration for nym nodes

fix formatting in wallet types

simplified client config creation

remove other swagger redirect

removed swagger redirect on /swagger/ route

log version info on startup

add workflows, contract address, and dockerfile

bugfix: use correct endpoints when setting up orchestrator (#6733)

clippy

adjust DEFAULT_MIN_STRESS_TESTED_NODES ratio

expose route with new performance metrics

fixes and additional docs

use stress testing scores

stub for usage of stress testing scores

stub traits

added new fields to nym-api config controlling usage of stress test data

guard against duplicate packets

prevent usage of chain_authorisation_check_max_attempts with value of 0

make sure duplicate results cant be inserted into the db

submit test results from orchestrator on an interval

docs and fixes

nym-api side of handling result submission

stubs for submitting results

NM orchestrator verifying nym-api result submission permissions

NM orchestrator to update announced key on startup

allow NM orchestrator to announce its identity key to the contract

stubs within nym-api for accepting NMv3 results

added additional metrics

docs

bugfixes + making sure to only assign mixnode testruns

fixed node refresher to only retrieve mixnodes and add additional metrics

topology metrics

defined basic prometheus metrics

authorised endpoint for returning prometheus data

create initial stub for prometheus metrics

post rebasing fixes

adjusted routes

missing implementation for storage getters

a lot of new stubs and db accessors

stubs for results endpoints

update utoipa tags for agent rountes

shared auth between metrics and results

moved stale results eviction into the interval.tick branch

refactor and comments

create background process to evict stale data

include sphinx packet delay as part of the stats

fix mock construction

add median to the calculated latency distribution

remove unused imports

cleanup

performing testrun and submitting the results

assigning testruns to requesting agents

basic stub for http server for the NMv3 orchestrator

chore: rename existing 'NetworkMonitorAgent' to 'NodeStressTester'

make sure to use canonical ips within the noise config

fixed contract tests

cargo fmt

additional comments and unit tests

contract and nym-node support of NM agents being run on the same host

basic unit tests

refactoring

make agents retrieve mix port assignment from the orchestrator

provide sensible defaults to CLI arguments

stub the initial structure for the agent

chore: remove redundant import

missed tick behaviour

removed redundant mutex

removed redundant try_get_client

reuse existing constant for default nymnode port

add node refresher for periodic scraping of bonded nym-node details

- NodeRefresher periodically queries the mixnet contract for all bonded
  nodes and probes each node's HTTP API for host information, sphinx keys,
  noise keys, and key rotation IDs
- Extract NymNodeApiClientRetriever into nym-node-requests with port
  probing, identity verification, and host information signature checking
- Add clone_query_client on NyxdClient so the refresher can hold its own
  query client without locking the signing client
- Batch upsert for nym_node rows (single transaction instead of per-row)
- Reuse the new helpers in nym-api's node_describe_cache

ensure assignment of testrun begins an IMMEDIATE tx

construction of the orchestrator struct

initial set of cli args

make sure to not assign testable nodes too often

very initial database structure and cli

fixed construction of RoutableNetworkMonitors

remove redundant constructor for NoiseNode

forbid 0-nonsense config values

add type safety for test route construction

moved lioness and arrayref to workspace deps

fixed dockerfile build

always use canonical addresses in RoutableNetworkMonitors

fixed old contract formatting issues

removed redundant into() call

network monitor agent fixes

additional logs

config unit tests

more docs

standalone stress testing invocation

further refactoring and changes

refactor testing loop and return valid test result upon completion

initial sending/receiving test loop

generating reusable sphinx headers

additional structure for receiving ingress packets

initial scaffolding for NMv3 agent

added validation of x25519 noise key

removed unstable call to 'is_multiple_of'

remove calls to from_octets as they're unavailable in pre 1.91

additional docs/comments

propagating noise information about NM for mixnet routing

pass full socket address of the agent into the contract storage

feat: store noise keys alongside ip addresses within the contract

removed redundant comment

ensure NM packets can only go to NM

PR review comments

added additional docs

allow NM to replay packets + fix replay prometheus metrics

propagate information about nm agent to connection handler

updated nym-node config migration

feat: introduced nym-node websocket subscription for keeping updated list of NM agents

allow admin to also revoke monitor agents

remove agents upon orchestrator removal

fixed schema generation and regenerated the contract schema

removed rustc restriction on contracts-common

added client methods for interacting with the contract

added unit tests for contract methods

implemented logic of the network monitors contract

create initial structure for network monitors contract

start mix stress testing topic branch

* make nym-node default to the new blockstream rpc/ws node cluster

* reduced mixnet-client log severity

* set network monitors contract address for mainnet
2026-05-22 09:43:20 +01:00

630 lines
22 KiB
Rust

// Copyright 2020-2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: GPL-3.0-only
use crate::config::Config;
use crate::error::GatewayError;
use crate::node::client_handling::websocket;
use crate::node::internal_service_providers::authenticator::Authenticator;
use crate::node::internal_service_providers::{
authenticator, ExitServiceProviders, ServiceProviderBeingBuilt, SpMessageRouterBuilder,
};
use crate::node::stale_data_cleaner::StaleMessagesCleaner;
use futures::channel::oneshot;
use nym_credential_verification::ecash::{
credential_sender::CredentialHandlerConfig, EcashManager, MockEcashManager,
};
use nym_credential_verification::upgrade_mode::{
UpgradeModeCheckConfig, UpgradeModeDetails, UpgradeModeState,
};
use nym_crypto::asymmetric::ed25519;
use nym_ip_packet_router::IpPacketRouter;
use nym_mixnet_client::forwarder::MixForwardingSender;
use nym_network_defaults::NymNetworkDetails;
use nym_network_requester::NRServiceProviderBuilder;
use nym_node_metrics::events::MetricEventsSender;
use nym_node_metrics::NymNodeMetrics;
use nym_task::ShutdownTracker;
use nym_topology::TopologyProvider;
use nym_validator_client::nyxd::{Coin, CosmWasmClient};
use nym_validator_client::{nyxd, DirectSigningHttpRpcNyxdClient};
use rand::seq::SliceRandom;
use rand::thread_rng;
use std::net::IpAddr;
use std::path::PathBuf;
use std::sync::Arc;
use tracing::*;
use zeroize::Zeroizing;
pub use crate::node::upgrade_mode::watcher::UpgradeModeWatcher;
use crate::node::wireguard::{PeerManager, PeerRegistrator};
pub use client_handling::active_clients::ActiveClientsStore;
pub use nym_credential_verification::upgrade_mode::UpgradeModeCheckRequestSender;
pub use nym_gateway_stats_storage::PersistentStatsStorage;
pub use nym_gateway_storage::{
error::GatewayStorageError,
traits::{BandwidthGatewayStorage, InboxGatewayStorage},
GatewayStorage,
};
pub use nym_sdk::{NymApiTopologyProvider, NymApiTopologyProviderConfig, UserAgent};
pub(crate) mod client_handling;
pub(crate) mod internal_service_providers;
mod stale_data_cleaner;
pub mod upgrade_mode;
pub mod wireguard;
#[derive(Debug, Clone)]
pub struct LocalNetworkRequesterOpts {
pub config: nym_network_requester::Config,
pub custom_mixnet_path: Option<PathBuf>,
}
#[derive(Debug, Clone)]
pub struct LocalIpPacketRouterOpts {
pub config: nym_ip_packet_router::Config,
pub custom_mixnet_path: Option<PathBuf>,
}
#[derive(Debug, Clone)]
pub struct LocalAuthenticatorOpts {
pub config: authenticator::Config,
pub custom_mixnet_path: Option<PathBuf>,
}
pub struct GatewayTasksBuilder {
config: Config,
network: NymNetworkDetails,
network_requester_opts: Option<LocalNetworkRequesterOpts>,
ip_packet_router_opts: Option<LocalIpPacketRouterOpts>,
authenticator_opts: Option<LocalAuthenticatorOpts>,
// TODO: combine with authenticator, since you have to start both
wireguard_data: Option<nym_wireguard::WireguardData>,
user_agent: UserAgent,
/// ed25519 keypair used to assert one's identity.
identity_keypair: Arc<ed25519::KeyPair>,
storage: GatewayStorage,
mix_packet_sender: MixForwardingSender,
metrics_sender: MetricEventsSender,
metrics: NymNodeMetrics,
upgrade_mode_state: UpgradeModeState,
mnemonic: Arc<Zeroizing<bip39::Mnemonic>>,
shutdown_tracker: ShutdownTracker,
use_mock_ecash: bool,
// populated and cached as necessary
ecash_manager:
Option<Arc<dyn nym_credential_verification::ecash::traits::EcashManager + Send + Sync>>,
wireguard_peers: Option<Vec<defguard_wireguard_rs::host::Peer>>,
wireguard_networks: Option<Vec<IpAddr>>,
}
impl GatewayTasksBuilder {
#[allow(clippy::too_many_arguments)]
pub fn new(
config: Config,
network: NymNetworkDetails,
identity: Arc<ed25519::KeyPair>,
storage: GatewayStorage,
mix_packet_sender: MixForwardingSender,
metrics_sender: MetricEventsSender,
metrics: NymNodeMetrics,
mnemonic: Arc<Zeroizing<bip39::Mnemonic>>,
user_agent: UserAgent,
upgrade_mode_state: UpgradeModeState,
use_mock_ecash: bool,
shutdown_tracker: ShutdownTracker,
) -> GatewayTasksBuilder {
GatewayTasksBuilder {
config,
network,
network_requester_opts: None,
ip_packet_router_opts: None,
authenticator_opts: None,
wireguard_data: None,
user_agent,
identity_keypair: identity,
storage,
mix_packet_sender,
metrics_sender,
metrics,
upgrade_mode_state,
mnemonic,
shutdown_tracker,
use_mock_ecash,
ecash_manager: None,
wireguard_peers: None,
wireguard_networks: None,
}
}
pub fn set_network_requester_opts(
&mut self,
network_requester_opts: Option<LocalNetworkRequesterOpts>,
) {
self.network_requester_opts = network_requester_opts;
}
pub fn set_ip_packet_router_opts(
&mut self,
ip_packet_router_opts: Option<LocalIpPacketRouterOpts>,
) {
self.ip_packet_router_opts = ip_packet_router_opts;
}
pub fn set_authenticator_opts(&mut self, authenticator_opts: Option<LocalAuthenticatorOpts>) {
self.authenticator_opts = authenticator_opts;
}
pub fn set_wireguard_data(&mut self, wireguard_data: nym_wireguard::WireguardData) {
self.wireguard_data = Some(wireguard_data)
}
// if this is to be used anywhere else, we might need some wrapper around it
async fn build_nyxd_signing_client(
&self,
) -> Result<DirectSigningHttpRpcNyxdClient, GatewayError> {
let endpoints = self.config.get_nyxd_urls();
let validator_nyxd = endpoints
.choose(&mut thread_rng())
.ok_or(GatewayError::NoNyxdAvailable)?;
let client_config = nyxd::Config::try_from_nym_network_details(&self.network)?;
let nyxd_client = DirectSigningHttpRpcNyxdClient::connect_with_mnemonic(
client_config,
validator_nyxd.as_ref(),
(**self.mnemonic).clone(),
)?;
let mix_denom_base = nyxd_client.current_chain_details().mix_denom.base.clone();
let account = nyxd_client.address();
let balance = nyxd_client
.get_balance(&account, mix_denom_base.clone())
.await?
.unwrap_or(Coin::new(0, mix_denom_base));
// see if we have at least 1nym (i.e. 1'000'000unym)
if balance.amount < 1_000_000 {
// don't allow constructing the client of we have to use zknym and don't have sufficient balance
if self.config.gateway.enforce_zk_nyms {
return Err(GatewayError::InsufficientNodeBalance { account, balance });
}
// TODO: this has to be enforced **ALL THE TIME in ENTRY mode**,
// because even if we don't demand zknym, somebody may send them and we need sufficient tokens for
// transaction fees for submitting redemption proposals
// but we're not going to introduce this check now as it would break a lot of existing gateways,
// so for now just log this error
error!("this gateway ({account}) has insufficient balance for possible zk-nym redemption transaction fees. it only has {balance} available.")
}
Ok(nyxd_client)
}
async fn build_ecash_manager(
&self,
) -> Result<
Arc<dyn nym_credential_verification::ecash::traits::EcashManager + Send + Sync>,
GatewayError,
> {
// Check if we should use mock ecash for testing
if self.use_mock_ecash {
warn!("Using MockEcashManager for testing (credentials NOT verified)");
let mock_manager = MockEcashManager::new(Box::new(self.storage.clone()));
return Ok(Arc::new(mock_manager)
as Arc<
dyn nym_credential_verification::ecash::traits::EcashManager + Send + Sync,
>);
}
// Production path: use real EcashManager with blockchain verification
let handler_config = CredentialHandlerConfig {
revocation_bandwidth_penalty: self
.config
.debug
.zk_nym_tickets
.revocation_bandwidth_penalty,
pending_poller: self.config.debug.zk_nym_tickets.pending_poller,
minimum_api_quorum: self.config.debug.zk_nym_tickets.minimum_api_quorum,
minimum_redemption_tickets: self.config.debug.zk_nym_tickets.minimum_redemption_tickets,
maximum_time_between_redemption: self
.config
.debug
.zk_nym_tickets
.maximum_time_between_redemption,
};
let nyxd_client = self.build_nyxd_signing_client().await?;
let (ecash_manager, credential_handler) = EcashManager::new(
handler_config,
nyxd_client,
self.identity_keypair.public_key().to_bytes(),
self.storage.clone(),
)
.await?;
let shutdown_token = self.shutdown_tracker.clone_shutdown_token();
self.shutdown_tracker.try_spawn_named(
async move { credential_handler.run(shutdown_token).await },
"EcashCredentialHandler",
);
Ok(Arc::new(ecash_manager)
as Arc<
dyn nym_credential_verification::ecash::traits::EcashManager + Send + Sync,
>)
}
async fn ecash_manager(
&mut self,
) -> Result<
Arc<dyn nym_credential_verification::ecash::traits::EcashManager + Send + Sync>,
GatewayError,
> {
match self.ecash_manager.clone() {
Some(cached) => Ok(cached),
None => {
let manager = self.build_ecash_manager().await?;
self.ecash_manager = Some(manager.clone());
Ok(manager)
}
}
}
pub async fn build_peer_registrator(
&mut self,
upgrade_mode_details: UpgradeModeDetails,
) -> Result<Option<PeerRegistrator>, GatewayError> {
let Some(wireguard_data) = &self.wireguard_data else {
return Ok(None);
};
let peer_manager = PeerManager::new(wireguard_data.inner.clone());
Ok(Some(PeerRegistrator::new(
self.ecash_manager().await?,
peer_manager,
upgrade_mode_details,
)))
}
pub async fn build_websocket_listener(
&mut self,
active_clients_store: ActiveClientsStore,
upgrade_mode_common_state: UpgradeModeDetails,
) -> Result<websocket::Listener, GatewayError> {
let shared_state = websocket::CommonHandlerState {
cfg: websocket::Config {
enforce_zk_nym: self.config.gateway.enforce_zk_nyms,
max_request_timestamp_skew: self.config.debug.max_request_timestamp_skew,
bandwidth: (&self.config).into(),
},
ecash_verifier: self.ecash_manager().await?,
storage: self.storage.clone(),
local_identity: Arc::clone(&self.identity_keypair),
metrics: self.metrics.clone(),
metrics_sender: self.metrics_sender.clone(),
outbound_mix_sender: self.mix_packet_sender.clone(),
active_clients_store: active_clients_store.clone(),
upgrade_mode: upgrade_mode_common_state,
};
Ok(websocket::Listener::new(
self.config.gateway.websocket_bind_address,
self.config.debug.maximum_open_connections,
shared_state,
self.shutdown_tracker.clone(),
))
}
fn build_network_requester(
&mut self,
topology_provider: Box<dyn TopologyProvider + Send + Sync>,
) -> Result<ServiceProviderBeingBuilt<NRServiceProviderBuilder>, GatewayError> {
// if network requester is enabled, configuration file must be provided!
let Some(nr_opts) = &self.network_requester_opts else {
return Err(GatewayError::UnspecifiedNetworkRequesterConfig);
};
let mut message_router_builder = SpMessageRouterBuilder::new(
*self.identity_keypair.public_key(),
self.mix_packet_sender.clone(),
);
let transceiver = message_router_builder.gateway_transceiver();
let (on_start_tx, on_start_rx) = oneshot::channel();
let mut nr_builder =
NRServiceProviderBuilder::new(nr_opts.config.clone(), self.shutdown_tracker.clone())
.with_custom_gateway_transceiver(transceiver)
.with_wait_for_gateway(true)
.with_wait_for_initial_topology(true)
.with_minimum_gateway_performance(0)
.with_custom_topology_provider(topology_provider)
.with_on_start(on_start_tx);
if let Some(custom_mixnet) = &nr_opts.custom_mixnet_path {
nr_builder = nr_builder.with_stored_topology(custom_mixnet)?
}
Ok(ServiceProviderBeingBuilt::new(
on_start_rx,
nr_builder,
message_router_builder,
self.shutdown_tracker.clone(),
))
}
fn build_ip_router(
&mut self,
topology_provider: Box<dyn TopologyProvider + Send + Sync>,
) -> Result<ServiceProviderBeingBuilt<IpPacketRouter>, GatewayError> {
let Some(ip_opts) = &self.ip_packet_router_opts else {
return Err(GatewayError::UnspecifiedIpPacketRouterConfig);
};
let mut message_router_builder = SpMessageRouterBuilder::new(
*self.identity_keypair.public_key(),
self.mix_packet_sender.clone(),
);
let transceiver = message_router_builder.gateway_transceiver();
let (on_start_tx, on_start_rx) = oneshot::channel();
let mut ip_packet_router =
IpPacketRouter::new(ip_opts.config.clone(), self.shutdown_tracker.clone())
.with_custom_gateway_transceiver(Box::new(transceiver))
.with_wait_for_gateway(true)
.with_wait_for_initial_topology(true)
.with_minimum_gateway_performance(0)
.with_custom_topology_provider(topology_provider)
.with_on_start(on_start_tx);
if let Some(custom_mixnet) = &ip_opts.custom_mixnet_path {
ip_packet_router = ip_packet_router.with_stored_topology(custom_mixnet)?
}
Ok(ServiceProviderBeingBuilt::new(
on_start_rx,
ip_packet_router,
message_router_builder,
self.shutdown_tracker.clone(),
))
}
pub fn build_exit_service_providers(
&mut self,
// TODO: redesign the trait to allow cloning more easily
// (or use concrete types)
nr_topology_provider: Box<dyn TopologyProvider + Send + Sync>,
ipr_topology_provider: Box<dyn TopologyProvider + Send + Sync>,
) -> Result<ExitServiceProviders, GatewayError> {
Ok(ExitServiceProviders {
network_requester: self.build_network_requester(nr_topology_provider)?,
ip_router: self.build_ip_router(ipr_topology_provider)?,
})
}
async fn build_wireguard_peers_and_networks(
&self,
) -> Result<(Vec<defguard_wireguard_rs::host::Peer>, Vec<IpAddr>), GatewayError> {
let mut used_private_network_ips = vec![];
let mut all_peers = vec![];
for wireguard_peer in self.storage.get_all_wireguard_peers().await?.into_iter() {
let mut peer = defguard_wireguard_rs::host::Peer::try_from(wireguard_peer.clone())?;
let Some(allowed_ip) = peer.allowed_ips.pop() else {
let peer_identity = &peer.public_key;
warn!("Peer {peer_identity} has empty allowed ips. It will be removed",);
self.storage
.remove_wireguard_peer(&peer_identity.to_string())
.await?;
continue;
};
used_private_network_ips.push(allowed_ip.address);
all_peers.push(peer);
}
Ok((all_peers, used_private_network_ips))
}
// only used under linux
#[allow(dead_code)]
async fn get_wireguard_peers(
&mut self,
) -> Result<Vec<defguard_wireguard_rs::host::Peer>, GatewayError> {
if let Some(cached) = self.wireguard_peers.take() {
return Ok(cached);
}
let (peers, used_private_network_ips) = self.build_wireguard_peers_and_networks().await?;
// cache private networks for the other task
self.wireguard_networks = Some(used_private_network_ips);
Ok(peers)
}
pub async fn build_wireguard_authenticator(
&mut self,
peer_registrator: PeerRegistrator,
upgrade_mode_common: UpgradeModeDetails,
topology_provider: Box<dyn TopologyProvider + Send + Sync>,
) -> Result<ServiceProviderBeingBuilt<Authenticator>, GatewayError> {
let Some(opts) = &self.authenticator_opts else {
return Err(GatewayError::UnspecifiedAuthenticatorConfig);
};
let Some(wireguard_data) = &self.wireguard_data else {
return Err(GatewayError::InternalWireguardError(
"wireguard not set".to_string(),
));
};
let mut message_router_builder = SpMessageRouterBuilder::new(
*self.identity_keypair.public_key(),
self.mix_packet_sender.clone(),
);
let transceiver = message_router_builder.gateway_transceiver();
let (on_start_tx, on_start_rx) = oneshot::channel();
let mut authenticator_server = Authenticator::new(
opts.config.clone(),
peer_registrator,
upgrade_mode_common,
wireguard_data.inner.clone(),
self.shutdown_tracker.clone(),
)
.with_custom_gateway_transceiver(transceiver)
.with_wait_for_gateway(true)
.with_wait_for_initial_topology(true)
.with_minimum_gateway_performance(0)
.with_custom_topology_provider(topology_provider)
.with_on_start(on_start_tx);
if let Some(custom_mixnet) = &opts.custom_mixnet_path {
authenticator_server = authenticator_server.with_stored_topology(custom_mixnet)?
}
Ok(ServiceProviderBeingBuilt::new(
on_start_rx,
authenticator_server,
message_router_builder,
self.shutdown_tracker.clone(),
))
}
pub fn build_stale_messages_cleaner(&self) -> StaleMessagesCleaner {
StaleMessagesCleaner::new(
&self.storage,
self.config.debug.stale_messages_max_age,
self.config.debug.stale_messages_cleaner_run_interval,
)
}
pub fn build_upgrade_mode_common_state(
&self,
request_checker: UpgradeModeCheckRequestSender,
) -> UpgradeModeDetails {
UpgradeModeDetails::new(
UpgradeModeCheckConfig {
min_staleness_recheck: self.config.debug.upgrade_mode_min_staleness_recheck,
},
request_checker,
self.upgrade_mode_state.clone(),
)
}
pub fn try_build_upgrade_mode_watcher(&self) -> Option<UpgradeModeWatcher> {
if !self.config.upgrade_mode_watcher.enabled {
warn!("upgrade mode watcher is disabled");
return None;
}
Some(UpgradeModeWatcher::new(
self.config
.upgrade_mode_watcher
.debug
.regular_polling_interval,
self.config
.upgrade_mode_watcher
.debug
.expedited_poll_interval,
self.config.debug.upgrade_mode_min_staleness_recheck,
self.config.upgrade_mode_watcher.attestation_url.clone(),
self.upgrade_mode_state.clone(),
self.user_agent.clone(),
self.shutdown_tracker.clone_shutdown_token(),
))
}
#[cfg(not(target_os = "linux"))]
#[allow(clippy::unimplemented)]
pub async fn try_start_wireguard(
&mut self,
_upgrade_mode_details: UpgradeModeDetails,
) -> Result<Arc<nym_wireguard::WgApiWrapper>, Box<dyn std::error::Error + Send + Sync>> {
let _ = self.metrics.clone();
let _ = self.shutdown_tracker.clone();
unimplemented!("wireguard is not supported on this platform")
}
#[cfg(target_os = "linux")]
pub async fn try_start_wireguard(
&mut self,
upgrade_mode_details: UpgradeModeDetails,
) -> Result<
nym_wireguard_private_metadata_server::ShutdownHandles,
Box<dyn std::error::Error + Send + Sync>,
> {
let all_peers = self.get_wireguard_peers().await?;
let Some(wireguard_data) = self.wireguard_data.take() else {
return Err(
GatewayError::InternalWireguardError("wireguard not set".to_string()).into(),
);
};
let Some(ecash_manager) = self.ecash_manager.clone() else {
return Err(
GatewayError::InternalWireguardError("ecash manager not set".to_string()).into(),
);
};
let router = nym_wireguard_private_metadata_server::RouterBuilder::with_default_routes();
let router = router.with_state(nym_wireguard_private_metadata_server::AppState::new(
nym_wireguard_private_metadata_server::PeerControllerTransceiver::new(
wireguard_data.inner.peer_tx().clone(),
),
upgrade_mode_details,
));
let bind_address = std::net::SocketAddr::new(
wireguard_data.inner.config().private_ipv4.into(),
wireguard_data.inner.config().announced_metadata_port,
);
let use_userspace = wireguard_data.use_userspace;
let wg_handle = nym_wireguard::start_wireguard(
ecash_manager,
self.metrics.clone(),
all_peers,
self.upgrade_mode_state.upgrade_mode_status(),
self.shutdown_tracker.clone_shutdown_token(),
wireguard_data,
use_userspace,
)
.await?;
let server = router.build_server(&bind_address).await?;
let cancel_token = self.shutdown_tracker.clone_shutdown_token();
let server_handle = tokio::spawn(async move {
{
info!("Started Wireguard Axum HTTP V2 server on {bind_address}");
server.run(cancel_token.cancelled_owned()).await
}
});
let shutdown_handles =
nym_wireguard_private_metadata_server::ShutdownHandles::new(server_handle, wg_handle);
Ok(shutdown_handles)
}
}