2019-03-20 05:24:28 +00:00
|
|
|
use bls::Keypair;
|
|
|
|
use clap::{App, Arg, SubCommand};
|
2019-06-09 08:34:56 +00:00
|
|
|
use slog::{crit, debug, info, o, Drain};
|
2019-07-01 06:38:42 +00:00
|
|
|
use std::fs;
|
2019-03-20 05:24:28 +00:00
|
|
|
use std::path::PathBuf;
|
2019-04-08 05:02:11 +00:00
|
|
|
use types::test_utils::generate_deterministic_keypair;
|
2019-04-08 05:18:40 +00:00
|
|
|
use validator_client::Config as ValidatorClientConfig;
|
2019-06-09 08:34:56 +00:00
|
|
|
|
2019-06-26 03:04:05 +00:00
|
|
|
pub const DEFAULT_DATA_DIR: &str = ".lighthouse-validator";
|
2019-06-13 16:20:22 +00:00
|
|
|
pub const CLIENT_CONFIG_FILENAME: &str = "account-manager.toml";
|
2019-03-20 05:24:28 +00:00
|
|
|
|
|
|
|
fn main() {
|
|
|
|
// Logging
|
|
|
|
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 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("datadir")
|
|
|
|
.long("datadir")
|
2019-06-09 08:34:56 +00:00
|
|
|
.short("d")
|
2019-03-20 05:24:28 +00:00
|
|
|
.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>"),
|
|
|
|
)
|
2019-04-08 05:02:11 +00:00
|
|
|
.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)
|
2019-04-08 05:18:40 +00:00
|
|
|
.required(true),
|
2019-05-28 04:32:32 +00:00
|
|
|
)
|
|
|
|
.arg(
|
2019-05-29 04:06:38 +00:00
|
|
|
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"),
|
2019-06-13 16:21:09 +00:00
|
|
|
),
|
2019-04-08 05:02:11 +00:00
|
|
|
)
|
2019-03-20 05:24:28 +00:00
|
|
|
.get_matches();
|
|
|
|
|
2019-07-02 07:32:14 +00:00
|
|
|
let data_dir = match matches
|
2019-07-01 06:38:42 +00:00
|
|
|
.value_of("datadir")
|
|
|
|
.and_then(|v| Some(PathBuf::from(v)))
|
2019-07-02 07:32:14 +00:00
|
|
|
{
|
|
|
|
Some(v) => v,
|
|
|
|
None => {
|
|
|
|
// use the default
|
|
|
|
let mut default_dir = match dirs::home_dir() {
|
|
|
|
Some(v) => v,
|
|
|
|
None => {
|
|
|
|
crit!(log, "Failed to find a home directory");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
default_dir.push(DEFAULT_DATA_DIR);
|
|
|
|
PathBuf::from(default_dir)
|
|
|
|
}
|
|
|
|
};
|
2019-07-01 06:38:42 +00:00
|
|
|
|
|
|
|
// create the directory if needed
|
|
|
|
match fs::create_dir_all(&data_dir) {
|
|
|
|
Ok(_) => {}
|
2019-06-09 08:34:56 +00:00
|
|
|
Err(e) => {
|
2019-07-01 06:38:42 +00:00
|
|
|
crit!(log, "Failed to initialize data dir"; "error" => format!("{}", e));
|
2019-06-13 16:21:09 +00:00
|
|
|
return;
|
2019-06-09 08:34:56 +00:00
|
|
|
}
|
2019-07-01 06:38:42 +00:00
|
|
|
}
|
2019-06-09 08:34:56 +00:00
|
|
|
|
|
|
|
let mut client_config = ValidatorClientConfig::default();
|
|
|
|
|
|
|
|
if let Err(e) = client_config.apply_cli_args(&matches) {
|
|
|
|
crit!(log, "Failed to apply CLI args"; "error" => format!("{:?}", e));
|
2019-06-13 16:21:09 +00:00
|
|
|
return;
|
2019-06-09 08:34:56 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
// Ensure the `data_dir` in the config matches that supplied to the CLI.
|
|
|
|
client_config.data_dir = data_dir.clone();
|
|
|
|
|
|
|
|
// Update the client config with any CLI args.
|
|
|
|
match client_config.apply_cli_args(&matches) {
|
|
|
|
Ok(()) => (),
|
|
|
|
Err(s) => {
|
|
|
|
crit!(log, "Failed to parse ClientConfig CLI arguments"; "error" => s);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
};
|
2019-03-20 05:24:28 +00:00
|
|
|
|
|
|
|
// Log configuration
|
|
|
|
info!(log, "";
|
2019-06-09 08:34:56 +00:00
|
|
|
"data_dir" => &client_config.data_dir.to_str());
|
2019-03-20 05:24:28 +00:00
|
|
|
|
|
|
|
match matches.subcommand() {
|
2019-06-09 08:34:56 +00:00
|
|
|
("generate", Some(_)) => generate_random(&client_config, &log),
|
2019-05-28 04:32:32 +00:00
|
|
|
("generate_deterministic", Some(m)) => {
|
|
|
|
if let Some(string) = m.value_of("validator index") {
|
|
|
|
let i: usize = string.parse().expect("Invalid validator index");
|
2019-05-29 04:06:38 +00:00
|
|
|
if let Some(string) = m.value_of("validator count") {
|
|
|
|
let n: usize = string.parse().expect("Invalid end validator count");
|
2019-05-28 04:32:32 +00:00
|
|
|
|
2019-05-29 04:06:38 +00:00
|
|
|
let indices: Vec<usize> = (i..i + n).collect();
|
2019-06-09 08:34:56 +00:00
|
|
|
generate_deterministic_multiple(&indices, &client_config, &log)
|
2019-05-28 04:32:32 +00:00
|
|
|
} else {
|
2019-06-09 08:34:56 +00:00
|
|
|
generate_deterministic(i, &client_config, &log)
|
2019-05-28 04:32:32 +00:00
|
|
|
}
|
|
|
|
}
|
2019-04-08 05:18:40 +00:00
|
|
|
}
|
2019-03-20 05:24:28 +00:00
|
|
|
_ => panic!(
|
|
|
|
"The account manager must be run with a subcommand. See help for more information."
|
|
|
|
),
|
|
|
|
}
|
|
|
|
}
|
2019-05-28 04:32:32 +00:00
|
|
|
|
|
|
|
fn generate_random(config: &ValidatorClientConfig, log: &slog::Logger) {
|
|
|
|
save_key(&Keypair::random(), config, log)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn generate_deterministic_multiple(
|
|
|
|
validator_indices: &[usize],
|
|
|
|
config: &ValidatorClientConfig,
|
|
|
|
log: &slog::Logger,
|
|
|
|
) {
|
|
|
|
for validator_index in validator_indices {
|
|
|
|
generate_deterministic(*validator_index, config, log)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn generate_deterministic(
|
|
|
|
validator_index: usize,
|
|
|
|
config: &ValidatorClientConfig,
|
|
|
|
log: &slog::Logger,
|
|
|
|
) {
|
|
|
|
save_key(
|
|
|
|
&generate_deterministic_keypair(validator_index),
|
|
|
|
config,
|
|
|
|
log,
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn save_key(keypair: &Keypair, config: &ValidatorClientConfig, log: &slog::Logger) {
|
|
|
|
let key_path: PathBuf = config
|
|
|
|
.save_key(&keypair)
|
|
|
|
.expect("Unable to save newly generated private key.");
|
|
|
|
debug!(
|
|
|
|
log,
|
|
|
|
"Keypair generated {:?}, saved to: {:?}",
|
|
|
|
keypair.identifier(),
|
|
|
|
key_path.to_string_lossy()
|
|
|
|
);
|
|
|
|
}
|