Feature/nymd client integration (#736)
* Calculating gas fees * Ability to set custom fees * Added extra test * Removed commented code * Moved all msg types to common contract crate * Temporarily disabling get_tx method * Finishing up nymd client API * Comment fix * Remaining fee values * Some cleanup * Removed needless borrow * Fixed imports in contract tests * Moved error types around * New ValidatorClient * Experiment with new type of defaults * Removed dead module * Dealt with unwrap * Migrated mixnode to use new validator client * Migrated gateway to use new validator client * Mixnode and gateway adjustments * More exported defaults * Clients using new validator client * Fixed mixnode upgrade * Moved default values to a new crate * Changed behaviour of validator client features * Migrated basic functions of validator api * Updated config + fixed startup * Fixed wasm client build * Integration with the explorer api * Removed tokio dev dependency * Needless borrow * Fixex wasm client build * Fixed tauri client build * Needless borrows * Fixed client upgrade print * Removed redundant comments * Made note on aggregated verification key into a doc comment * Removed mixnet contract references from verloc * Modified default validators structure * Reformatted validator-api Cargo.toml file * Removed commented code * Made the doc comment example a no-run * Fixed a upgrade print... again * Adjusted the doc example * Removed unused import
This commit is contained in:
committed by
GitHub
parent
eec211e038
commit
a274edffba
Vendored
+20
-17
@@ -1,7 +1,9 @@
|
||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::nymd_client::Client;
|
||||
use anyhow::Result;
|
||||
use config::defaults::VALIDATOR_API_VERSION;
|
||||
use mixnet_contract::{GatewayBond, MixNodeBond};
|
||||
use rocket::fairing::AdHoc;
|
||||
use serde::Serialize;
|
||||
@@ -10,13 +12,12 @@ use std::sync::Arc;
|
||||
use std::time::{Duration, SystemTime, UNIX_EPOCH};
|
||||
use tokio::sync::RwLock;
|
||||
use tokio::time;
|
||||
use validator_client::validator_api::VALIDATOR_API_CACHE_VERSION;
|
||||
use validator_client::Client;
|
||||
use validator_client::nymd::CosmWasmClient;
|
||||
|
||||
pub(crate) mod routes;
|
||||
|
||||
pub struct ValidatorCacheRefresher {
|
||||
validator_client: Client,
|
||||
pub struct ValidatorCacheRefresher<C> {
|
||||
nymd_client: Client<C>,
|
||||
cache: ValidatorCache,
|
||||
caching_interval: Duration,
|
||||
}
|
||||
@@ -35,7 +36,6 @@ struct ValidatorCacheInner {
|
||||
#[derive(Default, Serialize, Clone)]
|
||||
pub struct Cache<T> {
|
||||
value: T,
|
||||
#[allow(dead_code)]
|
||||
as_at: u64,
|
||||
}
|
||||
|
||||
@@ -53,27 +53,26 @@ impl<T: Clone> Cache<T> {
|
||||
}
|
||||
}
|
||||
|
||||
impl ValidatorCacheRefresher {
|
||||
impl<C> ValidatorCacheRefresher<C> {
|
||||
pub(crate) fn new(
|
||||
validators_rest_uris: Vec<String>,
|
||||
mixnet_contract: String,
|
||||
nymd_client: Client<C>,
|
||||
caching_interval: Duration,
|
||||
cache: ValidatorCache,
|
||||
) -> Self {
|
||||
let config = validator_client::Config::new(validators_rest_uris, mixnet_contract);
|
||||
let validator_client = validator_client::Client::new(config);
|
||||
|
||||
ValidatorCacheRefresher {
|
||||
validator_client,
|
||||
nymd_client,
|
||||
cache,
|
||||
caching_interval,
|
||||
}
|
||||
}
|
||||
|
||||
async fn refresh_cache(&self) -> Result<()> {
|
||||
async fn refresh_cache(&self) -> Result<()>
|
||||
where
|
||||
C: CosmWasmClient + Sync,
|
||||
{
|
||||
let (mixnodes, gateways) = tokio::try_join!(
|
||||
self.validator_client.get_mix_nodes(),
|
||||
self.validator_client.get_gateways()
|
||||
self.nymd_client.get_mixnodes(),
|
||||
self.nymd_client.get_gateways()
|
||||
)?;
|
||||
|
||||
info!(
|
||||
@@ -87,7 +86,10 @@ impl ValidatorCacheRefresher {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) async fn run(&self) {
|
||||
pub(crate) async fn run(&self)
|
||||
where
|
||||
C: CosmWasmClient + Sync,
|
||||
{
|
||||
let mut interval = time::interval(self.caching_interval);
|
||||
loop {
|
||||
interval.tick().await;
|
||||
@@ -113,7 +115,8 @@ impl ValidatorCache {
|
||||
pub fn stage() -> AdHoc {
|
||||
AdHoc::on_ignite("Validator Cache Stage", |rocket| async {
|
||||
rocket.manage(Self::new()).mount(
|
||||
VALIDATOR_API_CACHE_VERSION,
|
||||
// this format! is so ugly...
|
||||
format!("/{}", VALIDATOR_API_VERSION),
|
||||
routes![routes::get_mixnodes, routes::get_gateways],
|
||||
)
|
||||
})
|
||||
|
||||
@@ -1,12 +1,15 @@
|
||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use coconut_interface::{
|
||||
elgamal::PublicKey, Attribute, BlindSignRequest, BlindSignRequestBody, BlindedSignature,
|
||||
BlindedSignatureResponse, KeyPair, Parameters, VerificationKeyResponse,
|
||||
};
|
||||
use config::defaults::VALIDATOR_API_VERSION;
|
||||
use getset::{CopyGetters, Getters};
|
||||
use rocket::fairing::AdHoc;
|
||||
use rocket::serde::json::Json;
|
||||
use rocket::State;
|
||||
use validator_client::validator_api::VALIDATOR_API_CACHE_VERSION;
|
||||
|
||||
#[derive(Getters, CopyGetters, Debug)]
|
||||
pub(crate) struct InternalSignRequest {
|
||||
@@ -39,7 +42,8 @@ impl InternalSignRequest {
|
||||
pub fn stage(key_pair: KeyPair) -> AdHoc {
|
||||
AdHoc::on_ignite("Internal Sign Request Stage", |rocket| async {
|
||||
rocket.manage(key_pair).mount(
|
||||
VALIDATOR_API_CACHE_VERSION,
|
||||
// this format! is so ugly...
|
||||
format!("/{}", VALIDATOR_API_VERSION),
|
||||
routes![post_blind_sign, get_verification_key],
|
||||
)
|
||||
})
|
||||
|
||||
@@ -3,22 +3,16 @@
|
||||
|
||||
use crate::config::template::config_template;
|
||||
use coconut_interface::{Base58, KeyPair};
|
||||
use config::defaults::DEFAULT_MIXNET_CONTRACT_ADDRESS;
|
||||
use config::defaults::{default_api_endpoints, DEFAULT_MIXNET_CONTRACT_ADDRESS};
|
||||
use config::NymConfig;
|
||||
use const_format::formatcp;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::time::Duration;
|
||||
use url::Url;
|
||||
|
||||
mod template;
|
||||
|
||||
pub const DEFAULT_VALIDATOR_HOST: &str = "localhost";
|
||||
const DEFAULT_VALIDATOR_PORT: &str = "1317";
|
||||
const DEFAULT_VALIDATOR_REST_ENDPOINTS: &[&str] = &[formatcp!(
|
||||
"http://{}:{}",
|
||||
DEFAULT_VALIDATOR_HOST,
|
||||
DEFAULT_VALIDATOR_PORT,
|
||||
)];
|
||||
const DEFAULT_LOCAL_VALIDATOR: &str = "http://localhost:26657";
|
||||
|
||||
const DEFAULT_GATEWAY_SENDING_RATE: usize = 500;
|
||||
const DEFAULT_MAX_CONCURRENT_GATEWAY_CLIENTS: usize = 50;
|
||||
@@ -74,12 +68,14 @@ impl NymConfig for Config {
|
||||
#[derive(Debug, Deserialize, PartialEq, Serialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct Base {
|
||||
// TODO: this will probably be changed very soon to point only to a single endpoint,
|
||||
// that will be a local address
|
||||
validator_rest_urls: Vec<String>,
|
||||
local_validator: Url,
|
||||
|
||||
/// Address of the validator contract managing the network
|
||||
mixnet_contract_address: String,
|
||||
|
||||
/// Mnemonic (currently of the network monitor) used for rewarding
|
||||
mnemonic: String,
|
||||
|
||||
// Avoid breaking derives for now
|
||||
keypair_bs58: String,
|
||||
}
|
||||
@@ -87,11 +83,11 @@ pub struct Base {
|
||||
impl Default for Base {
|
||||
fn default() -> Self {
|
||||
Base {
|
||||
validator_rest_urls: DEFAULT_VALIDATOR_REST_ENDPOINTS
|
||||
.iter()
|
||||
.map(|&endpoint| endpoint.to_string())
|
||||
.collect(),
|
||||
local_validator: DEFAULT_LOCAL_VALIDATOR
|
||||
.parse()
|
||||
.expect("default local validator is malformed!"),
|
||||
mixnet_contract_address: DEFAULT_MIXNET_CONTRACT_ADDRESS.to_string(),
|
||||
mnemonic: String::default(),
|
||||
keypair_bs58: String::default(),
|
||||
}
|
||||
}
|
||||
@@ -103,6 +99,11 @@ pub struct NetworkMonitor {
|
||||
/// Specifies whether network monitoring service is enabled in this process.
|
||||
enabled: bool,
|
||||
|
||||
/// Specifies list of all validators on the network issuing coconut credentials.
|
||||
/// A special care must be taken to ensure they are in correct order.
|
||||
/// The list must also contain THIS validator that is running the test
|
||||
all_validator_apis: Vec<Url>,
|
||||
|
||||
/// Specifies whether a detailed report should be printed after each run
|
||||
print_detailed_report: bool,
|
||||
|
||||
@@ -158,6 +159,7 @@ impl Default for NetworkMonitor {
|
||||
fn default() -> Self {
|
||||
NetworkMonitor {
|
||||
enabled: false,
|
||||
all_validator_apis: default_api_endpoints(),
|
||||
print_detailed_report: false,
|
||||
good_v4_topology_file: Self::default_good_v4_topology_file(),
|
||||
good_v6_topology_file: Self::default_good_v6_topology_file(),
|
||||
@@ -237,8 +239,8 @@ impl Config {
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_custom_validators(mut self, validators: Vec<String>) -> Self {
|
||||
self.base.validator_rest_urls = validators;
|
||||
pub fn with_custom_nymd_validator(mut self, validator: Url) -> Self {
|
||||
self.base.local_validator = validator;
|
||||
self
|
||||
}
|
||||
|
||||
@@ -247,8 +249,18 @@ impl Config {
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_keypair(mut self, keypair_bs58: String) -> Self {
|
||||
self.base.keypair_bs58 = keypair_bs58;
|
||||
pub fn with_mnemonic<S: Into<String>>(mut self, mnemonic: S) -> Self {
|
||||
self.base.mnemonic = mnemonic.into();
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_keypair<S: Into<String>>(mut self, keypair_bs58: S) -> Self {
|
||||
self.base.keypair_bs58 = keypair_bs58.into();
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_custom_validator_apis(mut self, validator_api_urls: Vec<Url>) -> Self {
|
||||
self.network_monitor.all_validator_apis = validator_api_urls;
|
||||
self
|
||||
}
|
||||
|
||||
@@ -268,14 +280,18 @@ impl Config {
|
||||
self.network_monitor.good_v6_topology_file.clone()
|
||||
}
|
||||
|
||||
pub fn get_validators_urls(&self) -> Vec<String> {
|
||||
self.base.validator_rest_urls.clone()
|
||||
pub fn get_nymd_validator_url(&self) -> Url {
|
||||
self.base.local_validator.clone()
|
||||
}
|
||||
|
||||
pub fn get_mixnet_contract_address(&self) -> String {
|
||||
self.base.mixnet_contract_address.clone()
|
||||
}
|
||||
|
||||
pub fn get_mnemonic(&self) -> String {
|
||||
self.base.mnemonic.clone()
|
||||
}
|
||||
|
||||
pub fn get_network_monitor_run_interval(&self) -> Duration {
|
||||
self.network_monitor.run_interval
|
||||
}
|
||||
@@ -311,4 +327,8 @@ impl Config {
|
||||
pub fn get_node_status_api_database_path(&self) -> PathBuf {
|
||||
self.node_status_api.database_path.clone()
|
||||
}
|
||||
|
||||
pub fn get_all_validator_api_endpoints(&self) -> Vec<Url> {
|
||||
self.network_monitor.all_validator_apis.clone()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,15 +11,14 @@ pub(crate) fn config_template() -> &'static str {
|
||||
[base]
|
||||
|
||||
# Validator server to which the API will be getting information about the network.
|
||||
validator_rest_urls = [
|
||||
{{#each base.validator_rest_urls }}
|
||||
'{{this}}',
|
||||
{{/each}}
|
||||
]
|
||||
local_validator = '{{ base.local_validator }}'
|
||||
|
||||
# Address of the validator contract managing the network.
|
||||
mixnet_contract_address = '{{ base.mixnet_contract_address }}'
|
||||
|
||||
# Mnemonic (currently of the network monitor) used for rewarding
|
||||
mnemonic = '{{ base.mnemonic }}'
|
||||
|
||||
##### network monitor config options #####
|
||||
|
||||
[network_monitor]
|
||||
@@ -27,6 +26,15 @@ mixnet_contract_address = '{{ base.mixnet_contract_address }}'
|
||||
# Specifies whether network monitoring service is enabled in this process.
|
||||
enabled = {{ network_monitor.enabled }}
|
||||
|
||||
# Specifies list of all validators on the network issuing coconut credentials.
|
||||
# A special care must be taken to ensure they are in correct order.
|
||||
# The list must also contain THIS validator that is running the test
|
||||
all_validator_apis = [
|
||||
{{#each network_monitor.all_validator_apis }}
|
||||
'{{this}}',
|
||||
{{/each}}
|
||||
]
|
||||
|
||||
# Specifies whether a detailed report should be printed after each run
|
||||
print_detailed_report = {{ network_monitor.print_detailed_report }}
|
||||
|
||||
|
||||
+134
-68
@@ -6,38 +6,54 @@ extern crate rocket;
|
||||
|
||||
use crate::cache::ValidatorCacheRefresher;
|
||||
use crate::config::Config;
|
||||
use crate::network_monitor::new_monitor_runnables;
|
||||
use crate::network_monitor::tested_network::good_topology::parse_topology_file;
|
||||
use crate::network_monitor::{new_monitor_runnables, NetworkMonitorRunnables};
|
||||
use crate::nymd_client::Client;
|
||||
use crate::storage::NodeStatusStorage;
|
||||
use ::config::NymConfig;
|
||||
use ::config::{defaults::DEFAULT_VALIDATOR_API_PORT, NymConfig};
|
||||
use anyhow::Result;
|
||||
use cache::ValidatorCache;
|
||||
use clap::{App, Arg, ArgMatches};
|
||||
use coconut::InternalSignRequest;
|
||||
use log::info;
|
||||
use rocket::http::Method;
|
||||
use rocket::{Ignite, Rocket};
|
||||
use rocket_cors::{AllowedHeaders, AllowedOrigins, Cors};
|
||||
use std::process;
|
||||
use validator_client::validator_api::VALIDATOR_API_PORT;
|
||||
use url::Url;
|
||||
|
||||
pub(crate) mod cache;
|
||||
mod coconut;
|
||||
pub(crate) mod config;
|
||||
mod network_monitor;
|
||||
mod node_status_api;
|
||||
pub(crate) mod nymd_client;
|
||||
pub(crate) mod storage;
|
||||
|
||||
const MONITORING_ENABLED: &str = "enable-monitor";
|
||||
const V4_TOPOLOGY_ARG: &str = "v4-topology-filepath";
|
||||
const V6_TOPOLOGY_ARG: &str = "v6-topology-filepath";
|
||||
const VALIDATORS_ARG: &str = "validators";
|
||||
const API_VALIDATORS_ARG: &str = "api-validators";
|
||||
const DETAILED_REPORT_ARG: &str = "detailed-report";
|
||||
const MIXNET_CONTRACT_ARG: &str = "mixnet-contract";
|
||||
const MNEMONIC_ARG: &str = "mnemonic";
|
||||
const WRITE_CONFIG_ARG: &str = "save-config";
|
||||
const KEYPAIR_ARG: &str = "keypair";
|
||||
const NYMD_VALIDATOR_ARG: &str = "nymd-validator";
|
||||
|
||||
pub(crate) const PENALISE_OUTDATED: bool = false;
|
||||
|
||||
fn parse_validators(raw: &str) -> Vec<Url> {
|
||||
raw.split(',')
|
||||
.map(|raw_validator| {
|
||||
raw_validator
|
||||
.trim()
|
||||
.parse()
|
||||
.expect("one of the provided validator api urls is invalid")
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn parse_args<'a>() -> ArgMatches<'a> {
|
||||
App::new("Nym Network Monitor")
|
||||
.author("Nymtech")
|
||||
@@ -58,16 +74,21 @@ fn parse_args<'a>() -> ArgMatches<'a> {
|
||||
.takes_value(true)
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name(VALIDATORS_ARG)
|
||||
.help("REST endpoint of the validator the monitor will grab nodes to test")
|
||||
.long(VALIDATORS_ARG)
|
||||
Arg::with_name(NYMD_VALIDATOR_ARG)
|
||||
.help("Endpoint to nymd part of the validator from which the monitor will grab nodes to test")
|
||||
.long(NYMD_VALIDATOR_ARG)
|
||||
.takes_value(true)
|
||||
)
|
||||
.arg(Arg::with_name("mixnet-contract")
|
||||
.arg(Arg::with_name(MIXNET_CONTRACT_ARG)
|
||||
.long(MIXNET_CONTRACT_ARG)
|
||||
.help("Address of the validator contract managing the network")
|
||||
.takes_value(true),
|
||||
)
|
||||
.arg(Arg::with_name(MNEMONIC_ARG)
|
||||
.long(MNEMONIC_ARG)
|
||||
.help("Mnemonic of the network monitor used for rewarding operators")
|
||||
.takes_value(true),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name(DETAILED_REPORT_ARG)
|
||||
.help("specifies whether a detailed report should be printed after each run")
|
||||
@@ -117,12 +138,6 @@ fn setup_logging() {
|
||||
}
|
||||
|
||||
fn override_config(mut config: Config, matches: &ArgMatches) -> Config {
|
||||
fn parse_validators(raw: &str) -> Vec<String> {
|
||||
raw.split(',')
|
||||
.map(|raw_validator| raw_validator.trim().into())
|
||||
.collect()
|
||||
}
|
||||
|
||||
if matches.is_present(MONITORING_ENABLED) {
|
||||
config = config.enabled_network_monitor(true)
|
||||
}
|
||||
@@ -135,14 +150,29 @@ fn override_config(mut config: Config, matches: &ArgMatches) -> Config {
|
||||
config = config.with_v6_good_topology(v6_topology_path)
|
||||
}
|
||||
|
||||
if let Some(raw_validators) = matches.value_of(VALIDATORS_ARG) {
|
||||
config = config.with_custom_validators(parse_validators(raw_validators));
|
||||
if let Some(raw_validators) = matches.value_of(API_VALIDATORS_ARG) {
|
||||
config = config.with_custom_validator_apis(parse_validators(raw_validators));
|
||||
}
|
||||
|
||||
if let Some(raw_validator) = matches.value_of(NYMD_VALIDATOR_ARG) {
|
||||
let parsed = match raw_validator.parse() {
|
||||
Err(err) => {
|
||||
error!("Passed validator argument is invalid - {}", err);
|
||||
process::exit(1)
|
||||
}
|
||||
Ok(url) => url,
|
||||
};
|
||||
config = config.with_custom_nymd_validator(parsed);
|
||||
}
|
||||
|
||||
if let Some(mixnet_contract) = matches.value_of(MIXNET_CONTRACT_ARG) {
|
||||
config = config.with_custom_mixnet_contract(mixnet_contract)
|
||||
}
|
||||
|
||||
if let Some(mnemonic) = matches.value_of(MNEMONIC_ARG) {
|
||||
config = config.with_mnemonic(mnemonic)
|
||||
}
|
||||
|
||||
if matches.is_present(DETAILED_REPORT_ARG) {
|
||||
config = config.detailed_network_monitor_report(true)
|
||||
}
|
||||
@@ -184,6 +214,59 @@ fn setup_cors() -> Result<Cors> {
|
||||
Ok(cors)
|
||||
}
|
||||
|
||||
async fn setup_network_monitor(
|
||||
config: &Config,
|
||||
rocket: &Rocket<Ignite>,
|
||||
) -> Option<NetworkMonitorRunnables> {
|
||||
if !config.get_network_monitor_enabled() {
|
||||
return None;
|
||||
}
|
||||
|
||||
// get instances of managed states
|
||||
let node_status_storage = rocket.state::<NodeStatusStorage>().unwrap().clone();
|
||||
let validator_cache = rocket.state::<ValidatorCache>().unwrap().clone();
|
||||
|
||||
let v4_topology = parse_topology_file(config.get_v4_good_topology_file());
|
||||
let v6_topology = parse_topology_file(config.get_v6_good_topology_file());
|
||||
network_monitor::check_if_up_to_date(&v4_topology, &v6_topology);
|
||||
|
||||
Some(
|
||||
new_monitor_runnables(
|
||||
config,
|
||||
v4_topology,
|
||||
v6_topology,
|
||||
node_status_storage,
|
||||
validator_cache,
|
||||
)
|
||||
.await,
|
||||
)
|
||||
}
|
||||
|
||||
async fn setup_rocket(config: &Config) -> Result<Rocket<Ignite>> {
|
||||
// let's build our rocket!
|
||||
let rocket_config = rocket::config::Config {
|
||||
// TODO: probably the port should be configurable?
|
||||
port: DEFAULT_VALIDATOR_API_PORT,
|
||||
..Default::default()
|
||||
};
|
||||
let rocket = rocket::custom(rocket_config)
|
||||
.attach(setup_cors()?)
|
||||
.attach(ValidatorCache::stage())
|
||||
.attach(InternalSignRequest::stage(config.keypair()));
|
||||
|
||||
// see if we should start up network monitor and if so, attach the node status api
|
||||
if config.get_network_monitor_enabled() {
|
||||
Ok(rocket
|
||||
.attach(node_status_api::stage(
|
||||
config.get_node_status_api_database_path(),
|
||||
))
|
||||
.ignite()
|
||||
.await?)
|
||||
} else {
|
||||
Ok(rocket.ignite().await?)
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> Result<()> {
|
||||
setup_logging();
|
||||
@@ -209,67 +292,50 @@ async fn main() -> Result<()> {
|
||||
let config = override_config(config, &matches);
|
||||
|
||||
// let's build our rocket!
|
||||
let rocket_config = rocket::config::Config {
|
||||
port: VALIDATOR_API_PORT,
|
||||
..Default::default()
|
||||
};
|
||||
let rocket = rocket::custom(rocket_config)
|
||||
.attach(setup_cors()?)
|
||||
.attach(ValidatorCache::stage())
|
||||
.attach(InternalSignRequest::stage(config.keypair()));
|
||||
|
||||
// see if we should start up network monitor and ignite our rocket
|
||||
let rocket = if config.get_network_monitor_enabled() {
|
||||
// don't start our node-status api if we're not running the monitor - we can't get
|
||||
// report data otherwise
|
||||
let rocket = rocket
|
||||
.attach(node_status_api::stage(
|
||||
config.get_node_status_api_database_path(),
|
||||
))
|
||||
.ignite()
|
||||
.await?;
|
||||
|
||||
info!("Network monitor starting...");
|
||||
|
||||
// get instances of managed states
|
||||
let node_status_storage = rocket.state::<NodeStatusStorage>().unwrap().clone();
|
||||
let validator_cache = rocket.state::<ValidatorCache>().unwrap().clone();
|
||||
|
||||
let v4_topology = parse_topology_file(config.get_v4_good_topology_file());
|
||||
let v6_topology = parse_topology_file(config.get_v6_good_topology_file());
|
||||
network_monitor::check_if_up_to_date(&v4_topology, &v6_topology);
|
||||
|
||||
let network_monitor_runnables = new_monitor_runnables(
|
||||
&config,
|
||||
v4_topology,
|
||||
v6_topology,
|
||||
node_status_storage,
|
||||
validator_cache,
|
||||
);
|
||||
network_monitor_runnables.spawn_tasks();
|
||||
|
||||
rocket
|
||||
} else {
|
||||
info!("Network monitoring is disabled.");
|
||||
rocket.ignite().await?
|
||||
};
|
||||
let rocket = setup_rocket(&config).await?;
|
||||
let monitor_runnables = setup_network_monitor(&config, &rocket).await;
|
||||
|
||||
let validator_cache = rocket.state::<ValidatorCache>().unwrap().clone();
|
||||
|
||||
let validator_cache_refresher = ValidatorCacheRefresher::new(
|
||||
config.get_validators_urls(),
|
||||
config.get_mixnet_contract_address(),
|
||||
config.get_caching_interval(),
|
||||
validator_cache,
|
||||
);
|
||||
// if network monitor is disabled, we're not going to be sending any rewarding hence
|
||||
// we're not starting signing client
|
||||
if config.get_network_monitor_enabled() {
|
||||
let nymd_client = Client::new_signing(&config);
|
||||
let validator_cache_refresher = ValidatorCacheRefresher::new(
|
||||
nymd_client,
|
||||
config.get_caching_interval(),
|
||||
validator_cache,
|
||||
);
|
||||
|
||||
// spawn our cacher
|
||||
tokio::spawn(async move { validator_cache_refresher.run().await });
|
||||
// spawn our cacher
|
||||
tokio::spawn(async move { validator_cache_refresher.run().await });
|
||||
} else {
|
||||
let nymd_client = Client::new_query(&config);
|
||||
let validator_cache_refresher = ValidatorCacheRefresher::new(
|
||||
nymd_client,
|
||||
config.get_caching_interval(),
|
||||
validator_cache,
|
||||
);
|
||||
|
||||
// spawn our cacher
|
||||
tokio::spawn(async move { validator_cache_refresher.run().await });
|
||||
}
|
||||
|
||||
if let Some(runnables) = monitor_runnables {
|
||||
info!("Starting network monitor...");
|
||||
// spawn network monitor!
|
||||
runnables.spawn_tasks();
|
||||
} else {
|
||||
info!("Network monitoring is disabled.");
|
||||
}
|
||||
|
||||
// and launch the rocket
|
||||
let shutdown_handle = rocket.shutdown();
|
||||
|
||||
tokio::spawn(rocket.launch());
|
||||
|
||||
wait_for_interrupt().await;
|
||||
shutdown_handle.notify();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -15,8 +15,12 @@ use crate::network_monitor::monitor::summary_producer::SummaryProducer;
|
||||
use crate::network_monitor::monitor::Monitor;
|
||||
use crate::network_monitor::tested_network::TestedNetwork;
|
||||
use crate::storage::NodeStatusStorage;
|
||||
use coconut_interface::Credential;
|
||||
use credentials::bandwidth::prepare_for_spending;
|
||||
use credentials::obtain_aggregate_verification_key;
|
||||
use crypto::asymmetric::{encryption, identity};
|
||||
use futures::channel::mpsc;
|
||||
use log::info;
|
||||
use nymsphinx::addressing::clients::Recipient;
|
||||
use std::sync::Arc;
|
||||
use topology::NymTopology;
|
||||
@@ -44,7 +48,7 @@ impl NetworkMonitorRunnables {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn new_monitor_runnables(
|
||||
pub(crate) async fn new_monitor_runnables(
|
||||
config: &Config,
|
||||
v4_topology: NymTopology,
|
||||
v6_topology: NymTopology,
|
||||
@@ -86,10 +90,14 @@ pub(crate) fn new_monitor_runnables(
|
||||
*encryption_keypair.public_key(),
|
||||
);
|
||||
|
||||
let bandwidth_credential =
|
||||
TEMPORARY_obtain_bandwidth_credential(config, identity_keypair.public_key()).await;
|
||||
|
||||
let packet_sender = new_packet_sender(
|
||||
config,
|
||||
gateway_status_update_sender,
|
||||
Arc::clone(&identity_keypair),
|
||||
bandwidth_credential,
|
||||
config.get_gateway_sending_rate(),
|
||||
);
|
||||
|
||||
@@ -135,15 +143,44 @@ fn new_packet_preparer(
|
||||
)
|
||||
}
|
||||
|
||||
// SECURITY:
|
||||
// this implies we are re-using the same credential for all gateways all the time (which unfortunately is true!)
|
||||
#[allow(non_snake_case)]
|
||||
async fn TEMPORARY_obtain_bandwidth_credential(
|
||||
config: &Config,
|
||||
identity: &identity::PublicKey,
|
||||
) -> Credential {
|
||||
info!("Trying to obtain bandwidth credential...");
|
||||
let validators = config.get_all_validator_api_endpoints();
|
||||
|
||||
let verification_key = obtain_aggregate_verification_key(&validators)
|
||||
.await
|
||||
.expect("could not obtain aggregate verification key of ALL validators");
|
||||
|
||||
let bandwidth_credential =
|
||||
credentials::bandwidth::obtain_signature(&identity.to_bytes(), &validators)
|
||||
.await
|
||||
.expect("failed to obtain bandwidth credential!");
|
||||
|
||||
prepare_for_spending(
|
||||
&identity.to_bytes(),
|
||||
&bandwidth_credential,
|
||||
&verification_key,
|
||||
)
|
||||
.expect("failed to prepare bandwidth credential for spending!")
|
||||
}
|
||||
|
||||
fn new_packet_sender(
|
||||
config: &Config,
|
||||
gateways_status_updater: GatewayClientUpdateSender,
|
||||
local_identity: Arc<identity::KeyPair>,
|
||||
bandwidth_credential: Credential,
|
||||
max_sending_rate: usize,
|
||||
) -> PacketSender {
|
||||
PacketSender::new(
|
||||
gateways_status_updater,
|
||||
local_identity,
|
||||
bandwidth_credential,
|
||||
config.get_gateway_response_timeout(),
|
||||
config.get_gateway_connection_timeout(),
|
||||
config.get_max_concurrent_gateway_clients(),
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::config::DEFAULT_VALIDATOR_HOST;
|
||||
use crate::network_monitor::monitor::receiver::{GatewayClientUpdate, GatewayClientUpdateSender};
|
||||
use coconut_interface::Credential;
|
||||
use crypto::asymmetric::identity::{self, PUBLIC_KEY_LENGTH};
|
||||
@@ -22,7 +21,6 @@ use std::sync::Arc;
|
||||
use std::task::Poll;
|
||||
use std::time::Duration;
|
||||
use tokio::time::Instant;
|
||||
use validator_client::validator_api::VALIDATOR_API_PORT;
|
||||
|
||||
const TIME_CHUNK_SIZE: Duration = Duration::from_millis(50);
|
||||
|
||||
@@ -65,6 +63,15 @@ struct FreshGatewayClientData {
|
||||
gateways_status_updater: GatewayClientUpdateSender,
|
||||
local_identity: Arc<identity::KeyPair>,
|
||||
gateway_response_timeout: Duration,
|
||||
|
||||
// I guess in the future this struct will require aggregated verification key and....
|
||||
// ... something for obtaining actual credential
|
||||
|
||||
// TODO:
|
||||
// SECURITY:
|
||||
// since currently we have no double spending protection, just to get things running
|
||||
// we're re-using the same credential for all gateways all the time. THIS IS VERY BAD!!
|
||||
bandwidth_credential: Credential,
|
||||
}
|
||||
|
||||
pub(crate) struct PacketSender {
|
||||
@@ -84,6 +91,7 @@ impl PacketSender {
|
||||
pub(crate) fn new(
|
||||
gateways_status_updater: GatewayClientUpdateSender,
|
||||
local_identity: Arc<identity::KeyPair>,
|
||||
bandwidth_credential: Credential,
|
||||
gateway_response_timeout: Duration,
|
||||
gateway_connection_timeout: Duration,
|
||||
max_concurrent_clients: usize,
|
||||
@@ -95,6 +103,7 @@ impl PacketSender {
|
||||
gateways_status_updater,
|
||||
local_identity,
|
||||
gateway_response_timeout,
|
||||
bandwidth_credential,
|
||||
}),
|
||||
gateway_connection_timeout,
|
||||
max_concurrent_clients,
|
||||
@@ -114,16 +123,6 @@ impl PacketSender {
|
||||
// use old shared keys
|
||||
let (message_sender, message_receiver) = mpsc::unbounded();
|
||||
|
||||
let coconut_credential = Credential::init(
|
||||
vec![format!(
|
||||
"http://{}:{}",
|
||||
DEFAULT_VALIDATOR_HOST, VALIDATOR_API_PORT
|
||||
)],
|
||||
identity,
|
||||
)
|
||||
.await
|
||||
.expect("Could not initialize coconut credential");
|
||||
|
||||
// currently we do not care about acks at all, but we must keep the channel alive
|
||||
// so that the gateway client would not crash
|
||||
let (ack_sender, ack_receiver) = mpsc::unbounded();
|
||||
@@ -136,7 +135,7 @@ impl PacketSender {
|
||||
message_sender,
|
||||
ack_sender,
|
||||
fresh_gateway_client_data.gateway_response_timeout,
|
||||
coconut_credential,
|
||||
fresh_gateway_client_data.bandwidth_credential.clone(),
|
||||
),
|
||||
(message_receiver, ack_receiver),
|
||||
)
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::config::Config;
|
||||
use config::defaults::DEFAULT_VALIDATOR_API_PORT;
|
||||
use mixnet_contract::{GatewayBond, MixNodeBond};
|
||||
use std::sync::Arc;
|
||||
use tokio::sync::RwLock;
|
||||
use validator_client::nymd::{CosmWasmClient, QueryNymdClient, SigningNymdClient};
|
||||
use validator_client::ValidatorClientError;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub(crate) struct Client<C>(Arc<RwLock<validator_client::Client<C>>>);
|
||||
|
||||
impl Client<QueryNymdClient> {
|
||||
pub(crate) fn new_query(config: &Config) -> Self {
|
||||
// the api address is irrelevant here as **WE ARE THE API**
|
||||
let api_url = format!("http://localhost:{}", DEFAULT_VALIDATOR_API_PORT)
|
||||
.parse()
|
||||
.unwrap();
|
||||
let nymd_url = config.get_nymd_validator_url();
|
||||
|
||||
let mixnet_contract = config
|
||||
.get_mixnet_contract_address()
|
||||
.parse()
|
||||
.expect("the mixnet contract address is invalid!");
|
||||
|
||||
let client_config = validator_client::Config::new(nymd_url, api_url, Some(mixnet_contract));
|
||||
let inner =
|
||||
validator_client::Client::new_query(client_config).expect("Failed to connect to nymd!");
|
||||
|
||||
Client(Arc::new(RwLock::new(inner)))
|
||||
}
|
||||
}
|
||||
|
||||
impl Client<SigningNymdClient> {
|
||||
pub(crate) fn new_signing(config: &Config) -> Self {
|
||||
// the api address is irrelevant here as **WE ARE THE API**
|
||||
let api_url = format!("http://localhost:{}", DEFAULT_VALIDATOR_API_PORT)
|
||||
.parse()
|
||||
.unwrap();
|
||||
let nymd_url = config.get_nymd_validator_url();
|
||||
|
||||
let mixnet_contract = config
|
||||
.get_mixnet_contract_address()
|
||||
.parse()
|
||||
.expect("the mixnet contract address is invalid!");
|
||||
let mnemonic = config
|
||||
.get_mnemonic()
|
||||
.parse()
|
||||
.expect("the mnemonic is invalid!");
|
||||
|
||||
let client_config = validator_client::Config::new(nymd_url, api_url, Some(mixnet_contract));
|
||||
let inner = validator_client::Client::new_signing(client_config, mnemonic)
|
||||
.expect("Failed to connect to nymd!");
|
||||
|
||||
Client(Arc::new(RwLock::new(inner)))
|
||||
}
|
||||
}
|
||||
|
||||
impl<C> Client<C> {
|
||||
pub(crate) async fn get_mixnodes(&self) -> Result<Vec<MixNodeBond>, ValidatorClientError>
|
||||
where
|
||||
C: CosmWasmClient + Sync,
|
||||
{
|
||||
self.0.read().await.get_all_nymd_mixnodes().await
|
||||
}
|
||||
|
||||
pub(crate) async fn get_gateways(&self) -> Result<Vec<GatewayBond>, ValidatorClientError>
|
||||
where
|
||||
C: CosmWasmClient + Sync,
|
||||
{
|
||||
self.0.read().await.get_all_nymd_gateways().await
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub(crate) async fn some_rewarding_stuff_here(&self) {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user