diff --git a/common/client-libs/validator-client/src/lib.rs b/common/client-libs/validator-client/src/lib.rs index fc2c8b8a8b..f1b8c855cb 100644 --- a/common/client-libs/validator-client/src/lib.rs +++ b/common/client-libs/validator-client/src/lib.rs @@ -22,6 +22,7 @@ use crate::rest_requests::{ ReputationPatch, TopologyGet, TopologyGetResponse, }; use serde::Deserialize; +use std::fmt::{self, Display, Formatter}; pub mod models; pub mod rest_requests; @@ -29,6 +30,28 @@ pub mod rest_requests; // for ease of use type Result = std::result::Result; +const MAX_SANE_UNEXPECTED_PRINT: usize = 100; + +#[derive(Deserialize)] +#[serde(rename_all = "camelCase", untagged)] +pub(crate) enum ErrorResponses { + Error(ErrorResponse), + Unexpected(String), +} + +impl From for ValidatorClientError { + fn from(err: ErrorResponses) -> Self { + match err { + ErrorResponses::Error(err_message) => { + ValidatorClientError::ValidatorError(err_message.error) + } + ErrorResponses::Unexpected(received) => { + ValidatorClientError::UnexpectedResponse(received) + } + } + } +} + #[derive(Deserialize)] #[serde(rename_all = "camelCase")] pub(crate) struct ErrorResponse { @@ -45,7 +68,7 @@ struct OkResponse { #[serde(rename_all = "camelCase", untagged)] pub(crate) enum DefaultRESTResponse { Ok(OkResponse), - Error(ErrorResponse), + Error(ErrorResponses), } #[derive(Debug)] @@ -53,6 +76,7 @@ pub enum ValidatorClientError { RESTRequestError(RESTRequestError), ReqwestClientError(reqwest::Error), ValidatorError(String), + UnexpectedResponse(String), } impl From for ValidatorClientError { @@ -67,6 +91,40 @@ impl From for ValidatorClientError { } } +impl Display for ValidatorClientError { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + match self { + ValidatorClientError::RESTRequestError(err) => { + write!(f, "could not prepare the REST request - {}", err) + } + ValidatorClientError::ReqwestClientError(err) => { + write!(f, "there was an issue with the REST request - {}", err) + } + ValidatorClientError::ValidatorError(err) => { + write!(f, "there was an issue with the validator client - {}", err) + } + ValidatorClientError::UnexpectedResponse(received) => { + if received.len() < MAX_SANE_UNEXPECTED_PRINT { + write!( + f, + "received data was completely unexpected. got: {}", + received + ) + } else { + write!( + f, + "received data was completely unexpected. got: {}...", + received + .chars() + .take(MAX_SANE_UNEXPECTED_PRINT) + .collect::() + ) + } + } + } + } +} + pub struct Config { base_url: String, } @@ -117,7 +175,7 @@ impl Client { )?; match self.make_rest_request(req).await? { DefaultRESTResponse::Ok(_) => Ok(()), - DefaultRESTResponse::Error(err) => Err(ValidatorClientError::ValidatorError(err.error)), + DefaultRESTResponse::Error(err) => Err(err.into()), } } @@ -141,7 +199,7 @@ impl Client { )) } } - DefaultRESTResponse::Error(err) => Err(ValidatorClientError::ValidatorError(err.error)), + DefaultRESTResponse::Error(err) => Err(err.into()), } } @@ -159,7 +217,7 @@ impl Client { )) } } - DefaultRESTResponse::Error(err) => Err(ValidatorClientError::ValidatorError(err.error)), + DefaultRESTResponse::Error(err) => Err(err.into()), } } @@ -189,7 +247,7 @@ impl Client { )) } } - DefaultRESTResponse::Error(err) => Err(ValidatorClientError::ValidatorError(err.error)), + DefaultRESTResponse::Error(err) => Err(err.into()), } } @@ -197,7 +255,7 @@ impl Client { let req = TopologyGet::new(&self.config.base_url, None, None, None)?; match self.make_rest_request(req).await? { TopologyGetResponse::Ok(topology) => Ok(topology), - TopologyGetResponse::Error(err) => Err(ValidatorClientError::ValidatorError(err.error)), + TopologyGetResponse::Error(err) => Err(err.into()), } } @@ -205,9 +263,7 @@ impl Client { let req = ActiveTopologyGet::new(&self.config.base_url, None, None, None)?; match self.make_rest_request(req).await? { ActiveTopologyGetResponse::Ok(topology) => Ok(topology), - ActiveTopologyGetResponse::Error(err) => { - Err(ValidatorClientError::ValidatorError(err.error)) - } + ActiveTopologyGetResponse::Error(err) => Err(err.into()), } } @@ -223,7 +279,7 @@ impl Client { )) } } - DefaultRESTResponse::Error(err) => Err(ValidatorClientError::ValidatorError(err.error)), + DefaultRESTResponse::Error(err) => Err(err.into()), } } @@ -239,7 +295,7 @@ impl Client { )) } } - DefaultRESTResponse::Error(err) => Err(ValidatorClientError::ValidatorError(err.error)), + DefaultRESTResponse::Error(err) => Err(err.into()), } } } diff --git a/common/client-libs/validator-client/src/rest_requests/active_topology_get.rs b/common/client-libs/validator-client/src/rest_requests/active_topology_get.rs index 1973cea1d8..d1ae8295a2 100644 --- a/common/client-libs/validator-client/src/rest_requests/active_topology_get.rs +++ b/common/client-libs/validator-client/src/rest_requests/active_topology_get.rs @@ -14,7 +14,7 @@ use crate::models::topology::Topology; use crate::rest_requests::{PathParam, QueryParam, RESTRequest, RESTRequestError}; -use crate::ErrorResponse; +use crate::ErrorResponses; use reqwest::{Method, Url}; use serde::Deserialize; @@ -26,7 +26,7 @@ pub struct Request { #[serde(rename_all = "camelCase", untagged)] pub(crate) enum Response { Ok(Topology), - Error(ErrorResponse), + Error(ErrorResponses), } impl RESTRequest for Request { diff --git a/common/client-libs/validator-client/src/rest_requests/mod.rs b/common/client-libs/validator-client/src/rest_requests/mod.rs index 49b5f54390..679fc4db7c 100644 --- a/common/client-libs/validator-client/src/rest_requests/mod.rs +++ b/common/client-libs/validator-client/src/rest_requests/mod.rs @@ -14,6 +14,7 @@ use reqwest::{Method, Url}; use serde::{de::DeserializeOwned, Serialize}; +use std::fmt::{self, Display, Formatter}; pub(crate) use active_topology_get::{ Request as ActiveTopologyGet, Response as ActiveTopologyGetResponse, @@ -46,8 +47,30 @@ pub enum RESTRequestError { MalformedUrl(String), } +impl Display for RESTRequestError { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + match self { + RESTRequestError::InvalidPathParams => write!( + f, + "invalid number of path parameters was provided or they were malformed" + ), + RESTRequestError::InvalidQueryParams => write!( + f, + "invalid number of query parameters was provided or they were malformed" + ), + RESTRequestError::NoPayloadProvided => { + write!(f, "no request payload was provided while it was expected") + } + RESTRequestError::MalformedUrl(url) => { + write!(f, "tried to make request to malformed url ({})", url) + } + } + } +} + pub(crate) trait RESTRequest { - const METHOD: Method; // 'GET', 'POST', 'DELETE', etc. + // 'GET', 'POST', 'DELETE', etc. + const METHOD: Method; const RELATIVE_PATH: &'static str; type JsonPayload: Serialize + Sized; diff --git a/common/client-libs/validator-client/src/rest_requests/topology_get.rs b/common/client-libs/validator-client/src/rest_requests/topology_get.rs index 71f5ed8b1b..348f79a748 100644 --- a/common/client-libs/validator-client/src/rest_requests/topology_get.rs +++ b/common/client-libs/validator-client/src/rest_requests/topology_get.rs @@ -14,7 +14,7 @@ use crate::models::topology::Topology; use crate::rest_requests::{PathParam, QueryParam, RESTRequest, RESTRequestError}; -use crate::ErrorResponse; +use crate::ErrorResponses; use reqwest::{Method, Url}; use serde::Deserialize; @@ -26,7 +26,7 @@ pub struct Request { #[serde(rename_all = "camelCase", untagged)] pub(crate) enum Response { Ok(Topology), - Error(ErrorResponse), + Error(ErrorResponses), } impl RESTRequest for Request { diff --git a/gateway/src/node/mod.rs b/gateway/src/node/mod.rs index 8db7a7340d..60f9b39337 100644 --- a/gateway/src/node/mod.rs +++ b/gateway/src/node/mod.rs @@ -20,6 +20,7 @@ use crate::node::storage::{inboxes, ClientLedger}; use crypto::asymmetric::{encryption, identity}; use log::*; use mixnet_client::forwarder::{MixForwardingSender, PacketForwarder}; +use std::process; use std::sync::Arc; use tokio::runtime::Runtime; @@ -140,7 +141,7 @@ impl Gateway { ) .await { - error!("failed to unregister with validator... - {:?}", err) + error!("failed to unregister with validator... - {}", err) } else { info!("unregistration was successful!") } @@ -152,10 +153,13 @@ impl Gateway { let validator_client_config = validator_client::Config::new(self.config.get_validator_rest_endpoint()); let validator_client = validator_client::Client::new(validator_client_config); - let topology = validator_client - .get_topology() - .await - .expect("failed to grab network topology"); + let topology = match validator_client.get_topology().await { + Ok(topology) => topology, + Err(err) => { + error!("failed to grab initial network topology - {}\n Please try to startup again in few minutes", err); + process::exit(1); + } + }; let existing_gateways = topology.gateways; existing_gateways @@ -181,7 +185,7 @@ impl Gateway { warn!("We seem to have not unregistered after going offline - there's a node with identical identity and announce-host as us registered.") } else { error!( - "Our announce-host is identical to an existing node's announce-host! (its key is {:?}", + "Our announce-host is identical to an existing node's announce-host! (its key is {:?})", duplicate_node_key ); return; @@ -193,7 +197,7 @@ impl Gateway { self.identity.public_key().to_base58_string(), self.encryption_keys.public_key().to_base58_string(), ).await { - error!("failed to register with the validator - {:?}", err); + error!("failed to register with the validator - {}.\nPlease try again in few minutes.", err); return } diff --git a/mixnode/src/node/mod.rs b/mixnode/src/node/mod.rs index b53b859bfc..e66173063a 100644 --- a/mixnode/src/node/mod.rs +++ b/mixnode/src/node/mod.rs @@ -19,6 +19,7 @@ use crate::node::listener::Listener; use crate::node::packet_delayforwarder::{DelayForwarder, PacketDelayForwardSender}; use crypto::asymmetric::{encryption, identity}; use log::*; +use std::process; use std::sync::Arc; use tokio::runtime::Runtime; @@ -101,10 +102,14 @@ impl MixNode { let validator_client_config = validator_client::Config::new(self.config.get_validator_rest_endpoint()); let validator_client = validator_client::Client::new(validator_client_config); - let topology = validator_client - .get_topology() - .await - .expect("failed to grab network topology"); + let topology = match validator_client.get_topology().await { + Ok(topology) => topology, + Err(err) => { + error!("failed to grab initial network topology - {}\n Please try to startup again in few minutes", err); + process::exit(1); + } + }; + let existing_mixes_presence = topology.mix_nodes; existing_mixes_presence .iter() @@ -129,7 +134,7 @@ impl MixNode { ) .await { - error!("failed to unregister with validator... - {:?}", err) + error!("failed to unregister with validator... - {}", err) } else { info!("unregistration was successful!") } @@ -146,7 +151,7 @@ impl MixNode { warn!("We seem to have not unregistered after going offline - there's a node with identical identity and announce-host us as registered.") } else { error!( - "Our announce-host is identical to an existing node's announce-host! (its key is {:?}", + "Our announce-host is identical to an existing node's announce-host! (its key is {:?})", duplicate_node_key ); return; @@ -154,11 +159,11 @@ impl MixNode { } if let Err(err) = presence::register_with_validator( -&self.config, + &self.config, self.identity_keypair.public_key().to_base58_string(), self.sphinx_keypair.public_key().to_base58_string(), ).await { - error!("failed to register with the validator - {:?}", err); + error!("failed to register with the validator - {}.\nPlease try again in few minutes.", err); return; }