From 2f9999752e3068652153112c146121bcffe0a1b8 Mon Sep 17 00:00:00 2001 From: Paul Hauner Date: Mon, 9 Nov 2020 05:04:03 +0000 Subject: [PATCH] Add --testnet mainnet and start HTTP server before genesis (#1862) ## Issue Addressed NA ## Proposed Changes - Adds support for `--testnet mainnet` - Start HTTP server prior to genesis ## Additional Info **Note: This is an incomplete work-in-progress. Use Lighthouse for mainnet at your own risk.** With this PR, you can check the deposits: ```bash lighthouse --testnet mainnet bn --http ``` ```bash curl localhost:5052/lighthouse/eth1/deposit_cache | jq ``` ```json { "data": [ { "deposit_data": { "pubkey": "0x854980aa9bf2e84723e1fa6ef682e3537257984cc9cb1daea2ce6b268084b414f0bb43206e9fa6fd7a202357d6eb2b0d", "withdrawal_credentials": "0x00cacf703c658b802d55baa2a5c1777500ef5051fc084330d2761bcb6ab6182b", "amount": "32000000000", "signature": "0xace226cdfd9da6b1d827c3a6ab93f91f53e8e090eb6ca5ee7c7c5fe3acc75558240ca9291684a2a7af5cac67f0558d1109cc95309f5cdf8c125185ec9dcd22635f900d791316924aed7c40cff2ffccdac0d44cf496853db678c8c53745b3545b" }, "block_number": 3492981, "index": 0, "signature_is_valid": true }, { "deposit_data": { "pubkey": "0x93da03a71bc4ed163c2f91c8a54ea3ba2461383dd615388fd494670f8ce571b46e698fc8d04b49e4a8ffe653f581806b", "withdrawal_credentials": "0x006ebfbb7c8269a78018c8b810492979561d0404d74ba9c234650baa7524dcc4", "amount": "32000000000", "signature": "0x8d1f4a1683f798a76effcc6e2cdb8c3eed5a79123d201c5ecd4ab91f768a03c30885455b8a952aeec3c02110457f97ae0a60724187b6d4129d7c352f2e1ac19b4210daacd892fe4629ad3260ce2911dceae3890b04ed28267b2d8cb831f6a92d" }, "block_number": 3493427, "index": 1, "signature_is_valid": true }, ``` --- beacon_node/client/src/builder.rs | 68 +++++++- beacon_node/src/lib.rs | 2 +- common/eth2_config/src/lib.rs | 2 + common/eth2_testnet_config/.gitignore | 1 + .../mainnet/boot_enr.yaml | 1 + .../mainnet/config.yaml | 155 ++++++++++++++++++ .../mainnet/deploy_block.txt | 1 + .../mainnet/deposit_contract.txt | 1 + .../mainnet/genesis.ssz | 0 common/eth2_testnet_config/src/lib.rs | 38 +++-- lighthouse/src/main.rs | 13 +- 11 files changed, 264 insertions(+), 18 deletions(-) create mode 100644 common/eth2_testnet_config/built_in_testnet_configs/mainnet/boot_enr.yaml create mode 100644 common/eth2_testnet_config/built_in_testnet_configs/mainnet/config.yaml create mode 100644 common/eth2_testnet_config/built_in_testnet_configs/mainnet/deploy_block.txt create mode 100644 common/eth2_testnet_config/built_in_testnet_configs/mainnet/deposit_contract.txt create mode 100644 common/eth2_testnet_config/built_in_testnet_configs/mainnet/genesis.ssz diff --git a/beacon_node/client/src/builder.rs b/beacon_node/client/src/builder.rs index 9d0e6c25f6..58485d9787 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 9fccfb1a5e..e3e4c89e50 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 0002a4d7c3..9ea4e05baa 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 9cf78e1ae3..6af8cb7fc5 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 0000000000..fe51488c70 --- /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 0000000000..ace44dd232 --- /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 0000000000..8066179e33 --- /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 0000000000..54edc7cf88 --- /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 0000000000..e69de29bb2 diff --git a/common/eth2_testnet_config/src/lib.rs b/common/eth2_testnet_config/src/lib.rs index 3f2c2ca969..0311dcd430 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 dff10f5995..25b249ddd7 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) @@ -265,15 +265,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();