diff --git a/beacon_node/client/src/builder.rs b/beacon_node/client/src/builder.rs index 9d0e6c25f6b..58485d9787d 100644 --- a/beacon_node/client/src/builder.rs +++ b/beacon_node/client/src/builder.rs @@ -16,14 +16,15 @@ use eth2_libp2p::NetworkGlobals; use genesis::{interop_genesis_state, Eth1GenesisService}; use network::{NetworkConfig, NetworkMessage, NetworkService}; use parking_lot::Mutex; -use slog::{debug, info}; +use slog::{debug, info, warn}; use ssz::Decode; use std::net::SocketAddr; +use std::net::TcpListener; use std::path::{Path, PathBuf}; use std::sync::Arc; use std::time::Duration; use timer::spawn_timer; -use tokio::sync::mpsc::UnboundedSender; +use tokio::sync::{mpsc::UnboundedSender, oneshot}; use types::{ test_utils::generate_deterministic_keypairs, BeaconState, ChainSpec, EthSpec, SignedBeaconBlockHash, @@ -202,6 +203,53 @@ where context.eth2_config().spec.clone(), ); + // If the HTTP API server is enabled, start an instance of it where it only + // contains a reference to the eth1 service (all non-eth1 endpoints will fail + // gracefully). + // + // Later in this function we will shutdown this temporary "waiting for genesis" + // server so the real one can be started later. + let (exit_tx, exit_rx) = oneshot::channel::<()>(); + let http_listen_opt = if self.http_api_config.enabled { + #[allow(clippy::type_complexity)] + let ctx: Arc< + http_api::Context< + Witness< + TSlotClock, + TEth1Backend, + TEthSpec, + TEventHandler, + THotStore, + TColdStore, + >, + >, + > = Arc::new(http_api::Context { + config: self.http_api_config.clone(), + chain: None, + network_tx: None, + network_globals: None, + eth1_service: Some(genesis_service.eth1_service.clone()), + log: context.log().clone(), + }); + + // Discard the error from the oneshot. + let exit_future = async { + let _ = exit_rx.await; + }; + + let (listen_addr, server) = http_api::serve(ctx, exit_future) + .map_err(|e| format!("Unable to start HTTP API server: {:?}", e))?; + + context + .clone() + .executor + .spawn_without_exit(async move { server.await }, "http-api"); + + Some(listen_addr) + } else { + None + }; + let genesis_state = genesis_service .wait_for_genesis_state( Duration::from_millis(ETH1_GENESIS_UPDATE_INTERVAL_MILLIS), @@ -209,6 +257,22 @@ where ) .await?; + let _ = exit_tx.send(()); + + if let Some(http_listen) = http_listen_opt { + // This is a bit of a hack to ensure that the HTTP server has indeed shutdown. + // + // We will restart it again after we've finished setting up for genesis. + while TcpListener::bind(http_listen).is_err() { + warn!( + context.log(), + "Waiting for HTTP server port to open"; + "port" => http_listen + ); + tokio::time::delay_for(Duration::from_secs(1)).await; + } + } + builder .genesis_state(genesis_state) .map(|v| (v, Some(genesis_service.into_core_service())))? diff --git a/beacon_node/src/lib.rs b/beacon_node/src/lib.rs index 9fccfb1a5e7..e3e4c89e50c 100644 --- a/beacon_node/src/lib.rs +++ b/beacon_node/src/lib.rs @@ -79,6 +79,7 @@ impl ProductionBeaconNode { let builder = ClientBuilder::new(context.eth_spec_instance.clone()) .runtime_context(context) .chain_spec(spec) + .http_api_config(client_config.http_api.clone()) .disk_store(&db_path, &freezer_db_path_res?, store_config)?; let builder = builder @@ -123,7 +124,6 @@ impl ProductionBeaconNode { .network(&client_config.network) .await? .notifier()? - .http_api_config(client_config.http_api.clone()) .http_metrics_config(client_config.http_metrics.clone()) .build() .map(Self) diff --git a/common/eth2_config/src/lib.rs b/common/eth2_config/src/lib.rs index 0002a4d7c36..9ea4e05baa1 100644 --- a/common/eth2_config/src/lib.rs +++ b/common/eth2_config/src/lib.rs @@ -122,6 +122,8 @@ define_net!(spadina, include_spadina_file, "spadina", true); define_net!(zinken, include_zinken_file, "zinken", true); +define_net!(mainnet, include_mainnet_file, "mainnet", false); + #[cfg(test)] mod tests { use super::*; diff --git a/common/eth2_testnet_config/.gitignore b/common/eth2_testnet_config/.gitignore index 9cf78e1ae38..6af8cb7fc5e 100644 --- a/common/eth2_testnet_config/.gitignore +++ b/common/eth2_testnet_config/.gitignore @@ -3,3 +3,4 @@ schlesi-* witti-* /altona* built_in_testnet_configs/*/genesis.ssz +!built_in_testnet_configs/mainnet/genesis.ssz diff --git a/common/eth2_testnet_config/built_in_testnet_configs/mainnet/boot_enr.yaml b/common/eth2_testnet_config/built_in_testnet_configs/mainnet/boot_enr.yaml new file mode 100644 index 00000000000..fe51488c706 --- /dev/null +++ b/common/eth2_testnet_config/built_in_testnet_configs/mainnet/boot_enr.yaml @@ -0,0 +1 @@ +[] diff --git a/common/eth2_testnet_config/built_in_testnet_configs/mainnet/config.yaml b/common/eth2_testnet_config/built_in_testnet_configs/mainnet/config.yaml new file mode 100644 index 00000000000..ace44dd2325 --- /dev/null +++ b/common/eth2_testnet_config/built_in_testnet_configs/mainnet/config.yaml @@ -0,0 +1,155 @@ +# Mainnet preset + +CONFIG_NAME: "mainnet" + +# Misc +# --------------------------------------------------------------- +# 2**6 (= 64) +MAX_COMMITTEES_PER_SLOT: 64 +# 2**7 (= 128) +TARGET_COMMITTEE_SIZE: 128 +# 2**11 (= 2,048) +MAX_VALIDATORS_PER_COMMITTEE: 2048 +# 2**2 (= 4) +MIN_PER_EPOCH_CHURN_LIMIT: 4 +# 2**16 (= 65,536) +CHURN_LIMIT_QUOTIENT: 65536 +# See issue 563 +SHUFFLE_ROUND_COUNT: 90 +# `2**14` (= 16,384) +MIN_GENESIS_ACTIVE_VALIDATOR_COUNT: 16384 +# Dec 1, 2020, 12pm UTC +MIN_GENESIS_TIME: 1606824000 +# 4 +HYSTERESIS_QUOTIENT: 4 +# 1 (minus 0.25) +HYSTERESIS_DOWNWARD_MULTIPLIER: 1 +# 5 (plus 1.25) +HYSTERESIS_UPWARD_MULTIPLIER: 5 + + +# Fork Choice +# --------------------------------------------------------------- +# 2**3 (= 8) +SAFE_SLOTS_TO_UPDATE_JUSTIFIED: 8 + + +# Validator +# --------------------------------------------------------------- +# 2**11 (= 2,048) +ETH1_FOLLOW_DISTANCE: 2048 +# 2**4 (= 16) +TARGET_AGGREGATORS_PER_COMMITTEE: 16 +# 2**0 (= 1) +RANDOM_SUBNETS_PER_VALIDATOR: 1 +# 2**8 (= 256) +EPOCHS_PER_RANDOM_SUBNET_SUBSCRIPTION: 256 +# 14 (estimate from Eth1 mainnet) +SECONDS_PER_ETH1_BLOCK: 14 + + +# Deposit contract +# --------------------------------------------------------------- +# Ethereum PoW Mainnet +DEPOSIT_CHAIN_ID: 1 +DEPOSIT_NETWORK_ID: 1 +# **TBD** +DEPOSIT_CONTRACT_ADDRESS: 0x00000000219ab540356cBB839Cbe05303d7705Fa + + +# Gwei values +# --------------------------------------------------------------- +# 2**0 * 10**9 (= 1,000,000,000) Gwei +MIN_DEPOSIT_AMOUNT: 1000000000 +# 2**5 * 10**9 (= 32,000,000,000) Gwei +MAX_EFFECTIVE_BALANCE: 32000000000 +# 2**4 * 10**9 (= 16,000,000,000) Gwei +EJECTION_BALANCE: 16000000000 +# 2**0 * 10**9 (= 1,000,000,000) Gwei +EFFECTIVE_BALANCE_INCREMENT: 1000000000 + + +# Initial values +# --------------------------------------------------------------- +# Mainnet initial fork version, recommend altering for testnets +GENESIS_FORK_VERSION: 0x00000000 +BLS_WITHDRAWAL_PREFIX: 0x00 + + +# Time parameters +# --------------------------------------------------------------- +# 604800 seconds (7 days) +GENESIS_DELAY: 604800 +# 12 seconds +SECONDS_PER_SLOT: 12 +# 2**0 (= 1) slots 12 seconds +MIN_ATTESTATION_INCLUSION_DELAY: 1 +# 2**5 (= 32) slots 6.4 minutes +SLOTS_PER_EPOCH: 32 +# 2**0 (= 1) epochs 6.4 minutes +MIN_SEED_LOOKAHEAD: 1 +# 2**2 (= 4) epochs 25.6 minutes +MAX_SEED_LOOKAHEAD: 4 +# 2**6 (= 64) epochs ~6.8 hours +EPOCHS_PER_ETH1_VOTING_PERIOD: 64 +# 2**13 (= 8,192) slots ~13 hours +SLOTS_PER_HISTORICAL_ROOT: 8192 +# 2**8 (= 256) epochs ~27 hours +MIN_VALIDATOR_WITHDRAWABILITY_DELAY: 256 +# 2**8 (= 256) epochs ~27 hours +SHARD_COMMITTEE_PERIOD: 256 +# 2**2 (= 4) epochs 25.6 minutes +MIN_EPOCHS_TO_INACTIVITY_PENALTY: 4 + + +# State vector lengths +# --------------------------------------------------------------- +# 2**16 (= 65,536) epochs ~0.8 years +EPOCHS_PER_HISTORICAL_VECTOR: 65536 +# 2**13 (= 8,192) epochs ~36 days +EPOCHS_PER_SLASHINGS_VECTOR: 8192 +# 2**24 (= 16,777,216) historical roots, ~26,131 years +HISTORICAL_ROOTS_LIMIT: 16777216 +# 2**40 (= 1,099,511,627,776) validator spots +VALIDATOR_REGISTRY_LIMIT: 1099511627776 + + +# Reward and penalty quotients +# --------------------------------------------------------------- +# 2**6 (= 64) +BASE_REWARD_FACTOR: 64 +# 2**9 (= 512) +WHISTLEBLOWER_REWARD_QUOTIENT: 512 +# 2**3 (= 8) +PROPOSER_REWARD_QUOTIENT: 8 +# 2**26 (= 67,108,864) +INACTIVITY_PENALTY_QUOTIENT: 67108864 +# 2**7 (= 128) (lower safety margin at Phase 0 genesis) +MIN_SLASHING_PENALTY_QUOTIENT: 128 +# 1 (lower safety margin at Phase 0 genesis) +PROPORTIONAL_SLASHING_MULTIPLIER: 1 + + +# Max operations per block +# --------------------------------------------------------------- +# 2**4 (= 16) +MAX_PROPOSER_SLASHINGS: 16 +# 2**1 (= 2) +MAX_ATTESTER_SLASHINGS: 2 +# 2**7 (= 128) +MAX_ATTESTATIONS: 128 +# 2**4 (= 16) +MAX_DEPOSITS: 16 +# 2**4 (= 16) +MAX_VOLUNTARY_EXITS: 16 + + +# Signature domains +# --------------------------------------------------------------- +DOMAIN_BEACON_PROPOSER: 0x00000000 +DOMAIN_BEACON_ATTESTER: 0x01000000 +DOMAIN_RANDAO: 0x02000000 +DOMAIN_DEPOSIT: 0x03000000 +DOMAIN_VOLUNTARY_EXIT: 0x04000000 +DOMAIN_SELECTION_PROOF: 0x05000000 +DOMAIN_AGGREGATE_AND_PROOF: 0x06000000 diff --git a/common/eth2_testnet_config/built_in_testnet_configs/mainnet/deploy_block.txt b/common/eth2_testnet_config/built_in_testnet_configs/mainnet/deploy_block.txt new file mode 100644 index 00000000000..8066179e334 --- /dev/null +++ b/common/eth2_testnet_config/built_in_testnet_configs/mainnet/deploy_block.txt @@ -0,0 +1 @@ +11184524 diff --git a/common/eth2_testnet_config/built_in_testnet_configs/mainnet/deposit_contract.txt b/common/eth2_testnet_config/built_in_testnet_configs/mainnet/deposit_contract.txt new file mode 100644 index 00000000000..54edc7cf880 --- /dev/null +++ b/common/eth2_testnet_config/built_in_testnet_configs/mainnet/deposit_contract.txt @@ -0,0 +1 @@ +0x00000000219ab540356cBB839Cbe05303d7705Fa diff --git a/common/eth2_testnet_config/built_in_testnet_configs/mainnet/genesis.ssz b/common/eth2_testnet_config/built_in_testnet_configs/mainnet/genesis.ssz new file mode 100644 index 00000000000..e69de29bb2d diff --git a/common/eth2_testnet_config/src/lib.rs b/common/eth2_testnet_config/src/lib.rs index 3f2c2ca9695..0311dcd4300 100644 --- a/common/eth2_testnet_config/src/lib.rs +++ b/common/eth2_testnet_config/src/lib.rs @@ -8,8 +8,8 @@ //! https://github.com/sigp/lighthouse/pull/605 //! use eth2_config::{ - include_altona_file, include_medalla_file, include_spadina_file, include_zinken_file, - testnets_dir, + include_altona_file, include_mainnet_file, include_medalla_file, include_spadina_file, + include_zinken_file, testnets_dir, }; use enr::{CombinedKey, Enr}; @@ -56,8 +56,9 @@ const ALTONA: HardcodedNet = define_net!(altona, include_altona_file); const MEDALLA: HardcodedNet = define_net!(medalla, include_medalla_file); const SPADINA: HardcodedNet = define_net!(spadina, include_spadina_file); const ZINKEN: HardcodedNet = define_net!(zinken, include_zinken_file); +const MAINNET: HardcodedNet = define_net!(mainnet, include_mainnet_file); -const HARDCODED_NETS: &[HardcodedNet] = &[ALTONA, MEDALLA, SPADINA, ZINKEN]; +const HARDCODED_NETS: &[HardcodedNet] = &[ALTONA, MEDALLA, SPADINA, ZINKEN, MAINNET]; pub const DEFAULT_HARDCODED_TESTNET: &str = "medalla"; /// Specifies an Eth2 testnet. @@ -66,6 +67,8 @@ pub const DEFAULT_HARDCODED_TESTNET: &str = "medalla"; #[derive(Clone, PartialEq, Debug)] pub struct Eth2TestnetConfig { pub deposit_contract_address: String, + /// Note: instead of the block where the contract is deployed, it is acceptable to set this + /// value to be the block number where the first deposit occurs. pub deposit_contract_deploy_block: u64, pub boot_enr: Option>>, pub genesis_state_bytes: Option>, @@ -239,7 +242,8 @@ impl Eth2TestnetConfig { file.read_to_end(&mut bytes) .map_err(|e| format!("Unable to read {:?}: {:?}", file, e)) })?; - Some(bytes) + + Some(bytes).filter(|bytes| !bytes.is_empty()) } else { None }; @@ -269,7 +273,7 @@ mod tests { use super::*; use ssz::Encode; use tempdir::TempDir; - use types::{Eth1Data, Hash256, V012LegacyEthSpec, YamlConfig}; + use types::{Eth1Data, Hash256, MainnetEthSpec, V012LegacyEthSpec, YamlConfig}; type E = V012LegacyEthSpec; @@ -279,13 +283,23 @@ mod tests { let config = Eth2TestnetConfig::from_hardcoded_net(net).expect(&format!("{:?}", net.name)); - // Ensure we can parse the YAML config to a chain spec. - config - .yaml_config - .as_ref() - .unwrap() - .apply_to_chain_spec::(&E::default_spec()) - .unwrap(); + if net.name == "mainnet" { + // Ensure we can parse the YAML config to a chain spec. + config + .yaml_config + .as_ref() + .unwrap() + .apply_to_chain_spec::(&E::default_spec()) + .unwrap(); + } else { + // Ensure we can parse the YAML config to a chain spec. + config + .yaml_config + .as_ref() + .unwrap() + .apply_to_chain_spec::(&E::default_spec()) + .unwrap(); + } assert_eq!( config.genesis_state_bytes.is_some(), diff --git a/lighthouse/src/main.rs b/lighthouse/src/main.rs index 23bb5407081..60fab15500d 100644 --- a/lighthouse/src/main.rs +++ b/lighthouse/src/main.rs @@ -115,7 +115,7 @@ fn main() { .long("testnet") .value_name("testnet") .help("Name of network lighthouse will connect to") - .possible_values(&["medalla", "altona", "spadina", "zinken"]) + .possible_values(&["medalla", "altona", "spadina", "zinken", "mainnet"]) .conflicts_with("testnet-dir") .takes_value(true) .global(true) @@ -264,15 +264,22 @@ fn run( warn!( log, - "Ethereum 2.0 is pre-release. This software is experimental." + "Ethereum 2.0 is pre-release. This software is experimental" ); info!(log, "Lighthouse started"; "version" => VERSION); info!( log, "Configured for testnet"; - "name" => testnet_name + "name" => &testnet_name ); + if testnet_name == "mainnet" { + warn!( + log, + "The mainnet specification is being used. This not recommended (yet)." + ) + } + match matches.subcommand() { ("beacon_node", Some(matches)) => { let context = environment.core_context();