190d3c4972
* 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
191 lines
6.5 KiB
Rust
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();
|
|
}
|