diff --git a/common/client-core/src/client/base_client/mod.rs b/common/client-core/src/client/base_client/mod.rs index c7a84ca610..18d4b40a13 100644 --- a/common/client-core/src/client/base_client/mod.rs +++ b/common/client-core/src/client/base_client/mod.rs @@ -42,6 +42,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_validator_client::NymApiClient; +use rand::seq::SliceRandom; +use rand::thread_rng; use std::sync::Arc; use tap::TapFallible; use url::Url; @@ -298,6 +301,7 @@ where bandwidth_controller: Option>, mixnet_message_sender: MixnetMessageSender, ack_sender: AcknowledgementSender, + api_client: NymApiClient, shutdown: TaskClient, ) -> Result, ClientCoreError> where @@ -326,6 +330,7 @@ where ack_sender, config.debug.gateway_connection.gateway_response_timeout, bandwidth_controller, + api_client, shutdown, ); @@ -343,6 +348,15 @@ where Ok(gateway_client) } + fn random_api_client(&self) -> nym_validator_client::NymApiClient { + let endpoints = self.config.get_nym_api_endpoints(); + let nym_api = endpoints + .choose(&mut thread_rng()) + .expect("The list of validator apis is empty"); + + nym_validator_client::NymApiClient::new(nym_api.clone()) + } + fn setup_topology_provider( custom_provider: Option>, nym_api_urls: Vec, @@ -474,6 +488,8 @@ where let gateway_config = details.gateway_details; let managed_keys = details.managed_keys; + let random_api_client = self.random_api_client(); + let (reply_storage_backend, credential_store) = self.client_store.into_runtime_stores(); let bandwidth_controller = self @@ -517,6 +533,7 @@ where bandwidth_controller, mixnet_messages_sender, ack_sender, + random_api_client, task_manager.subscribe(), ) .await?; diff --git a/common/client-core/src/init/helpers.rs b/common/client-core/src/init/helpers.rs index c82100034b..77e14a2a51 100644 --- a/common/client-core/src/init/helpers.rs +++ b/common/client-core/src/init/helpers.rs @@ -9,6 +9,7 @@ use nym_crypto::asymmetric::{encryption, identity}; use nym_gateway_client::GatewayClient; use nym_gateway_requests::registration::handshake::SharedKeys; use nym_topology::{filter::VersionFilterable, gateway}; +use nym_validator_client::NymApiClient; use rand::{seq::SliceRandom, Rng}; use std::{sync::Arc, time::Duration}; use tap::TapFallible; @@ -201,6 +202,7 @@ pub(super) async fn register_with_gateway( gateway: &GatewayEndpointConfig, our_identity: Arc, our_sphinx: Arc, + nym_api_client: NymApiClient, ) -> Result, ClientCoreError> { let timeout = Duration::from_millis(1500); let mut gateway_client: GatewayClient = GatewayClient::new_init( @@ -210,6 +212,7 @@ pub(super) async fn register_with_gateway( our_identity.clone(), our_sphinx.clone(), timeout, + nym_api_client, ); gateway_client .establish_connection() diff --git a/common/client-core/src/init/mod.rs b/common/client-core/src/init/mod.rs index 77833b44b8..01668817bc 100644 --- a/common/client-core/src/init/mod.rs +++ b/common/client-core/src/init/mod.rs @@ -17,7 +17,9 @@ use nym_crypto::asymmetric::identity; use nym_sphinx::addressing::{clients::Recipient, nodes::NodeIdentity}; use nym_topology::gateway; use nym_validator_client::client::IdentityKey; +use nym_validator_client::NymApiClient; use rand::rngs::OsRng; +use rand::seq::SliceRandom; use serde::Serialize; use std::fmt::{Debug, Display}; use url::Url; @@ -271,6 +273,7 @@ pub async fn setup_gateway_from( details_store: &D, overwrite_data: bool, gateways: Option<&[gateway::Node]>, + nym_api_client: NymApiClient, ) -> Result where K: KeyStore, @@ -374,7 +377,8 @@ where // Establish connection, authenticate and generate keys for talking with the gateway let shared_keys = - helpers::register_with_gateway(&gateway_details, our_identity, our_sphinx).await?; + helpers::register_with_gateway(&gateway_details, our_identity, our_sphinx, nym_api_client) + .await?; let persisted_details = PersistedGatewayDetails::new(gateway_details, &shared_keys); @@ -411,12 +415,19 @@ where let mut rng = OsRng; let gateways = current_gateways(&mut rng, validator_servers.unwrap_or_default()).await?; + let nym_api = validator_servers + .unwrap_or_default() + .choose(&mut rng) + .ok_or(ClientCoreError::ListOfNymApisIsEmpty)?; + let client = nym_validator_client::client::NymApiClient::new(nym_api.clone()); + setup_gateway_from( setup, key_store, details_store, overwrite_data, Some(&gateways), + client, ) .await } diff --git a/common/client-libs/gateway-client/src/client.rs b/common/client-libs/gateway-client/src/client.rs index 12d5f6dfda..225b458936 100644 --- a/common/client-libs/gateway-client/src/client.rs +++ b/common/client-libs/gateway-client/src/client.rs @@ -23,6 +23,7 @@ use nym_network_defaults::{REMAINING_BANDWIDTH_THRESHOLD, TOKENS_TO_BURN}; use nym_noise::upgrade_noise_initiator; use nym_sphinx::forwarding::packet::MixPacket; use nym_task::TaskClient; +use nym_validator_client::NymApiClient; use rand::rngs::OsRng; use std::convert::TryFrom; use std::net::SocketAddr; @@ -60,6 +61,7 @@ pub struct GatewayClient { packet_router: PacketRouter, response_timeout_duration: Duration, bandwidth_controller: Option>, + nym_api_client: NymApiClient, // reconnection related variables /// Specifies whether client should try to reconnect to gateway on connection failure. @@ -89,6 +91,7 @@ impl GatewayClient { ack_sender: AcknowledgementSender, response_timeout_duration: Duration, bandwidth_controller: Option>, + nym_api_client: NymApiClient, shutdown: TaskClient, ) -> Self { GatewayClient { @@ -105,6 +108,7 @@ impl GatewayClient { packet_router: PacketRouter::new(ack_sender, mixnet_message_sender, shutdown.clone()), response_timeout_duration, bandwidth_controller, + nym_api_client, should_reconnect_on_failure: true, reconnection_attempts: DEFAULT_RECONNECTION_ATTEMPTS, reconnection_backoff: DEFAULT_RECONNECTION_BACKOFF, @@ -180,12 +184,20 @@ impl GatewayClient { Ok(stream_res) => match stream_res { Ok(stream) => { debug!("Managed to establish connection to gateway"); + let current_epoch_id = match self.nym_api_client.get_current_epoch_id().await { + Ok(epoch_id) => epoch_id, + Err(err) => { + error!("Failed to retrieve epoch Id for Noise handshake - {err}"); + return Err(GatewayClientError::ConnectionNotEstablished); + } + }; + let noise_stream = match upgrade_noise_initiator( stream, None, //as a client, the gateway cannot know my pub key &self.local_sphinx.private_key().to_bytes(), &self.gateway_sphinx.to_bytes(), - 0, + current_epoch_id, ) .await { @@ -830,6 +842,7 @@ impl GatewayClient { local_identity: Arc, local_sphinx: Arc, response_timeout_duration: Duration, + nym_api_client: NymApiClient, ) -> Self { use futures::channel::mpsc; @@ -854,6 +867,7 @@ impl GatewayClient { packet_router, response_timeout_duration, bandwidth_controller: None, + nym_api_client, should_reconnect_on_failure: false, reconnection_attempts: DEFAULT_RECONNECTION_ATTEMPTS, reconnection_backoff: DEFAULT_RECONNECTION_BACKOFF, diff --git a/gateway/src/node/client_handling/websocket/listener.rs b/gateway/src/node/client_handling/websocket/listener.rs index b0f35d4590..e2f187d3c2 100644 --- a/gateway/src/node/client_handling/websocket/listener.rs +++ b/gateway/src/node/client_handling/websocket/listener.rs @@ -9,6 +9,7 @@ use log::*; use nym_crypto::asymmetric::{encryption, identity}; use nym_mixnet_client::forwarder::MixForwardingSender; use nym_noise::upgrade_noise_responder; +use nym_validator_client::NymApiClient; use rand::rngs::OsRng; use std::net::SocketAddr; use std::process; @@ -21,6 +22,7 @@ pub(crate) struct Listener { local_sphinx: Arc, only_coconut_credentials: bool, pub(crate) coconut_verifier: Arc, + nym_api_client: NymApiClient, } impl Listener { @@ -30,6 +32,7 @@ impl Listener { local_sphinx: Arc, only_coconut_credentials: bool, coconut_verifier: Arc, + nym_api_client: NymApiClient, ) -> Self { Listener { address, @@ -37,6 +40,7 @@ impl Listener { local_sphinx, only_coconut_credentials, coconut_verifier, + nym_api_client, } } @@ -72,12 +76,20 @@ impl Listener { trace!("received a socket connection from {remote_addr}"); // TODO: I think we *REALLY* need a mechanism for having a maximum number of connected // clients or spawned tokio tasks -> perhaps a worker system? + + let current_epoch_id = match self.nym_api_client.get_current_epoch_id().await { + Ok(epoch_id) => epoch_id, + Err(err) => { + error!("Failed to retrieve epoch Id for Noise handshake - {err}"); + return; + } + }; let noise_stream = match upgrade_noise_responder( socket, &self.local_sphinx.public_key().to_bytes(), &self.local_sphinx.private_key().to_bytes(), None, //connection from client, no remote pub key - 0, + current_epoch_id, ) .await { diff --git a/gateway/src/node/mod.rs b/gateway/src/node/mod.rs index 623a2c08ba..2f53a7ccca 100644 --- a/gateway/src/node/mod.rs +++ b/gateway/src/node/mod.rs @@ -179,6 +179,7 @@ impl Gateway { Arc::clone(&self.sphinx_keypair), self.config.gateway.only_coconut_credentials, coconut_verifier, + self.random_api_client(), ) .start( forwarding_channel,