diff --git a/beacon_node/Cargo.toml b/beacon_node/Cargo.toml index d78a5b596..f1f47bef3 100644 --- a/beacon_node/Cargo.toml +++ b/beacon_node/Cargo.toml @@ -8,6 +8,7 @@ edition = "2018" types = { path = "../eth2/types" } store = { path = "./store" } client = { path = "client" } +fork_choice = { path = "../eth2/fork_choice" } version = { path = "version" } clap = "2.32.0" slog = { version = "^2.2.3" , features = ["max_level_trace", "release_max_level_debug"] } diff --git a/beacon_node/client/Cargo.toml b/beacon_node/client/Cargo.toml index afff86bcc..6da832c33 100644 --- a/beacon_node/client/Cargo.toml +++ b/beacon_node/client/Cargo.toml @@ -15,6 +15,8 @@ prometheus = "^0.6" types = { path = "../../eth2/types" } tree_hash = { path = "../../eth2/utils/tree_hash" } slot_clock = { path = "../../eth2/utils/slot_clock" } +serde = "1.0" +serde_derive = "1.0" error-chain = "0.12.0" slog = "^2.2.3" ssz = { path = "../../eth2/utils/ssz" } diff --git a/beacon_node/client/src/beacon_chain_types.rs b/beacon_node/client/src/beacon_chain_types.rs index f84a7fdf6..37b1d261d 100644 --- a/beacon_node/client/src/beacon_chain_types.rs +++ b/beacon_node/client/src/beacon_chain_types.rs @@ -18,42 +18,32 @@ const TESTNET_VALIDATOR_COUNT: usize = 16; /// Provides a new, initialized `BeaconChain` pub trait InitialiseBeaconChain { - fn initialise_beacon_chain(store: Arc, log: Logger) -> BeaconChain; + fn initialise_beacon_chain(store: Arc, log: Logger) -> BeaconChain { + maybe_load_from_store_for_testnet::<_, T::Store, T::EthSpec>(store, log) + } } /// A testnet-suitable BeaconChainType, using `MemoryStore`. #[derive(Clone)] pub struct TestnetMemoryBeaconChainTypes; - impl BeaconChainTypes for TestnetMemoryBeaconChainTypes { type Store = MemoryStore; type SlotClock = SystemTimeSlotClock; type ForkChoice = OptimizedLMDGhost; type EthSpec = LighthouseTestnetEthSpec; } - -impl InitialiseBeaconChain for TestnetMemoryBeaconChainTypes { - fn initialise_beacon_chain(store: Arc, log: Logger) -> BeaconChain { - maybe_load_from_store_for_testnet::<_, T::Store, T::EthSpec>(store, log) - } -} +impl InitialiseBeaconChain for TestnetMemoryBeaconChainTypes {} /// A testnet-suitable BeaconChainType, using `DiskStore`. #[derive(Clone)] pub struct TestnetDiskBeaconChainTypes; - impl BeaconChainTypes for TestnetDiskBeaconChainTypes { type Store = DiskStore; type SlotClock = SystemTimeSlotClock; type ForkChoice = OptimizedLMDGhost; type EthSpec = LighthouseTestnetEthSpec; } - -impl InitialiseBeaconChain for TestnetDiskBeaconChainTypes { - fn initialise_beacon_chain(store: Arc, log: Logger) -> BeaconChain { - maybe_load_from_store_for_testnet::<_, T::Store, T::EthSpec>(store, log) - } -} +impl InitialiseBeaconChain for TestnetDiskBeaconChainTypes {} /// Loads a `BeaconChain` from `store`, if it exists. Otherwise, create a new chain from genesis. fn maybe_load_from_store_for_testnet( diff --git a/beacon_node/client/src/client_config.rs b/beacon_node/client/src/client_config.rs index a34b83253..65964a794 100644 --- a/beacon_node/client/src/client_config.rs +++ b/beacon_node/client/src/client_config.rs @@ -1,164 +1,69 @@ use clap::ArgMatches; -use fork_choice::ForkChoiceAlgorithm; use http_server::HttpServerConfig; use network::NetworkConfig; -use slog::error; +use serde_derive::{Deserialize, Serialize}; use std::fs; -use std::net::SocketAddr; -use std::net::{IpAddr, Ipv4Addr}; use std::path::PathBuf; -use types::multiaddr::Protocol; -use types::multiaddr::ToMultiaddr; -use types::Multiaddr; -use types::{ChainSpec, EthSpec, LighthouseTestnetEthSpec}; -#[derive(Debug, Clone)] -pub enum DBType { - Memory, - Disk, -} - -/// Stores the client configuration for this Lighthouse instance. -#[derive(Debug, Clone)] +/// The core configuration of a Lighthouse beacon node. +#[derive(Debug, Clone, Serialize, Deserialize)] pub struct ClientConfig { - pub data_dir: PathBuf, - pub spec: ChainSpec, - pub net_conf: network::NetworkConfig, - pub fork_choice: ForkChoiceAlgorithm, - pub db_type: DBType, - pub db_name: PathBuf, - pub rpc_conf: rpc::RPCConfig, - pub http_conf: HttpServerConfig, //pub ipc_conf: + data_dir: String, + pub spec: String, + pub db_type: String, + db_name: String, + pub network: network::NetworkConfig, + pub rpc: rpc::RPCConfig, + pub http: HttpServerConfig, //pub ipc_conf: } impl Default for ClientConfig { - /// Build a new lighthouse configuration from defaults. fn default() -> Self { - let data_dir = { - let home = dirs::home_dir().expect("Unable to determine home dir."); - home.join(".lighthouse/") - }; - fs::create_dir_all(&data_dir) - .unwrap_or_else(|_| panic!("Unable to create {:?}", &data_dir)); - - let default_spec = LighthouseTestnetEthSpec::spec(); - let default_net_conf = NetworkConfig::new(default_spec.boot_nodes.clone()); - Self { - data_dir: data_dir.clone(), - // default to foundation for chain specs - spec: default_spec, - net_conf: default_net_conf, - // default to bitwise LMD Ghost - fork_choice: ForkChoiceAlgorithm::BitwiseLMDGhost, - // default to memory db for now - db_type: DBType::Memory, - // default db name for disk-based dbs - db_name: data_dir.join("chain_db"), - rpc_conf: rpc::RPCConfig::default(), - http_conf: HttpServerConfig::default(), + data_dir: ".lighthouse".to_string(), + spec: "testnet".to_string(), + db_type: "disk".to_string(), + db_name: "chain_db".to_string(), + // Note: there are no default bootnodes specified. + // Once bootnodes are established, add them here. + network: NetworkConfig::new(vec![]), + rpc: rpc::RPCConfig::default(), + http: HttpServerConfig::default(), } } } impl ClientConfig { - /// Parses the CLI arguments into a `Config` struct. - pub fn parse_args(args: ArgMatches, log: &slog::Logger) -> Result { - let mut config = ClientConfig::default(); + /// Returns the path to which the client may initialize an on-disk database. + pub fn db_path(&self) -> Option { + self.data_dir() + .and_then(|path| Some(path.join(&self.db_name))) + } - /* Network related arguments */ + /// Returns the core path for the client. + pub fn data_dir(&self) -> Option { + let path = dirs::home_dir()?.join(&self.data_dir); + fs::create_dir_all(&path).ok()?; + Some(path) + } - // Custom p2p listen port - if let Some(port_str) = args.value_of("port") { - if let Ok(port) = port_str.parse::() { - config.net_conf.listen_port = port; - // update the listening multiaddrs - for address in &mut config.net_conf.listen_addresses { - address.pop(); - address.append(Protocol::Tcp(port)); - } - } else { - error!(log, "Invalid port"; "port" => port_str); - return Err("Invalid port"); - } - } - // Custom listening address ipv4/ipv6 - // TODO: Handle list of addresses - if let Some(listen_address_str) = args.value_of("listen-address") { - if let Ok(listen_address) = listen_address_str.parse::() { - let multiaddr = SocketAddr::new(listen_address, config.net_conf.listen_port) - .to_multiaddr() - .expect("Invalid listen address format"); - config.net_conf.listen_addresses = vec![multiaddr]; - } else { - error!(log, "Invalid IP Address"; "Address" => listen_address_str); - return Err("Invalid IP Address"); - } - } - - // Custom bootnodes - if let Some(boot_addresses_str) = args.value_of("boot-nodes") { - let boot_addresses_split = boot_addresses_str.split(','); - for boot_address in boot_addresses_split { - if let Ok(boot_address) = boot_address.parse::() { - config.net_conf.boot_nodes.append(&mut vec![boot_address]); - } else { - error!(log, "Invalid Bootnode multiaddress"; "Multiaddr" => boot_addresses_str); - return Err("Invalid IP Address"); - } - } - } - - /* Filesystem related arguments */ - - // Custom datadir + /// 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(dir) = args.value_of("datadir") { - config.data_dir = PathBuf::from(dir.to_string()); + self.data_dir = dir.to_string(); }; - /* RPC related arguments */ - - if args.is_present("rpc") { - config.rpc_conf.enabled = true; + if let Some(dir) = args.value_of("db") { + self.db_type = dir.to_string(); } - if let Some(rpc_address) = args.value_of("rpc-address") { - if let Ok(listen_address) = rpc_address.parse::() { - config.rpc_conf.listen_address = listen_address; - } else { - error!(log, "Invalid RPC listen address"; "Address" => rpc_address); - return Err("Invalid RPC listen address"); - } - } + self.network.apply_cli_args(args)?; + self.rpc.apply_cli_args(args)?; + self.http.apply_cli_args(args)?; - if let Some(rpc_port) = args.value_of("rpc-port") { - if let Ok(port) = rpc_port.parse::() { - config.rpc_conf.port = port; - } else { - error!(log, "Invalid RPC port"; "port" => rpc_port); - return Err("Invalid RPC port"); - } - } - - /* HTTP related arguments */ - - if args.is_present("http") { - config.http_conf.enabled = true; - } - - if let Some(listen_address) = args.value_of("http-address") { - config.http_conf.listen_address = listen_address.to_string(); - } - if let Some(listen_port) = args.value_of("http-port") { - config.http_conf.listen_port = listen_port.to_string(); - } - - match args.value_of("db") { - Some("disk") => config.db_type = DBType::Disk, - Some("memory") => config.db_type = DBType::Memory, - _ => unreachable!(), // clap prevents this. - }; - - Ok(config) + Ok(()) } } diff --git a/beacon_node/client/src/error.rs b/beacon_node/client/src/error.rs index b0272400c..680ad8277 100644 --- a/beacon_node/client/src/error.rs +++ b/beacon_node/client/src/error.rs @@ -6,5 +6,4 @@ error_chain! { links { Network(network::error::Error, network::error::ErrorKind); } - } diff --git a/beacon_node/client/src/lib.rs b/beacon_node/client/src/lib.rs index d29d00ad4..36d1c7d1f 100644 --- a/beacon_node/client/src/lib.rs +++ b/beacon_node/client/src/lib.rs @@ -6,7 +6,6 @@ pub mod error; pub mod notifier; use beacon_chain::BeaconChain; -use beacon_chain_types::InitialiseBeaconChain; use exit_future::Signal; use futures::{future::Future, Stream}; use network::Service as NetworkService; @@ -18,10 +17,12 @@ use std::sync::Arc; use std::time::{Duration, Instant}; use tokio::runtime::TaskExecutor; use tokio::timer::Interval; +use types::EthSpec; pub use beacon_chain::BeaconChainTypes; +pub use beacon_chain_types::InitialiseBeaconChain; pub use beacon_chain_types::{TestnetDiskBeaconChainTypes, TestnetMemoryBeaconChainTypes}; -pub use client_config::{ClientConfig, DBType}; +pub use client_config::ClientConfig; /// Main beacon node client service. This provides the connection and initialisation of the clients /// sub-services in multiple threads. @@ -57,6 +58,7 @@ where ) -> error::Result { let metrics_registry = Registry::new(); let store = Arc::new(store); + let spec = T::EthSpec::spec(); // Load a `BeaconChain` from the store, or create a new one if it does not exist. let beacon_chain = Arc::new(T::initialise_beacon_chain(store, log.clone())); @@ -97,7 +99,7 @@ where // Start the network service, libp2p and syncing threads // TODO: Add beacon_chain reference to network parameters - let network_config = &config.net_conf; + let network_config = &config.network; let network_logger = log.new(o!("Service" => "Network")); let (network, network_send) = NetworkService::new( beacon_chain.clone(), @@ -107,9 +109,9 @@ where )?; // spawn the RPC server - let rpc_exit_signal = if config.rpc_conf.enabled { + let rpc_exit_signal = if config.rpc.enabled { Some(rpc::start_server( - &config.rpc_conf, + &config.rpc, executor, network_send.clone(), beacon_chain.clone(), @@ -122,13 +124,13 @@ where // Start the `http_server` service. // // Note: presently we are ignoring the config and _always_ starting a HTTP server. - let http_exit_signal = if config.http_conf.enabled { + let http_exit_signal = if config.http.enabled { Some(http_server::start_service( - &config.http_conf, + &config.http, executor, network_send, beacon_chain.clone(), - config.db_name.clone(), + config.db_path().expect("unable to read datadir"), metrics_registry, &log, )) @@ -141,7 +143,7 @@ where // set up the validator work interval - start at next slot and proceed every slot let interval = { // Set the interval to start at the next slot, and every slot after - let slot_duration = Duration::from_secs(config.spec.seconds_per_slot); + let slot_duration = Duration::from_secs(spec.seconds_per_slot); //TODO: Handle checked add correctly Interval::new(Instant::now() + duration_to_next_slot, slot_duration) }; diff --git a/beacon_node/eth2-libp2p/Cargo.toml b/beacon_node/eth2-libp2p/Cargo.toml index d9c43b23c..cc6393e38 100644 --- a/beacon_node/eth2-libp2p/Cargo.toml +++ b/beacon_node/eth2-libp2p/Cargo.toml @@ -6,9 +6,12 @@ edition = "2018" [dependencies] beacon_chain = { path = "../beacon_chain" } +clap = "2.32.0" # SigP repository until PR is merged libp2p = { git = "https://github.com/SigP/rust-libp2p", rev = "b3c32d9a821ae6cc89079499cc6e8a6bab0bffc3" } types = { path = "../../eth2/types" } +serde = "1.0" +serde_derive = "1.0" ssz = { path = "../../eth2/utils/ssz" } ssz_derive = { path = "../../eth2/utils/ssz_derive" } slog = "2.4.1" diff --git a/beacon_node/eth2-libp2p/src/config.rs b/beacon_node/eth2-libp2p/src/config.rs index 265100658..2a2701883 100644 --- a/beacon_node/eth2-libp2p/src/config.rs +++ b/beacon_node/eth2-libp2p/src/config.rs @@ -1,20 +1,22 @@ -use crate::Multiaddr; +use clap::ArgMatches; use libp2p::gossipsub::{GossipsubConfig, GossipsubConfigBuilder}; +use serde_derive::{Deserialize, Serialize}; +use types::multiaddr::{Error as MultiaddrError, Multiaddr}; -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Serialize, Deserialize)] +#[serde(default)] /// Network configuration for lighthouse. pub struct Config { - //TODO: stubbing networking initial params, change in the future /// IP address to listen on. - pub listen_addresses: Vec, - /// Listen port UDP/TCP. - pub listen_port: u16, + listen_addresses: Vec, /// Gossipsub configuration parameters. + #[serde(skip)] pub gs_config: GossipsubConfig, /// Configuration parameters for node identification protocol. + #[serde(skip)] pub identify_config: IdentifyConfig, /// List of nodes to initially connect to. - pub boot_nodes: Vec, + boot_nodes: Vec, /// Client version pub client_version: String, /// List of topics to subscribe to as strings @@ -25,15 +27,12 @@ impl Default for Config { /// Generate a default network configuration. fn default() -> Self { Config { - listen_addresses: vec!["/ip4/127.0.0.1/tcp/9000" - .parse() - .expect("is a correct multi-address")], - listen_port: 9000, + listen_addresses: vec!["/ip4/127.0.0.1/tcp/9000".to_string()], gs_config: GossipsubConfigBuilder::new() .max_gossip_size(4_000_000) .build(), identify_config: IdentifyConfig::default(), - boot_nodes: Vec::new(), + boot_nodes: vec![], client_version: version::version(), topics: vec![String::from("beacon_chain")], } @@ -41,12 +40,34 @@ impl Default for Config { } impl Config { - pub fn new(boot_nodes: Vec) -> Self { + pub fn new(boot_nodes: Vec) -> Self { let mut conf = Config::default(); conf.boot_nodes = boot_nodes; conf } + + pub fn listen_addresses(&self) -> Result, MultiaddrError> { + self.listen_addresses.iter().map(|s| s.parse()).collect() + } + + pub fn boot_nodes(&self) -> Result, MultiaddrError> { + self.boot_nodes.iter().map(|s| s.parse()).collect() + } + + pub fn apply_cli_args(&mut self, args: &ArgMatches) -> Result<(), &'static str> { + if let Some(listen_address_str) = args.value_of("listen-address") { + let listen_addresses = listen_address_str.split(",").map(Into::into).collect(); + self.listen_addresses = listen_addresses; + } + + if let Some(boot_addresses_str) = args.value_of("boot-nodes") { + let boot_addresses = boot_addresses_str.split(",").map(Into::into).collect(); + self.boot_nodes = boot_addresses; + } + + Ok(()) + } } /// The configuration parameters for the Identify protocol diff --git a/beacon_node/eth2-libp2p/src/service.rs b/beacon_node/eth2-libp2p/src/service.rs index 07a36e408..b18a7dc51 100644 --- a/beacon_node/eth2-libp2p/src/service.rs +++ b/beacon_node/eth2-libp2p/src/service.rs @@ -57,7 +57,7 @@ impl Service { }; // listen on all addresses - for address in &config.listen_addresses { + for address in config.listen_addresses().expect("invalid listen multiaddr") { match Swarm::listen_on(&mut swarm, address.clone()) { Ok(mut listen_addr) => { listen_addr.append(Protocol::P2p(local_peer_id.clone().into())); @@ -68,7 +68,7 @@ impl Service { } // connect to boot nodes - these are currently stored as multiaddrs // Once we have discovery, can set to peerId - for bootnode in config.boot_nodes { + for bootnode in config.boot_nodes().expect("invalid boot node multiaddr") { match Swarm::dial_addr(&mut swarm, bootnode.clone()) { Ok(()) => debug!(log, "Dialing bootnode: {}", bootnode), Err(err) => debug!( diff --git a/beacon_node/http_server/src/lib.rs b/beacon_node/http_server/src/lib.rs index fb9434826..ab1176d61 100644 --- a/beacon_node/http_server/src/lib.rs +++ b/beacon_node/http_server/src/lib.rs @@ -3,17 +3,19 @@ mod key; mod metrics; use beacon_chain::{BeaconChain, BeaconChainTypes}; +use clap::ArgMatches; use futures::Future; use iron::prelude::*; use network::NetworkMessage; use prometheus::Registry; use router::Router; +use serde_derive::{Deserialize, Serialize}; use slog::{info, o, warn}; use std::path::PathBuf; use std::sync::Arc; use tokio::runtime::TaskExecutor; -#[derive(PartialEq, Clone, Debug)] +#[derive(PartialEq, Clone, Debug, Serialize, Deserialize)] pub struct HttpServerConfig { pub enabled: bool, pub listen_address: String, @@ -30,6 +32,24 @@ impl Default for HttpServerConfig { } } +impl HttpServerConfig { + pub fn apply_cli_args(&mut self, args: &ArgMatches) -> Result<(), &'static str> { + if args.is_present("http") { + self.enabled = true; + } + + if let Some(listen_address) = args.value_of("http-address") { + self.listen_address = listen_address.to_string(); + } + + if let Some(listen_port) = args.value_of("http-port") { + self.listen_port = listen_port.to_string(); + } + + Ok(()) + } +} + /// Build the `iron` HTTP server, defining the core routes. pub fn create_iron_http_server( beacon_chain: Arc>, diff --git a/beacon_node/rpc/Cargo.toml b/beacon_node/rpc/Cargo.toml index a361c94ab..d707cc36d 100644 --- a/beacon_node/rpc/Cargo.toml +++ b/beacon_node/rpc/Cargo.toml @@ -20,6 +20,8 @@ clap = "2.32.0" store = { path = "../store" } dirs = "1.0.3" futures = "0.1.23" +serde = "1.0" +serde_derive = "1.0" slog = "^2.2.3" slog-term = "^2.4.0" slog-async = "^2.3.0" diff --git a/beacon_node/rpc/src/config.rs b/beacon_node/rpc/src/config.rs index e21c2f7a8..0f031ddc6 100644 --- a/beacon_node/rpc/src/config.rs +++ b/beacon_node/rpc/src/config.rs @@ -1,7 +1,9 @@ +use clap::ArgMatches; +use serde_derive::{Deserialize, Serialize}; use std::net::Ipv4Addr; /// RPC Configuration -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Serialize, Deserialize)] pub struct Config { /// Enable the RPC server. pub enabled: bool, @@ -20,3 +22,23 @@ impl Default for Config { } } } + +impl Config { + pub fn apply_cli_args(&mut self, args: &ArgMatches) -> Result<(), &'static str> { + if args.is_present("rpc") { + self.enabled = true; + } + + if let Some(rpc_address) = args.value_of("rpc-address") { + self.listen_address = rpc_address + .parse::() + .map_err(|_| "rpc-address is not IPv4 address")?; + } + + if let Some(rpc_port) = args.value_of("rpc-port") { + self.port = rpc_port.parse::().map_err(|_| "rpc-port is not u16")?; + } + + Ok(()) + } +} diff --git a/beacon_node/src/main.rs b/beacon_node/src/main.rs index 65f1899a0..68dbf6a74 100644 --- a/beacon_node/src/main.rs +++ b/beacon_node/src/main.rs @@ -4,7 +4,7 @@ mod run; use clap::{App, Arg}; use client::ClientConfig; -use slog::{error, o, Drain}; +use slog::{crit, o, Drain}; fn main() { let decorator = slog_term::TermDecorator::new().build(); @@ -29,21 +29,14 @@ fn main() { Arg::with_name("listen-address") .long("listen-address") .value_name("Listen Address") - .help("The Network address to listen for p2p connections.") - .takes_value(true), - ) - .arg( - Arg::with_name("port") - .long("port") - .value_name("PORT") - .help("Network listen port for p2p connections.") + .help("One or more comma-delimited multi-addresses to listen for p2p connections.") .takes_value(true), ) .arg( Arg::with_name("boot-nodes") .long("boot-nodes") .value_name("BOOTNODES") - .help("A list of comma separated multi addresses representing bootnodes to connect to.") + .help("One or more comma-delimited multi-addresses to bootstrap the p2p network.") .takes_value(true), ) // rpc related arguments @@ -101,11 +94,18 @@ fn main() { ) .get_matches(); - // invalid arguments, panic - let config = ClientConfig::parse_args(matches, &logger).unwrap(); + let mut config = ClientConfig::default(); + + match config.apply_cli_args(&matches) { + Ok(()) => (), + Err(s) => { + crit!(logger, "Failed to parse CLI arguments"; "error" => s); + return; + } + }; match run::run_beacon_node(config, &logger) { Ok(_) => {} - Err(e) => error!(logger, "Beacon node failed because {:?}", e), + Err(e) => crit!(logger, "Beacon node failed to start"; "reason" => format!("{:}", e)), } } diff --git a/beacon_node/src/run.rs b/beacon_node/src/run.rs index d8ff202bf..f3d656ad3 100644 --- a/beacon_node/src/run.rs +++ b/beacon_node/src/run.rs @@ -1,11 +1,13 @@ use client::{ - error, notifier, BeaconChainTypes, Client, ClientConfig, DBType, TestnetDiskBeaconChainTypes, - TestnetMemoryBeaconChainTypes, + error, notifier, BeaconChainTypes, Client, ClientConfig, InitialiseBeaconChain, + TestnetDiskBeaconChainTypes, TestnetMemoryBeaconChainTypes, }; use futures::sync::oneshot; use futures::Future; -use slog::info; +use slog::{error, info}; use std::cell::RefCell; +use std::path::Path; +use std::path::PathBuf; use store::{DiskStore, MemoryStore}; use tokio::runtime::Builder; use tokio::runtime::Runtime; @@ -19,51 +21,58 @@ pub fn run_beacon_node(config: ClientConfig, log: &slog::Logger) -> error::Resul .build() .map_err(|e| format!("{:?}", e))?; - // Log configuration - info!(log, "Listening on {:?}", &config.net_conf.listen_addresses; - "data_dir" => &config.data_dir.to_str(), - "port" => &config.net_conf.listen_port); - let executor = runtime.executor(); - match config.db_type { - DBType::Disk => { - info!( - log, - "BeaconNode starting"; - "type" => "TestnetDiskBeaconChainTypes" - ); + let db_path: PathBuf = config + .db_path() + .ok_or_else::(|| "Unable to access database path".into())?; + let db_type = &config.db_type; + let spec = &config.spec; - let store = DiskStore::open(&config.db_name).expect("Unable to open DB."); + let other_config = config.clone(); - let client: Client = - Client::new(config, store, log.clone(), &executor)?; - - run(client, executor, runtime, log) + let result = match (db_type.as_str(), spec.as_str()) { + ("disk", "testnet") => { + run::(&db_path, config, executor, runtime, log) } - DBType::Memory => { - info!( - log, - "BeaconNode starting"; - "type" => "TestnetMemoryBeaconChainTypes" - ); - - let store = MemoryStore::open(); - - let client: Client = - Client::new(config, store, log.clone(), &executor)?; - - run(client, executor, runtime, log) + ("memory", "testnet") => { + run::(&db_path, config, executor, runtime, log) } + (db_type, spec) => { + error!(log, "Unknown runtime configuration"; "spec" => spec, "db_type" => db_type); + Err("Unknown specification and/or db_type.".into()) + } + }; + + if result.is_ok() { + info!( + log, + "Started beacon node"; + "p2p_listen_addresses" => format!("{:?}", &other_config.network.listen_addresses()), + "data_dir" => format!("{:?}", other_config.data_dir()), + "spec" => &other_config.spec, + "db_type" => &other_config.db_type, + ); } + + result } -pub fn run( - client: Client, +pub fn run( + db_path: &Path, + config: ClientConfig, executor: TaskExecutor, mut runtime: Runtime, log: &slog::Logger, -) -> error::Result<()> { +) -> error::Result<()> +where + T: BeaconChainTypes + InitialiseBeaconChain + Send + Sync + 'static + Clone, + T::Store: OpenDatabase, +{ + let store = T::Store::open_database(&db_path)?; + + let client: Client = Client::new(config, store, log.clone(), &executor)?; + // run service until ctrl-c let (ctrlc_send, ctrlc_oneshot) = oneshot::channel(); let ctrlc_send_c = RefCell::new(Some(ctrlc_send)); @@ -91,3 +100,22 @@ pub fn run( runtime.shutdown_on_idle().wait().unwrap(); Ok(()) } + +/// A convenience trait, providing a method to open a database. +/// +/// Panics if unable to open the database. +pub trait OpenDatabase: Sized { + fn open_database(path: &Path) -> error::Result; +} + +impl OpenDatabase for MemoryStore { + fn open_database(_path: &Path) -> error::Result { + Ok(MemoryStore::open()) + } +} + +impl OpenDatabase for DiskStore { + fn open_database(path: &Path) -> error::Result { + DiskStore::open(path).map_err(|e| format!("Unable to open database: {:?}", e).into()) + } +} diff --git a/beacon_node/store/src/disk_db.rs b/beacon_node/store/src/disk_db.rs index eb2b885c6..669547ab9 100644 --- a/beacon_node/store/src/disk_db.rs +++ b/beacon_node/store/src/disk_db.rs @@ -1,6 +1,5 @@ extern crate rocksdb; -// use super::stores::COLUMNS; use super::{ClientDB, DBError, DBValue}; use rocksdb::Error as RocksError; use rocksdb::{Options, DB};