From 4c19187c787cc6b05858d0b837439a03296fd036 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jon=20H=C3=A4ggblad?= Date: Tue, 24 Jan 2023 08:50:59 +0100 Subject: [PATCH] rust-sdk: start adding rustdoc (#2895) * rust-sdk: start adding some rustdoc * rust-sdk: whole bunch of rustdoc * rustfmt --- .../manually_handle_keys_and_config.rs | 5 +- sdk/rust/nym-sdk/examples/persist_keys.rs | 6 +- sdk/rust/nym-sdk/examples/simple.rs | 4 +- .../examples/simple_but_manually_connect.rs | 6 +- sdk/rust/nym-sdk/src/error.rs | 10 +- sdk/rust/nym-sdk/src/lib.rs | 9 +- sdk/rust/nym-sdk/src/mixnet.rs | 40 +- sdk/rust/nym-sdk/src/mixnet/client.rs | 345 +++++++++++------- sdk/rust/nym-sdk/src/mixnet/config.rs | 2 + .../nym-sdk/src/mixnet/connection_state.rs | 2 +- sdk/rust/nym-sdk/src/mixnet/keys.rs | 15 + sdk/rust/nym-sdk/src/mixnet/paths.rs | 26 +- 12 files changed, 317 insertions(+), 153 deletions(-) diff --git a/sdk/rust/nym-sdk/examples/manually_handle_keys_and_config.rs b/sdk/rust/nym-sdk/examples/manually_handle_keys_and_config.rs index a412a6921a..95b76fd75e 100644 --- a/sdk/rust/nym-sdk/examples/manually_handle_keys_and_config.rs +++ b/sdk/rust/nym-sdk/examples/manually_handle_keys_and_config.rs @@ -10,7 +10,7 @@ async fn main() { let config = mixnet::Config::new(user_chosen_gateway_id, nym_api_endpoints); - let mut client = mixnet::MixnetClientBuilder::new(Some(config), None) + let mut client = mixnet::MixnetClient::builder(Some(config), None) .await .unwrap(); @@ -37,7 +37,8 @@ async fn main() { println!("Our client address is {}", client.nym_address()); // Send important info up the pipe to a buddy - client.send_str("foo.bar@blah", "flappappa").await; + let recipient = mixnet::Recipient::try_from_base58_string("foo.bar@blah").unwrap(); + client.send_str(recipient, "flappappa").await; } #[allow(unused)] diff --git a/sdk/rust/nym-sdk/examples/persist_keys.rs b/sdk/rust/nym-sdk/examples/persist_keys.rs index c4240d484f..dc983e695a 100644 --- a/sdk/rust/nym-sdk/examples/persist_keys.rs +++ b/sdk/rust/nym-sdk/examples/persist_keys.rs @@ -14,7 +14,7 @@ async fn main() { let keys = mixnet::StoragePaths::new_from_dir(mixnet::KeyMode::Keep, &config_dir).unwrap(); // Provide key paths for the client to read/write keys to. - let client = mixnet::MixnetClientBuilder::new(None, Some(keys)) + let client = mixnet::MixnetClient::builder(None, Some(keys)) .await .unwrap(); @@ -26,9 +26,7 @@ async fn main() { println!("Our client nym address is: {our_address}"); // Send a message throught the mixnet to ourselves - client - .send_str(&our_address.to_string(), "hello there") - .await; + client.send_str(*our_address, "hello there").await; println!("Waiting for message"); if let Some(received) = client.wait_for_messages().await { diff --git a/sdk/rust/nym-sdk/examples/simple.rs b/sdk/rust/nym-sdk/examples/simple.rs index d11d4c85a6..a485dbf75e 100644 --- a/sdk/rust/nym-sdk/examples/simple.rs +++ b/sdk/rust/nym-sdk/examples/simple.rs @@ -12,9 +12,7 @@ async fn main() { println!("Our client nym address is: {our_address}"); // Send a message throught the mixnet to ourselves - client - .send_str(&our_address.to_string(), "hello there") - .await; + client.send_str(*our_address, "hello there").await; println!("Waiting for message (ctrl-c to exit)"); client diff --git a/sdk/rust/nym-sdk/examples/simple_but_manually_connect.rs b/sdk/rust/nym-sdk/examples/simple_but_manually_connect.rs index 453ae795bd..5e9a98fa7e 100644 --- a/sdk/rust/nym-sdk/examples/simple_but_manually_connect.rs +++ b/sdk/rust/nym-sdk/examples/simple_but_manually_connect.rs @@ -7,7 +7,7 @@ async fn main() { // Create client builder, including ephemeral keys. The builder can be usable in the context // where you don't want to connect just yet. // Since not storage paths are given, the surb storage will be inactive. - let client = mixnet::MixnetClientBuilder::new(None, None).await.unwrap(); + let client = mixnet::MixnetClient::builder(None, None).await.unwrap(); // Now we connect to the mixnet, using ephemeral keys already created let mut client = client.connect_to_mixnet().await.unwrap(); @@ -17,9 +17,7 @@ async fn main() { println!("Our client nym address is: {our_address}"); // Send a message throught the mixnet to ourselves - client - .send_str(&our_address.to_string(), "hello there") - .await; + client.send_str(*our_address, "hello there").await; println!("Waiting for message"); if let Some(received) = client.wait_for_messages().await { diff --git a/sdk/rust/nym-sdk/src/error.rs b/sdk/rust/nym-sdk/src/error.rs index 6003256ad8..5e835db540 100644 --- a/sdk/rust/nym-sdk/src/error.rs +++ b/sdk/rust/nym-sdk/src/error.rs @@ -1,5 +1,6 @@ use std::path::PathBuf; +/// Top-level Error enum for the mixnet client and its relevant types. #[derive(Debug, thiserror::Error)] pub enum Error { #[error("i/o error: {0}")] @@ -20,9 +21,16 @@ pub enum Error { DontOverwriteGatewayKey(PathBuf), #[error("no gateway config available for writing")] GatewayNotAvailableForWriting, - #[error("expected to received a directory, received: {0}")] ExpectedDirectory(PathBuf), + + #[error("failed to transition to registered state before connection to mixnet")] + FailedToTransitionToRegisteredState, + #[error( + "registering with gateway when the client is already in a registered state is not \ + supported, and likely and user mistake" + )] + ReregisteringGatewayNotSupported, } pub type Result = std::result::Result; diff --git a/sdk/rust/nym-sdk/src/lib.rs b/sdk/rust/nym-sdk/src/lib.rs index de6ec53412..d4306ab336 100644 --- a/sdk/rust/nym-sdk/src/lib.rs +++ b/sdk/rust/nym-sdk/src/lib.rs @@ -1,2 +1,9 @@ -pub mod error; +//! Rust SDK for the Nym platform +//! +//! The main component currently is [`mixnet`]. + +mod error; + pub mod mixnet; + +pub use error::{Error, Result}; diff --git a/sdk/rust/nym-sdk/src/mixnet.rs b/sdk/rust/nym-sdk/src/mixnet.rs index 1428d6ae45..c4c4164958 100644 --- a/sdk/rust/nym-sdk/src/mixnet.rs +++ b/sdk/rust/nym-sdk/src/mixnet.rs @@ -1,17 +1,47 @@ +//! The mixnet component of the Rust SDK for the Nym platform +//! +//! +//! # Basic example +//! +//! ```no_run +//! use nym_sdk::mixnet; +//! +//! #[tokio::main] +//! async fn main() { +//! // Passing no config makes the client fire up an ephemeral session and figure stuff out on +//! // its own +//! let mut client = mixnet::MixnetClient::connect().await.unwrap(); +//! +//! // Be able to get our client address +//! let our_address = client.nym_address(); +//! println!("Our client nym address is: {our_address}"); +//! +//! // Send a message throught the mixnet to ourselves +//! client.send_str(*our_address, "hello there").await; +//! +//! println!("Waiting for message"); +//! if let Some(received) = client.wait_for_messages().await { +//! for r in received { +//! println!("Received: {}", String::from_utf8_lossy(&r.message)); +//! } +//! } +//! +//! client.disconnect().await; +//! } +//! ``` + mod client; mod config; mod connection_state; mod keys; mod paths; +pub use client::{MixnetClient, MixnetClientBuilder}; pub use client_core::config::GatewayEndpointConfig; +pub use config::Config; +pub use keys::{Keys, KeysArc}; pub use nymsphinx::{ addressing::clients::{ClientIdentity, Recipient}, receiver::ReconstructedMessage, }; - -pub use keys::{Keys, KeysArc}; pub use paths::{GatewayKeyMode, KeyMode, StoragePaths}; - -pub use client::{MixnetClient, MixnetClientBuilder}; -pub use config::Config; diff --git a/sdk/rust/nym-sdk/src/mixnet/client.rs b/sdk/rust/nym-sdk/src/mixnet/client.rs index 9a7df7ee96..4de5f04a81 100644 --- a/sdk/rust/nym-sdk/src/mixnet/client.rs +++ b/sdk/rust/nym-sdk/src/mixnet/client.rs @@ -24,10 +24,18 @@ use task::TaskManager; use futures::StreamExt; use validator_client::nyxd::SigningNyxdClient; -use super::{connection_state::BuilderState, Config, GatewayKeyMode, Keys, KeysArc, StoragePaths}; -use crate::error::{Error, Result}; +use crate::{Error, Result}; -pub struct MixnetClientBuilder { +use super::{connection_state::BuilderState, Config, GatewayKeyMode, Keys, KeysArc, StoragePaths}; + +/// Represents a client that is not yet connected to the mixnet. You typically create one when you +/// want to have a separate configuration and connection phase. Once the mixnet client builder is +/// configured, call [`MixnetClientBuilder::connect_to_mixnet()`] to transition to a connected +/// client. +pub struct MixnetClientBuilder +where + B: ReplyStorageBackend, +{ /// Keys handled by the client key_manager: KeyManager, @@ -45,105 +53,10 @@ pub struct MixnetClientBuilder { reply_storage_backend: B, } -impl MixnetClientBuilder { - /// Create a new mixnet client. If no config options are supplied, creates a new client with - /// ephemeral keys stored in RAM, which will be discarded at application close. - /// - /// Callers have the option of supplying futher parameters to store persistent identities at a - /// location on-disk, if desired. - pub async fn new(config: Option, paths: Option) -> Result { - let config = config.unwrap_or_default(); - - let reply_surb_database_path = paths.as_ref().map(|p| p.reply_surb_database_path.clone()); - - let reply_storage_backend = non_wasm_helpers::setup_fs_reply_surb_backend( - reply_surb_database_path, - &config.debug_config, - ) - .await?; - - MixnetClientBuilder::new_with_custom_storage(Some(config), paths, reply_storage_backend) - } -} - -impl MixnetClientBuilder { - /// Create a new mixnet client. If no config options are supplied, creates a new client with - /// ephemeral keys stored in RAM, which will be discarded at application close. - /// - /// Callers have the option of supplying futher parameters to store persistent identities at a - /// location on-disk, if desired. - pub fn new_without_storage( - config: Option, - paths: Option, - ) -> Result { - let config = config.unwrap_or_default(); - - let reply_storage_backend = - non_wasm_helpers::setup_empty_reply_surb_backend(&config.debug_config); - - MixnetClientBuilder::new_with_custom_storage(Some(config), paths, reply_storage_backend) - } -} - impl MixnetClientBuilder where B: ReplyStorageBackend + Sync + Send + 'static, { - /// Create a new mixnet client. If no config options are supplied, creates a new client with - /// ephemeral keys stored in RAM, which will be discarded at application close. - /// - /// Callers have the option of supplying futher parameters to store persistent identities at a - /// location on-disk, if desired. - /// - /// A custom storage backend can be passed in. - pub fn new_with_custom_storage( - config_option: Option, - paths: Option, - reply_storage_backend: B, - ) -> Result { - let config = config_option.unwrap_or_default(); - - // If we are provided paths to keys, use them if they are available. And if they are - // not, write the generated keys back to storage. - let key_manager = if let Some(ref paths) = paths { - let path_finder = ClientKeyPathfinder::from(paths.clone()); - - // Try load keys - match KeyManager::load_keys_but_gateway_is_optional(&path_finder) { - Ok(key_manager) => key_manager, - Err(err) => { - log::debug!("Not loading keys: {err}"); - if let Some(path) = path_finder.any_file_exists_and_return() { - if paths.operating_mode.is_keep() { - return Err(Error::DontOverwrite(path)); - } - } - - // Double check using a function that has slightly different internal logic. I - // know this is a bit defensive, but I don't want to overwrite - assert!(!(path_finder.any_file_exists() && paths.operating_mode.is_keep())); - - // Create new keys and write to storage - let key_manager = client_core::init::new_client_keys(); - // WARN: this will overwrite! - key_manager.store_keys(&path_finder)?; - key_manager - } - } - } else { - // Ephemeral keys that we only store in memory - client_core::init::new_client_keys() - }; - - Ok(Self { - key_manager, - config, - storage_paths: paths, - state: BuilderState::New, - reply_storage_backend, - }) - } - /// Client keys are generated at client creation if none were found. The gateway shared /// key, however, is created during the gateway registration handshake so it might not /// necessarily be available. @@ -151,6 +64,7 @@ where self.key_manager.is_gateway_key_set() } + /// Sets the keys of this [`MixnetClientBuilder`]. pub fn set_keys(&mut self, keys: Keys) { self.key_manager.set_identity_keypair(keys.identity_keypair); self.key_manager @@ -161,25 +75,35 @@ where .insert_gateway_shared_key(Arc::new(keys.gateway_shared_key)); } + /// Returns the keys of this [`MixnetClientBuilder`]. Client keys are always available since + /// if none are specified at creation time, new random ones are generated. pub fn get_keys(&self) -> KeysArc { KeysArc::from(&self.key_manager) } + /// Sets the gateway endpoint of this [`MixnetClientBuilder`]. pub fn set_gateway_endpoint(&mut self, gateway_endpoint_config: GatewayEndpointConfig) { self.state = BuilderState::Registered { gateway_endpoint_config, } } + /// Returns the get gateway endpoint of this [`MixnetClientBuilder`]. pub fn get_gateway_endpoint(&self) -> Option<&GatewayEndpointConfig> { self.state.gateway_endpoint_config() } + /// Register with a gateway. If a gateway is provided in the config then that will try to be + /// used. If none is specified, a gateway at random will be picked. + /// + /// # Errors + /// + /// This function will return an error if you try to re-register when in an already registered + /// state. pub async fn register_with_gateway(&mut self) -> Result<()> { - assert!( - matches!(self.state, BuilderState::New), - "can only setup gateway when in `New` connection state" - ); + if self.state != BuilderState::New { + return Err(Error::ReregisteringGatewayNotSupported); + } let user_chosen_gateway = self .config @@ -237,7 +161,24 @@ where Ok(()) } - /// Connects to the mixnet via the gateway in the client config + /// Connect the client to the mixnet. + /// + /// - If the client is already registered with a gateway, use that gateway. + /// - If no gateway is registered, but there is an existing configuration and key, use that. + /// - If no gateway is registered, and there is no pre-existing configuration or key, try to + /// register a new gateway. + /// + /// # Example + /// + /// ```no_run + /// use nym_sdk::mixnet; + /// + /// #[tokio::main] + /// async fn main() { + /// let client = mixnet::MixnetClient::builder(None, None).await.unwrap(); + /// let client = client.connect_to_mixnet().await.unwrap(); + /// } + /// ``` pub async fn connect_to_mixnet(mut self) -> Result where ::StorageError: Sync + Send, @@ -269,7 +210,7 @@ where // At this point we should be in a registered state, either at function entry or by the // above convenience logic. let BuilderState::Registered { gateway_endpoint_config } = self.state else { - todo!(); + return Err(Error::FailedToTransitionToRegisteredState); }; let nym_address = @@ -278,7 +219,7 @@ where // TODO: we currently don't support having a bandwidth controller let bandwidth_controller = None; - let base_builder: BaseClientBuilder<_, SigningNyxdClient> = BaseClientBuilder::new( + let base_builder: BaseClientBuilder<'_, _, SigningNyxdClient> = BaseClientBuilder::new( &gateway_endpoint_config, &self.config.debug_config, self.key_manager.clone(), @@ -288,13 +229,13 @@ where self.config.nym_api_endpoints.clone(), ); - let mut started_client = base_builder.start_base().await.unwrap(); + let mut started_client = base_builder.start_base().await?; let client_input = started_client.client_input.register_producer(); let mut client_output = started_client.client_output.register_consumer(); let client_state = started_client.client_state; // Register our receiver - let reconstructed_receiver = client_output.register_receiver().unwrap(); + let reconstructed_receiver = client_output.register_receiver()?; Ok(MixnetClient { nym_address, @@ -308,31 +249,170 @@ where } } +/// Client connected to the Nym mixnet. pub struct MixnetClient { + /// The nym address of this connected client. nym_address: Recipient, /// Keys handled by the client key_manager: KeyManager, + /// Input to the client from the users perspective. This can be either data to send or controll + /// messages. client_input: ClientInput, + /// Output from the client from the users perspective. This is typically messages arriving from + /// the mixnet. #[allow(dead_code)] client_output: ClientOutput, + /// The current state of the client that is exposed to the user. This includes things like + /// current message send queue length. #[allow(dead_code)] client_state: ClientState, + /// A channel for messages arriving from the mixnet after they have been reconstructed. reconstructed_receiver: ReconstructedMessagesReceiver, + /// The task manager that controlls all the spawned tasks that the clients uses to do it's job. task_manager: TaskManager, } impl MixnetClient { + /// Create a new client and connect to the mixnet using ephemeral in-memory keys that are + /// discarded at application close. + /// + /// # Examples + /// + /// ```no_run + /// use nym_sdk::mixnet; + /// + /// #[tokio::main] + /// async fn main() { + /// let mut client = mixnet::MixnetClient::connect().await; + /// } + /// + /// ``` pub async fn connect() -> Result { - let client = MixnetClientBuilder::new_without_storage(None, None)?; + let client = MixnetClient::builder_without_storage(None, None)?; client.connect_to_mixnet().await } + /// Create a new mixnet client builder. If no config options are supplied, creates a new client + /// with ephemeral keys stored in RAM, which will be discarded at application close. + /// + /// Callers have the option of supplying futher parameters to store persistent identities at a + /// location on-disk, if desired. + /// + /// # Examples + /// + /// ```no_run + /// use nym_sdk::mixnet; + /// + /// #[tokio::main] + /// async fn main() { + /// let client = mixnet::MixnetClient::builder(None, None).await; + /// } + /// ``` + pub async fn builder( + config: Option, + paths: Option, + ) -> Result> { + let config = config.unwrap_or_default(); + + let reply_surb_database_path = paths.as_ref().map(|p| p.reply_surb_database_path.clone()); + + let reply_storage_backend = non_wasm_helpers::setup_fs_reply_surb_backend( + reply_surb_database_path, + &config.debug_config, + ) + .await?; + + MixnetClient::builder_with_custom_storage(Some(config), paths, reply_storage_backend) + } + + /// Create a new mixnet client builder. If no config options are supplied, creates a new client with + /// ephemeral keys stored in RAM, which will be discarded at application close. + /// + /// Callers have the option of supplying futher parameters to store persistent identities at a + /// location on-disk, if desired. + /// + /// # Examples + /// + /// ``` + /// use nym_sdk::mixnet; + /// let client = mixnet::MixnetClient::builder_without_storage(None, None); + /// ``` + pub fn builder_without_storage( + config: Option, + paths: Option, + ) -> Result> { + let config = config.unwrap_or_default(); + + let reply_storage_backend = + non_wasm_helpers::setup_empty_reply_surb_backend(&config.debug_config); + + MixnetClient::builder_with_custom_storage(Some(config), paths, reply_storage_backend) + } + + /// Create a new mixnet client builder. If no config options are supplied, creates a new client with + /// ephemeral keys stored in RAM, which will be discarded at application close. + /// + /// Callers have the option of supplying futher parameters to store persistent identities at a + /// location on-disk, if desired. + /// + /// A custom storage backend can be passed in. + pub fn builder_with_custom_storage( + config_option: Option, + paths: Option, + reply_storage_backend: B, + ) -> Result> + where + B: ReplyStorageBackend, + { + let config = config_option.unwrap_or_default(); + + // If we are provided paths to keys, use them if they are available. And if they are + // not, write the generated keys back to storage. + let key_manager = if let Some(ref paths) = paths { + let path_finder = ClientKeyPathfinder::from(paths.clone()); + + // Try load keys + match KeyManager::load_keys_but_gateway_is_optional(&path_finder) { + Ok(key_manager) => key_manager, + Err(err) => { + log::debug!("Not loading keys: {err}"); + if let Some(path) = path_finder.any_file_exists_and_return() { + if paths.operating_mode.is_keep() { + return Err(Error::DontOverwrite(path)); + } + } + + // Double check using a function that has slightly different internal logic. I + // know this is a bit defensive, but I don't want to overwrite + assert!(!(path_finder.any_file_exists() && paths.operating_mode.is_keep())); + + // Create new keys and write to storage + let key_manager = client_core::init::new_client_keys(); + // WARN: this will overwrite! + key_manager.store_keys(&path_finder)?; + key_manager + } + } + } else { + // Ephemeral keys that we only store in memory + client_core::init::new_client_keys() + }; + + Ok(MixnetClientBuilder { + key_manager, + config, + storage_paths: paths, + state: BuilderState::New, + reply_storage_backend, + }) + } + /// Get the client identity, which is the public key of the identity key pair. pub fn identity(&self) -> ClientIdentity { *self.key_manager.identity_keypair().public_key() @@ -345,39 +425,59 @@ impl MixnetClient { } /// Sends stringy data to the supplied Nym address - pub async fn send_str(&self, address: &str, message: &str) { + pub async fn send_str(&self, address: Recipient, message: &str) { let message_bytes = message.to_string().into_bytes(); self.send_bytes(address, message_bytes).await; } /// Sends stringy data to the supplied Nym address, and skip sending reply-SURBs - pub async fn send_str_direct(&self, address: &str, message: &str) { + pub async fn send_str_direct(&self, address: Recipient, message: &str) { let message_bytes = message.to_string().into_bytes(); self.send_bytes(address, message_bytes).await; } /// Sends bytes to the supplied Nym address - pub async fn send_bytes(&self, address: &str, message: Vec) { + /// + /// # Example + /// + /// ```no_run + /// use nym_sdk::mixnet; + /// + /// #[tokio::main] + /// async fn main() { + /// let address = "foobar"; + /// let recipient = mixnet::Recipient::try_from_base58_string(address).unwrap(); + /// let mut client = mixnet::MixnetClient::connect().await.unwrap(); + /// client.send_bytes(recipient, "hi".to_owned().into_bytes()).await; + /// } + /// ``` + pub async fn send_bytes(&self, address: Recipient, message: Vec) { let lane = TransmissionLane::General; - let recipient = Recipient::try_from_base58_string(address).unwrap(); - let input_msg = InputMessage::new_anonymous(recipient, message, 20, lane); - self.client_input + let input_msg = InputMessage::new_anonymous(address, message, 20, lane); + if self + .client_input .input_sender .send(input_msg) .await - .unwrap(); + .is_err() + { + log::error!("Failed to send message"); + } } /// Sends bytes to the supplied Nym address, and skip sending reply-SURBs - pub async fn send_bytes_direct(&self, address: &str, message: Vec) { + pub async fn send_bytes_direct(&self, address: Recipient, message: Vec) { let lane = TransmissionLane::General; - let recipient = Recipient::try_from_base58_string(address).unwrap(); - let input_msg = InputMessage::new_regular(recipient, message, lane); - self.client_input + let input_msg = InputMessage::new_regular(address, message, lane); + if self + .client_input .input_sender .send(input_msg) .await - .unwrap(); + .is_err() + { + log::error!("Failed to send message"); + } } /// Wait for messages from the mixnet @@ -385,10 +485,7 @@ impl MixnetClient { self.reconstructed_receiver.next().await } - pub fn wait_for_messages_split(&mut self) -> Option { - todo!(); - } - + /// Provide a callback to execute on incoming messages from the mixnet. pub async fn on_messages(&mut self, fun: F) where F: Fn(ReconstructedMessage), diff --git a/sdk/rust/nym-sdk/src/mixnet/config.rs b/sdk/rust/nym-sdk/src/mixnet/config.rs index 641b1c01a5..b5705cae92 100644 --- a/sdk/rust/nym-sdk/src/mixnet/config.rs +++ b/sdk/rust/nym-sdk/src/mixnet/config.rs @@ -2,6 +2,7 @@ use client_core::config::DebugConfig; use network_defaults::mainnet; use url::Url; +/// Config struct for [`crate::mixnet::MixnetClient`] pub struct Config { /// If the user has explicitly specified a gateway. pub user_chosen_gateway: Option, @@ -26,6 +27,7 @@ impl Default for Config { } impl Config { + /// Creates a new [`Config`]. pub fn new(user_chosen_gateway: Option, nym_api_endpoints: Vec) -> Self { Self { user_chosen_gateway, diff --git a/sdk/rust/nym-sdk/src/mixnet/connection_state.rs b/sdk/rust/nym-sdk/src/mixnet/connection_state.rs index 2988948a60..611184298b 100644 --- a/sdk/rust/nym-sdk/src/mixnet/connection_state.rs +++ b/sdk/rust/nym-sdk/src/mixnet/connection_state.rs @@ -1,6 +1,6 @@ use client_core::config::GatewayEndpointConfig; -#[derive(Debug)] +#[derive(Debug, PartialEq, Eq)] pub(super) enum BuilderState { New, Registered { diff --git a/sdk/rust/nym-sdk/src/mixnet/keys.rs b/sdk/rust/nym-sdk/src/mixnet/keys.rs index 76a3bab39d..5d1a1d8f98 100644 --- a/sdk/rust/nym-sdk/src/mixnet/keys.rs +++ b/sdk/rust/nym-sdk/src/mixnet/keys.rs @@ -5,17 +5,32 @@ use crypto::asymmetric::{encryption, identity}; use gateway_requests::registration::handshake::SharedKeys; use nymsphinx::acknowledgements::AckKey; +/// The set of keys used by the client. Identity, encryption and ack keys are generated at creating +/// unless specified to loaded from storage or somehow explictly specified. The gateway shared key +/// is generated when registering with a gateway. pub struct Keys { + /// The identity key of the client. pub identity_keypair: identity::KeyPair, + /// The encryption key of the client. pub encryption_keypair: encryption::KeyPair, + /// The ack key used by the client. pub ack_key: AckKey, + + /// The gateway shared key that is obtained after registering with a gateway. pub gateway_shared_key: SharedKeys, } +/// The set of keys used by the client, but where each key is stored in an [`std::sync::Arc`] for +/// easy cloning. pub struct KeysArc { + /// The identity key of the client. pub identity_keypair: Arc, + /// The encryption key of the client. pub encryption_keypair: Arc, + /// The ack key used by the client. pub ack_key: Arc, + + /// The gateway shared key that is obtained after registering with a gateway. pub gateway_shared_key: Arc, } diff --git a/sdk/rust/nym-sdk/src/mixnet/paths.rs b/sdk/rust/nym-sdk/src/mixnet/paths.rs index 852da6c9e9..ccf0da2640 100644 --- a/sdk/rust/nym-sdk/src/mixnet/paths.rs +++ b/sdk/rust/nym-sdk/src/mixnet/paths.rs @@ -30,36 +30,46 @@ impl GatewayKeyMode { } } +/// Set of storage paths that the client will use if it is setup to persist keys, credentials, and +/// reply-SURBs. #[derive(Clone, Debug)] pub struct StoragePaths { - // Determines how to handle existing key files found. + /// Determines how to handle existing key files found. pub operating_mode: KeyMode, - // Client identity keys + /// Client private identity key pub private_identity: PathBuf, + /// Client public identity key pub public_identity: PathBuf, - // Client encryption keys + /// Client private encryption key pub private_encryption: PathBuf, + /// Client public encryption key pub public_encryption: PathBuf, - // Key for handling acks + /// Key for handling acks pub ack_key: PathBuf, - // Key setup after authenticating with a gateway + /// Key setup after authenticating with a gateway pub gateway_shared_key: PathBuf, - // The key isn't much use without knowing which entity it refers to. + /// The key isn't much use without knowing which entity it refers to. pub gateway_endpoint_config: PathBuf, - // The database containing credentials + /// The database containing credentials pub credential_database_path: PathBuf, - // The database storing reply surbs in-between sessions + /// The database storing reply surbs in-between sessions pub reply_surb_database_path: PathBuf, } impl StoragePaths { + /// Create a set of storage paths from a given directory. + /// + /// # Errors + /// + /// This function will return an error if it is passed a path to an existing file instead of a + /// directory. pub fn new_from_dir(operating_mode: KeyMode, dir: &Path) -> Result { if dir.is_file() { return Err(Error::ExpectedDirectory(dir.to_owned()));