diff --git a/.gitignore b/.gitignore index 74a82c4e13..0e2a851081 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,4 @@ target .env /.vscode/settings.json +sample-configs/validator-config.toml \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index 4b78ab0517..52ee8ead93 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,5 +1,22 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. +[[package]] +name = "abci" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1cfb90d266d6ca61cea4d155dd5033c9516495f4f74f82faf1ca5c4feeb82577" +dependencies = [ + "byteorder", + "bytes 0.4.12", + "env_logger 0.7.1", + "futures 0.3.1", + "integer-encoding", + "log", + "protobuf", + "protobuf-codegen-pure", + "tokio 0.1.22", +] + [[package]] name = "addressing" version = "0.1.0" @@ -606,6 +623,19 @@ dependencies = [ "termcolor", ] +[[package]] +name = "env_logger" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44533bbbb3bb3c1fa17d9f2e4e38bbbaf8396ba82193c4cb1b6445d711445d36" +dependencies = [ + "atty", + "humantime", + "log", + "regex", + "termcolor", +] + [[package]] name = "error-chain" version = "0.12.1" @@ -1043,6 +1073,12 @@ dependencies = [ "bytes 0.4.12", ] +[[package]] +name = "integer-encoding" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1aec89c15e2cfa0f0eae8ca60e03cb10b30d25ea2c0ad7d6be60a95e32729994" + [[package]] name = "iovec" version = "0.1.4" @@ -1449,7 +1485,9 @@ dependencies = [ name = "nym-validator" version = "0.4.1" dependencies = [ + "abci", "built", + "byteorder", "clap", "crypto", "directory-client", @@ -1656,7 +1694,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "717ee476b1690853d222af4634056d830b5197ffd747726a9a1eee6da9f49074" dependencies = [ "chrono", - "env_logger", + "env_logger 0.6.2", "log", ] @@ -1686,6 +1724,31 @@ dependencies = [ "unicode-xid", ] +[[package]] +name = "protobuf" +version = "2.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6563a657a014b771e7f69f06447d88d8fbb5a215ffc4cab724afb3acedcc7701" + +[[package]] +name = "protobuf-codegen" +version = "2.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f1bbc6db30d5d3e730b6e2326e9a64a75ca9c80d6427d6f054dc8cacc79d225" +dependencies = [ + "protobuf", +] + +[[package]] +name = "protobuf-codegen-pure" +version = "2.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db5473ffa23d2ea3b9046764f1a22149791967aad946b6cbd99601e720afc4d0" +dependencies = [ + "protobuf", + "protobuf-codegen", +] + [[package]] name = "provider-client" version = "0.1.0" @@ -2314,6 +2377,7 @@ dependencies = [ "futures 0.1.29", "mio", "num_cpus", + "tokio-codec", "tokio-current-thread", "tokio-executor", "tokio-io", @@ -2358,6 +2422,17 @@ dependencies = [ "futures 0.1.29", ] +[[package]] +name = "tokio-codec" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c501eceaf96f0e1793cf26beb63da3d11c738c4a943fdf3746d81d64684c39f" +dependencies = [ + "bytes 0.4.12", + "futures 0.1.29", + "tokio-io", +] + [[package]] name = "tokio-current-thread" version = "0.1.6" diff --git a/common/crypto/src/encryption/mod.rs b/common/crypto/src/encryption/mod.rs index b36ddf1af7..4a38cd89ed 100644 --- a/common/crypto/src/encryption/mod.rs +++ b/common/crypto/src/encryption/mod.rs @@ -1,39 +1,92 @@ use crate::PemStorable; +use curve25519_dalek::montgomery::MontgomeryPoint; +use curve25519_dalek::scalar::Scalar; -pub mod x25519; +// TODO: ensure this is a proper name for this considering we are not implementing entire DH here -pub trait MixnetEncryptionKeyPair -where - Priv: MixnetEncryptionPrivateKey, - Pub: MixnetEncryptionPublicKey, -{ - fn new() -> Self; - fn private_key(&self) -> &Priv; - fn public_key(&self) -> &Pub; - fn from_bytes(priv_bytes: &[u8], pub_bytes: &[u8]) -> Self; +const CURVE_GENERATOR: MontgomeryPoint = curve25519_dalek::constants::X25519_BASEPOINT; - // TODO: encryption related methods +pub struct KeyPair { + pub(crate) private_key: PrivateKey, + pub(crate) public_key: PublicKey, } -pub trait MixnetEncryptionPublicKey: - Sized + PemStorable + for<'a> From<&'a ::PrivateKeyMaterial> -{ - // we need to couple public and private keys together - type PrivateKeyMaterial: MixnetEncryptionPrivateKey; +impl KeyPair { + pub fn new() -> Self { + let mut rng = rand_os::OsRng::new().unwrap(); + let private_key_value = Scalar::random(&mut rng); + let public_key_value = CURVE_GENERATOR * private_key_value; - fn to_bytes(&self) -> Vec; - fn from_bytes(b: &[u8]) -> Self; -} - -pub trait MixnetEncryptionPrivateKey: Sized + PemStorable { - // we need to couple public and private keys together - type PublicKeyMaterial: MixnetEncryptionPublicKey; - - /// Returns the associated public key - fn public_key(&self) -> Self::PublicKeyMaterial { - self.into() + KeyPair { + private_key: PrivateKey(private_key_value), + public_key: PublicKey(public_key_value), + } } - fn to_bytes(&self) -> Vec; - fn from_bytes(b: &[u8]) -> Self; + pub fn private_key(&self) -> &PrivateKey { + &self.private_key + } + + pub fn public_key(&self) -> &PublicKey { + &self.public_key + } + + pub fn from_bytes(priv_bytes: &[u8], pub_bytes: &[u8]) -> Self { + KeyPair { + private_key: PrivateKey::from_bytes(priv_bytes), + public_key: PublicKey::from_bytes(pub_bytes), + } + } +} + +// COPY IS DERIVED ONLY TEMPORARILY UNTIL https://github.com/nymtech/nym/issues/47 is fixed +#[derive(Debug, Clone, Copy, Eq, PartialEq)] +pub struct PrivateKey(pub Scalar); + +impl PrivateKey { + pub fn to_bytes(&self) -> Vec { + self.0.to_bytes().to_vec() + } + + pub fn from_bytes(b: &[u8]) -> Self { + let mut bytes = [0; 32]; + bytes.copy_from_slice(&b[..]); + // due to trait restriction we have no choice but to panic if this fails + let key = Scalar::from_canonical_bytes(bytes).unwrap(); + Self(key) + } +} + +impl PemStorable for PrivateKey { + fn pem_type(&self) -> String { + String::from("X25519 PRIVATE KEY") + } +} + +#[derive(Debug, Clone, Eq, PartialEq)] +pub struct PublicKey(pub MontgomeryPoint); + +impl<'a> From<&'a PrivateKey> for PublicKey { + fn from(pk: &'a PrivateKey) -> Self { + PublicKey(CURVE_GENERATOR * pk.0) + } +} + +impl PublicKey { + pub fn to_bytes(&self) -> Vec { + self.0.to_bytes().to_vec() + } + + pub fn from_bytes(b: &[u8]) -> Self { + let mut bytes = [0; 32]; + bytes.copy_from_slice(&b[..]); + let key = MontgomeryPoint(bytes); + Self(key) + } +} + +impl PemStorable for PublicKey { + fn pem_type(&self) -> String { + String::from("X25519 PUBLIC KEY") + } } diff --git a/common/crypto/src/encryption/x25519.rs b/common/crypto/src/encryption/x25519.rs deleted file mode 100644 index 44d86783da..0000000000 --- a/common/crypto/src/encryption/x25519.rs +++ /dev/null @@ -1,99 +0,0 @@ -use crate::encryption::{ - MixnetEncryptionKeyPair, MixnetEncryptionPrivateKey, MixnetEncryptionPublicKey, -}; -use crate::PemStorable; -use curve25519_dalek::montgomery::MontgomeryPoint; -use curve25519_dalek::scalar::Scalar; - -// TODO: ensure this is a proper name for this considering we are not implementing entire DH here - -const CURVE_GENERATOR: MontgomeryPoint = curve25519_dalek::constants::X25519_BASEPOINT; - -pub struct KeyPair { - pub(crate) private_key: PrivateKey, - pub(crate) public_key: PublicKey, -} - -impl MixnetEncryptionKeyPair for KeyPair { - fn new() -> Self { - let mut rng = rand_os::OsRng::new().unwrap(); - let private_key_value = Scalar::random(&mut rng); - let public_key_value = CURVE_GENERATOR * private_key_value; - - KeyPair { - private_key: PrivateKey(private_key_value), - public_key: PublicKey(public_key_value), - } - } - - fn private_key(&self) -> &PrivateKey { - &self.private_key - } - - fn public_key(&self) -> &PublicKey { - &self.public_key - } - - fn from_bytes(priv_bytes: &[u8], pub_bytes: &[u8]) -> Self { - KeyPair { - private_key: PrivateKey::from_bytes(priv_bytes), - public_key: PublicKey::from_bytes(pub_bytes), - } - } -} - -// COPY IS DERIVED ONLY TEMPORARILY UNTIL https://github.com/nymtech/nym/issues/47 is fixed -#[derive(Debug, Clone, Copy, Eq, PartialEq)] -pub struct PrivateKey(pub Scalar); - -impl MixnetEncryptionPrivateKey for PrivateKey { - type PublicKeyMaterial = PublicKey; - - fn to_bytes(&self) -> Vec { - self.0.to_bytes().to_vec() - } - - fn from_bytes(b: &[u8]) -> Self { - let mut bytes = [0; 32]; - bytes.copy_from_slice(&b[..]); - // due to trait restriction we have no choice but to panic if this fails - let key = Scalar::from_canonical_bytes(bytes).unwrap(); - Self(key) - } -} - -impl PemStorable for PrivateKey { - fn pem_type(&self) -> String { - String::from("X25519 PRIVATE KEY") - } -} - -#[derive(Debug, Clone, Eq, PartialEq)] -pub struct PublicKey(pub MontgomeryPoint); - -impl<'a> From<&'a PrivateKey> for PublicKey { - fn from(pk: &'a PrivateKey) -> Self { - PublicKey(CURVE_GENERATOR * pk.0) - } -} - -impl MixnetEncryptionPublicKey for PublicKey { - type PrivateKeyMaterial = PrivateKey; - - fn to_bytes(&self) -> Vec { - self.0.to_bytes().to_vec() - } - - fn from_bytes(b: &[u8]) -> Self { - let mut bytes = [0; 32]; - bytes.copy_from_slice(&b[..]); - let key = MontgomeryPoint(bytes); - Self(key) - } -} - -impl PemStorable for PublicKey { - fn pem_type(&self) -> String { - String::from("X25519 PUBLIC KEY") - } -} diff --git a/common/crypto/src/identity/mod.rs b/common/crypto/src/identity/mod.rs index cf39000e5d..270e25dcfb 100644 --- a/common/crypto/src/identity/mod.rs +++ b/common/crypto/src/identity/mod.rs @@ -1,95 +1,46 @@ -use crate::encryption::{ - MixnetEncryptionKeyPair, MixnetEncryptionPrivateKey, MixnetEncryptionPublicKey, -}; use crate::{encryption, PemStorable}; use bs58; use curve25519_dalek::scalar::Scalar; use sphinx::route::DestinationAddressBytes; -pub trait MixnetIdentityKeyPair: Clone -where - Priv: MixnetIdentityPrivateKey, - Pub: MixnetIdentityPublicKey, -{ - fn new() -> Self; - fn private_key(&self) -> &Priv; - fn public_key(&self) -> &Pub; - fn from_bytes(priv_bytes: &[u8], pub_bytes: &[u8]) -> Self; - - // TODO: signing related methods -} - -pub trait MixnetIdentityPublicKey: - Sized - + PemStorable - + Clone - + for<'a> From<&'a ::PrivateKeyMaterial> -{ - // we need to couple public and private keys together - type PrivateKeyMaterial: MixnetIdentityPrivateKey; - - fn derive_address(&self) -> DestinationAddressBytes; - fn to_bytes(&self) -> Vec; - fn from_bytes(b: &[u8]) -> Self; -} - -pub trait MixnetIdentityPrivateKey: Sized + PemStorable + Clone { - // we need to couple public and private keys together - type PublicKeyMaterial: MixnetIdentityPublicKey; - - /// Returns the associated public key - fn public_key(&self) -> Self::PublicKeyMaterial { - self.into() - } - - fn to_bytes(&self) -> Vec; - fn from_bytes(b: &[u8]) -> Self; -} - -// same for validator - // for time being define a dummy identity using x25519 encryption keys (as we've done so far) // and replace it with proper keys, like ed25519 later on #[derive(Clone)] -pub struct DummyMixIdentityKeyPair { - pub private_key: DummyMixIdentityPrivateKey, - pub public_key: DummyMixIdentityPublicKey, +pub struct MixIdentityKeyPair { + pub private_key: MixIdentityPrivateKey, + pub public_key: MixIdentityPublicKey, } -impl MixnetIdentityKeyPair - for DummyMixIdentityKeyPair -{ - fn new() -> Self { - let keypair = encryption::x25519::KeyPair::new(); - DummyMixIdentityKeyPair { - private_key: DummyMixIdentityPrivateKey(keypair.private_key), - public_key: DummyMixIdentityPublicKey(keypair.public_key), +impl MixIdentityKeyPair { + pub fn new() -> Self { + let keypair = encryption::KeyPair::new(); + MixIdentityKeyPair { + private_key: MixIdentityPrivateKey(keypair.private_key), + public_key: MixIdentityPublicKey(keypair.public_key), } } - fn private_key(&self) -> &DummyMixIdentityPrivateKey { + pub fn private_key(&self) -> &MixIdentityPrivateKey { &self.private_key } - fn public_key(&self) -> &DummyMixIdentityPublicKey { + pub fn public_key(&self) -> &MixIdentityPublicKey { &self.public_key } - fn from_bytes(priv_bytes: &[u8], pub_bytes: &[u8]) -> Self { - DummyMixIdentityKeyPair { - private_key: DummyMixIdentityPrivateKey::from_bytes(priv_bytes), - public_key: DummyMixIdentityPublicKey::from_bytes(pub_bytes), + pub fn from_bytes(priv_bytes: &[u8], pub_bytes: &[u8]) -> Self { + MixIdentityKeyPair { + private_key: MixIdentityPrivateKey::from_bytes(priv_bytes), + public_key: MixIdentityPublicKey::from_bytes(pub_bytes), } } } #[derive(Debug, Clone, Eq, PartialEq)] -pub struct DummyMixIdentityPublicKey(encryption::x25519::PublicKey); +pub struct MixIdentityPublicKey(encryption::PublicKey); -impl MixnetIdentityPublicKey for DummyMixIdentityPublicKey { - type PrivateKeyMaterial = DummyMixIdentityPrivateKey; - - fn derive_address(&self) -> DestinationAddressBytes { +impl MixIdentityPublicKey { + pub fn derive_address(&self) -> DestinationAddressBytes { let mut temporary_address = [0u8; 32]; let public_key_bytes = self.to_bytes(); temporary_address.copy_from_slice(&public_key_bytes[..]); @@ -97,65 +48,60 @@ impl MixnetIdentityPublicKey for DummyMixIdentityPublicKey { temporary_address } - fn to_bytes(&self) -> Vec { + pub fn to_bytes(&self) -> Vec { self.0.to_bytes() } - fn from_bytes(b: &[u8]) -> Self { - Self(encryption::x25519::PublicKey::from_bytes(b)) + pub fn from_bytes(b: &[u8]) -> Self { + Self(encryption::PublicKey::from_bytes(b)) + } + + pub fn to_base58_string(&self) -> String { + bs58::encode(&self.to_bytes()).into_string() + } + + pub fn from_base58_string(val: String) -> Self { + Self::from_bytes(&bs58::decode(&val).into_vec().unwrap()) } } -impl PemStorable for DummyMixIdentityPublicKey { +impl PemStorable for MixIdentityPublicKey { fn pem_type(&self) -> String { format!("DUMMY KEY BASED ON {}", self.0.pem_type()) } } -impl DummyMixIdentityPublicKey { - pub fn to_base58_string(&self) -> String { - bs58::encode(&self.to_bytes()).into_string() - } - - #[allow(dead_code)] - fn from_base58_string(val: String) -> Self { - Self::from_bytes(&bs58::decode(&val).into_vec().unwrap()) - } -} - // COPY IS DERIVED ONLY TEMPORARILY UNTIL https://github.com/nymtech/nym/issues/47 is fixed #[derive(Debug, Clone, Copy, Eq, PartialEq)] -pub struct DummyMixIdentityPrivateKey(pub encryption::x25519::PrivateKey); +pub struct MixIdentityPrivateKey(pub encryption::PrivateKey); -impl<'a> From<&'a DummyMixIdentityPrivateKey> for DummyMixIdentityPublicKey { - fn from(pk: &'a DummyMixIdentityPrivateKey) -> Self { +impl<'a> From<&'a MixIdentityPrivateKey> for MixIdentityPublicKey { + fn from(pk: &'a MixIdentityPrivateKey) -> Self { let private_ref = &pk.0; - let public: encryption::x25519::PublicKey = private_ref.into(); - DummyMixIdentityPublicKey(public) + let public: encryption::PublicKey = private_ref.into(); + MixIdentityPublicKey(public) } } -impl MixnetIdentityPrivateKey for DummyMixIdentityPrivateKey { - type PublicKeyMaterial = DummyMixIdentityPublicKey; - - fn to_bytes(&self) -> Vec { +impl MixIdentityPrivateKey { + pub fn to_bytes(&self) -> Vec { self.0.to_bytes() } - fn from_bytes(b: &[u8]) -> Self { - Self(encryption::x25519::PrivateKey::from_bytes(b)) + pub fn from_bytes(b: &[u8]) -> Self { + Self(encryption::PrivateKey::from_bytes(b)) } } // TODO: this will be implemented differently by using the proper trait -impl DummyMixIdentityPrivateKey { +impl MixIdentityPrivateKey { pub fn as_scalar(self) -> Scalar { let encryption_key = self.0; encryption_key.0 } } -impl PemStorable for DummyMixIdentityPrivateKey { +impl PemStorable for MixIdentityPrivateKey { fn pem_type(&self) -> String { format!("DUMMY KEY BASED ON {}", self.0.pem_type()) } diff --git a/common/healthcheck/src/lib.rs b/common/healthcheck/src/lib.rs index 7cd97692db..fc4be5850e 100644 --- a/common/healthcheck/src/lib.rs +++ b/common/healthcheck/src/lib.rs @@ -1,10 +1,7 @@ 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::MixIdentityKeyPair; +use log::trace; use std::fmt::{Error, Formatter}; -use std::marker::PhantomData; use std::time::Duration; use topology::{NymTopology, NymTopologyError}; @@ -36,38 +33,22 @@ impl From for HealthCheckerError { } } -pub struct HealthChecker -where - IDPair: MixnetIdentityKeyPair, - Priv: MixnetIdentityPrivateKey, - Pub: MixnetIdentityPublicKey, -{ +pub struct HealthChecker { num_test_packets: usize, resolution_timeout: Duration, - identity_keypair: IDPair, - - _phantom_private: PhantomData, - _phantom_public: PhantomData, + identity_keypair: MixIdentityKeyPair, } -impl HealthChecker -where - IDPair: crypto::identity::MixnetIdentityKeyPair, - Priv: crypto::identity::MixnetIdentityPrivateKey, - Pub: crypto::identity::MixnetIdentityPublicKey, -{ +impl HealthChecker { pub fn new( resolution_timeout_f64: f64, num_test_packets: usize, - identity_keypair: IDPair, + identity_keypair: MixIdentityKeyPair, ) -> Self { HealthChecker { resolution_timeout: Duration::from_secs_f64(resolution_timeout_f64), num_test_packets, identity_keypair, - - _phantom_private: PhantomData, - _phantom_public: PhantomData, } } diff --git a/common/healthcheck/src/path_check.rs b/common/healthcheck/src/path_check.rs index b1d2617ad8..074df7da44 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::MixIdentityKeyPair; 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, + identity_keys: &MixIdentityKeyPair, 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 9eda0885f5..677114a457 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::MixIdentityKeyPair; use log::{debug, error, info, warn}; use rand_os::rand_core::RngCore; use sphinx::route::NodeAddressBytes; @@ -102,18 +102,12 @@ impl HealthCheckResult { id } - pub async fn calculate( + pub async fn calculate( topology: &T, iterations: usize, resolution_timeout: Duration, - identity_keys: &IDPair, - ) -> Self - where - T: NymTopology, - IDPair: MixnetIdentityKeyPair, - Priv: MixnetIdentityPrivateKey, - Pub: MixnetIdentityPublicKey, - { + identity_keys: &MixIdentityKeyPair, + ) -> Self { // currently healthchecker supports only up to 255 iterations - if we somehow // find we need more, it's relatively easy change assert!(iterations <= 255); diff --git a/common/pemstore/src/pemstore.rs b/common/pemstore/src/pemstore.rs index 9c7a914d02..0fbc38b71f 100644 --- a/common/pemstore/src/pemstore.rs +++ b/common/pemstore/src/pemstore.rs @@ -1,4 +1,6 @@ use crate::pathfinder::PathFinder; +use crypto::identity::MixIdentityKeyPair; +use crypto::PemStorable; use pem::{encode, parse, Pem}; use std::fs::File; use std::io; @@ -6,7 +8,7 @@ use std::io::prelude::*; use std::path::PathBuf; #[allow(dead_code)] -pub fn read_mix_encryption_keypair_from_disk(_id: String) -> crypto::encryption::x25519::KeyPair { +pub fn read_mix_encryption_keypair_from_disk(_id: String) -> crypto::encryption::KeyPair { unimplemented!() } @@ -25,16 +27,11 @@ 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())?; - let key_pair = IDPair::from_bytes(&private_pem.contents, &public_pem.contents); + let key_pair = MixIdentityKeyPair::from_bytes(&private_pem.contents, &public_pem.contents); if key_pair.private_key().pem_type() != private_pem.tag { return Err(io::Error::new( @@ -62,12 +59,7 @@ 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: MixIdentityKeyPair) -> io::Result<()> { std::fs::create_dir_all(self.config_dir.clone())?; let private_key = key_pair.private_key(); diff --git a/mixnode/src/node/mod.rs b/mixnode/src/node/mod.rs index 0432dec413..502ff77843 100644 --- a/mixnode/src/node/mod.rs +++ b/mixnode/src/node/mod.rs @@ -242,17 +242,20 @@ impl MixNode { } pub fn start(&self, config: node::Config) -> Result<(), Box> { - // Create the runtime, probably later move it to MixNode itself? - let mut rt = Runtime::new()?; - - let (received_tx, received_rx) = mpsc::channel(1024); - let (sent_tx, sent_rx) = mpsc::channel(1024); - + // Set up config and public key for this node let directory_cfg = directory_client::Config { base_url: self.directory_server.clone(), }; let pub_key_str = bs58::encode(&self.public_key.to_bytes().to_vec()).into_string(); + // Set up channels + let (received_tx, received_rx) = mpsc::channel(1024); + let (sent_tx, sent_rx) = mpsc::channel(1024); + + // Create the runtime, probably later move it to MixNode itself? + let mut rt = Runtime::new()?; + + // Spawn Tokio tasks as necessary for node functionality rt.spawn({ let presence_notifier = presence::Notifier::new(&config); presence_notifier.run() diff --git a/nym-client/src/client/mod.rs b/nym-client/src/client/mod.rs index daa7865271..27c08a012c 100644 --- a/nym-client/src/client/mod.rs +++ b/nym-client/src/client/mod.rs @@ -3,7 +3,7 @@ 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::MixIdentityKeyPair; use directory_client::presence::Topology; use futures::channel::mpsc; use futures::join; @@ -11,7 +11,6 @@ use log::*; use serde::{Deserialize, Serialize}; use sfw_provider_requests::AuthToken; use sphinx::route::Destination; -use std::marker::PhantomData; use std::net::SocketAddr; use tokio::runtime::Runtime; use topology::NymTopology; @@ -40,13 +39,8 @@ pub enum SocketType { None, } -pub struct NymClient -where - IDPair: MixnetIdentityKeyPair + Send + Sync, - Priv: MixnetIdentityPrivateKey + Send + Sync, - Pub: MixnetIdentityPublicKey + Send + Sync, -{ - keypair: IDPair, +pub struct NymClient { + keypair: MixIdentityKeyPair, // to be used by "send" function or socket, etc pub input_tx: mpsc::UnboundedSender, @@ -56,22 +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 -where - IDPair: MixnetIdentityKeyPair + Send + Sync, - Priv: MixnetIdentityPrivateKey + Send + Sync, - Pub: MixnetIdentityPublicKey + Send + Sync, -{ +impl NymClient { pub fn new( - keypair: IDPair, + keypair: MixIdentityKeyPair, socket_listening_address: SocketAddr, directory: String, auth_token: Option, @@ -87,8 +73,6 @@ where directory, auth_token, socket_type, - _phantom_private: PhantomData, - _phantom_public: PhantomData, } } @@ -128,15 +112,14 @@ where let self_address = self.keypair.public_key().derive_address(); // generate same type of keys we have as our identity - let healthcheck_keys = IDPair::new(); + let healthcheck_keys = MixIdentityKeyPair::new(); // 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( - self.directory.clone(), - TOPOLOGY_REFRESH_RATE, - healthcheck_keys, - )); + let topology_controller = rt.block_on(topology_control::TopologyControl::::new( + self.directory.clone(), + TOPOLOGY_REFRESH_RATE, + healthcheck_keys, + )); let provider_client_listener_address = rt.block_on(self.get_provider_socket_address(topology_controller.get_inner_ref())); diff --git a/nym-client/src/client/topology_control.rs b/nym-client/src/client/topology_control.rs index 9833f81166..90c84679cc 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::MixIdentityKeyPair; use healthcheck::HealthChecker; use log::{error, info, trace, warn}; use std::sync::Arc; @@ -12,16 +12,10 @@ const NODE_HEALTH_THRESHOLD: f64 = 0.0; // auxiliary type for ease of use pub type TopologyInnerRef = Arc>>; -pub(crate) struct TopologyControl -where - T: NymTopology, - IDPair: MixnetIdentityKeyPair, - Priv: MixnetIdentityPrivateKey, - Pub: MixnetIdentityPublicKey, -{ +pub(crate) struct TopologyControl { directory_server: String, inner: Arc>>, - health_checker: HealthChecker, + health_checker: HealthChecker, refresh_rate: f64, } @@ -31,17 +25,11 @@ enum TopologyError { NoValidPathsError, } -impl TopologyControl -where - T: NymTopology, - IDPair: MixnetIdentityKeyPair, - Priv: MixnetIdentityPrivateKey, - Pub: MixnetIdentityPublicKey, -{ +impl TopologyControl { pub(crate) async fn new( directory_server: String, refresh_rate: f64, - identity_keypair: IDPair, + identity_keypair: MixIdentityKeyPair, ) -> Self { // this is a temporary solution as the healthcheck will eventually be moved to validators let health_checker = healthcheck::HealthChecker::new(5.0, 2, identity_keypair); diff --git a/nym-client/src/commands/init.rs b/nym-client/src/commands/init.rs index bc4403e6b9..1ee2385ded 100644 --- a/nym-client/src/commands/init.rs +++ b/nym-client/src/commands/init.rs @@ -1,6 +1,6 @@ use crate::config::persistance::pathfinder::ClientPathfinder; use clap::ArgMatches; -use crypto::identity::MixnetIdentityKeyPair; +use crypto::identity::MixIdentityKeyPair; use pemstore::pemstore::PemStore; pub fn execute(matches: &ArgMatches) { @@ -10,7 +10,7 @@ pub fn execute(matches: &ArgMatches) { let pathfinder = ClientPathfinder::new(id); println!("Writing keypairs to {:?}...", pathfinder.config_dir); - let mix_keys = crypto::identity::DummyMixIdentityKeyPair::new(); + let mix_keys = MixIdentityKeyPair::new(); let pem_store = PemStore::new(pathfinder); pem_store.write_identity(mix_keys).unwrap(); diff --git a/nym-client/src/commands/tcpsocket.rs b/nym-client/src/commands/tcpsocket.rs index 7a98a91681..5dce285c0b 100644 --- a/nym-client/src/commands/tcpsocket.rs +++ b/nym-client/src/commands/tcpsocket.rs @@ -1,7 +1,7 @@ use crate::client::{NymClient, SocketType}; use crate::config::persistance::pathfinder::ClientPathfinder; use clap::ArgMatches; -use crypto::identity::DummyMixIdentityKeyPair; +use crypto::identity::MixIdentityKeyPair; use pemstore::pemstore::PemStore; use std::net::ToSocketAddrs; @@ -27,7 +27,7 @@ pub fn execute(matches: &ArgMatches) { .expect("Failed to extract the socket address from the iterator"); // TODO: currently we know we are reading the 'DummyMixIdentityKeyPair', but how to properly assert the type? - let keypair: DummyMixIdentityKeyPair = PemStore::new(ClientPathfinder::new(id)) + let keypair: MixIdentityKeyPair = PemStore::new(ClientPathfinder::new(id)) .read_identity() .unwrap(); // TODO: reading auth_token from disk (if exists); diff --git a/nym-client/src/commands/websocket.rs b/nym-client/src/commands/websocket.rs index 3193c1ffde..bcb375761e 100644 --- a/nym-client/src/commands/websocket.rs +++ b/nym-client/src/commands/websocket.rs @@ -1,7 +1,7 @@ use crate::client::{NymClient, SocketType}; use crate::config::persistance::pathfinder::ClientPathfinder; use clap::ArgMatches; -use crypto::identity::DummyMixIdentityKeyPair; +use crypto::identity::MixIdentityKeyPair; use pemstore::pemstore::PemStore; use std::net::ToSocketAddrs; @@ -27,7 +27,7 @@ pub fn execute(matches: &ArgMatches) { .expect("Failed to extract the socket address from the iterator"); // TODO: currently we know we are reading the 'DummyMixIdentityKeyPair', but how to properly assert the type? - let keypair: DummyMixIdentityKeyPair = PemStore::new(ClientPathfinder::new(id)) + let keypair: MixIdentityKeyPair = PemStore::new(ClientPathfinder::new(id)) .read_identity() .unwrap(); diff --git a/sfw-provider/src/main.rs b/sfw-provider/src/main.rs index 6cd945a2c0..408ec221b6 100644 --- a/sfw-provider/src/main.rs +++ b/sfw-provider/src/main.rs @@ -1,6 +1,5 @@ use crate::provider::ServiceProvider; use clap::{App, Arg, ArgMatches, SubCommand}; -use crypto::identity::MixnetIdentityKeyPair; use log::error; use std::net::ToSocketAddrs; use std::path::PathBuf; @@ -121,7 +120,7 @@ fn new_config(matches: &ArgMatches) -> provider::Config { print_binding_warning(client_host); } - let key_pair = crypto::identity::DummyMixIdentityKeyPair::new(); // TODO: persist this so keypairs don't change every restart + let key_pair = crypto::identity::MixIdentityKeyPair::new(); // TODO: persist this so keypairs don't change every restart let store_dir = PathBuf::from( matches .value_of("storeDir") diff --git a/sfw-provider/src/provider/client_handling/mod.rs b/sfw-provider/src/provider/client_handling/mod.rs index e3b9dcf86e..67a2658ebe 100644 --- a/sfw-provider/src/provider/client_handling/mod.rs +++ b/sfw-provider/src/provider/client_handling/mod.rs @@ -1,6 +1,6 @@ use crate::provider::storage::{ClientStorage, StoreError}; use crate::provider::ClientLedger; -use crypto::identity::{DummyMixIdentityPrivateKey, MixnetIdentityPrivateKey}; +use crypto::identity::MixIdentityPrivateKey; use futures::lock::Mutex as FMutex; use hmac::{Hmac, Mac}; use log::*; @@ -54,14 +54,14 @@ impl From for ClientProcessingError { pub(crate) struct ClientProcessingData { store_dir: PathBuf, registered_clients_ledger: Arc>, - secret_key: DummyMixIdentityPrivateKey, + secret_key: MixIdentityPrivateKey, } impl ClientProcessingData { pub(crate) fn new( store_dir: PathBuf, registered_clients_ledger: Arc>, - secret_key: DummyMixIdentityPrivateKey, + secret_key: MixIdentityPrivateKey, ) -> Self { ClientProcessingData { store_dir, @@ -153,7 +153,7 @@ impl ClientRequestProcessor { std::fs::create_dir_all(full_store_dir) } - fn generate_new_auth_token(data: Vec, key: DummyMixIdentityPrivateKey) -> AuthToken { + fn generate_new_auth_token(data: Vec, key: MixIdentityPrivateKey) -> AuthToken { // also note that `new_varkey` doesn't even have an execution branch returning an error let mut auth_token_raw = HmacSha256::new_varkey(&key.to_bytes()) .expect("HMAC should be able take key of any size"); @@ -249,7 +249,7 @@ mod generating_new_auth_token { fn for_the_same_input_generates_the_same_auth_token() { let data1 = vec![1u8; 55]; let data2 = vec![1u8; 55]; - let key = DummyMixIdentityPrivateKey::from_bytes(&[1u8; 32]); + let key = MixIdentityPrivateKey::from_bytes(&[1u8; 32]); let token1 = ClientRequestProcessor::generate_new_auth_token(data1, key); let token2 = ClientRequestProcessor::generate_new_auth_token(data2, key); assert_eq!(token1, token2); @@ -259,14 +259,14 @@ mod generating_new_auth_token { fn for_different_inputs_generates_different_auth_tokens() { let data1 = vec![1u8; 55]; let data2 = vec![2u8; 55]; - let key = DummyMixIdentityPrivateKey::from_bytes(&[1u8; 32]); + let key = MixIdentityPrivateKey::from_bytes(&[1u8; 32]); let token1 = ClientRequestProcessor::generate_new_auth_token(data1, key); let token2 = ClientRequestProcessor::generate_new_auth_token(data2, key); assert_ne!(token1, token2); let data1 = vec![1u8; 50]; let data2 = vec![2u8; 55]; - let key = DummyMixIdentityPrivateKey::from_bytes(&[1u8; 32]); + let key = MixIdentityPrivateKey::from_bytes(&[1u8; 32]); let token1 = ClientRequestProcessor::generate_new_auth_token(data1, key); let token2 = ClientRequestProcessor::generate_new_auth_token(data2, key); assert_ne!(token1, token2); diff --git a/sfw-provider/src/provider/mix_handling/mod.rs b/sfw-provider/src/provider/mix_handling/mod.rs index 338943efd1..60ceaf700e 100644 --- a/sfw-provider/src/provider/mix_handling/mod.rs +++ b/sfw-provider/src/provider/mix_handling/mod.rs @@ -1,5 +1,5 @@ use crate::provider::storage::StoreData; -use crypto::identity::DummyMixIdentityPrivateKey; +use crypto::identity::MixIdentityPrivateKey; use log::{error, warn}; use sphinx::{ProcessedPacket, SphinxPacket}; use std::path::PathBuf; @@ -37,12 +37,12 @@ impl From for MixProcessingError { // ProcessingData defines all data required to correctly unwrap sphinx packets #[derive(Debug, Clone)] pub(crate) struct MixProcessingData { - secret_key: DummyMixIdentityPrivateKey, + secret_key: MixIdentityPrivateKey, pub(crate) store_dir: PathBuf, } impl MixProcessingData { - pub(crate) fn new(secret_key: DummyMixIdentityPrivateKey, store_dir: PathBuf) -> Self { + pub(crate) fn new(secret_key: MixIdentityPrivateKey, store_dir: PathBuf) -> Self { MixProcessingData { secret_key, store_dir, diff --git a/sfw-provider/src/provider/mod.rs b/sfw-provider/src/provider/mod.rs index 4e16e5a2a2..56085917aa 100644 --- a/sfw-provider/src/provider/mod.rs +++ b/sfw-provider/src/provider/mod.rs @@ -1,7 +1,7 @@ use crate::provider::client_handling::{ClientProcessingData, ClientRequestProcessor}; use crate::provider::mix_handling::{MixPacketProcessor, MixProcessingData}; use crate::provider::storage::ClientStorage; -use crypto::identity::{DummyMixIdentityPrivateKey, DummyMixIdentityPublicKey}; +use crypto::identity::{MixIdentityPrivateKey, MixIdentityPublicKey}; use directory_client::presence::providers::MixProviderClient; use futures::io::Error; use futures::lock::Mutex as FMutex; @@ -29,8 +29,8 @@ pub struct Config { pub client_socket_address: SocketAddr, pub directory_server: String, pub mix_socket_address: SocketAddr, - pub public_key: DummyMixIdentityPublicKey, - pub secret_key: DummyMixIdentityPrivateKey, + pub public_key: MixIdentityPublicKey, + pub secret_key: MixIdentityPrivateKey, pub store_dir: PathBuf, } @@ -102,8 +102,8 @@ pub struct ServiceProvider { directory_server: String, mix_network_address: SocketAddr, client_network_address: SocketAddr, - public_key: DummyMixIdentityPublicKey, - secret_key: DummyMixIdentityPrivateKey, + public_key: MixIdentityPublicKey, + secret_key: MixIdentityPrivateKey, store_dir: PathBuf, registered_clients_ledger: ClientLedger, } @@ -236,7 +236,7 @@ impl ServiceProvider { async fn start_mixnet_listening( address: SocketAddr, - secret_key: DummyMixIdentityPrivateKey, + secret_key: MixIdentityPrivateKey, store_dir: PathBuf, ) -> Result<(), ProviderError> { let mut listener = tokio::net::TcpListener::bind(address).await?; @@ -258,7 +258,7 @@ impl ServiceProvider { address: SocketAddr, store_dir: PathBuf, client_ledger: Arc>, - secret_key: DummyMixIdentityPrivateKey, + secret_key: MixIdentityPrivateKey, ) -> Result<(), ProviderError> { let mut listener = tokio::net::TcpListener::bind(address).await?; let processing_data = diff --git a/sfw-provider/src/provider/presence.rs b/sfw-provider/src/provider/presence.rs index adfcebaddc..77945cb096 100644 --- a/sfw-provider/src/provider/presence.rs +++ b/sfw-provider/src/provider/presence.rs @@ -1,5 +1,5 @@ use crate::provider::ClientLedger; -use crypto::identity::DummyMixIdentityPublicKey; +use crypto::identity::MixIdentityPublicKey; use directory_client::presence::providers::MixProviderPresence; use directory_client::requests::presence_providers_post::PresenceMixProviderPoster; use directory_client::DirectoryClient; @@ -22,7 +22,7 @@ impl Notifier { directory_server_address: String, client_listener: SocketAddr, mixnet_listener: SocketAddr, - pub_key: DummyMixIdentityPublicKey, + pub_key: MixIdentityPublicKey, client_ledger: Arc>, ) -> Notifier { let directory_config = directory_client::Config { diff --git a/validator/Cargo.toml b/validator/Cargo.toml index a9ebe198b0..0dfe2ee076 100644 --- a/validator/Cargo.toml +++ b/validator/Cargo.toml @@ -8,6 +8,8 @@ edition = "2018" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +abci = "0.6.4" +byteorder = "1.3.2" clap = "2.33.0" # Read notes https://crates.io/crates/dotenv - tl;dr: don't use in production, set environmental variables properly. dotenv = "0.15.0" diff --git a/validator/README.md b/validator/README.md new file mode 100644 index 0000000000..c8bbad5042 --- /dev/null +++ b/validator/README.md @@ -0,0 +1,21 @@ +Nym Validator +============= + +The Nym Validator has several jobs: + +* use Tendermint (v0.33.0) to maintain a total global ordering of incoming transactions +* track quality of service for mixnet nodes (mixmining) +* generate Coconut credentials and ensure they're not double spent +* maintain a decentralized directory of all Nym nodes that have staked into the system + +Some of these functions may be moved away to their own node types in the future, for example to increase scalability or performance. At the moment, we'd like to keep deployments simple, so they're all in the validator node. + +Running the validator on your local machine +------------------------------------------- + +1. Download and install [Tendermint 0.32.7](https://github.com/tendermint/tendermint/releases/tag/v0.32.7) +2. `tendermint init` sets up Tendermint for use +3. `tendermint node` runs Tendermint. You'll get errors until you run the Nym validator, this is normal :). +4. `cp sample-configs/validator-config.toml.sample sample-configs/validator-config.toml` +5. `cargo run -- run --config ../sample-configs/validator-config.toml` builds the Nym Validator and runs it + diff --git a/validator/src/main.rs b/validator/src/main.rs index 39d0d375f3..20d7ee6f2d 100644 --- a/validator/src/main.rs +++ b/validator/src/main.rs @@ -1,10 +1,12 @@ -use crate::validator::config::Config; +use crate::validator::Config; use crate::validator::Validator; use clap::{App, Arg, ArgMatches, SubCommand}; -use log::{error, trace}; +use log::*; use std::process; use toml; +mod network; +mod services; mod validator; fn main() { diff --git a/validator/src/network/ethereum.rs b/validator/src/network/ethereum.rs new file mode 100644 index 0000000000..9aa85267fe --- /dev/null +++ b/validator/src/network/ethereum.rs @@ -0,0 +1 @@ +// placeholder for Ethereum / ERC20 bridge integration diff --git a/validator/src/network/mod.rs b/validator/src/network/mod.rs new file mode 100644 index 0000000000..6ad3fa6cb5 --- /dev/null +++ b/validator/src/network/mod.rs @@ -0,0 +1,4 @@ +//! The `network` module provides interfaces to external systems via network +//! connectivity. +//! +pub mod tendermint; diff --git a/validator/src/network/tendermint.rs b/validator/src/network/tendermint.rs new file mode 100644 index 0000000000..4a581774e6 --- /dev/null +++ b/validator/src/network/tendermint.rs @@ -0,0 +1,67 @@ +use abci::*; +use byteorder::{BigEndian, ByteOrder}; + +// Convert incoming tx network data to the proper BigEndian size. txs.len() > 8 will return 0 +fn convert_tx(tx: &[u8]) -> u64 { + if tx.len() < 8 { + let pad = 8 - tx.len(); + let mut x = vec![0; pad]; + x.extend_from_slice(tx); + return BigEndian::read_u64(x.as_slice()); + } + BigEndian::read_u64(tx) +} + +pub struct Abci { + count: u64, +} + +impl Abci { + pub fn new() -> Abci { + Abci { count: 0 } + } + + pub async fn run(self) { + abci::run_local(self); + } +} + +impl abci::Application for Abci { + // Validate transactions. Rule: Transactions must be incremental: 1,2,3,4... + fn check_tx(&mut self, req: &RequestCheckTx) -> ResponseCheckTx { + // Get the Tx [u8] and convert to u64 + let c = convert_tx(req.get_tx()); + let mut resp = ResponseCheckTx::new(); + + // Validation logic + if c != self.count + 1 { + resp.set_code(1); + resp.set_log(String::from("Count must be incremental!")); + return resp; + } + + // Update state to keep state correct for next check_tx call + self.count = c; + resp + } + + fn deliver_tx(&mut self, req: &RequestDeliverTx) -> ResponseDeliverTx { + // Get the Tx [u8] + let c = convert_tx(req.get_tx()); + // Update state + self.count = c; + // Return default code 0 == bueno + ResponseDeliverTx::new() + } + + fn commit(&mut self, _req: &RequestCommit) -> ResponseCommit { + // Create the response + let mut resp = ResponseCommit::new(); + // Convert count to bits + let mut buf = [0; 8]; + BigEndian::write_u64(&mut buf, self.count); + // Set data so last state is included in the block + resp.set_data(buf.to_vec()); + resp + } +} 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..1200c6fe4f --- /dev/null +++ b/validator/src/services/mixmining/health_check_runner.rs @@ -0,0 +1,47 @@ +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) { + 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 new file mode 100644 index 0000000000..f793440bcc --- /dev/null +++ b/validator/src/validator.rs @@ -0,0 +1,51 @@ +use crate::network::tendermint; +use crate::services::mixmining::health_check_runner; +use crypto::identity::MixIdentityKeyPair; +use healthcheck::HealthChecker; +use tokio::runtime::Runtime; + +use serde_derive::Deserialize; + +#[derive(Deserialize, Debug)] +pub struct Config { + #[serde(rename(deserialize = "healthcheck"))] + pub health_check: healthcheck::config::HealthCheck, +} + +// allow for a generic validator +pub struct Validator { + #[allow(dead_code)] + identity_keypair: MixIdentityKeyPair, + 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 { + pub fn new(config: Config) -> Self { + let dummy_keypair = MixIdentityKeyPair::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 { + identity_keypair: dummy_keypair, + health_check_runner, + tendermint_abci: tendermint::Abci::new(), + } + } + + pub fn start(self) { + let mut rt = Runtime::new().unwrap(); + rt.spawn(self.health_check_runner.run()); + rt.block_on(self.tendermint_abci.run()); + } +} diff --git a/validator/src/validator/config/mod.rs b/validator/src/validator/config/mod.rs deleted file mode 100644 index a6ec068a4f..0000000000 --- a/validator/src/validator/config/mod.rs +++ /dev/null @@ -1,7 +0,0 @@ -use serde::Deserialize; - -#[derive(Deserialize, Debug)] -pub struct Config { - #[serde(rename(deserialize = "healthcheck"))] - pub health_check: healthcheck::config::HealthCheck, -} diff --git a/validator/src/validator/mod.rs b/validator/src/validator/mod.rs deleted file mode 100644 index 26f031fab5..0000000000 --- a/validator/src/validator/mod.rs +++ /dev/null @@ -1,75 +0,0 @@ -use crate::validator::config::Config; -use crypto::identity::{ - DummyMixIdentityKeyPair, DummyMixIdentityPrivateKey, DummyMixIdentityPublicKey, - MixnetIdentityKeyPair, MixnetIdentityPrivateKey, MixnetIdentityPublicKey, -}; -use directory_client::presence::Topology; -use healthcheck::HealthChecker; -use log::{debug, error, info}; -use std::time::Duration; -use tokio::runtime::Runtime; -use topology::NymTopology; - -pub mod config; - -// allow for a generic validator -pub struct Validator -where - IDPair: MixnetIdentityKeyPair, - Priv: MixnetIdentityPrivateKey, - Pub: MixnetIdentityPublicKey, -{ - config: Config, - #[allow(dead_code)] - identity_keypair: IDPair, - heath_check: HealthChecker, -} - -// but for time being, since it's a dummy one, have it use dummy keys -impl Validator { - pub fn new(config: Config) -> Self { - debug!("validator new"); - - let dummy_keypair = DummyMixIdentityKeyPair::new(); - - Validator { - identity_keypair: dummy_keypair.clone(), - heath_check: HealthChecker::new( - config.health_check.resolution_timeout, - config.health_check.num_test_packets, - dummy_keypair, - ), - config, - } - } - - async fn healthcheck_runner(&self) { - let healthcheck_interval = Duration::from_secs_f64(self.config.health_check.interval); - debug!("healthcheck will run every {:?}", healthcheck_interval); - - loop { - let full_topology = T::new(self.config.health_check.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.heath_check.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; - } - } - - pub fn start(self) { - debug!("validator run"); - - let mut rt = Runtime::new().unwrap(); - - let health_check_future = self.healthcheck_runner::(); - rt.block_on(health_check_future); - } -}