Files
nym/mixnode/src/commands/run.rs
T
Dave Hrycyszyn 190d3c4972 Feature/add node description api (#605)
* Starting to build out node descriptions

* Renamed the mod to node_description instead of descriptor

* Returning results loaded from file

* Taking user input for node describe command

* Readline without new dependencies

* Adding input format hint

* Making sure the node can still start even when the descriptor file isn't there yet

* Adding some additional runtime checks

* Removing -dev from minimum node version

* Removing initial :: on serde

* Fixing comment on the /description endpoint

* Swapped json for toml

* Being a bit more specific with my startup message.

* Cleaning up path building

* Nicer runtime checks

* Put path building inside the file methods
2021-05-19 14:25:11 +01:00

191 lines
6.5 KiB
Rust

// Copyright 2020 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::commands::override_config;
use crate::config::{persistence::pathfinder::MixNodePathfinder, Config};
use crate::node::node_description::NodeDescription;
use crate::node::MixNode;
use clap::{App, Arg, ArgMatches};
use config::NymConfig;
use crypto::asymmetric::{encryption, identity};
use log::warn;
use version_checker::is_minor_version_compatible;
pub fn command_args<'a, 'b>() -> App<'a, 'b> {
App::new("run")
.about("Starts the mixnode")
.arg(
Arg::with_name("id")
.long("id")
.help("Id of the nym-mixnode we want to run")
.takes_value(true)
.required(true),
)
// the rest of arguments are optional, they are used to override settings in config file
.arg(
Arg::with_name("layer")
.long("layer")
.help("The mixnet layer of this particular node")
.takes_value(true),
)
.arg(
Arg::with_name("host")
.long("host")
.help("The custom host on which the mixnode will be running")
.takes_value(true),
)
.arg(
Arg::with_name("port")
.long("port")
.help("The port on which the mixnode will be listening")
.takes_value(true),
)
.arg(
Arg::with_name("announce-host")
.long("announce-host")
.help("The host that will be reported to the directory server")
.takes_value(true),
)
.arg(
Arg::with_name("announce-port")
.long("announce-port")
.help("The port that will be reported to the directory server")
.takes_value(true),
)
.arg(
Arg::with_name("validators")
.long("validators")
.help("Comma separated list of rest endpoints of the validators")
.takes_value(true),
)
.arg(
Arg::with_name("mixnet-contract")
.long("mixnet-contract")
.help("Address of the validator contract managing the network")
.takes_value(true),
)
.arg(
Arg::with_name("metrics-server")
.long("metrics-server")
.help("Server to which the node is sending all metrics data")
.takes_value(true),
)
}
fn show_binding_warning(address: String) {
println!("\n##### NOTE #####");
println!(
"\nYou are trying to bind to {} - 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
);
println!("\n\n");
}
fn special_addresses() -> Vec<&'static str> {
vec!["localhost", "127.0.0.1", "0.0.0.0", "::1", "[::1]"]
}
fn load_identity_keys(pathfinder: &MixNodePathfinder) -> identity::KeyPair {
let identity_keypair: identity::KeyPair = pemstore::load_keypair(&pemstore::KeyPairPath::new(
pathfinder.private_identity_key().to_owned(),
pathfinder.public_identity_key().to_owned(),
))
.expect("Failed to read stored identity key files");
identity_keypair
}
fn load_sphinx_keys(pathfinder: &MixNodePathfinder) -> encryption::KeyPair {
let sphinx_keypair: encryption::KeyPair = pemstore::load_keypair(&pemstore::KeyPairPath::new(
pathfinder.private_encryption_key().to_owned(),
pathfinder.public_encryption_key().to_owned(),
))
.expect("Failed to read stored sphinx key files");
sphinx_keypair
}
// this only checks compatibility between config the binary. It does not take into consideration
// network version. It might do so in the future.
fn version_check(cfg: &Config) -> bool {
let binary_version = env!("CARGO_PKG_VERSION");
let config_version = cfg.get_version();
if binary_version != config_version {
warn!("The mixnode binary has different version than what is specified in config file! {} and {}", binary_version, config_version);
if is_minor_version_compatible(binary_version, config_version) {
info!("but they are still semver compatible. However, consider running the `upgrade` command");
true
} else {
error!("and they are semver incompatible! - please run the `upgrade` command before attempting `run` again");
false
}
} else {
true
}
}
pub fn execute(matches: &ArgMatches) {
let id = matches.value_of("id").unwrap();
println!("Starting mixnode {}...", id);
let mut config = match Config::load_from_file(id) {
Ok(cfg) => cfg,
Err(err) => {
error!("Failed to load config for {}. Are you sure you have run `init` before? (Error was: {})", id, err);
return;
}
};
config = override_config(config, matches);
if !version_check(&config) {
error!("failed the local version check");
return;
}
let pathfinder = MixNodePathfinder::new_from_config(&config);
let identity_keypair = load_identity_keys(&pathfinder);
let sphinx_keypair = load_sphinx_keys(&pathfinder);
let listening_ip_string = config.get_listening_address().ip().to_string();
if special_addresses().contains(&listening_ip_string.as_ref()) {
show_binding_warning(listening_ip_string);
}
println!(
"Validator servers: {:?}",
config.get_validator_rest_endpoints()
);
println!("Metrics server: {}", config.get_metrics_server());
println!(
"Listening for incoming packets on {}",
config.get_listening_address()
);
println!(
"Announcing the following socket address: {}",
config.get_announce_address()
);
println!(
"\nTo bond your mixnode, go to https://web-wallet-finney.nymtech.net/. You will need to provide the following:
Identity key: {}
Sphinx key: {}
Host: {}
Layer: {}
Location: [physical location of your node's server]
Version: {}
",
identity_keypair.public_key().to_base58_string(),
sphinx_keypair.public_key().to_base58_string(),
config.get_announce_address(),
config.get_layer(),
config.get_version(),
);
let description =
NodeDescription::load_from_file(Config::default_config_directory(id)).unwrap_or_default();
MixNode::new(config, description, identity_keypair, sphinx_keypair).run();
}