From df827b6b0978173c6c1451593894b7666045689a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jon=20H=C3=A4ggblad?= Date: Fri, 25 Mar 2022 09:23:57 +0100 Subject: [PATCH 01/12] validator-client: rework connection tester --- Cargo.lock | 2 + .../client-libs/validator-client/Cargo.toml | 2 + .../validator-client/src/connection_tester.rs | 182 ++++++++++++++ .../client-libs/validator-client/src/lib.rs | 1 + nym-wallet/Cargo.lock | 10 + nym-wallet/src-tauri/Cargo.toml | 2 + nym-wallet/src-tauri/src/config/mod.rs | 11 +- nym-wallet/src-tauri/src/main.rs | 1 + .../src/operations/mixnet/account.rs | 225 +++++++----------- 9 files changed, 298 insertions(+), 138 deletions(-) create mode 100644 common/client-libs/validator-client/src/connection_tester.rs diff --git a/Cargo.lock b/Cargo.lock index e4ddeafe0a..287af42ae0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6072,6 +6072,7 @@ dependencies = [ "cosmrs", "cosmwasm-std", "flate2", + "futures", "itertools", "log", "mixnet-contract-common", @@ -6082,6 +6083,7 @@ dependencies = [ "serde_json", "sha2", "thiserror", + "tokio", "ts-rs", "url", "validator-api-requests", diff --git a/common/client-libs/validator-client/Cargo.toml b/common/client-libs/validator-client/Cargo.toml index 18322bac61..3755d9ee39 100644 --- a/common/client-libs/validator-client/Cargo.toml +++ b/common/client-libs/validator-client/Cargo.toml @@ -18,6 +18,8 @@ reqwest = { version = "0.11", features = ["json"] } thiserror = "1" log = "0.4" url = { version = "2.2", features = ["serde"] } +tokio = { version = "1.10", features = ["sync", "time"] } +futures = "0.3" coconut-interface = { path = "../../coconut-interface" } network-defaults = { path = "../../network-defaults" } diff --git a/common/client-libs/validator-client/src/connection_tester.rs b/common/client-libs/validator-client/src/connection_tester.rs new file mode 100644 index 0000000000..f76b028705 --- /dev/null +++ b/common/client-libs/validator-client/src/connection_tester.rs @@ -0,0 +1,182 @@ +use crate::nymd::error::NymdError; +use crate::nymd::{NymdClient, QueryNymdClient}; +use crate::ApiClient; +use network_defaults::all::Network; + +use core::fmt; +use itertools::Itertools; +use std::collections::HashMap; +use std::hash::BuildHasher; +use std::time::Duration; +use tokio::time::timeout; +use url::Url; + +// Run connection tests for all specified nymd and api urls. These are all run concurrently. +pub async fn run_validator_connection_test( + nymd_urls: impl Iterator, + api_urls: impl Iterator, + mixnet_contract_address: HashMap, H>, +) -> ( + HashMap>, + HashMap>, +) { + // Setup all the clients for the connection tests + let connection_test_clients = { + let nymd_connection_test_clients = nymd_urls.filter_map(|(network, url)| { + let address = mixnet_contract_address + .get(&network) + .expect("No configured contract address") + .clone(); + NymdClient::::connect(url.as_str(), address, None, None) + .map(move |client| ClientForConnectionTest::Nymd(network, url, Box::new(client))) + .ok() + }); + + let api_connection_test_clients = api_urls.map(|(network, url)| { + ClientForConnectionTest::Api(network, url.clone(), ApiClient::new(url)) + }); + + nymd_connection_test_clients.chain(api_connection_test_clients) + }; + + // Run all tests async + let connection_results = futures::future::join_all( + connection_test_clients + .into_iter() + .map(ClientForConnectionTest::run_connection_check), + ) + .await; + + // Seperate and collect results into HashMaps + let (nymd_urls, api_urls) = { + ( + connection_results + .iter() + .filter(|c| c.url_type() == UrlType::Nymd) + .map(|c| { + let (network, url, result) = c.result(); + (*network, (url.clone(), *result)) + }) + .into_group_map(), + connection_results + .iter() + .filter(|c| c.url_type() == UrlType::Api) + .map(|c| { + let (network, url, result) = c.result(); + (*network, (url.clone(), *result)) + }) + .into_group_map(), + ) + }; + + (nymd_urls, api_urls) +} + +enum ClientForConnectionTest { + Nymd(Network, Url, Box>), + Api(Network, Url, ApiClient), +} + +impl ClientForConnectionTest { + async fn run_connection_check(self) -> ConnectionResult { + match self { + ClientForConnectionTest::Nymd(network, ref url, ref client) => { + log::info!("{network}: {url}: checking nymd connection"); + let result = match client.get_mixnet_contract_version().await { + Err(NymdError::TendermintError(e)) => { + // If we get a tendermint-rpc error, we classify the node as not contactable + log::debug!("{network}: {url}: nymd connection test failed: {}", e); + false + } + Err(NymdError::AbciError(code, log)) => { + // We accept the mixnet contract not found as ok from a connection standpoint. This happens + // for example on a pre-launch network. + log::debug!("{network}: {url}: nymd abci error: {code}: {log}"); + code == 18 + } + Err(error @ NymdError::NoContractAddressAvailable) => { + log::debug!("{network}: {url}: nymd connection test failed: {error}"); + false + } + Err(e) => { + // For any other error, we're optimistic and just try anyway. + log::debug!("{network}: {url}: nymd connection test response ok, but with error: {e}"); + true + } + Ok(_) => { + log::debug!("{network}: {url}: nymd connection successful"); + true + } + }; + ConnectionResult::Nymd(network, url.clone(), result) + } + ClientForConnectionTest::Api(network, ref url, ref client) => { + log::info!("{network}: {url}: checking api connection"); + let result = + match timeout(Duration::from_secs(2), client.get_cached_mixnodes()).await { + Ok(Ok(_)) => { + log::debug!("{network}: {url}: api connection successful"); + true + } + Ok(Err(e)) => { + log::debug!("{network}: {url}: api connection failed: {e}"); + false + } + Err(e) => { + log::debug!("{network}: {url}: api connection failed: {e}"); + false + } + }; + ConnectionResult::Api(network, url.clone(), result) + } + } + } +} + +#[derive(Debug, PartialEq, Eq)] +enum UrlType { + Nymd, + Api, +} + +impl fmt::Display for UrlType { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + UrlType::Nymd => write!(f, "nymd"), + UrlType::Api => write!(f, "api"), + } + } +} + +#[derive(Debug)] +enum ConnectionResult { + Nymd(Network, Url, bool), + Api(Network, Url, bool), +} + +impl ConnectionResult { + fn result(&self) -> (&Network, &Url, &bool) { + match self { + ConnectionResult::Nymd(network, url, result) + | ConnectionResult::Api(network, url, result) => (network, url, result), + } + } + + fn url_type(&self) -> UrlType { + match self { + ConnectionResult::Nymd(..) => UrlType::Nymd, + ConnectionResult::Api(..) => UrlType::Api, + } + } +} + +impl fmt::Display for ConnectionResult { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let (network, url, result) = self.result(); + let url_type = self.url_type(); + write!( + f, + "{network}: {url}: {url_type}: connection is successful: {result}" + ) + } +} diff --git a/common/client-libs/validator-client/src/lib.rs b/common/client-libs/validator-client/src/lib.rs index 251501114d..88fe66f12f 100644 --- a/common/client-libs/validator-client/src/lib.rs +++ b/common/client-libs/validator-client/src/lib.rs @@ -2,6 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 pub mod client; +pub mod connection_tester; mod error; #[cfg(feature = "nymd-client")] pub mod nymd; diff --git a/nym-wallet/Cargo.lock b/nym-wallet/Cargo.lock index 57fbcfafea..7bec54729a 100644 --- a/nym-wallet/Cargo.lock +++ b/nym-wallet/Cargo.lock @@ -1112,6 +1112,12 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bd0c93bb4b0c6d9b77f4435b0ae98c24d17f1c45b2ff844c6151a07256ca923b" +[[package]] +name = "dotenv" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77c90badedccf4105eca100756a0b1289e191f6fcbdadd3cee1d2f614f97da8f" + [[package]] name = "dtoa" version = "0.4.8" @@ -2753,8 +2759,10 @@ dependencies = [ "cosmrs", "cosmwasm-std", "dirs", + "dotenv", "eyre", "futures", + "itertools", "log", "mixnet-contract-common", "pretty_env_logger", @@ -5110,6 +5118,7 @@ dependencies = [ "cosmrs", "cosmwasm-std", "flate2", + "futures", "itertools", "log", "mixnet-contract-common", @@ -5120,6 +5129,7 @@ dependencies = [ "serde_json", "sha2 0.9.9", "thiserror", + "tokio", "url", "validator-api-requests", "vesting-contract", diff --git a/nym-wallet/src-tauri/Cargo.toml b/nym-wallet/src-tauri/Cargo.toml index ea18268b84..4512f63f89 100644 --- a/nym-wallet/src-tauri/Cargo.toml +++ b/nym-wallet/src-tauri/Cargo.toml @@ -22,8 +22,10 @@ tauri-macros = "=1.0.0-rc.1" bip39 = "1.0" cfg-if = "1.0.0" dirs = "4.0" +dotenv = "0.15.0" eyre = "0.6.5" futures = "0.3.15" +itertools = "0.10" log = "0.4" pretty_env_logger = "0.4" rand = "0.6.5" diff --git a/nym-wallet/src-tauri/src/config/mod.rs b/nym-wallet/src-tauri/src/config/mod.rs index ed93d1da46..da5f733fed 100644 --- a/nym-wallet/src-tauri/src/config/mod.rs +++ b/nym-wallet/src-tauri/src/config/mod.rs @@ -117,14 +117,15 @@ impl Config { .chain(base_validators) } - pub fn get_validators_with_api_endpoint( - &self, - network: WalletNetwork, - ) -> impl Iterator + '_ { + pub fn get_nymd_urls(&self, network: WalletNetwork) -> impl Iterator + '_ { + self.get_validators(network).into_iter().map(|v| v.nymd_url) + } + + pub fn get_api_urls(&self, network: WalletNetwork) -> impl Iterator + '_ { self .get_validators(network) .into_iter() - .filter_map(|validator| ValidatorUrlWithApiEndpoint::try_from(validator).ok()) + .filter_map(|v| v.api_url) } pub fn get_mixnet_contract_address(&self, network: WalletNetwork) -> Option { diff --git a/nym-wallet/src-tauri/src/main.rs b/nym-wallet/src-tauri/src/main.rs index 316db50ac7..47490e17ae 100644 --- a/nym-wallet/src-tauri/src/main.rs +++ b/nym-wallet/src-tauri/src/main.rs @@ -30,6 +30,7 @@ use crate::operations::vesting; use crate::state::State; fn main() { + dotenv::dotenv().ok(); setup_logging(); tauri::Builder::default() diff --git a/nym-wallet/src-tauri/src/operations/mixnet/account.rs b/nym-wallet/src-tauri/src/operations/mixnet/account.rs index 02b632466a..aff0883c9c 100644 --- a/nym-wallet/src-tauri/src/operations/mixnet/account.rs +++ b/nym-wallet/src-tauri/src/operations/mixnet/account.rs @@ -1,7 +1,7 @@ use crate::coin::{Coin, Denom}; -use crate::config::{Config, ValidatorUrlWithApiEndpoint}; +use crate::config::Config; use crate::error::BackendError; -use crate::network::Network; +use crate::network::Network as WalletNetwork; use crate::nymd_client; use crate::state::State; use crate::wallet_storage::{self, DEFAULT_WALLET_ACCOUNT_ID}; @@ -9,17 +9,20 @@ use crate::wallet_storage::{self, DEFAULT_WALLET_ACCOUNT_ID}; use bip39::{Language, Mnemonic}; use config::defaults::COSMOS_DERIVATION_PATH; use cosmrs::bip32::DerivationPath; +use config::defaults::all::Network; +use rand::seq::SliceRandom; use serde::{Deserialize, Serialize}; use std::collections::HashMap; use std::convert::TryInto; use std::str::FromStr; use std::sync::Arc; -use std::time::Duration; use strum::IntoEnumIterator; use tokio::sync::RwLock; -use validator_client::nymd::error::NymdError; -use validator_client::nymd::SigningNymdClient; -use validator_client::Client; +use url::Url; + +use validator_client::{ + connection_tester::run_validator_connection_test, nymd::SigningNymdClient, Client, +}; #[cfg_attr(test, derive(ts_rs::TS))] #[cfg_attr(test, ts(export, export_to = "../src/types/rust/account.ts"))] @@ -112,7 +115,7 @@ pub async fn create_new_mnemonic() -> Result { #[tauri::command] pub async fn switch_network( state: tauri::State<'_, Arc>>, - network: Network, + network: WalletNetwork, ) -> Result { let account = { let r_state = state.read().await; @@ -158,16 +161,34 @@ async fn _connect_with_mnemonic( state: tauri::State<'_, Arc>>, ) -> Result { update_validator_urls(state.clone()).await?; - let validators = choose_validators(mnemonic.clone(), &state).await?; - let config = state.read().await.config(); - let clients = create_clients(&validators, &mnemonic, &config)?; + + // Run connection tests on all nymd and validator-api endpoints + let (nymd_urls, api_urls) = { + let mixnet_contract_address = WalletNetwork::iter() + .map(|network| (network.into(), config.get_mixnet_contract_address(network))) + .collect::>(); + let nymd_urls = WalletNetwork::iter().flat_map(|network| { + config + .get_nymd_urls(network) + .map(move |url| (network.into(), url)) + }); + let api_urls = WalletNetwork::iter().flat_map(|network| { + config + .get_api_urls(network) + .map(move |url| (network.into(), url)) + }); + + run_validator_connection_test(nymd_urls, api_urls, mixnet_contract_address).await + }; + + let clients = create_clients(&nymd_urls, &api_urls, &mnemonic, &config)?; // Set the default account - let default_network: Network = config::defaults::DEFAULT_NETWORK.into(); + let default_network: WalletNetwork = config::defaults::DEFAULT_NETWORK.into(); let client_for_default_network = clients .iter() - .find(|client| Network::from(client.network) == default_network); + .find(|client| WalletNetwork::from(client.network) == default_network); let account_for_default_network = match client_for_default_network { Some(client) => Ok(Account::new( client.nymd.mixnet_contract_address()?.to_string(), @@ -181,7 +202,7 @@ async fn _connect_with_mnemonic( // Register all the clients for client in clients { - let network: Network = client.network.into(); + let network: WalletNetwork = client.network.into(); let mut w_state = state.write().await; w_state.add_client(network, client); } @@ -189,18 +210,72 @@ async fn _connect_with_mnemonic( account_for_default_network } +fn select_random_responding_nymd_url( + nymd_urls: &HashMap>, + network: WalletNetwork, + config: &Config, +) -> Url { + // We pick a randon responding nymd url, and if not, fall back on the first one in the list. + nymd_urls + .get(&network.into()) + .and_then(|urls| { + let nymd_urls: Vec<_> = urls + .iter() + .filter_map(|(url, result)| if *result { Some(url.clone()) } else { None }) + .collect(); + nymd_urls.choose(&mut rand::thread_rng()).cloned() + }) + .unwrap_or_else(|| { + log::debug!("{network}: nymd_url: using default"); + config + .get_nymd_urls(network) + .next() + .expect("Expected at least one hardcoded nymd url") + }) +} + +fn select_first_responding_api_url( + api_urls: &HashMap>, + network: WalletNetwork, + config: &Config, +) -> Url { + // We pick the first API url among the responding ones. If none exists, fall back on the first + // one in the list. + api_urls + .get(&network.into()) + .and_then(|urls| { + urls + .iter() + .find_map(|(url, result)| if *result { Some(url.clone()) } else { None }) + }) + .unwrap_or_else(|| { + log::debug!("{network}: api_url: using default"); + config + .get_api_urls(network) + .next() + .expect("Expected at least one hardcoded api url") + }) +} + fn create_clients( - validators: &HashMap, + nymd_urls: &HashMap>, + api_urls: &HashMap>, mnemonic: &Mnemonic, config: &Config, ) -> Result>, BackendError> { let mut clients = Vec::new(); - for network in Network::iter() { + for network in WalletNetwork::iter() { + let nymd_url = select_random_responding_nymd_url(nymd_urls, network, config); + let api_url = select_first_responding_api_url(api_urls, network, config); + + log::info!("{network}: nymd_url: using: {nymd_url}"); + log::info!("{network}: api_url: using: {api_url}"); + let client = validator_client::Client::new_signing( validator_client::Config::new( network.into(), - validators[&network].nymd_url.clone(), - validators[&network].api_url.clone(), + nymd_url, + api_url, config.get_mixnet_contract_address(network), config.get_vesting_contract_address(network), config.get_bandwidth_claim_contract_address(network), @@ -212,122 +287,6 @@ fn create_clients( Ok(clients) } -async fn choose_validators( - mnemonic: Mnemonic, - state: &tauri::State<'_, Arc>>, -) -> Result, BackendError> { - let config = state.read().await.config(); - - // Try to connect to validators on all networks - let mut validators = select_responding_validators(&config, &mnemonic).await?; - - // If for a network we didn't manage to connect to any validators, just go ahead and try with the - // first in the list - for network in Network::iter() { - validators.entry(network).or_insert_with(|| { - let default_validator = config - .get_validators_with_api_endpoint(network) - .next() - // We always have at least one hardcoded default validator - .unwrap(); - log::info!( - "Using default for {network}: {}, {}", - default_validator.nymd_url, - default_validator.api_url, - ); - default_validator - }); - } - Ok(validators) -} - -// For each network, try the list of available validators one by one and use the first responding -// one. -async fn select_responding_validators( - config: &Config, - mnemonic: &Mnemonic, -) -> Result, BackendError> { - use tokio::time::timeout; - let validators = futures::future::join_all(Network::iter().map(|network| { - timeout( - Duration::from_millis(3000), - try_connect_to_validators( - config.get_validators_with_api_endpoint(network), - config, - network, - mnemonic.clone(), - ), - ) - })) - .await; - - // Drop networks that failed the global timeout - let validators = validators.into_iter().filter_map(Result::ok); - - // Rewrap to return any errors during client creation - let validators = validators.collect::, _>>()?; - - // Filter out networks where we exhausted all listed validators - let validators = validators.into_iter().flatten(); - - Ok(validators.collect::>()) -} - -async fn try_connect_to_validators( - validators: impl Iterator, - config: &Config, - network: Network, - mnemonic: Mnemonic, -) -> Result, BackendError> { - for validator in validators { - if let Some(responding_validator) = - try_connect_to_validator(&validator, config, network, mnemonic.clone()).await? - { - // Pick the first successful one - return Ok(Some(responding_validator)); - } - } - Ok(None) -} - -async fn try_connect_to_validator( - validator: &ValidatorUrlWithApiEndpoint, - config: &Config, - network: Network, - mnemonic: Mnemonic, -) -> Result, BackendError> { - let client = validator_client::Client::new_signing( - validator_client::Config::new( - network.into(), - validator.nymd_url.clone(), - validator.api_url.clone(), - config.get_mixnet_contract_address(network), - config.get_vesting_contract_address(network), - config.get_bandwidth_claim_contract_address(network), - ), - mnemonic, - )?; - - if is_validator_connection_ok(&client).await { - log::info!( - "Connection ok for {network}: {}, {}", - validator.nymd_url, - validator.api_url - ); - Ok(Some((network, validator.clone()))) - } else { - Ok(None) - } -} - -// The criteria used to determina if a validator endpoint is to be used -async fn is_validator_connection_ok(client: &Client) -> bool { - match client.get_mixnet_contract_version().await { - Err(NymdError::TendermintError(_)) => false, - Err(_) | Ok(_) => true, - } -} - #[tauri::command] pub fn does_password_file_exist() -> Result { log::info!("Checking wallet file"); From dd82b24d6175cd76a8be7ed4b9c533a8e38b16c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jon=20H=C3=A4ggblad?= Date: Mon, 28 Mar 2022 16:04:01 +0200 Subject: [PATCH 02/12] wallet: skip duplicate validator url entries --- .../client-libs/validator-client/src/connection_tester.rs | 1 + nym-wallet/src-tauri/src/config/mod.rs | 8 +++++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/common/client-libs/validator-client/src/connection_tester.rs b/common/client-libs/validator-client/src/connection_tester.rs index f76b028705..11d1dd70a4 100644 --- a/common/client-libs/validator-client/src/connection_tester.rs +++ b/common/client-libs/validator-client/src/connection_tester.rs @@ -43,6 +43,7 @@ pub async fn run_validator_connection_test( let connection_results = futures::future::join_all( connection_test_clients .into_iter() + .take(200) .map(ClientForConnectionTest::run_connection_check), ) .await; diff --git a/nym-wallet/src-tauri/src/config/mod.rs b/nym-wallet/src-tauri/src/config/mod.rs index da5f733fed..ed10e3d11b 100644 --- a/nym-wallet/src-tauri/src/config/mod.rs +++ b/nym-wallet/src-tauri/src/config/mod.rs @@ -4,6 +4,7 @@ use crate::{error::BackendError, network::Network as WalletNetwork}; use config::defaults::{all::SupportedNetworks, ValidatorDetails}; use config::NymConfig; +use itertools::Itertools; use reqwest::StatusCode; use serde::{Deserialize, Serialize}; use std::collections::HashMap; @@ -115,6 +116,7 @@ impl Config { .chain(self.network.validators(network)) .cloned() .chain(base_validators) + .unique() } pub fn get_nymd_urls(&self, network: WalletNetwork) -> impl Iterator + '_ { @@ -165,6 +167,10 @@ impl Config { let client = reqwest::Client::builder() .timeout(Duration::from_secs(3)) .build()?; + log::debug!( + "Fetching validator urls from: {}", + REMOTE_SOURCE_OF_VALIDATOR_URLS + ); let response = client .get(REMOTE_SOURCE_OF_VALIDATOR_URLS.to_string()) .send() @@ -224,7 +230,7 @@ impl Config { } } -#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)] +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, Hash)] pub struct ValidatorUrl { pub nymd_url: Url, pub api_url: Option, From cec749679448eb60d93ee1d325ca329ff96f37ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jon=20H=C3=A4ggblad?= Date: Mon, 28 Mar 2022 16:11:18 +0200 Subject: [PATCH 03/12] connection-tester: cap number of urls tested async --- common/client-libs/validator-client/src/connection_tester.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/common/client-libs/validator-client/src/connection_tester.rs b/common/client-libs/validator-client/src/connection_tester.rs index 11d1dd70a4..0e1d51577a 100644 --- a/common/client-libs/validator-client/src/connection_tester.rs +++ b/common/client-libs/validator-client/src/connection_tester.rs @@ -11,6 +11,8 @@ use std::time::Duration; use tokio::time::timeout; use url::Url; +const MAX_URLS_TESTED: usize = 200; + // Run connection tests for all specified nymd and api urls. These are all run concurrently. pub async fn run_validator_connection_test( nymd_urls: impl Iterator, @@ -43,7 +45,7 @@ pub async fn run_validator_connection_test( let connection_results = futures::future::join_all( connection_test_clients .into_iter() - .take(200) + .take(MAX_URLS_TESTED) .map(ClientForConnectionTest::run_connection_check), ) .await; From da18a60a9110b1eb8ed3e71df2c40b962c8641a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jon=20H=C3=A4ggblad?= Date: Mon, 28 Mar 2022 16:25:29 +0200 Subject: [PATCH 04/12] wallet: remove deprecated validator_health checks --- nym-wallet/src-tauri/src/config/mod.rs | 73 -------------------------- 1 file changed, 73 deletions(-) diff --git a/nym-wallet/src-tauri/src/config/mod.rs b/nym-wallet/src-tauri/src/config/mod.rs index ed10e3d11b..1299660f61 100644 --- a/nym-wallet/src-tauri/src/config/mod.rs +++ b/nym-wallet/src-tauri/src/config/mod.rs @@ -5,10 +5,7 @@ use crate::{error::BackendError, network::Network as WalletNetwork}; use config::defaults::{all::SupportedNetworks, ValidatorDetails}; use config::NymConfig; use itertools::Itertools; -use reqwest::StatusCode; use serde::{Deserialize, Serialize}; -use std::collections::HashMap; -use std::iter::zip; use std::time::Duration; use std::{fs, io, path::PathBuf}; use strum::IntoEnumIterator; @@ -178,56 +175,6 @@ impl Config { self.base.fetched_validators = serde_json::from_str(&response.text().await?)?; Ok(()) } - - pub async fn check_validator_health( - &self, - network: WalletNetwork, - ) -> Result, BackendError> { - // Limit the number of validators we query - let max_validators = 200_usize; - let validators_to_query = || self.get_validators(network).take(max_validators); - - let validator_urls = validators_to_query().map(|v| { - let mut health_url = v.nymd_url.clone(); - health_url.set_path("health"); - (v, health_url) - }); - - let client = reqwest::Client::builder() - .timeout(Duration::from_secs(3)) - .build()?; - - let requests = validator_urls.map(|(_, url)| client.get(url).send()); - let responses = futures::future::join_all(requests).await; - - let validators_responding_success = - zip(validators_to_query(), responses).filter_map(|(v, r)| match r { - Ok(r) if r.status().is_success() => Some((v, r.status())), - _ => None, - }); - - Ok(validators_responding_success.collect::>()) - } - - #[allow(unused)] - pub async fn check_validator_health_for_all_networks( - &self, - ) -> Result>, BackendError> { - let validator_health_requests = - WalletNetwork::iter().map(|network| self.check_validator_health(network)); - - let responses_keyed_by_network = zip( - WalletNetwork::iter(), - futures::future::join_all(validator_health_requests).await, - ); - - // Iterate and collect manually to be able to return errors in the response - let mut responses = HashMap::new(); - for (network, response) in responses_keyed_by_network { - responses.insert(network, response?); - } - Ok(responses) - } } #[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, Hash)] @@ -250,26 +197,6 @@ impl TryFrom for ValidatorUrl { } } -#[derive(Clone, Debug)] -pub struct ValidatorUrlWithApiEndpoint { - pub nymd_url: Url, - pub api_url: Url, -} - -impl TryFrom for ValidatorUrlWithApiEndpoint { - type Error = BackendError; - - fn try_from(validator: ValidatorUrl) -> Result { - match validator.api_url { - Some(api_url) => Ok(ValidatorUrlWithApiEndpoint { - nymd_url: validator.nymd_url, - api_url, - }), - None => Err(BackendError::NoValidatorApiUrlConfigured), - } - } -} - #[derive(Debug, Default, Deserialize, Serialize, Clone, PartialEq, Eq)] #[serde(deny_unknown_fields)] struct OptionalValidators { From d08bf619058d469da4d615553ccc7a76b39a85ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jon=20H=C3=A4ggblad?= Date: Mon, 28 Mar 2022 16:40:17 +0200 Subject: [PATCH 05/12] wallet: rustfmt --- nym-wallet/src-tauri/src/operations/mixnet/account.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nym-wallet/src-tauri/src/operations/mixnet/account.rs b/nym-wallet/src-tauri/src/operations/mixnet/account.rs index aff0883c9c..396d3913d0 100644 --- a/nym-wallet/src-tauri/src/operations/mixnet/account.rs +++ b/nym-wallet/src-tauri/src/operations/mixnet/account.rs @@ -7,9 +7,9 @@ use crate::state::State; use crate::wallet_storage::{self, DEFAULT_WALLET_ACCOUNT_ID}; use bip39::{Language, Mnemonic}; +use config::defaults::all::Network; use config::defaults::COSMOS_DERIVATION_PATH; use cosmrs::bip32::DerivationPath; -use config::defaults::all::Network; use rand::seq::SliceRandom; use serde::{Deserialize, Serialize}; use std::collections::HashMap; From 3f6cb919ac46e2af425558d863ec8e8d79e9e3e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jon=20H=C3=A4ggblad?= Date: Mon, 28 Mar 2022 17:40:04 +0200 Subject: [PATCH 06/12] connection-tester: extract or collection method --- .../validator-client/src/connection_tester.rs | 38 +++++++++---------- 1 file changed, 17 insertions(+), 21 deletions(-) diff --git a/common/client-libs/validator-client/src/connection_tester.rs b/common/client-libs/validator-client/src/connection_tester.rs index 0e1d51577a..390558d946 100644 --- a/common/client-libs/validator-client/src/connection_tester.rs +++ b/common/client-libs/validator-client/src/connection_tester.rs @@ -51,28 +51,24 @@ pub async fn run_validator_connection_test( .await; // Seperate and collect results into HashMaps - let (nymd_urls, api_urls) = { - ( - connection_results - .iter() - .filter(|c| c.url_type() == UrlType::Nymd) - .map(|c| { - let (network, url, result) = c.result(); - (*network, (url.clone(), *result)) - }) - .into_group_map(), - connection_results - .iter() - .filter(|c| c.url_type() == UrlType::Api) - .map(|c| { - let (network, url, result) = c.result(); - (*network, (url.clone(), *result)) - }) - .into_group_map(), - ) - }; + ( + extract_and_collect_results_into_map(&connection_results, &UrlType::Nymd), + extract_and_collect_results_into_map(&connection_results, &UrlType::Api), + ) +} - (nymd_urls, api_urls) +fn extract_and_collect_results_into_map( + connection_results: &[ConnectionResult], + url_type: &UrlType, +) -> HashMap> { + connection_results + .iter() + .filter(|c| &c.url_type() == url_type) + .map(|c| { + let (network, url, result) = c.result(); + (*network, (url.clone(), *result)) + }) + .into_group_map() } enum ClientForConnectionTest { From deefa090669f368af6872e14ff5e724443d5547b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jon=20H=C3=A4ggblad?= Date: Mon, 28 Mar 2022 17:50:29 +0200 Subject: [PATCH 07/12] connection-tester: extract out setup method --- .../validator-client/src/connection_tester.rs | 43 +++++++++++-------- 1 file changed, 25 insertions(+), 18 deletions(-) diff --git a/common/client-libs/validator-client/src/connection_tester.rs b/common/client-libs/validator-client/src/connection_tester.rs index 390558d946..362aa06bed 100644 --- a/common/client-libs/validator-client/src/connection_tester.rs +++ b/common/client-libs/validator-client/src/connection_tester.rs @@ -14,7 +14,7 @@ use url::Url; const MAX_URLS_TESTED: usize = 200; // Run connection tests for all specified nymd and api urls. These are all run concurrently. -pub async fn run_validator_connection_test( +pub async fn run_validator_connection_test( nymd_urls: impl Iterator, api_urls: impl Iterator, mixnet_contract_address: HashMap, H>, @@ -23,23 +23,8 @@ pub async fn run_validator_connection_test( HashMap>, ) { // Setup all the clients for the connection tests - let connection_test_clients = { - let nymd_connection_test_clients = nymd_urls.filter_map(|(network, url)| { - let address = mixnet_contract_address - .get(&network) - .expect("No configured contract address") - .clone(); - NymdClient::::connect(url.as_str(), address, None, None) - .map(move |client| ClientForConnectionTest::Nymd(network, url, Box::new(client))) - .ok() - }); - - let api_connection_test_clients = api_urls.map(|(network, url)| { - ClientForConnectionTest::Api(network, url.clone(), ApiClient::new(url)) - }); - - nymd_connection_test_clients.chain(api_connection_test_clients) - }; + let connection_test_clients = + setup_connection_tests(nymd_urls, api_urls, mixnet_contract_address); // Run all tests async let connection_results = futures::future::join_all( @@ -57,6 +42,28 @@ pub async fn run_validator_connection_test( ) } +fn setup_connection_tests( + nymd_urls: impl Iterator, + api_urls: impl Iterator, + mixnet_contract_address: HashMap, H>, +) -> impl Iterator { + let nymd_connection_test_clients = nymd_urls.filter_map(move |(network, url)| { + let address = mixnet_contract_address + .get(&network) + .expect("No configured contract address") + .clone(); + NymdClient::::connect(url.as_str(), address, None, None) + .map(move |client| ClientForConnectionTest::Nymd(network, url, Box::new(client))) + .ok() + }); + + let api_connection_test_clients = api_urls.map(|(network, url)| { + ClientForConnectionTest::Api(network, url.clone(), ApiClient::new(url)) + }); + + nymd_connection_test_clients.chain(api_connection_test_clients) +} + fn extract_and_collect_results_into_map( connection_results: &[ConnectionResult], url_type: &UrlType, From b759e5e7f22b17d2533c18768413fba112668b2c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jon=20H=C3=A4ggblad?= Date: Mon, 28 Mar 2022 17:54:16 +0200 Subject: [PATCH 08/12] connection-tester: extract out connection test methods --- .../validator-client/src/connection_tester.rs | 101 ++++++++++-------- 1 file changed, 56 insertions(+), 45 deletions(-) diff --git a/common/client-libs/validator-client/src/connection_tester.rs b/common/client-libs/validator-client/src/connection_tester.rs index 362aa06bed..0f48a4da62 100644 --- a/common/client-libs/validator-client/src/connection_tester.rs +++ b/common/client-libs/validator-client/src/connection_tester.rs @@ -83,57 +83,68 @@ enum ClientForConnectionTest { Api(Network, Url, ApiClient), } +async fn test_nymd_connection( + network: Network, + url: &Url, + client: &NymdClient, +) -> ConnectionResult { + log::info!("{network}: {url}: checking nymd connection"); + let result = match client.get_mixnet_contract_version().await { + Err(NymdError::TendermintError(e)) => { + // If we get a tendermint-rpc error, we classify the node as not contactable + log::debug!("{network}: {url}: nymd connection test failed: {}", e); + false + } + Err(NymdError::AbciError(code, log)) => { + // We accept the mixnet contract not found as ok from a connection standpoint. This happens + // for example on a pre-launch network. + log::debug!("{network}: {url}: nymd abci error: {code}: {log}"); + code == 18 + } + Err(error @ NymdError::NoContractAddressAvailable) => { + log::debug!("{network}: {url}: nymd connection test failed: {error}"); + false + } + Err(e) => { + // For any other error, we're optimistic and just try anyway. + log::debug!("{network}: {url}: nymd connection test response ok, but with error: {e}"); + true + } + Ok(_) => { + log::debug!("{network}: {url}: nymd connection successful"); + true + } + }; + ConnectionResult::Nymd(network, url.clone(), result) +} + +async fn test_api_connection(network: Network, url: &Url, client: &ApiClient) -> ConnectionResult { + log::info!("{network}: {url}: checking api connection"); + let result = match timeout(Duration::from_secs(2), client.get_cached_mixnodes()).await { + Ok(Ok(_)) => { + log::debug!("{network}: {url}: api connection successful"); + true + } + Ok(Err(e)) => { + log::debug!("{network}: {url}: api connection failed: {e}"); + false + } + Err(e) => { + log::debug!("{network}: {url}: api connection failed: {e}"); + false + } + }; + ConnectionResult::Api(network, url.clone(), result) +} + impl ClientForConnectionTest { async fn run_connection_check(self) -> ConnectionResult { match self { ClientForConnectionTest::Nymd(network, ref url, ref client) => { - log::info!("{network}: {url}: checking nymd connection"); - let result = match client.get_mixnet_contract_version().await { - Err(NymdError::TendermintError(e)) => { - // If we get a tendermint-rpc error, we classify the node as not contactable - log::debug!("{network}: {url}: nymd connection test failed: {}", e); - false - } - Err(NymdError::AbciError(code, log)) => { - // We accept the mixnet contract not found as ok from a connection standpoint. This happens - // for example on a pre-launch network. - log::debug!("{network}: {url}: nymd abci error: {code}: {log}"); - code == 18 - } - Err(error @ NymdError::NoContractAddressAvailable) => { - log::debug!("{network}: {url}: nymd connection test failed: {error}"); - false - } - Err(e) => { - // For any other error, we're optimistic and just try anyway. - log::debug!("{network}: {url}: nymd connection test response ok, but with error: {e}"); - true - } - Ok(_) => { - log::debug!("{network}: {url}: nymd connection successful"); - true - } - }; - ConnectionResult::Nymd(network, url.clone(), result) + test_nymd_connection(network, url, client).await } ClientForConnectionTest::Api(network, ref url, ref client) => { - log::info!("{network}: {url}: checking api connection"); - let result = - match timeout(Duration::from_secs(2), client.get_cached_mixnodes()).await { - Ok(Ok(_)) => { - log::debug!("{network}: {url}: api connection successful"); - true - } - Ok(Err(e)) => { - log::debug!("{network}: {url}: api connection failed: {e}"); - false - } - Err(e) => { - log::debug!("{network}: {url}: api connection failed: {e}"); - false - } - }; - ConnectionResult::Api(network, url.clone(), result) + test_api_connection(network, url, client).await } } } From 700f6a4e9896da54a7ec3937c7a3dd46bb69ebde Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jon=20H=C3=A4ggblad?= Date: Mon, 28 Mar 2022 18:00:45 +0200 Subject: [PATCH 09/12] connection-tester: add missing timeout for nymd test --- .../validator-client/src/connection_tester.rs | 49 ++++++++++++------- 1 file changed, 32 insertions(+), 17 deletions(-) diff --git a/common/client-libs/validator-client/src/connection_tester.rs b/common/client-libs/validator-client/src/connection_tester.rs index 0f48a4da62..92dd9d40b2 100644 --- a/common/client-libs/validator-client/src/connection_tester.rs +++ b/common/client-libs/validator-client/src/connection_tester.rs @@ -12,6 +12,7 @@ use tokio::time::timeout; use url::Url; const MAX_URLS_TESTED: usize = 200; +const CONNECTION_TEST_TIMEOUT_SEC: u64 = 2; // Run connection tests for all specified nymd and api urls. These are all run concurrently. pub async fn run_validator_connection_test( @@ -26,7 +27,7 @@ pub async fn run_validator_connection_test( let connection_test_clients = setup_connection_tests(nymd_urls, api_urls, mixnet_contract_address); - // Run all tests async + // Run all tests concurrently let connection_results = futures::future::join_all( connection_test_clients .into_iter() @@ -78,65 +79,79 @@ fn extract_and_collect_results_into_map( .into_group_map() } -enum ClientForConnectionTest { - Nymd(Network, Url, Box>), - Api(Network, Url, ApiClient), -} - async fn test_nymd_connection( network: Network, url: &Url, client: &NymdClient, ) -> ConnectionResult { log::info!("{network}: {url}: checking nymd connection"); - let result = match client.get_mixnet_contract_version().await { - Err(NymdError::TendermintError(e)) => { + let result = match timeout( + Duration::from_secs(CONNECTION_TEST_TIMEOUT_SEC), + client.get_mixnet_contract_version(), + ) + .await + { + Ok(Err(NymdError::TendermintError(e))) => { // If we get a tendermint-rpc error, we classify the node as not contactable log::debug!("{network}: {url}: nymd connection test failed: {}", e); false } - Err(NymdError::AbciError(code, log)) => { + Ok(Err(NymdError::AbciError(code, log))) => { // We accept the mixnet contract not found as ok from a connection standpoint. This happens // for example on a pre-launch network. log::debug!("{network}: {url}: nymd abci error: {code}: {log}"); code == 18 } - Err(error @ NymdError::NoContractAddressAvailable) => { + Ok(Err(error @ NymdError::NoContractAddressAvailable)) => { log::debug!("{network}: {url}: nymd connection test failed: {error}"); false } - Err(e) => { + Ok(Err(e)) => { // For any other error, we're optimistic and just try anyway. log::debug!("{network}: {url}: nymd connection test response ok, but with error: {e}"); true } - Ok(_) => { - log::debug!("{network}: {url}: nymd connection successful"); + Ok(Ok(_)) => { + log::debug!("{network}: {url}: nymd connection test successful"); true } + Err(e) => { + log::debug!("{network}: {url}: nymd connection test failed: {e}"); + false + } }; ConnectionResult::Nymd(network, url.clone(), result) } async fn test_api_connection(network: Network, url: &Url, client: &ApiClient) -> ConnectionResult { log::info!("{network}: {url}: checking api connection"); - let result = match timeout(Duration::from_secs(2), client.get_cached_mixnodes()).await { + let result = match timeout( + Duration::from_secs(CONNECTION_TEST_TIMEOUT_SEC), + client.get_cached_mixnodes(), + ) + .await + { Ok(Ok(_)) => { - log::debug!("{network}: {url}: api connection successful"); + log::debug!("{network}: {url}: api connection test successful"); true } Ok(Err(e)) => { - log::debug!("{network}: {url}: api connection failed: {e}"); + log::debug!("{network}: {url}: api connection test failed: {e}"); false } Err(e) => { - log::debug!("{network}: {url}: api connection failed: {e}"); + log::debug!("{network}: {url}: api connection test failed: {e}"); false } }; ConnectionResult::Api(network, url.clone(), result) } +enum ClientForConnectionTest { + Nymd(Network, Url, Box>), + Api(Network, Url, ApiClient), +} + impl ClientForConnectionTest { async fn run_connection_check(self) -> ConnectionResult { match self { From e91e6943c6a86e2882a78779fd0915fa8a057a9e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jon=20H=C3=A4ggblad?= Date: Tue, 29 Mar 2022 09:28:42 +0200 Subject: [PATCH 10/12] connection-tester: add nymd-client cfg --- common/client-libs/validator-client/src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/common/client-libs/validator-client/src/lib.rs b/common/client-libs/validator-client/src/lib.rs index 88fe66f12f..3e11d3fcb6 100644 --- a/common/client-libs/validator-client/src/lib.rs +++ b/common/client-libs/validator-client/src/lib.rs @@ -2,6 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 pub mod client; +#[cfg(feature = "nymd-client")] pub mod connection_tester; mod error; #[cfg(feature = "nymd-client")] From 1cf101d50fab6508e471cb9e60359fc489b2da47 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jon=20H=C3=A4ggblad?= Date: Tue, 29 Mar 2022 22:34:01 +0200 Subject: [PATCH 11/12] connection-tester: refine log statements --- Cargo.lock | 1 + .../client-libs/validator-client/Cargo.toml | 1 + .../validator-client/src/connection_tester.rs | 36 +++++++++++++------ nym-wallet/Cargo.lock | 13 +++++++ nym-wallet/src-tauri/Cargo.toml | 1 + nym-wallet/src-tauri/src/config/mod.rs | 31 ++++++++++++++++ .../src/operations/mixnet/account.rs | 16 ++++++--- 7 files changed, 84 insertions(+), 15 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 287af42ae0..2853c9d980 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6068,6 +6068,7 @@ dependencies = [ "base64", "bip39", "coconut-interface", + "colored", "config", "cosmrs", "cosmwasm-std", diff --git a/common/client-libs/validator-client/Cargo.toml b/common/client-libs/validator-client/Cargo.toml index 3755d9ee39..c762f44092 100644 --- a/common/client-libs/validator-client/Cargo.toml +++ b/common/client-libs/validator-client/Cargo.toml @@ -9,6 +9,7 @@ rust-version = "1.56" [dependencies] base64 = "0.13" +colored = "2.0" mixnet-contract-common = { path= "../../cosmwasm-smart-contracts/mixnet-contract" } vesting-contract-common = { path= "../../cosmwasm-smart-contracts/vesting-contract" } vesting-contract = { path = "../../../contracts/vesting" } diff --git a/common/client-libs/validator-client/src/connection_tester.rs b/common/client-libs/validator-client/src/connection_tester.rs index 92dd9d40b2..6a19c6ec74 100644 --- a/common/client-libs/validator-client/src/connection_tester.rs +++ b/common/client-libs/validator-client/src/connection_tester.rs @@ -3,6 +3,7 @@ use crate::nymd::{NymdClient, QueryNymdClient}; use crate::ApiClient; use network_defaults::all::Network; +use colored::Colorize; use core::fmt; use itertools::Itertools; use std::collections::HashMap; @@ -84,7 +85,6 @@ async fn test_nymd_connection( url: &Url, client: &NymdClient, ) -> ConnectionResult { - log::info!("{network}: {url}: checking nymd connection"); let result = match timeout( Duration::from_secs(CONNECTION_TEST_TIMEOUT_SEC), client.get_mixnet_contract_version(), @@ -93,30 +93,39 @@ async fn test_nymd_connection( { Ok(Err(NymdError::TendermintError(e))) => { // If we get a tendermint-rpc error, we classify the node as not contactable - log::debug!("{network}: {url}: nymd connection test failed: {}", e); + log::debug!("Checking: nymd_url: {network}: {url}: failed: {}", e); false } Ok(Err(NymdError::AbciError(code, log))) => { // We accept the mixnet contract not found as ok from a connection standpoint. This happens // for example on a pre-launch network. - log::debug!("{network}: {url}: nymd abci error: {code}: {log}"); + log::debug!( + "Checking: nymd_url: {network}: {url}: {}, but with abci error: {code}: {log}", + "success".green() + ); code == 18 } Ok(Err(error @ NymdError::NoContractAddressAvailable)) => { - log::debug!("{network}: {url}: nymd connection test failed: {error}"); + log::debug!( + "Checking: nymd_url: {network}: {url}: {}: {error}", + "failed".red() + ); false } Ok(Err(e)) => { // For any other error, we're optimistic and just try anyway. - log::debug!("{network}: {url}: nymd connection test response ok, but with error: {e}"); + log::debug!( + "Checking: nymd_url: {network}: {url}: {}, but with error: {e}", + "success".green() + ); true } Ok(Ok(_)) => { - log::debug!("{network}: {url}: nymd connection test successful"); + log::debug!("Checking: nymd_url: {network}: {url}: {}", "success".green()); true } Err(e) => { - log::debug!("{network}: {url}: nymd connection test failed: {e}"); + log::debug!("Checking: nymd_url: {network}: {url}: {}: {e}", "failed".red()); false } }; @@ -124,7 +133,6 @@ async fn test_nymd_connection( } async fn test_api_connection(network: Network, url: &Url, client: &ApiClient) -> ConnectionResult { - log::info!("{network}: {url}: checking api connection"); let result = match timeout( Duration::from_secs(CONNECTION_TEST_TIMEOUT_SEC), client.get_cached_mixnodes(), @@ -132,15 +140,21 @@ async fn test_api_connection(network: Network, url: &Url, client: &ApiClient) -> .await { Ok(Ok(_)) => { - log::debug!("{network}: {url}: api connection test successful"); + log::debug!("Checking: api_url: {network}: {url}: {}", "success".green()); true } Ok(Err(e)) => { - log::debug!("{network}: {url}: api connection test failed: {e}"); + log::debug!( + "Checking: api_url: {network}: {url}: {}: {e}", + "failed".red() + ); false } Err(e) => { - log::debug!("{network}: {url}: api connection test failed: {e}"); + log::debug!( + "Checking: api_url: {network}: {url}: {}: {e}", + "failed".red() + ); false } }; diff --git a/nym-wallet/Cargo.lock b/nym-wallet/Cargo.lock index 7bec54729a..3f5a26d260 100644 --- a/nym-wallet/Cargo.lock +++ b/nym-wallet/Cargo.lock @@ -551,6 +551,17 @@ dependencies = [ "thiserror", ] +[[package]] +name = "colored" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3616f750b84d8f0de8a58bda93e08e2a81ad3f523089b05f1dffecab48c6cbd" +dependencies = [ + "atty", + "lazy_static", + "winapi", +] + [[package]] name = "config" version = "0.1.0" @@ -2755,6 +2766,7 @@ dependencies = [ "bip39", "cfg-if", "coconut-interface", + "colored", "config", "cosmrs", "cosmwasm-std", @@ -5114,6 +5126,7 @@ dependencies = [ "base64", "bip39", "coconut-interface", + "colored", "config", "cosmrs", "cosmwasm-std", diff --git a/nym-wallet/src-tauri/Cargo.toml b/nym-wallet/src-tauri/Cargo.toml index 4512f63f89..55714076cb 100644 --- a/nym-wallet/src-tauri/Cargo.toml +++ b/nym-wallet/src-tauri/Cargo.toml @@ -21,6 +21,7 @@ tauri-macros = "=1.0.0-rc.1" [dependencies] bip39 = "1.0" cfg-if = "1.0.0" +colored = "2.0" dirs = "4.0" dotenv = "0.15.0" eyre = "0.6.5" diff --git a/nym-wallet/src-tauri/src/config/mod.rs b/nym-wallet/src-tauri/src/config/mod.rs index 1299660f61..0c6c256859 100644 --- a/nym-wallet/src-tauri/src/config/mod.rs +++ b/nym-wallet/src-tauri/src/config/mod.rs @@ -4,6 +4,7 @@ use crate::{error::BackendError, network::Network as WalletNetwork}; use config::defaults::{all::SupportedNetworks, ValidatorDetails}; use config::NymConfig; +use core::fmt; use itertools::Itertools; use serde::{Deserialize, Serialize}; use std::time::Duration; @@ -173,6 +174,7 @@ impl Config { .send() .await?; self.base.fetched_validators = serde_json::from_str(&response.text().await?)?; + log::debug!("Received validator urls: \n{}", self.base.fetched_validators); Ok(()) } } @@ -197,6 +199,14 @@ impl TryFrom for ValidatorUrl { } } +impl fmt::Display for ValidatorUrl { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let s1 = format!("nymd_url: {}", self.nymd_url); + let s2 = self.api_url.as_ref().map(|url| format!(", api_url: {}", url)); + write!(f, " {}{},", s1, s2.unwrap_or_default()) + } +} + #[derive(Debug, Default, Deserialize, Serialize, Clone, PartialEq, Eq)] #[serde(deny_unknown_fields)] struct OptionalValidators { @@ -219,6 +229,27 @@ impl OptionalValidators { } } +impl fmt::Display for OptionalValidators { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let s1 = self + .mainnet + .as_ref() + .map(|validators| format!("mainnet: [\n{}\n]", validators.iter().format("\n"))) + .unwrap_or_default(); + let s2 = self + .sandbox + .as_ref() + .map(|validators| format!(",\nsandbox: [\n{}\n]", validators.iter().format("\n"))) + .unwrap_or_default(); + let s3 = self + .qa + .as_ref() + .map(|validators| format!(",\nqa: [\n{}\n]", validators.iter().format("\n"))) + .unwrap_or_default(); + write!(f, "{}{}{}", s1, s2, s3) + } +} + #[cfg(test)] mod tests { use super::*; diff --git a/nym-wallet/src-tauri/src/operations/mixnet/account.rs b/nym-wallet/src-tauri/src/operations/mixnet/account.rs index 396d3913d0..56a051ae34 100644 --- a/nym-wallet/src-tauri/src/operations/mixnet/account.rs +++ b/nym-wallet/src-tauri/src/operations/mixnet/account.rs @@ -10,6 +10,7 @@ use bip39::{Language, Mnemonic}; use config::defaults::all::Network; use config::defaults::COSMOS_DERIVATION_PATH; use cosmrs::bip32::DerivationPath; +use itertools::Itertools; use rand::seq::SliceRandom; use serde::{Deserialize, Serialize}; use std::collections::HashMap; @@ -163,6 +164,13 @@ async fn _connect_with_mnemonic( update_validator_urls(state.clone()).await?; let config = state.read().await.config(); + for network in WalletNetwork::iter() { + log::debug!( + "List of validators for {network}: [\n{}\n]", + config.get_validators(network).format(",\n") + ); + } + // Run connection tests on all nymd and validator-api endpoints let (nymd_urls, api_urls) = { let mixnet_contract_address = WalletNetwork::iter() @@ -226,7 +234,7 @@ fn select_random_responding_nymd_url( nymd_urls.choose(&mut rand::thread_rng()).cloned() }) .unwrap_or_else(|| { - log::debug!("{network}: nymd_url: using default"); + log::debug!("No passing nymd_urls for {network}: using default"); config .get_nymd_urls(network) .next() @@ -249,7 +257,7 @@ fn select_first_responding_api_url( .find_map(|(url, result)| if *result { Some(url.clone()) } else { None }) }) .unwrap_or_else(|| { - log::debug!("{network}: api_url: using default"); + log::debug!("No passing api_urls for {network}: using default"); config .get_api_urls(network) .next() @@ -268,8 +276,8 @@ fn create_clients( let nymd_url = select_random_responding_nymd_url(nymd_urls, network, config); let api_url = select_first_responding_api_url(api_urls, network, config); - log::info!("{network}: nymd_url: using: {nymd_url}"); - log::info!("{network}: api_url: using: {api_url}"); + log::info!("Connecting to: nymd_url: {nymd_url} for {network}"); + log::info!("Connecting to: api_url: {api_url} for {network}"); let client = validator_client::Client::new_signing( validator_client::Config::new( From adf453718314ce5b7a752bc400f00628871de568 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jon=20H=C3=A4ggblad?= Date: Wed, 30 Mar 2022 00:02:34 +0200 Subject: [PATCH 12/12] rustfmt --- .../validator-client/src/connection_tester.rs | 10 ++++++++-- nym-wallet/src-tauri/src/config/mod.rs | 10 ++++++++-- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/common/client-libs/validator-client/src/connection_tester.rs b/common/client-libs/validator-client/src/connection_tester.rs index 6a19c6ec74..ebf156d7ca 100644 --- a/common/client-libs/validator-client/src/connection_tester.rs +++ b/common/client-libs/validator-client/src/connection_tester.rs @@ -121,11 +121,17 @@ async fn test_nymd_connection( true } Ok(Ok(_)) => { - log::debug!("Checking: nymd_url: {network}: {url}: {}", "success".green()); + log::debug!( + "Checking: nymd_url: {network}: {url}: {}", + "success".green() + ); true } Err(e) => { - log::debug!("Checking: nymd_url: {network}: {url}: {}: {e}", "failed".red()); + log::debug!( + "Checking: nymd_url: {network}: {url}: {}: {e}", + "failed".red() + ); false } }; diff --git a/nym-wallet/src-tauri/src/config/mod.rs b/nym-wallet/src-tauri/src/config/mod.rs index 0c6c256859..c35c80cb10 100644 --- a/nym-wallet/src-tauri/src/config/mod.rs +++ b/nym-wallet/src-tauri/src/config/mod.rs @@ -174,7 +174,10 @@ impl Config { .send() .await?; self.base.fetched_validators = serde_json::from_str(&response.text().await?)?; - log::debug!("Received validator urls: \n{}", self.base.fetched_validators); + log::debug!( + "Received validator urls: \n{}", + self.base.fetched_validators + ); Ok(()) } } @@ -202,7 +205,10 @@ impl TryFrom for ValidatorUrl { impl fmt::Display for ValidatorUrl { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let s1 = format!("nymd_url: {}", self.nymd_url); - let s2 = self.api_url.as_ref().map(|url| format!(", api_url: {}", url)); + let s2 = self + .api_url + .as_ref() + .map(|url| format!(", api_url: {}", url)); write!(f, " {}{},", s1, s2.unwrap_or_default()) } }