Move account manager under main binary (#601)
* Move account_manager under `lighthouse` binary * Unify logfile handling in `environment` crate.
This commit is contained in:
parent
24e941d175
commit
03e18ded86
@ -13,3 +13,4 @@ slog-async = "2.3.0"
|
|||||||
validator_client = { path = "../validator_client" }
|
validator_client = { path = "../validator_client" }
|
||||||
types = { path = "../eth2/types" }
|
types = { path = "../eth2/types" }
|
||||||
dirs = "2.0.2"
|
dirs = "2.0.2"
|
||||||
|
environment = { path = "../lighthouse/environment" }
|
||||||
|
54
account_manager/src/cli.rs
Normal file
54
account_manager/src/cli.rs
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
use clap::{App, Arg, SubCommand};
|
||||||
|
|
||||||
|
pub fn cli_app<'a, 'b>() -> App<'a, 'b> {
|
||||||
|
App::new("Account Manager")
|
||||||
|
.visible_aliases(&["am", "accounts", "accounts_manager"])
|
||||||
|
.version("0.0.1")
|
||||||
|
.author("Sigma Prime <contact@sigmaprime.io>")
|
||||||
|
.about("Eth 2.0 Accounts Manager")
|
||||||
|
.arg(
|
||||||
|
Arg::with_name("logfile")
|
||||||
|
.long("logfile")
|
||||||
|
.value_name("logfile")
|
||||||
|
.help("File path where output will be written.")
|
||||||
|
.takes_value(true),
|
||||||
|
)
|
||||||
|
.arg(
|
||||||
|
Arg::with_name("datadir")
|
||||||
|
.long("datadir")
|
||||||
|
.short("d")
|
||||||
|
.value_name("DIR")
|
||||||
|
.help("Data directory for keys and databases.")
|
||||||
|
.takes_value(true),
|
||||||
|
)
|
||||||
|
.subcommand(
|
||||||
|
SubCommand::with_name("generate")
|
||||||
|
.about("Generates a new validator private key")
|
||||||
|
.version("0.0.1")
|
||||||
|
.author("Sigma Prime <contact@sigmaprime.io>"),
|
||||||
|
)
|
||||||
|
.subcommand(
|
||||||
|
SubCommand::with_name("generate_deterministic")
|
||||||
|
.about("Generates a deterministic validator private key FOR TESTING")
|
||||||
|
.version("0.0.1")
|
||||||
|
.author("Sigma Prime <contact@sigmaprime.io>")
|
||||||
|
.arg(
|
||||||
|
Arg::with_name("validator index")
|
||||||
|
.long("index")
|
||||||
|
.short("i")
|
||||||
|
.value_name("index")
|
||||||
|
.help("The index of the validator, for which the test key is generated")
|
||||||
|
.takes_value(true)
|
||||||
|
.required(true),
|
||||||
|
)
|
||||||
|
.arg(
|
||||||
|
Arg::with_name("validator count")
|
||||||
|
.long("validator_count")
|
||||||
|
.short("n")
|
||||||
|
.value_name("validator_count")
|
||||||
|
.help("If supplied along with `index`, generates keys `i..i + n`.")
|
||||||
|
.takes_value(true)
|
||||||
|
.default_value("1"),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
@ -1,72 +1,21 @@
|
|||||||
|
mod cli;
|
||||||
|
|
||||||
use bls::Keypair;
|
use bls::Keypair;
|
||||||
use clap::{App, Arg, SubCommand};
|
use clap::ArgMatches;
|
||||||
use slog::{crit, debug, info, o, Drain};
|
use environment::RuntimeContext;
|
||||||
|
use slog::{crit, debug, info};
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use types::test_utils::generate_deterministic_keypair;
|
use types::{test_utils::generate_deterministic_keypair, EthSpec};
|
||||||
use validator_client::Config as ValidatorClientConfig;
|
use validator_client::Config as ValidatorClientConfig;
|
||||||
|
|
||||||
|
pub use cli::cli_app;
|
||||||
|
|
||||||
pub const DEFAULT_DATA_DIR: &str = ".lighthouse-validator";
|
pub const DEFAULT_DATA_DIR: &str = ".lighthouse-validator";
|
||||||
pub const CLIENT_CONFIG_FILENAME: &str = "account-manager.toml";
|
pub const CLIENT_CONFIG_FILENAME: &str = "account-manager.toml";
|
||||||
|
|
||||||
fn main() {
|
pub fn run<T: EthSpec>(matches: &ArgMatches, context: RuntimeContext<T>) {
|
||||||
// Logging
|
let mut log = context.log;
|
||||||
let decorator = slog_term::TermDecorator::new().build();
|
|
||||||
let drain = slog_term::CompactFormat::new(decorator).build().fuse();
|
|
||||||
let drain = slog_async::Async::new(drain).build().fuse();
|
|
||||||
let mut log = slog::Logger::root(drain, o!());
|
|
||||||
|
|
||||||
// CLI
|
|
||||||
let matches = App::new("Lighthouse Accounts Manager")
|
|
||||||
.version("0.0.1")
|
|
||||||
.author("Sigma Prime <contact@sigmaprime.io>")
|
|
||||||
.about("Eth 2.0 Accounts Manager")
|
|
||||||
.arg(
|
|
||||||
Arg::with_name("logfile")
|
|
||||||
.long("logfile")
|
|
||||||
.value_name("logfile")
|
|
||||||
.help("File path where output will be written.")
|
|
||||||
.takes_value(true),
|
|
||||||
)
|
|
||||||
.arg(
|
|
||||||
Arg::with_name("datadir")
|
|
||||||
.long("datadir")
|
|
||||||
.short("d")
|
|
||||||
.value_name("DIR")
|
|
||||||
.help("Data directory for keys and databases.")
|
|
||||||
.takes_value(true),
|
|
||||||
)
|
|
||||||
.subcommand(
|
|
||||||
SubCommand::with_name("generate")
|
|
||||||
.about("Generates a new validator private key")
|
|
||||||
.version("0.0.1")
|
|
||||||
.author("Sigma Prime <contact@sigmaprime.io>"),
|
|
||||||
)
|
|
||||||
.subcommand(
|
|
||||||
SubCommand::with_name("generate_deterministic")
|
|
||||||
.about("Generates a deterministic validator private key FOR TESTING")
|
|
||||||
.version("0.0.1")
|
|
||||||
.author("Sigma Prime <contact@sigmaprime.io>")
|
|
||||||
.arg(
|
|
||||||
Arg::with_name("validator index")
|
|
||||||
.long("index")
|
|
||||||
.short("i")
|
|
||||||
.value_name("index")
|
|
||||||
.help("The index of the validator, for which the test key is generated")
|
|
||||||
.takes_value(true)
|
|
||||||
.required(true),
|
|
||||||
)
|
|
||||||
.arg(
|
|
||||||
Arg::with_name("validator count")
|
|
||||||
.long("validator_count")
|
|
||||||
.short("n")
|
|
||||||
.value_name("validator_count")
|
|
||||||
.help("If supplied along with `index`, generates keys `i..i + n`.")
|
|
||||||
.takes_value(true)
|
|
||||||
.default_value("1"),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
.get_matches();
|
|
||||||
|
|
||||||
let data_dir = match matches
|
let data_dir = match matches
|
||||||
.value_of("datadir")
|
.value_of("datadir")
|
@ -27,7 +27,6 @@ error-chain = "0.12.1"
|
|||||||
serde_yaml = "0.8.11"
|
serde_yaml = "0.8.11"
|
||||||
slog = { version = "2.5.2", features = ["max_level_trace"] }
|
slog = { version = "2.5.2", features = ["max_level_trace"] }
|
||||||
slog-async = "2.3.0"
|
slog-async = "2.3.0"
|
||||||
slog-json = "2.3.0"
|
|
||||||
tokio = "0.1.22"
|
tokio = "0.1.22"
|
||||||
clap = "2.33.0"
|
clap = "2.33.0"
|
||||||
dirs = "2.0.2"
|
dirs = "2.0.2"
|
||||||
|
@ -1,10 +1,8 @@
|
|||||||
use clap::ArgMatches;
|
use clap::ArgMatches;
|
||||||
use network::NetworkConfig;
|
use network::NetworkConfig;
|
||||||
use serde_derive::{Deserialize, Serialize};
|
use serde_derive::{Deserialize, Serialize};
|
||||||
use slog::{info, o, Drain};
|
use std::fs;
|
||||||
use std::fs::{self, OpenOptions};
|
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::sync::Mutex;
|
|
||||||
|
|
||||||
/// The number initial validators when starting the `Minimal`.
|
/// The number initial validators when starting the `Minimal`.
|
||||||
const TESTNET_SPEC_CONSTANTS: &str = "minimal";
|
const TESTNET_SPEC_CONSTANTS: &str = "minimal";
|
||||||
@ -95,47 +93,11 @@ impl Config {
|
|||||||
Some(path)
|
Some(path)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update the logger to output in JSON to specified file
|
|
||||||
fn update_logger(&mut self, log: &mut slog::Logger) -> Result<(), &'static str> {
|
|
||||||
let file = OpenOptions::new()
|
|
||||||
.create(true)
|
|
||||||
.write(true)
|
|
||||||
.truncate(true)
|
|
||||||
.open(&self.log_file);
|
|
||||||
|
|
||||||
if file.is_err() {
|
|
||||||
return Err("Cannot open log file");
|
|
||||||
}
|
|
||||||
let file = file.unwrap();
|
|
||||||
|
|
||||||
if let Some(file) = self.log_file.to_str() {
|
|
||||||
info!(
|
|
||||||
*log,
|
|
||||||
"Log file specified, output will now be written to {} in json.", file
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
info!(
|
|
||||||
*log,
|
|
||||||
"Log file specified output will now be written in json"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
let drain = Mutex::new(slog_json::Json::default(file)).fuse();
|
|
||||||
let drain = slog_async::Async::new(drain).build().fuse();
|
|
||||||
*log = slog::Logger::root(drain, o!());
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Apply the following arguments to `self`, replacing values if they are specified in `args`.
|
/// Apply the following arguments to `self`, replacing values if they are specified in `args`.
|
||||||
///
|
///
|
||||||
/// Returns an error if arguments are obviously invalid. May succeed even if some values are
|
/// Returns an error if arguments are obviously invalid. May succeed even if some values are
|
||||||
/// invalid.
|
/// invalid.
|
||||||
pub fn apply_cli_args(
|
pub fn apply_cli_args(&mut self, args: &ArgMatches, _log: &slog::Logger) -> Result<(), String> {
|
||||||
&mut self,
|
|
||||||
args: &ArgMatches,
|
|
||||||
log: &mut slog::Logger,
|
|
||||||
) -> Result<(), String> {
|
|
||||||
if let Some(dir) = args.value_of("datadir") {
|
if let Some(dir) = args.value_of("datadir") {
|
||||||
self.data_dir = PathBuf::from(dir);
|
self.data_dir = PathBuf::from(dir);
|
||||||
};
|
};
|
||||||
@ -149,11 +111,6 @@ impl Config {
|
|||||||
self.rest_api.apply_cli_args(args)?;
|
self.rest_api.apply_cli_args(args)?;
|
||||||
self.websocket_server.apply_cli_args(args)?;
|
self.websocket_server.apply_cli_args(args)?;
|
||||||
|
|
||||||
if let Some(log_file) = args.value_of("logfile") {
|
|
||||||
self.log_file = PathBuf::from(log_file);
|
|
||||||
self.update_logger(log)?;
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,3 +18,4 @@ slog-async = "^2.3.0"
|
|||||||
environment = { path = "./environment" }
|
environment = { path = "./environment" }
|
||||||
futures = "0.1.25"
|
futures = "0.1.25"
|
||||||
validator_client = { "path" = "../validator_client" }
|
validator_client = { "path" = "../validator_client" }
|
||||||
|
account_manager = { "path" = "../account_manager" }
|
||||||
|
@ -17,3 +17,4 @@ slog-async = "^2.3.0"
|
|||||||
ctrlc = { version = "3.1.1", features = ["termination"] }
|
ctrlc = { version = "3.1.1", features = ["termination"] }
|
||||||
futures = "0.1.25"
|
futures = "0.1.25"
|
||||||
parking_lot = "0.7"
|
parking_lot = "0.7"
|
||||||
|
slog-json = "2.3.0"
|
||||||
|
@ -9,9 +9,12 @@
|
|||||||
|
|
||||||
use eth2_config::Eth2Config;
|
use eth2_config::Eth2Config;
|
||||||
use futures::{sync::oneshot, Future};
|
use futures::{sync::oneshot, Future};
|
||||||
use slog::{o, Drain, Level, Logger};
|
use slog::{info, o, Drain, Level, Logger};
|
||||||
use sloggers::{null::NullLoggerBuilder, Build};
|
use sloggers::{null::NullLoggerBuilder, Build};
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
|
use std::fs::OpenOptions;
|
||||||
|
use std::path::PathBuf;
|
||||||
|
use std::sync::Mutex;
|
||||||
use tokio::runtime::{Builder as RuntimeBuilder, Runtime, TaskExecutor};
|
use tokio::runtime::{Builder as RuntimeBuilder, Runtime, TaskExecutor};
|
||||||
use types::{EthSpec, InteropEthSpec, MainnetEthSpec, MinimalEthSpec};
|
use types::{EthSpec, InteropEthSpec, MainnetEthSpec, MinimalEthSpec};
|
||||||
|
|
||||||
@ -224,6 +227,28 @@ impl<E: EthSpec> Environment<E> {
|
|||||||
.map_err(|e| format!("Tokio runtime shutdown returned an error: {:?}", e))
|
.map_err(|e| format!("Tokio runtime shutdown returned an error: {:?}", e))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Sets the logger (and all child loggers) to log to a file.
|
||||||
|
pub fn log_to_json_file(&mut self, path: PathBuf) -> Result<(), String> {
|
||||||
|
let file = OpenOptions::new()
|
||||||
|
.create(true)
|
||||||
|
.write(true)
|
||||||
|
.truncate(true)
|
||||||
|
.open(&path)
|
||||||
|
.map_err(|e| format!("Unable to open logfile: {:?}", e))?;
|
||||||
|
|
||||||
|
let drain = Mutex::new(slog_json::Json::default(file)).fuse();
|
||||||
|
let drain = slog_async::Async::new(drain).build().fuse();
|
||||||
|
self.log = slog::Logger::root(drain, o!());
|
||||||
|
|
||||||
|
info!(
|
||||||
|
self.log,
|
||||||
|
"Logging to JSON file";
|
||||||
|
"path" => format!("{:?}", path)
|
||||||
|
);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
pub fn eth_spec_instance(&self) -> &E {
|
pub fn eth_spec_instance(&self) -> &E {
|
||||||
&self.eth_spec_instance
|
&self.eth_spec_instance
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,7 @@ use clap::{App, Arg, ArgMatches};
|
|||||||
use env_logger::{Builder, Env};
|
use env_logger::{Builder, Env};
|
||||||
use environment::EnvironmentBuilder;
|
use environment::EnvironmentBuilder;
|
||||||
use slog::{crit, info, warn};
|
use slog::{crit, info, warn};
|
||||||
|
use std::path::PathBuf;
|
||||||
use std::process::exit;
|
use std::process::exit;
|
||||||
use types::EthSpec;
|
use types::EthSpec;
|
||||||
use validator_client::ProductionValidatorClient;
|
use validator_client::ProductionValidatorClient;
|
||||||
@ -52,6 +53,7 @@ fn main() {
|
|||||||
)
|
)
|
||||||
.subcommand(beacon_node::cli_app())
|
.subcommand(beacon_node::cli_app())
|
||||||
.subcommand(validator_client::cli_app())
|
.subcommand(validator_client::cli_app())
|
||||||
|
.subcommand(account_manager::cli_app())
|
||||||
.get_matches();
|
.get_matches();
|
||||||
|
|
||||||
macro_rules! run_with_spec {
|
macro_rules! run_with_spec {
|
||||||
@ -92,6 +94,13 @@ fn run<E: EthSpec>(
|
|||||||
|
|
||||||
let log = environment.core_context().log;
|
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)?;
|
||||||
|
}
|
||||||
|
|
||||||
if std::mem::size_of::<usize>() != 8 {
|
if std::mem::size_of::<usize>() != 8 {
|
||||||
crit!(
|
crit!(
|
||||||
log,
|
log,
|
||||||
@ -114,6 +123,16 @@ fn run<E: EthSpec>(
|
|||||||
//
|
//
|
||||||
// Creating a command which can run both might be useful future works.
|
// Creating a command which can run both might be useful future works.
|
||||||
|
|
||||||
|
if let Some(sub_matches) = matches.subcommand_matches("Account Manager") {
|
||||||
|
let runtime_context = environment.core_context();
|
||||||
|
|
||||||
|
account_manager::run(sub_matches, runtime_context);
|
||||||
|
|
||||||
|
// Exit early if the account manager was run. It does not used the tokio executor, so no
|
||||||
|
// need to wait for it to shutdown.
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
let beacon_node = if let Some(sub_matches) = matches.subcommand_matches("Beacon Node") {
|
let beacon_node = if let Some(sub_matches) = matches.subcommand_matches("Beacon Node") {
|
||||||
let runtime_context = environment.core_context();
|
let runtime_context = environment.core_context();
|
||||||
|
|
||||||
|
@ -25,7 +25,6 @@ serde_derive = "1.0.102"
|
|||||||
serde_json = "1.0.41"
|
serde_json = "1.0.41"
|
||||||
slog = { version = "2.5.2", features = ["max_level_trace", "release_max_level_trace"] }
|
slog = { version = "2.5.2", features = ["max_level_trace", "release_max_level_trace"] }
|
||||||
slog-async = "2.3.0"
|
slog-async = "2.3.0"
|
||||||
slog-json = "2.3.0"
|
|
||||||
slog-term = "2.4.2"
|
slog-term = "2.4.2"
|
||||||
tokio = "0.1.22"
|
tokio = "0.1.22"
|
||||||
tokio-timer = "0.2.11"
|
tokio-timer = "0.2.11"
|
||||||
|
@ -2,12 +2,11 @@ use bincode;
|
|||||||
use bls::Keypair;
|
use bls::Keypair;
|
||||||
use clap::ArgMatches;
|
use clap::ArgMatches;
|
||||||
use serde_derive::{Deserialize, Serialize};
|
use serde_derive::{Deserialize, Serialize};
|
||||||
use slog::{error, info, o, warn, Drain};
|
use slog::{error, warn};
|
||||||
use std::fs::{self, File, OpenOptions};
|
use std::fs::{self, File};
|
||||||
use std::io::{Error, ErrorKind};
|
use std::io::{Error, ErrorKind};
|
||||||
use std::ops::Range;
|
use std::ops::Range;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::sync::Mutex;
|
|
||||||
use types::{
|
use types::{
|
||||||
test_utils::{generate_deterministic_keypair, load_keypairs_from_yaml},
|
test_utils::{generate_deterministic_keypair, load_keypairs_from_yaml},
|
||||||
EthSpec, MainnetEthSpec,
|
EthSpec, MainnetEthSpec,
|
||||||
@ -94,17 +93,12 @@ impl Config {
|
|||||||
pub fn apply_cli_args(
|
pub fn apply_cli_args(
|
||||||
&mut self,
|
&mut self,
|
||||||
args: &ArgMatches,
|
args: &ArgMatches,
|
||||||
log: &mut slog::Logger,
|
_log: &slog::Logger,
|
||||||
) -> Result<(), &'static str> {
|
) -> Result<(), &'static str> {
|
||||||
if let Some(datadir) = args.value_of("datadir") {
|
if let Some(datadir) = args.value_of("datadir") {
|
||||||
self.data_dir = PathBuf::from(datadir);
|
self.data_dir = PathBuf::from(datadir);
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(log_file) = args.value_of("logfile") {
|
|
||||||
self.log_file = PathBuf::from(log_file);
|
|
||||||
self.update_logger(log)?;
|
|
||||||
};
|
|
||||||
|
|
||||||
if let Some(srv) = args.value_of("server") {
|
if let Some(srv) = args.value_of("server") {
|
||||||
self.server = srv.to_string();
|
self.server = srv.to_string();
|
||||||
};
|
};
|
||||||
@ -112,38 +106,6 @@ impl Config {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update the logger to output in JSON to specified file
|
|
||||||
fn update_logger(&mut self, log: &mut slog::Logger) -> Result<(), &'static str> {
|
|
||||||
let file = OpenOptions::new()
|
|
||||||
.create(true)
|
|
||||||
.write(true)
|
|
||||||
.truncate(true)
|
|
||||||
.open(&self.log_file);
|
|
||||||
|
|
||||||
if file.is_err() {
|
|
||||||
return Err("Cannot open log file");
|
|
||||||
}
|
|
||||||
let file = file.unwrap();
|
|
||||||
|
|
||||||
if let Some(file) = self.log_file.to_str() {
|
|
||||||
info!(
|
|
||||||
*log,
|
|
||||||
"Log file specified, output will now be written to {} in json.", file
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
info!(
|
|
||||||
*log,
|
|
||||||
"Log file specified output will now be written in json"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
let drain = Mutex::new(slog_json::Json::default(file)).fuse();
|
|
||||||
let drain = slog_async::Async::new(drain).build().fuse();
|
|
||||||
*log = slog::Logger::root(drain, o!());
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Reads a single keypair from the given `path`.
|
/// Reads a single keypair from the given `path`.
|
||||||
///
|
///
|
||||||
/// `path` should be the path to a directory containing a private key. The file name of `path`
|
/// `path` should be the path to a directory containing a private key. The file name of `path`
|
||||||
|
Loading…
Reference in New Issue
Block a user