diff --git a/Cargo.lock b/Cargo.lock index c004f43b3d..4675662729 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -634,6 +634,7 @@ dependencies = [ name = "directory-client" version = "0.1.0" dependencies = [ + "directory-client-models", "futures 0.3.4", "log 0.4.8", "mockito", @@ -641,6 +642,13 @@ dependencies = [ "reqwest 0.10.4", "serde", "tokio 0.2.16", +] + +[[package]] +name = "directory-client-models" +version = "0.1.0" +dependencies = [ + "serde", "topology", ] @@ -1761,10 +1769,11 @@ dependencies = [ [[package]] name = "nym-client-wasm" -version = "0.7.4" +version = "0.7.5" dependencies = [ "console_error_panic_hook", "crypto", + "directory-client-models", "log 0.4.8", "nymsphinx", "rand 0.7.3", @@ -3271,7 +3280,6 @@ name = "topology" version = "0.1.0" dependencies = [ "bs58", - "futures 0.3.4", "itertools", "log 0.4.8", "nymsphinx-addressing", diff --git a/Cargo.toml b/Cargo.toml index 3bc05a60bc..9821863fe0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,6 +8,7 @@ members = [ "clients/native", "clients/webassembly", "common/client-libs/directory-client", + "common/client-libs/directory-client/models", "common/client-libs/gateway-client", "common/client-libs/mixnet-client", "common/client-libs/validator-client", diff --git a/clients/native/src/client/mod.rs b/clients/native/src/client/mod.rs index 42d400887a..27344223fa 100644 --- a/clients/native/src/client/mod.rs +++ b/clients/native/src/client/mod.rs @@ -25,7 +25,6 @@ use crate::client::topology_control::{ use crate::config::{Config, SocketType}; use crate::websocket; use crypto::identity::MixIdentityKeyPair; -use directory_client::presence; use futures::channel::mpsc; use gateway_client::{ AcknowledgementReceiver, AcknowledgementSender, GatewayClient, MixnetMessageReceiver, @@ -221,16 +220,16 @@ impl NymClient { // future responsible for periodically polling directory server and updating // the current global view of topology - fn start_topology_refresher( + fn start_topology_refresher( &mut self, - topology_accessor: TopologyAccessor, + topology_accessor: TopologyAccessor, ) { let topology_refresher_config = TopologyRefresherConfig::new( self.config.get_directory_server(), self.config.get_topology_refresh_rate(), ); let mut topology_refresher = - TopologyRefresher::new(topology_refresher_config, topology_accessor); + TopologyRefresher::new_directory_client(topology_refresher_config, topology_accessor); // before returning, block entire runtime to refresh the current network view so that any // components depending on topology would see a non-empty view info!( @@ -354,9 +353,8 @@ impl NymClient { // channels responsible for controlling ack messages let (ack_sender, ack_receiver) = mpsc::unbounded(); + let shared_topology_accessor = TopologyAccessor::::new(); - // TODO: when we switch to our graph topology, we need to remember to change 'presence::Topology' type - let shared_topology_accessor = TopologyAccessor::::new(); // the components are started in very specific order. Unless you know what you are doing, // do not change that. self.start_topology_refresher(shared_topology_accessor.clone()); diff --git a/clients/native/src/client/topology_control.rs b/clients/native/src/client/topology_control.rs index 740ffe34ec..126a2bdea0 100644 --- a/clients/native/src/client/topology_control.rs +++ b/clients/native/src/client/topology_control.rs @@ -13,6 +13,7 @@ // limitations under the License. use crate::built_info; +use directory_client::DirectoryClient; use log::*; use nymsphinx::addressing::clients::Recipient; use std::ops::Deref; @@ -167,34 +168,40 @@ impl TopologyRefresherConfig { } pub(crate) struct TopologyRefresher { - directory_server: String, + directory_client: directory_client::Client, topology_accessor: TopologyAccessor, refresh_rate: Duration, } -impl TopologyRefresher { - pub(crate) fn new( +// TODO: consider (or maybe not) restoring generic TopologyRefresher +impl TopologyRefresher { + pub(crate) fn new_directory_client( cfg: TopologyRefresherConfig, - topology_accessor: TopologyAccessor, + topology_accessor: TopologyAccessor, ) -> Self { + let directory_client_config = directory_client::Config::new(cfg.directory_server); + let directory_client = directory_client::Client::new(directory_client_config); + TopologyRefresher { - directory_server: cfg.directory_server, + directory_client, topology_accessor, refresh_rate: cfg.refresh_rate, } } - async fn get_current_compatible_topology(&self) -> T { - // note: this call makes it necessary that `T::new()`does *not* have 'static lifetime - let full_topology = T::new(self.directory_server.clone()).await; - // just filter by version and assume the validators will remove all bad behaving - // nodes with the staking - full_topology.filter_system_version(built_info::PKG_VERSION) + async fn get_current_compatible_topology(&self) -> Option { + match self.directory_client.get_topology().await { + Err(err) => { + error!("failed to get network topology! - {:?}", err); + None + } + Ok(topology) => Some(topology.filter_system_version(built_info::PKG_VERSION)), + } } pub(crate) async fn refresh(&mut self) { trace!("Refreshing the topology"); - let new_topology = Some(self.get_current_compatible_topology().await); + let new_topology = self.get_current_compatible_topology().await; self.topology_accessor .update_global_topology(new_topology) diff --git a/clients/native/src/commands/init.rs b/clients/native/src/commands/init.rs index 28ecdd5255..006cefb397 100644 --- a/clients/native/src/commands/init.rs +++ b/clients/native/src/commands/init.rs @@ -18,7 +18,7 @@ use crate::config::persistence::pathfinder::ClientPathfinder; use clap::{App, Arg, ArgMatches}; use config::NymConfig; use crypto::identity::MixIdentityKeyPair; -use directory_client::presence::Topology; +use directory_client::DirectoryClient; use gateway_client::GatewayClient; use gateway_requests::AuthToken; use nymsphinx::DestinationAddressBytes; @@ -90,8 +90,10 @@ async fn choose_gateway( directory_server: String, our_address: DestinationAddressBytes, ) -> (String, AuthToken) { - // TODO: once we change to graph topology this here will need to be updated! - let topology = Topology::new(directory_server.clone()).await; + let directory_client_config = directory_client::Config::new(directory_server.clone()); + let directory_client = directory_client::Client::new(directory_client_config); + let topology = directory_client.get_topology().await.unwrap(); + let version_filtered_topology = topology.filter_system_version(built_info::PKG_VERSION); // don't care about health of the networks as mixes can go up and down any time, // but DO care about gateways diff --git a/clients/webassembly/Cargo.toml b/clients/webassembly/Cargo.toml index 596ea4329c..a630dbe1e6 100644 --- a/clients/webassembly/Cargo.toml +++ b/clients/webassembly/Cargo.toml @@ -26,6 +26,7 @@ rand = "0.7.2" crypto = { path = "../../common/crypto" } nymsphinx = { path = "../../common/nymsphinx" } topology = { path = "../../common/topology" } +directory-client-models = { path = "../../common/client-libs/directory-client/models" } # The `console_error_panic_hook` crate provides better debugging of panics by # logging them with `console.error`. This is great for development, but requires diff --git a/clients/webassembly/src/lib.rs b/clients/webassembly/src/lib.rs index f20973d2cc..9466912cf9 100644 --- a/clients/webassembly/src/lib.rs +++ b/clients/webassembly/src/lib.rs @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. use crypto::identity::MixIdentityPublicKey; -use models::Topology; +use models::topology::Topology; use nymsphinx::addressing::nodes::NymNodeRoutingAddress; use nymsphinx::Node as SphinxNode; use nymsphinx::{delays, Destination, NodeAddressBytes, SphinxPacket}; @@ -28,6 +28,7 @@ mod utils; pub use models::keys::keygen; use nymsphinx::addressing::clients::Recipient; +use topology::NymTopology; // When the `wee_alloc` feature is enabled, use `wee_alloc` as the global // allocator. @@ -198,8 +199,8 @@ mod building_a_topology_from_json { #[test] #[should_panic] fn panics_when_there_are_no_mixnodes() { - let mut topology: Topology = serde_json::from_str(topology_fixture()).unwrap(); - topology.mix_nodes = vec![]; + let mut topology = Topology::new(topology_fixture()); + topology.set_mixnodes(vec![]); let json = serde_json::to_string(&topology).unwrap(); sphinx_route_to( &json, @@ -213,9 +214,9 @@ mod building_a_topology_from_json { #[test] #[should_panic] fn panics_when_there_are_not_enough_mixnodes() { - let mut topology: Topology = serde_json::from_str(topology_fixture()).unwrap(); - let node = topology.mix_nodes.first().unwrap().clone(); - topology.mix_nodes = vec![node]; // 1 mixnode isn't enough. Panic! + let mut topology = Topology::new(topology_fixture()); + let node = topology.get_current_raw_mixnodes().first().unwrap().clone(); + topology.set_mixnodes(vec![node]); // 1 mixnode isn't enough. Panic! let json = serde_json::to_string(&topology).unwrap(); sphinx_route_to( &json, @@ -226,6 +227,7 @@ mod building_a_topology_from_json { ); } + // JS: why is this an "offline-test" feature? It makes no network requests? #[test] #[cfg_attr(feature = "offline-test", ignore)] fn test_works_on_happy_json() { @@ -238,6 +240,20 @@ mod building_a_topology_from_json { ); assert_eq!(4, route.len()); } + + #[test] + fn test_works_on_happy_json_when_serialized() { + let topology = Topology::new(topology_fixture()); + let json = serde_json::to_string(&topology).unwrap(); + let route = sphinx_route_to( + &json, + &NodeAddressBytes::try_from_base58_string( + "7vhgER4Gz789QHNTSu4apMpTcpTuUaRiLxJnbz1g2HFh", + ) + .unwrap(), + ); + assert_eq!(4, route.len()); + } } #[cfg(test)] diff --git a/clients/webassembly/src/models/keys.rs b/clients/webassembly/src/models/keys.rs index d06696cb88..e559b7a10f 100644 --- a/clients/webassembly/src/models/keys.rs +++ b/clients/webassembly/src/models/keys.rs @@ -1,3 +1,17 @@ +// Copyright 2020 Nym Technologies SA +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + use crypto::identity::MixIdentityKeyPair; use serde::{Deserialize, Serialize}; use std::convert::{TryFrom, TryInto}; diff --git a/clients/webassembly/src/models/mod.rs b/clients/webassembly/src/models/mod.rs index 3f0c4e779b..b156775803 100644 --- a/clients/webassembly/src/models/mod.rs +++ b/clients/webassembly/src/models/mod.rs @@ -12,176 +12,5 @@ // See the License for the specific language governing permissions and // limitations under the License. -use nymsphinx::Node as SphinxNode; -use nymsphinx::NodeAddressBytes; -use rand::seq::IteratorRandom; -use serde::{Deserialize, Serialize}; -use std::cmp::max; -use std::collections::HashMap; -use std::convert::TryInto; -use topology::{gateway, mix, provider}; - -pub mod coconodes; -pub mod gateways; pub mod keys; -pub mod mixnodes; -pub mod providers; - -// JS: can we just get rid of this? It's mostly just copied (and un-updated) code from NymTopology trait -// Topology shows us the current state of the overall Nym network -#[derive(Clone, Debug, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct Topology { - pub coco_nodes: Vec, - pub mix_nodes: Vec, - pub mix_provider_nodes: Vec, - pub gateway_nodes: Vec, -} - -impl Topology { - pub fn new(json: &str) -> Self { - if json.is_empty() { - panic!("empty json passed"); - } - serde_json::from_str(json).unwrap() - } - - fn make_layered_topology(&self) -> Result>, NymTopologyError> { - let mut layered_topology: HashMap> = HashMap::new(); - let mut highest_layer = 0; - for mix in self.mix_nodes() { - // we need to have extra space for provider - if mix.layer > nymsphinx::MAX_PATH_LENGTH as u64 { - return Err(NymTopologyError::InvalidMixLayerError); - } - highest_layer = max(highest_layer, mix.layer); - - let layer_nodes = layered_topology.entry(mix.layer).or_insert_with(Vec::new); - layer_nodes.push(mix); - } - - // verify the topology - make sure there are no gaps and there is at least one node per layer - let mut missing_layers = Vec::new(); - for layer in 1..=highest_layer { - if !layered_topology.contains_key(&layer) { - missing_layers.push(layer); - } - if layered_topology[&layer].is_empty() { - missing_layers.push(layer); - } - } - - if !missing_layers.is_empty() { - return Err(NymTopologyError::MissingLayerError(missing_layers)); - } - - Ok(layered_topology) - } - - // Tries to get a route through the mix network - fn random_mix_route(&self) -> Result, NymTopologyError> { - let mut layered_topology = self.make_layered_topology()?; - let num_layers = layered_topology.len(); - let route = (1..=num_layers as u64) - // unwrap is safe for 'remove' as it it failed, it implied the entry never existed - // in the map in the first place which would contradict what we've just done - .map(|layer| layered_topology.remove(&layer).unwrap()) // for each layer - .map(|nodes| nodes.into_iter().choose(&mut rand::thread_rng()).unwrap()) // choose random node - .map(|random_node| random_node.into()) // and convert it into sphinx specific node format - .collect(); - - Ok(route) - } - - // Sets up a route to a specific gateway - pub fn random_route_to_gateway( - &self, - gateway_address: &NodeAddressBytes, - ) -> Result, NymTopologyError> { - let b58_address = gateway_address.to_base58_string(); - let gateway_node = self - .gateways() - .iter() - .cloned() - .find(|gateway| gateway.pub_key == b58_address.clone()) - .ok_or_else(|| NymTopologyError::InvalidMixLayerError)?; - - Ok(self - .random_mix_route()? - .into_iter() - .chain(std::iter::once(gateway_node.into())) - .collect()) - } - - pub fn mix_nodes(&self) -> Vec { - self.mix_nodes - .iter() - .filter_map(|x| x.clone().try_into().ok()) - .collect() - } - - // it's intesting how compiler knows this function is unused even though it's public - // but it will be removed once our topology is refactored and the concept of "provider" - // goes away. - #[allow(dead_code)] - pub fn providers(&self) -> Vec { - self.mix_provider_nodes - .iter() - .map(|x| x.clone().into()) - .collect() - } - - pub fn gateways(&self) -> Vec { - self.gateway_nodes - .iter() - .map(|x| x.clone().into()) - .collect() - } -} - -#[derive(Debug)] -pub enum NymTopologyError { - InvalidMixLayerError, - MissingLayerError(Vec), -} - -#[cfg(test)] -mod converting_mixnode_presence_into_topology_mixnode { - use super::*; - - #[test] - fn it_returns_error_on_unresolvable_hostname() { - let unresolvable_hostname = "foomp.foomp.foomp:1234"; - - let mix_presence = mixnodes::MixNodePresence { - location: "".to_string(), - host: unresolvable_hostname.to_string(), - pub_key: "".to_string(), - layer: 0, - last_seen: 0, - version: "".to_string(), - }; - - let _result: Result = mix_presence.try_into(); - // assert!(result.is_err()) // This fails only for me. Why? - // ¯\_(ツ)_/¯ - works on my machine (and travis) - } - - #[test] - #[cfg_attr(feature = "offline-test", ignore)] - fn it_returns_resolved_ip_on_resolvable_hostname() { - let resolvable_hostname = "nymtech.net:1234"; - - let mix_presence = mixnodes::MixNodePresence { - location: "".to_string(), - host: resolvable_hostname.to_string(), - pub_key: "".to_string(), - layer: 0, - last_seen: 0, - version: "".to_string(), - }; - - let result: Result = mix_presence.try_into(); - assert!(result.is_ok()) - } -} +pub mod topology; diff --git a/clients/webassembly/src/models/topology.rs b/clients/webassembly/src/models/topology.rs new file mode 100644 index 0000000000..ee9f263370 --- /dev/null +++ b/clients/webassembly/src/models/topology.rs @@ -0,0 +1,90 @@ +// Copyright 2020 Nym Technologies SA +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use serde::Serializer; +use topology::{coco, gateway, mix, provider, NymTopology}; + +#[derive(Clone, Debug)] +pub struct Topology { + inner: directory_client_models::presence::Topology, +} + +impl serde::Serialize for Topology { + fn serialize(&self, serializer: S) -> Result<::Ok, ::Error> + where + S: Serializer, + { + self.inner.serialize(serializer) + } +} + +impl Topology { + pub fn new(json: &str) -> Self { + if json.is_empty() { + panic!("empty json passed"); + } + + Topology { + inner: serde_json::from_str(json).unwrap(), + } + } + + #[cfg(test)] + pub(crate) fn set_mixnodes( + &mut self, + mix_nodes: Vec, + ) { + self.inner.mix_nodes = mix_nodes + } + + #[cfg(test)] + pub(crate) fn get_current_raw_mixnodes( + &self, + ) -> Vec { + self.inner.mix_nodes.clone() + } +} + +impl NymTopology for Topology { + fn new_from_nodes( + mix_nodes: Vec, + mix_provider_nodes: Vec, + coco_nodes: Vec, + gateway_nodes: Vec, + ) -> Self { + Topology { + inner: directory_client_models::presence::Topology::new_from_nodes( + mix_nodes, + mix_provider_nodes, + coco_nodes, + gateway_nodes, + ), + } + } + fn mix_nodes(&self) -> Vec { + self.inner.mix_nodes() + } + + fn providers(&self) -> Vec { + self.inner.providers() + } + + fn gateways(&self) -> Vec { + self.inner.gateways() + } + + fn coco_nodes(&self) -> Vec { + self.inner.coco_nodes() + } +} diff --git a/common/client-libs/directory-client/Cargo.toml b/common/client-libs/directory-client/Cargo.toml index 1b358c8a63..d9a96a2b47 100644 --- a/common/client-libs/directory-client/Cargo.toml +++ b/common/client-libs/directory-client/Cargo.toml @@ -13,11 +13,11 @@ offline-test = [] log = "0.4" futures = "0.3" pretty_env_logger = "0.3" -reqwest = { version = "0.10", features = ["json"] } serde = { version = "1.0.104", features = ["derive"] } +reqwest = { version = "0.10", features = ["json"] } ## internal -topology = {path = "../../topology"} +directory-client-models = { path = "models" } [dev-dependencies] mockito = "0.23.0" diff --git a/common/client-libs/directory-client/models/Cargo.toml b/common/client-libs/directory-client/models/Cargo.toml new file mode 100644 index 0000000000..533e3b8577 --- /dev/null +++ b/common/client-libs/directory-client/models/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "directory-client-models" +version = "0.1.0" +authors = ["Jędrzej Stuczyński "] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +serde = { version = "1.0.104", features = ["derive"] } + +topology = { path = "../../../topology" } diff --git a/common/client-libs/directory-client/models/src/lib.rs b/common/client-libs/directory-client/models/src/lib.rs new file mode 100644 index 0000000000..c577e00bea --- /dev/null +++ b/common/client-libs/directory-client/models/src/lib.rs @@ -0,0 +1,16 @@ +// Copyright 2020 Nym Technologies SA +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +pub mod metrics; +pub mod presence; diff --git a/common/client-libs/directory-client/src/metrics.rs b/common/client-libs/directory-client/models/src/metrics.rs similarity index 100% rename from common/client-libs/directory-client/src/metrics.rs rename to common/client-libs/directory-client/models/src/metrics.rs diff --git a/clients/webassembly/src/models/coconodes.rs b/common/client-libs/directory-client/models/src/presence/coconodes.rs similarity index 100% rename from clients/webassembly/src/models/coconodes.rs rename to common/client-libs/directory-client/models/src/presence/coconodes.rs diff --git a/clients/webassembly/src/models/gateways.rs b/common/client-libs/directory-client/models/src/presence/gateways.rs similarity index 100% rename from clients/webassembly/src/models/gateways.rs rename to common/client-libs/directory-client/models/src/presence/gateways.rs diff --git a/clients/webassembly/src/models/mixnodes.rs b/common/client-libs/directory-client/models/src/presence/mixnodes.rs similarity index 100% rename from clients/webassembly/src/models/mixnodes.rs rename to common/client-libs/directory-client/models/src/presence/mixnodes.rs diff --git a/common/client-libs/directory-client/src/presence/mod.rs b/common/client-libs/directory-client/models/src/presence/mod.rs similarity index 100% rename from common/client-libs/directory-client/src/presence/mod.rs rename to common/client-libs/directory-client/models/src/presence/mod.rs diff --git a/clients/webassembly/src/models/providers.rs b/common/client-libs/directory-client/models/src/presence/providers.rs similarity index 100% rename from clients/webassembly/src/models/providers.rs rename to common/client-libs/directory-client/models/src/presence/providers.rs diff --git a/common/client-libs/directory-client/src/presence/topology.rs b/common/client-libs/directory-client/models/src/presence/topology.rs similarity index 83% rename from common/client-libs/directory-client/src/presence/topology.rs rename to common/client-libs/directory-client/models/src/presence/topology.rs index 169415bc84..994da2e50f 100644 --- a/common/client-libs/directory-client/src/presence/topology.rs +++ b/common/client-libs/directory-client/models/src/presence/topology.rs @@ -13,12 +13,10 @@ // limitations under the License. use super::{coconodes, gateways, mixnodes, providers}; -use crate::{Client, Config, DirectoryClient}; -use futures::future::BoxFuture; -use log::*; use serde::{Deserialize, Serialize}; use std::convert::TryInto; use topology::{coco, gateway, mix, provider, NymTopology}; + // Topology shows us the current state of the overall Nym network #[derive(Clone, Debug, Deserialize, Serialize)] #[serde(rename_all = "camelCase")] @@ -30,24 +28,6 @@ pub struct Topology { } impl NymTopology for Topology { - // TODO: this will need some changes to not imply having to make an HTTP request in constructor - // TODO2: and also be reworked/removed with the topology re-work - fn new<'a>(directory_server: String) -> BoxFuture<'a, Self> { - debug!("Using directory server: {:?}", directory_server); - let directory_config = Config { - base_url: directory_server, - }; - let directory = Client::new(directory_config); - Box::pin({ - async move { - directory - .get_topology() - .await - .expect("Failed to retrieve network topology.") - } - }) - } - fn new_from_nodes( mix_nodes: Vec, mix_provider_nodes: Vec, diff --git a/common/client-libs/directory-client/src/lib.rs b/common/client-libs/directory-client/src/lib.rs index 80277174be..2540157870 100644 --- a/common/client-libs/directory-client/src/lib.rs +++ b/common/client-libs/directory-client/src/lib.rs @@ -20,16 +20,18 @@ use crate::requests::presence_gateways_post::Request as PresenceGatewayPost; use crate::requests::presence_mixnodes_post::Request as PresenceMixNodesPost; use crate::requests::presence_providers_post::Request as PresenceProvidersPost; use crate::requests::presence_topology_get::Request as PresenceTopologyRequest; - -use metrics::{MixMetric, PersistedMixMetric}; -use presence::{ +use directory_client_models::metrics::{MixMetric, PersistedMixMetric}; +use directory_client_models::presence::{ coconodes::CocoPresence, gateways::GatewayPresence, mixnodes::MixNodePresence, - providers::MixProviderPresence, Topology, + providers::MixProviderPresence, }; use requests::{health_check_get::HealthCheckResponse, DirectoryGetRequest, DirectoryPostRequest}; -pub mod metrics; -pub mod presence; +pub use directory_client_models::{ + metrics, + presence::{self, Topology}, +}; + pub mod requests; pub struct Config { diff --git a/common/client-libs/directory-client/src/presence/coconodes.rs b/common/client-libs/directory-client/src/presence/coconodes.rs deleted file mode 100644 index bff8800630..0000000000 --- a/common/client-libs/directory-client/src/presence/coconodes.rs +++ /dev/null @@ -1,50 +0,0 @@ -// Copyright 2020 Nym Technologies SA -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -use serde::{Deserialize, Serialize}; -use topology::coco; - -#[derive(Clone, Debug, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct CocoPresence { - pub location: String, - pub host: String, - pub pub_key: String, - pub last_seen: u64, - pub version: String, -} - -impl Into for CocoPresence { - fn into(self) -> topology::coco::Node { - topology::coco::Node { - location: self.location, - host: self.host, - pub_key: self.pub_key, - last_seen: self.last_seen, - version: self.version, - } - } -} - -impl From for CocoPresence { - fn from(cn: coco::Node) -> Self { - CocoPresence { - location: cn.location, - host: cn.host, - pub_key: cn.pub_key, - last_seen: cn.last_seen, - version: cn.version, - } - } -} diff --git a/common/client-libs/directory-client/src/presence/gateways.rs b/common/client-libs/directory-client/src/presence/gateways.rs deleted file mode 100644 index 78ffa78f44..0000000000 --- a/common/client-libs/directory-client/src/presence/gateways.rs +++ /dev/null @@ -1,86 +0,0 @@ -// Copyright 2020 Nym Technologies SA -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -use serde::{Deserialize, Serialize}; -use topology::gateway; - -#[derive(Clone, Debug, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct GatewayPresence { - pub location: String, - pub client_listener: String, - pub mixnet_listener: String, - pub pub_key: String, - pub registered_clients: Vec, - pub last_seen: u64, - pub version: String, -} - -impl Into for GatewayPresence { - fn into(self) -> topology::gateway::Node { - topology::gateway::Node { - location: self.location, - client_listener: self.client_listener.parse().unwrap(), - mixnet_listener: self.mixnet_listener.parse().unwrap(), - pub_key: self.pub_key, - registered_clients: self - .registered_clients - .into_iter() - .map(|c| c.into()) - .collect(), - last_seen: self.last_seen, - version: self.version, - } - } -} - -impl From for GatewayPresence { - fn from(mpn: gateway::Node) -> Self { - GatewayPresence { - location: mpn.location, - client_listener: mpn.client_listener.to_string(), - mixnet_listener: mpn.mixnet_listener.to_string(), - pub_key: mpn.pub_key, - registered_clients: mpn - .registered_clients - .into_iter() - .map(|c| c.into()) - .collect(), - last_seen: mpn.last_seen, - version: mpn.version, - } - } -} - -#[derive(Clone, Debug, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct GatewayClient { - pub pub_key: String, -} - -impl Into for GatewayClient { - fn into(self) -> topology::gateway::Client { - topology::gateway::Client { - pub_key: self.pub_key, - } - } -} - -impl From for GatewayClient { - fn from(mpc: topology::gateway::Client) -> Self { - GatewayClient { - pub_key: mpc.pub_key, - } - } -} diff --git a/common/client-libs/directory-client/src/presence/mixnodes.rs b/common/client-libs/directory-client/src/presence/mixnodes.rs deleted file mode 100644 index b1f6e7f837..0000000000 --- a/common/client-libs/directory-client/src/presence/mixnodes.rs +++ /dev/null @@ -1,66 +0,0 @@ -// Copyright 2020 Nym Technologies SA -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -use serde::{Deserialize, Serialize}; -use std::convert::TryInto; -use std::io; -use std::net::ToSocketAddrs; -use topology::mix; - -#[derive(Clone, Debug, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct MixNodePresence { - pub location: String, - pub host: String, - pub pub_key: String, - pub layer: u64, - pub last_seen: u64, - pub version: String, -} - -impl TryInto for MixNodePresence { - type Error = io::Error; - - fn try_into(self) -> Result { - let resolved_hostname = self.host.to_socket_addrs()?.next(); - if resolved_hostname.is_none() { - return Err(io::Error::new( - io::ErrorKind::Other, - "no valid socket address", - )); - } - - Ok(topology::mix::Node { - location: self.location, - host: resolved_hostname.unwrap(), - pub_key: self.pub_key, - layer: self.layer, - last_seen: self.last_seen, - version: self.version, - }) - } -} - -impl From for MixNodePresence { - fn from(mn: mix::Node) -> Self { - MixNodePresence { - location: mn.location, - host: mn.host.to_string(), - pub_key: mn.pub_key, - layer: mn.layer, - last_seen: mn.last_seen, - version: mn.version, - } - } -} diff --git a/common/client-libs/directory-client/src/presence/providers.rs b/common/client-libs/directory-client/src/presence/providers.rs deleted file mode 100644 index 7f01f6d6b7..0000000000 --- a/common/client-libs/directory-client/src/presence/providers.rs +++ /dev/null @@ -1,86 +0,0 @@ -// Copyright 2020 Nym Technologies SA -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -use serde::{Deserialize, Serialize}; -use topology::provider; - -#[derive(Clone, Debug, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct MixProviderPresence { - pub location: String, - pub client_listener: String, - pub mixnet_listener: String, - pub pub_key: String, - pub registered_clients: Vec, - pub last_seen: u64, - pub version: String, -} - -impl Into for MixProviderPresence { - fn into(self) -> topology::provider::Node { - topology::provider::Node { - location: self.location, - client_listener: self.client_listener.parse().unwrap(), - mixnet_listener: self.mixnet_listener.parse().unwrap(), - pub_key: self.pub_key, - registered_clients: self - .registered_clients - .into_iter() - .map(|c| c.into()) - .collect(), - last_seen: self.last_seen, - version: self.version, - } - } -} - -impl From for MixProviderPresence { - fn from(mpn: provider::Node) -> Self { - MixProviderPresence { - location: mpn.location, - client_listener: mpn.client_listener.to_string(), - mixnet_listener: mpn.mixnet_listener.to_string(), - pub_key: mpn.pub_key, - registered_clients: mpn - .registered_clients - .into_iter() - .map(|c| c.into()) - .collect(), - last_seen: mpn.last_seen, - version: mpn.version, - } - } -} - -#[derive(Clone, Debug, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct MixProviderClient { - pub pub_key: String, -} - -impl Into for MixProviderClient { - fn into(self) -> topology::provider::Client { - topology::provider::Client { - pub_key: self.pub_key, - } - } -} - -impl From for MixProviderClient { - fn from(mpc: topology::provider::Client) -> Self { - MixProviderClient { - pub_key: mpc.pub_key, - } - } -} diff --git a/common/topology/Cargo.toml b/common/topology/Cargo.toml index 17a568b979..7d15a481a5 100644 --- a/common/topology/Cargo.toml +++ b/common/topology/Cargo.toml @@ -9,7 +9,6 @@ edition = "2018" [dependencies] bs58 = "0.3.0" itertools = "0.8.2" -futures = "0.3" log = "0.4" pretty_env_logger = "0.3" rand = "0.7.2" diff --git a/common/topology/src/lib.rs b/common/topology/src/lib.rs index c519572b1f..712c0eef21 100644 --- a/common/topology/src/lib.rs +++ b/common/topology/src/lib.rs @@ -13,7 +13,6 @@ // limitations under the License. use crate::filter::VersionFilterable; -use futures::future::BoxFuture; use itertools::Itertools; use nymsphinx_types::{Node as SphinxNode, NodeAddressBytes}; use rand::seq::IteratorRandom; @@ -29,10 +28,6 @@ pub mod provider; // TODO: Figure out why 'Clone' was required to have 'TopologyAccessor' working // even though it only contains an Arc pub trait NymTopology: Sized + std::fmt::Debug + Send + Sync + Clone { - // this is just a temporary work-around to make current code work without having to - // do major topology rewrites now. - // This will be removed once topology is re-worked - fn new<'a>(directory_server: String) -> BoxFuture<'a, Self>; fn new_from_nodes( mix_nodes: Vec, mix_provider_nodes: Vec, diff --git a/mixnode/src/node/mod.rs b/mixnode/src/node/mod.rs index 34089d3474..0338602719 100644 --- a/mixnode/src/node/mod.rs +++ b/mixnode/src/node/mod.rs @@ -15,13 +15,12 @@ use crate::config::Config; use crate::node::packet_processing::PacketProcessor; use crypto::encryption; -use directory_client::presence::Topology; +use directory_client::DirectoryClient; use futures::channel::mpsc; use log::*; use nymsphinx::SphinxPacket; use std::net::SocketAddr; use tokio::runtime::Runtime; -use topology::NymTopology; mod listener; mod metrics; @@ -102,10 +101,13 @@ impl MixNode { } fn check_if_same_ip_node_exists(&mut self) -> Option { - // TODO: once we change to graph topology this here will need to be updated! + let directory_client_config = + directory_client::Config::new(self.config.get_presence_directory_server()); + let directory_client = directory_client::Client::new(directory_client_config); let topology = self .runtime - .block_on(Topology::new(self.config.get_presence_directory_server())); + .block_on(directory_client.get_topology()) + .ok()?; let existing_mixes_presence = topology.mix_nodes; existing_mixes_presence .iter()