diff --git a/Cargo.lock b/Cargo.lock index 611cdf57a3..9b30c138e7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -513,6 +513,7 @@ dependencies = [ "serde", "serde_derive", "serde_json", + "serde_yaml", "slog", "slog-async", "slog-scope", @@ -3339,8 +3340,10 @@ dependencies = [ "lighthouse_network", "lighthouse_version", "malloc_utils", + "sensitive_url", "serde", "serde_json", + "serde_yaml", "slashing_protection", "slog", "sloggers", diff --git a/beacon_node/network/src/beacon_processor/worker/gossip_methods.rs b/beacon_node/network/src/beacon_processor/worker/gossip_methods.rs index 72cb3a7ee1..bb85d063e9 100644 --- a/beacon_node/network/src/beacon_processor/worker/gossip_methods.rs +++ b/beacon_node/network/src/beacon_processor/worker/gossip_methods.rs @@ -772,6 +772,7 @@ impl Worker { } // TODO(merge): reconsider peer scoring for this event. Err(e @BlockError::ExecutionPayloadError(ExecutionPayloadError::RequestFailed(_))) + | Err(e @ BlockError::ExecutionPayloadError(ExecutionPayloadError::UnverifiedNonOptimisticCandidate)) | Err(e @BlockError::ExecutionPayloadError(ExecutionPayloadError::NoExecutionConnection)) => { debug!(self.log, "Could not verify block for gossip, ignoring the block"; "error" => %e); diff --git a/boot_node/Cargo.toml b/boot_node/Cargo.toml index 1d86da52e5..471d9d1e27 100644 --- a/boot_node/Cargo.toml +++ b/boot_node/Cargo.toml @@ -23,4 +23,5 @@ hex = "0.4.2" serde = "1.0.116" serde_derive = "1.0.116" serde_json = "1.0.66" +serde_yaml = "0.8.13" eth2_network_config = { path = "../common/eth2_network_config" } diff --git a/boot_node/src/lib.rs b/boot_node/src/lib.rs index 6b933013fc..baa7c69322 100644 --- a/boot_node/src/lib.rs +++ b/boot_node/src/lib.rs @@ -95,6 +95,15 @@ fn main( serde_json::to_writer(&mut file, &config_sz) .map_err(|e| format!("Error serializing config: {:?}", e))?; } + if let Some(dump_path) = clap_utils::parse_optional::(lh_matches, "dump-chain-config")? + { + let chain_config = + types::Config::from_chain_spec::(ð2_network_config.chain_spec::()?); + let mut file = File::create(dump_path) + .map_err(|e| format!("Failed to create dumped chain config: {:?}", e))?; + serde_yaml::to_writer(&mut file, &chain_config) + .map_err(|e| format!("Error serializing chain config: {:?}", e))?; + } // Run the boot node if !lh_matches.is_present("immediate-shutdown") { diff --git a/common/sensitive_url/src/lib.rs b/common/sensitive_url/src/lib.rs index b7e620485a..7a3cbae20c 100644 --- a/common/sensitive_url/src/lib.rs +++ b/common/sensitive_url/src/lib.rs @@ -10,7 +10,7 @@ pub enum SensitiveError { } // Wrapper around Url which provides a custom `Display` implementation to protect user secrets. -#[derive(Clone)] +#[derive(Clone, PartialEq)] pub struct SensitiveUrl { pub full: Url, pub redacted: String, diff --git a/consensus/types/src/chain_spec.rs b/consensus/types/src/chain_spec.rs index 3210920ae8..6cdddcd128 100644 --- a/consensus/types/src/chain_spec.rs +++ b/consensus/types/src/chain_spec.rs @@ -750,6 +750,7 @@ impl ChainSpec { .expect("addition does not overflow"), terminal_block_hash: Hash256::zero(), terminal_block_hash_activation_epoch: Epoch::new(u64::MAX), + safe_slots_to_import_optimistically: 128u64, /* * Network specific @@ -1239,6 +1240,7 @@ mod yaml_tests { #TERMINAL_TOTAL_DIFFICULTY: 115792089237316195423570985008687907853269984665640564039457584007913129638911 #TERMINAL_BLOCK_HASH: 0x0000000000000000000000000000000000000000000000000000000000000001 #TERMINAL_BLOCK_HASH_ACTIVATION_EPOCH: 18446744073709551614 + #SAFE_SLOTS_TO_IMPORT_OPTIMISTICALLY: 2 MIN_GENESIS_ACTIVE_VALIDATOR_COUNT: 16384 MIN_GENESIS_TIME: 1606824000 GENESIS_FORK_VERSION: 0x00000000 @@ -1278,6 +1280,10 @@ mod yaml_tests { chain_spec.terminal_block_hash_activation_epoch, default_terminal_block_hash_activation_epoch() ); + assert_eq!( + chain_spec.safe_slots_to_import_optimistically, + default_safe_slots_to_import_optimistically() + ); assert_eq!( chain_spec.bellatrix_fork_epoch, diff --git a/lighthouse/Cargo.toml b/lighthouse/Cargo.toml index 5cf04b3b4f..a2477c64fd 100644 --- a/lighthouse/Cargo.toml +++ b/lighthouse/Cargo.toml @@ -41,6 +41,7 @@ lighthouse_metrics = { path = "../common/lighthouse_metrics" } lazy_static = "1.4.0" serde = { version = "1.0.116", features = ["derive"] } serde_json = "1.0.59" +serde_yaml = "0.8.13" task_executor = { path = "../common/task_executor" } malloc_utils = { path = "../common/malloc_utils" } directory = { path = "../common/directory" } @@ -51,6 +52,7 @@ tempfile = "3.1.0" validator_dir = { path = "../common/validator_dir" } slashing_protection = { path = "../validator_client/slashing_protection" } lighthouse_network = { path = "../beacon_node/lighthouse_network" } +sensitive_url = { path = "../common/sensitive_url" } [[test]] name = "lighthouse_tests" diff --git a/lighthouse/src/main.rs b/lighthouse/src/main.rs index 49987ce902..890c4520da 100644 --- a/lighthouse/src/main.rs +++ b/lighthouse/src/main.rs @@ -17,7 +17,7 @@ use std::fs::File; use std::path::PathBuf; use std::process::exit; use task_executor::ShutdownReason; -use types::{EthSpec, EthSpecId}; +use types::{Config, EthSpec, EthSpecId}; use validator_client::ProductionValidatorClient; fn bls_library_name() -> &'static str { @@ -193,6 +193,14 @@ fn main() { .takes_value(true) .global(true) ) + .arg( + Arg::with_name("dump-chain-config") + .long("dump-chain-config") + .hidden(true) + .help("Dumps the chain config to a desired location. Used for testing only.") + .takes_value(true) + .global(true) + ) .arg( Arg::with_name("immediate-shutdown") .long("immediate-shutdown") @@ -494,6 +502,15 @@ fn run( serde_json::to_writer(&mut file, &config) .map_err(|e| format!("Error serializing config: {:?}", e))?; }; + if let Some(dump_path) = + clap_utils::parse_optional::(matches, "dump-chain-config")? + { + let chain_config = Config::from_chain_spec::(&context.eth2_config.spec); + let mut file = File::create(dump_path) + .map_err(|e| format!("Failed to create dumped chain config: {:?}", e))?; + serde_yaml::to_writer(&mut file, &chain_config) + .map_err(|e| format!("Error serializing chain config: {:?}", e))?; + }; executor.clone().spawn( async move { @@ -527,6 +544,15 @@ fn run( serde_json::to_writer(&mut file, &config) .map_err(|e| format!("Error serializing config: {:?}", e))?; }; + if let Some(dump_path) = + clap_utils::parse_optional::(matches, "dump-chain-config")? + { + let chain_config = Config::from_chain_spec::(&context.eth2_config.spec); + let mut file = File::create(dump_path) + .map_err(|e| format!("Failed to create dumped chain config: {:?}", e))?; + serde_yaml::to_writer(&mut file, &chain_config) + .map_err(|e| format!("Error serializing chain config: {:?}", e))?; + }; if !shutdown_flag { executor.clone().spawn( async move { diff --git a/lighthouse/tests/beacon_node.rs b/lighthouse/tests/beacon_node.rs index 37c4359453..2facd6d860 100644 --- a/lighthouse/tests/beacon_node.rs +++ b/lighthouse/tests/beacon_node.rs @@ -10,7 +10,7 @@ use std::process::Command; use std::str::FromStr; use std::string::ToString; use tempfile::TempDir; -use types::{Address, Checkpoint, Epoch, Hash256}; +use types::{Address, Checkpoint, Epoch, Hash256, MainnetEthSpec}; use unused_port::{unused_tcp_port, unused_udp_port}; const DEFAULT_ETH1_ENDPOINT: &str = "http://localhost:8545/"; @@ -206,7 +206,35 @@ fn eth1_purge_cache_flag() { .with_config(|config| assert!(config.eth1.purge_cache)); } -// Tests for Merge flags. +// Tests for Bellatrix flags. +#[test] +fn merge_flag() { + CommandLineTest::new() + .flag("merge", None) + .run_with_zero_port() + .with_config(|config| assert!(config.execution_endpoints.is_some())); +} +#[test] +fn merge_execution_endpoints_flag() { + use sensitive_url::SensitiveUrl; + let urls = vec!["http://sigp.io/no-way:1337", "http://infura.not_real:4242"]; + let endpoints = urls + .iter() + .map(|s| SensitiveUrl::parse(s).unwrap()) + .collect::>(); + let mut endpoint_arg = urls[0].to_string(); + for url in urls.into_iter().skip(1) { + endpoint_arg.push(','); + endpoint_arg.push_str(url); + } + // this is way better but intersperse is still a nightly feature :/ + // let endpoint_arg: String = urls.into_iter().intersperse(",").collect(); + CommandLineTest::new() + .flag("merge", None) + .flag("execution-endpoints", Some(&endpoint_arg)) + .run_with_zero_port() + .with_config(|config| assert_eq!(config.execution_endpoints.as_ref(), Some(&endpoints))); +} #[test] fn merge_fee_recipient_flag() { CommandLineTest::new() @@ -223,6 +251,46 @@ fn merge_fee_recipient_flag() { ) }); } +#[test] +fn terminal_total_difficulty_override_flag() { + use beacon_node::beacon_chain::types::Uint256; + CommandLineTest::new() + .flag("terminal-total-difficulty-override", Some("1337424242")) + .run_with_zero_port() + .with_spec::(|spec| { + assert_eq!(spec.terminal_total_difficulty, Uint256::from(1337424242)) + }); +} +#[test] +fn terminal_block_hash_and_activation_epoch_override_flags() { + use beacon_node::beacon_chain::types::Hash256; + CommandLineTest::new() + .flag("terminal-block-hash-epoch-override", Some("1337")) + .flag( + "terminal-block-hash-override", + Some("0x4242424242424242424242424242424242424242424242424242424242424242"), + ) + .run_with_zero_port() + .with_spec::(|spec| { + assert_eq!( + spec.terminal_block_hash, + Hash256::from_str( + "0x4242424242424242424242424242424242424242424242424242424242424242" + ) + .unwrap() + ); + assert_eq!(spec.terminal_block_hash_activation_epoch, 1337); + }); +} +#[test] +fn safe_slots_to_import_optimistically_flag() { + CommandLineTest::new() + .flag("safe-slots-to-import-optimistically", Some("421337")) + .run_with_zero_port() + .with_spec::(|spec| { + assert_eq!(spec.safe_slots_to_import_optimistically, 421337) + }); +} // Tests for Network flags. #[test] @@ -410,6 +478,15 @@ fn zero_ports_flag() { assert_eq!(config.http_metrics.listen_port, 0); }); } +#[test] +fn network_load_flag() { + CommandLineTest::new() + .flag("network-load", Some("4")) + .run_with_zero_port() + .with_config(|config| { + assert_eq!(config.network.network_load, 4); + }); +} // Tests for ENR flags. #[test] @@ -527,6 +604,13 @@ fn http_allow_origin_all_flag() { .with_config(|config| assert_eq!(config.http_api.allow_origin, Some("*".to_string()))); } #[test] +fn http_allow_sync_stalled_flag() { + CommandLineTest::new() + .flag("http-allow-sync-stalled", None) + .run_with_zero_port() + .with_config(|config| assert_eq!(config.http_api.allow_sync_stalled, true)); +} +#[test] fn http_tls_flags() { let dir = TempDir::new().expect("Unable to create temporary directory"); CommandLineTest::new() diff --git a/lighthouse/tests/exec.rs b/lighthouse/tests/exec.rs index 9526a1caf8..d003f46dd1 100644 --- a/lighthouse/tests/exec.rs +++ b/lighthouse/tests/exec.rs @@ -5,6 +5,7 @@ use std::path::PathBuf; use std::process::{Command, Output}; use std::str::from_utf8; use tempfile::TempDir; +use types::{ChainSpec, Config, EthSpec}; pub trait CommandLineTestExec { type Config: DeserializeOwned; @@ -29,6 +30,7 @@ pub trait CommandLineTestExec { // Setup temp directory. let tmp_dir = TempDir::new().expect("Unable to create temporary directory"); let tmp_config_path: PathBuf = tmp_dir.path().join("config.json"); + let tmp_chain_config_path: PathBuf = tmp_dir.path().join("chain_spec.yaml"); // Add args --datadir --dump-config --immediate-shutdown let cmd = self.cmd_mut(); @@ -36,6 +38,8 @@ pub trait CommandLineTestExec { .arg(tmp_dir.path().as_os_str()) .arg(format!("--{}", "--dump-config")) .arg(tmp_config_path.as_os_str()) + .arg(format!("--{}", "--dump-chain-config")) + .arg(tmp_chain_config_path.as_os_str()) .arg("--immediate-shutdown"); // Run the command. @@ -47,8 +51,13 @@ pub trait CommandLineTestExec { // Grab the config. let config_file = File::open(tmp_config_path).expect("Unable to open dumped config"); let config: Self::Config = from_reader(config_file).expect("Unable to deserialize config"); + // Grab the chain config. + let spec_file = + File::open(tmp_chain_config_path).expect("Unable to open dumped chain spec"); + let chain_config: Config = + serde_yaml::from_reader(spec_file).expect("Unable to deserialize config"); - CompletedTest::new(config, tmp_dir) + CompletedTest::new(config, chain_config, tmp_dir) } /// Executes the `Command` returned by `Self::cmd_mut` dumps the configuration and @@ -59,11 +68,14 @@ pub trait CommandLineTestExec { // Setup temp directory. let tmp_dir = TempDir::new().expect("Unable to create temporary directory"); let tmp_config_path: PathBuf = tmp_dir.path().join("config.json"); + let tmp_chain_config_path: PathBuf = tmp_dir.path().join("chain_spec.yaml"); // Add args --datadir --dump-config --immediate-shutdown let cmd = self.cmd_mut(); cmd.arg(format!("--{}", "--dump-config")) .arg(tmp_config_path.as_os_str()) + .arg(format!("--{}", "--dump-chain-config")) + .arg(tmp_chain_config_path.as_os_str()) .arg("--immediate-shutdown"); // Run the command. @@ -75,8 +87,13 @@ pub trait CommandLineTestExec { // Grab the config. let config_file = File::open(tmp_config_path).expect("Unable to open dumped config"); let config: Self::Config = from_reader(config_file).expect("Unable to deserialize config"); + // Grab the chain config. + let spec_file = + File::open(tmp_chain_config_path).expect("Unable to open dumped chain spec"); + let chain_config: Config = + serde_yaml::from_reader(spec_file).expect("Unable to deserialize config"); - CompletedTest::new(config, tmp_dir) + CompletedTest::new(config, chain_config, tmp_dir) } } @@ -95,19 +112,35 @@ fn output_result(cmd: &mut Command) -> Result { pub struct CompletedTest { config: C, + chain_config: Config, dir: TempDir, } impl CompletedTest { - fn new(config: C, dir: TempDir) -> Self { - CompletedTest { config, dir } + fn new(config: C, chain_config: Config, dir: TempDir) -> Self { + CompletedTest { + config, + chain_config, + dir, + } } pub fn with_config(self, func: F) { func(&self.config); } + pub fn with_spec(self, func: F) { + let spec = ChainSpec::from_config::(&self.chain_config).unwrap(); + func(spec); + } + pub fn with_config_and_dir(self, func: F) { func(&self.config, &self.dir); } + + #[allow(dead_code)] + pub fn with_config_and_spec(self, func: F) { + let spec = ChainSpec::from_config::(&self.chain_config).unwrap(); + func(&self.config, spec); + } }