Add eth2_config crate, integrate into val client

This commit is contained in:
Paul Hauner
2019-06-08 20:21:50 -04:00
parent eb23b003b4
commit 3487b16ce5
13 changed files with 366 additions and 129 deletions

View File

@@ -6,6 +6,7 @@ edition = "2018"
[dependencies]
dirs = "1.0.3"
eth2_config = { path = "../eth2/utils/eth2_config" }
types = { path = "../eth2/types" }
toml = "^0.5"
store = { path = "./store" }

View File

@@ -14,6 +14,7 @@ fork_choice = { path = "../../eth2/fork_choice" }
prometheus = "^0.6"
types = { path = "../../eth2/types" }
tree_hash = { path = "../../eth2/utils/tree_hash" }
eth2_config = { path = "../../eth2/utils/eth2_config" }
slot_clock = { path = "../../eth2/utils/slot_clock" }
serde = "1.0"
serde_derive = "1.0"

View File

@@ -8,7 +8,7 @@ use std::path::PathBuf;
/// The core configuration of a Lighthouse beacon node.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ClientConfig {
pub data_dir: String,
pub data_dir: PathBuf,
pub db_type: String,
db_name: String,
pub network: network::NetworkConfig,
@@ -19,7 +19,7 @@ pub struct ClientConfig {
impl Default for ClientConfig {
fn default() -> Self {
Self {
data_dir: ".lighthouse".to_string(),
data_dir: PathBuf::from(".lighthouse"),
db_type: "disk".to_string(),
db_name: "chain_db".to_string(),
// Note: there are no default bootnodes specified.
@@ -51,7 +51,7 @@ impl ClientConfig {
/// invalid.
pub fn apply_cli_args(&mut self, args: &ArgMatches) -> Result<(), &'static str> {
if let Some(dir) = args.value_of("datadir") {
self.data_dir = dir.to_string();
self.data_dir = PathBuf::from(dir);
};
if let Some(dir) = args.value_of("db") {

View File

@@ -1,64 +0,0 @@
use clap::ArgMatches;
use serde_derive::{Deserialize, Serialize};
use std::time::SystemTime;
use types::ChainSpec;
/// The core configuration of a Lighthouse beacon node.
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(default)]
pub struct Eth2Config {
pub spec_constants: String,
pub spec: ChainSpec,
}
impl Default for Eth2Config {
fn default() -> Self {
Self {
spec_constants: "minimal".to_string(),
spec: ChainSpec::minimal(),
}
}
}
impl Eth2Config {
pub fn mainnet() -> Self {
Self {
spec_constants: "mainnet".to_string(),
spec: ChainSpec::mainnet(),
}
}
pub fn minimal() -> Self {
Self {
spec_constants: "minimal".to_string(),
spec: ChainSpec::minimal(),
}
}
}
impl Eth2Config {
/// 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
/// invalid.
pub fn apply_cli_args(&mut self, args: &ArgMatches) -> Result<(), &'static str> {
if args.is_present("recent_genesis") {
self.spec.genesis_time = recent_genesis_time()
}
Ok(())
}
}
/// Returns the system time, mod 30 minutes.
///
/// Used for easily creating testnets.
fn recent_genesis_time() -> u64 {
let now = SystemTime::now()
.duration_since(SystemTime::UNIX_EPOCH)
.unwrap()
.as_secs();
let secs_after_last_period = now.checked_rem(30 * 60).unwrap_or(0);
// genesis is now the last 30 minute block.
now - secs_after_last_period
}

View File

@@ -3,7 +3,6 @@ extern crate slog;
mod beacon_chain_types;
mod client_config;
pub mod error;
mod eth2_config;
pub mod notifier;
use beacon_chain::BeaconChain;

View File

@@ -2,12 +2,12 @@ extern crate slog;
mod run;
use clap::{App, Arg};
use clap::{App, Arg, ArgMatches};
use client::{ClientConfig, Eth2Config};
use eth2_config::{read_from_file, write_to_file};
use slog::{crit, o, Drain};
use std::fs;
use std::fs::File;
use std::io::prelude::*;
use std::path::PathBuf;
pub const DEFAULT_DATA_DIR: &str = ".lighthouse";
@@ -105,7 +105,8 @@ fn main() {
Arg::with_name("spec-constants")
.long("spec-constants")
.value_name("TITLE")
.help("The title of the spec constants for chain config..")
.short("s")
.help("The title of the spec constants for chain config.")
.takes_value(true)
.possible_values(&["mainnet", "minimal"])
.default_value("minimal"),
@@ -113,34 +114,44 @@ fn main() {
.arg(
Arg::with_name("recent-genesis")
.long("recent-genesis")
.short("r")
.help("When present, genesis will be within 30 minutes prior. Only for testing"),
)
.get_matches();
// Attempt to lead the `ClientConfig` from disk. If it fails, write
let mut client_config = match read_from_file::<ClientConfig>(
matches.value_of("data_dir"),
CLIENT_CONFIG_FILENAME,
) {
let data_dir = match get_data_dir(&matches) {
Ok(dir) => dir,
Err(e) => {
crit!(logger, "Failed to initialize data dir"; "error" => format!("{:?}", e));
return;
}
};
let client_config_path = data_dir.join(CLIENT_CONFIG_FILENAME);
// Attempt to lead the `ClientConfig` from disk.
//
// If file doesn't exist, create a new, default one.
let mut client_config = match read_from_file::<ClientConfig>(client_config_path.clone()) {
Ok(Some(c)) => c,
Ok(None) => {
let default = ClientConfig::default();
if let Err(e) = write_to_file(matches.value_of("data_dir"), CLIENT_CONFIG_FILENAME, &default) {
if let Err(e) = write_to_file(client_config_path, &default) {
crit!(logger, "Failed to write default ClientConfig to file"; "error" => format!("{:?}", e));
return;
}
default
},
}
Err(e) => {
crit!(logger, "Failed to load a ChainConfig file"; "error" => format!("{:?}", e));
return;
}
};
if let Some(data_dir) = matches.value_of("data_dir") {
client_config.data_dir = data_dir.to_string();
}
// 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) => {
@@ -149,10 +160,12 @@ fn main() {
}
};
let mut eth2_config = match read_from_file::<Eth2Config>(
matches.value_of("data_dir"),
ETH2_CONFIG_FILENAME,
) {
let eth2_config_path = data_dir.join(ETH2_CONFIG_FILENAME);
// Attempt to load the `Eth2Config` from file.
//
// If the file doesn't exist, create a default one depending on the CLI flags.
let mut eth2_config = match read_from_file::<Eth2Config>(eth2_config_path.clone()) {
Ok(Some(c)) => c,
Ok(None) => {
let default = match matches.value_of("spec-constants") {
@@ -160,7 +173,7 @@ fn main() {
Some("minimal") => Eth2Config::minimal(),
_ => unreachable!(), // Guarded by slog.
};
if let Err(e) = write_to_file(matches.value_of("data_dir"), ETH2_CONFIG_FILENAME, &default) {
if let Err(e) = write_to_file(eth2_config_path, &default) {
crit!(logger, "Failed to write default Eth2Config to file"; "error" => format!("{:?}", e));
return;
}
@@ -172,6 +185,7 @@ fn main() {
}
};
// Update the eth2 config with any CLI flags.
match eth2_config.apply_cli_args(&matches) {
Ok(()) => (),
Err(s) => {
@@ -186,59 +200,14 @@ fn main() {
}
}
/// Write a configuration to file.
fn write_to_file<T>(data_dir: Option<&str>, config_filename: &str, config: &T) -> Result<(), String>
where
T: Default + serde::de::DeserializeOwned + serde::Serialize,
{
let data_dir = data_dir.unwrap_or_else(|| DEFAULT_DATA_DIR);
let path = dirs::home_dir()
.ok_or_else(|| "Unable to locate home directory")?
.join(&data_dir);
fs::create_dir_all(&path).map_err(|_| "Unable to open data_dir")?;
if let Ok(mut file) = File::create(path.join(config_filename)) {
let toml_encoded = toml::to_string(&config).map_err(|e| {
format!(
"Failed to write configuration to {}. Error: {:?}",
config_filename, e
)
})?;
file.write_all(toml_encoded.as_bytes())
.expect(&format!("Unable to write to {}", config_filename));
}
Ok(())
}
/// Loads a `ClientConfig` from file. If unable to load from file, generates a default
/// configuration and saves that as a sample file.
fn read_from_file<T>(data_dir: Option<&str>, config_filename: &str) -> Result<Option<T>, String>
where
T: Default + serde::de::DeserializeOwned + serde::Serialize,
{
let data_dir = data_dir.unwrap_or_else(|| DEFAULT_DATA_DIR);
let path = dirs::home_dir()
.ok_or_else(|| "Unable to locate home directory")?
.join(&data_dir);
fs::create_dir_all(&path).map_err(|_| "Unable to open data_dir")?;
if let Ok(mut file) = File::open(path.join(config_filename)) {
let mut contents = String::new();
file.read_to_string(&mut contents).map_err(|e| {
format!(
"Unable to read existing {}. Error: {:?}",
config_filename, e
)
})?;
let config = toml::from_str(&contents)
.map_err(|e| format!("Unable to parse {}: {:?}", config_filename, e))?;
Ok(Some(config))
fn get_data_dir(args: &ArgMatches) -> Result<PathBuf, &'static str> {
if let Some(data_dir) = args.value_of("data_dir") {
Ok(PathBuf::from(data_dir))
} else {
Ok(None)
let path = dirs::home_dir()
.ok_or_else(|| "Unable to locate home directory")?
.join(&DEFAULT_DATA_DIR);
fs::create_dir_all(&path).map_err(|_| "Unable to create data_dir")?;
Ok(path)
}
}