diff --git a/CHANGELOG.md b/CHANGELOG.md index 5dfcddc34a..983dcc4625 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,38 @@ # Changelog -## [Unreleased](https://github.com/nymtech/nym/tree/HEAD) +## [v0.4.1](https://github.com/nymtech/nym/tree/v0.4.1) (2020-01-29) -[Full Changelog](https://github.com/nymtech/nym/compare/v0.3.3...HEAD) +[Full Changelog](https://github.com/nymtech/nym/compare/v0.4.0...v0.4.1) + +**Closed issues:** + +- Change healthcheck to run on provided topology rather than pull one itself [\#95](https://github.com/nymtech/nym/issues/95) + +**Merged pull requests:** + +- Bugfix/healthcheck on provided topology [\#108](https://github.com/nymtech/nym/pull/108) ([jstuczyn](https://github.com/jstuczyn)) + +## [v0.4.0](https://github.com/nymtech/nym/tree/v0.4.0) (2020-01-28) + +[Full Changelog](https://github.com/nymtech/nym/compare/v0.4.0-rc.2...v0.4.0) + +Nym 0.4.0 Platform + +In this release, we're taking a lot more care with version numbers, so that we can ensure upgrade compatibility for mixnodes, providers, clients, and validators more easily. + +This release also integrates a health-checker and network topology refresh into the Nym client, so that the client can intelligently choose paths which route around any non-functional or incompatible nodes. + +## [v0.4.0-rc.2](https://github.com/nymtech/nym/tree/v0.4.0-rc.2) (2020-01-28) + +[Full Changelog](https://github.com/nymtech/nym/compare/v0.4.0-rc.1...v0.4.0-rc.2) + +**Merged pull requests:** + +- Hotfix/semver compatibility [\#106](https://github.com/nymtech/nym/pull/106) ([jstuczyn](https://github.com/jstuczyn)) + +## [v0.4.0-rc.1](https://github.com/nymtech/nym/tree/v0.4.0-rc.1) (2020-01-28) + +[Full Changelog](https://github.com/nymtech/nym/compare/v0.3.3...v0.4.0-rc.1) **Closed issues:** @@ -64,10 +94,6 @@ [Full Changelog](https://github.com/nymtech/nym/compare/v0.3.1...v0.3.2) -**Merged pull requests:** - -- Feature/separate presence address [\#59](https://github.com/nymtech/nym/pull/59) ([jstuczyn](https://github.com/jstuczyn)) - ## [v0.3.1](https://github.com/nymtech/nym/tree/v0.3.1) (2020-01-16) [Full Changelog](https://github.com/nymtech/nym/compare/v0.3.0...v0.3.1) @@ -94,6 +120,7 @@ **Merged pull requests:** +- Feature/separate presence address [\#59](https://github.com/nymtech/nym/pull/59) ([jstuczyn](https://github.com/jstuczyn)) - Feature/client topology filtering [\#54](https://github.com/nymtech/nym/pull/54) ([jstuczyn](https://github.com/jstuczyn)) - print public key for nym client tools [\#53](https://github.com/nymtech/nym/pull/53) ([mileschet](https://github.com/mileschet)) - Showing binding warning on binding to localhost, 0.0.0.0 or 127.0.0.1 [\#52](https://github.com/nymtech/nym/pull/52) ([jstuczyn](https://github.com/jstuczyn)) @@ -114,7 +141,11 @@ ## [v0.2.0](https://github.com/nymtech/nym/tree/v0.2.0) (2020-01-07) -[Full Changelog](https://github.com/nymtech/nym/compare/3c64a2facd753f4f2f431e7f888e54842e2bc64e...v0.2.0) +[Full Changelog](https://github.com/nymtech/nym/compare/0.2.0...v0.2.0) + +## [0.2.0](https://github.com/nymtech/nym/tree/0.2.0) (2020-01-06) + +[Full Changelog](https://github.com/nymtech/nym/compare/0.1.0...0.2.0) diff --git a/Cargo.lock b/Cargo.lock index 97d346cbc9..a8536a4cb2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1379,7 +1379,7 @@ dependencies = [ [[package]] name = "nym-client" -version = "0.4.0-rc.1" +version = "0.4.1" dependencies = [ "addressing", "bs58", @@ -1411,7 +1411,7 @@ dependencies = [ [[package]] name = "nym-mixnode" -version = "0.4.0-rc.1" +version = "0.4.1" dependencies = [ "addressing", "bs58", @@ -1429,7 +1429,7 @@ dependencies = [ [[package]] name = "nym-sfw-provider" -version = "0.4.0-rc.1" +version = "0.4.1" dependencies = [ "bs58", "built", @@ -1453,13 +1453,14 @@ dependencies = [ [[package]] name = "nym-validator" -version = "0.4.0-rc.1" +version = "0.4.1" dependencies = [ "abci", "built", "byteorder", "clap", "crypto", + "directory-client", "dotenv", "futures 0.3.1", "healthcheck", @@ -1469,6 +1470,7 @@ dependencies = [ "serde_derive", "tokio 0.2.10", "toml", + "topology", ] [[package]] diff --git a/common/crypto/src/identity/mod.rs b/common/crypto/src/identity/mod.rs index cf39000e5d..3c920f84dc 100644 --- a/common/crypto/src/identity/mod.rs +++ b/common/crypto/src/identity/mod.rs @@ -6,14 +6,13 @@ use bs58; use curve25519_dalek::scalar::Scalar; use sphinx::route::DestinationAddressBytes; -pub trait MixnetIdentityKeyPair: Clone -where - Priv: MixnetIdentityPrivateKey, - Pub: MixnetIdentityPublicKey, -{ +pub trait MixnetIdentityKeyPair: Clone { + type PublicKeyMaterial: MixnetIdentityPublicKey; + type PrivateKeyMaterial: MixnetIdentityPrivateKey; + fn new() -> Self; - fn private_key(&self) -> &Priv; - fn public_key(&self) -> &Pub; + fn private_key(&self) -> &Self::PrivateKeyMaterial; + fn public_key(&self) -> &Self::PublicKeyMaterial; fn from_bytes(priv_bytes: &[u8], pub_bytes: &[u8]) -> Self; // TODO: signing related methods @@ -56,9 +55,10 @@ pub struct DummyMixIdentityKeyPair { pub public_key: DummyMixIdentityPublicKey, } -impl MixnetIdentityKeyPair - for DummyMixIdentityKeyPair -{ +impl MixnetIdentityKeyPair for DummyMixIdentityKeyPair { + type PublicKeyMaterial = DummyMixIdentityPublicKey; + type PrivateKeyMaterial = DummyMixIdentityPrivateKey; + fn new() -> Self { let keypair = encryption::x25519::KeyPair::new(); DummyMixIdentityKeyPair { diff --git a/common/healthcheck/src/lib.rs b/common/healthcheck/src/lib.rs index b95eefd454..5554b2bb97 100644 --- a/common/healthcheck/src/lib.rs +++ b/common/healthcheck/src/lib.rs @@ -1,12 +1,9 @@ use crate::result::HealthCheckResult; -use crypto::identity::{MixnetIdentityKeyPair, MixnetIdentityPrivateKey, MixnetIdentityPublicKey}; -use directory_client::requests::presence_topology_get::PresenceTopologyGetRequester; -use directory_client::DirectoryClient; -use log::{debug, error, info, trace}; +use crypto::identity::MixnetIdentityKeyPair; +use log::trace; use std::fmt::{Error, Formatter}; -use std::marker::PhantomData; use std::time::Duration; -use topology::NymTopologyError; +use topology::{NymTopology, NymTopologyError}; pub mod config; mod path_check; @@ -36,58 +33,31 @@ impl From for HealthCheckerError { } } -pub struct HealthChecker -where - IDPair: MixnetIdentityKeyPair, - Priv: MixnetIdentityPrivateKey, - Pub: MixnetIdentityPublicKey, -{ - directory_client: directory_client::Client, - interval: Duration, +pub struct HealthChecker { num_test_packets: usize, resolution_timeout: Duration, identity_keypair: IDPair, - - _phantom_private: PhantomData, - _phantom_public: PhantomData, } -impl HealthChecker -where - IDPair: crypto::identity::MixnetIdentityKeyPair, - Priv: crypto::identity::MixnetIdentityPrivateKey, - Pub: crypto::identity::MixnetIdentityPublicKey, -{ - pub fn new(config: config::HealthCheck, identity_keypair: IDPair) -> Self { - debug!( - "healthcheck will be using the following directory server: {:?}", - config.directory_server - ); - let directory_client_config = directory_client::Config::new(config.directory_server); +impl HealthChecker { + pub fn new( + resolution_timeout_f64: f64, + num_test_packets: usize, + identity_keypair: IDPair, + ) -> Self { HealthChecker { - directory_client: directory_client::Client::new(directory_client_config), - interval: Duration::from_secs_f64(config.interval), - resolution_timeout: Duration::from_secs_f64(config.resolution_timeout), - num_test_packets: config.num_test_packets, + resolution_timeout: Duration::from_secs_f64(resolution_timeout_f64), + num_test_packets, identity_keypair, - - _phantom_private: PhantomData, - _phantom_public: PhantomData, } } - pub async fn do_check(&self) -> Result { + pub async fn do_check( + &self, + current_topology: &T, + ) -> Result { trace!("going to perform a healthcheck!"); - let current_topology = match self.directory_client.presence_topology.get() { - Ok(topology) => topology, - Err(err) => { - error!("failed to obtain topology - {:?}", err); - return Err(HealthCheckerError::FailedToObtainTopologyError); - } - }; - trace!("current topology: {:?}", current_topology); - let mut healthcheck_result = HealthCheckResult::calculate( current_topology, self.num_test_packets, @@ -98,20 +68,4 @@ where healthcheck_result.sort_scores(); Ok(healthcheck_result) } - - pub async fn run(self) -> Result<(), HealthCheckerError> { - debug!( - "healthcheck will run every {:?} and will send {} packets to each node", - self.interval, self.num_test_packets - ); - - loop { - match self.do_check().await { - Ok(health) => info!("current network health: \n{}", health), - Err(err) => error!("failed to perform healthcheck - {:?}", err), - }; - - tokio::time::delay_for(self.interval).await; - } - } } diff --git a/common/healthcheck/src/path_check.rs b/common/healthcheck/src/path_check.rs index b1d2617ad8..a345e82d99 100644 --- a/common/healthcheck/src/path_check.rs +++ b/common/healthcheck/src/path_check.rs @@ -1,4 +1,4 @@ -use crypto::identity::{MixnetIdentityKeyPair, MixnetIdentityPrivateKey, MixnetIdentityPublicKey}; +use crypto::identity::{MixnetIdentityKeyPair, MixnetIdentityPublicKey}; use itertools::Itertools; use log::{debug, error, info, trace, warn}; use mix_client::MixClient; @@ -27,16 +27,11 @@ pub(crate) struct PathChecker { } impl PathChecker { - pub(crate) async fn new( + pub(crate) async fn new( providers: Vec, identity_keys: &IDPair, check_id: [u8; 16], - ) -> Self - where - IDPair: MixnetIdentityKeyPair, - Priv: MixnetIdentityPrivateKey, - Pub: MixnetIdentityPublicKey, - { + ) -> Self { let mut provider_clients = HashMap::new(); let address = identity_keys.public_key().derive_address(); diff --git a/common/healthcheck/src/result.rs b/common/healthcheck/src/result.rs index 83d1f8778c..2dd199ffde 100644 --- a/common/healthcheck/src/result.rs +++ b/common/healthcheck/src/result.rs @@ -1,6 +1,6 @@ use crate::path_check::{PathChecker, PathStatus}; use crate::score::NodeScore; -use crypto::identity::{MixnetIdentityKeyPair, MixnetIdentityPrivateKey, MixnetIdentityPublicKey}; +use crypto::identity::MixnetIdentityKeyPair; use log::{debug, error, info, warn}; use rand_os::rand_core::RngCore; use sphinx::route::NodeAddressBytes; @@ -27,7 +27,7 @@ impl HealthCheckResult { self.0.sort(); } - fn zero_score(topology: T) -> Self { + fn zero_score(topology: &T) -> Self { warn!("The network is unhealthy, could not send any packets - returning zero score!"); let mixes = topology.mix_nodes(); let providers = topology.providers(); @@ -102,17 +102,15 @@ impl HealthCheckResult { id } - pub async fn calculate( - topology: T, + pub async fn calculate( + topology: &T, iterations: usize, resolution_timeout: Duration, identity_keys: &IDPair, ) -> Self where T: NymTopology, - IDPair: MixnetIdentityKeyPair, - Priv: MixnetIdentityPrivateKey, - Pub: MixnetIdentityPublicKey, + IDPair: MixnetIdentityKeyPair, { // currently healthchecker supports only up to 255 iterations - if we somehow // find we need more, it's relatively easy change diff --git a/common/pemstore/src/pemstore.rs b/common/pemstore/src/pemstore.rs index 9c7a914d02..84bc8cf60a 100644 --- a/common/pemstore/src/pemstore.rs +++ b/common/pemstore/src/pemstore.rs @@ -1,4 +1,6 @@ use crate::pathfinder::PathFinder; +use crypto::identity::{MixnetIdentityKeyPair, MixnetIdentityPrivateKey, MixnetIdentityPublicKey}; +use crypto::PemStorable; use pem::{encode, parse, Pem}; use std::fs::File; use std::io; @@ -25,12 +27,7 @@ impl PemStore { } } - pub fn read_identity(&self) -> io::Result - where - IDPair: crypto::identity::MixnetIdentityKeyPair, - Priv: crypto::identity::MixnetIdentityPrivateKey, - Pub: crypto::identity::MixnetIdentityPublicKey, - { + pub fn read_identity(&self) -> io::Result { let private_pem = self.read_pem_file(self.private_mix_key.clone())?; let public_pem = self.read_pem_file(self.public_mix_key.clone())?; @@ -62,12 +59,10 @@ impl PemStore { // This should be refactored and made more generic for when we have other kinds of // KeyPairs that we want to persist (e.g. validator keypairs, or keys for // signing vs encryption). However, for the moment, it does the job. - pub fn write_identity(&self, key_pair: IDPair) -> io::Result<()> - where - IDPair: crypto::identity::MixnetIdentityKeyPair, - Priv: crypto::identity::MixnetIdentityPrivateKey, - Pub: crypto::identity::MixnetIdentityPublicKey, - { + pub fn write_identity( + &self, + key_pair: IDPair, + ) -> io::Result<()> { std::fs::create_dir_all(self.config_dir.clone())?; let private_key = key_pair.private_key(); diff --git a/common/version-checker/src/lib.rs b/common/version-checker/src/lib.rs index 55232a9885..eda9391205 100644 --- a/common/version-checker/src/lib.rs +++ b/common/version-checker/src/lib.rs @@ -1,5 +1,4 @@ use semver::Version; -use semver::VersionReq; /// Checks whether given `version` is compatible with a given semantic version requirement `req` /// according to major-minor semver rules. The semantic version requirement can be passed as a full, @@ -7,18 +6,16 @@ use semver::VersionReq; /// The patch number in the requirement gets dropped and replaced with a wildcard (0.3.*) as all /// minor versions should be compatible with each other. pub fn is_minor_version_compatible(version: &str, req: &str) -> bool { - let version = match Version::parse(version) { + let expected_version = match Version::parse(version) { Ok(v) => v, Err(_) => return false, }; - let tmp = match Version::parse(req) { + let req_version = match Version::parse(req) { Ok(v) => v, Err(_) => return false, }; - let wildcard = format!("{}.{}.*", tmp.major, tmp.minor).to_string(); - let semver_requirement = VersionReq::parse(&wildcard).expect("panicked on semver requirement parsing. This should never happen as inputs should already have been sanitized."); - semver_requirement.matches(&version) + expected_version.major == req_version.major && expected_version.minor == req_version.minor } #[cfg(test)] @@ -55,6 +52,11 @@ mod tests { assert!(!is_minor_version_compatible("1.3.2", "0.3.2")); } + #[test] + fn version_0_4_0_rc_1_is_compatible_with_version_0_4_0_rc_1() { + assert!(is_minor_version_compatible("0.4.0-rc.1", "0.4.0-rc.1")); + } + #[test] fn returns_false_on_foo_version() { assert!(!is_minor_version_compatible("foo", "0.3.2")); diff --git a/mixnode/Cargo.toml b/mixnode/Cargo.toml index a87431cd2e..4685d6416e 100644 --- a/mixnode/Cargo.toml +++ b/mixnode/Cargo.toml @@ -1,7 +1,7 @@ [package] build = "build.rs" name = "nym-mixnode" -version = "0.4.0-rc.1" +version = "0.4.1" authors = ["Dave Hrycyszyn ", "Jędrzej Stuczyński "] edition = "2018" diff --git a/nym-client/Cargo.toml b/nym-client/Cargo.toml index ec184005c2..e5b16383f7 100644 --- a/nym-client/Cargo.toml +++ b/nym-client/Cargo.toml @@ -1,7 +1,7 @@ [package] build = "build.rs" name = "nym-client" -version = "0.4.0-rc.1" +version = "0.4.1" authors = ["Dave Hrycyszyn ", "Jędrzej Stuczyński "] edition = "2018" diff --git a/nym-client/src/client/mod.rs b/nym-client/src/client/mod.rs index 4d4e0da408..8bb090b95f 100644 --- a/nym-client/src/client/mod.rs +++ b/nym-client/src/client/mod.rs @@ -3,14 +3,13 @@ use crate::client::received_buffer::ReceivedMessagesBuffer; use crate::client::topology_control::TopologyInnerRef; use crate::sockets::tcp; use crate::sockets::ws; -use crypto::identity::{MixnetIdentityKeyPair, MixnetIdentityPrivateKey, MixnetIdentityPublicKey}; +use crypto::identity::{MixnetIdentityKeyPair, MixnetIdentityPublicKey}; use directory_client::presence::Topology; use futures::channel::mpsc; use futures::join; use log::*; use sfw_provider_requests::AuthToken; use sphinx::route::Destination; -use std::marker::PhantomData; use std::net::SocketAddr; use tokio::runtime::Runtime; use topology::NymTopology; @@ -37,11 +36,9 @@ pub enum SocketType { None, } -pub struct NymClient +pub struct NymClient where - IDPair: MixnetIdentityKeyPair + Send + Sync, - Priv: MixnetIdentityPrivateKey + Send + Sync, - Pub: MixnetIdentityPublicKey + Send + Sync, + IDPair: MixnetIdentityKeyPair + Send + Sync, { keypair: IDPair, @@ -53,19 +50,14 @@ where directory: String, auth_token: Option, socket_type: SocketType, - - _phantom_private: PhantomData, - _phantom_public: PhantomData, } #[derive(Debug)] pub struct InputMessage(pub Destination, pub Vec); -impl NymClient +impl NymClient where - IDPair: MixnetIdentityKeyPair + Send + Sync, - Priv: MixnetIdentityPrivateKey + Send + Sync, - Pub: MixnetIdentityPublicKey + Send + Sync, + IDPair: 'static + MixnetIdentityKeyPair + Send + Sync, { pub fn new( keypair: IDPair, @@ -84,8 +76,6 @@ where directory, auth_token, socket_type, - _phantom_private: PhantomData, - _phantom_public: PhantomData, } } @@ -129,7 +119,7 @@ where // TODO: when we switch to our graph topology, we need to remember to change 'Topology' type let topology_controller = - rt.block_on(topology_control::TopologyControl::::new( + rt.block_on(topology_control::TopologyControl::::new( self.directory.clone(), TOPOLOGY_REFRESH_RATE, healthcheck_keys, diff --git a/nym-client/src/client/topology_control.rs b/nym-client/src/client/topology_control.rs index 9daafc0572..5ec9422782 100644 --- a/nym-client/src/client/topology_control.rs +++ b/nym-client/src/client/topology_control.rs @@ -1,5 +1,5 @@ use crate::built_info; -use crypto::identity::{MixnetIdentityKeyPair, MixnetIdentityPrivateKey, MixnetIdentityPublicKey}; +use crypto::identity::MixnetIdentityKeyPair; use healthcheck::HealthChecker; use log::{error, info, trace, warn}; use std::sync::Arc; @@ -12,16 +12,14 @@ const NODE_HEALTH_THRESHOLD: f64 = 0.0; // auxiliary type for ease of use pub type TopologyInnerRef = Arc>>; -pub(crate) struct TopologyControl +pub(crate) struct TopologyControl where T: NymTopology, - IDPair: MixnetIdentityKeyPair, - Priv: MixnetIdentityPrivateKey, - Pub: MixnetIdentityPublicKey, + IDPair: MixnetIdentityKeyPair, { directory_server: String, inner: Arc>>, - health_checker: HealthChecker, + health_checker: HealthChecker, refresh_rate: f64, } @@ -31,29 +29,18 @@ enum TopologyError { NoValidPathsError, } -impl TopologyControl +impl TopologyControl where T: NymTopology, - IDPair: MixnetIdentityKeyPair, - Priv: MixnetIdentityPrivateKey, - Pub: MixnetIdentityPublicKey, + IDPair: MixnetIdentityKeyPair, { pub(crate) async fn new( directory_server: String, refresh_rate: f64, identity_keypair: IDPair, ) -> Self { - // topology control run a healthcheck to determine healthy-ish nodes: // this is a temporary solution as the healthcheck will eventually be moved to validators - - let healthcheck_config = healthcheck::config::HealthCheck { - directory_server: directory_server.clone(), - // those are literally irrelevant when running single check - interval: 100000.0, - resolution_timeout: 5.0, - num_test_packets: 2, - }; - let health_checker = healthcheck::HealthChecker::new(healthcheck_config, identity_keypair); + let health_checker = healthcheck::HealthChecker::new(5.0, 2, identity_keypair); let mut topology_control = TopologyControl { directory_server, @@ -79,8 +66,16 @@ where async fn get_current_compatible_topology(&self) -> Result { let full_topology = T::new(self.directory_server.clone()); + let version_filtered_topology = full_topology.filter_node_versions( + built_info::PKG_VERSION, + built_info::PKG_VERSION, + built_info::PKG_VERSION, + ); - let healthcheck_result = self.health_checker.do_check().await; + let healthcheck_result = self + .health_checker + .do_check(&version_filtered_topology) + .await; let healthcheck_scores = match healthcheck_result { Err(err) => { error!("Error while performing the healthcheck: {:?}", err); @@ -89,21 +84,15 @@ where Ok(scores) => scores, }; - let healthy_topology = - healthcheck_scores.filter_topology_by_score(&full_topology, NODE_HEALTH_THRESHOLD); - - let versioned_healthy_topology = healthy_topology.filter_node_versions( - built_info::PKG_VERSION, - built_info::PKG_VERSION, - built_info::PKG_VERSION, - ); + let healthy_topology = healthcheck_scores + .filter_topology_by_score(&version_filtered_topology, NODE_HEALTH_THRESHOLD); // make sure you can still send a packet through the network: - if !versioned_healthy_topology.can_construct_path_through() { + if !healthy_topology.can_construct_path_through() { return Err(TopologyError::NoValidPathsError); } - Ok(versioned_healthy_topology) + Ok(healthy_topology) } pub(crate) fn get_inner_ref(&self) -> Arc>> { diff --git a/scripts/generate_changelog.sh b/scripts/generate_changelog.sh new file mode 100755 index 0000000000..22097168ba --- /dev/null +++ b/scripts/generate_changelog.sh @@ -0,0 +1,3 @@ +#!/bin/bash +# set CHANGELOG_GITHUB_TOKEN in your .bashrc file +github_changelog_generator -u nymtech -p nym --exclude-tags 0.1.0 --token "$CHANGELOG_GITHUB_TOKEN" diff --git a/sfw-provider/Cargo.toml b/sfw-provider/Cargo.toml index 5bb8306412..d2a7cf2c5c 100644 --- a/sfw-provider/Cargo.toml +++ b/sfw-provider/Cargo.toml @@ -1,7 +1,7 @@ [package] build = "build.rs" name = "nym-sfw-provider" -version = "0.4.0-rc.1" +version = "0.4.1" authors = ["Dave Hrycyszyn ", "Jędrzej Stuczyński "] edition = "2018" diff --git a/validator/Cargo.toml b/validator/Cargo.toml index d59ebdbf06..6d9b2d92de 100644 --- a/validator/Cargo.toml +++ b/validator/Cargo.toml @@ -1,7 +1,7 @@ [package] build = "build.rs" name = "nym-validator" -version = "0.4.0-rc.1" +version = "0.4.1" authors = ["Jedrzej Stuczynski "] edition = "2018" @@ -23,7 +23,9 @@ toml = "0.5.5" ## internal crypto = {path = "../common/crypto"} +directory-client = { path = "../common/clients/directory-client" } healthcheck = {path = "../common/healthcheck" } +topology = {path = "../common/topology"} [build-dependencies] built = "0.3.2" diff --git a/validator/src/main.rs b/validator/src/main.rs index 335c3b0845..20d7ee6f2d 100644 --- a/validator/src/main.rs +++ b/validator/src/main.rs @@ -6,6 +6,7 @@ use std::process; use toml; mod network; +mod services; mod validator; fn main() { diff --git a/validator/src/network/tendermint.rs b/validator/src/network/tendermint.rs index 4a581774e6..2f3d2b924a 100644 --- a/validator/src/network/tendermint.rs +++ b/validator/src/network/tendermint.rs @@ -21,8 +21,8 @@ impl Abci { Abci { count: 0 } } - pub async fn run(self) { - abci::run_local(self); + pub fn run(self) { + tokio::spawn(async { abci::run_local(self) }) } } diff --git a/validator/src/services/mixmining/health_check_runner.rs b/validator/src/services/mixmining/health_check_runner.rs new file mode 100644 index 0000000000..c2bd6c7b18 --- /dev/null +++ b/validator/src/services/mixmining/health_check_runner.rs @@ -0,0 +1,50 @@ +use crypto::identity::MixnetIdentityKeyPair; +use healthcheck::HealthChecker; +use log::*; +use std::time::Duration; +use topology::NymTopology; + +pub struct HealthCheckRunner { + directory_server: String, + health_checker: HealthChecker, + interval: f64, +} + +impl HealthCheckRunner { + pub fn new( + directory_server: String, + interval: f64, + health_checker: HealthChecker, + ) -> HealthCheckRunner { + HealthCheckRunner { + directory_server, + health_checker, + interval, + } + } + + pub async fn run(self) { + tokio::spawn(async move { + let healthcheck_interval = Duration::from_secs_f64(self.interval); + debug!("healthcheck will run every {:?}", healthcheck_interval); + loop { + let full_topology = + directory_client::presence::Topology::new(self.directory_server.clone()); + let version_filtered_topology = full_topology.filter_node_versions( + crate::built_info::PKG_VERSION, + crate::built_info::PKG_VERSION, + crate::built_info::PKG_VERSION, + ); + match self + .health_checker + .do_check(&version_filtered_topology) + .await + { + Ok(health) => info!("current network health: \n{}", health), + Err(err) => error!("failed to perform healthcheck - {:?}", err), + }; + tokio::time::delay_for(healthcheck_interval).await; + } + }); + } +} diff --git a/validator/src/services/mixmining/mod.rs b/validator/src/services/mixmining/mod.rs new file mode 100644 index 0000000000..b80e115b6d --- /dev/null +++ b/validator/src/services/mixmining/mod.rs @@ -0,0 +1 @@ +pub mod health_check_runner; diff --git a/validator/src/services/mod.rs b/validator/src/services/mod.rs new file mode 100644 index 0000000000..ce0375046b --- /dev/null +++ b/validator/src/services/mod.rs @@ -0,0 +1 @@ +pub mod mixmining; diff --git a/validator/src/validator.rs b/validator/src/validator.rs index 343b8f54cd..1ba280dae7 100644 --- a/validator/src/validator.rs +++ b/validator/src/validator.rs @@ -1,8 +1,6 @@ use crate::network::tendermint; -use crypto::identity::{ - DummyMixIdentityKeyPair, DummyMixIdentityPrivateKey, DummyMixIdentityPublicKey, - MixnetIdentityKeyPair, MixnetIdentityPrivateKey, MixnetIdentityPublicKey, -}; +use crate::services::mixmining::health_check_runner; +use crypto::identity::{DummyMixIdentityKeyPair, MixnetIdentityKeyPair}; use healthcheck::HealthChecker; use tokio::runtime::Runtime; @@ -15,39 +13,41 @@ pub struct Config { } // allow for a generic validator -pub struct Validator -where - IDPair: MixnetIdentityKeyPair, - Priv: MixnetIdentityPrivateKey, - Pub: MixnetIdentityPublicKey, -{ - tendermint_abci: tendermint::Abci, - health_check: HealthChecker, +pub struct Validator { + config: Config, #[allow(dead_code)] identity_keypair: IDPair, + health_check_runner: health_check_runner::HealthCheckRunner, + tendermint_abci: tendermint::Abci, } // but for time being, since it's a dummy one, have it use dummy keys -impl Validator { +impl Validator { pub fn new(config: Config) -> Self { let dummy_keypair = DummyMixIdentityKeyPair::new(); + let hc = HealthChecker::new( + config.health_check.resolution_timeout, + config.health_check.num_test_packets, + dummy_keypair.clone(), + ); + + let health_check_runner = health_check_runner::HealthCheckRunner::new( + config.health_check.directory_server.clone(), + config.health_check.interval, + hc, + ); Validator { - tendermint_abci: tendermint::Abci::new(), - health_check: HealthChecker::new(config.health_check, dummy_keypair.clone()), identity_keypair: dummy_keypair, + health_check_runner, + config, + tendermint_abci: tendermint::Abci::new(), } } pub fn start(self) { let mut rt = Runtime::new().unwrap(); - - let abci_future = self.tendermint_abci.run(); - let health_check_future = self.health_check.run(); - - rt.spawn(abci_future); - - let health_check_res = rt.block_on(health_check_future); - assert!(health_check_res.is_ok()); // panic if health checker failed + rt.spawn(self.health_check_runner.run()); + rt.block_on(self.tendermint_abci.run()); } }