Ensure difficulty/hash/epoch overrides change the ChainSpec (#2798)

* Unify loading of eth2_network_config

* Apply overrides at lighthouse binary level

* Remove duplicate override values

* Add merge values to existing net configs

* Make override flags global

* Add merge fields to testing config

* Add one to TTD

* Fix failing engine tests

* Fix test compile error

* Remove TTD flags

* Move get_eth2_network_config

* Fix warn

* Address review comments
This commit is contained in:
Paul Hauner 2021-11-16 11:46:12 +11:00
parent 47db682d7e
commit afe59afacd
No known key found for this signature in database
GPG Key ID: 5E2CFF9B75FA63DF
25 changed files with 391 additions and 267 deletions

152
Cargo.lock generated
View File

@ -301,6 +301,7 @@ dependencies = [
"eth2_ssz 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "eth2_ssz 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"eth2_ssz_derive 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "eth2_ssz_derive 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"eth2_ssz_types 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "eth2_ssz_types 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"execution_layer",
"fork_choice", "fork_choice",
"futures", "futures",
"genesis", "genesis",
@ -318,6 +319,7 @@ dependencies = [
"rand 0.7.3", "rand 0.7.3",
"rayon", "rayon",
"safe_arith", "safe_arith",
"sensitive_url",
"serde", "serde",
"serde_derive", "serde_derive",
"slasher", "slasher",
@ -480,6 +482,7 @@ dependencies = [
"beacon_node", "beacon_node",
"clap", "clap",
"clap_utils", "clap_utils",
"eth2_network_config",
"eth2_ssz 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "eth2_ssz 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"hex", "hex",
"lighthouse_network", "lighthouse_network",
@ -682,6 +685,7 @@ dependencies = [
"dirs", "dirs",
"eth2_network_config", "eth2_network_config",
"eth2_ssz 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "eth2_ssz 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"ethereum-types 0.12.1",
"hex", "hex",
] ]
@ -697,6 +701,7 @@ dependencies = [
"eth1", "eth1",
"eth2", "eth2",
"eth2_config", "eth2_config",
"execution_layer",
"genesis", "genesis",
"http_api", "http_api",
"http_metrics", "http_metrics",
@ -1273,6 +1278,7 @@ dependencies = [
"eth2_ssz 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "eth2_ssz 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"eth2_ssz_derive 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "eth2_ssz_derive 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"ethereum-types 0.12.1", "ethereum-types 0.12.1",
"fork_choice",
"fs2", "fs2",
"hex", "hex",
"rayon", "rayon",
@ -1571,6 +1577,7 @@ dependencies = [
name = "eth2_serde_utils" name = "eth2_serde_utils"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"ethereum-types 0.12.1",
"hex", "hex",
"serde", "serde",
"serde_derive", "serde_derive",
@ -1782,6 +1789,35 @@ dependencies = [
"uint 0.9.1", "uint 0.9.1",
] ]
[[package]]
name = "execution_layer"
version = "0.1.0"
dependencies = [
"async-trait",
"bytes",
"environment",
"eth1",
"eth2_serde_utils 0.1.0",
"eth2_ssz_types 0.2.1",
"exit-future",
"futures",
"hex",
"lru",
"parking_lot",
"reqwest",
"sensitive_url",
"serde",
"serde_json",
"slog",
"slot_clock",
"task_executor",
"tokio",
"tree_hash 0.4.0",
"tree_hash_derive 0.4.0",
"types",
"warp 0.3.0",
]
[[package]] [[package]]
name = "exit-future" name = "exit-future"
version = "0.2.0" version = "0.2.0"
@ -2383,7 +2419,7 @@ dependencies = [
"tokio-stream", "tokio-stream",
"tree_hash 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "tree_hash 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"types", "types",
"warp", "warp 0.3.2",
"warp_utils", "warp_utils",
] ]
@ -2404,7 +2440,7 @@ dependencies = [
"store", "store",
"tokio", "tokio",
"types", "types",
"warp", "warp 0.3.2",
"warp_utils", "warp_utils",
] ]
@ -2580,6 +2616,15 @@ dependencies = [
"hashbrown", "hashbrown",
] ]
[[package]]
name = "input_buffer"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f97967975f448f1a7ddb12b0bc41069d09ed6a1c161a92687e057325db35d413"
dependencies = [
"bytes",
]
[[package]] [[package]]
name = "instant" name = "instant"
version = "0.1.12" version = "0.1.12"
@ -2709,6 +2754,7 @@ dependencies = [
"eth2_ssz 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "eth2_ssz 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"eth2_wallet", "eth2_wallet",
"genesis", "genesis",
"int_to_bytes",
"lighthouse_network", "lighthouse_network",
"lighthouse_version", "lighthouse_version",
"log", "log",
@ -3591,6 +3637,24 @@ version = "0.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e5ce46fe64a9d73be07dcbe690a38ce1b293be448fd8ce1e6c1b8062c9f72c6a" checksum = "e5ce46fe64a9d73be07dcbe690a38ce1b293be448fd8ce1e6c1b8062c9f72c6a"
[[package]]
name = "multipart"
version = "0.17.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d050aeedc89243f5347c3e237e3e13dc76fbe4ae3742a57b94dc14f69acf76d4"
dependencies = [
"buf_redux",
"httparse",
"log",
"mime",
"mime_guess",
"quick-error",
"rand 0.7.3",
"safemem",
"tempfile",
"twoway",
]
[[package]] [[package]]
name = "multipart" name = "multipart"
version = "0.18.0" version = "0.18.0"
@ -5986,6 +6050,19 @@ dependencies = [
"tokio-util", "tokio-util",
] ]
[[package]]
name = "tokio-tungstenite"
version = "0.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e1a5f475f1b9d077ea1017ecbc60890fda8e54942d680ca0b1d2b47cfa2d861b"
dependencies = [
"futures-util",
"log",
"pin-project 1.0.8",
"tokio",
"tungstenite 0.12.0",
]
[[package]] [[package]]
name = "tokio-tungstenite" name = "tokio-tungstenite"
version = "0.15.0" version = "0.15.0"
@ -5996,7 +6073,7 @@ dependencies = [
"log", "log",
"pin-project 1.0.8", "pin-project 1.0.8",
"tokio", "tokio",
"tungstenite", "tungstenite 0.14.0",
] ]
[[package]] [[package]]
@ -6063,6 +6140,16 @@ dependencies = [
"lazy_static", "lazy_static",
] ]
[[package]]
name = "tracing-futures"
version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "97d095ae15e245a057c8e8451bab9b3ee1e1f68e9ba2b4fbc18d0ac5237835f2"
dependencies = [
"pin-project 1.0.8",
"tracing",
]
[[package]] [[package]]
name = "tracing-log" name = "tracing-log"
version = "0.1.2" version = "0.1.2"
@ -6222,6 +6309,25 @@ version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642" checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642"
[[package]]
name = "tungstenite"
version = "0.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ada8297e8d70872fa9a551d93250a9f407beb9f37ef86494eb20012a2ff7c24"
dependencies = [
"base64 0.13.0",
"byteorder",
"bytes",
"http",
"httparse",
"input_buffer",
"log",
"rand 0.8.4",
"sha-1",
"url",
"utf-8",
]
[[package]] [[package]]
name = "tungstenite" name = "tungstenite"
version = "0.14.0" version = "0.14.0"
@ -6270,7 +6376,7 @@ dependencies = [
"derivative", "derivative",
"eth2_hashing 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "eth2_hashing 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"eth2_interop_keypairs", "eth2_interop_keypairs",
"eth2_serde_utils 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "eth2_serde_utils 0.1.0",
"eth2_ssz 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "eth2_ssz 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"eth2_ssz_derive 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "eth2_ssz_derive 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"eth2_ssz_types 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "eth2_ssz_types 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
@ -6490,7 +6596,7 @@ dependencies = [
"types", "types",
"url", "url",
"validator_dir", "validator_dir",
"warp", "warp 0.3.2",
"warp_utils", "warp_utils",
] ]
@ -6556,6 +6662,36 @@ dependencies = [
"try-lock", "try-lock",
] ]
[[package]]
name = "warp"
version = "0.3.0"
source = "git+https://github.com/macladson/warp?rev=dfa259e#dfa259e19b7490e6bc4bf247e8b76f671d29a0eb"
dependencies = [
"bytes",
"futures",
"headers",
"http",
"hyper",
"log",
"mime",
"mime_guess",
"multipart 0.17.1",
"percent-encoding",
"pin-project 1.0.8",
"scoped-tls",
"serde",
"serde_json",
"serde_urlencoded",
"tokio",
"tokio-rustls",
"tokio-stream",
"tokio-tungstenite 0.13.0",
"tokio-util",
"tower-service",
"tracing",
"tracing-futures",
]
[[package]] [[package]]
name = "warp" name = "warp"
version = "0.3.2" version = "0.3.2"
@ -6570,7 +6706,7 @@ dependencies = [
"log", "log",
"mime", "mime",
"mime_guess", "mime_guess",
"multipart", "multipart 0.18.0",
"percent-encoding", "percent-encoding",
"pin-project 1.0.8", "pin-project 1.0.8",
"scoped-tls", "scoped-tls",
@ -6580,7 +6716,7 @@ dependencies = [
"tokio", "tokio",
"tokio-rustls", "tokio-rustls",
"tokio-stream", "tokio-stream",
"tokio-tungstenite", "tokio-tungstenite 0.15.0",
"tokio-util", "tokio-util",
"tower-service", "tower-service",
"tracing", "tracing",
@ -6600,7 +6736,7 @@ dependencies = [
"state_processing", "state_processing",
"tokio", "tokio",
"types", "types",
"warp", "warp 0.3.2",
] ]
[[package]] [[package]]

View File

@ -2893,7 +2893,9 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
let parent_hash; let parent_hash;
if !is_merge_complete(&state) { if !is_merge_complete(&state) {
let terminal_pow_block_hash = execution_layer let terminal_pow_block_hash = execution_layer
.block_on(|execution_layer| execution_layer.get_terminal_pow_block_hash()) .block_on(|execution_layer| {
execution_layer.get_terminal_pow_block_hash(&self.spec)
})
.map_err(BlockProductionError::TerminalPoWBlockLookupFailed)?; .map_err(BlockProductionError::TerminalPoWBlockLookupFailed)?;
if let Some(terminal_pow_block_hash) = terminal_pow_block_hash { if let Some(terminal_pow_block_hash) = terminal_pow_block_hash {

View File

@ -1119,7 +1119,10 @@ impl<'a, T: BeaconChainTypes> FullyVerifiedBlock<'a, T> {
let is_valid_terminal_pow_block = execution_layer let is_valid_terminal_pow_block = execution_layer
.block_on(|execution_layer| { .block_on(|execution_layer| {
execution_layer.is_valid_terminal_pow_block_hash(execution_payload.parent_hash) execution_layer.is_valid_terminal_pow_block_hash(
execution_payload.parent_hash,
&chain.spec,
)
}) })
.map_err(ExecutionPayloadError::from)?; .map_err(ExecutionPayloadError::from)?;

View File

@ -330,7 +330,6 @@ where
} }
pub fn execution_layer(mut self, urls: &[&str]) -> Self { pub fn execution_layer(mut self, urls: &[&str]) -> Self {
let spec = self.spec.clone().expect("cannot build without spec");
assert!( assert!(
self.execution_layer.is_none(), self.execution_layer.is_none(),
"execution layer already defined" "execution layer already defined"
@ -345,8 +344,6 @@ where
.unwrap(); .unwrap();
let execution_layer = ExecutionLayer::from_urls( let execution_layer = ExecutionLayer::from_urls(
urls, urls,
spec.terminal_total_difficulty,
spec.terminal_block_hash,
Some(Address::repeat_byte(42)), Some(Address::repeat_byte(42)),
el_runtime.task_executor.clone(), el_runtime.task_executor.clone(),
el_runtime.log.clone(), el_runtime.log.clone(),
@ -364,6 +361,7 @@ where
spec.terminal_total_difficulty, spec.terminal_total_difficulty,
DEFAULT_TERMINAL_BLOCK, DEFAULT_TERMINAL_BLOCK,
spec.terminal_block_hash, spec.terminal_block_hash,
spec.terminal_block_hash_activation_epoch,
); );
self.execution_layer = Some(mock.el.clone()); self.execution_layer = Some(mock.el.clone());
self.mock_execution_layer = Some(mock); self.mock_execution_layer = Some(mock);

View File

@ -148,19 +148,10 @@ where
None None
}; };
let terminal_total_difficulty = config
.terminal_total_difficulty_override
.unwrap_or(spec.terminal_total_difficulty);
let terminal_block_hash = config
.terminal_block_hash_override
.unwrap_or(spec.terminal_block_hash);
let execution_layer = if let Some(execution_endpoints) = config.execution_endpoints { let execution_layer = if let Some(execution_endpoints) = config.execution_endpoints {
let context = runtime_context.service_context("exec".into()); let context = runtime_context.service_context("exec".into());
let execution_layer = ExecutionLayer::from_urls( let execution_layer = ExecutionLayer::from_urls(
execution_endpoints, execution_endpoints,
terminal_total_difficulty,
terminal_block_hash,
config.fee_recipient, config.fee_recipient,
context.executor.clone(), context.executor.clone(),
context.log().clone(), context.log().clone(),

View File

@ -1,11 +1,10 @@
use beacon_chain::types::Epoch;
use directory::DEFAULT_ROOT_DIR; use directory::DEFAULT_ROOT_DIR;
use network::NetworkConfig; use network::NetworkConfig;
use sensitive_url::SensitiveUrl; use sensitive_url::SensitiveUrl;
use serde_derive::{Deserialize, Serialize}; use serde_derive::{Deserialize, Serialize};
use std::fs; use std::fs;
use std::path::PathBuf; use std::path::PathBuf;
use types::{Address, Graffiti, Hash256, PublicKeyBytes, Uint256}; use types::{Address, Graffiti, PublicKeyBytes};
/// Default directory name for the freezer database under the top-level data dir. /// Default directory name for the freezer database under the top-level data dir.
const DEFAULT_FREEZER_DB_DIR: &str = "freezer_db"; const DEFAULT_FREEZER_DB_DIR: &str = "freezer_db";
@ -76,9 +75,6 @@ pub struct Config {
pub chain: beacon_chain::ChainConfig, pub chain: beacon_chain::ChainConfig,
pub eth1: eth1::Config, pub eth1: eth1::Config,
pub execution_endpoints: Option<Vec<SensitiveUrl>>, pub execution_endpoints: Option<Vec<SensitiveUrl>>,
pub terminal_total_difficulty_override: Option<Uint256>,
pub terminal_block_hash_override: Option<Hash256>,
pub terminal_block_hash_epoch_override: Option<Epoch>,
pub fee_recipient: Option<Address>, pub fee_recipient: Option<Address>,
pub http_api: http_api::Config, pub http_api: http_api::Config,
pub http_metrics: http_metrics::Config, pub http_metrics: http_metrics::Config,
@ -101,9 +97,6 @@ impl Default for Config {
sync_eth1_chain: false, sync_eth1_chain: false,
eth1: <_>::default(), eth1: <_>::default(),
execution_endpoints: None, execution_endpoints: None,
terminal_total_difficulty_override: None,
terminal_block_hash_override: None,
terminal_block_hash_epoch_override: None,
fee_recipient: None, fee_recipient: None,
disabled_forks: Vec::new(), disabled_forks: Vec::new(),
graffiti: Graffiti::default(), graffiti: Graffiti::default(),

View File

@ -18,6 +18,7 @@ use tokio::{
sync::{Mutex, MutexGuard}, sync::{Mutex, MutexGuard},
time::{sleep, sleep_until, Instant}, time::{sleep, sleep_until, Instant},
}; };
use types::ChainSpec;
pub use engine_api::{http::HttpJsonRpc, ExecutePayloadResponseStatus}; pub use engine_api::{http::HttpJsonRpc, ExecutePayloadResponseStatus};
@ -47,8 +48,6 @@ impl From<ApiError> for Error {
struct Inner { struct Inner {
engines: Engines<HttpJsonRpc>, engines: Engines<HttpJsonRpc>,
terminal_total_difficulty: Uint256,
terminal_block_hash: Hash256,
fee_recipient: Option<Address>, fee_recipient: Option<Address>,
execution_blocks: Mutex<LruCache<Hash256, ExecutionBlock>>, execution_blocks: Mutex<LruCache<Hash256, ExecutionBlock>>,
executor: TaskExecutor, executor: TaskExecutor,
@ -73,8 +72,6 @@ impl ExecutionLayer {
/// Instantiate `Self` with `urls.len()` engines, all using the JSON-RPC via HTTP. /// Instantiate `Self` with `urls.len()` engines, all using the JSON-RPC via HTTP.
pub fn from_urls( pub fn from_urls(
urls: Vec<SensitiveUrl>, urls: Vec<SensitiveUrl>,
terminal_total_difficulty: Uint256,
terminal_block_hash: Hash256,
fee_recipient: Option<Address>, fee_recipient: Option<Address>,
executor: TaskExecutor, executor: TaskExecutor,
log: Logger, log: Logger,
@ -98,8 +95,6 @@ impl ExecutionLayer {
latest_forkchoice_state: <_>::default(), latest_forkchoice_state: <_>::default(),
log: log.clone(), log: log.clone(),
}, },
terminal_total_difficulty,
terminal_block_hash,
fee_recipient, fee_recipient,
execution_blocks: Mutex::new(LruCache::new(EXECUTION_BLOCKS_LRU_CACHE_SIZE)), execution_blocks: Mutex::new(LruCache::new(EXECUTION_BLOCKS_LRU_CACHE_SIZE)),
executor, executor,
@ -121,14 +116,6 @@ impl ExecutionLayer {
&self.inner.executor &self.inner.executor
} }
fn terminal_total_difficulty(&self) -> Uint256 {
self.inner.terminal_total_difficulty
}
fn terminal_block_hash(&self) -> Hash256 {
self.inner.terminal_block_hash
}
fn fee_recipient(&self) -> Result<Address, Error> { fn fee_recipient(&self) -> Result<Address, Error> {
self.inner self.inner
.fee_recipient .fee_recipient
@ -455,11 +442,14 @@ impl ExecutionLayer {
/// `get_terminal_pow_block_hash` /// `get_terminal_pow_block_hash`
/// ///
/// https://github.com/ethereum/consensus-specs/blob/v1.1.0/specs/merge/validator.md /// https://github.com/ethereum/consensus-specs/blob/v1.1.0/specs/merge/validator.md
pub async fn get_terminal_pow_block_hash(&self) -> Result<Option<Hash256>, Error> { pub async fn get_terminal_pow_block_hash(
&self,
spec: &ChainSpec,
) -> Result<Option<Hash256>, Error> {
let hash_opt = self let hash_opt = self
.engines() .engines()
.first_success(|engine| async move { .first_success(|engine| async move {
if self.terminal_block_hash() != Hash256::zero() { if spec.terminal_block_hash != Hash256::zero() {
// Note: the specification is written such that if there are multiple blocks in // Note: the specification is written such that if there are multiple blocks in
// the PoW chain with the terminal block hash, then to select 0'th one. // the PoW chain with the terminal block hash, then to select 0'th one.
// //
@ -468,11 +458,12 @@ impl ExecutionLayer {
// hash. Such a scenario would be a devestating hash collision with external // hash. Such a scenario would be a devestating hash collision with external
// implications far outweighing those here. // implications far outweighing those here.
Ok(self Ok(self
.get_pow_block(engine, self.terminal_block_hash()) .get_pow_block(engine, spec.terminal_block_hash)
.await? .await?
.map(|block| block.block_hash)) .map(|block| block.block_hash))
} else { } else {
self.get_pow_block_hash_at_total_difficulty(engine).await self.get_pow_block_hash_at_total_difficulty(engine, spec)
.await
} }
}) })
.await .await
@ -482,8 +473,8 @@ impl ExecutionLayer {
info!( info!(
self.log(), self.log(),
"Found terminal block hash"; "Found terminal block hash";
"terminal_block_hash_override" => ?self.terminal_block_hash(), "terminal_block_hash_override" => ?spec.terminal_block_hash,
"terminal_total_difficulty" => ?self.terminal_total_difficulty(), "terminal_total_difficulty" => ?spec.terminal_total_difficulty,
"block_hash" => ?hash, "block_hash" => ?hash,
); );
} }
@ -503,6 +494,7 @@ impl ExecutionLayer {
async fn get_pow_block_hash_at_total_difficulty( async fn get_pow_block_hash_at_total_difficulty(
&self, &self,
engine: &Engine<HttpJsonRpc>, engine: &Engine<HttpJsonRpc>,
spec: &ChainSpec,
) -> Result<Option<Hash256>, ApiError> { ) -> Result<Option<Hash256>, ApiError> {
let mut ttd_exceeding_block = None; let mut ttd_exceeding_block = None;
let mut block = engine let mut block = engine
@ -518,7 +510,7 @@ impl ExecutionLayer {
// //
// https://github.com/ethereum/consensus-specs/issues/2636 // https://github.com/ethereum/consensus-specs/issues/2636
loop { loop {
if block.total_difficulty >= self.terminal_total_difficulty() { if block.total_difficulty >= spec.terminal_total_difficulty {
ttd_exceeding_block = Some(block.block_hash); ttd_exceeding_block = Some(block.block_hash);
// Try to prevent infinite loops. // Try to prevent infinite loops.
@ -565,6 +557,7 @@ impl ExecutionLayer {
pub async fn is_valid_terminal_pow_block_hash( pub async fn is_valid_terminal_pow_block_hash(
&self, &self,
block_hash: Hash256, block_hash: Hash256,
spec: &ChainSpec,
) -> Result<Option<bool>, Error> { ) -> Result<Option<bool>, Error> {
let broadcast_results = self let broadcast_results = self
.engines() .engines()
@ -574,7 +567,7 @@ impl ExecutionLayer {
self.get_pow_block(engine, pow_block.parent_hash).await? self.get_pow_block(engine, pow_block.parent_hash).await?
{ {
return Ok(Some( return Ok(Some(
self.is_valid_terminal_pow_block(pow_block, pow_parent), self.is_valid_terminal_pow_block(pow_block, pow_parent, spec),
)); ));
} }
} }
@ -618,15 +611,19 @@ impl ExecutionLayer {
/// This function should remain internal. /// This function should remain internal.
/// ///
/// External users should use `self.is_valid_terminal_pow_block_hash`. /// External users should use `self.is_valid_terminal_pow_block_hash`.
fn is_valid_terminal_pow_block(&self, block: ExecutionBlock, parent: ExecutionBlock) -> bool { fn is_valid_terminal_pow_block(
if block.block_hash == self.terminal_block_hash() { &self,
block: ExecutionBlock,
parent: ExecutionBlock,
spec: &ChainSpec,
) -> bool {
if block.block_hash == spec.terminal_block_hash {
return true; return true;
} }
let is_total_difficulty_reached = let is_total_difficulty_reached = block.total_difficulty >= spec.terminal_total_difficulty;
block.total_difficulty >= self.terminal_total_difficulty();
let is_parent_total_difficulty_valid = let is_parent_total_difficulty_valid =
parent.total_difficulty < self.terminal_total_difficulty(); parent.total_difficulty < spec.terminal_total_difficulty;
is_total_difficulty_reached && is_parent_total_difficulty_valid is_total_difficulty_reached && is_parent_total_difficulty_valid
} }
@ -685,14 +682,14 @@ mod test {
async fn finds_valid_terminal_block_hash() { async fn finds_valid_terminal_block_hash() {
MockExecutionLayer::default_params() MockExecutionLayer::default_params()
.move_to_block_prior_to_terminal_block() .move_to_block_prior_to_terminal_block()
.with_terminal_block(|el, _| async move { .with_terminal_block(|spec, el, _| async move {
assert_eq!(el.get_terminal_pow_block_hash().await.unwrap(), None) assert_eq!(el.get_terminal_pow_block_hash(&spec).await.unwrap(), None)
}) })
.await .await
.move_to_terminal_block() .move_to_terminal_block()
.with_terminal_block(|el, terminal_block| async move { .with_terminal_block(|spec, el, terminal_block| async move {
assert_eq!( assert_eq!(
el.get_terminal_pow_block_hash().await.unwrap(), el.get_terminal_pow_block_hash(&spec).await.unwrap(),
Some(terminal_block.unwrap().block_hash) Some(terminal_block.unwrap().block_hash)
) )
}) })
@ -703,9 +700,9 @@ mod test {
async fn verifies_valid_terminal_block_hash() { async fn verifies_valid_terminal_block_hash() {
MockExecutionLayer::default_params() MockExecutionLayer::default_params()
.move_to_terminal_block() .move_to_terminal_block()
.with_terminal_block(|el, terminal_block| async move { .with_terminal_block(|spec, el, terminal_block| async move {
assert_eq!( assert_eq!(
el.is_valid_terminal_pow_block_hash(terminal_block.unwrap().block_hash) el.is_valid_terminal_pow_block_hash(terminal_block.unwrap().block_hash, &spec)
.await .await
.unwrap(), .unwrap(),
Some(true) Some(true)
@ -718,11 +715,11 @@ mod test {
async fn rejects_invalid_terminal_block_hash() { async fn rejects_invalid_terminal_block_hash() {
MockExecutionLayer::default_params() MockExecutionLayer::default_params()
.move_to_terminal_block() .move_to_terminal_block()
.with_terminal_block(|el, terminal_block| async move { .with_terminal_block(|spec, el, terminal_block| async move {
let invalid_terminal_block = terminal_block.unwrap().parent_hash; let invalid_terminal_block = terminal_block.unwrap().parent_hash;
assert_eq!( assert_eq!(
el.is_valid_terminal_pow_block_hash(invalid_terminal_block) el.is_valid_terminal_pow_block_hash(invalid_terminal_block, &spec)
.await .await
.unwrap(), .unwrap(),
Some(false) Some(false)
@ -735,11 +732,11 @@ mod test {
async fn rejects_unknown_terminal_block_hash() { async fn rejects_unknown_terminal_block_hash() {
MockExecutionLayer::default_params() MockExecutionLayer::default_params()
.move_to_terminal_block() .move_to_terminal_block()
.with_terminal_block(|el, _| async move { .with_terminal_block(|spec, el, _| async move {
let missing_terminal_block = Hash256::repeat_byte(42); let missing_terminal_block = Hash256::repeat_byte(42);
assert_eq!( assert_eq!(
el.is_valid_terminal_pow_block_hash(missing_terminal_block) el.is_valid_terminal_pow_block_hash(missing_terminal_block, &spec)
.await .await
.unwrap(), .unwrap(),
None None

View File

@ -6,7 +6,7 @@ use environment::null_logger;
use sensitive_url::SensitiveUrl; use sensitive_url::SensitiveUrl;
use std::sync::Arc; use std::sync::Arc;
use task_executor::TaskExecutor; use task_executor::TaskExecutor;
use types::{Address, EthSpec, Hash256, Uint256}; use types::{Address, ChainSpec, Epoch, EthSpec, Hash256, Uint256};
pub struct ExecutionLayerRuntime { pub struct ExecutionLayerRuntime {
pub runtime: Option<Arc<tokio::runtime::Runtime>>, pub runtime: Option<Arc<tokio::runtime::Runtime>>,
@ -50,6 +50,7 @@ pub struct MockExecutionLayer<T: EthSpec> {
pub server: MockServer<T>, pub server: MockServer<T>,
pub el: ExecutionLayer, pub el: ExecutionLayer,
pub el_runtime: ExecutionLayerRuntime, pub el_runtime: ExecutionLayerRuntime,
pub spec: ChainSpec,
} }
impl<T: EthSpec> MockExecutionLayer<T> { impl<T: EthSpec> MockExecutionLayer<T> {
@ -58,6 +59,7 @@ impl<T: EthSpec> MockExecutionLayer<T> {
DEFAULT_TERMINAL_DIFFICULTY.into(), DEFAULT_TERMINAL_DIFFICULTY.into(),
DEFAULT_TERMINAL_BLOCK, DEFAULT_TERMINAL_BLOCK,
Hash256::zero(), Hash256::zero(),
Epoch::new(0),
) )
} }
@ -65,10 +67,16 @@ impl<T: EthSpec> MockExecutionLayer<T> {
terminal_total_difficulty: Uint256, terminal_total_difficulty: Uint256,
terminal_block: u64, terminal_block: u64,
terminal_block_hash: Hash256, terminal_block_hash: Hash256,
terminal_block_hash_activation_epoch: Epoch,
) -> Self { ) -> Self {
let el_runtime = ExecutionLayerRuntime::default(); let el_runtime = ExecutionLayerRuntime::default();
let handle = el_runtime.runtime.as_ref().unwrap().handle(); let handle = el_runtime.runtime.as_ref().unwrap().handle();
let mut spec = T::default_spec();
spec.terminal_total_difficulty = terminal_total_difficulty;
spec.terminal_block_hash = terminal_block_hash;
spec.terminal_block_hash_activation_epoch = terminal_block_hash_activation_epoch;
let server = MockServer::new( let server = MockServer::new(
handle, handle,
terminal_total_difficulty, terminal_total_difficulty,
@ -80,8 +88,6 @@ impl<T: EthSpec> MockExecutionLayer<T> {
let el = ExecutionLayer::from_urls( let el = ExecutionLayer::from_urls(
vec![url], vec![url],
terminal_total_difficulty,
Hash256::zero(),
Some(Address::repeat_byte(42)), Some(Address::repeat_byte(42)),
el_runtime.task_executor.clone(), el_runtime.task_executor.clone(),
el_runtime.log.clone(), el_runtime.log.clone(),
@ -92,6 +98,7 @@ impl<T: EthSpec> MockExecutionLayer<T> {
server, server,
el, el,
el_runtime, el_runtime,
spec,
} }
} }
@ -171,7 +178,7 @@ impl<T: EthSpec> MockExecutionLayer<T> {
pub async fn with_terminal_block<'a, U, V>(self, func: U) -> Self pub async fn with_terminal_block<'a, U, V>(self, func: U) -> Self
where where
U: Fn(ExecutionLayer, Option<ExecutionBlock>) -> V, U: Fn(ChainSpec, ExecutionLayer, Option<ExecutionBlock>) -> V,
V: Future<Output = ()>, V: Future<Output = ()>,
{ {
let terminal_block_number = self let terminal_block_number = self
@ -183,7 +190,7 @@ impl<T: EthSpec> MockExecutionLayer<T> {
.execution_block_generator() .execution_block_generator()
.execution_block_by_number(terminal_block_number); .execution_block_by_number(terminal_block_number);
func(self.el.clone(), terminal_block).await; func(self.spec.clone(), self.el.clone(), terminal_block).await;
self self
} }
} }

View File

@ -399,42 +399,6 @@ pub fn cli_app<'a, 'b>() -> App<'a, 'b> {
will be used. Defaults to http://127.0.0.1:8545.") will be used. Defaults to http://127.0.0.1:8545.")
.takes_value(true) .takes_value(true)
) )
.arg(
Arg::with_name("terminal-total-difficulty-override")
.long("terminal-total-difficulty-override")
.value_name("INTEGER")
.help("Used to coordinate manual overrides to the TERMINAL_TOTAL_DIFFICULTY parameter. \
This flag should only be used if the user has a clear understanding that \
the broad Ethereum community has elected to override the terminal difficulty. \
Incorrect use of this flag will cause your node to experience a consensus
failure. Be extremely careful with this flag.")
.takes_value(true)
)
.arg(
Arg::with_name("terminal-block-hash-override")
.long("terminal-block-hash-override")
.value_name("TERMINAL_BLOCK_HASH")
.help("Used to coordinate manual overrides to the TERMINAL_BLOCK_HASH parameter. \
Accepts a 256-bit decimal integer (not a hex value). \
This flag should only be used if the user has a clear understanding that \
the broad Ethereum community has elected to override the terminal PoW block. \
Incorrect use of this flag will cause your node to experience a consensus
failure. Be extremely careful with this flag.")
.requires("terminal-block-hash-epoch-override")
.takes_value(true)
)
.arg(
Arg::with_name("terminal-block-hash-epoch-override")
.long("terminal-block-hash-epoch-override")
.value_name("EPOCH")
.help("Used to coordinate manual overrides to the TERMINAL_BLOCK_HASH_ACTIVATION_EPOCH \
parameter. This flag should only be used if the user has a clear understanding \
that the broad Ethereum community has elected to override the terminal PoW block. \
Incorrect use of this flag will cause your node to experience a consensus
failure. Be extremely careful with this flag.")
.requires("terminal-block-hash-override")
.takes_value(true)
)
.arg( .arg(
Arg::with_name("fee-recipient") Arg::with_name("fee-recipient")
.long("fee-recipient") .long("fee-recipient")

View File

@ -1,8 +1,8 @@
use clap::ArgMatches; use clap::ArgMatches;
use clap_utils::{flags::DISABLE_MALLOC_TUNING_FLAG, BAD_TESTNET_DIR_MESSAGE}; use clap_utils::flags::DISABLE_MALLOC_TUNING_FLAG;
use client::{ClientConfig, ClientGenesis}; use client::{ClientConfig, ClientGenesis};
use directory::{DEFAULT_BEACON_NODE_DIR, DEFAULT_NETWORK_DIR, DEFAULT_ROOT_DIR}; use directory::{DEFAULT_BEACON_NODE_DIR, DEFAULT_NETWORK_DIR, DEFAULT_ROOT_DIR};
use eth2_network_config::{Eth2NetworkConfig, DEFAULT_HARDCODED_NETWORK}; use environment::RuntimeContext;
use http_api::TlsConfig; use http_api::TlsConfig;
use lighthouse_network::{multiaddr::Protocol, Enr, Multiaddr, NetworkConfig, PeerIdSerialized}; use lighthouse_network::{multiaddr::Protocol, Enr, Multiaddr, NetworkConfig, PeerIdSerialized};
use sensitive_url::SensitiveUrl; use sensitive_url::SensitiveUrl;
@ -14,9 +14,7 @@ use std::net::{IpAddr, Ipv4Addr, ToSocketAddrs};
use std::net::{TcpListener, UdpSocket}; use std::net::{TcpListener, UdpSocket};
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use std::str::FromStr; use std::str::FromStr;
use types::{ use types::{Checkpoint, Epoch, EthSpec, Hash256, PublicKeyBytes, GRAFFITI_BYTES_LEN};
ChainSpec, Checkpoint, Epoch, EthSpec, Hash256, PublicKeyBytes, Uint256, GRAFFITI_BYTES_LEN,
};
/// Gets the fully-initialized global client. /// Gets the fully-initialized global client.
/// ///
@ -27,9 +25,11 @@ use types::{
/// response of some remote server. /// response of some remote server.
pub fn get_config<E: EthSpec>( pub fn get_config<E: EthSpec>(
cli_args: &ArgMatches, cli_args: &ArgMatches,
spec: &ChainSpec, context: &RuntimeContext<E>,
log: Logger,
) -> Result<ClientConfig, String> { ) -> Result<ClientConfig, String> {
let spec = &context.eth2_config.spec;
let log = context.log();
let mut client_config = ClientConfig { let mut client_config = ClientConfig {
data_dir: get_data_dir(cli_args), data_dir: get_data_dir(cli_args),
..Default::default() ..Default::default()
@ -63,7 +63,7 @@ pub fn get_config<E: EthSpec>(
&mut client_config.network, &mut client_config.network,
cli_args, cli_args,
&client_config.data_dir, &client_config.data_dir,
&log, log,
false, false,
)?; )?;
@ -242,32 +242,7 @@ pub fn get_config<E: EthSpec>(
client_config.execution_endpoints = Some(client_config.eth1.endpoints.clone()); client_config.execution_endpoints = Some(client_config.eth1.endpoints.clone());
} }
if let Some(string) =
clap_utils::parse_optional::<String>(cli_args, "terminal-total-difficulty-override")?
{
let stripped = string.replace(",", "");
let terminal_total_difficulty = Uint256::from_dec_str(&stripped).map_err(|e| {
format!(
"Could not parse --terminal-total-difficulty-override as decimal value: {:?}",
e
)
})?;
if client_config.execution_endpoints.is_none() {
return Err(
"The --merge flag must be provided when using --terminal-total-difficulty-override"
.into(),
);
}
client_config.terminal_total_difficulty_override = Some(terminal_total_difficulty);
}
client_config.fee_recipient = clap_utils::parse_optional(cli_args, "fee-recipient")?; client_config.fee_recipient = clap_utils::parse_optional(cli_args, "fee-recipient")?;
client_config.terminal_block_hash_override =
clap_utils::parse_optional(cli_args, "terminal-block-hash-override")?;
client_config.terminal_block_hash_epoch_override =
clap_utils::parse_optional(cli_args, "terminal-block-hash-epoch-override")?;
if let Some(freezer_dir) = cli_args.value_of("freezer-dir") { if let Some(freezer_dir) = cli_args.value_of("freezer-dir") {
client_config.freezer_db_path = Some(PathBuf::from(freezer_dir)); client_config.freezer_db_path = Some(PathBuf::from(freezer_dir));
@ -321,7 +296,10 @@ pub fn get_config<E: EthSpec>(
/* /*
* Load the eth2 network dir to obtain some additional config values. * Load the eth2 network dir to obtain some additional config values.
*/ */
let eth2_network_config = get_eth2_network_config(cli_args)?; let eth2_network_config = context
.eth2_network_config
.as_ref()
.ok_or("Context is missing eth2 network config")?;
client_config.eth1.deposit_contract_address = format!("{:?}", spec.deposit_contract_address); client_config.eth1.deposit_contract_address = format!("{:?}", spec.deposit_contract_address);
client_config.eth1.deposit_contract_deploy_block = client_config.eth1.deposit_contract_deploy_block =
@ -344,13 +322,16 @@ pub fn get_config<E: EthSpec>(
// Only append network config bootnodes if discovery is not disabled // Only append network config bootnodes if discovery is not disabled
if !client_config.network.disable_discovery { if !client_config.network.disable_discovery {
if let Some(mut boot_nodes) = eth2_network_config.boot_enr { if let Some(boot_nodes) = &eth2_network_config.boot_enr {
client_config.network.boot_nodes_enr.append(&mut boot_nodes) client_config
.network
.boot_nodes_enr
.extend_from_slice(boot_nodes)
} }
} }
client_config.genesis = if let Some(genesis_state_bytes) = client_config.genesis = if let Some(genesis_state_bytes) =
eth2_network_config.genesis_state_bytes eth2_network_config.genesis_state_bytes.clone()
{ {
// Set up weak subjectivity sync, or start from the hardcoded genesis state. // Set up weak subjectivity sync, or start from the hardcoded genesis state.
if let (Some(initial_state_path), Some(initial_block_path)) = ( if let (Some(initial_state_path), Some(initial_block_path)) = (
@ -782,20 +763,6 @@ pub fn get_data_dir(cli_args: &ArgMatches) -> PathBuf {
.unwrap_or_else(|| PathBuf::from(".")) .unwrap_or_else(|| PathBuf::from("."))
} }
/// Try to parse the eth2 network config from the `network`, `testnet-dir` flags in that order.
/// Returns the default hardcoded testnet if neither flags are set.
pub fn get_eth2_network_config(cli_args: &ArgMatches) -> Result<Eth2NetworkConfig, String> {
let optional_network_config = if cli_args.is_present("network") {
clap_utils::parse_hardcoded_network(cli_args, "network")?
} else if cli_args.is_present("testnet-dir") {
clap_utils::parse_testnet_dir(cli_args, "testnet-dir")?
} else {
// if neither is present, assume the default network
Eth2NetworkConfig::constant(DEFAULT_HARDCODED_NETWORK)?
};
optional_network_config.ok_or_else(|| BAD_TESTNET_DIR_MESSAGE.to_string())
}
/// A bit of hack to find an unused port. /// A bit of hack to find an unused port.
/// ///
/// Does not guarantee that the given port is unused after the function exits, just that it was /// Does not guarantee that the given port is unused after the function exits, just that it was

View File

@ -13,7 +13,7 @@ use beacon_chain::{
use clap::ArgMatches; use clap::ArgMatches;
pub use cli::cli_app; pub use cli::cli_app;
pub use client::{Client, ClientBuilder, ClientConfig, ClientGenesis}; pub use client::{Client, ClientBuilder, ClientConfig, ClientGenesis};
pub use config::{get_config, get_data_dir, get_eth2_network_config, set_network_config}; pub use config::{get_config, get_data_dir, set_network_config};
use environment::RuntimeContext; use environment::RuntimeContext;
pub use eth2_config::Eth2Config; pub use eth2_config::Eth2Config;
use slasher::Slasher; use slasher::Slasher;
@ -46,8 +46,7 @@ impl<E: EthSpec> ProductionBeaconNode<E> {
context: RuntimeContext<E>, context: RuntimeContext<E>,
matches: ArgMatches<'static>, matches: ArgMatches<'static>,
) -> Result<Self, String> { ) -> Result<Self, String> {
let client_config = let client_config = get_config::<E>(&matches, &context)?;
get_config::<E>(&matches, &context.eth2_config().spec, context.log().clone())?;
Self::new(context, client_config).await Self::new(context, client_config).await
} }

View File

@ -23,3 +23,4 @@ hex = "0.4.2"
serde = "1.0.116" serde = "1.0.116"
serde_derive = "1.0.116" serde_derive = "1.0.116"
serde_json = "1.0.66" serde_json = "1.0.66"
eth2_network_config = { path = "../common/eth2_network_config" }

View File

@ -1,5 +1,6 @@
use beacon_node::{get_data_dir, get_eth2_network_config, set_network_config}; use beacon_node::{get_data_dir, set_network_config};
use clap::ArgMatches; use clap::ArgMatches;
use eth2_network_config::Eth2NetworkConfig;
use lighthouse_network::discv5::{enr::CombinedKey, Discv5Config, Enr}; use lighthouse_network::discv5::{enr::CombinedKey, Discv5Config, Enr};
use lighthouse_network::{ use lighthouse_network::{
discovery::{create_enr_builder_from_config, load_enr_from_disk, use_or_load_enr}, discovery::{create_enr_builder_from_config, load_enr_from_disk, use_or_load_enr},
@ -7,7 +8,6 @@ use lighthouse_network::{
}; };
use serde_derive::{Deserialize, Serialize}; use serde_derive::{Deserialize, Serialize};
use ssz::Encode; use ssz::Encode;
use std::convert::TryFrom;
use std::net::SocketAddr; use std::net::SocketAddr;
use std::{marker::PhantomData, path::PathBuf}; use std::{marker::PhantomData, path::PathBuf};
use types::EthSpec; use types::EthSpec;
@ -23,15 +23,13 @@ pub struct BootNodeConfig<T: EthSpec> {
phantom: PhantomData<T>, phantom: PhantomData<T>,
} }
impl<T: EthSpec> TryFrom<&ArgMatches<'_>> for BootNodeConfig<T> { impl<T: EthSpec> BootNodeConfig<T> {
type Error = String; pub fn new(
matches: &ArgMatches<'_>,
fn try_from(matches: &ArgMatches<'_>) -> Result<Self, Self::Error> { eth2_network_config: &Eth2NetworkConfig,
) -> Result<Self, String> {
let data_dir = get_data_dir(matches); let data_dir = get_data_dir(matches);
// Try and grab network config from input CLI params
let eth2_network_config = get_eth2_network_config(matches)?;
// Try and obtain bootnodes // Try and obtain bootnodes
let boot_nodes = { let boot_nodes = {

View File

@ -2,7 +2,7 @@
use clap::ArgMatches; use clap::ArgMatches;
use slog::{o, Drain, Level, Logger}; use slog::{o, Drain, Level, Logger};
use std::convert::TryFrom; use eth2_network_config::Eth2NetworkConfig;
use std::fs::File; use std::fs::File;
use std::path::PathBuf; use std::path::PathBuf;
mod cli; mod cli;
@ -19,6 +19,7 @@ pub fn run(
lh_matches: &ArgMatches<'_>, lh_matches: &ArgMatches<'_>,
bn_matches: &ArgMatches<'_>, bn_matches: &ArgMatches<'_>,
eth_spec_id: EthSpecId, eth_spec_id: EthSpecId,
eth2_network_config: &Eth2NetworkConfig,
debug_level: String, debug_level: String,
) { ) {
let debug_level = match debug_level.as_str() { let debug_level = match debug_level.as_str() {
@ -56,8 +57,12 @@ pub fn run(
let log = slog_scope::logger(); let log = slog_scope::logger();
// Run the main function emitting any errors // Run the main function emitting any errors
if let Err(e) = match eth_spec_id { if let Err(e) = match eth_spec_id {
EthSpecId::Minimal => main::<types::MinimalEthSpec>(lh_matches, bn_matches, log), EthSpecId::Minimal => {
EthSpecId::Mainnet => main::<types::MainnetEthSpec>(lh_matches, bn_matches, log), main::<types::MinimalEthSpec>(lh_matches, bn_matches, eth2_network_config, log)
}
EthSpecId::Mainnet => {
main::<types::MainnetEthSpec>(lh_matches, bn_matches, eth2_network_config, log)
}
} { } {
slog::crit!(slog_scope::logger(), "{}", e); slog::crit!(slog_scope::logger(), "{}", e);
} }
@ -66,6 +71,7 @@ pub fn run(
fn main<T: EthSpec>( fn main<T: EthSpec>(
lh_matches: &ArgMatches<'_>, lh_matches: &ArgMatches<'_>,
bn_matches: &ArgMatches<'_>, bn_matches: &ArgMatches<'_>,
eth2_network_config: &Eth2NetworkConfig,
log: slog::Logger, log: slog::Logger,
) -> Result<(), String> { ) -> Result<(), String> {
// Builds a custom executor for the bootnode // Builds a custom executor for the bootnode
@ -74,8 +80,8 @@ fn main<T: EthSpec>(
.build() .build()
.map_err(|e| format!("Failed to build runtime: {}", e))?; .map_err(|e| format!("Failed to build runtime: {}", e))?;
// Parse the CLI args into a useable config // parse the CLI args into a useable config
let config: BootNodeConfig<T> = BootNodeConfig::try_from(bn_matches)?; let config: BootNodeConfig<T> = BootNodeConfig::new(bn_matches, eth2_network_config)?;
// Dump config if `dump-config` flag is set // Dump config if `dump-config` flag is set
let dump_config = clap_utils::parse_optional::<PathBuf>(lh_matches, "dump-config")?; let dump_config = clap_utils::parse_optional::<PathBuf>(lh_matches, "dump-config")?;

View File

@ -12,3 +12,4 @@ hex = "0.4.2"
dirs = "3.0.1" dirs = "3.0.1"
eth2_network_config = { path = "../eth2_network_config" } eth2_network_config = { path = "../eth2_network_config" }
eth2_ssz = "0.4.0" eth2_ssz = "0.4.0"
ethereum-types = "0.12.1"

View File

@ -1,7 +1,8 @@
//! A helper library for parsing values from `clap::ArgMatches`. //! A helper library for parsing values from `clap::ArgMatches`.
use clap::ArgMatches; use clap::ArgMatches;
use eth2_network_config::Eth2NetworkConfig; use eth2_network_config::{Eth2NetworkConfig, DEFAULT_HARDCODED_NETWORK};
use ethereum_types::U256 as Uint256;
use ssz::Decode; use ssz::Decode;
use std::path::PathBuf; use std::path::PathBuf;
use std::str::FromStr; use std::str::FromStr;
@ -13,6 +14,47 @@ pub const BAD_TESTNET_DIR_MESSAGE: &str = "The hard-coded testnet directory was
or when there is no default public network to connect to. \ or when there is no default public network to connect to. \
During these times you must specify a --testnet-dir."; During these times you must specify a --testnet-dir.";
/// Try to parse the eth2 network config from the `network`, `testnet-dir` flags in that order.
/// Returns the default hardcoded testnet if neither flags are set.
pub fn get_eth2_network_config(cli_args: &ArgMatches) -> Result<Eth2NetworkConfig, String> {
let optional_network_config = if cli_args.is_present("network") {
parse_hardcoded_network(cli_args, "network")?
} else if cli_args.is_present("testnet-dir") {
parse_testnet_dir(cli_args, "testnet-dir")?
} else {
// if neither is present, assume the default network
Eth2NetworkConfig::constant(DEFAULT_HARDCODED_NETWORK)?
};
let mut eth2_network_config =
optional_network_config.ok_or_else(|| BAD_TESTNET_DIR_MESSAGE.to_string())?;
if let Some(string) = parse_optional::<String>(cli_args, "terminal-total-difficulty-override")?
{
let stripped = string.replace(",", "");
let terminal_total_difficulty = Uint256::from_dec_str(&stripped).map_err(|e| {
format!(
"Could not parse --terminal-total-difficulty-override as decimal value: {:?}",
e
)
})?;
eth2_network_config.config.terminal_total_difficulty = terminal_total_difficulty;
}
if let Some(hash) = parse_optional(cli_args, "terminal-block-hash-override")? {
eth2_network_config.config.terminal_block_hash = hash;
}
if let Some(epoch) = parse_optional(cli_args, "terminal-block-hash-epoch-override")? {
eth2_network_config
.config
.terminal_block_hash_activation_epoch = epoch;
}
Ok(eth2_network_config)
}
/// Attempts to load the testnet dir at the path if `name` is in `matches`, returning an error if /// Attempts to load the testnet dir at the path if `name` is in `matches`, returning an error if
/// the path cannot be found or the testnet dir is invalid. /// the path cannot be found or the testnet dir is invalid.
pub fn parse_testnet_dir( pub fn parse_testnet_dir(

View File

@ -3,6 +3,14 @@
# Extends the mainnet preset # Extends the mainnet preset
PRESET_BASE: 'mainnet' PRESET_BASE: 'mainnet'
# Transition
# ---------------------------------------------------------------
# TBD, 2**256-2**10 is a placeholder
TERMINAL_TOTAL_DIFFICULTY: 115792089237316195423570985008687907853269984665640564039457584007913129638912
# By default, don't use these params
TERMINAL_BLOCK_HASH: 0x0000000000000000000000000000000000000000000000000000000000000000
TERMINAL_BLOCK_HASH_ACTIVATION_EPOCH: 18446744073709551615
# Genesis # Genesis
# --------------------------------------------------------------- # ---------------------------------------------------------------
# `2**14` (= 16,384) # `2**14` (= 16,384)

View File

@ -3,6 +3,14 @@
# Extends the mainnet preset # Extends the mainnet preset
PRESET_BASE: 'mainnet' PRESET_BASE: 'mainnet'
# Transition
# ---------------------------------------------------------------
# TBD, 2**256-2**10 is a placeholder
TERMINAL_TOTAL_DIFFICULTY: 115792089237316195423570985008687907853269984665640564039457584007913129638912
# By default, don't use these params
TERMINAL_BLOCK_HASH: 0x0000000000000000000000000000000000000000000000000000000000000000
TERMINAL_BLOCK_HASH_ACTIVATION_EPOCH: 18446744073709551615
# Genesis # Genesis
# --------------------------------------------------------------- # ---------------------------------------------------------------
# `2**14` (= 16,384) # `2**14` (= 16,384)

View File

@ -3,6 +3,14 @@
# Extends the mainnet preset # Extends the mainnet preset
PRESET_BASE: 'mainnet' PRESET_BASE: 'mainnet'
# Transition
# ---------------------------------------------------------------
# TBD, 2**256-2**10 is a placeholder
TERMINAL_TOTAL_DIFFICULTY: 115792089237316195423570985008687907853269984665640564039457584007913129638912
# By default, don't use these params
TERMINAL_BLOCK_HASH: 0x0000000000000000000000000000000000000000000000000000000000000000
TERMINAL_BLOCK_HASH_ACTIVATION_EPOCH: 18446744073709551615
# Genesis # Genesis
# --------------------------------------------------------------- # ---------------------------------------------------------------
# `2**14` (= 16,384) # `2**14` (= 16,384)

View File

@ -533,7 +533,11 @@ impl ChainSpec {
merge_fork_epoch: None, merge_fork_epoch: None,
terminal_total_difficulty: Uint256::MAX terminal_total_difficulty: Uint256::MAX
.checked_sub(Uint256::from(2u64.pow(10))) .checked_sub(Uint256::from(2u64.pow(10)))
.expect("calculation does not overflow"), .expect("subtraction does not overflow")
// Add 1 since the spec declares `2**256 - 2**10` and we use
// `Uint256::MAX` which is `2*256- 1`.
.checked_add(Uint256::one())
.expect("addition does not overflow"),
terminal_block_hash: Hash256::zero(), terminal_block_hash: Hash256::zero(),
terminal_block_hash_activation_epoch: Epoch::new(u64::MAX), terminal_block_hash_activation_epoch: Epoch::new(u64::MAX),
@ -605,6 +609,11 @@ pub struct Config {
#[serde(default)] #[serde(default)]
pub preset_base: String, pub preset_base: String,
#[serde(with = "eth2_serde_utils::quoted_u256")]
pub terminal_total_difficulty: Uint256,
pub terminal_block_hash: Hash256,
pub terminal_block_hash_activation_epoch: Epoch,
#[serde(with = "eth2_serde_utils::quoted_u64")] #[serde(with = "eth2_serde_utils::quoted_u64")]
min_genesis_active_validator_count: u64, min_genesis_active_validator_count: u64,
#[serde(with = "eth2_serde_utils::quoted_u64")] #[serde(with = "eth2_serde_utils::quoted_u64")]
@ -707,6 +716,10 @@ impl Config {
Self { Self {
preset_base: T::spec_name().to_string(), preset_base: T::spec_name().to_string(),
terminal_total_difficulty: spec.terminal_total_difficulty,
terminal_block_hash: spec.terminal_block_hash,
terminal_block_hash_activation_epoch: spec.terminal_block_hash_activation_epoch,
min_genesis_active_validator_count: spec.min_genesis_active_validator_count, min_genesis_active_validator_count: spec.min_genesis_active_validator_count,
min_genesis_time: spec.min_genesis_time, min_genesis_time: spec.min_genesis_time,
genesis_fork_version: spec.genesis_fork_version, genesis_fork_version: spec.genesis_fork_version,
@ -750,6 +763,9 @@ impl Config {
// Pattern match here to avoid missing any fields. // Pattern match here to avoid missing any fields.
let &Config { let &Config {
ref preset_base, ref preset_base,
terminal_total_difficulty,
terminal_block_hash,
terminal_block_hash_activation_epoch,
min_genesis_active_validator_count, min_genesis_active_validator_count,
min_genesis_time, min_genesis_time,
genesis_fork_version, genesis_fork_version,
@ -799,6 +815,9 @@ impl Config {
deposit_chain_id, deposit_chain_id,
deposit_network_id, deposit_network_id,
deposit_contract_address, deposit_contract_address,
terminal_total_difficulty,
terminal_block_hash,
terminal_block_hash_activation_epoch,
..chain_spec.clone() ..chain_spec.clone()
}) })
} }

View File

@ -249,7 +249,7 @@ impl<E: EthSpec> EnvironmentBuilder<E> {
log: self.log.ok_or("Cannot build environment without log")?, log: self.log.ok_or("Cannot build environment without log")?,
eth_spec_instance: self.eth_spec_instance, eth_spec_instance: self.eth_spec_instance,
eth2_config: self.eth2_config, eth2_config: self.eth2_config,
eth2_network_config: self.eth2_network_config, eth2_network_config: self.eth2_network_config.map(Arc::new),
}) })
} }
} }
@ -263,6 +263,7 @@ pub struct RuntimeContext<E: EthSpec> {
pub executor: TaskExecutor, pub executor: TaskExecutor,
pub eth_spec_instance: E, pub eth_spec_instance: E,
pub eth2_config: Eth2Config, pub eth2_config: Eth2Config,
pub eth2_network_config: Option<Arc<Eth2NetworkConfig>>,
} }
impl<E: EthSpec> RuntimeContext<E> { impl<E: EthSpec> RuntimeContext<E> {
@ -274,6 +275,7 @@ impl<E: EthSpec> RuntimeContext<E> {
executor: self.executor.clone_with_name(service_name), executor: self.executor.clone_with_name(service_name),
eth_spec_instance: self.eth_spec_instance.clone(), eth_spec_instance: self.eth_spec_instance.clone(),
eth2_config: self.eth2_config.clone(), eth2_config: self.eth2_config.clone(),
eth2_network_config: self.eth2_network_config.clone(),
} }
} }
@ -301,7 +303,7 @@ pub struct Environment<E: EthSpec> {
log: Logger, log: Logger,
eth_spec_instance: E, eth_spec_instance: E,
pub eth2_config: Eth2Config, pub eth2_config: Eth2Config,
pub eth2_network_config: Option<Eth2NetworkConfig>, pub eth2_network_config: Option<Arc<Eth2NetworkConfig>>,
} }
impl<E: EthSpec> Environment<E> { impl<E: EthSpec> Environment<E> {
@ -324,6 +326,7 @@ impl<E: EthSpec> Environment<E> {
), ),
eth_spec_instance: self.eth_spec_instance.clone(), eth_spec_instance: self.eth_spec_instance.clone(),
eth2_config: self.eth2_config.clone(), eth2_config: self.eth2_config.clone(),
eth2_network_config: self.eth2_network_config.clone(),
} }
} }
@ -338,6 +341,7 @@ impl<E: EthSpec> Environment<E> {
), ),
eth_spec_instance: self.eth_spec_instance.clone(), eth_spec_instance: self.eth_spec_instance.clone(),
eth2_config: self.eth2_config.clone(), eth2_config: self.eth2_config.clone(),
eth2_network_config: self.eth2_network_config.clone(),
} }
} }

View File

@ -3,6 +3,14 @@
# Extends the mainnet preset # Extends the mainnet preset
PRESET_BASE: 'mainnet' PRESET_BASE: 'mainnet'
# Transition
# ---------------------------------------------------------------
# TBD, 2**256-2**10 is a placeholder
TERMINAL_TOTAL_DIFFICULTY: 115792089237316195423570985008687907853269984665640564039457584007913129638912
# By default, don't use these params
TERMINAL_BLOCK_HASH: 0x0000000000000000000000000000000000000000000000000000000000000000
TERMINAL_BLOCK_HASH_ACTIVATION_EPOCH: 18446744073709551615
# Genesis # Genesis
# --------------------------------------------------------------- # ---------------------------------------------------------------
# CUSTOMISED FOR TEST # CUSTOMISED FOR TEST

View File

@ -2,9 +2,9 @@
mod metrics; mod metrics;
use beacon_node::{get_eth2_network_config, ProductionBeaconNode}; use beacon_node::ProductionBeaconNode;
use clap::{App, Arg, ArgMatches}; use clap::{App, Arg, ArgMatches};
use clap_utils::{flags::DISABLE_MALLOC_TUNING_FLAG, parse_optional}; use clap_utils::{flags::DISABLE_MALLOC_TUNING_FLAG, get_eth2_network_config};
use directory::{parse_path_or_default, DEFAULT_BEACON_NODE_DIR, DEFAULT_VALIDATOR_DIR}; use directory::{parse_path_or_default, DEFAULT_BEACON_NODE_DIR, DEFAULT_VALIDATOR_DIR};
use env_logger::{Builder, Env}; use env_logger::{Builder, Env};
use environment::{EnvironmentBuilder, LoggerConfig}; use environment::{EnvironmentBuilder, LoggerConfig};
@ -211,6 +211,45 @@ fn main() {
) )
.global(true), .global(true),
) )
.arg(
Arg::with_name("terminal-total-difficulty-override")
.long("terminal-total-difficulty-override")
.value_name("INTEGER")
.help("Used to coordinate manual overrides to the TERMINAL_TOTAL_DIFFICULTY parameter. \
Accepts a 256-bit decimal integer (not a hex value). \
This flag should only be used if the user has a clear understanding that \
the broad Ethereum community has elected to override the terminal difficulty. \
Incorrect use of this flag will cause your node to experience a consensus
failure. Be extremely careful with this flag.")
.takes_value(true)
.global(true)
)
.arg(
Arg::with_name("terminal-block-hash-override")
.long("terminal-block-hash-override")
.value_name("TERMINAL_BLOCK_HASH")
.help("Used to coordinate manual overrides to the TERMINAL_BLOCK_HASH parameter. \
This flag should only be used if the user has a clear understanding that \
the broad Ethereum community has elected to override the terminal PoW block. \
Incorrect use of this flag will cause your node to experience a consensus
failure. Be extremely careful with this flag.")
.requires("terminal-block-hash-epoch-override")
.takes_value(true)
.global(true)
)
.arg(
Arg::with_name("terminal-block-hash-epoch-override")
.long("terminal-block-hash-epoch-override")
.value_name("EPOCH")
.help("Used to coordinate manual overrides to the TERMINAL_BLOCK_HASH_ACTIVATION_EPOCH \
parameter. This flag should only be used if the user has a clear understanding \
that the broad Ethereum community has elected to override the terminal PoW block. \
Incorrect use of this flag will cause your node to experience a consensus
failure. Be extremely careful with this flag.")
.requires("terminal-block-hash-override")
.takes_value(true)
.global(true)
)
.subcommand(beacon_node::cli_app()) .subcommand(beacon_node::cli_app())
.subcommand(boot_node::cli_app()) .subcommand(boot_node::cli_app())
.subcommand(validator_client::cli_app()) .subcommand(validator_client::cli_app())
@ -250,7 +289,13 @@ fn main() {
.expect("Debug-level must be present") .expect("Debug-level must be present")
.into(); .into();
boot_node::run(&matches, bootnode_matches, eth_spec_id, debug_info); boot_node::run(
&matches,
bootnode_matches,
eth_spec_id,
&eth2_network_config,
debug_info,
);
return Ok(()); return Ok(());
} }
@ -424,11 +469,7 @@ fn run<E: EthSpec>(
let context = environment.core_context(); let context = environment.core_context();
let log = context.log().clone(); let log = context.log().clone();
let executor = context.executor.clone(); let executor = context.executor.clone();
let config = beacon_node::get_config::<E>( let config = beacon_node::get_config::<E>(matches, &context)?;
matches,
&context.eth2_config().spec,
context.log().clone(),
)?;
let shutdown_flag = matches.is_present("immediate-shutdown"); let shutdown_flag = matches.is_present("immediate-shutdown");
if let Some(dump_path) = clap_utils::parse_optional::<PathBuf>(matches, "dump-config")? if let Some(dump_path) = clap_utils::parse_optional::<PathBuf>(matches, "dump-config")?
{ {

View File

@ -11,7 +11,7 @@ use std::process::Command;
use std::str::FromStr; use std::str::FromStr;
use std::string::ToString; use std::string::ToString;
use tempfile::TempDir; use tempfile::TempDir;
use types::{Checkpoint, Epoch, Hash256, Uint256}; use types::{Checkpoint, Epoch, Hash256};
const DEFAULT_ETH1_ENDPOINT: &str = "http://localhost:8545/"; const DEFAULT_ETH1_ENDPOINT: &str = "http://localhost:8545/";
@ -817,83 +817,6 @@ pub fn malloc_tuning_flag() {
}); });
} }
#[test] #[test]
pub fn ttd_override_decimal() {
CommandLineTest::new().run().with_config(|config| {
assert!(config.terminal_total_difficulty_override.is_none());
});
CommandLineTest::new()
.flag("merge", None)
.flag(
"terminal-total-difficulty-override",
Some("31,841,035,257,753,085,493,511"),
)
.run()
.with_config(|config| {
assert_eq!(
config.terminal_total_difficulty_override.unwrap(),
Uint256::from_dec_str(&"31841035257753085493511").unwrap()
);
});
CommandLineTest::new()
.flag("merge", None)
.flag(
"terminal-total-difficulty-override",
Some("31841035257753085493511"),
)
.run()
.with_config(|config| {
assert_eq!(
config.terminal_total_difficulty_override.unwrap(),
Uint256::from_dec_str(&"31841035257753085493511").unwrap()
);
});
CommandLineTest::new()
.flag("merge", None)
.flag("terminal-total-difficulty-override", Some("1234"))
.run()
.with_config(|config| {
assert_eq!(
config.terminal_total_difficulty_override.unwrap(),
Uint256::from(1234)
);
});
CommandLineTest::new()
.flag("merge", None)
.flag("terminal-total-difficulty-override", Some("1,234"))
.run()
.with_config(|config| {
assert_eq!(
config.terminal_total_difficulty_override.unwrap(),
Uint256::from(1234)
);
});
}
#[test]
#[should_panic]
pub fn ttd_override_without_merge() {
CommandLineTest::new()
.flag("terminal-total-difficulty-override", Some("1234"))
.run();
}
#[test]
#[should_panic]
pub fn ttd_override_hex() {
CommandLineTest::new()
.flag("terminal-total-difficulty-override", Some("0xabcd"))
.run();
}
#[test]
#[should_panic]
pub fn ttd_override_none() {
CommandLineTest::new()
.flag("terminal-total-difficulty-override", None)
.run();
}
#[test]
#[should_panic] #[should_panic]
fn ensure_panic_on_failed_launch() { fn ensure_panic_on_failed_launch() {
CommandLineTest::new() CommandLineTest::new()

View File

@ -1,8 +1,8 @@
use boot_node::config::BootNodeConfigSerialization; use boot_node::config::BootNodeConfigSerialization;
use crate::exec::{CommandLineTestExec, CompletedTest}; use crate::exec::{CommandLineTestExec, CompletedTest};
use beacon_node::get_eth2_network_config;
use clap::ArgMatches; use clap::ArgMatches;
use clap_utils::get_eth2_network_config;
use lighthouse_network::discovery::ENR_FILENAME; use lighthouse_network::discovery::ENR_FILENAME;
use lighthouse_network::Enr; use lighthouse_network::Enr;
use std::fs::File; use std::fs::File;