Merge commit '6d44fe818ea4c74f476cc6d79434cc8619b45c0c' into simon/instrumented

This commit is contained in:
Simon Wicky
2023-03-28 13:17:09 +00:00
1686 changed files with 70374 additions and 44574 deletions
+17 -20
View File
@@ -3,7 +3,7 @@
[package]
name = "nym-mixnode"
version = "1.1.4"
version = "1.1.14"
authors = [
"Dave Hrycyszyn <futurechimp@users.noreply.github.com>",
"Jędrzej Stuczyński <andrew@nymtech.net>",
@@ -18,20 +18,20 @@ rust-version = "1.58.1"
[dependencies]
anyhow = "1.0.40"
bs58 = "0.4.0"
clap = { version = "3.2", features = ["cargo", "derive"] }
clap = { version = "4.0", features = ["cargo", "derive"] }
colored = "2.0"
cupid = "0.6.1"
dirs = "4.0"
dotenv = "0.15.0"
futures = "0.3.0"
humantime-serde = "1.0"
lazy_static = "1.4.0"
log = "0.4.0"
log = { workspace = true }
pretty_env_logger = "0.4.0"
rand = "0.7.3"
rocket = { version = "0.5.0-rc.2", features = ["json"] }
serde = { version="1.0", features = ["derive"] }
sysinfo = "0.24.1"
serde_json = "1.0"
sysinfo = "0.27.7"
tokio = { version="1.21.2", features = ["rt-multi-thread", "net", "signal"] }
tokio-util = { version="0.7.3", features = ["codec"] }
toml = "0.5.8"
@@ -42,27 +42,24 @@ tracing-opentelemetry = "0.18.0"
opentelemetry-jaeger = {version = "0.17.0", features = ["collector_client","rt-tokio","isahc_collector_client"]}
opentelemetry = {version = "0.18.0", features = ["rt-tokio"]}
tracing-flame = "0.2.0"
atty = "0.2"
## internal
config = { path="../common/config" }
crypto = { path="../common/crypto" }
completions = { path="../common/completions" }
logging = { path="../common/logging" }
nym-config = { path="../common/config" }
nym-crypto = { path="../common/crypto" }
mixnet-client = { path="../common/client-libs/mixnet-client" }
mixnode-common = { path="../common/mixnode-common" }
nonexhaustive-delayqueue = { path="../common/nonexhaustive-delayqueue" }
nymsphinx = { path="../common/nymsphinx" }
pemstore = { path="../common/pemstore" }
task = { path = "../common/task" }
topology = { path="../common/topology" }
nym-nonexhaustive-delayqueue = { path="../common/nonexhaustive-delayqueue" }
nym-sphinx = { path="../common/nymsphinx" }
nym-pemstore = { path = "../common/pemstore", version = "0.2.0" }
nym-task = { path = "../common/task" }
nym-types = { path = "../common/types" }
nym-topology = { path="../common/topology" }
validator-client = { path="../common/client-libs/validator-client" }
version-checker = { path="../common/version-checker" }
nym-bin-common = { path="../common/bin-common" }
[dev-dependencies]
tokio = { version="1.21.2", features = ["rt-multi-thread", "net", "signal", "test-util"] }
nymsphinx-types = { path = "../common/nymsphinx/types" }
nymsphinx-params = { path = "../common/nymsphinx/params" }
[build-dependencies]
vergen = { version = "5", default-features = false, features = ["build", "git", "rustc", "cargo"] }
nym-sphinx-types = { path = "../common/nymsphinx/types" }
nym-sphinx-params = { path = "../common/nymsphinx/params" }
-8
View File
@@ -1,8 +0,0 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use vergen::{vergen, Config};
fn main() {
vergen(Config::default()).expect("failed to extract build metadata")
}
+50 -28
View File
@@ -1,8 +1,11 @@
// Copyright 2021-2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::config::Config;
use crate::node::node_description::NodeDescription;
use clap::Args;
use colored::Colorize;
use config::NymConfig;
use nym_config::NymConfig;
use std::io;
use std::io::Write;
@@ -11,45 +14,64 @@ pub(crate) struct Describe {
/// The id of the mixnode you want to describe
#[clap(long)]
id: String,
/// Human readable name of this node
#[clap(long)]
name: Option<String>,
/// Description of this node
#[clap(long)]
description: Option<String>,
/// Link associated with this node, for example `https://mixnode.yourdomain.com`
#[clap(long)]
link: Option<String>,
/// Physical location of this node, for example `City: London, Country: UK`
#[clap(long)]
location: Option<String>,
}
pub(crate) fn execute(args: &Describe) {
fn read_user_input() -> String {
io::stdout().flush().unwrap();
let mut buf = String::new();
io::stdin().read_line(&mut buf).unwrap();
buf.trim().to_string()
}
pub(crate) fn execute(args: Describe) {
// ensure that the mixnode has in fact been initialized
match Config::load_from_file(Some(&args.id)) {
match Config::load_from_file(&args.id) {
Ok(cfg) => cfg,
Err(err) => {
error!("Failed to load config for {}. Are you sure you have run `init` before? (Error was: {})", &args.id, err);
error!("Failed to load config for {}. Are you sure you have run `init` before? (Error was: {err})", &args.id);
return;
}
};
// get input from the user
print!("name: ");
io::stdout().flush().unwrap();
let mut name_buf = String::new();
io::stdin().read_line(&mut name_buf).unwrap();
let name = name_buf.trim().to_string();
print!("description: ");
io::stdout().flush().unwrap();
let mut desc_buf = String::new();
io::stdin().read_line(&mut desc_buf).unwrap();
let description = desc_buf.trim().to_string();
let example_url = "https://mixnode.yourdomain.com".bright_cyan();
let example_location = "City: London, Country: UK";
print!("link, e.g. {}: ", example_url);
io::stdout().flush().unwrap();
let mut link_buf = String::new();
io::stdin().read_line(&mut link_buf).unwrap();
let link = link_buf.trim().to_string();
// get input from the user if not provided via the arguments
let name = args.name.unwrap_or_else(|| {
print!("name: ");
read_user_input()
});
print!("location, e.g. {}: ", example_location);
io::stdout().flush().unwrap();
let mut location_buf = String::new();
io::stdin().read_line(&mut location_buf).unwrap();
let location = location_buf.trim().to_string();
let description = args.description.unwrap_or_else(|| {
print!("description: ");
read_user_input()
});
let link = args.link.unwrap_or_else(|| {
print!("link, e.g. {example_url}: ");
read_user_input()
});
let location = args.location.unwrap_or_else(|| {
print!("location, e.g. {example_location}: ");
read_user_input()
});
let node_description = NodeDescription {
name,
@@ -61,7 +83,7 @@ pub(crate) fn execute(args: &Describe) {
// save the struct
NodeDescription::save_to_file(
&node_description,
Config::default_config_directory(Some(&args.id)),
Config::default_config_directory(&args.id),
)
.unwrap()
}
+26 -24
View File
@@ -1,14 +1,16 @@
// Copyright 2020 - Nym Technologies SA <contact@nymtech.net>
// Copyright 2020-2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use super::OverrideConfig;
use crate::config::Config;
use crate::node::MixNode;
use crate::OutputFormat;
use crate::{commands::override_config, config::persistence::pathfinder::MixNodePathfinder};
use clap::Args;
use config::NymConfig;
use crypto::asymmetric::{encryption, identity};
use super::OverrideConfig;
use nym_config::NymConfig;
use nym_crypto::asymmetric::{encryption, identity};
use std::net::IpAddr;
use validator_client::nyxd;
#[derive(Args, Clone)]
pub(crate) struct Init {
@@ -18,11 +20,11 @@ pub(crate) struct Init {
/// The host on which the mixnode will be running
#[clap(long)]
host: String,
host: IpAddr,
/// The wallet address you will use to bond this mixnode, e.g. nymt1z9egw0knv47nmur0p8vk4rcx59h9gg4zuxrrr9
#[clap(long)]
wallet_address: String,
wallet_address: nyxd::AccountId,
/// The port on which the mixnode will be listening for mix packets
#[clap(long)]
@@ -40,9 +42,10 @@ pub(crate) struct Init {
#[clap(long)]
announce_host: Option<String>,
/// Comma separated list of rest endpoints of the validators
#[clap(long)]
validators: Option<String>,
/// Comma separated list of nym-api endpoints of the validators
// the alias here is included for backwards compatibility (1.1.4 and before)
#[clap(long, alias = "validators", value_delimiter = ',')]
nym_apis: Option<Vec<url::Url>>,
}
impl From<Init> for OverrideConfig {
@@ -55,18 +58,18 @@ impl From<Init> for OverrideConfig {
verloc_port: init_config.verloc_port,
http_api_port: init_config.http_api_port,
announce_host: init_config.announce_host,
validators: init_config.validators,
nym_apis: init_config.nym_apis,
}
}
}
pub(crate) fn execute(args: &Init) {
pub(crate) fn execute(args: &Init, output: OutputFormat) {
let override_config_fields = OverrideConfig::from(args.clone());
let id = &override_config_fields.id;
println!("Initialising mixnode {}...", id);
eprintln!("Initialising mixnode {id}...");
let already_init = if Config::default_config_file_path(Some(id)).exists() {
println!("Mixnode \"{}\" was already initialised before! Config information will be overwritten (but keys will be kept)!", id);
let already_init = if Config::default_config_file_path(id).exists() {
eprintln!("Mixnode \"{id}\" was already initialised before! Config information will be overwritten (but keys will be kept)!");
true
} else {
false
@@ -82,33 +85,32 @@ pub(crate) fn execute(args: &Init) {
let identity_keys = identity::KeyPair::new(&mut rng);
let sphinx_keys = encryption::KeyPair::new(&mut rng);
let pathfinder = MixNodePathfinder::new_from_config(&config);
pemstore::store_keypair(
nym_pemstore::store_keypair(
&identity_keys,
&pemstore::KeyPairPath::new(
&nym_pemstore::KeyPairPath::new(
pathfinder.private_identity_key().to_owned(),
pathfinder.public_identity_key().to_owned(),
),
)
.expect("Failed to save identity keys");
pemstore::store_keypair(
nym_pemstore::store_keypair(
&sphinx_keys,
&pemstore::KeyPairPath::new(
&nym_pemstore::KeyPairPath::new(
pathfinder.private_encryption_key().to_owned(),
pathfinder.public_encryption_key().to_owned(),
),
)
.expect("Failed to save sphinx keys");
println!("Saved mixnet identity and sphinx keypairs");
eprintln!("Saved mixnet identity and sphinx keypairs");
}
let config_save_location = config.get_config_file_save_location();
config
.save_to_file(None)
.expect("Failed to save the config file");
println!("Saved configuration file to {:?}", config_save_location);
println!("Mixnode configuration completed.\n\n\n");
eprintln!("Saved configuration file to {config_save_location:?}");
eprintln!("Mixnode configuration completed.\n\n\n");
MixNode::new(config).print_node_details()
MixNode::new(config).print_node_details(output)
}
+45 -53
View File
@@ -1,19 +1,18 @@
// Copyright 2020 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use std::process;
use crate::{config::Config, Cli};
use clap::CommandFactory;
use clap::Subcommand;
use colored::Colorize;
use completions::{fig_generate, ArgShell};
use config::defaults::mainnet::read_var_if_not_default;
use config::{
defaults::var_names::{API_VALIDATOR, BECH32_PREFIX, CONFIGURED},
parse_validators,
};
use crypto::bech32_address_validation;
use nym_bin_common::completions::{fig_generate, ArgShell};
use nym_bin_common::version_checker;
use nym_config::defaults::var_names::{BECH32_PREFIX, NYM_API};
use nym_config::OptionalSet;
use nym_crypto::bech32_address_validation;
use std::net::IpAddr;
use std::process;
use validator_client::nyxd;
mod describe;
mod init;
@@ -52,71 +51,64 @@ pub(crate) enum Commands {
// Configuration that can be overridden.
struct OverrideConfig {
id: String,
host: Option<String>,
wallet_address: Option<String>,
host: Option<IpAddr>,
wallet_address: Option<nyxd::AccountId>,
mix_port: Option<u16>,
verloc_port: Option<u16>,
http_api_port: Option<u16>,
announce_host: Option<String>,
validators: Option<String>,
nym_apis: Option<Vec<url::Url>>,
}
pub(crate) async fn execute(args: Cli) {
let bin_name = "nym-mixnode";
match &args.command {
let output = args.output();
match args.command {
Commands::Describe(m) => describe::execute(m),
Commands::Init(m) => init::execute(m),
Commands::Run(m) => run::execute(m).await,
Commands::Sign(m) => sign::execute(m),
Commands::Upgrade(m) => upgrade::execute(m),
Commands::NodeDetails(m) => node_details::execute(m),
Commands::Completions(s) => s.generate(&mut crate::Cli::into_app(), bin_name),
Commands::GenerateFigSpec => fig_generate(&mut crate::Cli::into_app(), bin_name),
Commands::Init(m) => init::execute(&m, output),
Commands::Run(m) => run::execute(&m, output).await,
Commands::Sign(m) => sign::execute(&m),
Commands::Upgrade(m) => upgrade::execute(&m),
Commands::NodeDetails(m) => node_details::execute(&m, output),
Commands::Completions(s) => s.generate(&mut crate::Cli::command(), bin_name),
Commands::GenerateFigSpec => fig_generate(&mut crate::Cli::command(), bin_name),
}
}
fn override_config(mut config: Config, args: OverrideConfig) -> Config {
// special case that I'm not sure could be easily handled with the trait
let mut was_host_overridden = false;
if let Some(host) = args.host {
config = config.with_listening_address(host);
was_host_overridden = true;
}
if let Some(port) = args.mix_port {
config = config.with_mix_port(port);
}
if let Some(port) = args.verloc_port {
config = config.with_verloc_port(port);
}
if let Some(port) = args.http_api_port {
config = config.with_http_api_port(port);
}
if let Some(ref raw_validators) = args.validators {
config = config.with_custom_validator_apis(parse_validators(raw_validators));
} else if std::env::var(CONFIGURED).is_ok() {
if let Some(raw_validators) = read_var_if_not_default(API_VALIDATOR) {
config = config.with_custom_validator_apis(::config::parse_validators(&raw_validators))
}
}
if let Some(ref announce_host) = args.announce_host {
if let Some(announce_host) = args.announce_host {
config = config.with_announce_address(announce_host);
} else if was_host_overridden {
// make sure our 'announce-host' always defaults to 'host'
config = config.announce_address_from_listening_address()
}
if let Some(ref wallet_address) = args.wallet_address {
let trimmed = wallet_address.trim();
validate_bech32_address_or_exit(trimmed);
config = config.with_wallet_address(trimmed);
}
config
.with_optional(Config::with_mix_port, args.mix_port)
.with_optional(Config::with_verloc_port, args.verloc_port)
.with_optional(Config::with_http_api_port, args.http_api_port)
.with_optional_custom_env(
Config::with_custom_nym_apis,
args.nym_apis,
NYM_API,
nym_config::parse_urls,
)
.with_optional(
|cfg, wallet_address| {
validate_bech32_address_or_exit(wallet_address.as_ref());
cfg.with_wallet_address(wallet_address)
},
args.wallet_address,
)
}
/// Ensures that a given bech32 address is valid, or exits
@@ -125,18 +117,18 @@ pub(crate) fn validate_bech32_address_or_exit(address: &str) {
if let Err(bech32_address_validation::Bech32Error::DecodeFailed(err)) =
bech32_address_validation::try_bech32_decode(address)
{
let error_message = format!("Error: wallet address decoding failed: {}", err).red();
println!("{}", error_message);
println!("Exiting...");
let error_message = format!("Error: wallet address decoding failed: {err}").red();
error!("{}", error_message);
error!("Exiting...");
process::exit(1);
}
if let Err(bech32_address_validation::Bech32Error::WrongPrefix(err)) =
bech32_address_validation::validate_bech32_prefix(&prefix, address)
{
let error_message = format!("Error: wallet address type is wrong, {}", err).red();
println!("{}", error_message);
println!("Exiting...");
let error_message = format!("Error: wallet address type is wrong, {err}").red();
error!("{}", error_message);
error!("Exiting...");
process::exit(1);
}
}
+5 -4
View File
@@ -3,8 +3,9 @@
use crate::config::Config;
use crate::node::MixNode;
use crate::OutputFormat;
use clap::Args;
use config::NymConfig;
use nym_config::NymConfig;
#[derive(Args)]
pub(crate) struct NodeDetails {
@@ -13,8 +14,8 @@ pub(crate) struct NodeDetails {
id: String,
}
pub(crate) fn execute(args: &NodeDetails) {
let config = match Config::load_from_file(Some(&args.id)) {
pub(crate) fn execute(args: &NodeDetails, output: OutputFormat) {
let config = match Config::load_from_file(&args.id) {
Ok(cfg) => cfg,
Err(err) => {
error!(
@@ -26,5 +27,5 @@ pub(crate) fn execute(args: &NodeDetails) {
}
};
MixNode::new(config).print_node_details()
MixNode::new(config).print_node_details(output)
}
+19 -17
View File
@@ -1,13 +1,15 @@
// Copyright 2020 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use super::OverrideConfig;
use crate::commands::{override_config, version_check};
use crate::config::Config;
use crate::node::MixNode;
use crate::OutputFormat;
use clap::Args;
use config::NymConfig;
use super::OverrideConfig;
use nym_config::NymConfig;
use std::net::IpAddr;
use validator_client::nyxd;
#[derive(Args, Clone)]
pub(crate) struct Run {
@@ -17,11 +19,11 @@ pub(crate) struct Run {
/// The custom host on which the mixnode will be running
#[clap(long)]
host: Option<String>,
host: Option<IpAddr>,
/// The wallet address you will use to bond this mixnode, e.g. nymt1z9egw0knv47nmur0p8vk4rcx59h9gg4zuxrrr9
#[clap(long)]
wallet_address: Option<String>,
wallet_address: Option<nyxd::AccountId>,
/// The port on which the mixnode will be listening for mix packets
#[clap(long)]
@@ -39,9 +41,10 @@ pub(crate) struct Run {
#[clap(long)]
announce_host: Option<String>,
/// Comma separated list of rest endpoints of the validators
#[clap(long)]
validators: Option<String>,
/// Comma separated list of nym-api endpoints of the validators
// the alias here is included for backwards compatibility (1.1.4 and before)
#[clap(long, alias = "validators", value_delimiter = ',')]
nym_apis: Option<Vec<url::Url>>,
}
impl From<Run> for OverrideConfig {
@@ -54,7 +57,7 @@ impl From<Run> for OverrideConfig {
verloc_port: run_config.verloc_port,
http_api_port: run_config.http_api_port,
announce_host: run_config.announce_host,
validators: run_config.validators,
nym_apis: run_config.nym_apis,
}
}
}
@@ -62,10 +65,9 @@ impl From<Run> for OverrideConfig {
fn show_binding_warning(address: &str) {
println!("\n##### NOTE #####");
println!(
"\nYou are trying to bind to {} - you might not be accessible to other nodes\n\
"\nYou are trying to bind to {address} - you might not be accessible to other nodes\n\
You can ignore this note if you're running setup on a local network \n\
or have set a custom 'announce-host'",
address
or have set a custom 'announce-host'"
);
println!("\n\n");
}
@@ -74,10 +76,10 @@ fn special_addresses() -> Vec<&'static str> {
vec!["localhost", "127.0.0.1", "0.0.0.0", "::1", "[::1]"]
}
pub(crate) async fn execute(args: &Run) {
println!("Starting mixnode {}...", args.id);
pub(crate) async fn execute(args: &Run, output: OutputFormat) {
eprintln!("Starting mixnode {}...", args.id);
let mut config = match Config::load_from_file(Some(&args.id)) {
let mut config = match Config::load_from_file(&args.id) {
Ok(cfg) => cfg,
Err(err) => {
error!(
@@ -102,10 +104,10 @@ pub(crate) async fn execute(args: &Run) {
let mut mixnode = MixNode::new(config);
println!(
eprintln!(
"\nTo bond your mixnode you will need to install the Nym wallet, go to https://nymtech.net/get-involved and select the Download button.\n\
Select the correct version and install it to your machine. You will need to provide the following: \n ");
mixnode.print_node_details();
mixnode.print_node_details(output);
mixnode.run().await
}
+19 -26
View File
@@ -1,4 +1,4 @@
// Copyright 2020 - Nym Technologies SA <contact@nymtech.net>
// Copyright 2020-2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use std::convert::TryFrom;
@@ -8,22 +8,24 @@ use crate::config::{persistence::pathfinder::MixNodePathfinder, Config};
use crate::node::MixNode;
use anyhow::{anyhow, Result};
use clap::{ArgGroup, Args};
use config::NymConfig;
use crypto::asymmetric::identity;
use log::error;
use nym_config::NymConfig;
use nym_crypto::asymmetric::identity;
use validator_client::nyxd;
use super::version_check;
#[derive(Args, Clone)]
#[clap(group(ArgGroup::new("sign").required(true).args(&["address", "text"])))]
#[clap(group(ArgGroup::new("sign").required(true).args(&["wallet_address", "text"])))]
pub(crate) struct Sign {
/// The id of the mixnode you want to sign with
#[clap(long)]
id: String,
/// Signs your blockchain address with your identity key
#[clap(long)]
address: Option<String>,
// the alias here is included for backwards compatibility (1.1.4 and before)
#[clap(long, alias = "address")]
wallet_address: Option<nyxd::AccountId>,
/// Signs an arbitrary piece of text with your identity key
#[clap(long)]
@@ -32,7 +34,7 @@ pub(crate) struct Sign {
enum SignedTarget {
Text(String),
Address(String),
Address(nyxd::AccountId),
}
impl TryFrom<Sign> for SignedTarget {
@@ -41,7 +43,7 @@ impl TryFrom<Sign> for SignedTarget {
fn try_from(args: Sign) -> Result<Self, Self::Error> {
if let Some(text) = args.text {
Ok(SignedTarget::Text(text))
} else if let Some(address) = args.address {
} else if let Some(address) = args.wallet_address {
Ok(SignedTarget::Address(address))
} else {
// This is unreachable, and hopefully clap will support it explicitly by outputting an
@@ -52,33 +54,24 @@ impl TryFrom<Sign> for SignedTarget {
}
}
fn print_signed_address(private_key: &identity::PrivateKey, raw_address: &str) {
let trimmed = raw_address.trim();
validate_bech32_address_or_exit(trimmed);
let signature = private_key.sign_text(trimmed);
fn print_signed_address(private_key: &identity::PrivateKey, wallet_address: nyxd::AccountId) {
// perform extra validation to ensure we have correct prefix
validate_bech32_address_or_exit(wallet_address.as_ref());
println!(
"The base58-encoded signature on '{}' is: {}",
trimmed, signature
);
let signature = private_key.sign_text(wallet_address.as_ref());
println!("The base58-encoded signature on '{wallet_address}' is: {signature}",);
}
fn print_signed_text(private_key: &identity::PrivateKey, text: &str) {
println!(
"Signing the text {:?} using your mixnode's Ed25519 identity key...",
text
);
println!("Signing the text {text:?} using your mixnode's Ed25519 identity key...");
let signature = private_key.sign_text(text);
println!(
"The base58-encoded signature on '{}' is: {}",
text, signature
);
println!("The base58-encoded signature on '{text}' is: {signature}");
}
pub(crate) fn execute(args: &Sign) {
let config = match Config::load_from_file(Some(&args.id)) {
let config = match Config::load_from_file(&args.id) {
Ok(cfg) => cfg,
Err(err) => {
error!(
@@ -107,6 +100,6 @@ pub(crate) fn execute(args: &Sign) {
match signed_target {
SignedTarget::Text(text) => print_signed_text(identity_keypair.private_key(), &text),
SignedTarget::Address(addr) => print_signed_address(identity_keypair.private_key(), &addr),
SignedTarget::Address(addr) => print_signed_address(identity_keypair.private_key(), addr),
}
}
+13 -27
View File
@@ -3,10 +3,10 @@
use crate::config::{missing_string_value, Config};
use clap::Args;
use config::NymConfig;
use nym_bin_common::version_checker::Version;
use nym_config::NymConfig;
use std::fmt::Display;
use std::process;
use version_checker::Version;
#[derive(Args)]
pub(crate) struct Upgrade {
@@ -22,49 +22,38 @@ fn fail_upgrade<D1: Display, D2: Display>(from_version: D1, to_version: D2) -> !
}
fn print_start_upgrade<D1: Display, D2: Display>(from: D1, to: D2) {
println!(
"\n==================\nTrying to upgrade mixnode from {} to {} ...",
from, to
);
println!("\n==================\nTrying to upgrade mixnode from {from} to {to} ...");
}
fn print_failed_upgrade<D1: Display, D2: Display>(from: D1, to: D2) {
eprintln!(
"Upgrade from {} to {} failed!\n==================\n",
from, to
);
eprintln!("Upgrade from {from} to {to} failed!\n==================\n");
}
fn print_successful_upgrade<D1: Display, D2: Display>(from: D1, to: D2) {
println!(
"Upgrade from {} to {} was successful!\n==================\n",
from, to
);
println!("Upgrade from {from} to {to} was successful!\n==================\n");
}
fn outdated_upgrade(config_version: &Version, package_version: &Version) -> ! {
eprintln!(
"Cannot perform upgrade from {} to {}. Your version is too old to perform the upgrade.!",
config_version, package_version
"Cannot perform upgrade from {config_version} to {package_version}. Your version is too old to perform the upgrade.!"
);
process::exit(1)
}
fn unsupported_upgrade(config_version: &Version, package_version: &Version) -> ! {
eprintln!("Cannot perform upgrade from {} to {}. Please let the developers know about this issue if you expected it to work!", config_version, package_version);
eprintln!("Cannot perform upgrade from {config_version} to {package_version}. Please let the developers know about this issue if you expected it to work!");
process::exit(1)
}
fn parse_config_version(config: &Config) -> Version {
let version = Version::parse(config.get_version()).unwrap_or_else(|err| {
eprintln!("failed to parse client version! - {:?}", err);
eprintln!("failed to parse client version! - {err}");
process::exit(1)
});
if version.is_prerelease() || !version.build.is_empty() {
eprintln!(
"Trying to upgrade from a non-released version {}. This is not supported!",
version
"Trying to upgrade from a non-released version {version}. This is not supported!"
);
process::exit(1)
}
@@ -79,10 +68,7 @@ fn parse_package_version() -> Version {
// however, we are not using them ourselves at the moment and hence it should be fine.
// if we change our mind, we could easily tweak this code
if version.is_prerelease() || !version.build.is_empty() {
eprintln!(
"Trying to upgrade to a non-released version {}. This is not supported!",
version
);
eprintln!("Trying to upgrade to a non-released version {version}. This is not supported!");
process::exit(1)
}
@@ -106,7 +92,7 @@ fn minor_0_12_upgrade(
let upgraded_config = config.with_custom_version(to_version.to_string().as_ref());
upgraded_config.save_to_file(None).unwrap_or_else(|err| {
eprintln!("failed to overwrite config file! - {:?}", err);
eprintln!("failed to overwrite config file! - {err}");
print_failed_upgrade(config_version, &to_version);
process::exit(1);
});
@@ -139,8 +125,8 @@ fn do_upgrade(mut config: Config, args: &Upgrade, package_version: Version) {
pub(crate) fn execute(args: &Upgrade) {
let package_version = parse_package_version();
let existing_config = Config::load_from_file(Some(&args.id)).unwrap_or_else(|err| {
eprintln!("failed to load existing config file! - {:?}", err);
let existing_config = Config::load_from_file(&args.id).unwrap_or_else(|err| {
eprintln!("failed to load existing config file! - {err}");
process::exit(1)
});
+24 -30
View File
@@ -2,17 +2,18 @@
// SPDX-License-Identifier: Apache-2.0
use crate::config::template::config_template;
use config::defaults::mainnet::API_VALIDATOR;
use config::defaults::{
use nym_config::defaults::mainnet::NYM_API;
use nym_config::defaults::{
DEFAULT_HTTP_API_LISTENING_PORT, DEFAULT_MIX_LISTENING_PORT, DEFAULT_VERLOC_LISTENING_PORT,
};
use config::NymConfig;
use nym_config::NymConfig;
use serde::{Deserialize, Deserializer, Serialize};
use std::net::{IpAddr, SocketAddr};
use std::path::PathBuf;
use std::str::FromStr;
use std::time::Duration;
use url::Url;
use validator_client::nyxd;
pub mod persistence;
mod template;
@@ -155,21 +156,13 @@ impl Config {
self
}
pub fn with_custom_validator_apis(mut self, validator_api_urls: Vec<Url>) -> Self {
self.mixnode.validator_api_urls = validator_api_urls;
pub fn with_custom_nym_apis(mut self, nym_api_urls: Vec<Url>) -> Self {
self.mixnode.nym_api_urls = nym_api_urls;
self
}
pub fn with_listening_address<S: Into<String>>(mut self, listening_address: S) -> Self {
let listening_address_string = listening_address.into();
if let Ok(ip_addr) = listening_address_string.parse() {
self.mixnode.listening_address = ip_addr
} else {
error!(
"failed to change listening address. the provided value ({}) was invalid",
listening_address_string
)
}
pub fn with_listening_address(mut self, listening_address: IpAddr) -> Self {
self.mixnode.listening_address = listening_address;
self
}
@@ -203,8 +196,8 @@ impl Config {
self
}
pub fn with_wallet_address(mut self, wallet_address: &str) -> Self {
self.mixnode.wallet_address = wallet_address.to_string();
pub fn with_wallet_address(mut self, wallet_address: nyxd::AccountId) -> Self {
self.mixnode.wallet_address = Some(wallet_address);
self
}
@@ -233,8 +226,8 @@ impl Config {
self.mixnode.public_sphinx_key_file.clone()
}
pub fn get_validator_api_endpoints(&self) -> Vec<Url> {
self.mixnode.validator_api_urls.clone()
pub fn get_nym_api_endpoints(&self) -> Vec<Url> {
self.mixnode.nym_api_urls.clone()
}
pub fn get_node_stats_logging_delay(&self) -> Duration {
@@ -317,8 +310,8 @@ impl Config {
self.verloc.retry_timeout
}
pub fn get_wallet_address(&self) -> &str {
&self.mixnode.wallet_address
pub fn get_wallet_address(&self) -> Option<nyxd::AccountId> {
self.mixnode.wallet_address.clone()
}
}
@@ -369,32 +362,33 @@ struct MixNode {
/// Path to file containing public sphinx key.
public_sphinx_key_file: PathBuf,
/// Addresses to APIs running on validator from which the node gets the view of the network.
validator_api_urls: Vec<Url>,
/// Addresses to nym APIs from which the node gets the view of the network.
nym_api_urls: Vec<Url>,
/// nym_home_directory specifies absolute path to the home nym MixNodes directory.
/// It is expected to use default value and hence .toml file should not redefine this field.
nym_root_directory: PathBuf,
/// The Cosmos wallet address that will control this mixnode
wallet_address: String,
// the only reason this is an Option is because of the lack of existence of a sane default value
wallet_address: Option<nyxd::AccountId>,
}
impl MixNode {
fn default_private_identity_key_file(id: &str) -> PathBuf {
Config::default_data_directory(Some(id)).join("private_identity.pem")
Config::default_data_directory(id).join("private_identity.pem")
}
fn default_public_identity_key_file(id: &str) -> PathBuf {
Config::default_data_directory(Some(id)).join("public_identity.pem")
Config::default_data_directory(id).join("public_identity.pem")
}
fn default_private_sphinx_key_file(id: &str) -> PathBuf {
Config::default_data_directory(Some(id)).join("private_sphinx.pem")
Config::default_data_directory(id).join("private_sphinx.pem")
}
fn default_public_sphinx_key_file(id: &str) -> PathBuf {
Config::default_data_directory(Some(id)).join("public_sphinx.pem")
Config::default_data_directory(id).join("public_sphinx.pem")
}
}
@@ -412,9 +406,9 @@ impl Default for MixNode {
public_identity_key_file: Default::default(),
private_sphinx_key_file: Default::default(),
public_sphinx_key_file: Default::default(),
validator_api_urls: vec![Url::from_str(API_VALIDATOR).expect("Invalid default API URL")],
nym_api_urls: vec![Url::from_str(NYM_API).expect("Invalid default API URL")],
nym_root_directory: Config::default_root_directory(),
wallet_address: "nymXXXXXXXX".to_string(),
wallet_address: None,
}
}
}
+2 -2
View File
@@ -54,8 +54,8 @@ verloc_port = {{ mixnode.verloc_port }}
http_api_port = {{ mixnode.http_api_port }}
# Addresses to APIs running on validator from which the node gets the view of the network.
validator_api_urls = [
{{#each mixnode.validator_api_urls }}
nym_api_urls = [
{{#each mixnode.nym_api_urls }}
'{{this}}',
{{/each}}
]
+41 -60
View File
@@ -1,41 +1,68 @@
// Copyright 2020-2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
#[macro_use]
extern crate rocket;
// Copyright 2020 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use ::config::defaults::setup_env;
use clap::{crate_version, Parser};
use ::nym_config::defaults::setup_env;
use clap::{crate_name, crate_version, Parser, ValueEnum};
use lazy_static::lazy_static;
use logging::setup_logging;
use tracing_subscriber::layer::SubscriberExt;
use tracing_subscriber::{EnvFilter, Registry, filter};
use tracing_flame::FlameLayer;
use nym_bin_common::logging::setup_logging;
use nym_bin_common::{build_information::BinaryBuildInformation, logging::banner};
mod commands;
mod config;
mod node;
lazy_static! {
pub static ref LONG_VERSION: String = long_version();
pub static ref PRETTY_BUILD_INFORMATION: String =
BinaryBuildInformation::new(env!("CARGO_PKG_VERSION")).pretty_print();
}
// Helper for passing LONG_VERSION to clap
fn long_version_static() -> &'static str {
&LONG_VERSION
fn pretty_build_info_static() -> &'static str {
&PRETTY_BUILD_INFORMATION
}
#[derive(Clone, ValueEnum)]
enum OutputFormat {
Json,
Text,
}
impl Default for OutputFormat {
fn default() -> Self {
OutputFormat::Text
}
}
#[derive(Parser)]
#[clap(author = "Nymtech", version, about, long_version = long_version_static())]
#[clap(author = "Nymtech", version, about, long_version = pretty_build_info_static())]
struct Cli {
/// Path pointing to an env file that configures the mixnode.
#[clap(short, long)]
pub(crate) config_env_file: Option<std::path::PathBuf>,
#[clap(short, long)]
pub(crate) output: Option<OutputFormat>,
#[clap(subcommand)]
command: commands::Commands,
}
impl Cli {
fn output(&self) -> OutputFormat {
if let Some(ref output) = self.output {
output.clone()
} else {
OutputFormat::default()
}
}
}
#[tokio::main]
async fn main() {
//setup_logging();
@@ -64,62 +91,16 @@ async fn main() {
tracing::subscriber::set_global_default(subscriber)
.expect("Failed to set global subscriber");
println!("{}", banner());
if atty::is(atty::Stream::Stdout) {
println!("{}", banner(crate_name!(), crate_version!()));
}
let args = Cli::parse();
setup_env(args.config_env_file.clone());
setup_env(args.config_env_file.as_ref());
commands::execute(args).await;
opentelemetry::global::shutdown_tracer_provider();
}
fn banner() -> String {
format!(
r#"
_ __ _ _ _ __ ___
| '_ \| | | | '_ \ _ \
| | | | |_| | | | | | |
|_| |_|\__, |_| |_| |_|
|___/
(mixnode - version {:})
"#,
crate_version!()
)
}
fn long_version() -> String {
format!(
r#"
{:<20}{}
{:<20}{}
{:<20}{}
{:<20}{}
{:<20}{}
{:<20}{}
{:<20}{}
{:<20}{}
"#,
"Build Timestamp:",
env!("VERGEN_BUILD_TIMESTAMP"),
"Build Version:",
env!("VERGEN_BUILD_SEMVER"),
"Commit SHA:",
env!("VERGEN_GIT_SHA"),
"Commit Date:",
env!("VERGEN_GIT_COMMIT_TIMESTAMP"),
"Commit Branch:",
env!("VERGEN_GIT_BRANCH"),
"rustc Version:",
env!("VERGEN_RUSTC_SEMVER"),
"rustc Channel:",
env!("VERGEN_RUSTC_CHANNEL"),
"cargo Profile:",
env!("VERGEN_CARGO_PROFILE")
)
}
#[cfg(test)]
mod tests {
use super::*;
@@ -5,15 +5,15 @@ use crate::node::listener::connection_handler::packet_processing::{
MixProcessingResult, PacketProcessor,
};
use crate::node::packet_delayforwarder::PacketDelayForwardSender;
use crate::node::ShutdownListener;
use crate::node::TaskClient;
use futures::StreamExt;
use tracing::{error, info, trace, debug, warn};
use tracing::*;
use nymsphinx::forwarding::packet::MixPacket;
use nymsphinx::params::PacketSize;
use nymsphinx::framing::codec::SphinxCodec;
use nymsphinx::framing::packet::FramedSphinxPacket;
use nymsphinx::Delay as SphinxDelay;
use nym_sphinx::forwarding::packet::MixPacket;
use nym_sphinx::params::PacketSize;
use nym_sphinx::framing::codec::SphinxCodec;
use nym_sphinx::framing::packet::FramedSphinxPacket;
use nym_sphinx::Delay as SphinxDelay;
use std::net::SocketAddr;
use tokio::net::TcpStream;
use tokio::time::Instant;
@@ -63,7 +63,7 @@ impl ConnectionHandler {
// all processing such, key caching, etc. was done.
// however, if it was a forward hop, we still need to delay it
match self.packet_processor.process_received(framed_sphinx_packet) {
Err(e) => debug!("We failed to process received sphinx packet - {:?}", e),
Err(err) => debug!("We failed to process received sphinx packet - {err}"),
Ok(res) => match res {
MixProcessingResult::ForwardHop(forward_packet, delay) => {
self.delay_and_forward_packet(forward_packet, delay)
@@ -79,12 +79,17 @@ impl ConnectionHandler {
self,
conn: TcpStream,
remote: SocketAddr,
mut shutdown: ShutdownListener,
mut shutdown: TaskClient,
) {
debug!("Starting connection handler for {:?}", remote);
shutdown.mark_as_success();
let mut framed_conn = Framed::new(conn, SphinxCodec);
while !shutdown.is_shutdown() {
tokio::select! {
biased;
_ = shutdown.recv() => {
trace!("ConnectionHandler: received shutdown");
}
Some(framed_sphinx_packet) = framed_conn.next() => {
match framed_sphinx_packet {
Ok(framed_sphinx_packet) => {
@@ -102,16 +107,12 @@ impl ConnectionHandler {
}
Err(err) => {
error!(
"The socket connection got corrupted with error: {:?}. Closing the socket",
err
"The socket connection got corrupted with error: {err}. Closing the socket",
);
return;
}
}
},
_ = shutdown.recv() => {
trace!("ConnectionHandler: received shutdown");
}
}
}
@@ -2,11 +2,11 @@
// SPDX-License-Identifier: Apache-2.0
use crate::node::node_statistics;
use crypto::asymmetric::encryption;
use mixnode_common::packet_processor::error::MixProcessingError;
pub use mixnode_common::packet_processor::processor::MixProcessingResult;
use mixnode_common::packet_processor::processor::SphinxPacketProcessor;
use nymsphinx::framing::packet::FramedSphinxPacket;
use nym_crypto::asymmetric::encryption;
use nym_sphinx::framing::packet::FramedSphinxPacket;
// PacketProcessor contains all data required to correctly unwrap and forward sphinx packets
#[derive(Clone)]
+9 -8
View File
@@ -9,17 +9,17 @@ use std::process;
use tokio::net::TcpListener;
use tokio::task::JoinHandle;
use super::ShutdownListener;
use super::TaskClient;
pub(crate) mod connection_handler;
pub(crate) struct Listener {
address: SocketAddr,
shutdown: ShutdownListener,
shutdown: TaskClient,
}
impl Listener {
pub(crate) fn new(address: SocketAddr, shutdown: ShutdownListener) -> Self {
pub(crate) fn new(address: SocketAddr, shutdown: TaskClient) -> Self {
Listener { address, shutdown }
}
#[instrument(level="info", skip_all, "Mixnet Listener")]
@@ -28,25 +28,26 @@ impl Listener {
let listener = match TcpListener::bind(self.address).await {
Ok(listener) => listener,
Err(err) => {
error!("Failed to bind to {} - {}. Are you sure nothing else is running on the specified port and your user has sufficient permission to bind to the requested address?", self.address, err);
error!("Failed to bind to {} - {err}. Are you sure nothing else is running on the specified port and your user has sufficient permission to bind to the requested address?", self.address);
process::exit(1);
}
};
while !self.shutdown.is_shutdown() {
tokio::select! {
biased;
_ = self.shutdown.recv() => {
trace!("Listener: Received shutdown");
}
connection = listener.accept() => {
match connection {
Ok((socket, remote_addr)) => {
let handler = connection_handler.clone();
tokio::spawn(handler.handle_connection(socket, remote_addr, self.shutdown.clone()).instrument(info_span!("Connection handling", address = %remote_addr)));
}
Err(err) => warn!("Failed to accept incoming connection - {:?}", err),
Err(err) => warn!("Failed to accept incoming connection - {err}"),
}
},
_ = self.shutdown.recv() => {
trace!("Listener: Received shutdown");
}
};
}
trace!("Listener: Exiting");
+52 -55
View File
@@ -17,18 +17,20 @@ use crate::node::listener::Listener;
use crate::node::node_description::NodeDescription;
use crate::node::node_statistics::SharedNodeStats;
use crate::node::packet_delayforwarder::{DelayForwarder, PacketDelayForwardSender};
use ::crypto::asymmetric::{encryption, identity};
use config::NymConfig;
use tracing::*;
use tracing::{info, error, warn};
use crate::OutputFormat;
use colored::Colorize;
use mixnode_common::verloc::{self, AtomicVerlocResult, VerlocMeasurer};
use nym_bin_common::version_checker::parse_version;
use nym_config::NymConfig;
use nym_crypto::asymmetric::{encryption, identity};
use nym_task::{TaskClient, TaskManager};
use rand::seq::SliceRandom;
use rand::thread_rng;
use std::net::SocketAddr;
use std::process;
use std::sync::Arc;
use task::{wait_for_signal, ShutdownListener, ShutdownNotifier};
use version_checker::parse_version;
mod http;
mod listener;
@@ -57,14 +59,14 @@ impl MixNode {
}
fn load_node_description(config: &Config) -> NodeDescription {
NodeDescription::load_from_file(Config::default_config_directory(Some(&config.get_id())))
NodeDescription::load_from_file(Config::default_config_directory(&config.get_id()))
.unwrap_or_default()
}
/// Loads identity keys stored on disk
pub(crate) fn load_identity_keys(pathfinder: &MixNodePathfinder) -> identity::KeyPair {
let identity_keypair: identity::KeyPair =
pemstore::load_keypair(&pemstore::KeyPairPath::new(
nym_pemstore::load_keypair(&nym_pemstore::KeyPairPath::new(
pathfinder.private_identity_key().to_owned(),
pathfinder.public_identity_key().to_owned(),
))
@@ -75,7 +77,7 @@ impl MixNode {
/// Loads Sphinx keys stored on disk
fn load_sphinx_keys(pathfinder: &MixNodePathfinder) -> encryption::KeyPair {
let sphinx_keypair: encryption::KeyPair =
pemstore::load_keypair(&pemstore::KeyPairPath::new(
nym_pemstore::load_keypair(&nym_pemstore::KeyPairPath::new(
pathfinder.private_encryption_key().to_owned(),
pathfinder.public_encryption_key().to_owned(),
))
@@ -88,39 +90,41 @@ impl MixNode {
fn generate_owner_signature(&self) -> String {
let pathfinder = MixNodePathfinder::new_from_config(&self.config);
let identity_keypair = Self::load_identity_keys(&pathfinder);
let address = self.config.get_wallet_address();
validate_bech32_address_or_exit(address);
let verification_code = identity_keypair.private_key().sign_text(address);
let Some(address) = self.config.get_wallet_address() else {
let error_message = "Error: mixnode hasn't set its wallet address".red();
println!("{error_message}");
println!("Exiting...");
process::exit(1);
};
// perform extra validation to ensure we have correct prefix
validate_bech32_address_or_exit(address.as_ref());
let verification_code = identity_keypair.private_key().sign_text(address.as_ref());
verification_code
}
/// Prints relevant node details to the console
pub(crate) fn print_node_details(&self) {
println!(
"Identity Key: {}",
self.identity_keypair.public_key().to_base58_string()
);
println!(
"Sphinx Key: {}",
self.sphinx_keypair.public_key().to_base58_string()
);
println!("Owner Signature: {}", self.generate_owner_signature());
println!(
"Host: {} (bind address: {})",
self.config.get_announce_address(),
self.config.get_listening_address()
);
println!("Version: {}", self.config.get_version());
println!(
"Mix Port: {}, Verloc port: {}, Http Port: {}\n",
self.config.get_mix_port(),
self.config.get_verloc_port(),
self.config.get_http_api_port()
);
println!(
"You are bonding to wallet address: {}\n\n",
self.config.get_wallet_address()
);
pub(crate) fn print_node_details(&self, output: OutputFormat) {
let node_details = nym_types::mixnode::MixnodeNodeDetailsResponse {
identity_key: self.identity_keypair.public_key().to_base58_string(),
sphinx_key: self.sphinx_keypair.public_key().to_base58_string(),
owner_signature: self.generate_owner_signature(),
announce_address: self.config.get_announce_address(),
bind_address: self.config.get_listening_address().to_string(),
version: self.config.get_version().to_string(),
mix_port: self.config.get_mix_port(),
http_api_port: self.config.get_http_api_port(),
verloc_port: self.config.get_verloc_port(),
wallet_address: self.config.get_wallet_address().map(|x| x.to_string()),
};
match output {
OutputFormat::Json => println!(
"{}",
serde_json::to_string(&node_details)
.unwrap_or_else(|_| "Could not serialize node details".to_string())
),
OutputFormat::Text => println!("{node_details}"),
}
}
fn start_http_api(
@@ -154,7 +158,7 @@ impl MixNode {
fn start_node_stats_controller(
&self,
shutdown: ShutdownListener,
shutdown: TaskClient,
) -> (SharedNodeStats, node_statistics::UpdateSender) {
info!("Starting node stats controller...");
let controller = node_statistics::Controller::new(
@@ -172,7 +176,7 @@ impl MixNode {
&self,
node_stats_update_sender: node_statistics::UpdateSender,
delay_forwarding_channel: PacketDelayForwardSender,
shutdown: ShutdownListener,
shutdown: TaskClient,
) {
info!("Starting socket listener...");
@@ -192,7 +196,7 @@ impl MixNode {
fn start_packet_delay_forwarder(
&mut self,
node_stats_update_sender: node_statistics::UpdateSender,
shutdown: ShutdownListener,
shutdown: TaskClient,
) -> PacketDelayForwardSender {
info!("Starting packet delay-forwarder...");
@@ -216,7 +220,7 @@ impl MixNode {
packet_sender
}
fn start_verloc_measurements(&self, shutdown: ShutdownListener) -> AtomicVerlocResult {
fn start_verloc_measurements(&self, shutdown: TaskClient) -> AtomicVerlocResult {
info!("Starting the round-trip-time measurer...");
// this is a sanity check to make sure we didn't mess up with the minimum version at some point
@@ -246,7 +250,7 @@ impl MixNode {
.tested_nodes_batch_size(self.config.get_measurement_tested_nodes_batch_size())
.testing_interval(self.config.get_measurement_testing_interval())
.retry_timeout(self.config.get_measurement_retry_timeout())
.validator_api_urls(self.config.get_validator_api_endpoints())
.nym_api_urls(self.config.get_nym_api_endpoints())
.build();
let mut verloc_measurer =
@@ -256,13 +260,13 @@ impl MixNode {
atomic_verloc_results
}
fn random_api_client(&self) -> validator_client::client::ApiClient {
let endpoints = self.config.get_validator_api_endpoints();
let validator_api = endpoints
fn random_api_client(&self) -> validator_client::NymApiClient {
let endpoints = self.config.get_nym_api_endpoints();
let nym_api = endpoints
.choose(&mut thread_rng())
.expect("The list of validator apis is empty");
validator_client::client::ApiClient::new(validator_api.clone())
validator_client::NymApiClient::new(nym_api.clone())
}
// TODO: ask DH whether this function still makes sense in ^0.10
@@ -289,15 +293,8 @@ impl MixNode {
.map(|node| node.bond_information.mix_node.identity_key.clone())
}
async fn wait_for_interrupt(&self, mut shutdown: ShutdownNotifier) {
wait_for_signal().await;
info!("Sending shutdown");
shutdown.signal_shutdown().ok();
info!("Waiting for tasks to finish... (Press ctrl-c to force)");
shutdown.wait_for_shutdown().await;
async fn wait_for_interrupt(&self, shutdown: TaskManager) {
let _res = shutdown.catch_interrupt().await;
info!("Stopping nym mixnode");
}
@@ -316,7 +313,7 @@ impl MixNode {
}
}
let shutdown = ShutdownNotifier::default();
let shutdown = TaskManager::default();
let (node_stats_pointer, node_stats_update_sender) =
self.start_node_stats_controller(shutdown.subscribe());
+10 -10
View File
@@ -9,7 +9,7 @@ use std::sync::Arc;
use std::time::{Duration, SystemTime};
use tokio::sync::{RwLock, RwLockReadGuard};
use super::ShutdownListener;
use super::TaskClient;
// convenience aliases
type PacketsMap = HashMap<String, u64>;
@@ -211,14 +211,14 @@ impl CurrentPacketData {
struct UpdateHandler {
current_data: CurrentPacketData,
update_receiver: PacketDataReceiver,
shutdown: ShutdownListener,
shutdown: TaskClient,
}
impl UpdateHandler {
fn new(
current_data: CurrentPacketData,
update_receiver: PacketDataReceiver,
shutdown: ShutdownListener,
shutdown: TaskClient,
) -> Self {
UpdateHandler {
current_data,
@@ -293,7 +293,7 @@ struct StatsUpdater {
updating_delay: Duration,
current_packet_data: CurrentPacketData,
current_stats: SharedNodeStats,
shutdown: ShutdownListener,
shutdown: TaskClient,
}
impl StatsUpdater {
@@ -301,7 +301,7 @@ impl StatsUpdater {
updating_delay: Duration,
current_packet_data: CurrentPacketData,
current_stats: SharedNodeStats,
shutdown: ShutdownListener,
shutdown: TaskClient,
) -> Self {
StatsUpdater {
updating_delay,
@@ -335,11 +335,11 @@ impl StatsUpdater {
struct PacketStatsConsoleLogger {
logging_delay: Duration,
stats: SharedNodeStats,
shutdown: ShutdownListener,
shutdown: TaskClient,
}
impl PacketStatsConsoleLogger {
fn new(logging_delay: Duration, stats: SharedNodeStats, shutdown: ShutdownListener) -> Self {
fn new(logging_delay: Duration, stats: SharedNodeStats, shutdown: TaskClient) -> Self {
PacketStatsConsoleLogger {
logging_delay,
stats,
@@ -451,7 +451,7 @@ impl Controller {
pub(crate) fn new(
logging_delay: Duration,
stats_updating_delay: Duration,
shutdown: ShutdownListener,
shutdown: TaskClient,
) -> Self {
let (sender, receiver) = mpsc::unbounded();
let shared_packet_data = CurrentPacketData::new();
@@ -503,13 +503,13 @@ impl Controller {
#[cfg(test)]
mod tests {
use super::*;
use task::ShutdownNotifier;
use nym_task::TaskManager;
#[tokio::test]
async fn node_stats_reported_are_received() {
let logging_delay = Duration::from_millis(20);
let stats_updating_delay = Duration::from_millis(10);
let shutdown = ShutdownNotifier::default();
let shutdown = TaskManager::default();
let node_stats_controller =
Controller::new(logging_delay, stats_updating_delay, shutdown.subscribe());
+13 -13
View File
@@ -4,15 +4,15 @@
use crate::node::node_statistics::UpdateSender;
use futures::channel::mpsc;
use futures::StreamExt;
use nymsphinx::params::packet_sizes::PacketSize;
use nonexhaustive_delayqueue::{Expired, NonExhaustiveDelayQueue};
use nymsphinx::forwarding::packet::MixPacket;
use nym_sphinx::params::packet_sizes::PacketSize;
use nym_nonexhaustive_delayqueue::{Expired, NonExhaustiveDelayQueue};
use nym_sphinx::forwarding::packet::MixPacket;
use std::io;
use tokio::time::Instant;
use tracing::*;
use tracing::{trace};
use super::ShutdownListener;
use super::TaskClient;
// Delay + MixPacket vs Instant + MixPacket
@@ -31,7 +31,7 @@ where
packet_sender: PacketDelayForwardSender,
packet_receiver: PacketDelayForwardReceiver,
node_stats_update_sender: UpdateSender,
shutdown: ShutdownListener,
shutdown: TaskClient,
}
impl<C> DelayForwarder<C>
@@ -41,7 +41,7 @@ where
pub(crate) fn new(
client: C,
node_stats_update_sender: UpdateSender,
shutdown: ShutdownListener,
shutdown: TaskClient,
) -> DelayForwarder<C> {
let (packet_sender, packet_receiver) = mpsc::unbounded();
@@ -139,13 +139,13 @@ mod tests {
use std::sync::{Arc, Mutex};
use std::time::Duration;
use task::ShutdownNotifier;
use nym_task::TaskManager;
use nymsphinx::addressing::nodes::NymNodeRoutingAddress;
use nymsphinx_params::packet_sizes::PacketSize;
use nymsphinx_params::PacketMode;
use nymsphinx_types::builder::SphinxPacketBuilder;
use nymsphinx_types::{
use nym_sphinx::addressing::nodes::NymNodeRoutingAddress;
use nym_sphinx_params::packet_sizes::PacketSize;
use nym_sphinx_params::PacketMode;
use nym_sphinx_types::builder::SphinxPacketBuilder;
use nym_sphinx_types::{
crypto, Delay as SphinxDelay, Destination, DestinationAddressBytes, Node, NodeAddressBytes,
SphinxPacket, DESTINATION_ADDRESS_LENGTH, IDENTIFIER_LENGTH, NODE_ADDRESS_LENGTH,
};
@@ -210,7 +210,7 @@ mod tests {
let node_stats_update_sender = UpdateSender::new(stats_sender);
let client = TestClient::default();
let client_packets_sent = client.packets_sent.clone();
let shutdown = ShutdownNotifier::default();
let shutdown = TaskManager::default();
let mut delay_forwarder =
DelayForwarder::new(client, node_stats_update_sender, shutdown.subscribe());
let packet_sender = delay_forwarder.sender();