mirror of
https://github.com/sigp/lighthouse.git
synced 2026-03-11 04:31:51 +00:00
237 lines
7.7 KiB
Rust
237 lines
7.7 KiB
Rust
#[macro_use]
|
|
extern crate clap;
|
|
|
|
use beacon_node::ProductionBeaconNode;
|
|
use clap::{App, Arg, ArgMatches};
|
|
use clap_utils;
|
|
use env_logger::{Builder, Env};
|
|
use environment::EnvironmentBuilder;
|
|
use eth2_testnet_config::HARDCODED_TESTNET;
|
|
use slog::{crit, info, warn};
|
|
use std::path::PathBuf;
|
|
use std::process::exit;
|
|
use types::EthSpec;
|
|
use validator_client::ProductionValidatorClient;
|
|
|
|
pub const DEFAULT_DATA_DIR: &str = ".lighthouse";
|
|
pub const CLIENT_CONFIG_FILENAME: &str = "beacon-node.toml";
|
|
pub const ETH2_CONFIG_FILENAME: &str = "eth2-spec.toml";
|
|
|
|
fn main() {
|
|
// Debugging output for libp2p and external crates.
|
|
Builder::from_env(Env::default()).init();
|
|
|
|
// Parse the CLI parameters.
|
|
let matches = App::new("Lighthouse")
|
|
.version(crate_version!())
|
|
.author("Sigma Prime <contact@sigmaprime.io>")
|
|
.about(
|
|
"Ethereum 2.0 client by Sigma Prime. Provides a full-featured beacon \
|
|
node, a validator client and utilities for managing validator accounts.",
|
|
)
|
|
.arg(
|
|
Arg::with_name("spec")
|
|
.short("s")
|
|
.long("spec")
|
|
.value_name("TITLE")
|
|
.help("Specifies the default eth2 spec type.")
|
|
.takes_value(true)
|
|
.possible_values(&["mainnet", "minimal", "interop"])
|
|
.global(true)
|
|
.default_value("mainnet"),
|
|
)
|
|
.arg(
|
|
Arg::with_name("logfile")
|
|
.long("logfile")
|
|
.value_name("FILE")
|
|
.help(
|
|
"File path where output will be written. Default file logging format is JSON.",
|
|
)
|
|
.takes_value(true),
|
|
)
|
|
.arg(
|
|
Arg::with_name("log-format")
|
|
.long("log-format")
|
|
.value_name("FORMAT")
|
|
.help("Specifies the format used for logging.")
|
|
.possible_values(&["JSON"])
|
|
.takes_value(true),
|
|
)
|
|
.arg(
|
|
Arg::with_name("debug-level")
|
|
.long("debug-level")
|
|
.value_name("LEVEL")
|
|
.help("The verbosity level for emitting logs.")
|
|
.takes_value(true)
|
|
.possible_values(&["info", "debug", "trace", "warn", "error", "crit"])
|
|
.default_value("info"),
|
|
)
|
|
.arg(
|
|
Arg::with_name("datadir")
|
|
.long("datadir")
|
|
.short("d")
|
|
.value_name("DIR")
|
|
.global(true)
|
|
.help("Data directory for lighthouse keys and databases.")
|
|
.takes_value(true),
|
|
)
|
|
.arg(
|
|
Arg::with_name("testnet-dir")
|
|
.short("t")
|
|
.long("testnet-dir")
|
|
.value_name("DIR")
|
|
.help(
|
|
"Path to directory containing eth2_testnet specs. Defaults to \
|
|
a hard-coded Lighthouse testnet. Only effective if there is no \
|
|
existing database.",
|
|
)
|
|
.takes_value(true)
|
|
.global(true),
|
|
)
|
|
.subcommand(beacon_node::cli_app())
|
|
.subcommand(validator_client::cli_app())
|
|
.subcommand(account_manager::cli_app())
|
|
.get_matches();
|
|
|
|
macro_rules! run_with_spec {
|
|
($env_builder: expr) => {
|
|
match run($env_builder, &matches) {
|
|
Ok(()) => exit(0),
|
|
Err(e) => {
|
|
println!("Failed to start Lighthouse: {}", e);
|
|
exit(1)
|
|
}
|
|
}
|
|
};
|
|
}
|
|
|
|
match matches.value_of("spec") {
|
|
Some("minimal") => run_with_spec!(EnvironmentBuilder::minimal()),
|
|
Some("mainnet") => run_with_spec!(EnvironmentBuilder::mainnet()),
|
|
Some("interop") => run_with_spec!(EnvironmentBuilder::interop()),
|
|
spec => {
|
|
// This path should be unreachable due to slog having a `default_value`
|
|
unreachable!("Unknown spec configuration: {:?}", spec);
|
|
}
|
|
}
|
|
}
|
|
|
|
fn run<E: EthSpec>(
|
|
environment_builder: EnvironmentBuilder<E>,
|
|
matches: &ArgMatches,
|
|
) -> Result<(), String> {
|
|
let debug_level = matches
|
|
.value_of("debug-level")
|
|
.ok_or_else(|| "Expected --debug-level flag".to_string())?;
|
|
|
|
let log_format = matches.value_of("log-format");
|
|
let eth2_testnet_config =
|
|
clap_utils::parse_testnet_dir_with_hardcoded_default(matches, "testnet-dir")?;
|
|
|
|
let mut environment = environment_builder
|
|
.async_logger(debug_level, log_format)?
|
|
.multi_threaded_tokio_runtime()?
|
|
.eth2_testnet_config(eth2_testnet_config)?
|
|
.build()?;
|
|
|
|
let log = environment.core_context().log;
|
|
|
|
if let Some(log_path) = matches.value_of("logfile") {
|
|
let path = log_path
|
|
.parse::<PathBuf>()
|
|
.map_err(|e| format!("Failed to parse log path: {:?}", e))?;
|
|
environment.log_to_json_file(path, debug_level, log_format)?;
|
|
}
|
|
|
|
if std::mem::size_of::<usize>() != 8 {
|
|
crit!(
|
|
log,
|
|
"Lighthouse only supports 64bit CPUs";
|
|
"detected" => format!("{}bit", std::mem::size_of::<usize>() * 8)
|
|
);
|
|
return Err("Invalid CPU architecture".into());
|
|
}
|
|
|
|
warn!(
|
|
log,
|
|
"Ethereum 2.0 is pre-release. This software is experimental."
|
|
);
|
|
|
|
if !matches.is_present("testnet-dir") {
|
|
info!(
|
|
log,
|
|
"Using default testnet";
|
|
"default" => HARDCODED_TESTNET
|
|
)
|
|
}
|
|
|
|
// Note: the current code technically allows for starting a beacon node _and_ a validator
|
|
// client at the same time.
|
|
//
|
|
// Whilst this is possible, the mutual-exclusivity of `clap` sub-commands prevents it from
|
|
// actually happening.
|
|
//
|
|
// Creating a command which can run both might be useful future works.
|
|
|
|
if let Some(sub_matches) = matches.subcommand_matches("account_manager") {
|
|
// Pass the entire `environment` to the account manager so it can run blocking operations.
|
|
account_manager::run(sub_matches, environment)?;
|
|
|
|
// Exit as soon as account manager returns control.
|
|
return Ok(());
|
|
};
|
|
|
|
let beacon_node = if let Some(sub_matches) = matches.subcommand_matches("beacon_node") {
|
|
let runtime_context = environment.core_context();
|
|
|
|
let beacon = environment
|
|
.runtime()
|
|
.block_on(ProductionBeaconNode::new_from_cli(
|
|
runtime_context,
|
|
sub_matches,
|
|
))
|
|
.map_err(|e| format!("Failed to start beacon node: {}", e))?;
|
|
|
|
Some(beacon)
|
|
} else {
|
|
None
|
|
};
|
|
|
|
let validator_client = if let Some(sub_matches) = matches.subcommand_matches("validator_client")
|
|
{
|
|
let runtime_context = environment.core_context();
|
|
|
|
let mut validator = environment
|
|
.runtime()
|
|
.block_on(ProductionValidatorClient::new_from_cli(
|
|
runtime_context,
|
|
sub_matches,
|
|
))
|
|
.map_err(|e| format!("Failed to init validator client: {}", e))?;
|
|
|
|
validator
|
|
.start_service()
|
|
.map_err(|e| format!("Failed to start validator client service: {}", e))?;
|
|
|
|
Some(validator)
|
|
} else {
|
|
None
|
|
};
|
|
|
|
if beacon_node.is_none() && validator_client.is_none() {
|
|
crit!(log, "No subcommand supplied. See --help .");
|
|
return Err("No subcommand supplied.".into());
|
|
}
|
|
|
|
// Block this thread until Crtl+C is pressed.
|
|
environment.block_until_ctrl_c()?;
|
|
|
|
info!(log, "Shutting down..");
|
|
|
|
drop(beacon_node);
|
|
drop(validator_client);
|
|
|
|
// Shutdown the environment once all tasks have completed.
|
|
Ok(environment.shutdown_on_idle())
|
|
}
|