use beacon_chain::validator_monitor::ValidatorMonitorConfig; use beacon_chain::TrustedSetup; use beacon_processor::BeaconProcessorConfig; use directory::DEFAULT_ROOT_DIR; use environment::LoggerConfig; use network::NetworkConfig; use sensitive_url::SensitiveUrl; use serde::{Deserialize, Serialize}; use std::fs; use std::path::PathBuf; use std::time::Duration; use types::Graffiti; /// Default directory name for the freezer database under the top-level data dir. const DEFAULT_FREEZER_DB_DIR: &str = "freezer_db"; /// Default directory name for the blobs database under the top-level data dir. const DEFAULT_BLOBS_DB_DIR: &str = "blobs_db"; /// Defines how the client should initialize the `BeaconChain` and other components. #[derive(Debug, Clone, Serialize, Deserialize, Default)] pub enum ClientGenesis { /// Creates a genesis state as per the 2019 Canada interop specifications. Interop { validator_count: usize, genesis_time: u64, }, /// Reads the genesis state and other persisted data from the `Store`. FromStore, /// Connects to an eth1 node and waits until it can create the genesis state from the deposit /// contract. #[default] DepositContract, /// Loads the genesis state from the genesis state in the `Eth2NetworkConfig`. GenesisState, WeakSubjSszBytes { anchor_state_bytes: Vec, anchor_block_bytes: Vec, anchor_blobs_bytes: Option>, }, CheckpointSyncUrl { url: SensitiveUrl, }, } /// The core configuration of a Lighthouse beacon node. #[derive(Debug, Clone, Serialize, Deserialize)] pub struct Config { data_dir: PathBuf, /// Name of the directory inside the data directory where the main "hot" DB is located. pub db_name: String, /// Path where the freezer database will be located. pub freezer_db_path: Option, /// Path where the blobs database will be located if blobs should be in a separate database. pub blobs_db_path: Option, pub log_file: PathBuf, /// If true, the node will use co-ordinated junk for eth1 values. /// /// This is the method used for the 2019 client interop in Canada. pub dummy_eth1_backend: bool, pub sync_eth1_chain: bool, /// Graffiti to be inserted everytime we create a block. pub graffiti: Graffiti, pub validator_monitor: ValidatorMonitorConfig, #[serde(skip)] /// The `genesis` field is not serialized or deserialized by `serde` to ensure it is defined /// via the CLI at runtime, instead of from a configuration file saved to disk. pub genesis: ClientGenesis, pub store: store::StoreConfig, pub network: network::NetworkConfig, pub chain: beacon_chain::ChainConfig, pub eth1: eth1::Config, pub execution_layer: Option, pub trusted_setup: Option, pub http_api: http_api::Config, pub http_metrics: http_metrics::Config, pub monitoring_api: Option, pub slasher: Option, pub logger_config: LoggerConfig, pub beacon_processor: BeaconProcessorConfig, pub genesis_state_url: Option, pub genesis_state_url_timeout: Duration, pub allow_insecure_genesis_sync: bool, } impl Default for Config { fn default() -> Self { Self { data_dir: PathBuf::from(DEFAULT_ROOT_DIR), db_name: "chain_db".to_string(), freezer_db_path: None, blobs_db_path: None, log_file: PathBuf::from(""), genesis: <_>::default(), store: <_>::default(), network: NetworkConfig::default(), chain: <_>::default(), dummy_eth1_backend: false, sync_eth1_chain: false, eth1: <_>::default(), execution_layer: None, trusted_setup: None, graffiti: Graffiti::default(), http_api: <_>::default(), http_metrics: <_>::default(), monitoring_api: None, slasher: None, validator_monitor: <_>::default(), logger_config: LoggerConfig::default(), beacon_processor: <_>::default(), genesis_state_url: <_>::default(), // This default value should always be overwritten by the CLI default value. genesis_state_url_timeout: Duration::from_secs(60), allow_insecure_genesis_sync: false, } } } impl Config { /// Updates the data directory for the Client. pub fn set_data_dir(&mut self, data_dir: PathBuf) { self.data_dir.clone_from(&data_dir); self.http_api.data_dir = data_dir; } /// Gets the config's data_dir. pub fn data_dir(&self) -> &PathBuf { &self.data_dir } /// Get the database path without initialising it. pub fn get_db_path(&self) -> PathBuf { self.get_data_dir().join(&self.db_name) } /// Get the database path, creating it if necessary. pub fn create_db_path(&self) -> Result { ensure_dir_exists(self.get_db_path()) } /// Fetch default path to use for the freezer database. fn default_freezer_db_path(&self) -> PathBuf { self.get_data_dir().join(DEFAULT_FREEZER_DB_DIR) } /// Returns the path to which the client may initialize the on-disk freezer database. /// /// Will attempt to use the user-supplied path from e.g. the CLI, or will default /// to a directory in the data_dir if no path is provided. pub fn get_freezer_db_path(&self) -> PathBuf { self.freezer_db_path .clone() .unwrap_or_else(|| self.default_freezer_db_path()) } /// Fetch default path to use for the blobs database. fn default_blobs_db_path(&self) -> PathBuf { self.get_data_dir().join(DEFAULT_BLOBS_DB_DIR) } /// Returns the path to which the client may initialize the on-disk blobs database. /// /// Will attempt to use the user-supplied path from e.g. the CLI, or will default /// to None. pub fn get_blobs_db_path(&self) -> PathBuf { self.blobs_db_path .clone() .unwrap_or_else(|| self.default_blobs_db_path()) } /// Get the freezer DB path, creating it if necessary. pub fn create_freezer_db_path(&self) -> Result { ensure_dir_exists(self.get_freezer_db_path()) } /// Get the blobs DB path, creating it if necessary. pub fn create_blobs_db_path(&self) -> Result { ensure_dir_exists(self.get_blobs_db_path()) } /// Returns the "modern" path to the data_dir. /// /// See `Self::get_data_dir` documentation for more info. fn get_modern_data_dir(&self) -> PathBuf { self.data_dir.clone() } /// Returns the "legacy" path to the data_dir. /// /// See `Self::get_data_dir` documentation for more info. pub fn get_existing_legacy_data_dir(&self) -> Option { dirs::home_dir() .map(|home_dir| home_dir.join(&self.data_dir)) // Return `None` if the legacy directory does not exist or if it is identical to the modern. .filter(|dir| dir.exists() && *dir != self.get_modern_data_dir()) } /// Returns the core path for the client. /// /// Will not create any directories. /// /// ## Legacy Info /// /// Legacy versions of Lighthouse did not properly handle relative paths for `--datadir`. /// /// For backwards compatibility, we still compute the legacy path and check if it exists. If /// it does exist, we use that directory rather than the modern path. /// /// For more information, see: /// /// https://github.com/sigp/lighthouse/pull/2843 pub fn get_data_dir(&self) -> PathBuf { let existing_legacy_dir = self.get_existing_legacy_data_dir(); if let Some(legacy_dir) = existing_legacy_dir { legacy_dir } else { self.get_modern_data_dir() } } /// Returns the core path for the client. /// /// Creates the directory if it does not exist. pub fn create_data_dir(&self) -> Result { ensure_dir_exists(self.get_data_dir()) } } /// Ensure that the directory at `path` exists, by creating it and all parents if necessary. fn ensure_dir_exists(path: PathBuf) -> Result { fs::create_dir_all(&path).map_err(|e| format!("Unable to create {}: {}", path.display(), e))?; Ok(path) } #[cfg(test)] mod tests { use super::*; #[test] fn serde() { let config = Config::default(); let serialized = serde_yaml::to_string(&config).expect("should serde encode default config"); serde_yaml::from_str::(&serialized).expect("should serde decode default config"); } }