From 5b715acc4ecf358897870f095ae86691ce4a8eeb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jon=20H=C3=A4ggblad?= Date: Thu, 16 Jun 2022 12:24:19 +0200 Subject: [PATCH 01/16] client: allow rerun init for gateway config (#1353) * socks5: reuse existing gateway configuration instead of failing on init * socks5: rework setting and registering gateway logic * rustfmt * client/native: port same changes here * changelog: add note about re-running init for clients * client-core/config: add with_gateway_endpoint_from_config * clients: pass GatewayEndpoint * clients: add warning note onf force-register-gateway * connect: fix with_gateway_endpoint call --- CHANGELOG.md | 3 + clients/client-core/src/config/mod.rs | 35 ++++--- clients/native/src/commands/init.rs | 120 ++++++++++++++-------- clients/socks5/src/commands/init.rs | 130 ++++++++++++++++-------- clients/socks5/src/commands/run.rs | 10 +- nym-connect/src-tauri/src/config/mod.rs | 6 +- nym-connect/src-tauri/src/menu.rs | 4 +- nym-connect/src-tauri/src/state.rs | 2 +- 8 files changed, 203 insertions(+), 107 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 299156be03..f95ab530f5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ Post 1.0.0 release, the changelog format is based on [Keep a Changelog](https:// ### Added +- socks5 client/websocket client: add `--force-register-gateway` flag, useful when rerunning init ([#1353]) - nym-connect: initial proof-of-concept of a UI around the socks5 client was added - all: added network compilation target to `--help` (or `--version`) commands ([#1256]). - explorer-api: learned how to sum the delegations by owner in a new endpoint. @@ -34,6 +35,7 @@ Post 1.0.0 release, the changelog format is based on [Keep a Changelog](https:// - mixnode, gateway: attempting to determine reconnection backoff to persistently failing mixnode could result in a crash ([#1260]) - mixnode: the mixnode learned how to shutdown gracefully - native & socks5 clients: fail early when clients try to re-init with a different gateway, which is not supported yet ([#1322]) +- native & socks5 clients: rerun init will now reuse previous gateway configuration instead of failing ([#1353]) - validator: fixed local docker-compose setup to work on Apple M1 ([#1329]) - vesting-contract: replaced `checked_sub` with `saturating_sub` to fix the underflow in `get_vesting_tokens` ([#1275]) - wallet: undelegating now uses either the mixnet or vesting contract, or both, depending on how delegations were made @@ -64,6 +66,7 @@ Post 1.0.0 release, the changelog format is based on [Keep a Changelog](https:// [#1324]: https://github.com/nymtech/nym/pull/1324 [#1328]: https://github.com/nymtech/nym/pull/1328 [#1329]: https://github.com/nymtech/nym/pull/1329 +[#1353]: https://github.com/nymtech/nym/pull/1353 ## [nym-wallet-v1.0.5](https://github.com/nymtech/nym/tree/nym-wallet-v1.0.5) (2022-06-14) diff --git a/clients/client-core/src/config/mod.rs b/clients/client-core/src/config/mod.rs index 3d8c7dc3e1..f7b2acf8ac 100644 --- a/clients/client-core/src/config/mod.rs +++ b/clients/client-core/src/config/mod.rs @@ -114,12 +114,8 @@ impl Config { self.client.disabled_credentials_mode = disabled_credentials_mode; } - pub fn with_gateway_endpoint>(&mut self, id: S, owner: S, listener: S) { - self.client.gateway_endpoint = GatewayEndpoint { - gateway_id: id.into(), - gateway_owner: owner.into(), - gateway_listener: listener.into(), - }; + pub fn with_gateway_endpoint(&mut self, gateway_endpoint: GatewayEndpoint) { + self.client.gateway_endpoint = gateway_endpoint; } pub fn with_gateway_id>(&mut self, id: S) { @@ -142,7 +138,7 @@ impl Config { pub fn set_high_default_traffic_volume(&mut self) { self.debug.average_packet_delay = Duration::from_millis(10); - self.debug.loop_cover_traffic_average_delay = Duration::from_millis(2000000); // basically don't really send cover messages + self.debug.loop_cover_traffic_average_delay = Duration::from_millis(2_000_000); // basically don't really send cover messages self.debug.message_sending_average_delay = Duration::from_millis(4); // 250 "real" messages / s } @@ -206,6 +202,10 @@ impl Config { self.client.gateway_endpoint.gateway_listener.clone() } + pub fn get_gateway_endpoint(&self) -> &GatewayEndpoint { + &self.client.gateway_endpoint + } + pub fn get_database_path(&self) -> PathBuf { self.client.database_path.clone() } @@ -272,17 +272,28 @@ impl Default for Config { } } -#[derive(Debug, Default, Deserialize, PartialEq, Serialize)] -struct GatewayEndpoint { +#[derive(Clone, Debug, Default, Deserialize, PartialEq, Serialize)] +pub struct GatewayEndpoint { /// gateway_id specifies ID of the gateway to which the client should send messages. /// If initially omitted, a random gateway will be chosen from the available topology. - gateway_id: String, + pub gateway_id: String, /// Address of the gateway owner to which the client should send messages. - gateway_owner: String, + pub gateway_owner: String, /// Address of the gateway listener to which all client requests should be sent. - gateway_listener: String, + pub gateway_listener: String, +} + +impl From for GatewayEndpoint { + fn from(node: topology::gateway::Node) -> GatewayEndpoint { + let gateway_listener = node.clients_address(); + GatewayEndpoint { + gateway_id: node.identity_key.to_base58_string(), + gateway_owner: node.owner, + gateway_listener, + } + } } #[derive(Debug, Deserialize, PartialEq, Serialize)] diff --git a/clients/native/src/commands/init.rs b/clients/native/src/commands/init.rs index 4810365526..13e487c099 100644 --- a/clients/native/src/commands/init.rs +++ b/clients/native/src/commands/init.rs @@ -42,6 +42,11 @@ pub fn command_args<'a, 'b>() -> clap::App<'a, 'b> { .help("Id of the gateway we are going to connect to.") .takes_value(true) ) + .arg(Arg::with_name("force-register-gateway") + .long("force-register-gateway") + .help("Force register gateway. WARNING: this will overwrite any existing keys for the given id, potentially causing loss of access.") + .takes_value(false) + ) .arg(Arg::with_name("validators") .long("validators") .help("Comma separated list of rest endpoints of the validators") @@ -181,25 +186,68 @@ fn show_address(config: &Config) { println!("\nThe address of this client is: {}", client_recipient); } +async fn set_gateway_config(config: &mut Config, chosen_gateway_id: Option<&str>) -> gateway::Node { + println!("Setting gateway config"); + log::trace!("Chosen gateway: {:?}", chosen_gateway_id); + + // Get the gateway details by querying the validator-api, and using the chosen one if it's + // among the available ones. + let gateway_details = gateway_details( + config.get_base().get_validator_api_endpoints(), + chosen_gateway_id, + ) + .await; + log::trace!("Used gateway: {}", gateway_details); + + config + .get_base_mut() + .with_gateway_endpoint(gateway_details.clone().into()); + gateway_details +} + +async fn register_and_store_gateway_keys(gateway_details: gateway::Node, config: &Config) { + println!("Registering gateway"); + + let mut rng = OsRng; + let mut key_manager = KeyManager::new(&mut rng); + let shared_keys = register_with_gateway(&gateway_details, key_manager.identity_keypair()).await; + key_manager.insert_gateway_shared_key(shared_keys); + + let pathfinder = ClientKeyPathfinder::new_from_config(config.get_base()); + key_manager + .store_keys(&pathfinder) + .expect("Failed to generated keys"); + println!("Saved all generated keys"); +} + pub async fn execute(matches: ArgMatches<'static>) { println!("Initialising client..."); let id = matches.value_of("id").unwrap(); // required for now - let already_init = if Config::default_config_file_path(Some(id)).exists() { - if matches.is_present("gateway") { - panic!("At the moment, gateway information can't be overwritten. If you want to point to a different gateway, client {}'s directory will need to be manually removed", id); - } - println!("Client \"{}\" was already initialised before! Config information will be overwritten (but keys will be kept)!", id); - true - } else { - false - }; + let already_init = Config::default_config_file_path(Some(id)).exists(); + if already_init { + println!( + "Client \"{}\" was already initialised before! \ + Config information will be overwritten (but keys will be kept)!", + id + ); + } + + // Usually you only register with the gateway on the first init, however you can force + // re-registering if wanted. + let should_force_register = matches.is_present("force-register-gateway"); + + // If the client was already initialized, don't generate new keys and don't re-register with + // the gateway (because this would create a new shared key). + // Unless the user really wants to. + let will_register_gateway = !already_init || should_force_register; + + // Attempt to use a user-provided gateway, if possible + let is_gateway_provided = matches.value_of("gateway").is_some(); let mut config = Config::new(id); - let mut rng = OsRng; - // TODO: ideally that should be the last thing that's being done to config. // However, we are later further overriding it with gateway id config = override_config(config, &matches); @@ -207,36 +255,26 @@ pub async fn execute(matches: ArgMatches<'static>) { config.get_base_mut().set_high_default_traffic_volume(); } - // if client was already initialised, don't generate new keys, not re-register with gateway - // (because this would create new shared key) - if !already_init { - // create identity, encryption and ack keys. - let mut key_manager = KeyManager::new(&mut rng); - - let chosen_gateway_id = matches.value_of("gateway"); - log::trace!("Chosen gateway: {:?}", chosen_gateway_id); - - let gateway_details = gateway_details( - config.get_base().get_validator_api_endpoints(), - chosen_gateway_id, - ) - .await; - log::trace!("Used gateway: {}", gateway_details); - let shared_keys = - register_with_gateway(&gateway_details, key_manager.identity_keypair()).await; - - config.get_base_mut().with_gateway_endpoint( - gateway_details.identity_key.to_base58_string(), - gateway_details.owner.clone(), - gateway_details.clients_address(), - ); - key_manager.insert_gateway_shared_key(shared_keys); - - let pathfinder = ClientKeyPathfinder::new_from_config(config.get_base()); - key_manager - .store_keys(&pathfinder) - .expect("Failed to generated keys"); - println!("Saved all generated keys"); + if will_register_gateway { + // Create identity, encryption and ack keys. + let gateway_details = set_gateway_config(&mut config, matches.value_of("gateway")).await; + register_and_store_gateway_keys(gateway_details, &config).await; + } else if is_gateway_provided { + // Just set the config, don't register or create any keys + set_gateway_config(&mut config, matches.value_of("gateway")).await; + } else { + // Read the existing config to reuse the gateway configuration + println!("Not registering gateway, will reuse existing config and keys"); + if let Ok(existing_config) = Config::load_from_file(Some(id)) { + config + .get_base_mut() + .with_gateway_endpoint(existing_config.get_base().get_gateway_endpoint().clone()); + } else { + log::warn!( + "Existing configuration found, but enable to load gateway details. \ + Proceeding anyway." + ); + }; } let config_save_location = config.get_config_file_save_location(); diff --git a/clients/socks5/src/commands/init.rs b/clients/socks5/src/commands/init.rs index 53d3b6ddc1..b4142d50b5 100644 --- a/clients/socks5/src/commands/init.rs +++ b/clients/socks5/src/commands/init.rs @@ -46,6 +46,11 @@ pub fn command_args<'a, 'b>() -> clap::App<'a, 'b> { .help("Id of the gateway we are going to connect to.") .takes_value(true) ) + .arg(Arg::with_name("force-register-gateway") + .long("force-register-gateway") + .help("Force register gateway. WARNING: this will overwrite any existing keys for the given id, potentially causing loss of access.") + .takes_value(false) + ) .arg(Arg::with_name("validators") .long("validators") .help("Comma separated list of rest endpoints of the validators") @@ -121,6 +126,7 @@ pub async fn gateway_details( .expect("The list of validator apis is empty"); let validator_client = validator_client::ApiClient::new(validator_api.clone()); + log::trace!("Fetching list of gateways from: {}", validator_api); let gateways = validator_client.get_cached_gateways().await.unwrap(); let valid_gateways = gateways .into_iter() @@ -183,26 +189,70 @@ pub fn show_address(config: &Config) { println!("\nThe address of this client is: {}", client_recipient); } +async fn set_gateway_config(config: &mut Config, chosen_gateway_id: Option<&str>) -> gateway::Node { + println!("Setting gateway config"); + log::trace!("Chosen gateway: {:?}", chosen_gateway_id); + + // Get the gateway details by querying the validator-api, and using the chosen one if it's + // among the available ones. + let gateway_details = gateway_details( + config.get_base().get_validator_api_endpoints(), + chosen_gateway_id, + ) + .await; + + log::trace!("Used gateway: {}", gateway_details); + + config + .get_base_mut() + .with_gateway_endpoint(gateway_details.clone().into()); + gateway_details +} + +async fn register_and_store_gateway_keys(gateway_details: gateway::Node, config: &Config) { + println!("Registering gateway"); + + let mut rng = OsRng; + let mut key_manager = KeyManager::new(&mut rng); + let shared_keys = register_with_gateway(&gateway_details, key_manager.identity_keypair()).await; + key_manager.insert_gateway_shared_key(shared_keys); + + let pathfinder = ClientKeyPathfinder::new_from_config(config.get_base()); + key_manager + .store_keys(&pathfinder) + .expect("Failed to generated keys"); + println!("Saved all generated keys"); +} + pub async fn execute(matches: ArgMatches<'static>) { println!("Initialising client..."); let id = matches.value_of("id").unwrap(); // required for now let provider_address = matches.value_of("provider").unwrap(); - let already_init = if Config::default_config_file_path(Some(id)).exists() { - if matches.is_present("gateway") { - panic!("At the moment, gateway information can't be overwritten. If you want to point to a different gateway, client {}'s directory will need to be manually removed", id); - } - println!("Socks5 client \"{}\" was already initialised before! Config information will be overwritten (but keys will be kept)!", id); - true - } else { - false - }; + let already_init = Config::default_config_file_path(Some(id)).exists(); + if already_init { + println!( + "SOCKS5 client \"{}\" was already initialised before! \ + Config information will be overwritten (but keys will be kept)!", + id + ); + } + + // Usually you only register with the gateway on the first init, however you can force + // re-registering if wanted. + let should_force_register = matches.is_present("force-register-gateway"); + + // If the client was already initialized, don't generate new keys and don't re-register with + // the gateway (because this would create a new shared key). + // Unless the user really wants to. + let will_register_gateway = !already_init || should_force_register; + + // Attempt to use a user-provided gateway, if possible + let is_gateway_provided = matches.value_of("gateway").is_some(); let mut config = Config::new(id, provider_address); - let mut rng = OsRng; - // TODO: ideally that should be the last thing that's being done to config. // However, we are later further overriding it with gateway id config = override_config(config, &matches); @@ -210,34 +260,26 @@ pub async fn execute(matches: ArgMatches<'static>) { config.get_base_mut().set_high_default_traffic_volume(); } - // if client was already initialised, don't generate new keys, not re-register with gateway - // (because this would create new shared key) - if !already_init { - // create identity, encryption and ack keys. - let mut key_manager = KeyManager::new(&mut rng); - - let chosen_gateway_id = matches.value_of("gateway"); - - let gateway_details = gateway_details( - config.get_base().get_validator_api_endpoints(), - chosen_gateway_id, - ) - .await; - let shared_keys = - register_with_gateway(&gateway_details, key_manager.identity_keypair()).await; - - config.get_base_mut().with_gateway_endpoint( - gateway_details.identity_key.to_base58_string(), - gateway_details.owner.clone(), - gateway_details.clients_address(), - ); - key_manager.insert_gateway_shared_key(shared_keys); - - let pathfinder = ClientKeyPathfinder::new_from_config(config.get_base()); - key_manager - .store_keys(&pathfinder) - .expect("Failed to generated keys"); - println!("Saved all generated keys"); + if will_register_gateway { + // Create identity, encryption and ack keys. + let gateway_details = set_gateway_config(&mut config, matches.value_of("gateway")).await; + register_and_store_gateway_keys(gateway_details, &config).await; + } else if is_gateway_provided { + // Just set the config, don't register or create any keys + set_gateway_config(&mut config, matches.value_of("gateway")).await; + } else { + // Read the existing config to reuse the gateway configuration + println!("Not registering gateway, will reuse existing config and keys"); + if let Ok(existing_config) = Config::load_from_file(Some(id)) { + config + .get_base_mut() + .with_gateway_endpoint(existing_config.get_base().get_gateway_endpoint().clone()); + } else { + log::warn!( + "Existing configuration found, but enable to load gateway details. \ + Proceeding anyway." + ); + }; } let config_save_location = config.get_config_file_save_location(); @@ -245,8 +287,14 @@ pub async fn execute(matches: ArgMatches<'static>) { .save_to_file(None) .expect("Failed to save the config file"); println!("Saved configuration file to {:?}", config_save_location); - println!("Using gateway: {}", config.get_base().get_gateway_id(),); - println!("Client configuration completed.\n\n\n"); + println!("Using gateway: {}", config.get_base().get_gateway_id()); + log::debug!("Gateway id: {}", config.get_base().get_gateway_id()); + log::debug!("Gateway owner: {}", config.get_base().get_gateway_owner()); + log::debug!( + "Gateway listener: {}", + config.get_base().get_gateway_listener() + ); + println!("Client configuration completed."); show_address(&config); } diff --git a/clients/socks5/src/commands/run.rs b/clients/socks5/src/commands/run.rs index 889da7e432..c3080bdf92 100644 --- a/clients/socks5/src/commands/run.rs +++ b/clients/socks5/src/commands/run.rs @@ -34,16 +34,16 @@ pub fn command_args<'a, 'b>() -> clap::App<'a, 'b> { .help("Address of the socks5 provider to send messages to.") .takes_value(true) ) - .arg(Arg::with_name("validators") - .long("validators") - .help("Comma separated list of rest endpoints of the validators") - .takes_value(true), - ) .arg(Arg::with_name("gateway") .long("gateway") .help("Id of the gateway we want to connect to. If overridden, it is user's responsibility to ensure prior registration happened") .takes_value(true) ) + .arg(Arg::with_name("validators") + .long("validators") + .help("Comma separated list of rest endpoints of the validators") + .takes_value(true), + ) .arg(Arg::with_name("port") .short("p") .long("port") diff --git a/nym-connect/src-tauri/src/config/mod.rs b/nym-connect/src-tauri/src/config/mod.rs index fa37e59865..e807bc9515 100644 --- a/nym-connect/src-tauri/src/config/mod.rs +++ b/nym-connect/src-tauri/src/config/mod.rs @@ -56,11 +56,7 @@ pub async fn init_socks5(provider_address: &str, chosen_gateway_id: Option<&str> .await; info!("Setting gateway endpoint"); - config.get_base_mut().with_gateway_endpoint( - gateway_details.identity_key.to_base58_string(), - gateway_details.owner.clone(), - gateway_details.clients_address(), - ); + config.get_base_mut().with_gateway_endpoint(gateway_details.into()); info!("Insert gateway shared key"); key_manager.insert_gateway_shared_key(shared_keys); diff --git a/nym-connect/src-tauri/src/menu.rs b/nym-connect/src-tauri/src/menu.rs index 3eb88f84f6..cb4d0626d1 100644 --- a/nym-connect/src-tauri/src/menu.rs +++ b/nym-connect/src-tauri/src/menu.rs @@ -1,7 +1,7 @@ use crate::window_toggle; use tauri::{ - AppHandle, CustomMenuItem, Menu, - SystemTray, SystemTrayEvent, SystemTrayMenu, SystemTrayMenuItem, Wry, + AppHandle, CustomMenuItem, Menu, SystemTray, SystemTrayEvent, SystemTrayMenu, + SystemTrayMenuItem, Wry, }; #[cfg(target_os = "macos")] use tauri::{CustomMenuItem, MenuItem, Submenu, SystemTray, SystemTrayMenu, SystemTrayMenuItem}; diff --git a/nym-connect/src-tauri/src/state.rs b/nym-connect/src-tauri/src/state.rs index 9a1376378a..6299954aab 100644 --- a/nym-connect/src-tauri/src/state.rs +++ b/nym-connect/src-tauri/src/state.rs @@ -1,6 +1,6 @@ +use futures::channel::mpsc; use futures::SinkExt; use log::info; -use futures::channel::mpsc; use config::NymConfig; #[cfg(not(feature = "coconut"))] From 784f6d0939dac2db519e49f75d6af2abcbf466b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jon=20H=C3=A4ggblad?= Date: Thu, 16 Jun 2022 12:52:23 +0200 Subject: [PATCH 02/16] wallet: dont try archive if file doesnt exist (#1377) --- .../src-tauri/src/wallet_storage/mod.rs | 21 +++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/nym-wallet/src-tauri/src/wallet_storage/mod.rs b/nym-wallet/src-tauri/src/wallet_storage/mod.rs index eed3f0ada1..50d2eae135 100644 --- a/nym-wallet/src-tauri/src/wallet_storage/mod.rs +++ b/nym-wallet/src-tauri/src/wallet_storage/mod.rs @@ -308,10 +308,27 @@ fn _archive_wallet_file(path: &Path) -> Result<(), BackendError> { } pub(crate) fn archive_wallet_file() -> Result<(), BackendError> { - log::info!("Archiving wallet file"); let store_dir = get_storage_directory()?; let filepath = store_dir.join(WALLET_INFO_FILENAME); - _archive_wallet_file(&filepath) + + if filepath.exists() { + if let Some(filepath) = filepath.to_str() { + log::info!("Archiving wallet file: {}", filepath); + } else { + log::info!("Archiving wallet file"); + } + _archive_wallet_file(&filepath) + } else { + if let Some(filepath) = filepath.to_str() { + log::info!( + "Skipping archiving wallet file, as it's not found: {}", + filepath + ); + } else { + log::info!("Skipping archiving wallet file, as it's not found"); + } + Err(BackendError::WalletFileNotFound) + } } /// Remove an account from inside the encrypted login. From 661a1420c1fb39d41374d641aed2a6893c49869b Mon Sep 17 00:00:00 2001 From: Mark Sinclair Date: Thu, 16 Jun 2022 12:12:44 +0100 Subject: [PATCH 03/16] Wallet: add error checking when switching networks and determining admin mode --- nym-wallet/src/context/main.tsx | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/nym-wallet/src/context/main.tsx b/nym-wallet/src/context/main.tsx index 151934f88e..b6fcda2513 100644 --- a/nym-wallet/src/context/main.tsx +++ b/nym-wallet/src/context/main.tsx @@ -143,14 +143,25 @@ export const AppProvider = ({ children }: { children: React.ReactNode }) => { useEffect(() => { let newValue = false; if (network && appEnv?.ADMIN_ADDRESS && clientDetails?.client_address) { - const adminAddressMap = JSON.parse(appEnv.ADMIN_ADDRESS); - const adminAddresses = adminAddressMap[network] || []; - if (adminAddresses.length) { - newValue = adminAddresses.includes(clientDetails?.client_address); + try { + const adminAddressMap = JSON.parse(appEnv.ADMIN_ADDRESS); + const adminAddresses = adminAddressMap[network] || []; + if (adminAddresses.length) { + newValue = adminAddresses.includes(clientDetails?.client_address); + if (newValue) { + Console.log('Wallet is in admin mode: ', { + network, + adminAddress: adminAddressMap[network], + clientAddress: clientDetails?.client_address, + }); + } + } + } catch (e) { + Console.error('Failed to check admin addresses', e); } } setIsAdminAddress(newValue); - }, [appEnv, network]); + }, [appEnv, network, clientDetails?.client_address]); const logIn = async ({ type, value }: { type: TLoginType; value: string }) => { if (value.length === 0) { From b42472486fb6f035cd7bfe0bf802ad6cb679a611 Mon Sep 17 00:00:00 2001 From: Pierre Dommerc Date: Thu, 16 Jun 2022 13:36:30 +0200 Subject: [PATCH 04/16] feat(wallet): add a custom link component to match new design (#1355) * feat(wallet): add custom link component * feat(wallet): uniformize links * feat(wallet): move link component to ts-packages * feat(wallet): post merge fix * ts-packages: build theme first, then react components * Update README.md Co-authored-by: Mark Sinclair --- .../components/Delegation/DelegationList.tsx | 9 ++-- .../components/Delegation/DelegationModal.tsx | 13 ++++-- .../src/components/Delegation/Delegations.tsx | 11 ++--- .../components/Delegation/PendingEvents.tsx | 9 ++-- nym-wallet/src/components/Nav.tsx | 3 ++ nym-wallet/src/pages/balance/balance.tsx | 12 +++--- nym-wallet/src/pages/delegate/index.tsx | 11 +++-- nym-wallet/src/pages/delegation/index.tsx | 12 ++---- .../src/pages/send/SendConfirmation.tsx | 11 +++-- nym-wallet/src/pages/settings/node-stats.tsx | 12 +++--- nym-wallet/src/theme/mui-theme.d.ts | 1 + nym-wallet/src/theme/theme.tsx | 6 +++ package.json | 4 +- ts-packages/mui-theme/src/theme/common.ts | 4 ++ ts-packages/mui-theme/src/theme/theme.ts | 5 +++ ts-packages/react-components/README.md | 6 +++ .../src/components/link/Link.stories.tsx | 26 ++++++++++++ .../src/components/link/Link.tsx | 42 +++++++++++++++++++ 18 files changed, 146 insertions(+), 51 deletions(-) create mode 100644 ts-packages/react-components/src/components/link/Link.stories.tsx create mode 100644 ts-packages/react-components/src/components/link/Link.tsx diff --git a/nym-wallet/src/components/Delegation/DelegationList.tsx b/nym-wallet/src/components/Delegation/DelegationList.tsx index af23a3a5ca..9ba426f20a 100644 --- a/nym-wallet/src/components/Delegation/DelegationList.tsx +++ b/nym-wallet/src/components/Delegation/DelegationList.tsx @@ -3,7 +3,6 @@ import { Box, Chip, CircularProgress, - Link, Table, TableBody, TableCell, @@ -19,6 +18,7 @@ import { visuallyHidden } from '@mui/utils'; import ArrowDropDownIcon from '@mui/icons-material/ArrowDropDown'; import { CopyToClipboard } from '@nymproject/react/clipboard/CopyToClipboard'; import { DelegationWithEverything } from '@nymproject/types'; +import { Link } from '@nymproject/react/link/Link'; import { format, formatDistanceToNow, parseISO } from 'date-fns'; import { styled } from '@mui/material/styles'; import { tableCellClasses } from '@mui/material/TableCell'; @@ -163,11 +163,8 @@ export const DelegationList: React.FC<{ - {item.node_identity.slice(0, 6)}...{item.node_identity.slice(-6)} - + text={`${item.node_identity.slice(0, 6)}...${item.node_identity.slice(-6)}`} + /> {!item.avg_uptime_percent ? '-' : `${item.avg_uptime_percent}%`} diff --git a/nym-wallet/src/components/Delegation/DelegationModal.tsx b/nym-wallet/src/components/Delegation/DelegationModal.tsx index 87627bf115..aec11bcf2a 100644 --- a/nym-wallet/src/components/Delegation/DelegationModal.tsx +++ b/nym-wallet/src/components/Delegation/DelegationModal.tsx @@ -1,5 +1,6 @@ import React from 'react'; -import { Box, Button, CircularProgress, Link, Modal, Stack, Typography } from '@mui/material'; +import { Box, Button, CircularProgress, Modal, Stack, Typography } from '@mui/material'; +import { Link } from '@nymproject/react/link/Link'; import { modalStyle } from '../Modals/styles'; export type ActionType = 'delegate' | 'undelegate' | 'redeem' | 'redeem-all' | 'compound'; @@ -101,9 +102,13 @@ export const DelegationModal: React.FC< theme.palette.text.secondary}> Check the transaction {transactions.length > 1 ? 'hashes' : 'hash'}: {transactions.map((transaction) => ( - - {transaction.hash.slice(0, 6)} - + ))} )} diff --git a/nym-wallet/src/components/Delegation/Delegations.tsx b/nym-wallet/src/components/Delegation/Delegations.tsx index 9958e1b1be..35a35a22a5 100644 --- a/nym-wallet/src/components/Delegation/Delegations.tsx +++ b/nym-wallet/src/components/Delegation/Delegations.tsx @@ -1,6 +1,7 @@ import React from 'react'; -import { Box, Link, Typography } from '@mui/material'; +import { Box, Typography } from '@mui/material'; import { DelegationWithEverything } from '@nymproject/types'; +import { Link } from '@nymproject/react/link/Link'; import { DelegationList } from './DelegationList'; import { DelegationListItemActions } from './DelegationActions'; @@ -18,13 +19,7 @@ export const Delegations: React.FC<{ onItemActionClick={onDelegationItemActionClick} /> - theme.palette.text.primary} - > + Check the{' '} list of mixnodes diff --git a/nym-wallet/src/components/Delegation/PendingEvents.tsx b/nym-wallet/src/components/Delegation/PendingEvents.tsx index c8a7da8ebd..6e9263b03f 100644 --- a/nym-wallet/src/components/Delegation/PendingEvents.tsx +++ b/nym-wallet/src/components/Delegation/PendingEvents.tsx @@ -2,7 +2,6 @@ import React, { FC } from 'react'; import LockOutlinedIcon from '@mui/icons-material/LockOutlined'; import { Box, - Link, Table, TableBody, TableCell, @@ -17,6 +16,7 @@ import { CopyToClipboard } from '@nymproject/react/clipboard/CopyToClipboard'; import { DelegationEvent } from '@nymproject/types'; import { ArrowDropDown } from '@mui/icons-material'; import { visuallyHidden } from '@mui/utils'; +import { Link } from '@nymproject/react/link/Link'; type Order = 'asc' | 'desc'; @@ -138,11 +138,8 @@ export const PendingEvents: FC<{ pendingEvents: DelegationEvent[]; explorerUrl: - {item.node_identity.slice(0, 6)}...{item.node_identity.slice(-6)} - + text={`${item.node_identity.slice(0, 6)}...${item.node_identity.slice(-6)}`} + /> {!item.amount ? '-' : `${item.amount?.amount} ${item.amount?.denom}`} diff --git a/nym-wallet/src/components/Nav.tsx b/nym-wallet/src/components/Nav.tsx index 6afbca3215..d3ab7eef74 100644 --- a/nym-wallet/src/components/Nav.tsx +++ b/nym-wallet/src/components/Nav.tsx @@ -90,6 +90,9 @@ export const Nav = () => { diff --git a/nym-wallet/src/pages/balance/balance.tsx b/nym-wallet/src/pages/balance/balance.tsx index 63dcb3a663..edb025e68a 100644 --- a/nym-wallet/src/pages/balance/balance.tsx +++ b/nym-wallet/src/pages/balance/balance.tsx @@ -1,6 +1,6 @@ import React, { useContext, useEffect } from 'react'; -import { Alert, Button, Grid, Link, Typography } from '@mui/material'; -import { OpenInNew } from '@mui/icons-material'; +import { Alert, Grid, Typography } from '@mui/material'; +import { Link } from '@nymproject/react/link/Link'; import { NymCard, ClientAddress } from '../../components'; import { AppContext, urls } from '../../context/main'; @@ -33,9 +33,11 @@ export const BalanceCard = () => { {network && ( - - - + )} diff --git a/nym-wallet/src/pages/delegate/index.tsx b/nym-wallet/src/pages/delegate/index.tsx index 83893f8aa6..6fbe7dbf63 100644 --- a/nym-wallet/src/pages/delegate/index.tsx +++ b/nym-wallet/src/pages/delegate/index.tsx @@ -1,6 +1,7 @@ import React, { useContext, useState } from 'react'; -import { Alert, AlertTitle, Box, Button, Link, Typography } from '@mui/material'; +import { Alert, AlertTitle, Box, Button, Typography } from '@mui/material'; import { TransactionExecuteResult } from '@nymproject/types'; +import { Link } from '@nymproject/react/link/Link'; import { DelegateForm } from './DelegateForm'; import { NymCard } from '../../components'; import { EnumRequestStatus, RequestStatus } from '../../components/RequestStatus'; @@ -76,9 +77,11 @@ export const Delegate = () => { Checkout the{' '} - - list of mixnodes - {' '} + {' '} for uptime and performances to help make delegation decisions diff --git a/nym-wallet/src/pages/delegation/index.tsx b/nym-wallet/src/pages/delegation/index.tsx index 6c4724c200..5b3b116304 100644 --- a/nym-wallet/src/pages/delegation/index.tsx +++ b/nym-wallet/src/pages/delegation/index.tsx @@ -1,6 +1,7 @@ import React, { FC, useContext, useEffect, useState } from 'react'; -import { Box, Button, Link, Paper, Stack, Typography } from '@mui/material'; +import { Box, Button, Paper, Stack, Typography } from '@mui/material'; import { DelegationWithEverything, MajorCurrencyAmount } from '@nymproject/types'; +import { Link } from '@nymproject/react/link/Link'; import { AppContext, urls } from 'src/context/main'; import { DelegationList } from 'src/components/Delegation/DelegationList'; import { PendingEvents } from 'src/components/Delegation/PendingEvents'; @@ -273,13 +274,8 @@ export const Delegation: FC = () => { href={`${urls(network).networkExplorer}/network-components/mixnodes/`} target="_blank" rel="noreferrer" - underline="hover" - sx={{ color: 'primary.main', textDecorationColor: 'primary.main' }} - > - - Network Explorer - - + text="Network Explorer" + /> diff --git a/nym-wallet/src/pages/send/SendConfirmation.tsx b/nym-wallet/src/pages/send/SendConfirmation.tsx index b6cbdd7b82..6e4c21c35c 100644 --- a/nym-wallet/src/pages/send/SendConfirmation.tsx +++ b/nym-wallet/src/pages/send/SendConfirmation.tsx @@ -1,6 +1,7 @@ import React, { useContext } from 'react'; -import { Box, CircularProgress, Link, Typography } from '@mui/material'; +import { Box, CircularProgress, Typography } from '@mui/material'; import { TransactionDetails as TTransactionDetails } from '@nymproject/types'; +import { Link } from '@nymproject/react/link/Link'; import { SendError } from './SendError'; import { AppContext, urls } from '../../context/main'; import { SuccessReponse } from '../../components'; @@ -38,9 +39,11 @@ export const SendConfirmation = ({ subtitle={ <> Check the transaction hash{' '} - - here - + } caption={ diff --git a/nym-wallet/src/pages/settings/node-stats.tsx b/nym-wallet/src/pages/settings/node-stats.tsx index 38b385dd37..be453054fc 100644 --- a/nym-wallet/src/pages/settings/node-stats.tsx +++ b/nym-wallet/src/pages/settings/node-stats.tsx @@ -1,6 +1,6 @@ import React, { useContext } from 'react'; -import { OpenInNew } from '@mui/icons-material'; -import { Button, Link, Stack, Typography } from '@mui/material'; +import { Stack, Typography } from '@mui/material'; +import { Link } from '@nymproject/react/link/Link'; import { urls, AppContext } from '../../context/main'; export const NodeStats = ({ mixnodeId }: { mixnodeId?: string }) => { @@ -8,9 +8,11 @@ export const NodeStats = ({ mixnodeId }: { mixnodeId?: string }) => { return ( All your node stats are available on the link below - - - + ); }; diff --git a/nym-wallet/src/theme/mui-theme.d.ts b/nym-wallet/src/theme/mui-theme.d.ts index ac63a4dd5c..7c7db30e24 100644 --- a/nym-wallet/src/theme/mui-theme.d.ts +++ b/nym-wallet/src/theme/mui-theme.d.ts @@ -38,6 +38,7 @@ declare module '@mui/material/styles' { dark: string; muted: string; }; + linkHover: string; } interface NymPaletteVariant { diff --git a/nym-wallet/src/theme/theme.tsx b/nym-wallet/src/theme/theme.tsx index 261e51c9de..2f7dee68e3 100644 --- a/nym-wallet/src/theme/theme.tsx +++ b/nym-wallet/src/theme/theme.tsx @@ -30,6 +30,7 @@ const nymPalette: NymPalette = { dark: '#121726', muted: '#7D7D7D', }, + linkHover: '#AF4D36', }; const darkMode: NymPaletteVariant = { @@ -235,6 +236,11 @@ export const getDesignTokens = (mode: PaletteMode): ThemeOptions => { }, }, }, + MuiLink: { + defaultProps: { + underline: 'none', + }, + }, }, palette, }; diff --git a/package.json b/package.json index 9f15639850..55dc2fccea 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,9 @@ "clean": "lerna run clean", "build": "run-s build:types build:packages", "build:types": "lerna run --scope @nymproject/types build --stream", - "build:packages": "lerna run --scope @nymproject/mui-theme --scope @nymproject/react --stream build", + "build:packages": "run-s build:packages:theme build:packages:react", + "build:packages:theme": "lerna run --scope @nymproject/mui-theme build", + "build:packages:react": "lerna run --scope @nymproject/react build", "build:react-example": "lerna run --scope @nymproject/react-webpack-with-theme-example build --stream", "build:playground": "lerna run --scope @nymproject/react storybook:build --stream", "build:ci": "yarn build && run-p build:react-example build:playground && yarn build:ci:collect-artifacts", diff --git a/ts-packages/mui-theme/src/theme/common.ts b/ts-packages/mui-theme/src/theme/common.ts index 810ce7285c..3e7c9b765c 100644 --- a/ts-packages/mui-theme/src/theme/common.ts +++ b/ts-packages/mui-theme/src/theme/common.ts @@ -18,6 +18,8 @@ export interface NymPalette { muted: { onDarkBg: string; }; + + linkHover: string; } /** @@ -79,6 +81,8 @@ export const nymPalette: NymPalette = { muted: { onDarkBg: '#666B77', }, + + linkHover: '#AF4D36', }; // ------------------------------------------------------------------------------------------------------------------- diff --git a/ts-packages/mui-theme/src/theme/theme.ts b/ts-packages/mui-theme/src/theme/theme.ts index 233eeab16c..a12e706e9e 100644 --- a/ts-packages/mui-theme/src/theme/theme.ts +++ b/ts-packages/mui-theme/src/theme/theme.ts @@ -126,6 +126,11 @@ export const getDesignTokens = (mode: PaletteMode): ThemeOptions => { }, }, }, + MuiLink: { + defaultProps: { + underline: 'none', + }, + }, }, palette, }; diff --git a/ts-packages/react-components/README.md b/ts-packages/react-components/README.md index bc2bd7710f..7581c9fc33 100644 --- a/ts-packages/react-components/README.md +++ b/ts-packages/react-components/README.md @@ -50,3 +50,9 @@ This project uses [shared asset files](../../assets/README.md) such as favicons ## Publishing This package is not published to NPM ... yet. + +## TODO + +- ugprade to React 18 +- upgrade Storybook +- upgrade MUI diff --git a/ts-packages/react-components/src/components/link/Link.stories.tsx b/ts-packages/react-components/src/components/link/Link.stories.tsx new file mode 100644 index 0000000000..a1dd2b88ac --- /dev/null +++ b/ts-packages/react-components/src/components/link/Link.stories.tsx @@ -0,0 +1,26 @@ +import * as React from 'react'; +import { ComponentMeta } from '@storybook/react'; +import { Typography } from '@mui/material'; +import { Link as LinkIcon } from '@mui/icons-material'; +import { Link } from './Link'; + +export default { + title: 'Basics/Link', + component: Link, +} as ComponentMeta; + +export const Default = () => ; + +export const NoIcon = () => ; + +export const WithCustomChildren = () => ( + + + +); + +export const InTextExample = () => ( + + You can find the Nym website . + +); diff --git a/ts-packages/react-components/src/components/link/Link.tsx b/ts-packages/react-components/src/components/link/Link.tsx new file mode 100644 index 0000000000..5581715afd --- /dev/null +++ b/ts-packages/react-components/src/components/link/Link.tsx @@ -0,0 +1,42 @@ +import * as React from 'react'; +import { Box, Typography, Link as MUILink, LinkProps as MUILinkProps } from '@mui/material'; +import { OpenInNew } from '@mui/icons-material'; + +export interface LinkProps { + text?: string; + icon?: React.ReactNode; + noIcon?: boolean; +} + +export const Link = (props: MUILinkProps & LinkProps) => { + const { text, icon, underline, noIcon, children } = props; + let typoProps = {}; + if (!noIcon) { + typoProps = { mr: 0.5 }; + } + return ( + theme.palette.nym.linkHover, + }, + }} + underline={underline || 'none'} + > + {children || ( + + {text} + {!noIcon && (icon || )} + + )} + + ); +}; From 13d74200e25735284fc14a0ca930e75807c8805b Mon Sep 17 00:00:00 2001 From: Mark Sinclair Date: Thu, 16 Jun 2022 13:19:51 +0100 Subject: [PATCH 05/16] GitHub Actions: add test workflow --- .github/workflows/wallet-admin-test.yml | 26 +++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 .github/workflows/wallet-admin-test.yml diff --git a/.github/workflows/wallet-admin-test.yml b/.github/workflows/wallet-admin-test.yml new file mode 100644 index 0000000000..ef11fa0e1f --- /dev/null +++ b/.github/workflows/wallet-admin-test.yml @@ -0,0 +1,26 @@ +# This is a basic workflow to help you get started with Actions + +name: CI - test + +# Controls when the workflow will run +on: + # Allows you to run this workflow manually from the Actions tab + workflow_dispatch: + +# A workflow run is made up of one or more jobs that can run sequentially or in parallel +jobs: + # This workflow contains a single job called "build" + build: + # The type of runner that the job will run on + runs-on: ubuntu-latest + + # Steps represent a sequence of tasks that will be executed as part of the job + steps: + # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it + - uses: actions/checkout@v3 + + # Runs a single command using the runners shell + - name: Run a one-line script + env: + ADMIN_ADDRESS: ${{ secrets.WALLET_ADMIN_ADDRESS }} + run: echo $ADMIN_ADDRESS From eaf207b6679dda3f8eb8f24c506765032e5b7a0b Mon Sep 17 00:00:00 2001 From: Mark Sinclair Date: Thu, 16 Jun 2022 13:22:25 +0100 Subject: [PATCH 06/16] GitHub Actions: delete test file --- .github/workflows/wallet-admin-test.yml | 26 ------------------------- 1 file changed, 26 deletions(-) delete mode 100644 .github/workflows/wallet-admin-test.yml diff --git a/.github/workflows/wallet-admin-test.yml b/.github/workflows/wallet-admin-test.yml deleted file mode 100644 index ef11fa0e1f..0000000000 --- a/.github/workflows/wallet-admin-test.yml +++ /dev/null @@ -1,26 +0,0 @@ -# This is a basic workflow to help you get started with Actions - -name: CI - test - -# Controls when the workflow will run -on: - # Allows you to run this workflow manually from the Actions tab - workflow_dispatch: - -# A workflow run is made up of one or more jobs that can run sequentially or in parallel -jobs: - # This workflow contains a single job called "build" - build: - # The type of runner that the job will run on - runs-on: ubuntu-latest - - # Steps represent a sequence of tasks that will be executed as part of the job - steps: - # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it - - uses: actions/checkout@v3 - - # Runs a single command using the runners shell - - name: Run a one-line script - env: - ADMIN_ADDRESS: ${{ secrets.WALLET_ADMIN_ADDRESS }} - run: echo $ADMIN_ADDRESS From 92f154fde5cf3605978a3595506abf8485061446 Mon Sep 17 00:00:00 2001 From: Mark Sinclair Date: Thu, 16 Jun 2022 13:35:07 +0100 Subject: [PATCH 07/16] GitHub Actions: generate wallet `.env` file and add manual trigger for MacOS build --- .../workflows/nym-wallet-publish-macos.yml | 25 ++++++++++++++----- .../workflows/nym-wallet-publish-ubuntu.yml | 6 ++++- .../nym-wallet-publish-windows10.yml | 7 +++++- 3 files changed, 30 insertions(+), 8 deletions(-) diff --git a/.github/workflows/nym-wallet-publish-macos.yml b/.github/workflows/nym-wallet-publish-macos.yml index b5d3b0b277..673a2df6ac 100644 --- a/.github/workflows/nym-wallet-publish-macos.yml +++ b/.github/workflows/nym-wallet-publish-macos.yml @@ -1,5 +1,6 @@ name: Publish Nym Wallet (MacOS) on: + workflow_dispatch: release: types: [created] @@ -55,6 +56,12 @@ jobs: security import $CERTIFICATE_PATH -P "$APPLE_CERTIFICATE_PASSWORD" -A -t cert -f pkcs12 -k $KEYCHAIN_PATH security list-keychain -d user -s $KEYCHAIN_PATH + - name: Create env file + run: | + touch .env + echo ADMIN_ADDRESS=${{ secrets.WALLET_ADMIN_ADDRESS }} >> .env + cat .env + - name: Install app dependencies and build it env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} @@ -66,17 +73,23 @@ jobs: APPLE_PASSWORD: ${{ secrets.APPLE_PASSWORD }} TAURI_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }} TAURI_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }} - ADMIN_ADDRESS: ${{ secrets.WALLET_ADMIN_ADDRESS }} run: yarn && yarn build + - name: Upload Artifact + uses: actions/upload-artifact@v3 + with: + name: nym-wallet.app.tar.gz + path: nym-wallet/target/release/bundle/macos/nym-wallet.app.tar.gz + retention-days: 5 + + - name: Clean up keychain + if: ${{ always() }} + run: | + security delete-keychain $RUNNER_TEMP/app-signing.keychain-db + - name: Upload to release based on tag name uses: softprops/action-gh-release@v1 with: files: | nym-wallet/target/release/bundle/dmg/*.dmg nym-wallet/target/release/bundle/macos/*.app.tar.gz* - - - name: Clean up keychain - if: ${{ always() }} - run: | - security delete-keychain $RUNNER_TEMP/app-signing.keychain-db diff --git a/.github/workflows/nym-wallet-publish-ubuntu.yml b/.github/workflows/nym-wallet-publish-ubuntu.yml index 2d06f8800f..3beaea9dd8 100644 --- a/.github/workflows/nym-wallet-publish-ubuntu.yml +++ b/.github/workflows/nym-wallet-publish-ubuntu.yml @@ -39,12 +39,16 @@ jobs: toolchain: stable - name: Install app dependencies run: yarn + - name: Create env file + run: | + touch .env + echo ADMIN_ADDRESS=${{ secrets.WALLET_ADMIN_ADDRESS }} >> .env + cat .env - name: Build app run: yarn build env: TAURI_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }} TAURI_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }} - ADMIN_ADDRESS: ${{ secrets.WALLET_ADMIN_ADDRESS }} - name: Upload to release based on tag name uses: softprops/action-gh-release@v1 with: diff --git a/.github/workflows/nym-wallet-publish-windows10.yml b/.github/workflows/nym-wallet-publish-windows10.yml index 6ce47457fb..7ade58c372 100644 --- a/.github/workflows/nym-wallet-publish-windows10.yml +++ b/.github/workflows/nym-wallet-publish-windows10.yml @@ -54,6 +54,12 @@ jobs: with: toolchain: stable + - name: Create env file + run: | + touch .env + echo ADMIN_ADDRESS=${{ secrets.WALLET_ADMIN_ADDRESS }} >> .env + cat .env + - name: Install app dependencies run: yarn @@ -65,7 +71,6 @@ jobs: WINDOWS_CERTIFICATE_PASSWORD: ${{ secrets.WINDOWS_CERTIFICATE_PASSWORD }} TAURI_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }} TAURI_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }} - ADMIN_ADDRESS: ${{ secrets.WALLET_ADMIN_ADDRESS }} run: yarn build - name: Upload to release based on tag name From 2689de2334b805d3b526fe00ea4a1828813fc069 Mon Sep 17 00:00:00 2001 From: Mark Sinclair Date: Thu, 16 Jun 2022 13:42:46 +0100 Subject: [PATCH 08/16] GitHub Actions: fix up condition --- .github/workflows/nym-wallet-publish-macos.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/nym-wallet-publish-macos.yml b/.github/workflows/nym-wallet-publish-macos.yml index 673a2df6ac..7a2b586bce 100644 --- a/.github/workflows/nym-wallet-publish-macos.yml +++ b/.github/workflows/nym-wallet-publish-macos.yml @@ -20,7 +20,7 @@ jobs: - uses: actions/checkout@v2 - name: Check the release tag starts with `nym-wallet-` - if: startsWith(github.ref, 'refs/tags/nym-wallet-') == false + if: startsWith(github.ref, 'refs/tags/nym-wallet-') == false && github.event_name !== 'workflow_dispatch' uses: actions/github-script@v3 with: script: | From c926e0e652c3d5e7236894176cc1c0c9be4a8ae8 Mon Sep 17 00:00:00 2001 From: Mark Sinclair Date: Thu, 16 Jun 2022 13:43:54 +0100 Subject: [PATCH 09/16] GitHub Actions: fix syntax error --- .github/workflows/nym-wallet-publish-macos.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/nym-wallet-publish-macos.yml b/.github/workflows/nym-wallet-publish-macos.yml index 7a2b586bce..f55043e1c5 100644 --- a/.github/workflows/nym-wallet-publish-macos.yml +++ b/.github/workflows/nym-wallet-publish-macos.yml @@ -20,7 +20,7 @@ jobs: - uses: actions/checkout@v2 - name: Check the release tag starts with `nym-wallet-` - if: startsWith(github.ref, 'refs/tags/nym-wallet-') == false && github.event_name !== 'workflow_dispatch' + if: startsWith(github.ref, 'refs/tags/nym-wallet-') == false && github.event_name != 'workflow_dispatch' uses: actions/github-script@v3 with: script: | From f8c8b1a85e5a95015b05119a5f5c92b9b113169c Mon Sep 17 00:00:00 2001 From: Mark Sinclair Date: Thu, 16 Jun 2022 14:09:42 +0100 Subject: [PATCH 10/16] GitHub Actions: adjust generating `.env` file and add conditional to release upload --- .github/workflows/nym-wallet-publish-macos.yml | 3 ++- .github/workflows/nym-wallet-publish-ubuntu.yml | 2 +- .github/workflows/nym-wallet-publish-windows10.yml | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/.github/workflows/nym-wallet-publish-macos.yml b/.github/workflows/nym-wallet-publish-macos.yml index f55043e1c5..4fa4cbbb66 100644 --- a/.github/workflows/nym-wallet-publish-macos.yml +++ b/.github/workflows/nym-wallet-publish-macos.yml @@ -59,7 +59,7 @@ jobs: - name: Create env file run: | touch .env - echo ADMIN_ADDRESS=${{ secrets.WALLET_ADMIN_ADDRESS }} >> .env + echo ADMIN_ADDRESS="${{ secrets.WALLET_ADMIN_ADDRESS }}" >> .env cat .env - name: Install app dependencies and build it @@ -89,6 +89,7 @@ jobs: - name: Upload to release based on tag name uses: softprops/action-gh-release@v1 + if: github.event_name == 'release' with: files: | nym-wallet/target/release/bundle/dmg/*.dmg diff --git a/.github/workflows/nym-wallet-publish-ubuntu.yml b/.github/workflows/nym-wallet-publish-ubuntu.yml index 3beaea9dd8..8b1326e781 100644 --- a/.github/workflows/nym-wallet-publish-ubuntu.yml +++ b/.github/workflows/nym-wallet-publish-ubuntu.yml @@ -42,7 +42,7 @@ jobs: - name: Create env file run: | touch .env - echo ADMIN_ADDRESS=${{ secrets.WALLET_ADMIN_ADDRESS }} >> .env + echo ADMIN_ADDRESS="${{ secrets.WALLET_ADMIN_ADDRESS }}" >> .env cat .env - name: Build app run: yarn build diff --git a/.github/workflows/nym-wallet-publish-windows10.yml b/.github/workflows/nym-wallet-publish-windows10.yml index 7ade58c372..ae911a1685 100644 --- a/.github/workflows/nym-wallet-publish-windows10.yml +++ b/.github/workflows/nym-wallet-publish-windows10.yml @@ -57,7 +57,7 @@ jobs: - name: Create env file run: | touch .env - echo ADMIN_ADDRESS=${{ secrets.WALLET_ADMIN_ADDRESS }} >> .env + echo ADMIN_ADDRESS="${{ secrets.WALLET_ADMIN_ADDRESS }}" >> .env cat .env - name: Install app dependencies From c59e8086a624d94aba5e3abb437ed188f6fdee22 Mon Sep 17 00:00:00 2001 From: Mark Sinclair Date: Thu, 16 Jun 2022 14:14:20 +0100 Subject: [PATCH 11/16] GitHub Actions: fix up `.env` file generation --- .github/workflows/nym-wallet-publish-macos.yml | 1 - .github/workflows/nym-wallet-publish-ubuntu.yml | 1 - .github/workflows/nym-wallet-publish-windows10.yml | 1 - 3 files changed, 3 deletions(-) diff --git a/.github/workflows/nym-wallet-publish-macos.yml b/.github/workflows/nym-wallet-publish-macos.yml index 4fa4cbbb66..4ddffca9f5 100644 --- a/.github/workflows/nym-wallet-publish-macos.yml +++ b/.github/workflows/nym-wallet-publish-macos.yml @@ -60,7 +60,6 @@ jobs: run: | touch .env echo ADMIN_ADDRESS="${{ secrets.WALLET_ADMIN_ADDRESS }}" >> .env - cat .env - name: Install app dependencies and build it env: diff --git a/.github/workflows/nym-wallet-publish-ubuntu.yml b/.github/workflows/nym-wallet-publish-ubuntu.yml index 8b1326e781..fab10aa823 100644 --- a/.github/workflows/nym-wallet-publish-ubuntu.yml +++ b/.github/workflows/nym-wallet-publish-ubuntu.yml @@ -43,7 +43,6 @@ jobs: run: | touch .env echo ADMIN_ADDRESS="${{ secrets.WALLET_ADMIN_ADDRESS }}" >> .env - cat .env - name: Build app run: yarn build env: diff --git a/.github/workflows/nym-wallet-publish-windows10.yml b/.github/workflows/nym-wallet-publish-windows10.yml index ae911a1685..0791206fdd 100644 --- a/.github/workflows/nym-wallet-publish-windows10.yml +++ b/.github/workflows/nym-wallet-publish-windows10.yml @@ -58,7 +58,6 @@ jobs: run: | touch .env echo ADMIN_ADDRESS="${{ secrets.WALLET_ADMIN_ADDRESS }}" >> .env - cat .env - name: Install app dependencies run: yarn From 4f46e36aa8ad066683f6af1b35725c590b53ac05 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bogdan-=C8=98tefan=20Neac=C5=9Fu?= Date: Thu, 16 Jun 2022 15:24:31 +0200 Subject: [PATCH 12/16] Feature/gateway direct stats (#1376) * Make gateway mnemonic optional * Remove unnecessary timer struct * Prepare for code reuse * Use trait for stats collector * Put trait definition in common crate * Gateway stats runner * Custom statistics url arg * Build & send stats req to url * Storage support for new stats type * Make gateway stats opt in * Test&clippy fixes * CHANGELOG update --- CHANGELOG.md | 2 + Cargo.lock | 13 +- common/network-defaults/src/all.rs | 6 + common/network-defaults/src/lib.rs | 11 + common/network-defaults/src/mainnet.rs | 1 + common/network-defaults/src/qa.rs | 1 + common/network-defaults/src/sandbox.rs | 1 + common/statistics/Cargo.toml | 12 +- common/statistics/src/api.rs | 18 +- common/statistics/src/collector.rs | 57 +++++ common/statistics/src/error.rs | 3 + common/statistics/src/lib.rs | 20 +- gateway/Cargo.toml | 1 + gateway/src/commands/init.rs | 19 +- gateway/src/commands/mod.rs | 14 ++ gateway/src/commands/run.rs | 11 + gateway/src/config/mod.rs | 28 ++- gateway/src/config/template.rs | 6 + .../node/client_handling/active_clients.rs | 5 + gateway/src/node/mod.rs | 15 ++ gateway/src/node/statistics/collector.rs | 52 ++++ gateway/src/node/statistics/mod.rs | 4 + .../network-requester/Cargo.toml | 5 +- .../network-requester/src/core.rs | 24 +- .../network-requester/src/main.rs | 2 +- .../src/statistics/collector.rs | 215 ++++++++++++++++ .../network-requester/src/statistics/comm.rs | 229 ------------------ .../network-requester/src/statistics/error.rs | 3 + .../network-requester/src/statistics/mod.rs | 6 +- .../network-requester/src/statistics/timer.rs | 40 --- .../network-statistics/Cargo.toml | 2 +- .../20220512120000_mixnet_statistics.sql | 7 + .../network-statistics/src/api/mod.rs | 2 +- .../network-statistics/src/api/routes.rs | 55 ++++- .../network-statistics/src/storage/manager.rs | 51 +++- .../network-statistics/src/storage/mod.rs | 60 +++-- .../network-statistics/src/storage/models.rs | 7 + 37 files changed, 673 insertions(+), 335 deletions(-) create mode 100644 common/statistics/src/collector.rs create mode 100644 gateway/src/node/statistics/collector.rs create mode 100644 gateway/src/node/statistics/mod.rs create mode 100644 service-providers/network-requester/src/statistics/collector.rs delete mode 100644 service-providers/network-requester/src/statistics/comm.rs delete mode 100644 service-providers/network-requester/src/statistics/timer.rs diff --git a/CHANGELOG.md b/CHANGELOG.md index f95ab530f5..34ac4fdd34 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -46,6 +46,7 @@ Post 1.0.0 release, the changelog format is based on [Keep a Changelog](https:// - validator-client: created internal `Coin` type that replaces coins from `cosmrs` and `cosmwasm` for API entrypoints [[#1295]] - all: updated all `cosmwasm`-related dependencies to `1.0.0` and `cw-storage-plus` to `0.13.4` [[#1318]] - network-requester: allow to voluntarily store and send statistical data about the number of bytes the proxied server serves ([#1328]) +- gateway: allow to voluntarily send statistical data about the number of active inboxes served by a gateway ([#1376]) [#1249]: https://github.com/nymtech/nym/pull/1249 [#1256]: https://github.com/nymtech/nym/pull/1256 @@ -67,6 +68,7 @@ Post 1.0.0 release, the changelog format is based on [Keep a Changelog](https:// [#1328]: https://github.com/nymtech/nym/pull/1328 [#1329]: https://github.com/nymtech/nym/pull/1329 [#1353]: https://github.com/nymtech/nym/pull/1353 +[#1376]: https://github.com/nymtech/nym/pull/1376 ## [nym-wallet-v1.0.5](https://github.com/nymtech/nym/tree/nym-wallet-v1.0.5) (2022-06-14) diff --git a/Cargo.lock b/Cargo.lock index 37bb1e7bfd..17fa5b8e7d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3074,6 +3074,7 @@ dependencies = [ "rand 0.7.3", "serde", "sqlx", + "statistics-common", "subtle-encoding", "thiserror", "tokio", @@ -3130,6 +3131,7 @@ dependencies = [ name = "nym-network-requester" version = "1.0.1" dependencies = [ + "async-trait", "clap 2.34.0", "dirs", "futures", @@ -3146,7 +3148,7 @@ dependencies = [ "serde", "socks5-requests", "sqlx", - "statistics", + "statistics-common", "thiserror", "tokio", "tokio-tungstenite", @@ -3163,7 +3165,7 @@ dependencies = [ "rocket", "serde", "sqlx", - "statistics", + "statistics-common", "thiserror", "tokio", "tokio-tungstenite", @@ -5365,13 +5367,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" [[package]] -name = "statistics" +name = "statistics-common" version = "1.0.1" dependencies = [ + "async-trait", + "log", + "network-defaults", "reqwest", "serde", "serde_json", + "sqlx", "thiserror", + "tokio", ] [[package]] diff --git a/common/network-defaults/src/all.rs b/common/network-defaults/src/all.rs index bdc62fe952..e54d65a92a 100644 --- a/common/network-defaults/src/all.rs +++ b/common/network-defaults/src/all.rs @@ -64,6 +64,10 @@ impl Network { self.details().rewarding_validator_address } + pub fn statistics_service_url(&self) -> &str { + self.details().statistics_service_url + } + pub fn validators(&self) -> impl Iterator { self.details().validators.iter() } @@ -101,6 +105,7 @@ pub struct NetworkDetails { mixnet_contract_address: String, vesting_contract_address: String, bandwidth_claim_contract_address: String, + statistics_service_url: String, validators: Vec, } @@ -112,6 +117,7 @@ impl From<&DefaultNetworkDetails<'_>> for NetworkDetails { mixnet_contract_address: details.mixnet_contract_address.into(), vesting_contract_address: details.vesting_contract_address.into(), bandwidth_claim_contract_address: details.bandwidth_claim_contract_address.into(), + statistics_service_url: details.statistics_service_url.into(), validators: details.validators.clone(), } } diff --git a/common/network-defaults/src/lib.rs b/common/network-defaults/src/lib.rs index 66c8621843..1b0cfa9518 100644 --- a/common/network-defaults/src/lib.rs +++ b/common/network-defaults/src/lib.rs @@ -54,6 +54,7 @@ pub struct DefaultNetworkDetails<'a> { coconut_bandwidth_contract_address: &'a str, multisig_contract_address: &'a str, rewarding_validator_address: &'a str, + statistics_service_url: &'a str, validators: Vec, } @@ -67,6 +68,7 @@ static MAINNET_DEFAULTS: Lazy> = coconut_bandwidth_contract_address: mainnet::COCONUT_BANDWIDTH_CONTRACT_ADDRESS, multisig_contract_address: mainnet::MULTISIG_CONTRACT_ADDRESS, rewarding_validator_address: mainnet::REWARDING_VALIDATOR_ADDRESS, + statistics_service_url: mainnet::STATISTICS_SERVICE_DOMAIN_ADDRESS, validators: mainnet::validators(), }); @@ -80,6 +82,7 @@ static SANDBOX_DEFAULTS: Lazy> = coconut_bandwidth_contract_address: sandbox::COCONUT_BANDWIDTH_CONTRACT_ADDRESS, multisig_contract_address: sandbox::MULTISIG_CONTRACT_ADDRESS, rewarding_validator_address: sandbox::REWARDING_VALIDATOR_ADDRESS, + statistics_service_url: sandbox::STATISTICS_SERVICE_DOMAIN_ADDRESS, validators: sandbox::validators(), }); @@ -92,6 +95,7 @@ static QA_DEFAULTS: Lazy> = Lazy::new(|| DefaultN coconut_bandwidth_contract_address: qa::COCONUT_BANDWIDTH_CONTRACT_ADDRESS, multisig_contract_address: qa::MULTISIG_CONTRACT_ADDRESS, rewarding_validator_address: qa::REWARDING_VALIDATOR_ADDRESS, + statistics_service_url: qa::STATISTICS_SERVICE_DOMAIN_ADDRESS, validators: qa::validators(), }); @@ -132,6 +136,13 @@ impl ValidatorDetails { } } +pub fn default_statistics_service_url() -> Url { + DEFAULT_NETWORK + .statistics_service_url() + .parse() + .expect("the provided statistics service url is invalid!") +} + pub fn default_nymd_endpoints() -> Vec { DEFAULT_NETWORK .validators() diff --git a/common/network-defaults/src/mainnet.rs b/common/network-defaults/src/mainnet.rs index 0e9f16eb05..f6757fff61 100644 --- a/common/network-defaults/src/mainnet.rs +++ b/common/network-defaults/src/mainnet.rs @@ -22,6 +22,7 @@ pub(crate) const _ETH_ERC20_CONTRACT_ADDRESS: [u8; 20] = hex_literal::hex!("0000000000000000000000000000000000000000"); pub(crate) const REWARDING_VALIDATOR_ADDRESS: &str = "n10yyd98e2tuwu0f7ypz9dy3hhjw7v772q6287gy"; +pub(crate) const STATISTICS_SERVICE_DOMAIN_ADDRESS: &str = "http://127.0.0.1:8090"; pub(crate) fn validators() -> Vec { vec![ValidatorDetails::new( "https://rpc.nyx.nodes.guru/", diff --git a/common/network-defaults/src/qa.rs b/common/network-defaults/src/qa.rs index c782e089ab..db16286da7 100644 --- a/common/network-defaults/src/qa.rs +++ b/common/network-defaults/src/qa.rs @@ -22,6 +22,7 @@ pub(crate) const _ETH_ERC20_CONTRACT_ADDRESS: [u8; 20] = hex_literal::hex!("0000000000000000000000000000000000000000"); pub(crate) const REWARDING_VALIDATOR_ADDRESS: &str = "n1tfzd4qz3a45u8p4mr5zmzv66457uwjgcl05jdq"; +pub(crate) const STATISTICS_SERVICE_DOMAIN_ADDRESS: &str = ""; pub(crate) fn validators() -> Vec { vec![ValidatorDetails::new( "https://qa-validator.nymtech.net", diff --git a/common/network-defaults/src/sandbox.rs b/common/network-defaults/src/sandbox.rs index a6cfc39514..4a23f7747b 100644 --- a/common/network-defaults/src/sandbox.rs +++ b/common/network-defaults/src/sandbox.rs @@ -20,6 +20,7 @@ pub(crate) const _ETH_ERC20_CONTRACT_ADDRESS: [u8; 20] = hex_literal::hex!("E8883BAeF3869e14E4823F46662e81D4F7d2A81F"); pub(crate) const REWARDING_VALIDATOR_ADDRESS: &str = "nymt1jh0s6qu6tuw9ut438836mmn7f3f2wencrnmdj4"; +pub(crate) const STATISTICS_SERVICE_DOMAIN_ADDRESS: &str = ""; pub(crate) fn validators() -> Vec { vec![ValidatorDetails::new( "https://sandbox-validator.nymtech.net", diff --git a/common/statistics/Cargo.toml b/common/statistics/Cargo.toml index efed3428a5..2bee2c1c39 100644 --- a/common/statistics/Cargo.toml +++ b/common/statistics/Cargo.toml @@ -2,14 +2,20 @@ # SPDX-License-Identifier: Apache-2.0 [package] -name = "statistics" +name = "statistics-common" version = "1.0.1" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -reqwest = "0.11" +async-trait = { version = "0.1.51" } +log = "0.4" +reqwest = { version = "0.11", features = ["json"] } serde = { version = "1.0", features = ["derive"] } serde_json = "1" -thiserror = "1" \ No newline at end of file +sqlx = { version = "0.5", features = ["runtime-tokio-rustls", "chrono"]} +thiserror = "1" +tokio = { version = "1.19.1", features = [ "time" ] } + +network-defaults = { path = "../network-defaults" } \ No newline at end of file diff --git a/common/statistics/src/api.rs b/common/statistics/src/api.rs index 6b9139adba..6f43436432 100644 --- a/common/statistics/src/api.rs +++ b/common/statistics/src/api.rs @@ -10,13 +10,29 @@ pub const DEFAULT_STATISTICS_SERVICE_PORT: u16 = 8090; pub const STATISTICS_SERVICE_VERSION: &str = "/v1"; pub const STATISTICS_SERVICE_API_STATISTICS: &str = "statistic"; +pub async fn build_and_send_statistics_request( + msg: StatsMessage, + url: String, +) -> Result<(), StatsError> { + reqwest::Client::new() + .post(format!( + "{}{}/{}", + url, STATISTICS_SERVICE_VERSION, STATISTICS_SERVICE_API_STATISTICS + )) + .json(&msg) + .send() + .await?; + + Ok(()) +} + pub fn build_statistics_request_bytes(msg: StatsMessage) -> Result, StatsError> { let json_msg = msg.to_json()?; let req = reqwest::Request::new( reqwest::Method::POST, reqwest::Url::parse(&format!( - "http://{}:{}/{}/{}", + "http://{}:{}{}/{}", DEFAULT_STATISTICS_SERVICE_ADDRESS, DEFAULT_STATISTICS_SERVICE_PORT, STATISTICS_SERVICE_VERSION, diff --git a/common/statistics/src/collector.rs b/common/statistics/src/collector.rs new file mode 100644 index 0000000000..ee418a2028 --- /dev/null +++ b/common/statistics/src/collector.rs @@ -0,0 +1,57 @@ +// Copyright 2022 - Nym Technologies SA +// SPDX-License-Identifier: Apache-2.0 + +use async_trait::async_trait; +use log::error; +use sqlx::types::chrono::{DateTime, Utc}; +use std::time::Duration; +use tokio::time; + +use crate::error::StatsError; +use crate::StatsMessage; + +const STATISTICS_TIMER_INTERVAL: Duration = Duration::from_secs(60); + +#[async_trait] +pub trait StatisticsCollector { + async fn create_stats_message( + &self, + interval: Duration, + timestamp: DateTime, + ) -> StatsMessage; + async fn send_stats_message(&self, stats_message: StatsMessage) -> Result<(), StatsError>; + async fn reset_stats(&mut self); +} + +pub struct StatisticsSender { + collector: T, + interval: Duration, + timestamp: DateTime, +} + +impl StatisticsSender { + pub fn new(collector: T) -> Self { + StatisticsSender { + collector, + interval: STATISTICS_TIMER_INTERVAL, + timestamp: Utc::now(), + } + } + + pub async fn run(&mut self) { + let mut interval = time::interval(self.interval); + loop { + interval.tick().await; + + let stats_message = self + .collector + .create_stats_message(self.interval, self.timestamp) + .await; + if let Err(e) = self.collector.send_stats_message(stats_message).await { + error!("Statistics not sent: {}", e); + } + self.collector.reset_stats().await; + self.timestamp = Utc::now(); + } + } +} diff --git a/common/statistics/src/error.rs b/common/statistics/src/error.rs index 1c25807d98..e152c79f81 100644 --- a/common/statistics/src/error.rs +++ b/common/statistics/src/error.rs @@ -7,4 +7,7 @@ use thiserror::Error; pub enum StatsError { #[error("Serde JSON error: {0}")] SerdeJsonError(#[from] serde_json::Error), + + #[error("Reqwest error: {0}")] + ReqwestError(#[from] reqwest::Error), } diff --git a/common/statistics/src/lib.rs b/common/statistics/src/lib.rs index 267ccafb83..9e107fc119 100644 --- a/common/statistics/src/lib.rs +++ b/common/statistics/src/lib.rs @@ -6,11 +6,12 @@ use serde::{Deserialize, Serialize}; use error::StatsError; pub mod api; +pub mod collector; pub mod error; #[derive(Clone, Debug, Deserialize, Serialize)] pub struct StatsMessage { - pub stats_data: Vec, + pub stats_data: Vec, pub interval_seconds: u32, pub timestamp: String, } @@ -25,6 +26,23 @@ impl StatsMessage { } } +#[derive(Clone, Debug, Deserialize, Serialize)] +pub enum StatsData { + Service(StatsServiceData), + Gateway(StatsGatewayData), +} + +#[derive(Clone, Debug, Deserialize, Serialize)] +pub struct StatsGatewayData { + pub inbox_count: u32, +} + +impl StatsGatewayData { + pub fn new(inbox_count: u32) -> Self { + StatsGatewayData { inbox_count } + } +} + #[derive(Clone, Debug, Deserialize, Serialize)] pub struct StatsServiceData { pub requested_service: String, diff --git a/gateway/Cargo.toml b/gateway/Cargo.toml index e3ab0f4722..2d0205002b 100644 --- a/gateway/Cargo.toml +++ b/gateway/Cargo.toml @@ -51,6 +51,7 @@ mixnode-common = { path = "../common/mixnode-common" } network-defaults = { path = "../common/network-defaults" } nymsphinx = { path = "../common/nymsphinx" } pemstore = { path = "../common/pemstore" } +statistics-common = { path = "../common/statistics" } validator-client = { path = "../common/client-libs/validator-client", features = ["nymd-client"] } version-checker = { path = "../common/version-checker" } diff --git a/gateway/src/commands/init.rs b/gateway/src/commands/init.rs index 5f3dd1693c..76966ca9f3 100644 --- a/gateway/src/commands/init.rs +++ b/gateway/src/commands/init.rs @@ -45,7 +45,7 @@ pub struct Init { /// Cosmos wallet mnemonic needed for double spending protection #[clap(long)] - mnemonic: String, + mnemonic: Option, /// Set this gateway to work in a enabled credentials mode that would disallow clients to bypass bandwidth credential requirement #[cfg(all(feature = "eth", not(feature = "coconut")))] @@ -57,6 +57,14 @@ pub struct Init { #[clap(long)] eth_endpoint: String, + /// Enable/disable gateway anonymized statistics that get sent to a statistics aggregator server + #[clap(long)] + enabled_statistics: Option, + + /// URL where a statistics aggregator is running. The default value is a Nym aggregator server + #[clap(long)] + statistics_service_url: Option, + /// Comma separated list of endpoints of the validator #[cfg(all(feature = "eth", not(feature = "coconut")))] #[clap(long)] @@ -73,7 +81,7 @@ impl From for OverrideConfig { datastore: init_config.datastore, announce_host: init_config.announce_host, validator_apis: init_config.validator_apis, - mnemonic: Some(init_config.mnemonic), + mnemonic: init_config.mnemonic, #[cfg(all(feature = "eth", not(feature = "coconut")))] enabled_credentials_mode: init_config.enabled_credentials_mode, @@ -81,6 +89,9 @@ impl From for OverrideConfig { #[cfg(all(feature = "eth", not(feature = "coconut")))] eth_endpoint: Some(init_config.eth_endpoint), + enabled_statistics: init_config.enabled_statistics, + statistics_service_url: init_config.statistics_service_url, + #[cfg(all(feature = "eth", not(feature = "coconut")))] validators: init_config.validators, } @@ -163,7 +174,9 @@ mod tests { announce_host: Some("foo-announce-host".to_string()), datastore: Some("foo-datastore".to_string()), validator_apis: None, - mnemonic: "a b c".to_string(), + mnemonic: Some("a b c".to_string()), + statistics_service_url: None, + enabled_statistics: None, }; let config = Config::new(&args.id); diff --git a/gateway/src/commands/mod.rs b/gateway/src/commands/mod.rs index 680636d9b6..30ecf79dc8 100644 --- a/gateway/src/commands/mod.rs +++ b/gateway/src/commands/mod.rs @@ -46,6 +46,8 @@ pub(crate) struct OverrideConfig { clients_port: Option, datastore: Option, announce_host: Option, + enabled_statistics: Option, + statistics_service_url: Option, validator_apis: Option, mnemonic: Option, @@ -102,6 +104,18 @@ pub(crate) fn override_config(mut config: Config, args: OverrideConfig) -> Confi config = config.announce_host_from_listening_host(); } + if let Some(enabled_statistics) = args.enabled_statistics { + config = config.with_enabled_statistics(enabled_statistics); + } + + if let Some(raw_url) = args.statistics_service_url { + config = config.with_custom_statistics_service_url( + raw_url + .parse() + .expect("the provided statistics service url is invalid!"), + ); + } + if let Some(raw_validators) = args.validator_apis { config = config.with_custom_validator_apis(parse_validators(&raw_validators)); } diff --git a/gateway/src/commands/run.rs b/gateway/src/commands/run.rs index 708c9a9ec1..96cfc0c5b9 100644 --- a/gateway/src/commands/run.rs +++ b/gateway/src/commands/run.rs @@ -57,6 +57,14 @@ pub struct Run { #[clap(long)] eth_endpoint: Option, + /// Enable/disable gateway anonymized statistics that get sent to a statistics aggregator server + #[clap(long)] + enabled_statistics: Option, + + /// URL where a statistics aggregator is running. The default value is a Nym aggregator server + #[clap(long)] + statistics_service_url: Option, + /// Comma separated list of endpoints of the validator #[cfg(all(feature = "eth", not(feature = "coconut")))] #[clap(long)] @@ -81,6 +89,9 @@ impl From for OverrideConfig { #[cfg(all(feature = "eth", not(feature = "coconut")))] eth_endpoint: run_config.eth_endpoint, + enabled_statistics: run_config.enabled_statistics, + statistics_service_url: run_config.statistics_service_url, + #[cfg(all(feature = "eth", not(feature = "coconut")))] validators: run_config.validators, } diff --git a/gateway/src/config/mod.rs b/gateway/src/config/mod.rs index e7214ca5ba..f16c1c124f 100644 --- a/gateway/src/config/mod.rs +++ b/gateway/src/config/mod.rs @@ -127,6 +127,16 @@ impl Config { self } + pub fn with_enabled_statistics(mut self, enabled_statistics: bool) -> Self { + self.gateway.enabled_statistics = enabled_statistics; + self + } + + pub fn with_custom_statistics_service_url(mut self, statistics_service_url: Url) -> Self { + self.gateway.statistics_service_url = statistics_service_url; + self + } + pub fn with_custom_validator_apis(mut self, validator_api_urls: Vec) -> Self { self.gateway.validator_api_urls = validator_api_urls; self @@ -227,6 +237,14 @@ impl Config { self.gateway.eth_endpoint.clone() } + pub fn get_enabled_statistics(&self) -> bool { + self.gateway.enabled_statistics + } + + pub fn get_statistics_service_url(&self) -> Url { + self.gateway.statistics_service_url.clone() + } + pub fn get_validator_api_endpoints(&self) -> Vec { self.gateway.validator_api_urls.clone() } @@ -339,6 +357,12 @@ pub struct Gateway { #[cfg(not(feature = "coconut"))] eth_endpoint: String, + /// Wheather gateway collects and sends anonymized statistics + enabled_statistics: bool, + + /// Domain address of the statistics service + statistics_service_url: Url, + /// Addresses to APIs running on validator from which the node gets the view of the network. validator_api_urls: Vec, @@ -399,10 +423,12 @@ impl Default for Gateway { public_sphinx_key_file: Default::default(), #[cfg(not(feature = "coconut"))] eth_endpoint: "".to_string(), + enabled_statistics: false, + statistics_service_url: default_statistics_service_url(), validator_api_urls: default_api_endpoints(), #[cfg(not(feature = "coconut"))] validator_nymd_urls: default_nymd_endpoints(), - cosmos_mnemonic: "".to_string(), + cosmos_mnemonic: "exact antique hybrid width raise anchor puzzle degree fee quit long crack net vague hip despair write put useless civil mechanic broom music day".to_string(), nym_root_directory: Config::default_root_directory(), persistent_storage: Default::default(), wallet_address: "nymXXXXXXXX".to_string(), diff --git a/gateway/src/config/template.rs b/gateway/src/config/template.rs index 64aeaf646d..423f50fc7a 100644 --- a/gateway/src/config/template.rs +++ b/gateway/src/config/template.rs @@ -56,6 +56,12 @@ mix_port = {{ gateway.mix_port }} # (default: 9000) clients_port = {{ gateway.clients_port }} +# Wheather gateway collects and sends anonymized statistics +enabled_statistics = {{ gateway.enabled_statistics }} + +# Domain address of the statistics service +statistics_service_url = '{{ gateway.statistics_service_url }}' + # Addresses to APIs running on validator from which the node gets the view of the network. validator_api_urls = [ {{#each gateway.validator_api_urls }} diff --git a/gateway/src/node/client_handling/active_clients.rs b/gateway/src/node/client_handling/active_clients.rs index 95ca62b576..7eeefd2a65 100644 --- a/gateway/src/node/client_handling/active_clients.rs +++ b/gateway/src/node/client_handling/active_clients.rs @@ -55,4 +55,9 @@ impl ActiveClientsStore { pub(crate) fn insert(&self, client: DestinationAddressBytes, handle: MixMessageSender) { self.0.insert(client, handle); } + + /// Get number of active clients in store + pub(crate) fn size(&self) -> usize { + self.0.len() + } } diff --git a/gateway/src/node/mod.rs b/gateway/src/node/mod.rs index 5b33bdb319..8b5f512630 100644 --- a/gateway/src/node/mod.rs +++ b/gateway/src/node/mod.rs @@ -7,12 +7,14 @@ use crate::config::Config; use crate::node::client_handling::active_clients::ActiveClientsStore; use crate::node::client_handling::websocket; use crate::node::mixnet_handling::receiver::connection_handler::ConnectionHandler; +use crate::node::statistics::collector::GatewayStatisticsCollector; use crate::node::storage::Storage; use crypto::asymmetric::{encryption, identity}; use log::*; use mixnet_client::forwarder::{MixForwardingSender, PacketForwarder}; use rand::seq::SliceRandom; use rand::thread_rng; +use statistics_common::collector::StatisticsSender; use std::net::SocketAddr; use std::process; use std::sync::Arc; @@ -29,6 +31,7 @@ use self::storage::PersistentStorage; pub(crate) mod client_handling; pub(crate) mod mixnet_handling; +pub(crate) mod statistics; pub(crate) mod storage; /// Wire up and create Gateway instance @@ -304,6 +307,18 @@ where active_clients_store.clone(), ); + if self.config.get_enabled_statistics() { + let statistics_service_url = self.config.get_statistics_service_url(); + let stats_collector = GatewayStatisticsCollector::new( + active_clients_store.clone(), + statistics_service_url, + ); + let mut stats_sender = StatisticsSender::new(stats_collector); + tokio::spawn(async move { + stats_sender.run().await; + }); + } + self.start_client_websocket_listener( mix_forwarding_channel, active_clients_store, diff --git a/gateway/src/node/statistics/collector.rs b/gateway/src/node/statistics/collector.rs new file mode 100644 index 0000000000..18f290d006 --- /dev/null +++ b/gateway/src/node/statistics/collector.rs @@ -0,0 +1,52 @@ +// Copyright 2022 - Nym Technologies SA +// SPDX-License-Identifier: Apache-2.0 + +use async_trait::async_trait; +use sqlx::types::chrono::{DateTime, Utc}; +use std::time::Duration; +use url::Url; + +use statistics_common::{ + api::build_and_send_statistics_request, collector::StatisticsCollector, error::StatsError, + StatsData, StatsGatewayData, StatsMessage, +}; + +use crate::node::client_handling::active_clients::ActiveClientsStore; + +pub(crate) struct GatewayStatisticsCollector { + active_clients_store: ActiveClientsStore, + statistics_service_url: Url, +} + +impl GatewayStatisticsCollector { + pub fn new(active_clients_store: ActiveClientsStore, statistics_service_url: Url) -> Self { + GatewayStatisticsCollector { + active_clients_store, + statistics_service_url, + } + } +} + +#[async_trait] +impl StatisticsCollector for GatewayStatisticsCollector { + async fn create_stats_message( + &self, + interval: Duration, + timestamp: DateTime, + ) -> StatsMessage { + let inbox_count = self.active_clients_store.size() as u32; + let stats_data = vec![StatsData::Gateway(StatsGatewayData { inbox_count })]; + StatsMessage { + stats_data, + interval_seconds: interval.as_secs() as u32, + timestamp: timestamp.to_rfc3339(), + } + } + + async fn send_stats_message(&self, stats_message: StatsMessage) -> Result<(), StatsError> { + build_and_send_statistics_request(stats_message, self.statistics_service_url.to_string()) + .await + } + + async fn reset_stats(&mut self) {} +} diff --git a/gateway/src/node/statistics/mod.rs b/gateway/src/node/statistics/mod.rs new file mode 100644 index 0000000000..3248ece682 --- /dev/null +++ b/gateway/src/node/statistics/mod.rs @@ -0,0 +1,4 @@ +// Copyright 2022 - Nym Technologies SA +// SPDX-License-Identifier: Apache-2.0 + +pub mod collector; diff --git a/service-providers/network-requester/Cargo.toml b/service-providers/network-requester/Cargo.toml index b4825bb782..11ff1285aa 100644 --- a/service-providers/network-requester/Cargo.toml +++ b/service-providers/network-requester/Cargo.toml @@ -10,6 +10,7 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +async-trait = { version = "0.1.51" } clap = "2.33.0" dirs = "3.0" futures = "0.3" @@ -22,7 +23,7 @@ reqwest = { version = "0.11", features = ["json"] } serde = { version = "1.0", features = ["derive"] } sqlx = { version = "0.5", features = ["runtime-tokio-rustls", "chrono"]} thiserror = "1" -tokio = { version = "1.19.1", features = [ "net", "rt-multi-thread", "macros", "time" ] } +tokio = { version = "1.19.1", features = [ "net", "rt-multi-thread", "macros" ] } tokio-tungstenite = "0.14" @@ -32,5 +33,5 @@ nymsphinx = { path = "../../common/nymsphinx" } ordered-buffer = {path = "../../common/socks5/ordered-buffer"} proxy-helpers = { path = "../../common/socks5/proxy-helpers" } socks5-requests = { path = "../../common/socks5/requests" } -statistics = { path = "../../common/statistics" } +statistics-common = { path = "../../common/statistics" } websocket-requests = { path = "../../clients/native/websocket-requests" } diff --git a/service-providers/network-requester/src/core.rs b/service-providers/network-requester/src/core.rs index 74fd2fb509..9f1e6e8bff 100644 --- a/service-providers/network-requester/src/core.rs +++ b/service-providers/network-requester/src/core.rs @@ -3,7 +3,7 @@ use crate::allowed_hosts::{HostsStore, OutboundRequestFilter}; use crate::connection::Connection; -use crate::statistics::{StatisticsCollector, StatisticsSender, Timer}; +use crate::statistics::ServiceStatisticsCollector; use crate::websocket; use crate::websocket::TSWebsocketStream; use futures::channel::mpsc; @@ -14,6 +14,7 @@ use nymsphinx::addressing::clients::Recipient; use nymsphinx::receiver::ReconstructedMessage; use proxy_helpers::connection_controller::{Controller, ControllerCommand, ControllerSender}; use socks5_requests::{ConnectionId, Message as Socks5Message, Request, Response}; +use statistics_common::collector::StatisticsSender; use std::path::PathBuf; use std::sync::atomic::{AtomicUsize, Ordering}; use tokio_tungstenite::tungstenite::protocol::Message; @@ -63,7 +64,7 @@ impl ServiceProvider { async fn mixnet_response_listener( mut websocket_writer: SplitSink, mut mix_reader: mpsc::UnboundedReceiver<(Socks5Message, Recipient)>, - stats_collector: Option, + stats_collector: Option, ) { // TODO: wire SURBs in here once they're available while let Some((msg, return_address)) = mix_reader.next().await { @@ -228,7 +229,7 @@ impl ServiceProvider { raw_request: &[u8], controller_sender: &mut ControllerSender, mix_input_sender: &mpsc::UnboundedSender<(Socks5Message, Recipient)>, - stats_collector: Option, + stats_collector: Option, ) { let deserialized_msg = match Socks5Message::try_from_bytes(raw_request) { Ok(msg) => msg, @@ -290,12 +291,6 @@ impl ServiceProvider { let (mix_input_sender, mix_input_receiver) = mpsc::unbounded::<(Socks5Message, Recipient)>(); - let (mut timer_sender, timer_receiver) = Timer::new(); - let interval = timer_sender.interval(); - tokio::spawn(async move { - timer_sender.run().await; - }); - // controller for managing all active connections let (mut active_connections_controller, mut controller_sender) = Controller::new(); tokio::spawn(async move { @@ -303,15 +298,14 @@ impl ServiceProvider { }); let stats_collector = if self.enable_statistics { - let mut stats_sender = - StatisticsSender::new(interval, timer_receiver, self.stats_provider_addr) + let stats_collector = + ServiceStatisticsCollector::new(self.stats_provider_addr, mix_input_sender.clone()) .await - .expect("Statistics controller could not be bootstrapped"); - let stats_collector = StatisticsCollector::from(&stats_sender); + .expect("Service statistics collector could not be bootstrapped"); + let mut stats_sender = StatisticsSender::new(stats_collector.clone()); - let mix_input_sender_clone = mix_input_sender.clone(); tokio::spawn(async move { - stats_sender.run(&mix_input_sender_clone).await; + stats_sender.run().await; }); Some(stats_collector) } else { diff --git a/service-providers/network-requester/src/main.rs b/service-providers/network-requester/src/main.rs index 8b6d8d5834..60f57bc745 100644 --- a/service-providers/network-requester/src/main.rs +++ b/service-providers/network-requester/src/main.rs @@ -36,7 +36,7 @@ fn parse_args<'a>() -> ArgMatches<'a> { ) .arg( Arg::with_name(ENABLE_STATISTICS) - .help("enable service statistics that get sent to a statistics aggregator server") + .help("enable service anonymized statistics that get sent to a statistics aggregator server") .long(ENABLE_STATISTICS), ) .arg( diff --git a/service-providers/network-requester/src/statistics/collector.rs b/service-providers/network-requester/src/statistics/collector.rs new file mode 100644 index 0000000000..2b2485b14d --- /dev/null +++ b/service-providers/network-requester/src/statistics/collector.rs @@ -0,0 +1,215 @@ +// Copyright 2022 - Nym Technologies SA +// SPDX-License-Identifier: Apache-2.0 + +use async_trait::async_trait; +use futures::channel::mpsc; +use log::*; +use rand::RngCore; +use serde::Deserialize; +use sqlx::types::chrono::{DateTime, Utc}; +use std::collections::{HashMap, HashSet}; +use std::sync::Arc; +use std::time::Duration; +use tokio::sync::RwLock; + +use network_defaults::DEFAULT_NETWORK; +use nymsphinx::addressing::clients::Recipient; +use ordered_buffer::OrderedMessageSender; +use socks5_requests::{ConnectionId, Message as Socks5Message, RemoteAddress, Request}; +use statistics_common::api::{ + build_statistics_request_bytes, DEFAULT_STATISTICS_SERVICE_ADDRESS, + DEFAULT_STATISTICS_SERVICE_PORT, +}; +use statistics_common::{ + collector::StatisticsCollector, error::StatsError as CommonStatsError, StatsMessage, + StatsServiceData, +}; + +use super::error::StatsError; + +const REMOTE_SOURCE_OF_STATS_PROVIDER_CONFIG: &str = + "https://nymtech.net/.wellknown/network-requester/stats-provider.json"; + +#[derive(Clone, Debug)] +pub struct StatsData { + client_processed_bytes: HashMap, +} + +impl StatsData { + pub fn new() -> Self { + StatsData { + client_processed_bytes: HashMap::new(), + } + } + + pub fn processed(&mut self, remote_addr: &str, bytes: u32) { + if let Some(curr_bytes) = self.client_processed_bytes.get_mut(remote_addr) { + *curr_bytes += bytes; + } else { + self.client_processed_bytes + .insert(remote_addr.to_string(), bytes); + } + } +} + +#[derive(Clone, Debug, Deserialize)] +pub struct StatsProviderConfigEntry { + stats_client_address: String, +} + +#[derive(Clone, Debug, Deserialize)] +#[serde(deny_unknown_fields)] +pub struct OptionalStatsProviderConfig { + mainnet: Option, + sandbox: Option, + qa: Option, +} + +impl OptionalStatsProviderConfig { + pub fn stats_client_address(&self) -> Option { + let entry_config = match DEFAULT_NETWORK { + network_defaults::all::Network::MAINNET => self.mainnet.clone(), + network_defaults::all::Network::SANDBOX => self.sandbox.clone(), + network_defaults::all::Network::QA => self.qa.clone(), + }; + entry_config.map(|e| e.stats_client_address) + } +} + +#[derive(Clone)] +pub struct ServiceStatisticsCollector { + pub(crate) request_stats_data: Arc>, + pub(crate) response_stats_data: Arc>, + pub(crate) connected_services: Arc>>, + stats_provider_addr: Recipient, + mix_input_sender: mpsc::UnboundedSender<(Socks5Message, Recipient)>, +} + +impl ServiceStatisticsCollector { + pub async fn new( + stats_provider_addr: Option, + mix_input_sender: mpsc::UnboundedSender<(Socks5Message, Recipient)>, + ) -> Result { + let client = reqwest::Client::builder() + .timeout(Duration::from_secs(3)) + .build()?; + let stats_provider_config: OptionalStatsProviderConfig = client + .get(REMOTE_SOURCE_OF_STATS_PROVIDER_CONFIG.to_string()) + .send() + .await? + .json() + .await?; + let stats_provider_addr = stats_provider_addr.unwrap_or( + Recipient::try_from_base58_string( + stats_provider_config + .stats_client_address() + .ok_or(StatsError::InvalidClientAddress)?, + ) + .map_err(|_| StatsError::InvalidClientAddress)?, + ); + + Ok(ServiceStatisticsCollector { + request_stats_data: Arc::new(RwLock::new(StatsData::new())), + response_stats_data: Arc::new(RwLock::new(StatsData::new())), + connected_services: Arc::new(RwLock::new(HashMap::new())), + stats_provider_addr, + mix_input_sender, + }) + } +} + +#[async_trait] +impl StatisticsCollector for ServiceStatisticsCollector { + async fn create_stats_message( + &self, + interval: Duration, + timestamp: DateTime, + ) -> StatsMessage { + let stats_data = { + let request_data_bytes = self.request_stats_data.read().await; + let response_data_bytes = self.response_stats_data.read().await; + let services: HashSet = request_data_bytes + .client_processed_bytes + .keys() + .chain(response_data_bytes.client_processed_bytes.keys()) + .cloned() + .collect(); + services + .into_iter() + .map(|requested_service| { + let request_bytes = request_data_bytes + .client_processed_bytes + .get(&requested_service) + .copied() + .unwrap_or(0); + let response_bytes = response_data_bytes + .client_processed_bytes + .get(&requested_service) + .copied() + .unwrap_or(0); + statistics_common::StatsData::Service(StatsServiceData::new( + requested_service, + request_bytes, + response_bytes, + )) + }) + .collect() + }; + + StatsMessage { + stats_data, + interval_seconds: interval.as_secs() as u32, + timestamp: timestamp.to_rfc3339(), + } + } + + async fn send_stats_message( + &self, + stats_message: StatsMessage, + ) -> Result<(), CommonStatsError> { + let msg = build_statistics_request_bytes(stats_message)?; + + trace!("Connecting to statistics service"); + let mut rng = rand::rngs::OsRng; + let conn_id = rng.next_u64(); + let connect_req = Request::new_connect( + conn_id, + format!( + "{}:{}", + DEFAULT_STATISTICS_SERVICE_ADDRESS, DEFAULT_STATISTICS_SERVICE_PORT + ), + self.stats_provider_addr, + ); + self.mix_input_sender + .unbounded_send(( + Socks5Message::Request(connect_req), + self.stats_provider_addr, + )) + .unwrap(); + + trace!("Sending data to statistics service"); + let mut message_sender = OrderedMessageSender::new(); + let ordered_msg = message_sender.wrap_message(msg).into_bytes(); + let send_req = Request::new_send(conn_id, ordered_msg, true); + self.mix_input_sender + .unbounded_send((Socks5Message::Request(send_req), self.stats_provider_addr)) + .unwrap(); + + Ok(()) + } + + async fn reset_stats(&mut self) { + self.request_stats_data + .write() + .await + .client_processed_bytes + .iter_mut() + .for_each(|(_, b)| *b = 0); + self.response_stats_data + .write() + .await + .client_processed_bytes + .iter_mut() + .for_each(|(_, b)| *b = 0); + } +} diff --git a/service-providers/network-requester/src/statistics/comm.rs b/service-providers/network-requester/src/statistics/comm.rs deleted file mode 100644 index 79f619b0db..0000000000 --- a/service-providers/network-requester/src/statistics/comm.rs +++ /dev/null @@ -1,229 +0,0 @@ -// Copyright 2022 - Nym Technologies SA -// SPDX-License-Identifier: Apache-2.0 - -use futures::channel::mpsc; -use futures::StreamExt; -use log::*; -use rand::RngCore; -use serde::Deserialize; -use sqlx::types::chrono::{DateTime, Utc}; -use std::collections::{HashMap, HashSet}; -use std::sync::Arc; -use std::time::Duration; -use tokio::sync::RwLock; - -use network_defaults::DEFAULT_NETWORK; -use nymsphinx::addressing::clients::Recipient; -use ordered_buffer::OrderedMessageSender; -use socks5_requests::{ConnectionId, Message as Socks5Message, RemoteAddress, Request}; -use statistics::api::{ - build_statistics_request_bytes, DEFAULT_STATISTICS_SERVICE_ADDRESS, - DEFAULT_STATISTICS_SERVICE_PORT, -}; -use statistics::{StatsMessage, StatsServiceData}; - -use super::error::StatsError; - -const REMOTE_SOURCE_OF_STATS_PROVIDER_CONFIG: &str = - "https://nymtech.net/.wellknown/network-requester/stats-provider.json"; - -#[derive(Clone, Debug)] -pub struct StatsData { - client_processed_bytes: HashMap, -} - -impl StatsData { - pub fn new() -> Self { - StatsData { - client_processed_bytes: HashMap::new(), - } - } - - pub fn processed(&mut self, remote_addr: &str, bytes: u32) { - if let Some(curr_bytes) = self.client_processed_bytes.get_mut(remote_addr) { - *curr_bytes += bytes; - } else { - self.client_processed_bytes - .insert(remote_addr.to_string(), bytes); - } - } -} - -#[derive(Clone, Debug, Deserialize)] -pub struct StatsProviderConfigEntry { - stats_client_address: String, -} - -#[derive(Clone, Debug, Deserialize)] -#[serde(deny_unknown_fields)] -pub struct OptionalStatsProviderConfig { - mainnet: Option, - sandbox: Option, - qa: Option, -} - -impl OptionalStatsProviderConfig { - pub fn stats_client_address(&self) -> Option { - let entry_config = match DEFAULT_NETWORK { - network_defaults::all::Network::MAINNET => self.mainnet.clone(), - network_defaults::all::Network::SANDBOX => self.sandbox.clone(), - network_defaults::all::Network::QA => self.qa.clone(), - }; - entry_config.map(|e| e.stats_client_address) - } -} - -#[derive(Clone)] -pub struct StatisticsCollector { - pub(crate) request_stats_data: Arc>, - pub(crate) response_stats_data: Arc>, - pub(crate) connected_services: Arc>>, -} - -impl StatisticsCollector { - pub fn from(stats: &StatisticsSender) -> Self { - Self { - request_stats_data: Arc::clone(&stats.request_data), - response_stats_data: Arc::clone(&stats.response_data), - connected_services: Arc::new(RwLock::new(HashMap::new())), - } - } -} - -pub struct StatisticsSender { - request_data: Arc>, - response_data: Arc>, - interval_seconds: u32, - timestamp: DateTime, - timer_receiver: mpsc::Receiver<()>, - stats_provider_addr: Recipient, -} - -impl StatisticsSender { - pub async fn new( - interval_seconds: Duration, - timer_receiver: mpsc::Receiver<()>, - stats_provider_addr: Option, - ) -> Result { - let client = reqwest::Client::builder() - .timeout(Duration::from_secs(3)) - .build()?; - let stats_provider_config: OptionalStatsProviderConfig = client - .get(REMOTE_SOURCE_OF_STATS_PROVIDER_CONFIG.to_string()) - .send() - .await? - .json() - .await?; - let stats_provider_addr = stats_provider_addr.unwrap_or( - Recipient::try_from_base58_string( - stats_provider_config - .stats_client_address() - .ok_or(StatsError::InvalidClientAddress)?, - ) - .map_err(|_| StatsError::InvalidClientAddress)?, - ); - - Ok(StatisticsSender { - request_data: Arc::new(RwLock::new(StatsData::new())), - response_data: Arc::new(RwLock::new(StatsData::new())), - timestamp: Utc::now(), - interval_seconds: interval_seconds.as_secs() as u32, - timer_receiver, - stats_provider_addr, - }) - } - - pub async fn run( - &mut self, - mix_input_sender: &mpsc::UnboundedSender<(Socks5Message, Recipient)>, - ) { - loop { - if self.timer_receiver.next().await == None { - error!("Timer thread has died. No more statistics will be sent"); - } else { - let stats_data = { - let request_data_bytes = self.request_data.read().await; - let response_data_bytes = self.response_data.read().await; - let services: HashSet = request_data_bytes - .client_processed_bytes - .keys() - .chain(response_data_bytes.client_processed_bytes.keys()) - .cloned() - .collect(); - services - .into_iter() - .map(|requested_service| { - let request_bytes = request_data_bytes - .client_processed_bytes - .get(&requested_service) - .copied() - .unwrap_or(0); - let response_bytes = response_data_bytes - .client_processed_bytes - .get(&requested_service) - .copied() - .unwrap_or(0); - StatsServiceData::new(requested_service, request_bytes, response_bytes) - }) - .collect() - }; - - let stats_message = StatsMessage { - stats_data, - interval_seconds: self.interval_seconds, - timestamp: self.timestamp.to_rfc3339(), - }; - match build_statistics_request_bytes(stats_message) { - Ok(data) => { - trace!("Connecting to statistics service"); - let mut rng = rand::rngs::OsRng; - let conn_id = rng.next_u64(); - let connect_req = Request::new_connect( - conn_id, - format!( - "{}:{}", - DEFAULT_STATISTICS_SERVICE_ADDRESS, DEFAULT_STATISTICS_SERVICE_PORT - ), - self.stats_provider_addr, - ); - mix_input_sender - .unbounded_send(( - Socks5Message::Request(connect_req), - self.stats_provider_addr, - )) - .unwrap(); - - trace!("Sending data to statistics service"); - let mut message_sender = OrderedMessageSender::new(); - let ordered_msg = message_sender.wrap_message(data).into_bytes(); - let send_req = Request::new_send(conn_id, ordered_msg, true); - mix_input_sender - .unbounded_send(( - Socks5Message::Request(send_req), - self.stats_provider_addr, - )) - .unwrap(); - } - Err(e) => error!("Statistics not sent: {}", e), - } - self.reset_stats().await; - } - } - } - - async fn reset_stats(&mut self) { - self.request_data - .write() - .await - .client_processed_bytes - .iter_mut() - .for_each(|(_, b)| *b = 0); - self.response_data - .write() - .await - .client_processed_bytes - .iter_mut() - .for_each(|(_, b)| *b = 0); - self.timestamp = Utc::now(); - } -} diff --git a/service-providers/network-requester/src/statistics/error.rs b/service-providers/network-requester/src/statistics/error.rs index eadc188c5a..6554f2dc45 100644 --- a/service-providers/network-requester/src/statistics/error.rs +++ b/service-providers/network-requester/src/statistics/error.rs @@ -10,4 +10,7 @@ pub enum StatsError { #[error("Invalid stats provider client address")] InvalidClientAddress, + + #[error("Common statistics error {0}")] + CommonError(#[from] statistics_common::error::StatsError), } diff --git a/service-providers/network-requester/src/statistics/mod.rs b/service-providers/network-requester/src/statistics/mod.rs index 8284283801..0e77a9333b 100644 --- a/service-providers/network-requester/src/statistics/mod.rs +++ b/service-providers/network-requester/src/statistics/mod.rs @@ -1,9 +1,7 @@ // Copyright 2022 - Nym Technologies SA // SPDX-License-Identifier: Apache-2.0 -mod comm; +mod collector; mod error; -mod timer; -pub use comm::{StatisticsCollector, StatisticsSender, StatsData}; -pub use timer::Timer; +pub use collector::ServiceStatisticsCollector; diff --git a/service-providers/network-requester/src/statistics/timer.rs b/service-providers/network-requester/src/statistics/timer.rs deleted file mode 100644 index cde054c931..0000000000 --- a/service-providers/network-requester/src/statistics/timer.rs +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright 2022 - Nym Technologies SA -// SPDX-License-Identifier: Apache-2.0 - -use futures::channel::mpsc; -use std::time::Duration; -use tokio::time; - -const STATISTICS_INTERVAL: Duration = Duration::from_secs(60); - -pub type TimerReceiver = mpsc::Receiver<()>; - -pub struct Timer { - interval: Duration, - stats_sender: mpsc::Sender<()>, -} - -impl Timer { - pub fn new() -> (Self, TimerReceiver) { - let (stats_sender, stats_receiver) = mpsc::channel::<()>(1); - ( - Timer { - interval: STATISTICS_INTERVAL, - stats_sender, - }, - stats_receiver, - ) - } - - pub fn interval(&self) -> Duration { - self.interval - } - - pub async fn run(&mut self) { - let mut interval = time::interval(self.interval); - loop { - interval.tick().await; - let _ = self.stats_sender.try_send(()); - } - } -} diff --git a/service-providers/network-statistics/Cargo.toml b/service-providers/network-statistics/Cargo.toml index de08cf0785..6efd30a2c2 100644 --- a/service-providers/network-statistics/Cargo.toml +++ b/service-providers/network-statistics/Cargo.toml @@ -16,7 +16,7 @@ thiserror = "1" tokio = { version = "1.4", features = [ "net", "rt-multi-thread", "macros", "time" ] } tokio-tungstenite = "0.14" -statistics = { path = "../../common/statistics" } +statistics-common = { path = "../../common/statistics" } [build-dependencies] sqlx = { version = "0.5", features = ["runtime-tokio-rustls", "sqlite", "macros", "migrate"] } diff --git a/service-providers/network-statistics/migrations/20220512120000_mixnet_statistics.sql b/service-providers/network-statistics/migrations/20220512120000_mixnet_statistics.sql index 51514df755..5e6b2aa348 100644 --- a/service-providers/network-statistics/migrations/20220512120000_mixnet_statistics.sql +++ b/service-providers/network-statistics/migrations/20220512120000_mixnet_statistics.sql @@ -11,4 +11,11 @@ CREATE TABLE service_statistics response_processed_bytes INTEGER NOT NULL, interval_seconds INTEGER NOT NULL, timestamp DATETIME NOT NULL +); + +CREATE TABLE gateway_statistics +( + id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + inbox_count INTEGER NOT NULL, + timestamp DATETIME NOT NULL ); \ No newline at end of file diff --git a/service-providers/network-statistics/src/api/mod.rs b/service-providers/network-statistics/src/api/mod.rs index 3a30d8ebb8..f309976faa 100644 --- a/service-providers/network-statistics/src/api/mod.rs +++ b/service-providers/network-statistics/src/api/mod.rs @@ -8,7 +8,7 @@ use crate::storage::NetworkStatisticsStorage; use error::Result; use routes::{post_all_statistics, post_statistic}; -use statistics::api::STATISTICS_SERVICE_VERSION; +use statistics_common::api::STATISTICS_SERVICE_VERSION; mod error; mod routes; diff --git a/service-providers/network-statistics/src/api/routes.rs b/service-providers/network-statistics/src/api/routes.rs index 5f5c9bb3b1..7316d2c375 100644 --- a/service-providers/network-statistics/src/api/routes.rs +++ b/service-providers/network-statistics/src/api/routes.rs @@ -5,19 +5,25 @@ use rocket::serde::json::Json; use rocket::State; use serde::{Deserialize, Serialize}; -use statistics::StatsMessage; +use statistics_common::StatsMessage; use crate::api::error::Result; use crate::storage::NetworkStatisticsStorage; #[derive(Clone, Serialize, Deserialize, Debug)] -pub struct ServiceStatisticsRequest { +pub struct StatisticsRequest { // date, RFC 3339 format since: String, // date, RFC 3339 format until: String, } +#[derive(Clone, Serialize, Deserialize, Debug)] +pub enum GenericStatistic { + Service(ServiceStatistic), + Gateway(GatewayStatistic), +} + #[derive(Clone, Serialize, Deserialize, Debug)] pub struct ServiceStatistic { pub requested_service: String, @@ -27,28 +33,51 @@ pub struct ServiceStatistic { pub timestamp: String, } +#[derive(Clone, Serialize, Deserialize, Debug)] +pub struct GatewayStatistic { + pub inbox_count: u32, + pub timestamp: String, +} + #[rocket::post("/all-statistics", data = "")] pub(crate) async fn post_all_statistics( - all_statistics_request: Json, + all_statistics_request: Json, storage: &State, -) -> Result>> { - let service_statistics = storage +) -> Result>> { + let all_statistics = storage .get_service_statistics_in_interval( &all_statistics_request.since, &all_statistics_request.until, ) .await? .into_iter() - .map(|data| ServiceStatistic { - requested_service: data.requested_service, - request_processed_bytes: data.request_processed_bytes as u32, - response_processed_bytes: data.response_processed_bytes as u32, - interval_seconds: data.interval_seconds as u32, - timestamp: data.timestamp.to_string(), + .map(|data| { + GenericStatistic::Service(ServiceStatistic { + requested_service: data.requested_service, + request_processed_bytes: data.request_processed_bytes as u32, + response_processed_bytes: data.response_processed_bytes as u32, + interval_seconds: data.interval_seconds as u32, + timestamp: data.timestamp.to_string(), + }) }) + .chain( + storage + .get_gateway_statistics_in_interval( + &all_statistics_request.since, + &all_statistics_request.until, + ) + .await? + .into_iter() + .map(|data| { + GenericStatistic::Gateway(GatewayStatistic { + inbox_count: data.inbox_count as u32, + timestamp: data.timestamp.to_string(), + }) + }), + ) .collect(); - Ok(Json(service_statistics)) + Ok(Json(all_statistics)) } #[rocket::post("/statistic", data = "")] @@ -56,6 +85,6 @@ pub(crate) async fn post_statistic( statistic: Json, storage: &State, ) -> Result> { - storage.insert_service_statistics(statistic.0).await?; + storage.insert_statistics(statistic.0).await?; Ok(Json(())) } diff --git a/service-providers/network-statistics/src/storage/manager.rs b/service-providers/network-statistics/src/storage/manager.rs index 4fda9d7bd0..07e0cc751b 100644 --- a/service-providers/network-statistics/src/storage/manager.rs +++ b/service-providers/network-statistics/src/storage/manager.rs @@ -3,7 +3,7 @@ use sqlx::types::chrono::{DateTime, Utc}; -use crate::storage::models::ServiceStatistics; +use crate::storage::models::{GatewayStatistics, ServiceStatistics}; #[derive(Clone)] pub(crate) struct StorageManager { @@ -12,7 +12,7 @@ pub(crate) struct StorageManager { // all SQL goes here impl StorageManager { - /// Adds an entry for some statistical data. + /// Adds an entry for some service statistical data. /// /// # Arguments /// @@ -20,6 +20,7 @@ impl StorageManager { /// * `request_processed_bytes`: Number of bytes for socks5 requests. /// * `response_processed_bytes`: Number of bytes for socks5 responses. /// * `interval_seconds`: Duration in seconds in which the data was gathered. + /// * `timestamp`: The moment in time when the data started being collected. pub(super) async fn insert_service_statistics( &self, requested_service: String, @@ -42,7 +43,30 @@ impl StorageManager { Ok(()) } - /// Returns data submitted within the provided time interval. + /// Adds an entry for some gateway statistical data. + /// + /// # Arguments + /// + /// * `inbox_count`: Number of clients of a gateway. + /// * `interval_seconds`: Duration in seconds in which the data was gathered. + /// * `timestamp`: The moment in time when the data started being collected. + pub(super) async fn insert_gateway_statistics( + &self, + inbox_count: u32, + timestamp: DateTime, + ) -> Result<(), sqlx::Error> { + sqlx::query!( + "INSERT INTO gateway_statistics(inbox_count, timestamp) VALUES (?, ?)", + inbox_count, + timestamp, + ) + .execute(&self.connection_pool) + .await?; + + Ok(()) + } + + /// Returns service statistical data submitted within the provided time interval. /// /// # Arguments /// @@ -62,4 +86,25 @@ impl StorageManager { .fetch_all(&self.connection_pool) .await } + + /// Returns gateway statistical data submitted within the provided time interval. + /// + /// # Arguments + /// + /// * `since`: indicates the lower bound timestamp for the data + /// * `until`: indicates the upper bound timestamp for the data + pub(super) async fn get_gateway_statistics_in_interval( + &self, + since: DateTime, + until: DateTime, + ) -> Result, sqlx::Error> { + sqlx::query_as!( + GatewayStatistics, + "SELECT * FROM gateway_statistics WHERE timestamp BETWEEN ? AND ?", + since, + until + ) + .fetch_all(&self.connection_pool) + .await + } } diff --git a/service-providers/network-statistics/src/storage/mod.rs b/service-providers/network-statistics/src/storage/mod.rs index ac7cdb8bdd..6ae4e08646 100644 --- a/service-providers/network-statistics/src/storage/mod.rs +++ b/service-providers/network-statistics/src/storage/mod.rs @@ -6,11 +6,11 @@ use sqlx::types::chrono::{DateTime, Utc}; use sqlx::ConnectOptions; use std::path::PathBuf; -use statistics::StatsMessage; +use statistics_common::StatsMessage; use crate::storage::error::NetworkStatisticsStorageError; use crate::storage::manager::StorageManager; -use crate::storage::models::ServiceStatistics; +use crate::storage::models::{GatewayStatistics, ServiceStatistics}; pub(crate) mod error; mod manager; @@ -49,29 +49,38 @@ impl NetworkStatisticsStorage { /// # Arguments /// /// * `msg`: Message containing the statistical data. - pub(super) async fn insert_service_statistics( + pub(super) async fn insert_statistics( &self, msg: StatsMessage, ) -> Result<(), NetworkStatisticsStorageError> { let timestamp: DateTime = DateTime::parse_from_rfc3339(&msg.timestamp) .map_err(|_| NetworkStatisticsStorageError::TimestampParse)? .into(); - for service_data in msg.stats_data { - self.manager - .insert_service_statistics( - service_data.requested_service.clone(), - service_data.request_bytes, - service_data.response_bytes, - msg.interval_seconds, - timestamp, - ) - .await?; + for stats_data in msg.stats_data { + match stats_data { + statistics_common::StatsData::Service(service_data) => { + self.manager + .insert_service_statistics( + service_data.requested_service.clone(), + service_data.request_bytes, + service_data.response_bytes, + msg.interval_seconds, + timestamp, + ) + .await?; + } + statistics_common::StatsData::Gateway(gateway_data) => { + self.manager + .insert_gateway_statistics(gateway_data.inbox_count, timestamp) + .await? + } + } } Ok(()) } - /// Returns data submitted within the provided time interval. + /// Returns service data submitted within the provided time interval. /// /// # Arguments /// @@ -93,4 +102,27 @@ impl NetworkStatisticsStorage { .get_service_statistics_in_interval(since, until) .await?) } + + /// Returns gateway data submitted within the provided time interval. + /// + /// # Arguments + /// + /// * `since`: indicates the lower bound timestamp for the data, RFC 3339 format + /// * `until`: indicates the upper bound timestamp for the data, RFC 3339 format + pub(super) async fn get_gateway_statistics_in_interval( + &self, + since: &str, + until: &str, + ) -> Result, NetworkStatisticsStorageError> { + let since = DateTime::parse_from_rfc3339(since) + .map_err(|_| NetworkStatisticsStorageError::TimestampParse)? + .into(); + let until = DateTime::parse_from_rfc3339(until) + .map_err(|_| NetworkStatisticsStorageError::TimestampParse)? + .into(); + Ok(self + .manager + .get_gateway_statistics_in_interval(since, until) + .await?) + } } diff --git a/service-providers/network-statistics/src/storage/models.rs b/service-providers/network-statistics/src/storage/models.rs index 1f3ee3e1de..f04a333495 100644 --- a/service-providers/network-statistics/src/storage/models.rs +++ b/service-providers/network-statistics/src/storage/models.rs @@ -13,3 +13,10 @@ pub(crate) struct ServiceStatistics { pub(crate) interval_seconds: i64, pub(crate) timestamp: NaiveDateTime, } + +pub(crate) struct GatewayStatistics { + #[allow(dead_code)] + pub(crate) id: i64, + pub(crate) inbox_count: i64, + pub(crate) timestamp: NaiveDateTime, +} From 3aff419a764079c813c81784bd65d71e021be0a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bogdan-=C8=98tefan=20Neac=C8=99u?= Date: Thu, 16 Jun 2022 16:26:51 +0200 Subject: [PATCH 13/16] Fix imports for macos --- nym-connect/src-tauri/src/menu.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nym-connect/src-tauri/src/menu.rs b/nym-connect/src-tauri/src/menu.rs index cb4d0626d1..368fc07d3a 100644 --- a/nym-connect/src-tauri/src/menu.rs +++ b/nym-connect/src-tauri/src/menu.rs @@ -4,7 +4,7 @@ use tauri::{ SystemTrayMenuItem, Wry, }; #[cfg(target_os = "macos")] -use tauri::{CustomMenuItem, MenuItem, Submenu, SystemTray, SystemTrayMenu, SystemTrayMenuItem}; +use tauri::{MenuItem, Submenu}; pub trait AddDefaultSubmenus { fn add_default_app_submenu_if_macos(self) -> Self; From 287c45d6b5857273d0d6cd79d241c87e8c3cb8d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jon=20H=C3=A4ggblad?= Date: Thu, 16 Jun 2022 16:45:33 +0200 Subject: [PATCH 14/16] ci: add nym-connect rust to build (#1378) * ci: add nym-connect rust to build * rustfmt * connect: add gitkeep in dist dir * wallet: dont trigger connect on pull_request * github: libayatana-indicator3-dev * github: libayatana-appindicator3-dev --- .github/workflows/connect.yml | 56 +++++++++++++++++++++++++ nym-connect/dist/.gitkeep | 0 nym-connect/src-tauri/src/config/mod.rs | 4 +- 3 files changed, 59 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/connect.yml create mode 100644 nym-connect/dist/.gitkeep diff --git a/.github/workflows/connect.yml b/.github/workflows/connect.yml new file mode 100644 index 0000000000..292fee7482 --- /dev/null +++ b/.github/workflows/connect.yml @@ -0,0 +1,56 @@ +name: Nym Connect (rust) + +on: + push: + paths-ignore: + - 'explorer/**' + +jobs: + build: + runs-on: [ self-hosted, custom-linux ] + env: + RUSTC_WRAPPER: /home/ubuntu/.cargo/bin/sccache + steps: + - name: Install Dependencies (Linux) + run: sudo apt-get update && sudo apt-get -y install libwebkit2gtk-4.0-dev build-essential curl wget libssl-dev libgtk-3-dev squashfs-tools libayatana-appindicator3-dev + + - name: Check out repository code + uses: actions/checkout@v2 + + - name: Install rust toolchain + uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: stable + override: true + components: rustfmt, clippy + + - name: Build all binaries + uses: actions-rs/cargo@v1 + with: + command: build + args: --manifest-path nym-connect/Cargo.toml --workspace + + - name: Run all tests + uses: actions-rs/cargo@v1 + with: + command: test + args: --manifest-path nym-connect/Cargo.toml --workspace + + - name: Check formatting + uses: actions-rs/cargo@v1 + with: + command: fmt + args: --manifest-path nym-connect/Cargo.toml --all -- --check + + - uses: actions-rs/clippy-check@v1 + name: Clippy checks + with: + token: ${{ secrets.GITHUB_TOKEN }} + args: --manifest-path nym-connect/Cargo.toml --workspace --all-features + + - name: Run clippy + uses: actions-rs/cargo@v1 + with: + command: clippy + args: --manifest-path nym-connect/Cargo.toml --workspace --all-features -- -D warnings diff --git a/nym-connect/dist/.gitkeep b/nym-connect/dist/.gitkeep new file mode 100644 index 0000000000..e69de29bb2 diff --git a/nym-connect/src-tauri/src/config/mod.rs b/nym-connect/src-tauri/src/config/mod.rs index e807bc9515..b2dfb2840f 100644 --- a/nym-connect/src-tauri/src/config/mod.rs +++ b/nym-connect/src-tauri/src/config/mod.rs @@ -56,7 +56,9 @@ pub async fn init_socks5(provider_address: &str, chosen_gateway_id: Option<&str> .await; info!("Setting gateway endpoint"); - config.get_base_mut().with_gateway_endpoint(gateway_details.into()); + config + .get_base_mut() + .with_gateway_endpoint(gateway_details.into()); info!("Insert gateway shared key"); key_manager.insert_gateway_shared_key(shared_keys); From 6bd0ff796adb73fe3ac55bd9f476013b6683c368 Mon Sep 17 00:00:00 2001 From: Fouad Date: Thu, 16 Jun 2022 16:02:36 +0100 Subject: [PATCH 15/16] archive password when new paasword is created (#1380) --- .../src/pages/auth/pages/connect-password.tsx | 8 +++++++- .../src/pages/auth/pages/forgot-password.tsx | 19 +------------------ 2 files changed, 8 insertions(+), 19 deletions(-) diff --git a/nym-wallet/src/pages/auth/pages/connect-password.tsx b/nym-wallet/src/pages/auth/pages/connect-password.tsx index 971326ffc6..133d0a27cb 100644 --- a/nym-wallet/src/pages/auth/pages/connect-password.tsx +++ b/nym-wallet/src/pages/auth/pages/connect-password.tsx @@ -3,8 +3,8 @@ import { useNavigate } from 'react-router-dom'; import { Button, CircularProgress, FormControl, Stack } from '@mui/material'; import { useSnackbar } from 'notistack'; import { AuthContext } from 'src/context/auth'; -import { createPassword } from 'src/requests'; import { PasswordInput } from 'src/components'; +import { archiveWalletFile, createPassword, isPasswordCreated } from 'src/requests'; import { Subtitle, Title, PasswordStrength } from '../components'; export const ConnectPassword = () => { @@ -20,6 +20,12 @@ export const ConnectPassword = () => { const storePassword = async () => { try { setIsLoading(true); + + const exists = await isPasswordCreated(); + if (exists) { + await archiveWalletFile(); + } + await createPassword({ mnemonic, password }); resetState(); enqueueSnackbar('Password successfully created', { variant: 'success' }); diff --git a/nym-wallet/src/pages/auth/pages/forgot-password.tsx b/nym-wallet/src/pages/auth/pages/forgot-password.tsx index d0f614856a..0bf535d391 100644 --- a/nym-wallet/src/pages/auth/pages/forgot-password.tsx +++ b/nym-wallet/src/pages/auth/pages/forgot-password.tsx @@ -2,32 +2,15 @@ import React from 'react'; import { useNavigate } from 'react-router-dom'; import { Button, Stack, Typography } from '@mui/material'; -import { useSnackbar } from 'notistack'; -import { archiveWalletFile } from 'src/requests'; -import { Console } from 'src/utils/console'; import { Subtitle } from '../components'; export const ForgotPassword = () => { const navigate = useNavigate(); - const { enqueueSnackbar } = useSnackbar(); return ( <> - or From 56b1dba66ae359b619a872b05d95c95a4bed196e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jon=20H=C3=A4ggblad?= Date: Thu, 16 Jun 2022 17:59:46 +0200 Subject: [PATCH 16/16] cargo upgrade rocket --workspace (#1330) --- CHANGELOG.md | 1 + Cargo.lock | 327 +++++++----------- clients/client-core/Cargo.toml | 2 +- clients/credential/Cargo.toml | 2 +- clients/native/Cargo.toml | 2 +- clients/native/websocket-requests/Cargo.toml | 2 +- clients/socks5/Cargo.toml | 2 +- common/client-libs/gateway-client/Cargo.toml | 2 +- .../multisig-contract/Cargo.toml | 2 +- common/credential-storage/Cargo.toml | 2 +- common/credentials/Cargo.toml | 2 +- common/crypto/dkg/Cargo.toml | 2 +- common/nymsphinx/addressing/Cargo.toml | 2 +- common/nymsphinx/cover/Cargo.toml | 2 +- common/nymsphinx/params/Cargo.toml | 2 +- common/socks5/proxy-helpers/Cargo.toml | 2 +- common/version-checker/Cargo.toml | 2 +- common/wasm-utils/Cargo.toml | 2 +- explorer-api/Cargo.toml | 4 +- mixnode/Cargo.toml | 2 +- .../network-statistics/Cargo.toml | 2 +- validator-api/Cargo.toml | 6 +- 22 files changed, 144 insertions(+), 230 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 34ac4fdd34..b99c085bb4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -45,6 +45,7 @@ Post 1.0.0 release, the changelog format is based on [Keep a Changelog](https:// - validator-client: created internal `Coin` type that replaces coins from `cosmrs` and `cosmwasm` for API entrypoints [[#1295]] - all: updated all `cosmwasm`-related dependencies to `1.0.0` and `cw-storage-plus` to `0.13.4` [[#1318]] +- all: updated `rocket` to `0.5.0-rc.2`. - network-requester: allow to voluntarily store and send statistical data about the number of bytes the proxied server serves ([#1328]) - gateway: allow to voluntarily send statistical data about the number of active inboxes served by a gateway ([#1376]) diff --git a/Cargo.lock b/Cargo.lock index 17fa5b8e7d..80bb5e4055 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -14,6 +14,15 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" +[[package]] +name = "aead" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b613b8e1e3cf911a086f53f03bf286f52fd7a7258e4fa606f0ef220d39d8877" +dependencies = [ + "generic-array 0.14.5", +] + [[package]] name = "aes" version = "0.7.5" @@ -38,6 +47,20 @@ dependencies = [ "cpufeatures", ] +[[package]] +name = "aes-gcm" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df5f85a83a7d8b0442b6aa7b504b8212c1733da07b98aae43d4bc21b2cb3cdf6" +dependencies = [ + "aead", + "aes 0.7.5", + "cipher 0.3.0", + "ctr 0.8.0", + "ghash", + "subtle 2.4.1", +] + [[package]] name = "ahash" version = "0.7.6" @@ -198,12 +221,6 @@ dependencies = [ "serde", ] -[[package]] -name = "base-x" -version = "0.2.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4521f3e3d031370679b3b140beb36dfe4801b09ac77e30c61941f97df3ef28b" - [[package]] name = "base16ct" version = "0.1.1" @@ -250,7 +267,7 @@ dependencies = [ "pbkdf2", "rand_core 0.6.3", "ripemd160", - "sha2", + "sha2 0.9.9", "subtle 2.4.1", "zeroize", ] @@ -410,7 +427,7 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "771fe0050b883fcc3ea2359b1a96bcfbc090b7116eae7c3c512c7a083fdf23d3" dependencies = [ - "sha2", + "sha2 0.9.9", ] [[package]] @@ -467,7 +484,7 @@ version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4c24dab4283a142afa2fdca129b80ad2c6284e073930f964c3a1293c225ee39a" dependencies = [ - "rustc_version 0.4.0", + "rustc_version", ] [[package]] @@ -701,12 +718,6 @@ version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e4c78c047431fee22c1a7bb92e00ad095a02a983affe4d8a72e2a2c62c1b94f3" -[[package]] -name = "const_fn" -version = "0.4.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbdcdcb6d86f71c5e97409ad45898af11cbc995b4ee8112d59095a28d376c935" - [[package]] name = "constant_time_eq" version = "0.1.5" @@ -728,12 +739,19 @@ checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" [[package]] name = "cookie" -version = "0.15.1" +version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5f1c7727e460397e56abc4bddc1d49e07a1ad78fc98eb2e1c8f032a58a2f80d" +checksum = "94d4706de1b0fa5b132270cddffa8585166037822e260a944fe161acd137ca05" dependencies = [ + "aes-gcm", + "base64", + "hkdf 0.12.3", + "hmac 0.12.1", "percent-encoding", - "time 0.2.27", + "rand 0.8.5", + "sha2 0.10.2", + "subtle 2.4.1", + "time 0.3.9", "version_check", ] @@ -1246,7 +1264,7 @@ dependencies = [ "convert_case", "proc-macro2", "quote", - "rustc_version 0.4.0", + "rustc_version", "syn", ] @@ -1332,12 +1350,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "discard" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "212d0f5754cb6769937f4501cc0e67f4f4483c8d2c3e1e922ee9edbe4ab4c7c0" - [[package]] name = "dkg" version = "0.1.0" @@ -1354,7 +1366,7 @@ dependencies = [ "rand_core 0.6.3", "serde", "serde_derive", - "sha2", + "sha2 0.9.9", "thiserror", "zeroize", ] @@ -1410,7 +1422,7 @@ dependencies = [ "rand 0.7.3", "serde", "serde_bytes", - "sha2", + "sha2 0.9.9", "zeroize", ] @@ -1424,7 +1436,7 @@ dependencies = [ "hex", "rand_core 0.6.3", "serde", - "sha2", + "sha2 0.9.9", "thiserror", "zeroize", ] @@ -2024,6 +2036,16 @@ dependencies = [ "syn", ] +[[package]] +name = "ghash" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1583cc1656d7839fd3732b80cf4f38850336cdb9b8ded1cd399ca62958de3c99" +dependencies = [ + "opaque-debug 0.3.0", + "polyval", +] + [[package]] name = "git2" version = "0.14.2" @@ -2596,7 +2618,7 @@ dependencies = [ "ecdsa", "elliptic-curve", "sec1", - "sha2", + "sha2 0.9.9", "sha3", ] @@ -3323,7 +3345,7 @@ dependencies = [ "rand 0.8.5", "serde", "serde_derive", - "sha2", + "sha2 0.9.9", "thiserror", ] @@ -3854,6 +3876,18 @@ dependencies = [ "plotters-backend", ] +[[package]] +name = "polyval" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8419d2b623c7c0896ff2d5d96e2cb4ede590fed28fcc34934f4c33c036e620a1" +dependencies = [ + "cfg-if 1.0.0", + "cpufeatures", + "opaque-debug 0.3.0", + "universal-hash", +] + [[package]] name = "ppv-lite86" version = "0.2.16" @@ -3917,12 +3951,6 @@ dependencies = [ "version_check", ] -[[package]] -name = "proc-macro-hack" -version = "0.5.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5" - [[package]] name = "proc-macro2" version = "1.0.37" @@ -4484,9 +4512,9 @@ dependencies = [ [[package]] name = "rocket" -version = "0.5.0-rc.1" +version = "0.5.0-rc.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a71c18c42a0eb15bf3816831caf0dad11e7966f2a41aaf486a701979c4dd1f2" +checksum = "98ead083fce4a405feb349cf09abdf64471c6077f14e0ce59364aa90d4b99317" dependencies = [ "async-stream", "async-trait", @@ -4502,7 +4530,7 @@ dependencies = [ "memchr", "multer", "num_cpus", - "parking_lot 0.11.2", + "parking_lot 0.12.0", "pin-project-lite", "rand 0.8.5", "ref-cast", @@ -4512,10 +4540,10 @@ dependencies = [ "serde_json", "state", "tempfile", - "time 0.2.27", + "time 0.3.9", "tokio", "tokio-stream", - "tokio-util 0.6.9", + "tokio-util 0.7.3", "ubyte", "version_check", "yansi", @@ -4523,9 +4551,9 @@ dependencies = [ [[package]] name = "rocket_codegen" -version = "0.5.0-rc.1" +version = "0.5.0-rc.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66f5fa462f7eb958bba8710c17c5d774bbbd59809fa76fb1957af7e545aea8bb" +checksum = "d6aeb6bb9c61e9cd2c00d70ea267bf36f76a4cc615e5908b349c2f9d93999b47" dependencies = [ "devise", "glob", @@ -4554,19 +4582,18 @@ dependencies = [ [[package]] name = "rocket_http" -version = "0.5.0-rc.1" +version = "0.5.0-rc.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23c8b7d512d2fcac2316ebe590cde67573844b99e6cc9ee0f53375fa16e25ebd" +checksum = "2ded65d127954de3c12471630bf4b81a2792f065984461e65b91d0fdaafc17a2" dependencies = [ "cookie", "either", + "futures", "http", "hyper", "indexmap", "log", "memchr", - "mime", - "parking_lot 0.11.2", "pear", "percent-encoding", "pin-project-lite", @@ -4575,16 +4602,16 @@ dependencies = [ "smallvec 1.8.0", "stable-pattern", "state", - "time 0.2.27", + "time 0.3.9", "tokio", "uncased", ] [[package]] name = "rocket_okapi" -version = "0.8.0-rc.1" +version = "0.8.0-rc.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0025aa04994af8cd8e1fcdd5a73579a395c941ae090ecb0a39b41cca7e237a20" +checksum = "489f4f5b120762f7974e65b919fc462d0660fd8b839026d8985b850fe5acccb0" dependencies = [ "either", "log", @@ -4598,9 +4625,9 @@ dependencies = [ [[package]] name = "rocket_okapi_codegen" -version = "0.8.0-rc.1" +version = "0.8.0-rc.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc114779fc27afb78179233e966f469e47fd7a98dc15181cff2574cdddb65612" +checksum = "54f94d1ffe41472e08463d7a2674f1db04dc4df745285e8369b33d3cfd6b0308" dependencies = [ "darling", "proc-macro2", @@ -4611,9 +4638,9 @@ dependencies = [ [[package]] name = "rocket_sync_db_pools" -version = "0.1.0-rc.1" +version = "0.1.0-rc.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38cfdfebd552d075c368e641c88a5cd6ce1c58c5c710548aeb777abb48830f4b" +checksum = "5fa48b6ab25013e9812f1b0c592741900b3a2a83c0936292e0565c0ac842f558" dependencies = [ "r2d2", "rocket", @@ -4624,9 +4651,9 @@ dependencies = [ [[package]] name = "rocket_sync_db_pools_codegen" -version = "0.1.0-rc.1" +version = "0.1.0-rc.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5267808c094db5366e1d8925aaf9f2ce05ff9b3bd92cb18c7040a1fe219c2e25" +checksum = "280ef2d232923e69cb93da156972eb5476a7cce5ba44843f6608f46a4abf7aab" dependencies = [ "devise", "quote", @@ -4638,15 +4665,6 @@ version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3e75f6a532d0fd9f7f13144f392b6ad56a32696bfcd9c78f797f16bbb6f072d6" -[[package]] -name = "rustc_version" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" -dependencies = [ - "semver 0.9.0", -] - [[package]] name = "rustc_version" version = "0.4.0" @@ -4723,9 +4741,9 @@ dependencies = [ [[package]] name = "schemars" -version = "0.8.8" +version = "0.8.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6b5a3c80cea1ab61f4260238409510e814e38b4b563c06044edf91e7dc070e3" +checksum = "1847b767a3d62d95cbf3d8a9f0e421cf57a0d8aa4f411d4b16525afb0284d4ed" dependencies = [ "dyn-clone", "indexmap", @@ -4736,9 +4754,9 @@ dependencies = [ [[package]] name = "schemars_derive" -version = "0.8.8" +version = "0.8.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41ae4dce13e8614c46ac3c38ef1c0d668b101df6ac39817aebdaa26642ddae9b" +checksum = "af4d7e1b012cb3d9129567661a63755ea4b8a7386d339dc945ae187e403c6743" dependencies = [ "proc-macro2", "quote", @@ -4822,22 +4840,13 @@ dependencies = [ "libc", ] -[[package]] -name = "semver" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" -dependencies = [ - "semver-parser 0.7.0", -] - [[package]] name = "semver" version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f301af10236f6df4160f7c3f04eec6dbc70ace82d23326abad5edee88801c6b6" dependencies = [ - "semver-parser 0.10.2", + "semver-parser", ] [[package]] @@ -4846,12 +4855,6 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d65bd28f48be7196d222d95b9243287f48d27aca604e08497513019ff0502cc4" -[[package]] -name = "semver-parser" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" - [[package]] name = "semver-parser" version = "0.10.2" @@ -4917,9 +4920,9 @@ dependencies = [ [[package]] name = "serde_derive_internals" -version = "0.25.0" +version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1dbab34ca63057a1f15280bdf3c39f2b1eb1b54c17e98360e511637aef7418c6" +checksum = "85bf8229e7920a9f636479437026331ce11aa132b4dde37d121944a44d6e5f3c" dependencies = [ "proc-macro2", "quote", @@ -5030,21 +5033,6 @@ dependencies = [ "digest 0.10.3", ] -[[package]] -name = "sha1" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1da05c97445caa12d05e848c4a4fcbbea29e748ac28f7e80e9b010392063770" -dependencies = [ - "sha1_smol", -] - -[[package]] -name = "sha1_smol" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae1a47186c03a32177042e55dbc5fd5aee900b8e0069a8d70fba96a9375cd012" - [[package]] name = "sha2" version = "0.9.9" @@ -5058,6 +5046,17 @@ dependencies = [ "opaque-debug 0.3.0", ] +[[package]] +name = "sha2" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55deaec60f81eefe3cce0dc50bda92d6d8e88f2a27df7c5033b42afeb1ed2676" +dependencies = [ + "cfg-if 1.0.0", + "cpufeatures", + "digest 0.10.3", +] + [[package]] name = "sha3" version = "0.9.1" @@ -5208,7 +5207,7 @@ dependencies = [ "log", "rand 0.7.3", "rand_distr", - "sha2", + "sha2 0.9.9", "subtle 2.4.1", ] @@ -5291,7 +5290,7 @@ dependencies = [ "paste", "percent-encoding", "rustls", - "sha2", + "sha2 0.9.9", "smallvec 1.8.0", "sqlformat", "sqlx-rt", @@ -5315,7 +5314,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "sha2", + "sha2 0.9.9", "sqlx-core", "sqlx-rt", "syn", @@ -5342,20 +5341,11 @@ dependencies = [ "memchr", ] -[[package]] -name = "standback" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e113fb6f3de07a243d434a56ec6f186dfd51cb08448239fe7bcae73f87ff28ff" -dependencies = [ - "version_check", -] - [[package]] name = "state" -version = "0.5.2" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87cf4f5369e6d3044b5e365c9690f451516ac8f0954084622b49ea3fde2f6de5" +checksum = "dbe866e1e51e8260c9eed836a042a5e7f6726bb2b411dffeaa712e19c388f23b" dependencies = [ "loom", ] @@ -5381,55 +5371,6 @@ dependencies = [ "tokio", ] -[[package]] -name = "stdweb" -version = "0.4.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d022496b16281348b52d0e30ae99e01a73d737b2f45d38fed4edf79f9325a1d5" -dependencies = [ - "discard", - "rustc_version 0.2.3", - "stdweb-derive", - "stdweb-internal-macros", - "stdweb-internal-runtime", - "wasm-bindgen", -] - -[[package]] -name = "stdweb-derive" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c87a60a40fccc84bef0652345bbbbbe20a605bf5d0ce81719fc476f5c03b50ef" -dependencies = [ - "proc-macro2", - "quote", - "serde", - "serde_derive", - "syn", -] - -[[package]] -name = "stdweb-internal-macros" -version = "0.2.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58fa5ff6ad0d98d1ffa8cb115892b6e69d67799f6763e162a1c9db421dc22e11" -dependencies = [ - "base-x", - "proc-macro2", - "quote", - "serde", - "serde_derive", - "serde_json", - "sha1", - "syn", -] - -[[package]] -name = "stdweb-internal-runtime" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "213701ba3370744dcd1a12960caa4843b3d68b4d1c0a5d575e0d65b2ee9d16c0" - [[package]] name = "stringprep" version = "0.1.2" @@ -5569,7 +5510,7 @@ dependencies = [ "serde_bytes", "serde_json", "serde_repr", - "sha2", + "sha2 0.9.9", "signature", "subtle 2.4.1", "subtle-encoding", @@ -5707,21 +5648,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "time" -version = "0.2.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4752a97f8eebd6854ff91f1c1824cd6160626ac4bd44287f7f4ea2035a02a242" -dependencies = [ - "const_fn", - "libc", - "standback", - "stdweb", - "time-macros 0.1.1", - "version_check", - "winapi", -] - [[package]] name = "time" version = "0.3.9" @@ -5732,17 +5658,7 @@ dependencies = [ "libc", "num_threads", "serde", - "time-macros 0.2.4", -] - -[[package]] -name = "time-macros" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "957e9c6e26f12cb6d0dd7fc776bb67a706312e7299aed74c8dd5b17ebb27e2f1" -dependencies = [ - "proc-macro-hack", - "time-macros-impl", + "time-macros", ] [[package]] @@ -5751,19 +5667,6 @@ version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42657b1a6f4d817cda8e7a0ace261fe0cc946cf3a80314390b22cc61ae080792" -[[package]] -name = "time-macros-impl" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd3c141a1b43194f3f56a1411225df8646c55781d5f26db825b3d98507eb482f" -dependencies = [ - "proc-macro-hack", - "proc-macro2", - "quote", - "standback", - "syn", -] - [[package]] name = "tiny-keccak" version = "2.0.2" @@ -6249,6 +6152,16 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "39ec24b3121d976906ece63c9daad25b85969647682eee313cb5779fdd69e14e" +[[package]] +name = "universal-hash" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f214e8f697e925001e66ec2c6e37a4ef93f0f78c2eed7814394e10c62025b05" +dependencies = [ + "generic-array 0.14.5", + "subtle 2.4.1", +] + [[package]] name = "untrusted" version = "0.7.1" @@ -6316,7 +6229,7 @@ dependencies = [ "reqwest", "serde", "serde_json", - "sha2", + "sha2 0.9.9", "thiserror", "tokio", "ts-rs", @@ -6356,7 +6269,7 @@ dependencies = [ "enum-iterator", "getset", "git2", - "rustc_version 0.4.0", + "rustc_version", "rustversion", "thiserror", ] diff --git a/clients/client-core/Cargo.toml b/clients/client-core/Cargo.toml index ddd6d14ef9..8d2d453dac 100644 --- a/clients/client-core/Cargo.toml +++ b/clients/client-core/Cargo.toml @@ -32,4 +32,4 @@ validator-client = { path = "../../common/client-libs/validator-client" } tempfile = "3.1.0" [features] -coconut = ["gateway-client/coconut", "gateway-requests/coconut"] \ No newline at end of file +coconut = ["gateway-client/coconut", "gateway-requests/coconut"] diff --git a/clients/credential/Cargo.toml b/clients/credential/Cargo.toml index 5d2d4d8142..4b975aacf5 100644 --- a/clients/credential/Cargo.toml +++ b/clients/credential/Cargo.toml @@ -26,4 +26,4 @@ pemstore = { path = "../../common/pemstore" } validator-client = { path = "../../common/client-libs/validator-client", features = ["nymd-client"] } [features] -coconut = ["credentials/coconut"] \ No newline at end of file +coconut = ["credentials/coconut"] diff --git a/clients/native/Cargo.toml b/clients/native/Cargo.toml index 661af318c9..18c156975c 100644 --- a/clients/native/Cargo.toml +++ b/clients/native/Cargo.toml @@ -55,4 +55,4 @@ eth = [] serde_json = "1.0" # for the "textsend" example [build-dependencies] -vergen = { version = "5", default-features = false, features = ["build", "git", "rustc", "cargo"] } \ No newline at end of file +vergen = { version = "5", default-features = false, features = ["build", "git", "rustc", "cargo"] } diff --git a/clients/native/websocket-requests/Cargo.toml b/clients/native/websocket-requests/Cargo.toml index 74bb1ee500..a2689476bc 100644 --- a/clients/native/websocket-requests/Cargo.toml +++ b/clients/native/websocket-requests/Cargo.toml @@ -10,4 +10,4 @@ edition = "2021" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" -nymsphinx = { path = "../../../common/nymsphinx" } \ No newline at end of file +nymsphinx = { path = "../../../common/nymsphinx" } diff --git a/clients/socks5/Cargo.toml b/clients/socks5/Cargo.toml index 1ac917a7cf..504a5d7518 100644 --- a/clients/socks5/Cargo.toml +++ b/clients/socks5/Cargo.toml @@ -47,4 +47,4 @@ coconut = ["coconut-interface", "credentials", "gateway-requests/coconut", "gate eth = [] [build-dependencies] -vergen = { version = "5", default-features = false, features = ["build", "git", "rustc", "cargo"] } \ No newline at end of file +vergen = { version = "5", default-features = false, features = ["build", "git", "rustc", "cargo"] } diff --git a/common/client-libs/gateway-client/Cargo.toml b/common/client-libs/gateway-client/Cargo.toml index 8e22cd012e..2cd7388139 100644 --- a/common/client-libs/gateway-client/Cargo.toml +++ b/common/client-libs/gateway-client/Cargo.toml @@ -74,4 +74,4 @@ features = ["js"] [features] coconut = ["gateway-requests/coconut", "coconut-interface", "validator-client", "credentials/coconut"] wasm = ["web3/wasm", "web3/http", "web3/signing"] -default = ["web3/default"] \ No newline at end of file +default = ["web3/default"] diff --git a/common/cosmwasm-smart-contracts/multisig-contract/Cargo.toml b/common/cosmwasm-smart-contracts/multisig-contract/Cargo.toml index 2a063367ba..cb3c2c0cb1 100644 --- a/common/cosmwasm-smart-contracts/multisig-contract/Cargo.toml +++ b/common/cosmwasm-smart-contracts/multisig-contract/Cargo.toml @@ -11,4 +11,4 @@ cw3 = { version = "0.13.1" } cw4 = { version = "0.13.1" } cosmwasm-std = "1.0.0" schemars = "0.8" -serde = { version = "1.0.103", default-features = false, features = ["derive"] } \ No newline at end of file +serde = { version = "1.0.103", default-features = false, features = ["derive"] } diff --git a/common/credential-storage/Cargo.toml b/common/credential-storage/Cargo.toml index 70d18c4716..8b797fb74a 100644 --- a/common/credential-storage/Cargo.toml +++ b/common/credential-storage/Cargo.toml @@ -17,4 +17,4 @@ tokio = { version = "1.19.1", features = [ "rt-multi-thread", "net", "signal", " [build-dependencies] sqlx = { version = "0.5", features = ["runtime-tokio-rustls", "sqlite", "macros", "migrate"] } -tokio = { version = "1.19.1", features = ["rt-multi-thread", "macros"] } \ No newline at end of file +tokio = { version = "1.19.1", features = ["rt-multi-thread", "macros"] } diff --git a/common/credentials/Cargo.toml b/common/credentials/Cargo.toml index a579b69a6c..94dc68b785 100644 --- a/common/credentials/Cargo.toml +++ b/common/credentials/Cargo.toml @@ -21,4 +21,4 @@ validator-client = { path = "../client-libs/validator-client" } rand = "0.7.3" [features] -coconut = ["cosmrs"] \ No newline at end of file +coconut = ["cosmrs"] diff --git a/common/crypto/dkg/Cargo.toml b/common/crypto/dkg/Cargo.toml index 610e41be19..c6e3edefd4 100644 --- a/common/crypto/dkg/Cargo.toml +++ b/common/crypto/dkg/Cargo.toml @@ -38,4 +38,4 @@ criterion = "0.3" [[bench]] name = "benchmarks" -harness = false \ No newline at end of file +harness = false diff --git a/common/nymsphinx/addressing/Cargo.toml b/common/nymsphinx/addressing/Cargo.toml index 8527e1bed0..a67849b128 100644 --- a/common/nymsphinx/addressing/Cargo.toml +++ b/common/nymsphinx/addressing/Cargo.toml @@ -12,4 +12,4 @@ nymsphinx-types = { path = "../types" } # we need to be able to refer to some ty serde = "1.0" # implementing serialization/deserialization for some types, like `Recipient` [dev-dependencies] -rand = "0.7" \ No newline at end of file +rand = "0.7" diff --git a/common/nymsphinx/cover/Cargo.toml b/common/nymsphinx/cover/Cargo.toml index bb58af09b7..6fd629ade7 100644 --- a/common/nymsphinx/cover/Cargo.toml +++ b/common/nymsphinx/cover/Cargo.toml @@ -16,4 +16,4 @@ nymsphinx-chunking = { path = "../chunking" } nymsphinx-params = { path = "../params" } nymsphinx-forwarding = { path = "../forwarding" } nymsphinx-types = { path = "../types" } -topology = { path = "../../topology" } \ No newline at end of file +topology = { path = "../../topology" } diff --git a/common/nymsphinx/params/Cargo.toml b/common/nymsphinx/params/Cargo.toml index b00f472ff4..a06f897f22 100644 --- a/common/nymsphinx/params/Cargo.toml +++ b/common/nymsphinx/params/Cargo.toml @@ -8,4 +8,4 @@ edition = "2021" [dependencies] crypto = { path = "../../crypto", features = ["hashing", "symmetric"] } -nymsphinx-types = { path = "../types" } \ No newline at end of file +nymsphinx-types = { path = "../types" } diff --git a/common/socks5/proxy-helpers/Cargo.toml b/common/socks5/proxy-helpers/Cargo.toml index 71a4cebb23..92ac6a2bae 100644 --- a/common/socks5/proxy-helpers/Cargo.toml +++ b/common/socks5/proxy-helpers/Cargo.toml @@ -18,4 +18,4 @@ socks5-requests = { path = "../requests" } ordered-buffer = { path = "../ordered-buffer" } [dev-dependencies] -tokio-test = "0.4.2" \ No newline at end of file +tokio-test = "0.4.2" diff --git a/common/version-checker/Cargo.toml b/common/version-checker/Cargo.toml index e6ccdbf241..9bc3c16ccf 100644 --- a/common/version-checker/Cargo.toml +++ b/common/version-checker/Cargo.toml @@ -7,4 +7,4 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -semver = "0.11" \ No newline at end of file +semver = "0.11" diff --git a/common/wasm-utils/Cargo.toml b/common/wasm-utils/Cargo.toml index 30f61734b2..1a19af2a8b 100644 --- a/common/wasm-utils/Cargo.toml +++ b/common/wasm-utils/Cargo.toml @@ -29,4 +29,4 @@ features = [ "ProgressEvent", "WebSocket", "Window", -] \ No newline at end of file +] diff --git a/explorer-api/Cargo.toml b/explorer-api/Cargo.toml index 58096adee4..7e0400693f 100644 --- a/explorer-api/Cargo.toml +++ b/explorer-api/Cargo.toml @@ -14,9 +14,9 @@ log = "0.4.0" okapi = { version = "0.7.0-rc.1", features = ["impl_json_schema"] } pretty_env_logger = "0.4.0" reqwest = "0.11.4" -rocket = {version = "0.5.0-rc.1", features=["json"] } +rocket = { version = "0.5.0-rc.2", features = ["json"] } rocket_cors = { git="https://github.com/lawliet89/rocket_cors", rev="dfd3662c49e2f6fc37df35091cb94d82f7fb5915" } -rocket_okapi = { version = "0.8.0-rc.1", features = ["swagger"] } +rocket_okapi = { version = "0.8.0-rc.2", features = ["swagger"] } schemars = { version = "0.8", features = ["preserve_order"] } serde = "1.0.126" serde_json = "1.0.66" diff --git a/mixnode/Cargo.toml b/mixnode/Cargo.toml index 3c99624cb5..8043ee96f2 100644 --- a/mixnode/Cargo.toml +++ b/mixnode/Cargo.toml @@ -26,7 +26,7 @@ humantime-serde = "1.0" log = "0.4.0" pretty_env_logger = "0.4.0" rand = "0.7.3" -rocket = { version="0.5.0-rc.1", features = ["json"] } +rocket = { version = "0.5.0-rc.2", features = ["json"] } serde = { version="1.0", features = ["derive"] } tokio = { version="1.19.1", features = ["rt-multi-thread", "net", "signal"] } tokio-util = { version="0.7.3", features = ["codec"] } diff --git a/service-providers/network-statistics/Cargo.toml b/service-providers/network-statistics/Cargo.toml index 6efd30a2c2..94e16ac6fe 100644 --- a/service-providers/network-statistics/Cargo.toml +++ b/service-providers/network-statistics/Cargo.toml @@ -9,7 +9,7 @@ edition = "2021" dirs = "3.0" log = "0.4" pretty_env_logger = "0.4" -rocket = { version = "0.5.0-rc.1", features = ["json"] } +rocket = { version = "0.5.0-rc.2", features = ["json"] } serde = { version = "1.0", features = ["derive"] } sqlx = { version = "0.5", features = ["runtime-tokio-rustls", "sqlite", "macros", "migrate", "chrono"]} thiserror = "1" diff --git a/validator-api/Cargo.toml b/validator-api/Cargo.toml index bd4a937535..1c4f97c8d3 100644 --- a/validator-api/Cargo.toml +++ b/validator-api/Cargo.toml @@ -27,7 +27,7 @@ pretty_env_logger = "0.4" rand = "0.8" rand-07 = { package = "rand", version = "0.7" } # required for compatibility reqwest = { version = "0.11", features = ["json"] } -rocket = { version = "0.5.0-rc.1", features = ["json"] } +rocket = { version = "0.5.0-rc.2", features = ["json"] } rocket_cors = { git="https://github.com/lawliet89/rocket_cors", rev="dfd3662c49e2f6fc37df35091cb94d82f7fb5915" } serde = "1.0" serde_json = "1.0" @@ -42,11 +42,11 @@ ts-rs = "6.1.2" anyhow = "1" getset = "0.1.1" -rocket_sync_db_pools = { version = "0.1.0-rc.1", default-features = false } +rocket_sync_db_pools = { version = "0.1.0-rc.2", default-features = false } sqlx = { version = "0.5", features = ["runtime-tokio-rustls", "sqlite", "macros", "migrate"]} okapi = { version = "0.7.0-rc.1", features = ["impl_json_schema"] } -rocket_okapi = { version = "0.8.0-rc.1", features = ["swagger"] } +rocket_okapi = { version = "0.8.0-rc.2", features = ["swagger"] } schemars = { version = "0.8", features = ["preserve_order"] } ## internal