Add eth2_config
crate, integrate into val client
This commit is contained in:
parent
eb23b003b4
commit
3487b16ce5
@ -9,6 +9,7 @@ members = [
|
|||||||
"eth2/utils/cached_tree_hash",
|
"eth2/utils/cached_tree_hash",
|
||||||
"eth2/utils/compare_fields",
|
"eth2/utils/compare_fields",
|
||||||
"eth2/utils/compare_fields_derive",
|
"eth2/utils/compare_fields_derive",
|
||||||
|
"eth2/utils/eth2_config",
|
||||||
"eth2/utils/fixed_len_vec",
|
"eth2/utils/fixed_len_vec",
|
||||||
"eth2/utils/hashing",
|
"eth2/utils/hashing",
|
||||||
"eth2/utils/honey-badger-split",
|
"eth2/utils/honey-badger-split",
|
||||||
|
@ -6,6 +6,7 @@ edition = "2018"
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
dirs = "1.0.3"
|
dirs = "1.0.3"
|
||||||
|
eth2_config = { path = "../eth2/utils/eth2_config" }
|
||||||
types = { path = "../eth2/types" }
|
types = { path = "../eth2/types" }
|
||||||
toml = "^0.5"
|
toml = "^0.5"
|
||||||
store = { path = "./store" }
|
store = { path = "./store" }
|
||||||
|
@ -14,6 +14,7 @@ fork_choice = { path = "../../eth2/fork_choice" }
|
|||||||
prometheus = "^0.6"
|
prometheus = "^0.6"
|
||||||
types = { path = "../../eth2/types" }
|
types = { path = "../../eth2/types" }
|
||||||
tree_hash = { path = "../../eth2/utils/tree_hash" }
|
tree_hash = { path = "../../eth2/utils/tree_hash" }
|
||||||
|
eth2_config = { path = "../../eth2/utils/eth2_config" }
|
||||||
slot_clock = { path = "../../eth2/utils/slot_clock" }
|
slot_clock = { path = "../../eth2/utils/slot_clock" }
|
||||||
serde = "1.0"
|
serde = "1.0"
|
||||||
serde_derive = "1.0"
|
serde_derive = "1.0"
|
||||||
|
@ -8,7 +8,7 @@ use std::path::PathBuf;
|
|||||||
/// The core configuration of a Lighthouse beacon node.
|
/// The core configuration of a Lighthouse beacon node.
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub struct ClientConfig {
|
pub struct ClientConfig {
|
||||||
pub data_dir: String,
|
pub data_dir: PathBuf,
|
||||||
pub db_type: String,
|
pub db_type: String,
|
||||||
db_name: String,
|
db_name: String,
|
||||||
pub network: network::NetworkConfig,
|
pub network: network::NetworkConfig,
|
||||||
@ -19,7 +19,7 @@ pub struct ClientConfig {
|
|||||||
impl Default for ClientConfig {
|
impl Default for ClientConfig {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
data_dir: ".lighthouse".to_string(),
|
data_dir: PathBuf::from(".lighthouse"),
|
||||||
db_type: "disk".to_string(),
|
db_type: "disk".to_string(),
|
||||||
db_name: "chain_db".to_string(),
|
db_name: "chain_db".to_string(),
|
||||||
// Note: there are no default bootnodes specified.
|
// Note: there are no default bootnodes specified.
|
||||||
@ -51,7 +51,7 @@ impl ClientConfig {
|
|||||||
/// invalid.
|
/// invalid.
|
||||||
pub fn apply_cli_args(&mut self, args: &ArgMatches) -> Result<(), &'static str> {
|
pub fn apply_cli_args(&mut self, args: &ArgMatches) -> Result<(), &'static str> {
|
||||||
if let Some(dir) = args.value_of("datadir") {
|
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") {
|
if let Some(dir) = args.value_of("db") {
|
||||||
|
@ -3,7 +3,6 @@ extern crate slog;
|
|||||||
mod beacon_chain_types;
|
mod beacon_chain_types;
|
||||||
mod client_config;
|
mod client_config;
|
||||||
pub mod error;
|
pub mod error;
|
||||||
mod eth2_config;
|
|
||||||
pub mod notifier;
|
pub mod notifier;
|
||||||
|
|
||||||
use beacon_chain::BeaconChain;
|
use beacon_chain::BeaconChain;
|
||||||
|
@ -2,12 +2,12 @@ extern crate slog;
|
|||||||
|
|
||||||
mod run;
|
mod run;
|
||||||
|
|
||||||
use clap::{App, Arg};
|
use clap::{App, Arg, ArgMatches};
|
||||||
use client::{ClientConfig, Eth2Config};
|
use client::{ClientConfig, Eth2Config};
|
||||||
|
use eth2_config::{read_from_file, write_to_file};
|
||||||
use slog::{crit, o, Drain};
|
use slog::{crit, o, Drain};
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::fs::File;
|
use std::path::PathBuf;
|
||||||
use std::io::prelude::*;
|
|
||||||
|
|
||||||
pub const DEFAULT_DATA_DIR: &str = ".lighthouse";
|
pub const DEFAULT_DATA_DIR: &str = ".lighthouse";
|
||||||
|
|
||||||
@ -105,7 +105,8 @@ fn main() {
|
|||||||
Arg::with_name("spec-constants")
|
Arg::with_name("spec-constants")
|
||||||
.long("spec-constants")
|
.long("spec-constants")
|
||||||
.value_name("TITLE")
|
.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)
|
.takes_value(true)
|
||||||
.possible_values(&["mainnet", "minimal"])
|
.possible_values(&["mainnet", "minimal"])
|
||||||
.default_value("minimal"),
|
.default_value("minimal"),
|
||||||
@ -113,34 +114,44 @@ fn main() {
|
|||||||
.arg(
|
.arg(
|
||||||
Arg::with_name("recent-genesis")
|
Arg::with_name("recent-genesis")
|
||||||
.long("recent-genesis")
|
.long("recent-genesis")
|
||||||
|
.short("r")
|
||||||
.help("When present, genesis will be within 30 minutes prior. Only for testing"),
|
.help("When present, genesis will be within 30 minutes prior. Only for testing"),
|
||||||
)
|
)
|
||||||
.get_matches();
|
.get_matches();
|
||||||
|
|
||||||
// Attempt to lead the `ClientConfig` from disk. If it fails, write
|
let data_dir = match get_data_dir(&matches) {
|
||||||
let mut client_config = match read_from_file::<ClientConfig>(
|
Ok(dir) => dir,
|
||||||
matches.value_of("data_dir"),
|
Err(e) => {
|
||||||
CLIENT_CONFIG_FILENAME,
|
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(Some(c)) => c,
|
||||||
Ok(None) => {
|
Ok(None) => {
|
||||||
let default = ClientConfig::default();
|
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));
|
crit!(logger, "Failed to write default ClientConfig to file"; "error" => format!("{:?}", e));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
default
|
default
|
||||||
},
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
crit!(logger, "Failed to load a ChainConfig file"; "error" => format!("{:?}", e));
|
crit!(logger, "Failed to load a ChainConfig file"; "error" => format!("{:?}", e));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(data_dir) = matches.value_of("data_dir") {
|
// Ensure the `data_dir` in the config matches that supplied to the CLI.
|
||||||
client_config.data_dir = data_dir.to_string();
|
client_config.data_dir = data_dir.clone();
|
||||||
}
|
|
||||||
|
|
||||||
|
// Update the client config with any CLI args.
|
||||||
match client_config.apply_cli_args(&matches) {
|
match client_config.apply_cli_args(&matches) {
|
||||||
Ok(()) => (),
|
Ok(()) => (),
|
||||||
Err(s) => {
|
Err(s) => {
|
||||||
@ -149,10 +160,12 @@ fn main() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut eth2_config = match read_from_file::<Eth2Config>(
|
let eth2_config_path = data_dir.join(ETH2_CONFIG_FILENAME);
|
||||||
matches.value_of("data_dir"),
|
|
||||||
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(Some(c)) => c,
|
||||||
Ok(None) => {
|
Ok(None) => {
|
||||||
let default = match matches.value_of("spec-constants") {
|
let default = match matches.value_of("spec-constants") {
|
||||||
@ -160,7 +173,7 @@ fn main() {
|
|||||||
Some("minimal") => Eth2Config::minimal(),
|
Some("minimal") => Eth2Config::minimal(),
|
||||||
_ => unreachable!(), // Guarded by slog.
|
_ => 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));
|
crit!(logger, "Failed to write default Eth2Config to file"; "error" => format!("{:?}", e));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -172,6 +185,7 @@ fn main() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Update the eth2 config with any CLI flags.
|
||||||
match eth2_config.apply_cli_args(&matches) {
|
match eth2_config.apply_cli_args(&matches) {
|
||||||
Ok(()) => (),
|
Ok(()) => (),
|
||||||
Err(s) => {
|
Err(s) => {
|
||||||
@ -186,59 +200,14 @@ fn main() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Write a configuration to file.
|
fn get_data_dir(args: &ArgMatches) -> Result<PathBuf, &'static str> {
|
||||||
fn write_to_file<T>(data_dir: Option<&str>, config_filename: &str, config: &T) -> Result<(), String>
|
if let Some(data_dir) = args.value_of("data_dir") {
|
||||||
where
|
Ok(PathBuf::from(data_dir))
|
||||||
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))
|
|
||||||
} else {
|
} 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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
13
eth2/utils/eth2_config/Cargo.toml
Normal file
13
eth2/utils/eth2_config/Cargo.toml
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
[package]
|
||||||
|
name = "eth2_config"
|
||||||
|
version = "0.1.0"
|
||||||
|
authors = ["Paul Hauner <paul@paulhauner.com>"]
|
||||||
|
edition = "2018"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
clap = "2.32.0"
|
||||||
|
dirs = "1.0.3"
|
||||||
|
serde = "1.0"
|
||||||
|
serde_derive = "1.0"
|
||||||
|
toml = "^0.5"
|
||||||
|
types = { path = "../../types" }
|
@ -1,5 +1,8 @@
|
|||||||
use clap::ArgMatches;
|
use clap::ArgMatches;
|
||||||
use serde_derive::{Deserialize, Serialize};
|
use serde_derive::{Deserialize, Serialize};
|
||||||
|
use std::fs::File;
|
||||||
|
use std::io::prelude::*;
|
||||||
|
use std::path::PathBuf;
|
||||||
use std::time::SystemTime;
|
use std::time::SystemTime;
|
||||||
use types::ChainSpec;
|
use types::ChainSpec;
|
||||||
|
|
||||||
@ -42,7 +45,7 @@ impl Eth2Config {
|
|||||||
/// 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(&mut self, args: &ArgMatches) -> Result<(), &'static str> {
|
pub fn apply_cli_args(&mut self, args: &ArgMatches) -> Result<(), &'static str> {
|
||||||
if args.is_present("recent_genesis") {
|
if args.is_present("recent-genesis") {
|
||||||
self.spec.genesis_time = recent_genesis_time()
|
self.spec.genesis_time = recent_genesis_time()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -62,3 +65,42 @@ fn recent_genesis_time() -> u64 {
|
|||||||
// genesis is now the last 30 minute block.
|
// genesis is now the last 30 minute block.
|
||||||
now - secs_after_last_period
|
now - secs_after_last_period
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Write a configuration to file.
|
||||||
|
pub fn write_to_file<T>(path: PathBuf, config: &T) -> Result<(), String>
|
||||||
|
where
|
||||||
|
T: Default + serde::de::DeserializeOwned + serde::Serialize,
|
||||||
|
{
|
||||||
|
if let Ok(mut file) = File::create(path.clone()) {
|
||||||
|
let toml_encoded = toml::to_string(&config).map_err(|e| {
|
||||||
|
format!(
|
||||||
|
"Failed to write configuration to {:?}. Error: {:?}",
|
||||||
|
path, e
|
||||||
|
)
|
||||||
|
})?;
|
||||||
|
file.write_all(toml_encoded.as_bytes())
|
||||||
|
.expect(&format!("Unable to write to {:?}", path));
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Loads a `ClientConfig` from file. If unable to load from file, generates a default
|
||||||
|
/// configuration and saves that as a sample file.
|
||||||
|
pub fn read_from_file<T>(path: PathBuf) -> Result<Option<T>, String>
|
||||||
|
where
|
||||||
|
T: Default + serde::de::DeserializeOwned + serde::Serialize,
|
||||||
|
{
|
||||||
|
if let Ok(mut file) = File::open(path.clone()) {
|
||||||
|
let mut contents = String::new();
|
||||||
|
file.read_to_string(&mut contents)
|
||||||
|
.map_err(|e| format!("Unable to read {:?}. Error: {:?}", path, e))?;
|
||||||
|
|
||||||
|
let config = toml::from_str(&contents)
|
||||||
|
.map_err(|e| format!("Unable to parse {:?}: {:?}", path, e))?;
|
||||||
|
|
||||||
|
Ok(Some(config))
|
||||||
|
} else {
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
}
|
@ -15,6 +15,7 @@ path = "src/lib.rs"
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
bls = { path = "../eth2/utils/bls" }
|
bls = { path = "../eth2/utils/bls" }
|
||||||
ssz = { path = "../eth2/utils/ssz" }
|
ssz = { path = "../eth2/utils/ssz" }
|
||||||
|
eth2_config = { path = "../eth2/utils/eth2_config" }
|
||||||
tree_hash = { path = "../eth2/utils/tree_hash" }
|
tree_hash = { path = "../eth2/utils/tree_hash" }
|
||||||
clap = "2.32.0"
|
clap = "2.32.0"
|
||||||
dirs = "1.0.3"
|
dirs = "1.0.3"
|
||||||
@ -23,11 +24,14 @@ protobuf = "2.0.2"
|
|||||||
protos = { path = "../protos" }
|
protos = { path = "../protos" }
|
||||||
slot_clock = { path = "../eth2/utils/slot_clock" }
|
slot_clock = { path = "../eth2/utils/slot_clock" }
|
||||||
types = { path = "../eth2/types" }
|
types = { path = "../eth2/types" }
|
||||||
|
serde = "1.0"
|
||||||
|
serde_derive = "1.0"
|
||||||
slog = "^2.2.3"
|
slog = "^2.2.3"
|
||||||
slog-term = "^2.4.0"
|
slog-term = "^2.4.0"
|
||||||
slog-async = "^2.3.0"
|
slog-async = "^2.3.0"
|
||||||
tokio = "0.1.18"
|
tokio = "0.1.18"
|
||||||
tokio-timer = "0.2.10"
|
tokio-timer = "0.2.10"
|
||||||
|
toml = "^0.5"
|
||||||
error-chain = "0.12.0"
|
error-chain = "0.12.0"
|
||||||
bincode = "^1.1.2"
|
bincode = "^1.1.2"
|
||||||
futures = "0.1.25"
|
futures = "0.1.25"
|
||||||
|
47
validator_client/eth2_config.toml
Normal file
47
validator_client/eth2_config.toml
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
spec_constants = "minimal"
|
||||||
|
|
||||||
|
[spec]
|
||||||
|
target_committee_size = 1
|
||||||
|
max_indices_per_attestation = 4096
|
||||||
|
min_per_epoch_churn_limit = 4
|
||||||
|
churn_limit_quotient = 65536
|
||||||
|
base_rewards_per_epoch = 5
|
||||||
|
shuffle_round_count = 10
|
||||||
|
deposit_contract_tree_depth = 32
|
||||||
|
min_deposit_amount = 1000000000
|
||||||
|
max_effective_balance = 32000000000
|
||||||
|
ejection_balance = 16000000000
|
||||||
|
effective_balance_increment = 1000000000
|
||||||
|
genesis_slot = 0
|
||||||
|
zero_hash = "0x0000000000000000000000000000000000000000000000000000000000000000"
|
||||||
|
bls_withdrawal_prefix_byte = "0x00"
|
||||||
|
genesis_time = 4294967295
|
||||||
|
seconds_per_slot = 6
|
||||||
|
min_attestation_inclusion_delay = 4
|
||||||
|
min_seed_lookahead = 1
|
||||||
|
activation_exit_delay = 4
|
||||||
|
slots_per_eth1_voting_period = 1024
|
||||||
|
slots_per_historical_root = 8192
|
||||||
|
min_validator_withdrawability_delay = 256
|
||||||
|
persistent_committee_period = 2048
|
||||||
|
max_crosslink_epochs = 64
|
||||||
|
min_epochs_to_inactivity_penalty = 4
|
||||||
|
base_reward_quotient = 32
|
||||||
|
whistleblowing_reward_quotient = 512
|
||||||
|
proposer_reward_quotient = 8
|
||||||
|
inactivity_penalty_quotient = 33554432
|
||||||
|
min_slashing_penalty_quotient = 32
|
||||||
|
max_proposer_slashings = 16
|
||||||
|
max_attester_slashings = 1
|
||||||
|
max_attestations = 128
|
||||||
|
max_deposits = 16
|
||||||
|
max_voluntary_exits = 16
|
||||||
|
max_transfers = 0
|
||||||
|
domain_beacon_proposer = 0
|
||||||
|
domain_randao = 1
|
||||||
|
domain_attestation = 2
|
||||||
|
domain_deposit = 3
|
||||||
|
domain_voluntary_exit = 4
|
||||||
|
domain_transfer = 5
|
||||||
|
boot_nodes = ["/ip4/127.0.0.1/tcp/9000"]
|
||||||
|
chain_id = 2
|
@ -1,22 +1,22 @@
|
|||||||
use bincode;
|
use bincode;
|
||||||
use bls::Keypair;
|
use bls::Keypair;
|
||||||
use clap::ArgMatches;
|
use clap::ArgMatches;
|
||||||
|
use serde_derive::{Deserialize, Serialize};
|
||||||
use slog::{debug, error, info};
|
use slog::{debug, error, info};
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io::{Error, ErrorKind};
|
use std::io::{Error, ErrorKind};
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use types::{ChainSpec, EthSpec, MainnetEthSpec, MinimalEthSpec};
|
use types::{EthSpec, MainnetEthSpec};
|
||||||
|
|
||||||
/// Stores the core configuration for this validator instance.
|
/// Stores the core configuration for this validator instance.
|
||||||
#[derive(Clone)]
|
#[derive(Clone, Serialize, Deserialize)]
|
||||||
pub struct Config {
|
pub struct Config {
|
||||||
/// The data directory, which stores all validator databases
|
/// The data directory, which stores all validator databases
|
||||||
pub data_dir: PathBuf,
|
pub data_dir: PathBuf,
|
||||||
/// The server at which the Beacon Node can be contacted
|
/// The server at which the Beacon Node can be contacted
|
||||||
pub server: String,
|
pub server: String,
|
||||||
/// The chain specification that we are connecting to
|
/// The number of slots per epoch.
|
||||||
pub spec: ChainSpec,
|
|
||||||
pub slots_per_epoch: u64,
|
pub slots_per_epoch: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -25,25 +25,33 @@ const DEFAULT_PRIVATE_KEY_FILENAME: &str = "private.key";
|
|||||||
impl Default for Config {
|
impl Default for Config {
|
||||||
/// Build a new configuration from defaults.
|
/// Build a new configuration from defaults.
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
let data_dir = {
|
|
||||||
let home = dirs::home_dir().expect("Unable to determine home directory.");
|
|
||||||
home.join(".lighthouse-validator")
|
|
||||||
};
|
|
||||||
|
|
||||||
let server = "localhost:5051".to_string();
|
|
||||||
|
|
||||||
let spec = MainnetEthSpec::default_spec();
|
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
data_dir,
|
data_dir: PathBuf::from(".lighthouse-validator"),
|
||||||
server,
|
server: "localhost:5051".to_string(),
|
||||||
spec,
|
|
||||||
slots_per_epoch: MainnetEthSpec::slots_per_epoch(),
|
slots_per_epoch: MainnetEthSpec::slots_per_epoch(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Config {
|
impl Config {
|
||||||
|
/// 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 let Some(datadir) = args.value_of("datadir") {
|
||||||
|
self.data_dir = PathBuf::from(datadir);
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Some(srv) = args.value_of("server") {
|
||||||
|
self.server = srv.to_string();
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
/// Build a new configuration from defaults, which are overrided by arguments provided.
|
/// Build a new configuration from defaults, which are overrided by arguments provided.
|
||||||
pub fn parse_args(args: &ArgMatches, log: &slog::Logger) -> Result<Self, Error> {
|
pub fn parse_args(args: &ArgMatches, log: &slog::Logger) -> Result<Self, Error> {
|
||||||
let mut config = Config::default();
|
let mut config = Config::default();
|
||||||
@ -80,12 +88,13 @@ impl Config {
|
|||||||
|
|
||||||
Ok(config)
|
Ok(config)
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
/// Try to load keys from validator_dir, returning None if none are found or an error.
|
/// Try to load keys from validator_dir, returning None if none are found or an error.
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub fn fetch_keys(&self, log: &slog::Logger) -> Option<Vec<Keypair>> {
|
pub fn fetch_keys(&self, log: &slog::Logger) -> Option<Vec<Keypair>> {
|
||||||
let key_pairs: Vec<Keypair> = fs::read_dir(&self.data_dir)
|
let key_pairs: Vec<Keypair> = fs::read_dir(&self.data_dir)
|
||||||
.unwrap()
|
.ok()?
|
||||||
.filter_map(|validator_dir| {
|
.filter_map(|validator_dir| {
|
||||||
let validator_dir = validator_dir.ok()?;
|
let validator_dir = validator_dir.ok()?;
|
||||||
|
|
||||||
|
@ -7,11 +7,19 @@ mod service;
|
|||||||
mod signer;
|
mod signer;
|
||||||
|
|
||||||
use crate::config::Config as ValidatorClientConfig;
|
use crate::config::Config as ValidatorClientConfig;
|
||||||
|
use std::fs;
|
||||||
use crate::service::Service as ValidatorService;
|
use crate::service::Service as ValidatorService;
|
||||||
use clap::{App, Arg};
|
use clap::{App, Arg, ArgMatches};
|
||||||
|
use eth2_config::{read_from_file, write_to_file, Eth2Config};
|
||||||
use protos::services_grpc::ValidatorServiceClient;
|
use protos::services_grpc::ValidatorServiceClient;
|
||||||
use slog::{error, info, o, Drain};
|
use slog::{crit, error, info, o, Drain};
|
||||||
use types::Keypair;
|
use std::path::PathBuf;
|
||||||
|
use types::{Keypair, MainnetEthSpec, MinimalEthSpec};
|
||||||
|
|
||||||
|
pub const DEFAULT_SPEC: &str = "minimal";
|
||||||
|
pub const DEFAULT_DATA_DIR: &str = ".lighthouse-validator";
|
||||||
|
pub const CLIENT_CONFIG_FILENAME: &str = "client_config.toml";
|
||||||
|
pub const ETH2_CONFIG_FILENAME: &str = "eth2_config.toml";
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
// Logging
|
// Logging
|
||||||
@ -30,7 +38,16 @@ fn main() {
|
|||||||
.long("datadir")
|
.long("datadir")
|
||||||
.value_name("DIR")
|
.value_name("DIR")
|
||||||
.help("Data directory for keys and databases.")
|
.help("Data directory for keys and databases.")
|
||||||
.takes_value(true),
|
.takes_value(true)
|
||||||
|
)
|
||||||
|
.arg(
|
||||||
|
Arg::with_name("eth-config")
|
||||||
|
.long("eth-config")
|
||||||
|
.short("e")
|
||||||
|
.value_name("DIR")
|
||||||
|
.help(&format!("Directory containing {}.", ETH2_CONFIG_FILENAME))
|
||||||
|
.takes_value(true)
|
||||||
|
.default_value(ETH2_CONFIG_FILENAME),
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::with_name("server")
|
Arg::with_name("server")
|
||||||
@ -40,24 +57,139 @@ fn main() {
|
|||||||
.takes_value(true),
|
.takes_value(true),
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::with_name("spec")
|
Arg::with_name("spec-constants")
|
||||||
.long("spec")
|
.long("spec-constants")
|
||||||
.value_name("spec")
|
.value_name("TITLE")
|
||||||
.short("s")
|
.short("s")
|
||||||
.help("Configuration of Beacon Chain")
|
.help("The title of the spec constants for chain config.")
|
||||||
.takes_value(true)
|
.takes_value(true)
|
||||||
.possible_values(&["mainnet", "minimal"])
|
.possible_values(&["mainnet", "minimal"])
|
||||||
.default_value("minimal"),
|
.default_value("minimal"),
|
||||||
)
|
)
|
||||||
.get_matches();
|
.get_matches();
|
||||||
|
|
||||||
let config = ValidatorClientConfig::parse_args(&matches, &log)
|
let data_dir = match get_data_dir(&matches) {
|
||||||
.expect("Unable to build a configuration for the validator client.");
|
Ok(dir) => dir,
|
||||||
|
Err(e) => {
|
||||||
|
crit!(log, "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::<ValidatorClientConfig>(
|
||||||
|
client_config_path.clone(),
|
||||||
|
) {
|
||||||
|
Ok(Some(c)) => c,
|
||||||
|
Ok(None) => {
|
||||||
|
let default = ValidatorClientConfig::default();
|
||||||
|
if let Err(e) = write_to_file(client_config_path.clone(), &default) {
|
||||||
|
crit!(log, "Failed to write default ClientConfig to file"; "error" => format!("{:?}", e));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
default
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
crit!(log, "Failed to load a ChainConfig file"; "error" => format!("{:?}", e));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let eth2_config_path: PathBuf = matches
|
||||||
|
.value_of("eth-config")
|
||||||
|
.and_then(|s| Some(PathBuf::from(s)))
|
||||||
|
.unwrap_or_else(|| 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") {
|
||||||
|
Some("mainnet") => Eth2Config::mainnet(),
|
||||||
|
Some("minimal") => Eth2Config::minimal(),
|
||||||
|
_ => unreachable!(), // Guarded by slog.
|
||||||
|
};
|
||||||
|
if let Err(e) = write_to_file(eth2_config_path, &default) {
|
||||||
|
crit!(log, "Failed to write default Eth2Config to file"; "error" => format!("{:?}", e));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
default
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
crit!(log, "Failed to instantiate an Eth2Config"; "error" => format!("{:?}", e));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Update the eth2 config with any CLI flags.
|
||||||
|
match eth2_config.apply_cli_args(&matches) {
|
||||||
|
Ok(()) => (),
|
||||||
|
Err(s) => {
|
||||||
|
crit!(log, "Failed to parse Eth2Config CLI arguments"; "error" => s);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
info!(
|
||||||
|
log,
|
||||||
|
"Starting validator client";
|
||||||
|
"datadir" => client_config.data_dir.to_str(),
|
||||||
|
"spec_constants" => ð2_config.spec_constants,
|
||||||
|
);
|
||||||
|
|
||||||
|
let result = match eth2_config.spec_constants.as_str() {
|
||||||
|
"mainnet" => ValidatorService::<ValidatorServiceClient, Keypair>::start::<MainnetEthSpec>(
|
||||||
|
client_config,
|
||||||
|
eth2_config,
|
||||||
|
log.clone(),
|
||||||
|
),
|
||||||
|
"minimal" => ValidatorService::<ValidatorServiceClient, Keypair>::start::<MinimalEthSpec>(
|
||||||
|
client_config,
|
||||||
|
eth2_config,
|
||||||
|
log.clone(),
|
||||||
|
),
|
||||||
|
other => {
|
||||||
|
crit!(log, "Unknown spec constants"; "title" => other);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// start the validator service.
|
// start the validator service.
|
||||||
// this specifies the GRPC and signer type to use as the duty manager beacon node.
|
// this specifies the GRPC and signer type to use as the duty manager beacon node.
|
||||||
match ValidatorService::<ValidatorServiceClient, Keypair>::start(config, log.clone()) {
|
match result {
|
||||||
Ok(_) => info!(log, "Validator client shutdown successfully."),
|
Ok(_) => info!(log, "Validator client shutdown successfully."),
|
||||||
Err(e) => error!(log, "Validator exited due to: {}", e.to_string()),
|
Err(e) => crit!(log, "Validator client exited with error"; "error" => e.to_string()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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 {
|
||||||
|
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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,6 +16,7 @@ use crate::error as error_chain;
|
|||||||
use crate::error::ErrorKind;
|
use crate::error::ErrorKind;
|
||||||
use crate::signer::Signer;
|
use crate::signer::Signer;
|
||||||
use bls::Keypair;
|
use bls::Keypair;
|
||||||
|
use eth2_config::Eth2Config;
|
||||||
use grpcio::{ChannelBuilder, EnvBuilder};
|
use grpcio::{ChannelBuilder, EnvBuilder};
|
||||||
use protos::services::Empty;
|
use protos::services::Empty;
|
||||||
use protos::services_grpc::{
|
use protos::services_grpc::{
|
||||||
@ -31,7 +32,7 @@ use tokio::prelude::*;
|
|||||||
use tokio::runtime::Builder;
|
use tokio::runtime::Builder;
|
||||||
use tokio::timer::Interval;
|
use tokio::timer::Interval;
|
||||||
use tokio_timer::clock::Clock;
|
use tokio_timer::clock::Clock;
|
||||||
use types::{ChainSpec, Epoch, Fork, Slot};
|
use types::{ChainSpec, Epoch, EthSpec, Fork, Slot};
|
||||||
|
|
||||||
/// A fixed amount of time after a slot to perform operations. This gives the node time to complete
|
/// A fixed amount of time after a slot to perform operations. This gives the node time to complete
|
||||||
/// per-slot processes.
|
/// per-slot processes.
|
||||||
@ -66,8 +67,9 @@ impl<B: BeaconNodeDuties + 'static, S: Signer + 'static> Service<B, S> {
|
|||||||
///
|
///
|
||||||
/// This tries to connect to a beacon node. Once connected, it initialised the gRPC clients
|
/// This tries to connect to a beacon node. Once connected, it initialised the gRPC clients
|
||||||
/// and returns an instance of the service.
|
/// and returns an instance of the service.
|
||||||
fn initialize_service(
|
fn initialize_service<T: EthSpec>(
|
||||||
config: ValidatorConfig,
|
client_config: ValidatorConfig,
|
||||||
|
eth2_config: Eth2Config,
|
||||||
log: slog::Logger,
|
log: slog::Logger,
|
||||||
) -> error_chain::Result<Service<ValidatorServiceClient, Keypair>> {
|
) -> error_chain::Result<Service<ValidatorServiceClient, Keypair>> {
|
||||||
// initialise the beacon node client to check for a connection
|
// initialise the beacon node client to check for a connection
|
||||||
@ -75,7 +77,7 @@ impl<B: BeaconNodeDuties + 'static, S: Signer + 'static> Service<B, S> {
|
|||||||
let env = Arc::new(EnvBuilder::new().build());
|
let env = Arc::new(EnvBuilder::new().build());
|
||||||
// Beacon node gRPC beacon node endpoints.
|
// Beacon node gRPC beacon node endpoints.
|
||||||
let beacon_node_client = {
|
let beacon_node_client = {
|
||||||
let ch = ChannelBuilder::new(env.clone()).connect(&config.server);
|
let ch = ChannelBuilder::new(env.clone()).connect(&client_config.server);
|
||||||
BeaconNodeServiceClient::new(ch)
|
BeaconNodeServiceClient::new(ch)
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -103,12 +105,12 @@ impl<B: BeaconNodeDuties + 'static, S: Signer + 'static> Service<B, S> {
|
|||||||
return Err("Genesis time in the future".into());
|
return Err("Genesis time in the future".into());
|
||||||
}
|
}
|
||||||
// verify the node's chain id
|
// verify the node's chain id
|
||||||
if config.spec.chain_id != info.chain_id as u8 {
|
if eth2_config.spec.chain_id != info.chain_id as u8 {
|
||||||
error!(
|
error!(
|
||||||
log,
|
log,
|
||||||
"Beacon Node's genesis time is in the future. No work to do.\n Exiting"
|
"Beacon Node's genesis time is in the future. No work to do.\n Exiting"
|
||||||
);
|
);
|
||||||
return Err(format!("Beacon node has the wrong chain id. Expected chain id: {}, node's chain id: {}", config.spec.chain_id, info.chain_id).into());
|
return Err(format!("Beacon node has the wrong chain id. Expected chain id: {}, node's chain id: {}", eth2_config.spec.chain_id, info.chain_id).into());
|
||||||
}
|
}
|
||||||
break info;
|
break info;
|
||||||
}
|
}
|
||||||
@ -136,7 +138,7 @@ impl<B: BeaconNodeDuties + 'static, S: Signer + 'static> Service<B, S> {
|
|||||||
|
|
||||||
// Beacon node gRPC beacon block endpoints.
|
// Beacon node gRPC beacon block endpoints.
|
||||||
let beacon_block_client = {
|
let beacon_block_client = {
|
||||||
let ch = ChannelBuilder::new(env.clone()).connect(&config.server);
|
let ch = ChannelBuilder::new(env.clone()).connect(&client_config.server);
|
||||||
let beacon_block_service_client = Arc::new(BeaconBlockServiceClient::new(ch));
|
let beacon_block_service_client = Arc::new(BeaconBlockServiceClient::new(ch));
|
||||||
// a wrapper around the service client to implement the beacon block node trait
|
// a wrapper around the service client to implement the beacon block node trait
|
||||||
Arc::new(BeaconBlockGrpcClient::new(beacon_block_service_client))
|
Arc::new(BeaconBlockGrpcClient::new(beacon_block_service_client))
|
||||||
@ -144,33 +146,42 @@ impl<B: BeaconNodeDuties + 'static, S: Signer + 'static> Service<B, S> {
|
|||||||
|
|
||||||
// Beacon node gRPC validator endpoints.
|
// Beacon node gRPC validator endpoints.
|
||||||
let validator_client = {
|
let validator_client = {
|
||||||
let ch = ChannelBuilder::new(env.clone()).connect(&config.server);
|
let ch = ChannelBuilder::new(env.clone()).connect(&client_config.server);
|
||||||
Arc::new(ValidatorServiceClient::new(ch))
|
Arc::new(ValidatorServiceClient::new(ch))
|
||||||
};
|
};
|
||||||
|
|
||||||
//Beacon node gRPC attester endpoints.
|
//Beacon node gRPC attester endpoints.
|
||||||
let attestation_client = {
|
let attestation_client = {
|
||||||
let ch = ChannelBuilder::new(env.clone()).connect(&config.server);
|
let ch = ChannelBuilder::new(env.clone()).connect(&client_config.server);
|
||||||
Arc::new(AttestationServiceClient::new(ch))
|
Arc::new(AttestationServiceClient::new(ch))
|
||||||
};
|
};
|
||||||
|
|
||||||
// build the validator slot clock
|
// build the validator slot clock
|
||||||
let slot_clock =
|
let slot_clock = SystemTimeSlotClock::new(
|
||||||
SystemTimeSlotClock::new(genesis_slot, genesis_time, config.spec.seconds_per_slot);
|
genesis_slot,
|
||||||
|
genesis_time,
|
||||||
|
eth2_config.spec.seconds_per_slot,
|
||||||
|
);
|
||||||
|
|
||||||
let current_slot = slot_clock
|
let current_slot = slot_clock
|
||||||
.present_slot()
|
.present_slot()
|
||||||
.map_err(ErrorKind::SlotClockError)?
|
.map_err(ErrorKind::SlotClockError)?
|
||||||
.expect("Genesis must be in the future");
|
.ok_or_else::<error_chain::Error, _>(|| {
|
||||||
|
"Genesis is not in the past. Exiting.".into()
|
||||||
|
})?;
|
||||||
|
|
||||||
/* Generate the duties manager */
|
/* Generate the duties manager */
|
||||||
|
|
||||||
// Load generated keypairs
|
// Load generated keypairs
|
||||||
let keypairs = match config.fetch_keys(&log) {
|
let keypairs = match client_config.fetch_keys(&log) {
|
||||||
Some(kps) => Arc::new(kps),
|
Some(kps) => Arc::new(kps),
|
||||||
None => panic!("No key pairs found, cannot start validator client without at least one. Try running `./account_manager generate` first.")
|
None => {
|
||||||
|
return Err("Unable to locate validator key pairs, nothing to do.".into());
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let slots_per_epoch = T::slots_per_epoch();
|
||||||
|
|
||||||
// TODO: keypairs are randomly generated; they should be loaded from a file or generated.
|
// TODO: keypairs are randomly generated; they should be loaded from a file or generated.
|
||||||
// https://github.com/sigp/lighthouse/issues/160
|
// https://github.com/sigp/lighthouse/issues/160
|
||||||
//let keypairs = Arc::new(generate_deterministic_keypairs(8));
|
//let keypairs = Arc::new(generate_deterministic_keypairs(8));
|
||||||
@ -178,7 +189,7 @@ impl<B: BeaconNodeDuties + 'static, S: Signer + 'static> Service<B, S> {
|
|||||||
// Builds a mapping of Epoch -> Map(PublicKey, EpochDuty)
|
// Builds a mapping of Epoch -> Map(PublicKey, EpochDuty)
|
||||||
// where EpochDuty contains slot numbers and attestation data that each validator needs to
|
// where EpochDuty contains slot numbers and attestation data that each validator needs to
|
||||||
// produce work on.
|
// produce work on.
|
||||||
let duties_map = RwLock::new(EpochDutiesMap::new(config.slots_per_epoch));
|
let duties_map = RwLock::new(EpochDutiesMap::new(slots_per_epoch));
|
||||||
|
|
||||||
// builds a manager which maintains the list of current duties for all known validators
|
// builds a manager which maintains the list of current duties for all known validators
|
||||||
// and can check when a validator needs to perform a task.
|
// and can check when a validator needs to perform a task.
|
||||||
@ -189,13 +200,13 @@ impl<B: BeaconNodeDuties + 'static, S: Signer + 'static> Service<B, S> {
|
|||||||
beacon_node: validator_client,
|
beacon_node: validator_client,
|
||||||
});
|
});
|
||||||
|
|
||||||
let spec = Arc::new(config.spec);
|
let spec = Arc::new(eth2_config.spec);
|
||||||
|
|
||||||
Ok(Service {
|
Ok(Service {
|
||||||
fork,
|
fork,
|
||||||
slot_clock,
|
slot_clock,
|
||||||
current_slot,
|
current_slot,
|
||||||
slots_per_epoch: config.slots_per_epoch,
|
slots_per_epoch,
|
||||||
spec,
|
spec,
|
||||||
duties_manager,
|
duties_manager,
|
||||||
beacon_block_client,
|
beacon_block_client,
|
||||||
@ -206,13 +217,17 @@ impl<B: BeaconNodeDuties + 'static, S: Signer + 'static> Service<B, S> {
|
|||||||
|
|
||||||
/// Initialise the service then run the core thread.
|
/// Initialise the service then run the core thread.
|
||||||
// TODO: Improve handling of generic BeaconNode types, to stub grpcClient
|
// TODO: Improve handling of generic BeaconNode types, to stub grpcClient
|
||||||
pub fn start(
|
pub fn start<T: EthSpec>(
|
||||||
config: ValidatorConfig,
|
client_config: ValidatorConfig,
|
||||||
|
eth2_config: Eth2Config,
|
||||||
log: slog::Logger,
|
log: slog::Logger,
|
||||||
) -> error_chain::Result<()> {
|
) -> error_chain::Result<()> {
|
||||||
// connect to the node and retrieve its properties and initialize the gRPC clients
|
// connect to the node and retrieve its properties and initialize the gRPC clients
|
||||||
let mut service =
|
let mut service = Service::<ValidatorServiceClient, Keypair>::initialize_service::<T>(
|
||||||
Service::<ValidatorServiceClient, Keypair>::initialize_service(config, log)?;
|
client_config,
|
||||||
|
eth2_config,
|
||||||
|
log,
|
||||||
|
)?;
|
||||||
|
|
||||||
// we have connected to a node and established its parameters. Spin up the core service
|
// we have connected to a node and established its parameters. Spin up the core service
|
||||||
|
|
||||||
@ -227,7 +242,9 @@ impl<B: BeaconNodeDuties + 'static, S: Signer + 'static> Service<B, S> {
|
|||||||
.slot_clock
|
.slot_clock
|
||||||
.duration_to_next_slot()
|
.duration_to_next_slot()
|
||||||
.map_err(|e| format!("System clock error: {:?}", e))?
|
.map_err(|e| format!("System clock error: {:?}", e))?
|
||||||
.expect("Cannot start before genesis");
|
.ok_or_else::<error_chain::Error, _>(|| {
|
||||||
|
"Genesis is not in the past. Exiting.".into()
|
||||||
|
})?;
|
||||||
|
|
||||||
// set up the validator work interval - start at next slot and proceed every slot
|
// set up the validator work interval - start at next slot and proceed every slot
|
||||||
let interval = {
|
let interval = {
|
||||||
@ -276,7 +293,9 @@ impl<B: BeaconNodeDuties + 'static, S: Signer + 'static> Service<B, S> {
|
|||||||
error!(self.log, "SystemTimeError {:?}", e);
|
error!(self.log, "SystemTimeError {:?}", e);
|
||||||
return Err("Could not read system time".into());
|
return Err("Could not read system time".into());
|
||||||
}
|
}
|
||||||
Ok(slot) => slot.expect("Genesis is in the future"),
|
Ok(slot) => slot.ok_or_else::<error_chain::Error, _>(|| {
|
||||||
|
"Genesis is not in the past. Exiting.".into()
|
||||||
|
})?,
|
||||||
};
|
};
|
||||||
|
|
||||||
let current_epoch = current_slot.epoch(self.slots_per_epoch);
|
let current_epoch = current_slot.epoch(self.slots_per_epoch);
|
||||||
|
Loading…
Reference in New Issue
Block a user