diff --git a/beacon_node/beacon_chain/src/test_utils.rs b/beacon_node/beacon_chain/src/test_utils.rs index d267e3a5300..4f213821f5d 100644 --- a/beacon_node/beacon_chain/src/test_utils.rs +++ b/beacon_node/beacon_chain/src/test_utils.rs @@ -640,65 +640,71 @@ where slot, ); - let aggregated_attestations: Vec>> = unaggregated_attestations - .iter() - .map(|committee_attestations| { - // If there are any attestations in this committee, create an aggregate. - if let Some((attestation, _)) = committee_attestations.first() { - let bc = state.get_beacon_committee(attestation.data.slot, attestation.data.index) - .unwrap(); - - let aggregator_index = bc.committee - .iter() - .find(|&validator_index| { - if !attesting_validators.contains(validator_index) { - return false - } - - let selection_proof = SelectionProof::new::( - state.slot(), - &self.validator_keypairs[*validator_index].sk, - &state.fork(), - state.genesis_validators_root(), - &self.spec, - ); + let aggregated_attestations: Vec>> = + unaggregated_attestations + .iter() + .map(|committee_attestations| { + // If there are any attestations in this committee, create an aggregate. + if let Some((attestation, _)) = committee_attestations.first() { + let bc = state + .get_beacon_committee(attestation.data.slot, attestation.data.index) + .unwrap(); - selection_proof.is_aggregator(bc.committee.len(), &self.spec).unwrap_or(false) - }) - .copied() - .unwrap_or_else(|| panic!( - "Committee {} at slot {} with {} attesting validators does not have any aggregators", - bc.index, state.slot(), bc.committee.len() - )); - - // If the chain is able to produce an aggregate, use that. Otherwise, build an - // aggregate locally. - let aggregate = self - .chain - .get_aggregated_attestation(&attestation.data) - .unwrap_or_else(|| { - committee_attestations.iter().skip(1).fold(attestation.clone(), |mut agg, (att, _)| { - agg.aggregate(att); - agg + // Find an aggregator if one exists. Return `None` if there are no + // aggregators. + let aggregator_index = bc + .committee + .iter() + .find(|&validator_index| { + if !attesting_validators.contains(validator_index) { + return false; + } + + let selection_proof = SelectionProof::new::( + state.slot(), + &self.validator_keypairs[*validator_index].sk, + &state.fork(), + state.genesis_validators_root(), + &self.spec, + ); + + selection_proof + .is_aggregator(bc.committee.len(), &self.spec) + .unwrap_or(false) }) - }); - - let signed_aggregate = SignedAggregateAndProof::from_aggregate( - aggregator_index as u64, - aggregate, - None, - &self.validator_keypairs[aggregator_index].sk, - &state.fork(), - state.genesis_validators_root(), - &self.spec, - ); + .copied()?; - Some(signed_aggregate) - } - else { - None - } - }).collect(); + // If the chain is able to produce an aggregate, use that. Otherwise, build an + // aggregate locally. + let aggregate = self + .chain + .get_aggregated_attestation(&attestation.data) + .unwrap_or_else(|| { + committee_attestations.iter().skip(1).fold( + attestation.clone(), + |mut agg, (att, _)| { + agg.aggregate(att); + agg + }, + ) + }); + + let signed_aggregate = SignedAggregateAndProof::from_aggregate( + aggregator_index as u64, + aggregate, + None, + &self.validator_keypairs[aggregator_index].sk, + &state.fork(), + state.genesis_validators_root(), + &self.spec, + ); + + Some(signed_aggregate) + } else { + None + } + }) + .collect(); unaggregated_attestations .into_iter() diff --git a/beacon_node/beacon_chain/tests/block_verification.rs b/beacon_node/beacon_chain/tests/block_verification.rs index 7f4bfeb9fed..446b19195ab 100644 --- a/beacon_node/beacon_chain/tests/block_verification.rs +++ b/beacon_node/beacon_chain/tests/block_verification.rs @@ -866,7 +866,7 @@ fn add_base_block_to_altair_chain() { let slots_per_epoch = MainnetEthSpec::slots_per_epoch(); // The Altair fork happens at epoch 1. - spec.altair_fork_slot = Some(Epoch::new(1).start_slot(slots_per_epoch)); + spec.altair_fork_epoch = Some(Epoch::new(1)); let harness = BeaconChainHarness::new_with_chain_config( MainnetEthSpec, @@ -986,7 +986,7 @@ fn add_altair_block_to_base_chain() { let mut spec = MainnetEthSpec::default_spec(); // Altair never happens. - spec.altair_fork_slot = None; + spec.altair_fork_epoch = None; let harness = BeaconChainHarness::new_with_chain_config( MainnetEthSpec, diff --git a/beacon_node/http_api/src/lib.rs b/beacon_node/http_api/src/lib.rs index bd330bf4e28..b2ec3a64ce2 100644 --- a/beacon_node/http_api/src/lib.rs +++ b/beacon_node/http_api/src/lib.rs @@ -36,8 +36,9 @@ use std::sync::Arc; use tokio::sync::mpsc::UnboundedSender; use tokio_stream::{wrappers::BroadcastStream, StreamExt}; use types::{ - Attestation, AttesterSlashing, CommitteeCache, Epoch, EthSpec, ProposerSlashing, RelativeEpoch, - SignedAggregateAndProof, SignedBeaconBlock, SignedVoluntaryExit, Slot, StandardConfig, + Attestation, AttesterSlashing, CommitteeCache, ConfigAndPreset, Epoch, EthSpec, + ProposerSlashing, RelativeEpoch, SignedAggregateAndProof, SignedBeaconBlock, + SignedVoluntaryExit, Slot, }; use warp::http::StatusCode; use warp::sse::Event; @@ -74,6 +75,7 @@ pub struct Config { pub listen_addr: Ipv4Addr, pub listen_port: u16, pub allow_origin: Option, + pub serve_legacy_spec: bool, } impl Default for Config { @@ -83,6 +85,7 @@ impl Default for Config { listen_addr: Ipv4Addr::new(127, 0, 0, 1), listen_port: 5052, allow_origin: None, + serve_legacy_spec: true, } } } @@ -331,7 +334,8 @@ pub fn serve( .untuple_one(); // Create a `warp` filter that provides access to the logger. - let log_filter = warp::any().map(move || ctx.log.clone()); + let inner_ctx = ctx.clone(); + let log_filter = warp::any().map(move || inner_ctx.log.clone()); /* * @@ -1267,16 +1271,20 @@ pub fn serve( }); // GET config/spec + let serve_legacy_spec = ctx.config.serve_legacy_spec; let get_config_spec = config_path .clone() .and(warp::path("spec")) .and(warp::path::end()) .and(chain_filter.clone()) - .and_then(|chain: Arc>| { + .and_then(move |chain: Arc>| { blocking_json_task(move || { - Ok(api_types::GenericResponse::from( - StandardConfig::from_chain_spec::(&chain.spec), - )) + let mut config_and_preset = + ConfigAndPreset::from_chain_spec::(&chain.spec); + if serve_legacy_spec { + config_and_preset.make_backwards_compat(&chain.spec); + } + Ok(api_types::GenericResponse::from(config_and_preset)) }) }); diff --git a/beacon_node/http_api/tests/tests.rs b/beacon_node/http_api/tests/tests.rs index 957891d0b0d..75d75330682 100644 --- a/beacon_node/http_api/tests/tests.rs +++ b/beacon_node/http_api/tests/tests.rs @@ -186,6 +186,7 @@ impl ApiTester { listen_addr: Ipv4Addr::new(127, 0, 0, 1), listen_port: 0, allow_origin: None, + serve_legacy_spec: true, }, chain: Some(chain.clone()), network_tx: Some(network_tx), @@ -294,6 +295,7 @@ impl ApiTester { listen_addr: Ipv4Addr::new(127, 0, 0, 1), listen_port: 0, allow_origin: None, + serve_legacy_spec: true, }, chain: Some(chain.clone()), network_tx: Some(network_tx), @@ -1253,7 +1255,8 @@ impl ApiTester { pub async fn test_get_config_spec(self) -> Self { let result = self.client.get_config_spec().await.unwrap().data; - let expected = StandardConfig::from_chain_spec::(&self.chain.spec); + let mut expected = ConfigAndPreset::from_chain_spec::(&self.chain.spec); + expected.make_backwards_compat(&self.chain.spec); assert_eq!(result, expected); diff --git a/beacon_node/operation_pool/src/attestation.rs b/beacon_node/operation_pool/src/attestation.rs index a3a151a79c2..2ed580cae28 100644 --- a/beacon_node/operation_pool/src/attestation.rs +++ b/beacon_node/operation_pool/src/attestation.rs @@ -5,7 +5,7 @@ use state_processing::common::{ use std::collections::HashMap; use types::{ beacon_state::BeaconStateBase, - consts::altair::{FLAG_INDICES_AND_WEIGHTS, WEIGHT_DENOMINATOR}, + consts::altair::{PARTICIPATION_FLAG_WEIGHTS, WEIGHT_DENOMINATOR}, Attestation, BeaconState, BitList, ChainSpec, EthSpec, }; @@ -100,9 +100,9 @@ impl<'a, T: EthSpec> AttMaxCover<'a, T> { let base_reward = altair::get_base_reward(state, index, total_active_balance, spec).ok()?; - for (flag_index, weight) in &FLAG_INDICES_AND_WEIGHTS { - if att_participation_flags.contains(flag_index) - && !participation.has_flag(*flag_index).ok()? + for (flag_index, weight) in PARTICIPATION_FLAG_WEIGHTS.iter().enumerate() { + if att_participation_flags.contains(&flag_index) + && !participation.has_flag(flag_index).ok()? { proposer_reward_numerator += base_reward.checked_mul(*weight)?; } diff --git a/beacon_node/src/cli.rs b/beacon_node/src/cli.rs index fb871c2e2cd..4c309ae4ff0 100644 --- a/beacon_node/src/cli.rs +++ b/beacon_node/src/cli.rs @@ -198,6 +198,12 @@ pub fn cli_app<'a, 'b>() -> App<'a, 'b> { address of this server (e.g., http://localhost:5052).") .takes_value(true), ) + .arg( + Arg::with_name("http-disable-legacy-spec") + .long("http-disable-legacy-spec") + .help("Disable serving of legacy data on the /config/spec endpoint. May be \ + disabled by default in a future release.") + ) /* Prometheus metrics HTTP server related arguments */ .arg( Arg::with_name("metrics") diff --git a/beacon_node/src/config.rs b/beacon_node/src/config.rs index 0550e8e0850..089845961dc 100644 --- a/beacon_node/src/config.rs +++ b/beacon_node/src/config.rs @@ -107,6 +107,10 @@ pub fn get_config( client_config.http_api.allow_origin = Some(allow_origin.to_string()); } + if cli_args.is_present("http-disable-legacy-spec") { + client_config.http_api.serve_legacy_spec = false; + } + /* * Prometheus metrics HTTP server */ diff --git a/beacon_node/store/src/partial_beacon_state.rs b/beacon_node/store/src/partial_beacon_state.rs index 6f51c4f57b5..a6cd02bbc37 100644 --- a/beacon_node/store/src/partial_beacon_state.rs +++ b/beacon_node/store/src/partial_beacon_state.rs @@ -178,10 +178,11 @@ impl PartialBeaconState { )?; let slot = Slot::from_ssz_bytes(slot_bytes)?; + let epoch = slot.epoch(T::slots_per_epoch()); if spec - .altair_fork_slot - .map_or(true, |altair_slot| slot < altair_slot) + .altair_fork_epoch + .map_or(true, |altair_epoch| epoch < altair_epoch) { PartialBeaconStateBase::from_ssz_bytes(bytes).map(Self::Base) } else { diff --git a/common/eth2/src/lib.rs b/common/eth2/src/lib.rs index 60f016ad2d2..19269337640 100644 --- a/common/eth2/src/lib.rs +++ b/common/eth2/src/lib.rs @@ -715,7 +715,7 @@ impl BeaconNodeHttpClient { } /// `GET config/spec` - pub async fn get_config_spec(&self) -> Result, Error> { + pub async fn get_config_spec(&self) -> Result, Error> { let mut path = self.eth_path()?; path.path_segments_mut() diff --git a/common/eth2/src/lighthouse_vc/http_client.rs b/common/eth2/src/lighthouse_vc/http_client.rs index b27bca813fe..c6a12350987 100644 --- a/common/eth2/src/lighthouse_vc/http_client.rs +++ b/common/eth2/src/lighthouse_vc/http_client.rs @@ -211,7 +211,7 @@ impl ValidatorClientHttpClient { } /// `GET lighthouse/spec` - pub async fn get_lighthouse_spec(&self) -> Result, Error> { + pub async fn get_lighthouse_spec(&self) -> Result, Error> { let mut path = self.server.full.clone(); path.path_segments_mut() diff --git a/common/eth2_config/src/lib.rs b/common/eth2_config/src/lib.rs index fe296b27917..c30dab5df7a 100644 --- a/common/eth2_config/src/lib.rs +++ b/common/eth2_config/src/lib.rs @@ -109,6 +109,4 @@ define_net!(pyrmont, include_pyrmont_file, "pyrmont", true); define_net!(mainnet, include_mainnet_file, "mainnet", true); -define_net!(toledo, include_toledo_file, "toledo", true); - define_net!(prater, include_prater_file, "prater", true); diff --git a/common/eth2_network_config/build.rs b/common/eth2_network_config/build.rs index 1a559f387e2..d84dbde4d88 100644 --- a/common/eth2_network_config/build.rs +++ b/common/eth2_network_config/build.rs @@ -1,7 +1,5 @@ //! Extracts zipped genesis states on first run. -use eth2_config::{ - mainnet, prater, pyrmont, toledo, Eth2NetArchiveAndDirectory, GENESIS_FILE_NAME, -}; +use eth2_config::{mainnet, prater, pyrmont, Eth2NetArchiveAndDirectory, GENESIS_FILE_NAME}; use std::fs::File; use std::io; use zip::ZipArchive; @@ -9,7 +7,6 @@ use zip::ZipArchive; const ETH2_NET_DIRS: &[Eth2NetArchiveAndDirectory<'static>] = &[ mainnet::ETH2_NET_DIR, pyrmont::ETH2_NET_DIR, - toledo::ETH2_NET_DIR, prater::ETH2_NET_DIR, ]; diff --git a/common/eth2_network_config/built_in_network_configs/mainnet/altair.yaml b/common/eth2_network_config/built_in_network_configs/mainnet/altair.yaml deleted file mode 100644 index 2a2552da401..00000000000 --- a/common/eth2_network_config/built_in_network_configs/mainnet/altair.yaml +++ /dev/null @@ -1,53 +0,0 @@ -# Mainnet preset - Altair - -CONFIG_NAME: "mainnet" - -# Updated penalty values -# --------------------------------------------------------------- -# 3 * 2**24 (= 50,331,648) -INACTIVITY_PENALTY_QUOTIENT_ALTAIR: 50331648 -# 2**6 (= 64) -MIN_SLASHING_PENALTY_QUOTIENT_ALTAIR: 64 -# 2 -PROPORTIONAL_SLASHING_MULTIPLIER_ALTAIR: 2 - - -# Misc -# --------------------------------------------------------------- -# 2**10 (= 1,024) -SYNC_COMMITTEE_SIZE: 1024 -# 2**6 (= 64) -SYNC_PUBKEYS_PER_AGGREGATE: 64 -# 2**2 (= 4) -INACTIVITY_SCORE_BIAS: 4 - - -# Time parameters -# --------------------------------------------------------------- -# 2**8 (= 256) -EPOCHS_PER_SYNC_COMMITTEE_PERIOD: 256 - - -# Signature domains -# --------------------------------------------------------------- -DOMAIN_SYNC_COMMITTEE: 0x07000000 -DOMAIN_SYNC_COMMITTEE_SELECTION_PROOF: 0x08000000 -DOMAIN_CONTRIBUTION_AND_PROOF: 0x09000000 - - -# Fork -# --------------------------------------------------------------- -# 0x01000000 -ALTAIR_FORK_VERSION: 0x01000000 -# TBD -ALTAIR_FORK_SLOT: 18446744073709551615 - - -# Sync protocol -# --------------------------------------------------------------- -# 1 -MIN_SYNC_COMMITTEE_PARTICIPANTS: 1 -# 2**13 -MAX_VALID_LIGHT_CLIENT_UPDATES: 8192 -# 2**13 (=8192) -LIGHT_CLIENT_UPDATE_TIMEOUT: 8192 diff --git a/common/eth2_network_config/built_in_network_configs/mainnet/config.yaml b/common/eth2_network_config/built_in_network_configs/mainnet/config.yaml index ace44dd2325..47b02aa8d97 100644 --- a/common/eth2_network_config/built_in_network_configs/mainnet/config.yaml +++ b/common/eth2_network_config/built_in_network_configs/mainnet/config.yaml @@ -1,155 +1,71 @@ -# Mainnet preset +# Mainnet config -CONFIG_NAME: "mainnet" +# Extends the mainnet preset +PRESET_BASE: 'mainnet' -# Misc +# Genesis # --------------------------------------------------------------- -# 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 +# Mainnet initial fork version, recommend altering for testnets +GENESIS_FORK_VERSION: 0x00000000 +# 604800 seconds (7 days) +GENESIS_DELAY: 604800 -# Gwei values +# Forking # --------------------------------------------------------------- -# 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 +# Some forks are disabled for now: +# - These may be re-assigned to another fork-version later +# - Temporarily set to max uint64 value: 2**64 - 1 +# Altair +ALTAIR_FORK_VERSION: 0x01000000 +ALTAIR_FORK_EPOCH: 18446744073709551615 +# Merge +MERGE_FORK_VERSION: 0x02000000 +MERGE_FORK_EPOCH: 18446744073709551615 +# Sharding +SHARDING_FORK_VERSION: 0x03000000 +SHARDING_FORK_EPOCH: 18446744073709551615 -# Initial values -# --------------------------------------------------------------- -# Mainnet initial fork version, recommend altering for testnets -GENESIS_FORK_VERSION: 0x00000000 -BLS_WITHDRAWAL_PREFIX: 0x00 +# TBD, 2**32 is a placeholder. Merge transition approach is in active R&D. +TRANSITION_TOTAL_DIFFICULTY: 4294967296 # 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 +# 14 (estimate from Eth1 mainnet) +SECONDS_PER_ETH1_BLOCK: 14 # 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 +# 2**11 (= 2,048) Eth1 blocks ~8 hours +ETH1_FOLLOW_DISTANCE: 2048 -# Max operations per block +# Validator cycle # --------------------------------------------------------------- +# 2**2 (= 4) +INACTIVITY_SCORE_BIAS: 4 # 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 +INACTIVITY_SCORE_RECOVERY_RATE: 16 +# 2**4 * 10**9 (= 16,000,000,000) Gwei +EJECTION_BALANCE: 16000000000 +# 2**2 (= 4) +MIN_PER_EPOCH_CHURN_LIMIT: 4 +# 2**16 (= 65,536) +CHURN_LIMIT_QUOTIENT: 65536 -# Signature domains +# Deposit contract # --------------------------------------------------------------- -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 +# Ethereum PoW Mainnet +DEPOSIT_CHAIN_ID: 1 +DEPOSIT_NETWORK_ID: 1 +DEPOSIT_CONTRACT_ADDRESS: 0x00000000219ab540356cBB839Cbe05303d7705Fa diff --git a/common/eth2_network_config/built_in_network_configs/prater/altair.yaml b/common/eth2_network_config/built_in_network_configs/prater/altair.yaml deleted file mode 100644 index 2a2552da401..00000000000 --- a/common/eth2_network_config/built_in_network_configs/prater/altair.yaml +++ /dev/null @@ -1,53 +0,0 @@ -# Mainnet preset - Altair - -CONFIG_NAME: "mainnet" - -# Updated penalty values -# --------------------------------------------------------------- -# 3 * 2**24 (= 50,331,648) -INACTIVITY_PENALTY_QUOTIENT_ALTAIR: 50331648 -# 2**6 (= 64) -MIN_SLASHING_PENALTY_QUOTIENT_ALTAIR: 64 -# 2 -PROPORTIONAL_SLASHING_MULTIPLIER_ALTAIR: 2 - - -# Misc -# --------------------------------------------------------------- -# 2**10 (= 1,024) -SYNC_COMMITTEE_SIZE: 1024 -# 2**6 (= 64) -SYNC_PUBKEYS_PER_AGGREGATE: 64 -# 2**2 (= 4) -INACTIVITY_SCORE_BIAS: 4 - - -# Time parameters -# --------------------------------------------------------------- -# 2**8 (= 256) -EPOCHS_PER_SYNC_COMMITTEE_PERIOD: 256 - - -# Signature domains -# --------------------------------------------------------------- -DOMAIN_SYNC_COMMITTEE: 0x07000000 -DOMAIN_SYNC_COMMITTEE_SELECTION_PROOF: 0x08000000 -DOMAIN_CONTRIBUTION_AND_PROOF: 0x09000000 - - -# Fork -# --------------------------------------------------------------- -# 0x01000000 -ALTAIR_FORK_VERSION: 0x01000000 -# TBD -ALTAIR_FORK_SLOT: 18446744073709551615 - - -# Sync protocol -# --------------------------------------------------------------- -# 1 -MIN_SYNC_COMMITTEE_PARTICIPANTS: 1 -# 2**13 -MAX_VALID_LIGHT_CLIENT_UPDATES: 8192 -# 2**13 (=8192) -LIGHT_CLIENT_UPDATE_TIMEOUT: 8192 diff --git a/common/eth2_network_config/built_in_network_configs/prater/config.yaml b/common/eth2_network_config/built_in_network_configs/prater/config.yaml index 6328a92ddca..e99939cabd2 100644 --- a/common/eth2_network_config/built_in_network_configs/prater/config.yaml +++ b/common/eth2_network_config/built_in_network_configs/prater/config.yaml @@ -1,155 +1,70 @@ -# Prater preset +# Prater config -CONFIG_NAME: "prater" +# Extends the mainnet preset +PRESET_BASE: 'mainnet' -# Misc +# Genesis # --------------------------------------------------------------- -# 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 # Mar-01-2021 08:53:32 AM +UTC MIN_GENESIS_TIME: 1614588812 -# 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 Goerli testnet -DEPOSIT_CHAIN_ID: 5 -DEPOSIT_NETWORK_ID: 5 -# Prater test deposit contract on Goerli Testnet -DEPOSIT_CONTRACT_ADDRESS: 0xff50ed3d0ec03aC01D4C79aAd74928BFF48a7b2b - +# Prater area code (Vienna) +GENESIS_FORK_VERSION: 0x00001020 +# Customized for Prater: 1919188 seconds (Mar-23-2021 02:00:00 PM +UTC) +GENESIS_DELAY: 1919188 -# Gwei values +# Forking # --------------------------------------------------------------- -# 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 +# Some forks are disabled for now: +# - These may be re-assigned to another fork-version later +# - Temporarily set to max uint64 value: 2**64 - 1 +# Altair +ALTAIR_FORK_VERSION: 0x01000000 +ALTAIR_FORK_EPOCH: 18446744073709551615 +# Merge +MERGE_FORK_VERSION: 0x02000000 +MERGE_FORK_EPOCH: 18446744073709551615 +# Sharding +SHARDING_FORK_VERSION: 0x03000000 +SHARDING_FORK_EPOCH: 18446744073709551615 -# Initial values -# --------------------------------------------------------------- -# Prater area code (Vienna) -GENESIS_FORK_VERSION: 0x00001020 -BLS_WITHDRAWAL_PREFIX: 0x00 +# TBD, 2**32 is a placeholder. Merge transition approach is in active R&D. +TRANSITION_TOTAL_DIFFICULTY: 4294967296 # Time parameters # --------------------------------------------------------------- -# Customized for Prater: 1919188 seconds (Mar-23-2021 02:00:00 PM +UTC) -GENESIS_DELAY: 1919188 # 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 +# 14 (estimate from Eth1 mainnet) +SECONDS_PER_ETH1_BLOCK: 14 # 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 +# 2**11 (= 2,048) Eth1 blocks ~8 hours +ETH1_FOLLOW_DISTANCE: 2048 -# Max operations per block +# Validator cycle # --------------------------------------------------------------- +# 2**2 (= 4) +INACTIVITY_SCORE_BIAS: 4 # 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 - +INACTIVITY_SCORE_RECOVERY_RATE: 16 +# 2**4 * 10**9 (= 16,000,000,000) Gwei +EJECTION_BALANCE: 16000000000 +# 2**2 (= 4) +MIN_PER_EPOCH_CHURN_LIMIT: 4 +# 2**16 (= 65,536) +CHURN_LIMIT_QUOTIENT: 65536 -# Signature domains +# Deposit contract # --------------------------------------------------------------- -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 +# Ethereum Goerli testnet +DEPOSIT_CHAIN_ID: 5 +DEPOSIT_NETWORK_ID: 5 +# Prater test deposit contract on Goerli Testnet +DEPOSIT_CONTRACT_ADDRESS: 0xff50ed3d0ec03aC01D4C79aAd74928BFF48a7b2b diff --git a/common/eth2_network_config/built_in_network_configs/pyrmont/altair.yaml b/common/eth2_network_config/built_in_network_configs/pyrmont/altair.yaml deleted file mode 100644 index 2a2552da401..00000000000 --- a/common/eth2_network_config/built_in_network_configs/pyrmont/altair.yaml +++ /dev/null @@ -1,53 +0,0 @@ -# Mainnet preset - Altair - -CONFIG_NAME: "mainnet" - -# Updated penalty values -# --------------------------------------------------------------- -# 3 * 2**24 (= 50,331,648) -INACTIVITY_PENALTY_QUOTIENT_ALTAIR: 50331648 -# 2**6 (= 64) -MIN_SLASHING_PENALTY_QUOTIENT_ALTAIR: 64 -# 2 -PROPORTIONAL_SLASHING_MULTIPLIER_ALTAIR: 2 - - -# Misc -# --------------------------------------------------------------- -# 2**10 (= 1,024) -SYNC_COMMITTEE_SIZE: 1024 -# 2**6 (= 64) -SYNC_PUBKEYS_PER_AGGREGATE: 64 -# 2**2 (= 4) -INACTIVITY_SCORE_BIAS: 4 - - -# Time parameters -# --------------------------------------------------------------- -# 2**8 (= 256) -EPOCHS_PER_SYNC_COMMITTEE_PERIOD: 256 - - -# Signature domains -# --------------------------------------------------------------- -DOMAIN_SYNC_COMMITTEE: 0x07000000 -DOMAIN_SYNC_COMMITTEE_SELECTION_PROOF: 0x08000000 -DOMAIN_CONTRIBUTION_AND_PROOF: 0x09000000 - - -# Fork -# --------------------------------------------------------------- -# 0x01000000 -ALTAIR_FORK_VERSION: 0x01000000 -# TBD -ALTAIR_FORK_SLOT: 18446744073709551615 - - -# Sync protocol -# --------------------------------------------------------------- -# 1 -MIN_SYNC_COMMITTEE_PARTICIPANTS: 1 -# 2**13 -MAX_VALID_LIGHT_CLIENT_UPDATES: 8192 -# 2**13 (=8192) -LIGHT_CLIENT_UPDATE_TIMEOUT: 8192 diff --git a/common/eth2_network_config/built_in_network_configs/pyrmont/config.yaml b/common/eth2_network_config/built_in_network_configs/pyrmont/config.yaml index f9d1b92be4c..2cdca808d85 100644 --- a/common/eth2_network_config/built_in_network_configs/pyrmont/config.yaml +++ b/common/eth2_network_config/built_in_network_configs/pyrmont/config.yaml @@ -1,154 +1,70 @@ -# Pyrmont preset -CONFIG_NAME: "pyrmont" +# Pyrmont config -# Misc +# Extends the mainnet preset +PRESET_BASE: 'mainnet' + +# Genesis # --------------------------------------------------------------- -# 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 # Nov 18, 2020, 12pm UTC MIN_GENESIS_TIME: 1605700800 -# 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 - +# Pyrmont area code +GENESIS_FORK_VERSION: 0x00002009 +# Customized for Pyrmont: 432000 seconds (5 days) +GENESIS_DELAY: 432000 -# Deposit contract +# Forking # --------------------------------------------------------------- -# Ethereum Goerli testnet -DEPOSIT_CHAIN_ID: 5 -DEPOSIT_NETWORK_ID: 5 -# Pyrmont test deposit contract on Goerli (2nd edition, 0x00002009 fork version) -DEPOSIT_CONTRACT_ADDRESS: 0x8c5fecdC472E27Bc447696F431E425D02dd46a8c +# Some forks are disabled for now: +# - These may be re-assigned to another fork-version later +# - Temporarily set to max uint64 value: 2**64 - 1 +# Altair +ALTAIR_FORK_VERSION: 0x01000000 +ALTAIR_FORK_EPOCH: 18446744073709551615 +# Merge +MERGE_FORK_VERSION: 0x02000000 +MERGE_FORK_EPOCH: 18446744073709551615 +# Sharding +SHARDING_FORK_VERSION: 0x03000000 +SHARDING_FORK_EPOCH: 18446744073709551615 -# 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 -# --------------------------------------------------------------- -# Pyrmont area code -GENESIS_FORK_VERSION: 0x00002009 -BLS_WITHDRAWAL_PREFIX: 0x00 +# TBD, 2**32 is a placeholder. Merge transition approach is in active R&D. +TRANSITION_TOTAL_DIFFICULTY: 4294967296 # Time parameters # --------------------------------------------------------------- -# Customized for Pyrmont: 432000 seconds (5 days) -GENESIS_DELAY: 432000 # 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 +# 14 (estimate from Eth1 mainnet) +SECONDS_PER_ETH1_BLOCK: 14 # 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 +# 2**11 (= 2,048) Eth1 blocks ~8 hours +ETH1_FOLLOW_DISTANCE: 2048 -# Max operations per block +# Validator cycle # --------------------------------------------------------------- +# 2**2 (= 4) +INACTIVITY_SCORE_BIAS: 4 # 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 - +INACTIVITY_SCORE_RECOVERY_RATE: 16 +# 2**4 * 10**9 (= 16,000,000,000) Gwei +EJECTION_BALANCE: 16000000000 +# 2**2 (= 4) +MIN_PER_EPOCH_CHURN_LIMIT: 4 +# 2**16 (= 65,536) +CHURN_LIMIT_QUOTIENT: 65536 -# Signature domains +# Deposit contract # --------------------------------------------------------------- -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 +# Ethereum Goerli testnet +DEPOSIT_CHAIN_ID: 5 +DEPOSIT_NETWORK_ID: 5 +# Pyrmont test deposit contract on Goerli (2nd edition, 0x00002009 fork version) +DEPOSIT_CONTRACT_ADDRESS: 0x8c5fecdC472E27Bc447696F431E425D02dd46a8c diff --git a/common/eth2_network_config/built_in_network_configs/toledo/altair.yaml b/common/eth2_network_config/built_in_network_configs/toledo/altair.yaml deleted file mode 100644 index 2a2552da401..00000000000 --- a/common/eth2_network_config/built_in_network_configs/toledo/altair.yaml +++ /dev/null @@ -1,53 +0,0 @@ -# Mainnet preset - Altair - -CONFIG_NAME: "mainnet" - -# Updated penalty values -# --------------------------------------------------------------- -# 3 * 2**24 (= 50,331,648) -INACTIVITY_PENALTY_QUOTIENT_ALTAIR: 50331648 -# 2**6 (= 64) -MIN_SLASHING_PENALTY_QUOTIENT_ALTAIR: 64 -# 2 -PROPORTIONAL_SLASHING_MULTIPLIER_ALTAIR: 2 - - -# Misc -# --------------------------------------------------------------- -# 2**10 (= 1,024) -SYNC_COMMITTEE_SIZE: 1024 -# 2**6 (= 64) -SYNC_PUBKEYS_PER_AGGREGATE: 64 -# 2**2 (= 4) -INACTIVITY_SCORE_BIAS: 4 - - -# Time parameters -# --------------------------------------------------------------- -# 2**8 (= 256) -EPOCHS_PER_SYNC_COMMITTEE_PERIOD: 256 - - -# Signature domains -# --------------------------------------------------------------- -DOMAIN_SYNC_COMMITTEE: 0x07000000 -DOMAIN_SYNC_COMMITTEE_SELECTION_PROOF: 0x08000000 -DOMAIN_CONTRIBUTION_AND_PROOF: 0x09000000 - - -# Fork -# --------------------------------------------------------------- -# 0x01000000 -ALTAIR_FORK_VERSION: 0x01000000 -# TBD -ALTAIR_FORK_SLOT: 18446744073709551615 - - -# Sync protocol -# --------------------------------------------------------------- -# 1 -MIN_SYNC_COMMITTEE_PARTICIPANTS: 1 -# 2**13 -MAX_VALID_LIGHT_CLIENT_UPDATES: 8192 -# 2**13 (=8192) -LIGHT_CLIENT_UPDATE_TIMEOUT: 8192 diff --git a/common/eth2_network_config/built_in_network_configs/toledo/boot_enr.yaml b/common/eth2_network_config/built_in_network_configs/toledo/boot_enr.yaml deleted file mode 100644 index 9b3f564b8e3..00000000000 --- a/common/eth2_network_config/built_in_network_configs/toledo/boot_enr.yaml +++ /dev/null @@ -1,20 +0,0 @@ -# discv5.1-only bootnode @protolambda -- enr:-Ku4QL5E378NT4-vqP6v1mZ7kHxiTHJvuBvQixQsuTTCffa0PJNWMBlG3Mduvsvd6T2YP1U3l5tBKO5H-9wyX2SCtPkBh2F0dG5ldHOIAAAAAAAAAACEZXRoMpC4EvfsAHAe0P__________gmlkgnY0gmlwhDaetEeJc2VjcDI1NmsxoQKtGC2CAuba7goLLdle899M3esUmoWRvzi7GBVhq6ViCYN1ZHCCIyg - -# lighthouse (Canada) @protolambda -- enr:-LK4QHLujdDjOwm2siyFJ2XGz19_ip-qTtozG3ceZ3_56G-LMWb4um67gTSYRJg0WsSkyvRMBEpz8uuIYl-7HfWvktgBh2F0dG5ldHOIAAAAAAAAAACEZXRoMpCXm69nAHAe0P__________gmlkgnY0gmlwhCO3C5OJc2VjcDI1NmsxoQKXw9BLDY6YwmqTtfkzUnlJQb82UrlX4lIAnSSYWHFRlYN0Y3CCIyiDdWRwgiMo - -# lighthouse (Sao Paulo) @protolambda -- enr:-LK4QMxmk7obupScBebKFaasSH3QmYUg-HaEmMAljfmGQCLbKwdOhszzx-VfVPvlH7bZZbOmg3-SNWbJsFfytdjD7a4Bh2F0dG5ldHOIAAAAAAAAAACEZXRoMpCXm69nAHAe0P__________gmlkgnY0gmlwhBLkdWuJc2VjcDI1NmsxoQOwYsJyLOjJcDIqiQSSZtDi_EwwSaUjPBSnLVY_PYu-HoN0Y3CCIyiDdWRwgiMo - -# Teku @protolambda -- enr:-KG4QKqo0mG4C35ntJg8icO54wd973aZ7aBiAnC2t1XkGvgqNDOEHwNe2ykxYVUj9AWjm_lKD7brlhXKCZEskGbie2cDhGV0aDKQl5uvZwBwHtD__________4JpZIJ2NIJpcIQNOThwiXNlY3AyNTZrMaECn1dwC8MRt8rk2VUT8RjzEBaceF09d4CEQI20O_SWYcqDdGNwgiMog3VkcIIjKA - -# Prysm @protolambda -- enr:-LK4QAhU5smiLgU0AgrdFv8eCKmDPCBkXCMCIy8Aktaci5qvCYOsW98xVqJS6OoPWt4Sz_YoTdLQBWxd-RZ756vmGPMBh2F0dG5ldHOIAAAAAAAAAACEZXRoMpCXm69nAHAe0P__________gmlkgnY0gmlwhDTTDL2Jc2VjcDI1NmsxoQOmSJ0mKsQjab7Zralm1Hi0AEReZ2SEqYdKoOPmoA98DoN0Y3CCIyiDdWRwgiMo - -# Lighthouse: @sigp -- enr:-LK4QBsu_4I-tmA5WgxkJWRuVUCj2_QE2mmrwX0sFvAc3NR_YPrub4kpvPCb_OjKLwEefxey81SAcvQ7mr2Vvh8xhbgBh2F0dG5ldHOIAAAAAAAAAACEZXRoMpCXm69nAHAe0P__________gmlkgnY0gmlwhA3UHZWJc2VjcDI1NmsxoQL9FPylFeunleHuPXlbB938eIMd3X9y9cJ8ZI8y3Li0u4N0Y3CCIyiDdWRwgiMo - -# Lighthouse: @sigp -- enr:-LK4QEfW9TCASUUy8L5xamlTVs3JbgT8iYOUspJkbh3rj-BuUndLjtonockiN2K_0g-cBQGq-wvsgAiz5Q3-ic-Wz_ABh2F0dG5ldHOIAAAAAAAAAACEZXRoMpCXm69nAHAe0P__________gmlkgnY0gmlwhCLV8-OJc2VjcDI1NmsxoQKYJuiXbqPzkbT0NAKIJneNWiX0136HiYI9qtx5NF1IloN0Y3CCIyiDdWRwgiMo diff --git a/common/eth2_network_config/built_in_network_configs/toledo/deploy_block.txt b/common/eth2_network_config/built_in_network_configs/toledo/deploy_block.txt deleted file mode 100644 index 99798b05602..00000000000 --- a/common/eth2_network_config/built_in_network_configs/toledo/deploy_block.txt +++ /dev/null @@ -1 +0,0 @@ -3702432 diff --git a/common/eth2_network_config/built_in_network_configs/toledo/genesis.ssz.zip b/common/eth2_network_config/built_in_network_configs/toledo/genesis.ssz.zip deleted file mode 100644 index 842591737af..00000000000 Binary files a/common/eth2_network_config/built_in_network_configs/toledo/genesis.ssz.zip and /dev/null differ diff --git a/common/eth2_network_config/src/lib.rs b/common/eth2_network_config/src/lib.rs index 24dd2c210ae..337990b7a85 100644 --- a/common/eth2_network_config/src/lib.rs +++ b/common/eth2_network_config/src/lib.rs @@ -4,21 +4,18 @@ use enr::{CombinedKey, Enr}; use std::fs::{create_dir_all, File}; use std::io::{Read, Write}; use std::path::PathBuf; -use types::{AltairConfig, BaseConfig, BeaconState, ChainSpec, EthSpec, EthSpecId, StandardConfig}; +use types::{BeaconState, ChainSpec, Config, EthSpec, EthSpecId}; -pub const ADDRESS_FILE: &str = "deposit_contract.txt"; pub const DEPLOY_BLOCK_FILE: &str = "deploy_block.txt"; pub const BOOT_ENR_FILE: &str = "boot_enr.yaml"; pub const GENESIS_STATE_FILE: &str = "genesis.ssz"; pub const BASE_CONFIG_FILE: &str = "config.yaml"; -pub const ALTAIR_CONFIG_FILE: &str = "altair.yaml"; #[derive(Copy, Clone, Debug, PartialEq)] pub struct HardcodedNet { pub name: &'static str, pub genesis_is_known: bool, - pub base_config: &'static [u8], - pub altair_config: &'static [u8], + pub config: &'static [u8], pub deploy_block: &'static [u8], pub boot_enr: &'static [u8], pub genesis_state_bytes: &'static [u8], @@ -31,8 +28,7 @@ macro_rules! define_net { HardcodedNet { name: ETH2_NET_DIR.name, genesis_is_known: ETH2_NET_DIR.genesis_is_known, - base_config: $include_file!("../", "config.yaml"), - altair_config: $include_file!("../", "altair.yaml"), + config: $include_file!("../", "config.yaml"), deploy_block: $include_file!("../", "deploy_block.txt"), boot_enr: $include_file!("../", "boot_enr.yaml"), genesis_state_bytes: $include_file!("../", "genesis.ssz"), @@ -42,10 +38,9 @@ macro_rules! define_net { const PYRMONT: HardcodedNet = define_net!(pyrmont, include_pyrmont_file); const MAINNET: HardcodedNet = define_net!(mainnet, include_mainnet_file); -const TOLEDO: HardcodedNet = define_net!(toledo, include_toledo_file); const PRATER: HardcodedNet = define_net!(prater, include_prater_file); -const HARDCODED_NETS: &[HardcodedNet] = &[PYRMONT, MAINNET, TOLEDO, PRATER]; +const HARDCODED_NETS: &[HardcodedNet] = &[PYRMONT, MAINNET, PRATER]; pub const DEFAULT_HARDCODED_NETWORK: &str = "mainnet"; /// Specifies an Eth2 network. @@ -58,8 +53,7 @@ pub struct Eth2NetworkConfig { pub deposit_contract_deploy_block: u64, pub boot_enr: Option>>, pub genesis_state_bytes: Option>, - pub base_config: BaseConfig, - pub altair_config: AltairConfig, + pub config: Config, } impl Eth2NetworkConfig { @@ -84,19 +78,17 @@ impl Eth2NetworkConfig { ), genesis_state_bytes: Some(net.genesis_state_bytes.to_vec()) .filter(|bytes| !bytes.is_empty()), - base_config: serde_yaml::from_reader(net.base_config) + config: serde_yaml::from_reader(net.config) .map_err(|e| format!("Unable to parse yaml config: {:?}", e))?, - altair_config: serde_yaml::from_reader(net.altair_config) - .map_err(|e| format!("Unable to parse Altair config: {:?}", e))?, }) } /// Returns an identifier that should be used for selecting an `EthSpec` instance for this /// network configuration. pub fn eth_spec_id(&self) -> Result { - self.base_config + self.config .eth_spec_id() - .ok_or_else(|| format!("Unknown CONFIG_NAME: {}", self.base_config.config_name)) + .ok_or_else(|| "Config does not match any known preset".to_string()) } /// Returns `true` if this configuration contains a `BeaconState`. @@ -106,12 +98,10 @@ impl Eth2NetworkConfig { /// Construct a consolidated `ChainSpec` from the YAML config. pub fn chain_spec(&self) -> Result { - let standard_config = - StandardConfig::from_parts(self.base_config.clone(), self.altair_config.clone()); - ChainSpec::from_standard_config::(&standard_config).ok_or_else(|| { + ChainSpec::from_config::(&self.config).ok_or_else(|| { format!( "YAML configuration incompatible with spec constants for {}", - self.base_config.config_name + E::spec_name() ) }) } @@ -174,8 +164,7 @@ impl Eth2NetworkConfig { write_to_yaml_file!(BOOT_ENR_FILE, boot_enr); } - write_to_yaml_file!(BASE_CONFIG_FILE, &self.base_config); - write_to_yaml_file!(ALTAIR_CONFIG_FILE, &self.altair_config); + write_to_yaml_file!(BASE_CONFIG_FILE, &self.config); // The genesis state is a special case because it uses SSZ, not YAML. if let Some(genesis_state_bytes) = &self.genesis_state_bytes { @@ -216,8 +205,7 @@ impl Eth2NetworkConfig { let deposit_contract_deploy_block = load_from_file!(DEPLOY_BLOCK_FILE); let boot_enr = optional_load_from_file!(BOOT_ENR_FILE); - let base_config = load_from_file!(BASE_CONFIG_FILE); - let altair_config = load_from_file!(ALTAIR_CONFIG_FILE); + let config = load_from_file!(BASE_CONFIG_FILE); // The genesis state is a special case because it uses SSZ, not YAML. let genesis_file_path = base_dir.join(GENESIS_STATE_FILE); @@ -239,8 +227,7 @@ impl Eth2NetworkConfig { deposit_contract_deploy_block, boot_enr, genesis_state_bytes, - base_config, - altair_config, + config, }) } } @@ -250,7 +237,7 @@ mod tests { use super::*; use ssz::Encode; use tempfile::Builder as TempBuilder; - use types::{BaseConfig, Eth1Data, Hash256, MainnetEthSpec}; + use types::{Config, Eth1Data, Hash256, MainnetEthSpec}; type E = MainnetEthSpec; @@ -260,14 +247,8 @@ mod tests { let config = Eth2NetworkConfig::from_hardcoded_net(net) .unwrap_or_else(|_| panic!("{:?}", net.name)); - if net.name == "mainnet" - || net.name == "toledo" - || net.name == "pyrmont" - || net.name == "prater" - { - // Ensure we can parse the YAML config to a chain spec. - config.chain_spec::().unwrap(); - } + // Ensure we can parse the YAML config to a chain spec. + config.chain_spec::().unwrap(); assert_eq!( config.genesis_state_bytes.is_some(), @@ -291,23 +272,16 @@ mod tests { // TODO: figure out how to generate ENR and add some here. let boot_enr = None; let genesis_state = Some(BeaconState::new(42, eth1_data, spec)); - let base_config = BaseConfig::from_chain_spec::(spec); - let altair_config = AltairConfig::from_chain_spec::(spec); + let config = Config::from_chain_spec::(spec); - do_test::( - boot_enr, - genesis_state, - base_config.clone(), - altair_config.clone(), - ); - do_test::(None, None, base_config, altair_config); + do_test::(boot_enr, genesis_state, config.clone()); + do_test::(None, None, config); } fn do_test( boot_enr: Option>>, genesis_state: Option>, - base_config: BaseConfig, - altair_config: AltairConfig, + config: Config, ) { let temp_dir = TempBuilder::new() .prefix("eth2_testnet_test") @@ -320,8 +294,7 @@ mod tests { deposit_contract_deploy_block, boot_enr, genesis_state_bytes: genesis_state.as_ref().map(Encode::as_ssz_bytes), - base_config, - altair_config, + config, }; testnet diff --git a/consensus/state_processing/src/common/get_attestation_participation.rs b/consensus/state_processing/src/common/get_attestation_participation.rs index 066f193bef2..499d8fa8f86 100644 --- a/consensus/state_processing/src/common/get_attestation_participation.rs +++ b/consensus/state_processing/src/common/get_attestation_participation.rs @@ -21,7 +21,7 @@ pub fn get_attestation_participation_flag_indices( data: &AttestationData, inclusion_delay: u64, spec: &ChainSpec, -) -> Result, Error> { +) -> Result, Error> { let justified_checkpoint = if data.target.epoch == state.current_epoch() { state.current_justified_checkpoint() } else { diff --git a/consensus/state_processing/src/genesis.rs b/consensus/state_processing/src/genesis.rs index b1937c72e63..bbc24534081 100644 --- a/consensus/state_processing/src/genesis.rs +++ b/consensus/state_processing/src/genesis.rs @@ -2,6 +2,7 @@ use super::per_block_processing::{ errors::BlockProcessingError, process_operations::process_deposit, }; use crate::common::DepositDataTree; +use crate::upgrade::upgrade_to_altair; use safe_arith::{ArithError, SafeArith}; use tree_hash::TreeHash; use types::DEPOSIT_TREE_DEPTH; @@ -40,16 +41,13 @@ pub fn initialize_beacon_state_from_eth1( // To support testnets with Altair enabled from genesis, perform a possible state upgrade here. // This must happen *after* deposits and activations are processed or the calculation of sync - // committees during the upgrade will fail. - if spec.fork_name_at_slot(state.slot()) == ForkName::Altair { - state.upgrade_to_altair(spec)?; - - // Reset the sync committees (this seems to be what the tests want) - state.as_altair_mut()?.current_sync_committee = SyncCommittee::temporary()?; - state.as_altair_mut()?.next_sync_committee = SyncCommittee::temporary()?; - - // Reset the fork version too. - state.fork_mut().current_version = spec.genesis_fork_version; + // committees during the upgrade will fail. It's a bit cheeky to do this instead of having + // separate Altair genesis initialization logic, but it turns out that our + // use of `BeaconBlock::empty` in `BeaconState::new` is sufficient to correctly initialise + // the `latest_block_header` as per: + // https://github.com/ethereum/eth2.0-specs/pull/2323 + if spec.fork_name_at_epoch(state.current_epoch()) == ForkName::Altair { + upgrade_to_altair(&mut state, spec)?; } // Now that we have our validators, initialize the caches (including the committees) diff --git a/consensus/state_processing/src/lib.rs b/consensus/state_processing/src/lib.rs index 519bae4bf97..91959cd866b 100644 --- a/consensus/state_processing/src/lib.rs +++ b/consensus/state_processing/src/lib.rs @@ -21,6 +21,7 @@ pub mod per_block_processing; pub mod per_epoch_processing; pub mod per_slot_processing; pub mod state_advance; +pub mod upgrade; pub mod verify_operation; pub use genesis::{ diff --git a/consensus/state_processing/src/per_block_processing/process_operations.rs b/consensus/state_processing/src/per_block_processing/process_operations.rs index ea998151756..d576396fb83 100644 --- a/consensus/state_processing/src/per_block_processing/process_operations.rs +++ b/consensus/state_processing/src/per_block_processing/process_operations.rs @@ -6,7 +6,7 @@ use crate::common::{ use crate::per_block_processing::errors::{BlockProcessingError, IntoWithIndex}; use crate::VerifySignatures; use safe_arith::SafeArith; -use types::consts::altair::{FLAG_INDICES_AND_WEIGHTS, PROPOSER_WEIGHT, WEIGHT_DENOMINATOR}; +use types::consts::altair::{PARTICIPATION_FLAG_WEIGHTS, PROPOSER_WEIGHT, WEIGHT_DENOMINATOR}; pub fn process_operations<'a, T: EthSpec>( state: &mut BeaconState, @@ -122,7 +122,7 @@ pub mod altair { for index in &indexed_attestation.attesting_indices { let index = *index as usize; - for &(flag_index, weight) in FLAG_INDICES_AND_WEIGHTS.iter() { + for (flag_index, &weight) in PARTICIPATION_FLAG_WEIGHTS.iter().enumerate() { let epoch_participation = state.get_epoch_participation_mut(data.target.epoch)?; let validator_participation = epoch_participation .get_mut(index) diff --git a/consensus/state_processing/src/per_epoch_processing/altair/inactivity_updates.rs b/consensus/state_processing/src/per_epoch_processing/altair/inactivity_updates.rs index 51f6c5aa811..cc629c1ef09 100644 --- a/consensus/state_processing/src/per_epoch_processing/altair/inactivity_updates.rs +++ b/consensus/state_processing/src/per_epoch_processing/altair/inactivity_updates.rs @@ -2,16 +2,21 @@ use crate::EpochProcessingError; use core::result::Result; use core::result::Result::Ok; use safe_arith::SafeArith; +use std::cmp::min; use types::beacon_state::BeaconState; use types::chain_spec::ChainSpec; use types::consts::altair::TIMELY_TARGET_FLAG_INDEX; use types::eth_spec::EthSpec; -// FIXME(altair): there's no EF test for this one (yet) pub fn process_inactivity_updates( state: &mut BeaconState, spec: &ChainSpec, ) -> Result<(), EpochProcessingError> { + // Score updates based on previous epoch participation, skip genesis epoch + if state.current_epoch() == T::genesis_epoch() { + return Ok(()); + } + let unslashed_indices = state.get_unslashed_participating_indices( TIMELY_TARGET_FLAG_INDEX, state.previous_epoch(), @@ -19,16 +24,21 @@ pub fn process_inactivity_updates( )?; for index in state.get_eligible_validator_indices()? { + // Increase inactivity score of inactive validators if unslashed_indices.contains(&index) { let inactivity_score = state.get_inactivity_score_mut(index)?; - if *inactivity_score > 0 { - inactivity_score.safe_sub_assign(1)?; - } - } else if state.is_in_inactivity_leak(spec) { + inactivity_score.safe_sub_assign(min(1, *inactivity_score))?; + } else { state .get_inactivity_score_mut(index)? .safe_add_assign(spec.inactivity_score_bias)?; } + // Decrease the score of all validators for forgiveness when not during a leak + if !state.is_in_inactivity_leak(spec) { + let inactivity_score = state.get_inactivity_score_mut(index)?; + inactivity_score + .safe_sub_assign(min(spec.inactivity_score_recovery_rate, *inactivity_score))?; + } } Ok(()) } diff --git a/consensus/state_processing/src/per_epoch_processing/altair/participation_flag_updates.rs b/consensus/state_processing/src/per_epoch_processing/altair/participation_flag_updates.rs index 7ad583ca4fa..7162fa7f4af 100644 --- a/consensus/state_processing/src/per_epoch_processing/altair/participation_flag_updates.rs +++ b/consensus/state_processing/src/per_epoch_processing/altair/participation_flag_updates.rs @@ -6,7 +6,6 @@ use types::eth_spec::EthSpec; use types::participation_flags::ParticipationFlags; use types::VariableList; -//TODO: there's no EF test for this one pub fn process_participation_flag_updates( state: &mut BeaconState, ) -> Result<(), EpochProcessingError> { diff --git a/consensus/state_processing/src/per_epoch_processing/altair/rewards_and_penalties.rs b/consensus/state_processing/src/per_epoch_processing/altair/rewards_and_penalties.rs index 8f23e45a831..6e1475d06d0 100644 --- a/consensus/state_processing/src/per_epoch_processing/altair/rewards_and_penalties.rs +++ b/consensus/state_processing/src/per_epoch_processing/altair/rewards_and_penalties.rs @@ -1,6 +1,7 @@ use safe_arith::SafeArith; use types::consts::altair::{ - FLAG_INDICES_AND_WEIGHTS, TIMELY_TARGET_FLAG_INDEX, WEIGHT_DENOMINATOR, + PARTICIPATION_FLAG_WEIGHTS, TIMELY_HEAD_FLAG_INDEX, TIMELY_TARGET_FLAG_INDEX, + WEIGHT_DENOMINATOR, }; use types::{BeaconState, ChainSpec, EthSpec}; @@ -22,18 +23,11 @@ pub fn process_rewards_and_penalties( let total_active_balance = state.get_total_active_balance(spec)?; - for (index, numerator) in FLAG_INDICES_AND_WEIGHTS.iter() { - get_flag_index_deltas( - &mut deltas, - state, - *index, - *numerator, - total_active_balance, - spec, - )?; + for flag_index in 0..PARTICIPATION_FLAG_WEIGHTS.len() { + get_flag_index_deltas(&mut deltas, state, flag_index, total_active_balance, spec)?; } - get_inactivity_penalty_deltas(&mut deltas, state, total_active_balance, spec)?; + get_inactivity_penalty_deltas(&mut deltas, state, spec)?; // Apply the deltas, erroring on overflow above but not on overflow below (saturating at 0 // instead). @@ -51,28 +45,26 @@ pub fn process_rewards_and_penalties( pub fn get_flag_index_deltas( deltas: &mut Vec, state: &BeaconState, - flag_index: u32, - weight: u64, + flag_index: usize, total_active_balance: u64, spec: &ChainSpec, ) -> Result<(), Error> { + let previous_epoch = state.previous_epoch(); let unslashed_participating_indices = - state.get_unslashed_participating_indices(flag_index, state.previous_epoch(), spec)?; - let increment = spec.effective_balance_increment; //Factored out from balances to avoid uint64 overflow - let unslashed_participating_increments = state - .get_total_balance(&unslashed_participating_indices, spec)? - .safe_div(increment)?; - let active_increments = total_active_balance.safe_div(increment)?; + state.get_unslashed_participating_indices(flag_index, previous_epoch, spec)?; + let weight = get_flag_weight(flag_index)?; + let unslashed_participating_balance = + state.get_total_balance(&unslashed_participating_indices, spec)?; + let unslashed_participating_increments = + unslashed_participating_balance.safe_div(spec.effective_balance_increment)?; + let active_increments = total_active_balance.safe_div(spec.effective_balance_increment)?; for index in state.get_eligible_validator_indices()? { let base_reward = get_base_reward(state, index, total_active_balance, spec)?; let mut delta = Delta::default(); if unslashed_participating_indices.contains(&(index as usize)) { - if state.is_in_inactivity_leak(spec) { - // This flag reward cancels the inactivity penalty corresponding to the flag index - delta.reward(base_reward.safe_mul(weight)?.safe_div(WEIGHT_DENOMINATOR)?)?; - } else { + if !state.is_in_inactivity_leak(spec) { let reward_numerator = base_reward .safe_mul(weight)? .safe_mul(unslashed_participating_increments)?; @@ -80,7 +72,7 @@ pub fn get_flag_index_deltas( reward_numerator.safe_div(active_increments.safe_mul(WEIGHT_DENOMINATOR)?)?, )?; } - } else { + } else if flag_index != TIMELY_HEAD_FLAG_INDEX { delta.penalize(base_reward.safe_mul(weight)?.safe_div(WEIGHT_DENOMINATOR)?)?; } deltas @@ -91,44 +83,42 @@ pub fn get_flag_index_deltas( Ok(()) } +/// Get the weight for a `flag_index` from the constant list of all weights. +pub fn get_flag_weight(flag_index: usize) -> Result { + PARTICIPATION_FLAG_WEIGHTS + .get(flag_index) + .copied() + .ok_or(Error::InvalidFlagIndex(flag_index)) +} + pub fn get_inactivity_penalty_deltas( deltas: &mut Vec, state: &BeaconState, - total_active_balance: u64, spec: &ChainSpec, ) -> Result<(), Error> { - if state.is_in_inactivity_leak(spec) { - let previous_epoch = state.previous_epoch(); - let matching_target_indices = state.get_unslashed_participating_indices( - TIMELY_TARGET_FLAG_INDEX, - previous_epoch, - spec, - )?; - for index in state.get_eligible_validator_indices()? { - let mut delta = Delta::default(); + let previous_epoch = state.previous_epoch(); + let matching_target_indices = state.get_unslashed_participating_indices( + TIMELY_TARGET_FLAG_INDEX, + previous_epoch, + spec, + )?; + for index in state.get_eligible_validator_indices()? { + let mut delta = Delta::default(); - for (_, weight) in FLAG_INDICES_AND_WEIGHTS.iter() { - delta.penalize( - get_base_reward(state, index, total_active_balance, spec)? - .safe_mul(*weight)? - .safe_div(WEIGHT_DENOMINATOR)?, - )?; - } - if !matching_target_indices.contains(&index) { - let penalty_numerator = state - .get_validator(index)? - .effective_balance - .safe_mul(state.get_inactivity_score(index)?)?; - let penalty_denominator = spec - .inactivity_score_bias - .safe_mul(spec.inactivity_penalty_quotient_altair)?; - delta.penalize(penalty_numerator.safe_div(penalty_denominator)?)?; - } - deltas - .get_mut(index) - .ok_or(Error::DeltaOutOfBounds(index))? - .combine(delta)?; + if !matching_target_indices.contains(&index) { + let penalty_numerator = state + .get_validator(index)? + .effective_balance + .safe_mul(state.get_inactivity_score(index)?)?; + let penalty_denominator = spec + .inactivity_score_bias + .safe_mul(spec.inactivity_penalty_quotient_altair)?; + delta.penalize(penalty_numerator.safe_div(penalty_denominator)?)?; } + deltas + .get_mut(index) + .ok_or(Error::DeltaOutOfBounds(index))? + .combine(delta)?; } Ok(()) } diff --git a/consensus/state_processing/src/per_epoch_processing/altair/sync_committee_updates.rs b/consensus/state_processing/src/per_epoch_processing/altair/sync_committee_updates.rs index e7216e60e47..1edc845cb4e 100644 --- a/consensus/state_processing/src/per_epoch_processing/altair/sync_committee_updates.rs +++ b/consensus/state_processing/src/per_epoch_processing/altair/sync_committee_updates.rs @@ -12,10 +12,7 @@ pub fn process_sync_committee_updates( if next_epoch.safe_rem(spec.epochs_per_sync_committee_period)? == 0 { *state.current_sync_committee_mut()? = state.next_sync_committee()?.clone(); - *state.next_sync_committee_mut()? = state.get_sync_committee( - next_epoch.safe_add(spec.epochs_per_sync_committee_period)?, - spec, - )?; + *state.next_sync_committee_mut()? = state.get_next_sync_committee(spec)?; } Ok(()) } diff --git a/consensus/state_processing/src/per_epoch_processing/errors.rs b/consensus/state_processing/src/per_epoch_processing/errors.rs index 738d8b012d9..651bf41ca26 100644 --- a/consensus/state_processing/src/per_epoch_processing/errors.rs +++ b/consensus/state_processing/src/per_epoch_processing/errors.rs @@ -22,6 +22,7 @@ pub enum EpochProcessingError { ArithError(safe_arith::ArithError), InconsistentStateFork(InconsistentFork), InvalidJustificationBit(ssz_types::Error), + InvalidFlagIndex(usize), } impl From for EpochProcessingError { diff --git a/consensus/state_processing/src/per_epoch_processing/tests.rs b/consensus/state_processing/src/per_epoch_processing/tests.rs index d05837d268b..ac1ce6b0194 100644 --- a/consensus/state_processing/src/per_epoch_processing/tests.rs +++ b/consensus/state_processing/src/per_epoch_processing/tests.rs @@ -52,7 +52,7 @@ mod release_tests { let mut spec = MainnetEthSpec::default_spec(); let slots_per_epoch = MainnetEthSpec::slots_per_epoch(); // The Altair fork happens at epoch 1. - spec.altair_fork_slot = Some(Epoch::new(1).start_slot(slots_per_epoch)); + spec.altair_fork_epoch = Some(Epoch::new(1)); let altair_state = { let harness = BeaconChainHarness::new( @@ -87,7 +87,7 @@ mod release_tests { .expect("state passes intial slot processing"); // Modify the spec so altair never happens. - spec.altair_fork_slot = None; + spec.altair_fork_epoch = None; let expected_err = InconsistentFork { fork_at_slot: ForkName::Base, @@ -110,7 +110,7 @@ mod release_tests { let mut spec = MainnetEthSpec::default_spec(); let slots_per_epoch = MainnetEthSpec::slots_per_epoch(); // The Altair fork never happens. - spec.altair_fork_slot = None; + spec.altair_fork_epoch = None; let base_state = { let harness = BeaconChainHarness::new( @@ -145,7 +145,7 @@ mod release_tests { .expect("state passes intial slot processing"); // Modify the spec so Altair happens at the first epoch. - spec.altair_fork_slot = Some(Epoch::new(1).start_slot(slots_per_epoch)); + spec.altair_fork_epoch = Some(Epoch::new(1)); let expected_err = InconsistentFork { fork_at_slot: ForkName::Altair, diff --git a/consensus/state_processing/src/per_slot_processing.rs b/consensus/state_processing/src/per_slot_processing.rs index df427761c54..3413a0d02a4 100644 --- a/consensus/state_processing/src/per_slot_processing.rs +++ b/consensus/state_processing/src/per_slot_processing.rs @@ -1,3 +1,4 @@ +use crate::upgrade::upgrade_to_altair; use crate::{per_epoch_processing::EpochProcessingSummary, *}; use safe_arith::{ArithError, SafeArith}; use types::*; @@ -21,8 +22,6 @@ impl From for Error { /// If the root of the supplied `state` is known, then it can be passed as `state_root`. If /// `state_root` is `None`, the root of `state` will be computed using a cached tree hash. /// Providing the `state_root` makes this function several orders of magniude faster. -/// -/// Spec v0.12.1 pub fn per_slot_processing( state: &mut BeaconState, state_root: Option, @@ -45,9 +44,11 @@ pub fn per_slot_processing( state.slot_mut().safe_add_assign(1)?; - // If the Altair fork slot is reached, perform an irregular state upgrade. - if spec.altair_fork_slot == Some(state.slot()) { - state.upgrade_to_altair(spec)?; + // If the Altair fork epoch is reached, perform an irregular state upgrade. + if state.slot().safe_rem(T::slots_per_epoch())? == 0 + && spec.altair_fork_epoch == Some(state.current_epoch()) + { + upgrade_to_altair(state, spec)?; } Ok(summary) diff --git a/consensus/state_processing/src/upgrade.rs b/consensus/state_processing/src/upgrade.rs new file mode 100644 index 00000000000..ca8e515967e --- /dev/null +++ b/consensus/state_processing/src/upgrade.rs @@ -0,0 +1,3 @@ +pub mod altair; + +pub use altair::upgrade_to_altair; diff --git a/consensus/state_processing/src/upgrade/altair.rs b/consensus/state_processing/src/upgrade/altair.rs new file mode 100644 index 00000000000..34ccc9e0b0d --- /dev/null +++ b/consensus/state_processing/src/upgrade/altair.rs @@ -0,0 +1,119 @@ +use crate::common::{get_attestation_participation_flag_indices, get_attesting_indices}; +use std::mem; +use types::{ + BeaconState, BeaconStateAltair, BeaconStateError as Error, ChainSpec, EthSpec, Fork, + ParticipationFlags, PendingAttestation, RelativeEpoch, SyncCommittee, VariableList, +}; + +/// Translate the participation information from the epoch prior to the fork into Altair's format. +pub fn translate_participation( + state: &mut BeaconState, + pending_attestations: &VariableList, E::MaxPendingAttestations>, + spec: &ChainSpec, +) -> Result<(), Error> { + // Previous epoch committee cache is required for `get_attesting_indices`. + state.build_committee_cache(RelativeEpoch::Previous, spec)?; + + for attestation in pending_attestations { + let data = &attestation.data; + let inclusion_delay = attestation.inclusion_delay; + + // Translate attestation inclusion info to flag indices. + let participation_flag_indices = + get_attestation_participation_flag_indices(state, data, inclusion_delay, spec)?; + + // Apply flags to all attesting validators. + let committee = state.get_beacon_committee(data.slot, data.index)?; + let attesting_indices = + get_attesting_indices::(&committee.committee, &attestation.aggregation_bits)?; + let epoch_participation = state.previous_epoch_participation_mut()?; + + for index in attesting_indices { + for flag_index in &participation_flag_indices { + epoch_participation + .get_mut(index) + .ok_or(Error::UnknownValidator(index))? + .add_flag(*flag_index)?; + } + } + } + Ok(()) +} + +/// Transform a `Base` state into an `Altair` state. +pub fn upgrade_to_altair( + pre_state: &mut BeaconState, + spec: &ChainSpec, +) -> Result<(), Error> { + let epoch = pre_state.current_epoch(); + let pre = pre_state.as_base_mut()?; + + let default_epoch_participation = + VariableList::new(vec![ParticipationFlags::default(); pre.validators.len()])?; + let inactivity_scores = VariableList::new(vec![0; pre.validators.len()])?; + + // Where possible, use something like `mem::take` to move fields from behind the &mut + // reference. For other fields that don't have a good default value, use `clone`. + // + // Fixed size vectors get cloned because replacing them would require the same size + // allocation as cloning. + let mut post = BeaconState::Altair(BeaconStateAltair { + // Versioning + genesis_time: pre.genesis_time, + genesis_validators_root: pre.genesis_validators_root, + slot: pre.slot, + fork: Fork { + previous_version: pre.fork.current_version, + current_version: spec.altair_fork_version, + epoch, + }, + // History + latest_block_header: pre.latest_block_header.clone(), + block_roots: pre.block_roots.clone(), + state_roots: pre.state_roots.clone(), + historical_roots: mem::take(&mut pre.historical_roots), + // Eth1 + eth1_data: pre.eth1_data.clone(), + eth1_data_votes: mem::take(&mut pre.eth1_data_votes), + eth1_deposit_index: pre.eth1_deposit_index, + // Registry + validators: mem::take(&mut pre.validators), + balances: mem::take(&mut pre.balances), + // Randomness + randao_mixes: pre.randao_mixes.clone(), + // Slashings + slashings: pre.slashings.clone(), + // `Participation + previous_epoch_participation: default_epoch_participation.clone(), + current_epoch_participation: default_epoch_participation, + // Finality + justification_bits: pre.justification_bits.clone(), + previous_justified_checkpoint: pre.previous_justified_checkpoint, + current_justified_checkpoint: pre.current_justified_checkpoint, + finalized_checkpoint: pre.finalized_checkpoint, + // Inactivity + inactivity_scores, + // Sync committees + current_sync_committee: SyncCommittee::temporary()?, // not read + next_sync_committee: SyncCommittee::temporary()?, // not read + // Caches + committee_caches: mem::take(&mut pre.committee_caches), + pubkey_cache: mem::take(&mut pre.pubkey_cache), + exit_cache: mem::take(&mut pre.exit_cache), + tree_hash_cache: mem::take(&mut pre.tree_hash_cache), + }); + + // Fill in previous epoch participation from the pre state's pending attestations. + translate_participation(&mut post, &pre.previous_epoch_attestations, spec)?; + + // Fill in sync committees + // Note: A duplicate committee is assigned for the current and next committee at the fork + // boundary + let sync_committee = post.get_next_sync_committee(spec)?; + post.as_altair_mut()?.current_sync_committee = sync_committee.clone(); + post.as_altair_mut()?.next_sync_committee = sync_committee; + + *pre_state = post; + + Ok(()) +} diff --git a/consensus/types/presets/mainnet/altair.yaml b/consensus/types/presets/mainnet/altair.yaml new file mode 100644 index 00000000000..9f0ad9b4ce0 --- /dev/null +++ b/consensus/types/presets/mainnet/altair.yaml @@ -0,0 +1,24 @@ +# Mainnet preset - Altair + +# Updated penalty values +# --------------------------------------------------------------- +# 3 * 2**24 (= 50,331,648) +INACTIVITY_PENALTY_QUOTIENT_ALTAIR: 50331648 +# 2**6 (= 64) +MIN_SLASHING_PENALTY_QUOTIENT_ALTAIR: 64 +# 2 +PROPORTIONAL_SLASHING_MULTIPLIER_ALTAIR: 2 + + +# Sync committee +# --------------------------------------------------------------- +# 2**9 (= 512) +SYNC_COMMITTEE_SIZE: 512 +# 2**9 (= 512) +EPOCHS_PER_SYNC_COMMITTEE_PERIOD: 512 + + +# Sync protocol +# --------------------------------------------------------------- +# 1 +MIN_SYNC_COMMITTEE_PARTICIPANTS: 1 diff --git a/common/eth2_network_config/built_in_network_configs/toledo/config.yaml b/consensus/types/presets/mainnet/phase0.yaml similarity index 58% rename from common/eth2_network_config/built_in_network_configs/toledo/config.yaml rename to consensus/types/presets/mainnet/phase0.yaml index 99a9012d732..89bb97d6a87 100644 --- a/common/eth2_network_config/built_in_network_configs/toledo/config.yaml +++ b/consensus/types/presets/mainnet/phase0.yaml @@ -1,6 +1,4 @@ -# Toledo preset, variant of mainnet - -CONFIG_NAME: "toledo" +# Mainnet preset - Phase0 # Misc # --------------------------------------------------------------- @@ -10,16 +8,8 @@ MAX_COMMITTEES_PER_SLOT: 64 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 -# Nov 10, 2020, 12pm UTC -MIN_GENESIS_TIME: 1605009600 # 4 HYSTERESIS_QUOTIENT: 4 # 1 (minus 0.25) @@ -34,53 +24,18 @@ HYSTERESIS_UPWARD_MULTIPLIER: 5 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 Goerli testnet -DEPOSIT_CHAIN_ID: 5 -DEPOSIT_NETWORK_ID: 5 -# Toledo permissioned test deposit contract on Goerli -DEPOSIT_CONTRACT_ADDRESS: 0x47709dC7a8c18688a1f051761fc34ac253970bC0 - - # 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 -# --------------------------------------------------------------- -GENESIS_FORK_VERSION: 0x00701ED0 -BLS_WITHDRAWAL_PREFIX: 0x00 - - # Time parameters # --------------------------------------------------------------- -# 86400 seconds (1 day) -GENESIS_DELAY: 86400 -# 12 seconds -SECONDS_PER_SLOT: 12 # 2**0 (= 1) slots 12 seconds MIN_ATTESTATION_INCLUSION_DELAY: 1 # 2**5 (= 32) slots 6.4 minutes @@ -91,17 +46,13 @@ MIN_SEED_LOOKAHEAD: 1 MAX_SEED_LOOKAHEAD: 4 # 2**6 (= 64) epochs ~6.8 hours EPOCHS_PER_ETH1_VOTING_PERIOD: 64 -# 2**13 (= 8,192) slots ~13 hours +# 2**13 (= 8,192) slots ~27 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 +# State list lengths # --------------------------------------------------------------- # 2**16 (= 65,536) epochs ~0.8 years EPOCHS_PER_HISTORICAL_VECTOR: 65536 @@ -141,14 +92,3 @@ MAX_ATTESTATIONS: 128 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/consensus/types/presets/minimal/altair.yaml b/consensus/types/presets/minimal/altair.yaml new file mode 100644 index 00000000000..88d78bea365 --- /dev/null +++ b/consensus/types/presets/minimal/altair.yaml @@ -0,0 +1,24 @@ +# Minimal preset - Altair + +# Updated penalty values +# --------------------------------------------------------------- +# 3 * 2**24 (= 50,331,648) +INACTIVITY_PENALTY_QUOTIENT_ALTAIR: 50331648 +# 2**6 (= 64) +MIN_SLASHING_PENALTY_QUOTIENT_ALTAIR: 64 +# 2 +PROPORTIONAL_SLASHING_MULTIPLIER_ALTAIR: 2 + + +# Sync committee +# --------------------------------------------------------------- +# [customized] +SYNC_COMMITTEE_SIZE: 32 +# [customized] +EPOCHS_PER_SYNC_COMMITTEE_PERIOD: 8 + + +# Sync protocol +# --------------------------------------------------------------- +# 1 +MIN_SYNC_COMMITTEE_PARTICIPANTS: 1 diff --git a/consensus/types/presets/minimal/phase0.yaml b/consensus/types/presets/minimal/phase0.yaml new file mode 100644 index 00000000000..c9c81325f1b --- /dev/null +++ b/consensus/types/presets/minimal/phase0.yaml @@ -0,0 +1,94 @@ +# Minimal preset - Phase0 + +# Misc +# --------------------------------------------------------------- +# [customized] Just 4 committees for slot for testing purposes +MAX_COMMITTEES_PER_SLOT: 4 +# [customized] unsecure, but fast +TARGET_COMMITTEE_SIZE: 4 +# 2**11 (= 2,048) +MAX_VALIDATORS_PER_COMMITTEE: 2048 +# [customized] Faster, but unsecure. +SHUFFLE_ROUND_COUNT: 10 +# 4 +HYSTERESIS_QUOTIENT: 4 +# 1 (minus 0.25) +HYSTERESIS_DOWNWARD_MULTIPLIER: 1 +# 5 (plus 1.25) +HYSTERESIS_UPWARD_MULTIPLIER: 5 + + +# Fork Choice +# --------------------------------------------------------------- +# 2**1 (= 1) +SAFE_SLOTS_TO_UPDATE_JUSTIFIED: 2 + + +# 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**0 * 10**9 (= 1,000,000,000) Gwei +EFFECTIVE_BALANCE_INCREMENT: 1000000000 + + +# Time parameters +# --------------------------------------------------------------- +# 2**0 (= 1) slots 6 seconds +MIN_ATTESTATION_INCLUSION_DELAY: 1 +# [customized] fast epochs +SLOTS_PER_EPOCH: 8 +# 2**0 (= 1) epochs +MIN_SEED_LOOKAHEAD: 1 +# 2**2 (= 4) epochs +MAX_SEED_LOOKAHEAD: 4 +# [customized] higher frequency new deposits from eth1 for testing +EPOCHS_PER_ETH1_VOTING_PERIOD: 4 +# [customized] smaller state +SLOTS_PER_HISTORICAL_ROOT: 64 +# 2**2 (= 4) epochs +MIN_EPOCHS_TO_INACTIVITY_PENALTY: 4 + + +# State list lengths +# --------------------------------------------------------------- +# [customized] smaller state +EPOCHS_PER_HISTORICAL_VECTOR: 64 +# [customized] smaller state +EPOCHS_PER_SLASHINGS_VECTOR: 64 +# 2**24 (= 16,777,216) historical roots +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 +# [customized] 2**25 (= 33,554,432) +INACTIVITY_PENALTY_QUOTIENT: 33554432 +# [customized] 2**6 (= 64) +MIN_SLASHING_PENALTY_QUOTIENT: 64 +# [customized] 2 (lower safety margin than Phase 0 genesis but different than mainnet config for testing) +PROPORTIONAL_SLASHING_MULTIPLIER: 2 + + +# 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 diff --git a/consensus/types/src/beacon_block.rs b/consensus/types/src/beacon_block.rs index 2293b572dca..67caabd570f 100644 --- a/consensus/types/src/beacon_block.rs +++ b/consensus/types/src/beacon_block.rs @@ -58,7 +58,7 @@ impl<'a, T: EthSpec> SignedRoot for BeaconBlockRef<'a, T> {} impl BeaconBlock { /// Returns an empty block to be used during genesis. pub fn empty(spec: &ChainSpec) -> Self { - if spec.altair_fork_slot == Some(spec.genesis_slot) { + if spec.altair_fork_epoch == Some(T::genesis_epoch()) { Self::Altair(BeaconBlockAltair::empty(spec)) } else { Self::Base(BeaconBlockBase::empty(spec)) @@ -171,10 +171,11 @@ impl BeaconBlock { })?; let slot = Slot::from_ssz_bytes(slot_bytes)?; + let epoch = slot.epoch(T::slots_per_epoch()); if spec - .altair_fork_slot - .map_or(true, |altair_slot| slot < altair_slot) + .altair_fork_epoch + .map_or(true, |altair_epoch| epoch < altair_epoch) { BeaconBlockBase::from_ssz_bytes(bytes).map(Self::Base) } else { @@ -393,15 +394,19 @@ mod tests { #[test] fn decode_base_and_altair() { + type E = MainnetEthSpec; + let rng = &mut XorShiftRng::from_seed([42; 16]); - let fork_slot = Slot::from_ssz_bytes(&[7, 6, 5, 4, 3, 2, 1, 0]).unwrap(); + let fork_epoch = Epoch::from_ssz_bytes(&[7, 6, 5, 4, 3, 2, 1, 0]).unwrap(); - let base_slot = fork_slot.saturating_sub(1_u64); - let altair_slot = fork_slot; + let base_epoch = fork_epoch.saturating_sub(1_u64); + let base_slot = base_epoch.end_slot(E::slots_per_epoch()); + let altair_epoch = fork_epoch; + let altair_slot = altair_epoch.start_slot(E::slots_per_epoch()); - let mut spec = MainnetEthSpec::default_spec(); - spec.altair_fork_slot = Some(fork_slot); + let mut spec = E::default_spec(); + spec.altair_fork_epoch = Some(fork_epoch); // BeaconBlockBase { @@ -409,7 +414,7 @@ mod tests { slot: base_slot, ..<_>::random_for_test(rng) }); - // It's invalid to have a base block with a slot higher than the fork slot. + // It's invalid to have a base block with a slot higher than the fork epoch. let bad_base_block = { let mut bad = good_base_block.clone(); *bad.slot_mut() = altair_slot; @@ -431,7 +436,7 @@ mod tests { slot: altair_slot, ..<_>::random_for_test(rng) }); - // It's invalid to have an Altair block with a slot lower than the fork slot. + // It's invalid to have an Altair block with a epoch lower than the fork epoch. let bad_altair_block = { let mut bad = good_altair_block.clone(); *bad.slot_mut() = base_slot; diff --git a/consensus/types/src/beacon_state.rs b/consensus/types/src/beacon_state.rs index 31e56038c99..291219ec697 100644 --- a/consensus/types/src/beacon_state.rs +++ b/consensus/types/src/beacon_state.rs @@ -358,7 +358,7 @@ impl BeaconState { /// Will return an `Err` if `self` has been instantiated to a variant conflicting with the fork /// dictated by `self.slot()`. pub fn fork_name(&self, spec: &ChainSpec) -> Result { - let fork_at_slot = spec.fork_name_at_slot(self.slot()); + let fork_at_slot = spec.fork_name_at_epoch(self.current_epoch()); let object_fork = match self { BeaconState::Base { .. } => ForkName::Base, BeaconState::Altair { .. } => ForkName::Altair, @@ -389,10 +389,11 @@ impl BeaconState { })?; let slot = Slot::from_ssz_bytes(slot_bytes)?; + let epoch = slot.epoch(T::slots_per_epoch()); if spec - .altair_fork_slot - .map_or(true, |altair_slot| slot < altair_slot) + .altair_fork_epoch + .map_or(true, |altair_epoch| epoch < altair_epoch) { BeaconStateBase::from_ssz_bytes(bytes).map(Self::Base) } else { @@ -727,16 +728,6 @@ impl BeaconState { Ok(hash(&preimage)) } - /// Get the sync committee for the current or next period by computing it from scratch. - pub fn get_sync_committee( - &self, - epoch: Epoch, - spec: &ChainSpec, - ) -> Result, Error> { - let sync_committee_indices = self.compute_sync_committee_indices(epoch, spec)?; - self.compute_sync_committee(&sync_committee_indices) - } - /// Get the validator indices of all validators from `sync_committee` identified by /// `sync_committee_bits`. pub fn get_sync_committee_participant_indices( @@ -761,22 +752,14 @@ impl BeaconState { .collect() } - /// Calculate the sync committee indices for the state's base epoch from scratch. - pub fn compute_sync_committee_indices( - &self, - epoch: Epoch, - spec: &ChainSpec, - ) -> Result, Error> { - let base_epoch = self.sync_committee_base_epoch(epoch, spec)?; - - if base_epoch > self.next_epoch()? { - return Err(Error::EpochOutOfBounds); - } + /// Compute the sync committee indices for the next sync committee. + fn get_next_sync_committee_indices(&self, spec: &ChainSpec) -> Result, Error> { + let epoch = self.current_epoch().safe_add(1)?; - let active_validator_indices = self.get_active_validator_indices(base_epoch, spec)?; + let active_validator_indices = self.get_active_validator_indices(epoch, spec)?; let active_validator_count = active_validator_indices.len(); - let seed = self.get_seed(base_epoch, Domain::SyncCommittee, spec)?; + let seed = self.get_seed(epoch, Domain::SyncCommittee, spec)?; let mut i = 0; let mut sync_committee_indices = Vec::with_capacity(T::SyncCommitteeSize::to_usize()); @@ -805,14 +788,9 @@ impl BeaconState { Ok(sync_committee_indices) } - /// Compute the sync committee for a given list of indices. - pub fn compute_sync_committee( - &self, - sync_committee_indices: &[usize], - ) -> Result, Error> { - if sync_committee_indices.len() != T::SyncCommitteeSize::to_usize() { - return Err(Error::InsufficientValidators); - } + /// Compute the next sync committee. + pub fn get_next_sync_committee(&self, spec: &ChainSpec) -> Result, Error> { + let sync_committee_indices = self.get_next_sync_committee_indices(spec)?; let pubkeys = sync_committee_indices .iter() @@ -823,40 +801,18 @@ impl BeaconState { .ok_or(Error::UnknownValidator(index)) }) .collect::, _>>()?; - let pubkeys_per_aggregate = T::SyncPubkeysPerAggregate::to_usize(); - let pubkey_aggregates = pubkeys - .chunks_exact(pubkeys_per_aggregate) - .map(|preaggregate| { - // Decompress the pubkeys and aggregate them - let decompressed_keys = preaggregate - .iter() - .map(|key_bytes| key_bytes.decompress()) - .collect::, _>>()?; - let agg_pk = AggregatePublicKey::aggregate(&decompressed_keys)?; - Ok(agg_pk.to_public_key().compress()) - }) - .collect::, Error>>()?; + let decompressed_pubkeys = pubkeys + .iter() + .map(|pk| pk.decompress()) + .collect::, _>>()?; + let aggregate_pubkey = AggregatePublicKey::aggregate(&decompressed_pubkeys)?; Ok(SyncCommittee { pubkeys: FixedVector::new(pubkeys)?, - pubkey_aggregates: FixedVector::new(pubkey_aggregates)?, + aggregate_pubkey: aggregate_pubkey.to_public_key().compress(), }) } - /// Compute the `base_epoch` used by sync committees. - pub fn sync_committee_base_epoch( - &self, - epoch: Epoch, - spec: &ChainSpec, - ) -> Result { - Ok(std::cmp::max( - epoch.safe_div(spec.epochs_per_sync_committee_period)?, - Epoch::new(1), - ) - .safe_sub(1)? - .safe_mul(spec.epochs_per_sync_committee_period)?) - } - /// Get the canonical root of the `latest_block_header`, filling in its state root if necessary. /// /// It needs filling in on all slots where there isn't a skip. @@ -1492,84 +1448,6 @@ impl BeaconState { res } - /// Transform a `Base` state into an `Altair` state. - pub fn upgrade_to_altair(&mut self, spec: &ChainSpec) -> Result<(), Error> { - let epoch = self.current_epoch(); - let pre = if let BeaconState::Base(pre) = self { - pre - } else { - return Err(Error::IncorrectStateVariant); - }; - - let default_epoch_participation = - VariableList::new(vec![ParticipationFlags::default(); pre.validators.len()])?; - let inactivity_scores = VariableList::new(vec![0; pre.validators.len()])?; - - // Where possible, use something like `mem::take` to move fields from behind the &mut - // reference. For other fields that don't have a good default value, use `clone`. - // - // Fixed size vectors get cloned because replacing them would require the same size - // allocation as cloning. - let mut post = BeaconState::Altair(BeaconStateAltair { - // Versioning - genesis_time: pre.genesis_time, - genesis_validators_root: pre.genesis_validators_root, - slot: pre.slot, - fork: Fork { - previous_version: pre.fork.current_version, - current_version: spec.altair_fork_version, - epoch, - }, - // History - latest_block_header: pre.latest_block_header.clone(), - block_roots: pre.block_roots.clone(), - state_roots: pre.state_roots.clone(), - historical_roots: mem::take(&mut pre.historical_roots), - // Eth1 - eth1_data: pre.eth1_data.clone(), - eth1_data_votes: mem::take(&mut pre.eth1_data_votes), - eth1_deposit_index: pre.eth1_deposit_index, - // Registry - validators: mem::take(&mut pre.validators), - balances: mem::take(&mut pre.balances), - // Randomness - randao_mixes: pre.randao_mixes.clone(), - // Slashings - slashings: pre.slashings.clone(), - // `Participation - previous_epoch_participation: default_epoch_participation.clone(), - current_epoch_participation: default_epoch_participation, - // Finality - justification_bits: pre.justification_bits.clone(), - previous_justified_checkpoint: pre.previous_justified_checkpoint, - current_justified_checkpoint: pre.current_justified_checkpoint, - finalized_checkpoint: pre.finalized_checkpoint, - // Inactivity - inactivity_scores, - // Sync committees - current_sync_committee: SyncCommittee::temporary()?, // not read - next_sync_committee: SyncCommittee::temporary()?, // not read - // Caches - committee_caches: mem::take(&mut pre.committee_caches), - pubkey_cache: mem::take(&mut pre.pubkey_cache), - exit_cache: mem::take(&mut pre.exit_cache), - tree_hash_cache: mem::take(&mut pre.tree_hash_cache), - }); - - // Fill in sync committees - post.as_altair_mut()?.current_sync_committee = - post.get_sync_committee(post.current_epoch(), spec)?; - post.as_altair_mut()?.next_sync_committee = post.get_sync_committee( - post.current_epoch() - .safe_add(spec.epochs_per_sync_committee_period)?, - spec, - )?; - - *self = post; - - Ok(()) - } - pub fn clone_with_only_committee_caches(&self) -> Self { self.clone_with(CloneConfig::committee_caches_only()) } @@ -1579,7 +1457,7 @@ impl BeaconState { /// The `self` state must be Altair or later. pub fn get_unslashed_participating_indices( &self, - flag_index: u32, + flag_index: usize, epoch: Epoch, spec: &ChainSpec, ) -> Result, Error> { diff --git a/consensus/types/src/beacon_state/tests.rs b/consensus/types/src/beacon_state/tests.rs index f43537ba768..ff7c503f249 100644 --- a/consensus/types/src/beacon_state/tests.rs +++ b/consensus/types/src/beacon_state/tests.rs @@ -424,15 +424,19 @@ mod get_outstanding_deposit_len { #[test] fn decode_base_and_altair() { + type E = MainnetEthSpec; + let rng = &mut XorShiftRng::from_seed([42; 16]); - let fork_slot = Slot::from_ssz_bytes(&[7, 6, 5, 4, 3, 2, 1, 0]).unwrap(); + let fork_epoch = Epoch::from_ssz_bytes(&[7, 6, 5, 4, 3, 2, 1, 0]).unwrap(); - let base_slot = fork_slot.saturating_sub(1_u64); - let altair_slot = fork_slot; + let base_epoch = fork_epoch.saturating_sub(1_u64); + let base_slot = base_epoch.end_slot(E::slots_per_epoch()); + let altair_epoch = fork_epoch; + let altair_slot = altair_epoch.start_slot(E::slots_per_epoch()); - let mut spec = MainnetEthSpec::default_spec(); - spec.altair_fork_slot = Some(fork_slot); + let mut spec = E::default_spec(); + spec.altair_fork_epoch = Some(altair_epoch); // BeaconStateBase { diff --git a/consensus/types/src/chain_spec.rs b/consensus/types/src/chain_spec.rs index 603eba89683..63383155f47 100644 --- a/consensus/types/src/chain_spec.rs +++ b/consensus/types/src/chain_spec.rs @@ -1,17 +1,7 @@ -//! This file contains several different representations of the beacon chain configuration -//! parameters. -//! -//! Arguably the most important of these is `ChainSpec`, which is used throughout Lighthouse as the -//! source-of-truth regarding spec-level configuration. -//! -//! The other types exist for interoperability with other systems. The `StandardConfig` is an object -//! intended to match an EF spec configuration (usually YAML), and is broken into sub-parts for -//! each relevant fork. It is also serialised as JSON for the standardised HTTP API. use crate::*; use int_to_bytes::int_to_bytes4; use serde_derive::{Deserialize, Serialize}; use serde_utils::quoted_u64::MaybeQuoted; -use std::collections::HashMap; use std::fs::File; use std::path::Path; use tree_hash::TreeHash; @@ -29,7 +19,9 @@ pub enum Domain { SyncCommittee, } -/// Holds all the "constants" for a BeaconChain. +/// Lighthouse's internal configuration struct. +/// +/// Contains a mixture of "preset" and "config" values w.r.t to the EF definitions. #[cfg_attr(feature = "arbitrary-fuzz", derive(arbitrary::Arbitrary))] #[derive(PartialEq, Debug, Clone)] pub struct ChainSpec { @@ -94,13 +86,13 @@ pub struct ChainSpec { /* * Signature domains */ - domain_beacon_proposer: u32, - domain_beacon_attester: u32, - domain_randao: u32, - domain_deposit: u32, - domain_voluntary_exit: u32, - domain_selection_proof: u32, - domain_aggregate_and_proof: u32, + pub(crate) domain_beacon_proposer: u32, + pub(crate) domain_beacon_attester: u32, + pub(crate) domain_randao: u32, + pub(crate) domain_deposit: u32, + pub(crate) domain_voluntary_exit: u32, + pub(crate) domain_selection_proof: u32, + pub(crate) domain_aggregate_and_proof: u32, /* * Fork choice @@ -124,12 +116,14 @@ pub struct ChainSpec { pub proportional_slashing_multiplier_altair: u64, pub epochs_per_sync_committee_period: Epoch, pub inactivity_score_bias: u64, - domain_sync_committee: u32, - domain_sync_committee_selection_proof: u32, - domain_contribution_and_proof: u32, + pub inactivity_score_recovery_rate: u64, + pub min_sync_committee_participants: u64, + pub(crate) domain_sync_committee: u32, + pub(crate) domain_sync_committee_selection_proof: u32, + pub(crate) domain_contribution_and_proof: u32, pub altair_fork_version: [u8; 4], - /// The Altair fork slot is optional, with `None` representing "Altair never happens". - pub altair_fork_slot: Option, + /// The Altair fork epoch is optional, with `None` representing "Altair never happens". + pub altair_fork_epoch: Option, /* * Networking @@ -146,14 +140,9 @@ pub struct ChainSpec { impl ChainSpec { /// Construct a `ChainSpec` from a standard config. - pub fn from_standard_config(standard_config: &StandardConfig) -> Option { - let mut spec = T::default_spec(); - spec = standard_config.base().apply_to_chain_spec::(&spec)?; - - if let Ok(altair) = standard_config.altair() { - spec = altair.apply_to_chain_spec::(&spec)?; - } - Some(spec) + pub fn from_config(config: &Config) -> Option { + let spec = T::default_spec(); + config.apply_to_chain_spec::(&spec) } /// Returns an `EnrForkId` for the given `slot`. @@ -180,9 +169,14 @@ impl ChainSpec { } /// Returns the name of the fork which is active at `slot`. - pub fn fork_name_at_slot(&self, slot: Slot) -> ForkName { - match self.altair_fork_slot { - Some(fork_slot) if slot >= fork_slot => ForkName::Altair, + pub fn fork_name_at_slot(&self, slot: Slot) -> ForkName { + self.fork_name_at_epoch(slot.epoch(E::slots_per_epoch())) + } + + /// Returns the name of the fork which is active at `epoch`. + pub fn fork_name_at_epoch(&self, epoch: Epoch) -> ForkName { + match self.altair_fork_epoch { + Some(fork_epoch) if epoch >= fork_epoch => ForkName::Altair, _ => ForkName::Base, } } @@ -395,12 +389,14 @@ impl ChainSpec { .expect("pow does not overflow"), proportional_slashing_multiplier_altair: 2, inactivity_score_bias: 4, - epochs_per_sync_committee_period: Epoch::new(256), + inactivity_score_recovery_rate: 16, + min_sync_committee_participants: 1, + epochs_per_sync_committee_period: Epoch::new(512), domain_sync_committee: 7, domain_sync_committee_selection_proof: 8, domain_contribution_and_proof: 9, altair_fork_version: [0x01, 0x00, 0x00, 0x00], - altair_fork_slot: Some(Slot::new(u64::MAX)), + altair_fork_epoch: Some(Epoch::new(u64::MAX)), /* * Network specific @@ -439,7 +435,7 @@ impl ChainSpec { // Altair epochs_per_sync_committee_period: Epoch::new(8), altair_fork_version: [0x01, 0x00, 0x00, 0x01], - altair_fork_slot: Some(Slot::new(u64::MAX)), + altair_fork_epoch: Some(Epoch::new(u64::MAX)), // Other network_id: 2, // lighthouse testnet network id deposit_chain_id: 5, @@ -459,169 +455,48 @@ impl Default for ChainSpec { } } -/// Configuration struct for compatibility with the spec's .yaml configuration -/// -/// Ordering of these enum variants is significant because it determines serde's deserialisation -/// priority. I.e. Altair before Base. -/// -#[superstruct( - variants(Altair, Base), - variant_attributes(derive(Serialize, Deserialize, Debug, PartialEq, Clone)) -)] -#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)] -#[serde(untagged)] -pub struct StandardConfig { - #[serde(flatten)] - pub base: BaseConfig, - /// Configuration related to the Altair hard fork. - #[superstruct(only(Altair))] - #[serde(flatten)] - pub altair: AltairConfig, - - /// The `extra_fields` map allows us to gracefully decode fields intended for future hard forks. - #[serde(flatten)] - pub extra_fields: HashMap, -} - -impl StandardConfig { - pub fn from_chain_spec(spec: &ChainSpec) -> Self { - let base = BaseConfig::from_chain_spec::(spec); - let altair = AltairConfig::from_chain_spec::(spec); - Self::from_parts(base, altair) - } - - pub fn from_parts(base: BaseConfig, altair: AltairConfig) -> Self { - let extra_fields = HashMap::new(); - StandardConfig::Altair(StandardConfigAltair { - base, - altair, - extra_fields, - }) - } -} - -/// Configuration related to the base/phase0/genesis fork (YAML/JSON version). +/// Exact implementation of the *config* object from the Ethereum spec (YAML/JSON). #[derive(Serialize, Deserialize, Debug, PartialEq, Clone)] #[serde(rename_all = "UPPERCASE")] -pub struct BaseConfig { - pub config_name: String, - // ChainSpec - #[serde(with = "serde_utils::quoted_u64")] - max_committees_per_slot: u64, - #[serde(with = "serde_utils::quoted_u64")] - target_committee_size: u64, - #[serde(with = "serde_utils::quoted_u64")] - min_per_epoch_churn_limit: u64, - #[serde(with = "serde_utils::quoted_u64")] - churn_limit_quotient: u64, - #[serde(with = "serde_utils::quoted_u8")] - shuffle_round_count: u8, +pub struct Config { + #[serde(default)] + pub preset_base: String, + #[serde(with = "serde_utils::quoted_u64")] min_genesis_active_validator_count: u64, #[serde(with = "serde_utils::quoted_u64")] min_genesis_time: u64, + #[serde(with = "serde_utils::bytes_4_hex")] + genesis_fork_version: [u8; 4], #[serde(with = "serde_utils::quoted_u64")] genesis_delay: u64, - #[serde(with = "serde_utils::quoted_u64")] - min_deposit_amount: u64, - #[serde(with = "serde_utils::quoted_u64")] - max_effective_balance: u64, - #[serde(with = "serde_utils::quoted_u64")] - ejection_balance: u64, - #[serde(with = "serde_utils::quoted_u64")] - effective_balance_increment: u64, - #[serde(with = "serde_utils::quoted_u64")] - hysteresis_quotient: u64, - #[serde(with = "serde_utils::quoted_u64")] - hysteresis_downward_multiplier: u64, - #[serde(with = "serde_utils::quoted_u64")] - hysteresis_upward_multiplier: u64, + #[serde(with = "serde_utils::bytes_4_hex")] - genesis_fork_version: [u8; 4], - #[serde(with = "serde_utils::u8_hex")] - bls_withdrawal_prefix: u8, + altair_fork_version: [u8; 4], + altair_fork_epoch: Option>, + #[serde(with = "serde_utils::quoted_u64")] seconds_per_slot: u64, #[serde(with = "serde_utils::quoted_u64")] - min_attestation_inclusion_delay: u64, - #[serde(with = "serde_utils::quoted_u64")] - min_seed_lookahead: u64, - #[serde(with = "serde_utils::quoted_u64")] - max_seed_lookahead: u64, - #[serde(with = "serde_utils::quoted_u64")] - min_epochs_to_inactivity_penalty: u64, + seconds_per_eth1_block: u64, #[serde(with = "serde_utils::quoted_u64")] - min_validator_withdrawability_delay: u64, + min_validator_withdrawability_delay: Epoch, #[serde(with = "serde_utils::quoted_u64")] shard_committee_period: u64, #[serde(with = "serde_utils::quoted_u64")] - base_reward_factor: u64, - #[serde(with = "serde_utils::quoted_u64")] - whistleblower_reward_quotient: u64, - #[serde(with = "serde_utils::quoted_u64")] - proposer_reward_quotient: u64, - #[serde(with = "serde_utils::quoted_u64")] - inactivity_penalty_quotient: u64, - #[serde(with = "serde_utils::quoted_u64")] - min_slashing_penalty_quotient: u64, - #[serde(with = "serde_utils::quoted_u64")] - proportional_slashing_multiplier: u64, - #[serde(with = "serde_utils::quoted_u64")] - safe_slots_to_update_justified: u64, - - #[serde(with = "serde_utils::u32_hex")] - domain_beacon_proposer: u32, - #[serde(with = "serde_utils::u32_hex")] - domain_beacon_attester: u32, - #[serde(with = "serde_utils::u32_hex")] - domain_randao: u32, - #[serde(with = "serde_utils::u32_hex")] - domain_deposit: u32, - #[serde(with = "serde_utils::u32_hex")] - domain_voluntary_exit: u32, - #[serde(with = "serde_utils::u32_hex")] - domain_selection_proof: u32, - #[serde(with = "serde_utils::u32_hex")] - domain_aggregate_and_proof: u32, - - // EthSpec - #[serde(with = "serde_utils::quoted_u32")] - max_validators_per_committee: u32, - #[serde(with = "serde_utils::quoted_u64")] - slots_per_epoch: u64, - #[serde(with = "serde_utils::quoted_u64")] - epochs_per_eth1_voting_period: u64, - #[serde(with = "serde_utils::quoted_u64")] - slots_per_historical_root: u64, - #[serde(with = "serde_utils::quoted_u64")] - epochs_per_historical_vector: u64, - #[serde(with = "serde_utils::quoted_u64")] - epochs_per_slashings_vector: u64, - #[serde(with = "serde_utils::quoted_u64")] - historical_roots_limit: u64, - #[serde(with = "serde_utils::quoted_u64")] - validator_registry_limit: u64, - #[serde(with = "serde_utils::quoted_u32")] - max_proposer_slashings: u32, - #[serde(with = "serde_utils::quoted_u32")] - max_attester_slashings: u32, - #[serde(with = "serde_utils::quoted_u32")] - max_attestations: u32, - #[serde(with = "serde_utils::quoted_u32")] - max_deposits: u32, - #[serde(with = "serde_utils::quoted_u32")] - max_voluntary_exits: u32, - // Validator - #[serde(with = "serde_utils::quoted_u64")] eth1_follow_distance: u64, + #[serde(with = "serde_utils::quoted_u64")] - target_aggregators_per_committee: u64, + inactivity_score_bias: u64, #[serde(with = "serde_utils::quoted_u64")] - random_subnets_per_validator: u64, + inactivity_score_recovery_rate: u64, #[serde(with = "serde_utils::quoted_u64")] - epochs_per_random_subnet_subscription: u64, + ejection_balance: u64, #[serde(with = "serde_utils::quoted_u64")] - seconds_per_eth1_block: u64, + min_per_epoch_churn_limit: u64, + #[serde(with = "serde_utils::quoted_u64")] + churn_limit_quotient: u64, + #[serde(with = "serde_utils::quoted_u64")] deposit_chain_id: u64, #[serde(with = "serde_utils::quoted_u64")] @@ -629,92 +504,51 @@ pub struct BaseConfig { deposit_contract_address: Address, } -impl Default for BaseConfig { +impl Default for Config { fn default() -> Self { let chain_spec = MainnetEthSpec::default_spec(); - BaseConfig::from_chain_spec::(&chain_spec) + Config::from_chain_spec::(&chain_spec) } } -impl BaseConfig { - /// Maps `self.config_name` to an identifier for an `EthSpec` instance. +impl Config { + /// Maps `self` to an identifier for an `EthSpec` instance. /// /// Returns `None` if there is no match. pub fn eth_spec_id(&self) -> Option { - Some(match self.config_name.as_str() { - "mainnet" => EthSpecId::Mainnet, - "minimal" => EthSpecId::Minimal, - "toledo" => EthSpecId::Mainnet, - "prater" => EthSpecId::Mainnet, - "pyrmont" => EthSpecId::Mainnet, - _ => return None, - }) + match self.preset_base.as_str() { + "minimal" => Some(EthSpecId::Minimal), + "mainnet" => Some(EthSpecId::Mainnet), + _ => None, + } } pub fn from_chain_spec(spec: &ChainSpec) -> Self { Self { - config_name: T::spec_name().to_string(), - // ChainSpec - max_committees_per_slot: spec.max_committees_per_slot as u64, - target_committee_size: spec.target_committee_size as u64, - min_per_epoch_churn_limit: spec.min_per_epoch_churn_limit, - churn_limit_quotient: spec.churn_limit_quotient, - shuffle_round_count: spec.shuffle_round_count, + preset_base: T::spec_name().to_string(), + min_genesis_active_validator_count: spec.min_genesis_active_validator_count, min_genesis_time: spec.min_genesis_time, + genesis_fork_version: spec.genesis_fork_version, genesis_delay: spec.genesis_delay, - min_deposit_amount: spec.min_deposit_amount, - max_effective_balance: spec.max_effective_balance, - ejection_balance: spec.ejection_balance, - effective_balance_increment: spec.effective_balance_increment, - hysteresis_quotient: spec.hysteresis_quotient, - hysteresis_downward_multiplier: spec.hysteresis_downward_multiplier, - hysteresis_upward_multiplier: spec.hysteresis_upward_multiplier, - proportional_slashing_multiplier: spec.proportional_slashing_multiplier, - bls_withdrawal_prefix: spec.bls_withdrawal_prefix_byte, + + altair_fork_version: spec.altair_fork_version, + altair_fork_epoch: spec + .altair_fork_epoch + .map(|slot| MaybeQuoted { value: slot }), + seconds_per_slot: spec.seconds_per_slot, - min_attestation_inclusion_delay: spec.min_attestation_inclusion_delay, - min_seed_lookahead: spec.min_seed_lookahead.into(), - max_seed_lookahead: spec.max_seed_lookahead.into(), - min_validator_withdrawability_delay: spec.min_validator_withdrawability_delay.into(), + seconds_per_eth1_block: spec.seconds_per_eth1_block, + min_validator_withdrawability_delay: spec.min_validator_withdrawability_delay, shard_committee_period: spec.shard_committee_period, - min_epochs_to_inactivity_penalty: spec.min_epochs_to_inactivity_penalty, - base_reward_factor: spec.base_reward_factor, - whistleblower_reward_quotient: spec.whistleblower_reward_quotient, - proposer_reward_quotient: spec.proposer_reward_quotient, - inactivity_penalty_quotient: spec.inactivity_penalty_quotient, - min_slashing_penalty_quotient: spec.min_slashing_penalty_quotient, - genesis_fork_version: spec.genesis_fork_version, - safe_slots_to_update_justified: spec.safe_slots_to_update_justified, - domain_beacon_proposer: spec.domain_beacon_proposer, - domain_beacon_attester: spec.domain_beacon_attester, - domain_randao: spec.domain_randao, - domain_deposit: spec.domain_deposit, - domain_voluntary_exit: spec.domain_voluntary_exit, - domain_selection_proof: spec.domain_selection_proof, - domain_aggregate_and_proof: spec.domain_aggregate_and_proof, - - // EthSpec - max_validators_per_committee: T::MaxValidatorsPerCommittee::to_u32(), - slots_per_epoch: T::slots_per_epoch(), - epochs_per_eth1_voting_period: T::EpochsPerEth1VotingPeriod::to_u64(), - slots_per_historical_root: T::slots_per_historical_root() as u64, - epochs_per_historical_vector: T::epochs_per_historical_vector() as u64, - epochs_per_slashings_vector: T::EpochsPerSlashingsVector::to_u64(), - historical_roots_limit: T::HistoricalRootsLimit::to_u64(), - validator_registry_limit: T::ValidatorRegistryLimit::to_u64(), - max_proposer_slashings: T::MaxProposerSlashings::to_u32(), - max_attester_slashings: T::MaxAttesterSlashings::to_u32(), - max_attestations: T::MaxAttestations::to_u32(), - max_deposits: T::MaxDeposits::to_u32(), - max_voluntary_exits: T::MaxVoluntaryExits::to_u32(), - - // Validator eth1_follow_distance: spec.eth1_follow_distance, - target_aggregators_per_committee: spec.target_aggregators_per_committee, - random_subnets_per_validator: spec.random_subnets_per_validator, - epochs_per_random_subnet_subscription: spec.epochs_per_random_subnet_subscription, - seconds_per_eth1_block: spec.seconds_per_eth1_block, + + inactivity_score_bias: spec.inactivity_score_bias, + inactivity_score_recovery_rate: spec.inactivity_score_recovery_rate, + ejection_balance: spec.ejection_balance, + churn_limit_quotient: spec.churn_limit_quotient, + min_per_epoch_churn_limit: spec.min_per_epoch_churn_limit, + deposit_chain_id: spec.deposit_chain_id, deposit_network_id: spec.deposit_network_id, deposit_contract_address: spec.deposit_contract_address, @@ -729,229 +563,57 @@ impl BaseConfig { } pub fn apply_to_chain_spec(&self, chain_spec: &ChainSpec) -> Option { - // Check that YAML values match type-level EthSpec constants - if self.max_validators_per_committee != T::MaxValidatorsPerCommittee::to_u32() - || self.slots_per_epoch != T::slots_per_epoch() - || self.epochs_per_eth1_voting_period != T::EpochsPerEth1VotingPeriod::to_u64() - || self.slots_per_historical_root != T::slots_per_historical_root() as u64 - || self.epochs_per_historical_vector != T::epochs_per_historical_vector() as u64 - || self.epochs_per_slashings_vector != T::EpochsPerSlashingsVector::to_u64() - || self.historical_roots_limit != T::HistoricalRootsLimit::to_u64() - || self.validator_registry_limit != T::ValidatorRegistryLimit::to_u64() - || self.max_proposer_slashings != T::MaxProposerSlashings::to_u32() - || self.max_attester_slashings != T::MaxAttesterSlashings::to_u32() - || self.max_attestations != T::MaxAttestations::to_u32() - || self.max_deposits != T::MaxDeposits::to_u32() - || self.max_voluntary_exits != T::MaxVoluntaryExits::to_u32() - { - return None; - } - - // Create a ChainSpec from the yaml config - Some(ChainSpec { - /* - * Misc - */ - max_committees_per_slot: self.max_committees_per_slot as usize, - target_committee_size: self.target_committee_size as usize, - min_per_epoch_churn_limit: self.min_per_epoch_churn_limit, - churn_limit_quotient: self.churn_limit_quotient, - shuffle_round_count: self.shuffle_round_count, - min_genesis_active_validator_count: self.min_genesis_active_validator_count, - min_genesis_time: self.min_genesis_time, - hysteresis_quotient: self.hysteresis_quotient, - hysteresis_downward_multiplier: self.hysteresis_downward_multiplier, - hysteresis_upward_multiplier: self.hysteresis_upward_multiplier, - proportional_slashing_multiplier: self.proportional_slashing_multiplier, - /* - * Fork Choice - */ - safe_slots_to_update_justified: self.safe_slots_to_update_justified, - /* - * Validator - */ - eth1_follow_distance: self.eth1_follow_distance, - target_aggregators_per_committee: self.target_aggregators_per_committee, - random_subnets_per_validator: self.random_subnets_per_validator, - epochs_per_random_subnet_subscription: self.epochs_per_random_subnet_subscription, - seconds_per_eth1_block: self.seconds_per_eth1_block, - deposit_chain_id: self.deposit_chain_id, - deposit_network_id: self.deposit_network_id, - deposit_contract_address: self.deposit_contract_address, - /* - * Gwei values - */ - min_deposit_amount: self.min_deposit_amount, - max_effective_balance: self.max_effective_balance, - ejection_balance: self.ejection_balance, - effective_balance_increment: self.effective_balance_increment, - /* - * Initial values - */ - genesis_fork_version: self.genesis_fork_version, - bls_withdrawal_prefix_byte: self.bls_withdrawal_prefix, - /* - * Time parameters - */ - genesis_delay: self.genesis_delay, - seconds_per_slot: self.seconds_per_slot, - min_attestation_inclusion_delay: self.min_attestation_inclusion_delay, - min_seed_lookahead: Epoch::from(self.min_seed_lookahead), - max_seed_lookahead: Epoch::from(self.max_seed_lookahead), - min_validator_withdrawability_delay: Epoch::from( - self.min_validator_withdrawability_delay, - ), - shard_committee_period: self.shard_committee_period, - min_epochs_to_inactivity_penalty: self.min_epochs_to_inactivity_penalty, - /* - * Reward and penalty quotients - */ - base_reward_factor: self.base_reward_factor, - whistleblower_reward_quotient: self.whistleblower_reward_quotient, - proposer_reward_quotient: self.proposer_reward_quotient, - inactivity_penalty_quotient: self.inactivity_penalty_quotient, - min_slashing_penalty_quotient: self.min_slashing_penalty_quotient, - /* - * Signature domains - */ - domain_beacon_proposer: self.domain_beacon_proposer, - domain_beacon_attester: self.domain_beacon_attester, - domain_randao: self.domain_randao, - domain_deposit: self.domain_deposit, - domain_voluntary_exit: self.domain_voluntary_exit, - domain_selection_proof: self.domain_selection_proof, - domain_aggregate_and_proof: self.domain_aggregate_and_proof, - /* - * Altair params (passthrough: they come from the other config file) - */ - inactivity_penalty_quotient_altair: chain_spec.inactivity_penalty_quotient_altair, - min_slashing_penalty_quotient_altair: chain_spec.min_slashing_penalty_quotient_altair, - proportional_slashing_multiplier_altair: chain_spec - .proportional_slashing_multiplier_altair, - inactivity_score_bias: chain_spec.inactivity_score_bias, - epochs_per_sync_committee_period: chain_spec.epochs_per_sync_committee_period, - domain_sync_committee: chain_spec.domain_sync_committee, - domain_sync_committee_selection_proof: chain_spec.domain_sync_committee_selection_proof, - domain_contribution_and_proof: chain_spec.domain_contribution_and_proof, - altair_fork_version: chain_spec.altair_fork_version, - altair_fork_slot: chain_spec.altair_fork_slot, - /* - * Lighthouse-specific parameters - * - * These are paramaters that are present in the chain spec but aren't part of the YAML - * config. We avoid using `..chain_spec` so that changes to the set of fields don't - * accidentally get forgotten (explicit better than implicit, yada yada). - */ - boot_nodes: chain_spec.boot_nodes.clone(), - network_id: chain_spec.network_id, - attestation_propagation_slot_range: chain_spec.attestation_propagation_slot_range, - maximum_gossip_clock_disparity_millis: chain_spec.maximum_gossip_clock_disparity_millis, - attestation_subnet_count: chain_spec.attestation_subnet_count, - /* - * Constants, not configurable. - */ - genesis_slot: chain_spec.genesis_slot, - far_future_epoch: chain_spec.far_future_epoch, - base_rewards_per_epoch: chain_spec.base_rewards_per_epoch, - deposit_contract_tree_depth: chain_spec.deposit_contract_tree_depth, - }) - } -} - -/// The Altair spec file -#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)] -#[serde(rename_all = "UPPERCASE")] -pub struct AltairConfig { - #[serde(with = "serde_utils::quoted_u64")] - inactivity_penalty_quotient_altair: u64, - #[serde(with = "serde_utils::quoted_u64")] - min_slashing_penalty_quotient_altair: u64, - #[serde(with = "serde_utils::quoted_u64")] - proportional_slashing_multiplier_altair: u64, - #[serde(with = "serde_utils::quoted_u64")] - sync_committee_size: u64, - #[serde(with = "serde_utils::quoted_u64")] - sync_pubkeys_per_aggregate: u64, - #[serde(with = "serde_utils::quoted_u64")] - inactivity_score_bias: u64, - #[serde(with = "serde_utils::quoted_u64")] - epochs_per_sync_committee_period: Epoch, - #[serde(with = "serde_utils::u32_hex")] - domain_sync_committee: u32, - #[serde(with = "serde_utils::u32_hex")] - domain_sync_committee_selection_proof: u32, - #[serde(with = "serde_utils::u32_hex")] - domain_contribution_and_proof: u32, - #[serde(with = "serde_utils::bytes_4_hex")] - altair_fork_version: [u8; 4], - altair_fork_slot: Option>, - // FIXME(altair): sync protocol params? -} - -impl AltairConfig { - pub fn from_file(filename: &Path) -> Result { - let f = File::open(filename) - .map_err(|e| format!("Error opening spec at {}: {:?}", filename.display(), e))?; - serde_yaml::from_reader(f) - .map_err(|e| format!("Error parsing spec at {}: {:?}", filename.display(), e)) - } - - pub fn apply_to_chain_spec(&self, chain_spec: &ChainSpec) -> Option { - // Pattern-match to avoid missing any fields. - let &AltairConfig { - inactivity_penalty_quotient_altair, - min_slashing_penalty_quotient_altair, - proportional_slashing_multiplier_altair, - sync_committee_size, - sync_pubkeys_per_aggregate, - inactivity_score_bias, - epochs_per_sync_committee_period, - domain_sync_committee, - domain_sync_committee_selection_proof, - domain_contribution_and_proof, + // Pattern match here to avoid missing any fields. + let &Config { + ref preset_base, + min_genesis_active_validator_count, + min_genesis_time, + genesis_fork_version, + genesis_delay, altair_fork_version, - altair_fork_slot, + altair_fork_epoch, + seconds_per_slot, + seconds_per_eth1_block, + min_validator_withdrawability_delay, + shard_committee_period, + eth1_follow_distance, + inactivity_score_bias, + inactivity_score_recovery_rate, + ejection_balance, + min_per_epoch_churn_limit, + churn_limit_quotient, + deposit_chain_id, + deposit_network_id, + deposit_contract_address, } = self; - if sync_committee_size != T::SyncCommitteeSize::to_u64() - || sync_pubkeys_per_aggregate != T::SyncPubkeysPerAggregate::to_u64() - { + if preset_base != T::spec_name().to_string().as_str() { return None; } Some(ChainSpec { - inactivity_penalty_quotient_altair, - min_slashing_penalty_quotient_altair, - proportional_slashing_multiplier_altair, - inactivity_score_bias, - epochs_per_sync_committee_period, - domain_sync_committee, - domain_sync_committee_selection_proof, - domain_contribution_and_proof, + min_genesis_active_validator_count, + min_genesis_time, + genesis_fork_version, + genesis_delay, altair_fork_version, - altair_fork_slot: altair_fork_slot.map(|q| q.value), + altair_fork_epoch: altair_fork_epoch.map(|q| q.value), + seconds_per_slot, + seconds_per_eth1_block, + min_validator_withdrawability_delay, + shard_committee_period, + eth1_follow_distance, + inactivity_score_bias, + inactivity_score_recovery_rate, + ejection_balance, + min_per_epoch_churn_limit, + churn_limit_quotient, + deposit_chain_id, + deposit_network_id, + deposit_contract_address, ..chain_spec.clone() }) } - - pub fn from_chain_spec(spec: &ChainSpec) -> Self { - Self { - inactivity_penalty_quotient_altair: spec.inactivity_penalty_quotient_altair, - min_slashing_penalty_quotient_altair: spec.min_slashing_penalty_quotient_altair, - proportional_slashing_multiplier_altair: spec.proportional_slashing_multiplier_altair, - sync_committee_size: T::SyncCommitteeSize::to_u64(), - sync_pubkeys_per_aggregate: T::SyncPubkeysPerAggregate::to_u64(), - inactivity_score_bias: spec.inactivity_score_bias, - epochs_per_sync_committee_period: spec.epochs_per_sync_committee_period, - domain_sync_committee: spec.domain_sync_committee, - domain_sync_committee_selection_proof: spec.domain_sync_committee_selection_proof, - domain_contribution_and_proof: spec.domain_contribution_and_proof, - altair_fork_version: spec.altair_fork_version, - altair_fork_slot: spec - .altair_fork_slot - .map(|slot| MaybeQuoted { value: slot }), - } - } } /// A simple wrapper to permit the in-line use of `?`. @@ -965,7 +627,6 @@ where #[cfg(test)] mod tests { use super::*; - use tempfile::NamedTempFile; #[test] fn test_mainnet_spec_can_be_constructed() { @@ -1014,23 +675,6 @@ mod tests { ); test_domain(Domain::SyncCommittee, spec.domain_sync_committee, &spec); } - - #[test] - fn decode_no_altair() { - let spec = MainnetEthSpec::default_spec(); - let base_config = BaseConfig::from_chain_spec::(&spec); - - let tmp_file = NamedTempFile::new().expect("failed to create temp file"); - let f = File::create(tmp_file.as_ref()).unwrap(); - serde_yaml::to_writer(f, &base_config).expect("failed to write or serialize"); - - let f = File::open(tmp_file.as_ref()).unwrap(); - let standard_config: StandardConfig = serde_yaml::from_reader(f).unwrap(); - - let standard_base = standard_config.as_base().unwrap(); - assert_eq!(standard_base.base, base_config); - assert!(standard_base.extra_fields.is_empty()); - } } #[cfg(test)] @@ -1050,7 +694,7 @@ mod yaml_tests { .expect("error opening file"); let minimal_spec = ChainSpec::minimal(); - let yamlconfig = BaseConfig::from_chain_spec::(&minimal_spec); + let yamlconfig = Config::from_chain_spec::(&minimal_spec); // write fresh minimal config to file serde_yaml::to_writer(writer, &yamlconfig).expect("failed to write or serialize"); @@ -1060,7 +704,7 @@ mod yaml_tests { .open(tmp_file.as_ref()) .expect("error while opening the file"); // deserialize minimal config from file - let from: BaseConfig = serde_yaml::from_reader(reader).expect("error while deserializing"); + let from: Config = serde_yaml::from_reader(reader).expect("error while deserializing"); assert_eq!(from, yamlconfig); } @@ -1073,32 +717,7 @@ mod yaml_tests { .open(tmp_file.as_ref()) .expect("error opening file"); let mainnet_spec = ChainSpec::mainnet(); - let yamlconfig = BaseConfig::from_chain_spec::(&mainnet_spec); - serde_yaml::to_writer(writer, &yamlconfig).expect("failed to write or serialize"); - - let reader = OpenOptions::new() - .read(true) - .write(false) - .open(tmp_file.as_ref()) - .expect("error while opening the file"); - let from: BaseConfig = serde_yaml::from_reader(reader).expect("error while deserializing"); - assert_eq!(from, yamlconfig); - } - - #[test] - fn extra_fields_round_trip() { - let tmp_file = NamedTempFile::new().expect("failed to create temp file"); - let writer = OpenOptions::new() - .read(false) - .write(true) - .open(tmp_file.as_ref()) - .expect("error opening file"); - let mainnet_spec = ChainSpec::mainnet(); - let mut yamlconfig = StandardConfig::from_chain_spec::(&mainnet_spec); - let (k1, v1) = ("SAMPLE_HARDFORK_KEY1", "123456789"); - let (k2, v2) = ("SAMPLE_HARDFORK_KEY2", "987654321"); - yamlconfig.extra_fields_mut().insert(k1.into(), v1.into()); - yamlconfig.extra_fields_mut().insert(k2.into(), v2.into()); + let yamlconfig = Config::from_chain_spec::(&mainnet_spec); serde_yaml::to_writer(writer, &yamlconfig).expect("failed to write or serialize"); let reader = OpenOptions::new() @@ -1106,18 +725,17 @@ mod yaml_tests { .write(false) .open(tmp_file.as_ref()) .expect("error while opening the file"); - let from: StandardConfig = - serde_yaml::from_reader(reader).expect("error while deserializing"); + let from: Config = serde_yaml::from_reader(reader).expect("error while deserializing"); assert_eq!(from, yamlconfig); } #[test] fn apply_to_spec() { let mut spec = ChainSpec::minimal(); - let yamlconfig = BaseConfig::from_chain_spec::(&spec); + let yamlconfig = Config::from_chain_spec::(&spec); // modifying the original spec - spec.max_committees_per_slot += 1; + spec.min_genesis_active_validator_count += 1; spec.deposit_chain_id += 1; spec.deposit_network_id += 1; // Applying a yaml config with incorrect EthSpec should fail diff --git a/consensus/types/src/config_and_preset.rs b/consensus/types/src/config_and_preset.rs new file mode 100644 index 00000000000..16d36c850c3 --- /dev/null +++ b/consensus/types/src/config_and_preset.rs @@ -0,0 +1,119 @@ +use crate::{AltairPreset, BasePreset, ChainSpec, Config, EthSpec}; +use serde_derive::{Deserialize, Serialize}; +use std::collections::HashMap; + +/// Fusion of a runtime-config with the compile-time preset values. +/// +/// Mostly useful for the API. +#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)] +pub struct ConfigAndPreset { + #[serde(flatten)] + pub config: Config, + + #[serde(flatten)] + pub base_preset: BasePreset, + #[serde(flatten)] + pub altair_preset: AltairPreset, + + /// The `extra_fields` map allows us to gracefully decode fields intended for future hard forks. + #[serde(flatten)] + pub extra_fields: HashMap, +} + +impl ConfigAndPreset { + pub fn from_chain_spec(spec: &ChainSpec) -> Self { + let config = Config::from_chain_spec::(spec); + let base_preset = BasePreset::from_chain_spec::(spec); + let altair_preset = AltairPreset::from_chain_spec::(spec); + let extra_fields = HashMap::new(); + + Self { + config, + base_preset, + altair_preset, + extra_fields, + } + } + + /// Add fields that were previously part of the config but are now constants. + pub fn make_backwards_compat(&mut self, spec: &ChainSpec) { + let hex_string = |value: &[u8]| format!("0x{}", hex::encode(&value)); + let u32_hex = |v: u32| hex_string(&v.to_le_bytes()); + let u8_hex = |v: u8| hex_string(&v.to_le_bytes()); + let fields = vec![ + ("config_name", self.config.preset_base.clone()), + ( + "bls_withdrawal_prefix", + u8_hex(spec.bls_withdrawal_prefix_byte), + ), + ( + "domain_beacon_proposer", + u32_hex(spec.domain_beacon_proposer), + ), + ( + "domain_beacon_attester", + u32_hex(spec.domain_beacon_attester), + ), + ("domain_randao", u32_hex(spec.domain_randao)), + ("domain_deposit", u32_hex(spec.domain_deposit)), + ("domain_voluntary_exit", u32_hex(spec.domain_voluntary_exit)), + ( + "domain_selection_proof", + u32_hex(spec.domain_selection_proof), + ), + ( + "domain_aggregate_and_proof", + u32_hex(spec.domain_aggregate_and_proof), + ), + ( + "target_aggregators_per_committee", + spec.target_aggregators_per_committee.to_string(), + ), + ( + "random_subnets_per_validator", + spec.random_subnets_per_validator.to_string(), + ), + ( + "epochs_per_random_subnet_subscription", + spec.epochs_per_random_subnet_subscription.to_string(), + ), + ]; + for (key, value) in fields { + self.extra_fields.insert(key.to_uppercase(), value); + } + } +} + +#[cfg(test)] +mod test { + use super::*; + use crate::MainnetEthSpec; + use std::fs::OpenOptions; + use tempfile::NamedTempFile; + + #[test] + fn extra_fields_round_trip() { + let tmp_file = NamedTempFile::new().expect("failed to create temp file"); + let writer = OpenOptions::new() + .read(false) + .write(true) + .open(tmp_file.as_ref()) + .expect("error opening file"); + let mainnet_spec = ChainSpec::mainnet(); + let mut yamlconfig = ConfigAndPreset::from_chain_spec::(&mainnet_spec); + let (k1, v1) = ("SAMPLE_HARDFORK_KEY1", "123456789"); + let (k2, v2) = ("SAMPLE_HARDFORK_KEY2", "987654321"); + yamlconfig.extra_fields.insert(k1.into(), v1.into()); + yamlconfig.extra_fields.insert(k2.into(), v2.into()); + serde_yaml::to_writer(writer, &yamlconfig).expect("failed to write or serialize"); + + let reader = OpenOptions::new() + .read(true) + .write(false) + .open(tmp_file.as_ref()) + .expect("error while opening the file"); + let from: ConfigAndPreset = + serde_yaml::from_reader(reader).expect("error while deserializing"); + assert_eq!(from, yamlconfig); + } +} diff --git a/consensus/types/src/consts.rs b/consensus/types/src/consts.rs index 92c77588aad..d872a42c5bb 100644 --- a/consensus/types/src/consts.rs +++ b/consensus/types/src/consts.rs @@ -1,18 +1,18 @@ pub mod altair { - pub const TIMELY_HEAD_FLAG_INDEX: u32 = 0; - pub const TIMELY_SOURCE_FLAG_INDEX: u32 = 1; - pub const TIMELY_TARGET_FLAG_INDEX: u32 = 2; - pub const TIMELY_HEAD_WEIGHT: u64 = 12; + pub const TIMELY_SOURCE_FLAG_INDEX: usize = 0; + pub const TIMELY_TARGET_FLAG_INDEX: usize = 1; + pub const TIMELY_HEAD_FLAG_INDEX: usize = 2; pub const TIMELY_SOURCE_WEIGHT: u64 = 12; pub const TIMELY_TARGET_WEIGHT: u64 = 24; + pub const TIMELY_HEAD_WEIGHT: u64 = 12; pub const SYNC_REWARD_WEIGHT: u64 = 8; pub const PROPOSER_WEIGHT: u64 = 8; pub const WEIGHT_DENOMINATOR: u64 = 64; - pub const FLAG_INDICES_AND_WEIGHTS: [(u32, u64); NUM_FLAG_INDICES] = [ - (TIMELY_HEAD_FLAG_INDEX, TIMELY_HEAD_WEIGHT), - (TIMELY_SOURCE_FLAG_INDEX, TIMELY_SOURCE_WEIGHT), - (TIMELY_TARGET_FLAG_INDEX, TIMELY_TARGET_WEIGHT), + pub const PARTICIPATION_FLAG_WEIGHTS: [u64; NUM_FLAG_INDICES] = [ + TIMELY_SOURCE_WEIGHT, + TIMELY_TARGET_WEIGHT, + TIMELY_HEAD_WEIGHT, ]; pub const NUM_FLAG_INDICES: usize = 3; diff --git a/consensus/types/src/eth_spec.rs b/consensus/types/src/eth_spec.rs index 64c932b78c9..dbf70f78e32 100644 --- a/consensus/types/src/eth_spec.rs +++ b/consensus/types/src/eth_spec.rs @@ -3,8 +3,8 @@ use crate::*; use safe_arith::SafeArith; use serde_derive::{Deserialize, Serialize}; use ssz_types::typenum::{ - Unsigned, U0, U1024, U1099511627776, U128, U16, U16777216, U2, U2048, U32, U4, U4096, U64, - U65536, U8, U8192, + Unsigned, U0, U1024, U1099511627776, U128, U16, U16777216, U2, U2048, U32, U4, U4096, U512, + U64, U65536, U8, U8192, }; use std::fmt::{self, Debug}; use std::str::FromStr; @@ -78,7 +78,6 @@ pub trait EthSpec: 'static + Default + Sync + Send + Clone + Debug + PartialEq + * New in Altair */ type SyncCommitteeSize: Unsigned + Clone + Sync + Send + Debug + PartialEq; - type SyncPubkeysPerAggregate: Unsigned + Clone + Sync + Send + Debug + PartialEq; /* * Derived values (set these CAREFULLY) */ @@ -92,10 +91,6 @@ pub trait EthSpec: 'static + Default + Sync + Send + Clone + Debug + PartialEq + /// /// Must be set to `EpochsPerEth1VotingPeriod * SlotsPerEpoch` type SlotsPerEth1VotingPeriod: Unsigned + Clone + Sync + Send + Debug + PartialEq; - /// The length of `pubkey_aggregates`. - /// - /// Must be set to `SyncCommitteeSize / SyncPubkeysPerAggregate`. - type SyncAggregateSize: Unsigned + Clone + Sync + Send + Debug + PartialEq; fn default_spec() -> ChainSpec; @@ -208,9 +203,7 @@ impl EthSpec for MainnetEthSpec { type MaxAttestations = U128; type MaxDeposits = U16; type MaxVoluntaryExits = U16; - type SyncCommitteeSize = U1024; - type SyncPubkeysPerAggregate = U64; - type SyncAggregateSize = U16; // 1024 committee size / 64 subcommittee size + type SyncCommitteeSize = U512; type MaxPendingAttestations = U4096; // 128 max attestations * 32 slots per epoch type SlotsPerEth1VotingPeriod = U2048; // 64 epochs * 32 slots per epoch @@ -235,8 +228,6 @@ impl EthSpec for MinimalEthSpec { type EpochsPerHistoricalVector = U64; type EpochsPerSlashingsVector = U64; type SyncCommitteeSize = U32; - type SyncPubkeysPerAggregate = U16; - type SyncAggregateSize = U2; // 32 committee size / 16 subcommittee size type MaxPendingAttestations = U1024; // 128 max attestations * 8 slots per epoch type SlotsPerEth1VotingPeriod = U32; // 4 epochs * 8 slots per epoch diff --git a/consensus/types/src/fork_name.rs b/consensus/types/src/fork_name.rs index e0f304178c2..b6c939709ae 100644 --- a/consensus/types/src/fork_name.rs +++ b/consensus/types/src/fork_name.rs @@ -1,4 +1,4 @@ -use crate::ChainSpec; +use crate::{ChainSpec, Epoch}; #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub enum ForkName { @@ -14,19 +14,32 @@ impl ForkName { /// Set the activation slots in the given `ChainSpec` so that the fork named by `self` /// is the only fork in effect from genesis. pub fn make_genesis_spec(&self, mut spec: ChainSpec) -> ChainSpec { + // Assumes GENESIS_EPOCH = 0, which is safe because it's a constant. match self { ForkName::Base => { - spec.altair_fork_slot = None; + spec.altair_fork_epoch = None; spec } ForkName::Altair => { - spec.altair_fork_slot = Some(spec.genesis_slot); + spec.altair_fork_epoch = Some(Epoch::new(0)); spec } } } } +impl std::str::FromStr for ForkName { + type Err = (); + + fn from_str(fork_name: &str) -> Result { + Ok(match fork_name { + "phase0" | "base" => ForkName::Base, + "altair" => ForkName::Altair, + _ => return Err(()), + }) + } +} + #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct InconsistentFork { pub fork_at_slot: ForkName, diff --git a/consensus/types/src/lib.rs b/consensus/types/src/lib.rs index 6a68b039fb5..b30ca63d8a5 100644 --- a/consensus/types/src/lib.rs +++ b/consensus/types/src/lib.rs @@ -58,7 +58,9 @@ pub mod validator_subscription; pub mod voluntary_exit; #[macro_use] pub mod slot_epoch_macros; +pub mod config_and_preset; pub mod participation_flags; +pub mod preset; pub mod slot_epoch; pub mod subnet_id; pub mod sync_aggregate; @@ -85,8 +87,9 @@ pub use crate::beacon_block_body::{ pub use crate::beacon_block_header::BeaconBlockHeader; pub use crate::beacon_committee::{BeaconCommittee, OwnedBeaconCommittee}; pub use crate::beacon_state::{BeaconTreeHashCache, Error as BeaconStateError, *}; -pub use crate::chain_spec::{AltairConfig, BaseConfig, ChainSpec, Domain, StandardConfig}; +pub use crate::chain_spec::{ChainSpec, Config, Domain}; pub use crate::checkpoint::Checkpoint; +pub use crate::config_and_preset::ConfigAndPreset; pub use crate::deposit::{Deposit, DEPOSIT_TREE_DEPTH}; pub use crate::deposit_data::DepositData; pub use crate::deposit_message::DepositMessage; @@ -102,6 +105,7 @@ pub use crate::historical_batch::HistoricalBatch; pub use crate::indexed_attestation::IndexedAttestation; pub use crate::participation_flags::ParticipationFlags; pub use crate::pending_attestation::PendingAttestation; +pub use crate::preset::{AltairPreset, BasePreset}; pub use crate::proposer_slashing::ProposerSlashing; pub use crate::relative_epoch::{Error as RelativeEpochError, RelativeEpoch}; pub use crate::selection_proof::SelectionProof; diff --git a/consensus/types/src/participation_flags.rs b/consensus/types/src/participation_flags.rs index 1aa3e16127f..c0ccb6db2c5 100644 --- a/consensus/types/src/participation_flags.rs +++ b/consensus/types/src/participation_flags.rs @@ -13,19 +13,19 @@ pub struct ParticipationFlags { } impl ParticipationFlags { - pub fn add_flag(&mut self, flag_index: u32) -> Result<(), ArithError> { - if flag_index > NUM_FLAG_INDICES as u32 { + pub fn add_flag(&mut self, flag_index: usize) -> Result<(), ArithError> { + if flag_index >= NUM_FLAG_INDICES { return Err(ArithError::Overflow); } - self.bits |= 1u8.safe_shl(flag_index)?; + self.bits |= 1u8.safe_shl(flag_index as u32)?; Ok(()) } - pub fn has_flag(&self, flag_index: u32) -> Result { - if flag_index > NUM_FLAG_INDICES as u32 { + pub fn has_flag(&self, flag_index: usize) -> Result { + if flag_index >= NUM_FLAG_INDICES { return Err(ArithError::Overflow); } - let mask = 1u8.safe_shl(flag_index)?; + let mask = 1u8.safe_shl(flag_index as u32)?; Ok(self.bits & mask == mask) } } diff --git a/consensus/types/src/preset.rs b/consensus/types/src/preset.rs new file mode 100644 index 00000000000..fcb550b81ca --- /dev/null +++ b/consensus/types/src/preset.rs @@ -0,0 +1,196 @@ +use crate::{ChainSpec, Epoch, EthSpec, Unsigned}; +use serde_derive::{Deserialize, Serialize}; + +/// Value-level representation of an Ethereum consensus "preset". +/// +/// This should only be used to check consistency of the compile-time constants +/// with a preset YAML file, or to make preset values available to the API. Prefer +/// the constants on `EthSpec` or the fields on `ChainSpec` to constructing and using +/// one of these structs. +/// +/// https://github.com/ethereum/eth2.0-specs/blob/dev/presets/mainnet/phase0.yaml +#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)] +#[serde(rename_all = "UPPERCASE")] +pub struct BasePreset { + #[serde(with = "serde_utils::quoted_u64")] + pub max_committees_per_slot: u64, + #[serde(with = "serde_utils::quoted_u64")] + pub target_committee_size: u64, + #[serde(with = "serde_utils::quoted_u64")] + pub max_validators_per_committee: u64, + #[serde(with = "serde_utils::quoted_u8")] + pub shuffle_round_count: u8, + #[serde(with = "serde_utils::quoted_u64")] + pub hysteresis_quotient: u64, + #[serde(with = "serde_utils::quoted_u64")] + pub hysteresis_downward_multiplier: u64, + #[serde(with = "serde_utils::quoted_u64")] + pub hysteresis_upward_multiplier: u64, + #[serde(with = "serde_utils::quoted_u64")] + pub safe_slots_to_update_justified: u64, + #[serde(with = "serde_utils::quoted_u64")] + pub min_deposit_amount: u64, + #[serde(with = "serde_utils::quoted_u64")] + pub max_effective_balance: u64, + #[serde(with = "serde_utils::quoted_u64")] + pub effective_balance_increment: u64, + #[serde(with = "serde_utils::quoted_u64")] + pub min_attestation_inclusion_delay: u64, + #[serde(with = "serde_utils::quoted_u64")] + pub slots_per_epoch: u64, + #[serde(with = "serde_utils::quoted_u64")] + pub min_seed_lookahead: Epoch, + #[serde(with = "serde_utils::quoted_u64")] + pub max_seed_lookahead: Epoch, + #[serde(with = "serde_utils::quoted_u64")] + pub epochs_per_eth1_voting_period: u64, + #[serde(with = "serde_utils::quoted_u64")] + pub slots_per_historical_root: u64, + #[serde(with = "serde_utils::quoted_u64")] + pub min_epochs_to_inactivity_penalty: u64, + #[serde(with = "serde_utils::quoted_u64")] + pub epochs_per_historical_vector: u64, + #[serde(with = "serde_utils::quoted_u64")] + pub epochs_per_slashings_vector: u64, + #[serde(with = "serde_utils::quoted_u64")] + pub historical_roots_limit: u64, + #[serde(with = "serde_utils::quoted_u64")] + pub validator_registry_limit: u64, + #[serde(with = "serde_utils::quoted_u64")] + pub base_reward_factor: u64, + #[serde(with = "serde_utils::quoted_u64")] + pub whistleblower_reward_quotient: u64, + #[serde(with = "serde_utils::quoted_u64")] + pub proposer_reward_quotient: u64, + #[serde(with = "serde_utils::quoted_u64")] + pub inactivity_penalty_quotient: u64, + #[serde(with = "serde_utils::quoted_u64")] + pub min_slashing_penalty_quotient: u64, + #[serde(with = "serde_utils::quoted_u64")] + pub proportional_slashing_multiplier: u64, + #[serde(with = "serde_utils::quoted_u64")] + pub max_proposer_slashings: u64, + #[serde(with = "serde_utils::quoted_u64")] + pub max_attester_slashings: u64, + #[serde(with = "serde_utils::quoted_u64")] + pub max_attestations: u64, + #[serde(with = "serde_utils::quoted_u64")] + pub max_deposits: u64, + #[serde(with = "serde_utils::quoted_u64")] + pub max_voluntary_exits: u64, +} + +impl BasePreset { + pub fn from_chain_spec(spec: &ChainSpec) -> Self { + Self { + max_committees_per_slot: spec.max_committees_per_slot as u64, + target_committee_size: spec.target_committee_size as u64, + max_validators_per_committee: T::MaxValidatorsPerCommittee::to_u64(), + shuffle_round_count: spec.shuffle_round_count, + hysteresis_quotient: spec.hysteresis_quotient, + hysteresis_downward_multiplier: spec.hysteresis_downward_multiplier, + hysteresis_upward_multiplier: spec.hysteresis_upward_multiplier, + safe_slots_to_update_justified: spec.safe_slots_to_update_justified, + min_deposit_amount: spec.min_deposit_amount, + max_effective_balance: spec.max_effective_balance, + effective_balance_increment: spec.effective_balance_increment, + min_attestation_inclusion_delay: spec.min_attestation_inclusion_delay, + slots_per_epoch: T::SlotsPerEpoch::to_u64(), + min_seed_lookahead: spec.min_seed_lookahead, + max_seed_lookahead: spec.max_seed_lookahead, + epochs_per_eth1_voting_period: T::EpochsPerEth1VotingPeriod::to_u64(), + slots_per_historical_root: T::SlotsPerHistoricalRoot::to_u64(), + min_epochs_to_inactivity_penalty: spec.min_epochs_to_inactivity_penalty, + epochs_per_historical_vector: T::EpochsPerHistoricalVector::to_u64(), + epochs_per_slashings_vector: T::EpochsPerSlashingsVector::to_u64(), + historical_roots_limit: T::HistoricalRootsLimit::to_u64(), + validator_registry_limit: T::ValidatorRegistryLimit::to_u64(), + base_reward_factor: spec.base_reward_factor, + whistleblower_reward_quotient: spec.whistleblower_reward_quotient, + proposer_reward_quotient: spec.proposer_reward_quotient, + inactivity_penalty_quotient: spec.inactivity_penalty_quotient, + min_slashing_penalty_quotient: spec.min_slashing_penalty_quotient, + proportional_slashing_multiplier: spec.proportional_slashing_multiplier, + max_proposer_slashings: T::MaxProposerSlashings::to_u64(), + max_attester_slashings: T::MaxAttesterSlashings::to_u64(), + max_attestations: T::MaxAttestations::to_u64(), + max_deposits: T::MaxDeposits::to_u64(), + max_voluntary_exits: T::MaxVoluntaryExits::to_u64(), + } + } +} + +#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)] +#[serde(rename_all = "UPPERCASE")] +pub struct AltairPreset { + #[serde(with = "serde_utils::quoted_u64")] + pub inactivity_penalty_quotient_altair: u64, + #[serde(with = "serde_utils::quoted_u64")] + pub min_slashing_penalty_quotient_altair: u64, + #[serde(with = "serde_utils::quoted_u64")] + pub proportional_slashing_multiplier_altair: u64, + #[serde(with = "serde_utils::quoted_u64")] + pub sync_committee_size: u64, + #[serde(with = "serde_utils::quoted_u64")] + pub epochs_per_sync_committee_period: Epoch, + #[serde(with = "serde_utils::quoted_u64")] + pub min_sync_committee_participants: u64, +} + +impl AltairPreset { + pub fn from_chain_spec(spec: &ChainSpec) -> Self { + Self { + inactivity_penalty_quotient_altair: spec.inactivity_penalty_quotient_altair, + min_slashing_penalty_quotient_altair: spec.min_slashing_penalty_quotient_altair, + proportional_slashing_multiplier_altair: spec.proportional_slashing_multiplier_altair, + sync_committee_size: T::SyncCommitteeSize::to_u64(), + epochs_per_sync_committee_period: spec.epochs_per_sync_committee_period, + min_sync_committee_participants: spec.min_sync_committee_participants, + } + } +} + +#[cfg(test)] +mod test { + use super::*; + use crate::{MainnetEthSpec, MinimalEthSpec}; + use serde::de::DeserializeOwned; + use std::env; + use std::fs::File; + use std::path::PathBuf; + + fn presets_base_path() -> PathBuf { + env::var("CARGO_MANIFEST_DIR") + .expect("should know manifest dir") + .parse::() + .expect("should parse manifest dir as path") + .join("presets") + } + + fn preset_from_file(preset_name: &str, filename: &str) -> T { + let f = File::open(&presets_base_path().join(preset_name).join(filename)) + .expect("preset file exists"); + serde_yaml::from_reader(f).unwrap() + } + + fn preset_test() { + let preset_name = E::spec_name().to_string(); + let spec = E::default_spec(); + + let phase0: BasePreset = preset_from_file(&preset_name, "phase0.yaml"); + assert_eq!(phase0, BasePreset::from_chain_spec::(&spec)); + + let altair: AltairPreset = preset_from_file(&preset_name, "altair.yaml"); + assert_eq!(altair, AltairPreset::from_chain_spec::(&spec)); + } + + #[test] + fn mainnet_presets_consistent() { + preset_test::(); + } + + #[test] + fn minimal_presets_consistent() { + preset_test::(); + } +} diff --git a/consensus/types/src/signed_beacon_block.rs b/consensus/types/src/signed_beacon_block.rs index 2436d5552e2..1a9e93b8e2d 100644 --- a/consensus/types/src/signed_beacon_block.rs +++ b/consensus/types/src/signed_beacon_block.rs @@ -71,7 +71,7 @@ impl SignedBeaconBlock { /// Will return an `Err` if `self` has been instantiated to a variant conflicting with the fork /// dictated by `self.slot()`. pub fn fork_name(&self, spec: &ChainSpec) -> Result { - let fork_at_slot = spec.fork_name_at_slot(self.slot()); + let fork_at_slot = spec.fork_name_at_slot::(self.slot()); let object_fork = match self { SignedBeaconBlock::Base { .. } => ForkName::Base, SignedBeaconBlock::Altair { .. } => ForkName::Altair, diff --git a/consensus/types/src/sync_committee.rs b/consensus/types/src/sync_committee.rs index 663a3f88dc8..085f0bc04fe 100644 --- a/consensus/types/src/sync_committee.rs +++ b/consensus/types/src/sync_committee.rs @@ -12,7 +12,7 @@ use tree_hash_derive::TreeHash; #[serde(bound = "T: EthSpec")] pub struct SyncCommittee { pub pubkeys: FixedVector, - pub pubkey_aggregates: FixedVector, + pub aggregate_pubkey: PublicKeyBytes, } impl SyncCommittee { @@ -23,10 +23,7 @@ impl SyncCommittee { PublicKeyBytes::empty(); T::SyncCommitteeSize::to_usize() ])?, - pubkey_aggregates: FixedVector::new(vec![ - PublicKeyBytes::empty(); - T::SyncAggregateSize::to_usize() - ])?, + aggregate_pubkey: PublicKeyBytes::empty(), }) } } diff --git a/lcli/src/main.rs b/lcli/src/main.rs index 0a2c4d2548c..48ca0338dd2 100644 --- a/lcli/src/main.rs +++ b/lcli/src/main.rs @@ -378,12 +378,12 @@ fn main() { ), ) .arg( - Arg::with_name("altair-fork-slot") - .long("altair-fork-slot") - .value_name("SLOT") + Arg::with_name("altair-fork-epoch") + .long("altair-fork-epoch") + .value_name("EPOCH") .takes_value(true) .help( - "The slot at which to enable the Altair hard fork", + "The epoch at which to enable the Altair hard fork", ), ) ) diff --git a/lcli/src/new_testnet.rs b/lcli/src/new_testnet.rs index c143d437fd7..777633ca821 100644 --- a/lcli/src/new_testnet.rs +++ b/lcli/src/new_testnet.rs @@ -2,7 +2,7 @@ use clap::ArgMatches; use clap_utils::{parse_optional, parse_required, parse_ssz_optional}; use eth2_network_config::Eth2NetworkConfig; use std::path::PathBuf; -use types::{Address, AltairConfig, BaseConfig, EthSpec}; +use types::{Address, Config, EthSpec}; pub fn run(testnet_dir_path: PathBuf, matches: &ArgMatches) -> Result<(), String> { let deposit_contract_address: Address = parse_required(matches, "deposit-contract-address")?; @@ -49,16 +49,15 @@ pub fn run(testnet_dir_path: PathBuf, matches: &ArgMatches) -> Resul spec.genesis_fork_version = v; } - if let Some(fork_slot) = parse_optional(matches, "altair-fork-slot")? { - spec.altair_fork_slot = Some(fork_slot); + if let Some(fork_epoch) = parse_optional(matches, "altair-fork-epoch")? { + spec.altair_fork_epoch = Some(fork_epoch); } let testnet = Eth2NetworkConfig { deposit_contract_deploy_block, boot_enr: Some(vec![]), genesis_state_bytes: None, - base_config: BaseConfig::from_chain_spec::(&spec), - altair_config: AltairConfig::from_chain_spec::(&spec), + config: Config::from_chain_spec::(&spec), }; testnet.write_to_file(testnet_dir_path, overwrite_files) diff --git a/lighthouse/environment/tests/environment_builder.rs b/lighthouse/environment/tests/environment_builder.rs index 99f9cf28760..ad775c99f5e 100644 --- a/lighthouse/environment/tests/environment_builder.rs +++ b/lighthouse/environment/tests/environment_builder.rs @@ -3,7 +3,7 @@ use environment::EnvironmentBuilder; use eth2_network_config::{Eth2NetworkConfig, DEFAULT_HARDCODED_NETWORK}; use std::path::PathBuf; -use types::{AltairConfig, BaseConfig, MainnetEthSpec}; +use types::{Config, MainnetEthSpec}; fn builder() -> EnvironmentBuilder { EnvironmentBuilder::mainnet() @@ -24,13 +24,10 @@ mod setup_eth2_config { fn update_spec_with_yaml_config() { if let Some(mut eth2_network_config) = eth2_network_config() { let testnet_dir = PathBuf::from("./tests/testnet_dir"); - let base_config = testnet_dir.join("config.yaml"); - let altair_config = testnet_dir.join("altair.yaml"); + let config = testnet_dir.join("config.yaml"); - eth2_network_config.base_config = - BaseConfig::from_file(base_config.as_path()).expect("should load yaml config"); - eth2_network_config.altair_config = - AltairConfig::from_file(altair_config.as_path()).expect("should load yaml config"); + eth2_network_config.config = + Config::from_file(config.as_path()).expect("should load yaml config"); let environment = builder() .eth2_network_config(eth2_network_config) @@ -38,16 +35,16 @@ mod setup_eth2_config { .build() .expect("should build environment"); - assert_eq!( - environment.eth2_config.spec.max_committees_per_slot, - 128 // see testnet_dir/config.yaml - ); assert_eq!( environment .eth2_config .spec - .inactivity_penalty_quotient_altair, - 7 // see testnet_dir/altair.yaml + .min_genesis_active_validator_count, + 100000 // see testnet_dir/config.yaml + ); + assert_eq!( + environment.eth2_config.spec.inactivity_score_bias, + 2 // see testnet_dir/config.yaml ); } } diff --git a/lighthouse/environment/tests/testnet_dir/altair.yaml b/lighthouse/environment/tests/testnet_dir/altair.yaml deleted file mode 100644 index 854eee30186..00000000000 --- a/lighthouse/environment/tests/testnet_dir/altair.yaml +++ /dev/null @@ -1,53 +0,0 @@ -# Mainnet preset - Altair - -CONFIG_NAME: "mainnet" - -# Updated penalty values -# --------------------------------------------------------------- -# 3 * 2**24 (= 50,331,648) -INACTIVITY_PENALTY_QUOTIENT_ALTAIR: 7 # MODIFIED FOR TESTING -# 2**6 (= 64) -MIN_SLASHING_PENALTY_QUOTIENT_ALTAIR: 64 -# 2 -PROPORTIONAL_SLASHING_MULTIPLIER_ALTAIR: 2 - - -# Misc -# --------------------------------------------------------------- -# 2**10 (= 1,024) -SYNC_COMMITTEE_SIZE: 1024 -# 2**6 (= 64) -SYNC_PUBKEYS_PER_AGGREGATE: 64 -# 2**2 (= 4) -INACTIVITY_SCORE_BIAS: 4 - - -# Time parameters -# --------------------------------------------------------------- -# 2**8 (= 256) -EPOCHS_PER_SYNC_COMMITTEE_PERIOD: 256 - - -# Signature domains -# --------------------------------------------------------------- -DOMAIN_SYNC_COMMITTEE: 0x07000000 -DOMAIN_SYNC_COMMITTEE_SELECTION_PROOF: 0x08000000 -DOMAIN_CONTRIBUTION_AND_PROOF: 0x09000000 - - -# Fork -# --------------------------------------------------------------- -# 0x01000000 -ALTAIR_FORK_VERSION: 0x01000000 -# TBD -ALTAIR_FORK_SLOT: 18446744073709551615 - - -# Sync protocol -# --------------------------------------------------------------- -# 1 -MIN_SYNC_COMMITTEE_PARTICIPANTS: 1 -# 2**13 -MAX_VALID_LIGHT_CLIENT_UPDATES: 8192 -# 2**13 (=8192) -LIGHT_CLIENT_UPDATE_TIMEOUT: 8192 diff --git a/lighthouse/environment/tests/testnet_dir/config.yaml b/lighthouse/environment/tests/testnet_dir/config.yaml index ec09289d926..7d0105cca8e 100644 --- a/lighthouse/environment/tests/testnet_dir/config.yaml +++ b/lighthouse/environment/tests/testnet_dir/config.yaml @@ -1,155 +1,71 @@ -# Mainnet preset +# Mainnet config -CONFIG_NAME: "mainnet" +# Extends the mainnet preset +PRESET_BASE: 'mainnet' -# Misc +# Genesis # --------------------------------------------------------------- -# 2**6 (= 64) -MAX_COMMITTEES_PER_SLOT: 128 # MODIFIED FOR TESTING -# 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 +# CUSTOMISED FOR TEST +MIN_GENESIS_ACTIVE_VALIDATOR_COUNT: 100000 # 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 +# Mainnet initial fork version, recommend altering for testnets +GENESIS_FORK_VERSION: 0x00000000 +# 604800 seconds (7 days) +GENESIS_DELAY: 604800 -# Deposit contract +# Forking # --------------------------------------------------------------- -# Ethereum PoW Mainnet -DEPOSIT_CHAIN_ID: 1 -DEPOSIT_NETWORK_ID: 1 -# **TBD** -DEPOSIT_CONTRACT_ADDRESS: 0x00000000219ab540356cBB839Cbe05303d7705Fa +# Some forks are disabled for now: +# - These may be re-assigned to another fork-version later +# - Temporarily set to max uint64 value: 2**64 - 1 +# Altair +ALTAIR_FORK_VERSION: 0x01000000 +ALTAIR_FORK_EPOCH: 18446744073709551615 +# Merge +MERGE_FORK_VERSION: 0x02000000 +MERGE_FORK_EPOCH: 18446744073709551615 +# Sharding +SHARDING_FORK_VERSION: 0x03000000 +SHARDING_FORK_EPOCH: 18446744073709551615 -# 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 +# TBD, 2**32 is a placeholder. Merge transition approach is in active R&D. +TRANSITION_TOTAL_DIFFICULTY: 4294967296 # 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 +# 14 (estimate from Eth1 mainnet) +SECONDS_PER_ETH1_BLOCK: 14 # 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 +# 2**11 (= 2,048) Eth1 blocks ~8 hours +ETH1_FOLLOW_DISTANCE: 2048 -# Max operations per block +# Validator cycle # --------------------------------------------------------------- +# CUSTOMISED FOR TEST +INACTIVITY_SCORE_BIAS: 2 # 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 +INACTIVITY_SCORE_RECOVERY_RATE: 16 +# 2**4 * 10**9 (= 16,000,000,000) Gwei +EJECTION_BALANCE: 16000000000 +# 2**2 (= 4) +MIN_PER_EPOCH_CHURN_LIMIT: 4 +# 2**16 (= 65,536) +CHURN_LIMIT_QUOTIENT: 65536 -# Signature domains +# Deposit contract # --------------------------------------------------------------- -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 +# Ethereum PoW Mainnet +DEPOSIT_CHAIN_ID: 1 +DEPOSIT_NETWORK_ID: 1 +DEPOSIT_CONTRACT_ADDRESS: 0x00000000219ab540356cBB839Cbe05303d7705Fa diff --git a/lighthouse/src/main.rs b/lighthouse/src/main.rs index a2520d9be1c..bce2ecafe82 100644 --- a/lighthouse/src/main.rs +++ b/lighthouse/src/main.rs @@ -119,7 +119,7 @@ fn main() { .long("network") .value_name("network") .help("Name of the Eth2 chain Lighthouse will sync and follow.") - .possible_values(&["pyrmont", "mainnet", "toledo", "prater"]) + .possible_values(&["pyrmont", "mainnet", "prater"]) .conflicts_with("testnet-dir") .takes_value(true) .global(true) diff --git a/scripts/local_testnet/setup.sh b/scripts/local_testnet/setup.sh index 906d8112c2b..4e86ec88064 100755 --- a/scripts/local_testnet/setup.sh +++ b/scripts/local_testnet/setup.sh @@ -30,7 +30,7 @@ lcli \ --min-genesis-time $GENESIS_TIME \ --genesis-delay $GENESIS_DELAY \ --genesis-fork-version $GENESIS_FORK_VERSION \ - --altair-fork-slot $ALTAIR_FORK_SLOT \ + --altair-fork-epoch $ALTAIR_FORK_EPOCH \ --eth1-id $NETWORK_ID \ --eth1-follow-distance 1 \ --seconds-per-eth1-block 1 \ diff --git a/scripts/local_testnet/vars.env b/scripts/local_testnet/vars.env index 252daeae8e8..3152dd49f47 100644 --- a/scripts/local_testnet/vars.env +++ b/scripts/local_testnet/vars.env @@ -27,4 +27,4 @@ BOOTNODE_PORT=4242 NETWORK_ID=4242 # Hard fork configuration -ALTAIR_FORK_SLOT=18446744073709551615 +ALTAIR_FORK_EPOCH=18446744073709551615 diff --git a/testing/ef_tests/Makefile b/testing/ef_tests/Makefile index e1066e8315a..2a089dc62a2 100644 --- a/testing/ef_tests/Makefile +++ b/testing/ef_tests/Makefile @@ -1,4 +1,4 @@ -TESTS_TAG := v1.1.0-alpha.3 +TESTS_TAG := v1.1.0-alpha.6 TESTS = general minimal mainnet TARBALLS = $(patsubst %,%-$(TESTS_TAG).tar.gz,$(TESTS)) diff --git a/testing/ef_tests/check_all_files_accessed.py b/testing/ef_tests/check_all_files_accessed.py index fac2cf383f6..17ca67de6b7 100755 --- a/testing/ef_tests/check_all_files_accessed.py +++ b/testing/ef_tests/check_all_files_accessed.py @@ -19,15 +19,16 @@ # following strings, we will assume they are to be ignored (i.e., we are purposefully *not* running # the spec tests). excluded_paths = [ - # Things from future phases + # Configs from future phases "tests/mainnet/config/custody_game.yaml", "tests/mainnet/config/sharding.yaml", "tests/mainnet/config/merge.yaml", "tests/minimal/config/custody_game.yaml", "tests/minimal/config/sharding.yaml", "tests/minimal/config/merge.yaml", - # Genesis Validity - "tests/minimal/altair/genesis/validity", + # Merge tests + "tests/minimal/merge", + "tests/mainnet/merge", # Eth1Block # # Intentionally omitted, as per https://github.com/sigp/lighthouse/issues/1835 @@ -59,6 +60,9 @@ # SyncCommitteeSigningData "tests/minimal/altair/ssz_static/SyncCommitteeSigningData", "tests/mainnet/altair/ssz_static/SyncCommitteeSigningData", + # SyncAggregatorSelectionData + "tests/minimal/altair/ssz_static/SyncAggregatorSelectionData", + "tests/mainnet/altair/ssz_static/SyncAggregatorSelectionData", # Fork choice "tests/mainnet/phase0/fork_choice", "tests/minimal/phase0/fork_choice", diff --git a/testing/ef_tests/src/cases.rs b/testing/ef_tests/src/cases.rs index 2fed10169b1..2e52d8c2b57 100644 --- a/testing/ef_tests/src/cases.rs +++ b/testing/ef_tests/src/cases.rs @@ -21,6 +21,7 @@ mod sanity_slots; mod shuffling; mod ssz_generic; mod ssz_static; +mod transition; pub use bls_aggregate_sigs::*; pub use bls_aggregate_verify::*; @@ -39,6 +40,7 @@ pub use sanity_slots::*; pub use shuffling::*; pub use ssz_generic::*; pub use ssz_static::*; +pub use transition::TransitionTest; pub trait LoadCase: Sized { /// Load the test case from a test case directory. diff --git a/testing/ef_tests/src/cases/common.rs b/testing/ef_tests/src/cases/common.rs index 34f5c581e8d..175ad113b61 100644 --- a/testing/ef_tests/src/cases/common.rs +++ b/testing/ef_tests/src/cases/common.rs @@ -71,3 +71,11 @@ impl SszStaticType for T where T: serde::de::DeserializeOwned + Encode + TreeHash + Clone + PartialEq + Debug + Sync { } + +/// Return the fork immediately prior to a fork. +pub fn previous_fork(fork_name: ForkName) -> ForkName { + match fork_name { + ForkName::Base => ForkName::Base, + ForkName::Altair => ForkName::Base, + } +} diff --git a/testing/ef_tests/src/cases/epoch_processing.rs b/testing/ef_tests/src/cases/epoch_processing.rs index 20b9b955ef5..8ca3775f06d 100644 --- a/testing/ef_tests/src/cases/epoch_processing.rs +++ b/testing/ef_tests/src/cases/epoch_processing.rs @@ -61,6 +61,10 @@ pub struct HistoricalRootsUpdate; pub struct ParticipationRecordUpdates; #[derive(Debug)] pub struct SyncCommitteeUpdates; +#[derive(Debug)] +pub struct InactivityUpdates; +#[derive(Debug)] +pub struct ParticipationFlagUpdates; type_name!( JustificationAndFinalization, @@ -76,6 +80,8 @@ type_name!(RandaoMixesReset, "randao_mixes_reset"); type_name!(HistoricalRootsUpdate, "historical_roots_update"); type_name!(ParticipationRecordUpdates, "participation_record_updates"); type_name!(SyncCommitteeUpdates, "sync_committee_updates"); +type_name!(InactivityUpdates, "inactivity_updates"); +type_name!(ParticipationFlagUpdates, "participation_flag_updates"); impl EpochTransition for JustificationAndFinalization { fn run(state: &mut BeaconState, spec: &ChainSpec) -> Result<(), EpochProcessingError> { @@ -188,19 +194,30 @@ impl EpochTransition for SyncCommitteeUpdates { } } +impl EpochTransition for InactivityUpdates { + fn run(state: &mut BeaconState, spec: &ChainSpec) -> Result<(), EpochProcessingError> { + match state { + BeaconState::Base(_) => Ok(()), + BeaconState::Altair(_) => altair::process_inactivity_updates(state, spec), + } + } +} + +impl EpochTransition for ParticipationFlagUpdates { + fn run(state: &mut BeaconState, _: &ChainSpec) -> Result<(), EpochProcessingError> { + match state { + BeaconState::Base(_) => Ok(()), + BeaconState::Altair(_) => altair::process_participation_flag_updates(state), + } + } +} + impl> LoadCase for EpochProcessing { fn load_from_dir(path: &Path, fork_name: ForkName) -> Result { let spec = &testing_spec::(fork_name); let metadata_path = path.join("meta.yaml"); let metadata: Metadata = if metadata_path.is_file() { yaml_decode_file(&metadata_path)? - } else if T::name() == "sync_committee_updates" { - // FIXME(altair): this is a hack because the epoch tests are missing metadata - // and the sync aggregate tests need real BLS - Metadata { - description: None, - bls_setting: Some(BlsSetting::Required), - } } else { Metadata::default() }; @@ -232,8 +249,12 @@ impl> Case for EpochProcessing { fn is_enabled_for_fork(fork_name: ForkName) -> bool { match fork_name { - // No sync committee tests for genesis fork. - ForkName::Base => T::name() != "sync_committee_updates", + // No Altair tests for genesis fork. + ForkName::Base => { + T::name() != "sync_committee_updates" + && T::name() != "inactivity_updates" + && T::name() != "participation_flag_updates" + } ForkName::Altair => true, } } diff --git a/testing/ef_tests/src/cases/fork.rs b/testing/ef_tests/src/cases/fork.rs index f6bab913100..f3591bee729 100644 --- a/testing/ef_tests/src/cases/fork.rs +++ b/testing/ef_tests/src/cases/fork.rs @@ -1,7 +1,9 @@ use super::*; use crate::case_result::compare_beacon_state_results_without_caches; +use crate::cases::common::previous_fork; use crate::decode::{ssz_decode_state, yaml_decode_file}; use serde_derive::Deserialize; +use state_processing::upgrade::upgrade_to_altair; use types::{BeaconState, ForkName}; #[derive(Debug, Clone, Default, Deserialize)] @@ -11,17 +13,7 @@ pub struct Metadata { impl Metadata { fn fork_name(&self) -> ForkName { - match self.fork.as_str() { - "altair" => ForkName::Altair, - _ => panic!("unknown fork: {}", self.fork), - } - } -} - -fn previous_fork(fork_name: ForkName) -> ForkName { - match fork_name { - ForkName::Base => ForkName::Base, - ForkName::Altair => ForkName::Base, + self.fork.parse().unwrap() } } @@ -66,7 +58,7 @@ impl Case for ForkTest { let spec = &E::default_spec(); let mut result = match fork_name { - ForkName::Altair => result_state.upgrade_to_altair(spec).map(|_| result_state), + ForkName::Altair => upgrade_to_altair(&mut result_state, spec).map(|_| result_state), _ => panic!("unknown fork: {:?}", fork_name), }; diff --git a/testing/ef_tests/src/cases/genesis_initialization.rs b/testing/ef_tests/src/cases/genesis_initialization.rs index dc1b2a68bab..2a9323c96a2 100644 --- a/testing/ef_tests/src/cases/genesis_initialization.rs +++ b/testing/ef_tests/src/cases/genesis_initialization.rs @@ -54,6 +54,11 @@ impl LoadCase for GenesisInitialization { } impl Case for GenesisInitialization { + fn is_enabled_for_fork(fork_name: ForkName) -> bool { + // Altair genesis and later requires real crypto. + fork_name == ForkName::Base || cfg!(not(feature = "fake_crypto")) + } + fn result(&self, _case_index: usize, fork_name: ForkName) -> Result<(), Error> { let spec = &testing_spec::(fork_name); diff --git a/testing/ef_tests/src/cases/genesis_validity.rs b/testing/ef_tests/src/cases/genesis_validity.rs index 4a722c96ddb..e645d69adc0 100644 --- a/testing/ef_tests/src/cases/genesis_validity.rs +++ b/testing/ef_tests/src/cases/genesis_validity.rs @@ -5,9 +5,15 @@ use state_processing::is_valid_genesis_state; use std::path::Path; use types::{BeaconState, EthSpec, ForkName}; +#[derive(Debug, Clone, Deserialize)] +pub struct Metadata { + description: String, +} + #[derive(Debug, Clone, Deserialize)] #[serde(bound = "E: EthSpec")] pub struct GenesisValidity { + pub metadata: Option, pub genesis: BeaconState, pub is_valid: bool, } @@ -17,8 +23,18 @@ impl LoadCase for GenesisValidity { let spec = &testing_spec::(fork_name); let genesis = ssz_decode_state(&path.join("genesis.ssz_snappy"), spec)?; let is_valid = yaml_decode_file(&path.join("is_valid.yaml"))?; + let meta_path = path.join("meta.yaml"); + let metadata = if meta_path.exists() { + Some(yaml_decode_file(&meta_path)?) + } else { + None + }; - Ok(Self { genesis, is_valid }) + Ok(Self { + metadata, + genesis, + is_valid, + }) } } diff --git a/testing/ef_tests/src/cases/rewards.rs b/testing/ef_tests/src/cases/rewards.rs index 2136d237d46..df9c1766199 100644 --- a/testing/ef_tests/src/cases/rewards.rs +++ b/testing/ef_tests/src/cases/rewards.rs @@ -15,10 +15,7 @@ use state_processing::{ }; use std::path::{Path, PathBuf}; use types::{ - consts::altair::{ - TIMELY_HEAD_FLAG_INDEX, TIMELY_HEAD_WEIGHT, TIMELY_SOURCE_FLAG_INDEX, TIMELY_SOURCE_WEIGHT, - TIMELY_TARGET_FLAG_INDEX, TIMELY_TARGET_WEIGHT, - }, + consts::altair::{TIMELY_HEAD_FLAG_INDEX, TIMELY_SOURCE_FLAG_INDEX, TIMELY_TARGET_FLAG_INDEX}, BeaconState, EthSpec, ForkName, }; @@ -132,26 +129,22 @@ impl Case for RewardsTest { let source_deltas = compute_altair_flag_deltas( &state, TIMELY_SOURCE_FLAG_INDEX, - TIMELY_SOURCE_WEIGHT, total_active_balance, spec, )?; let target_deltas = compute_altair_flag_deltas( &state, TIMELY_TARGET_FLAG_INDEX, - TIMELY_TARGET_WEIGHT, total_active_balance, spec, )?; let head_deltas = compute_altair_flag_deltas( &state, TIMELY_HEAD_FLAG_INDEX, - TIMELY_HEAD_WEIGHT, total_active_balance, spec, )?; - let inactivity_penalty_deltas = - compute_altair_inactivity_deltas(&state, total_active_balance, spec)?; + let inactivity_penalty_deltas = compute_altair_inactivity_deltas(&state, spec)?; Ok(AllDeltas { source_deltas, target_deltas, @@ -189,35 +182,21 @@ fn convert_base_deltas(attestation_deltas: &[AttestationDelta], accessor: Access fn compute_altair_flag_deltas( state: &BeaconState, - flag_index: u32, - flag_weight: u64, + flag_index: usize, total_active_balance: u64, spec: &ChainSpec, ) -> Result { let mut deltas = vec![Delta::default(); state.validators().len()]; - get_flag_index_deltas( - &mut deltas, - state, - flag_index, - flag_weight, - total_active_balance, - spec, - )?; + get_flag_index_deltas(&mut deltas, state, flag_index, total_active_balance, spec)?; Ok(convert_altair_deltas(deltas)) } fn compute_altair_inactivity_deltas( state: &BeaconState, - total_active_balance: u64, spec: &ChainSpec, ) -> Result { let mut deltas = vec![Delta::default(); state.validators().len()]; - altair::rewards_and_penalties::get_inactivity_penalty_deltas( - &mut deltas, - state, - total_active_balance, - spec, - )?; + altair::rewards_and_penalties::get_inactivity_penalty_deltas(&mut deltas, state, spec)?; Ok(convert_altair_deltas(deltas)) } diff --git a/testing/ef_tests/src/cases/transition.rs b/testing/ef_tests/src/cases/transition.rs new file mode 100644 index 00000000000..d41a52d52ff --- /dev/null +++ b/testing/ef_tests/src/cases/transition.rs @@ -0,0 +1,114 @@ +use super::*; +use crate::case_result::compare_beacon_state_results_without_caches; +use crate::decode::{ssz_decode_file_with, ssz_decode_state, yaml_decode_file}; +use serde_derive::Deserialize; +use state_processing::{ + per_block_processing, state_advance::complete_state_advance, BlockSignatureStrategy, +}; +use std::str::FromStr; +use types::{BeaconState, Epoch, ForkName, SignedBeaconBlock}; + +#[derive(Debug, Clone, Deserialize)] +pub struct Metadata { + pub post_fork: String, + pub fork_epoch: Epoch, + pub fork_block: Option, + pub blocks_count: usize, +} + +#[derive(Debug)] +pub struct TransitionTest { + pub metadata: Metadata, + pub pre: BeaconState, + pub blocks: Vec>, + pub post: BeaconState, + pub spec: ChainSpec, +} + +impl LoadCase for TransitionTest { + fn load_from_dir(path: &Path, fork_name: ForkName) -> Result { + let metadata: Metadata = yaml_decode_file(&path.join("meta.yaml"))?; + assert_eq!(ForkName::from_str(&metadata.post_fork).unwrap(), fork_name); + + // Make spec with appropriate fork block. + let mut spec = E::default_spec(); + match fork_name { + ForkName::Base => panic!("cannot fork to base/phase0"), + ForkName::Altair => { + spec.altair_fork_epoch = Some(metadata.fork_epoch); + } + } + + // Load blocks + let blocks = (0..metadata.blocks_count) + .map(|i| { + let filename = format!("blocks_{}.ssz_snappy", i); + ssz_decode_file_with(&path.join(filename), |bytes| { + SignedBeaconBlock::from_ssz_bytes(bytes, &spec) + }) + }) + .collect::, _>>()?; + + // Decode pre-state. + let pre = ssz_decode_state(&path.join("pre.ssz_snappy"), &spec)?; + + // Decode post-state. + let post = ssz_decode_state(&path.join("post.ssz_snappy"), &spec)?; + + Ok(Self { + metadata, + pre, + blocks, + post, + spec, + }) + } +} + +impl Case for TransitionTest { + fn is_enabled_for_fork(fork_name: ForkName) -> bool { + // Upgrades exist targeting all forks except phase0/base. + // Transition tests also need BLS. + cfg!(not(feature = "fake_crypto")) && fork_name != ForkName::Base + } + + fn result(&self, _case_index: usize, _fork_name: ForkName) -> Result<(), Error> { + let mut state = self.pre.clone(); + let mut expected = Some(self.post.clone()); + let spec = &self.spec; + + let mut result: Result<_, String> = self + .blocks + .iter() + .try_for_each(|block| { + // Advance to block slot. + complete_state_advance(&mut state, None, block.slot(), spec) + .map_err(|e| format!("Failed to advance: {:?}", e))?; + + // Apply block. + per_block_processing( + &mut state, + block, + None, + BlockSignatureStrategy::VerifyBulk, + spec, + ) + .map_err(|e| format!("Block processing failed: {:?}", e))?; + + let state_root = state.update_tree_hash_cache().unwrap(); + if block.state_root() != state_root { + return Err(format!( + "Mismatched state root at slot {}, got: {:?}, expected: {:?}", + block.slot(), + state_root, + block.state_root() + )); + } + + Ok(()) + }) + .map(move |()| state); + + compare_beacon_state_results_without_caches(&mut result, &mut expected) + } +} diff --git a/testing/ef_tests/src/handler.rs b/testing/ef_tests/src/handler.rs index 136cf7d4083..6c89f70ad44 100644 --- a/testing/ef_tests/src/handler.rs +++ b/testing/ef_tests/src/handler.rs @@ -354,6 +354,26 @@ impl Handler for ForkHandler { } } +#[derive(Derivative)] +#[derivative(Default(bound = ""))] +pub struct TransitionHandler(PhantomData); + +impl Handler for TransitionHandler { + type Case = cases::TransitionTest; + + fn config_name() -> &'static str { + E::name() + } + + fn runner_name() -> &'static str { + "transition" + } + + fn handler_name(&self) -> String { + "core".into() + } +} + #[derive(Derivative)] #[derivative(Default(bound = ""))] pub struct FinalityHandler(PhantomData); diff --git a/testing/ef_tests/src/lib.rs b/testing/ef_tests/src/lib.rs index 667323c0c80..5c2ca3fb55e 100644 --- a/testing/ef_tests/src/lib.rs +++ b/testing/ef_tests/src/lib.rs @@ -1,9 +1,10 @@ pub use case_result::CaseResult; pub use cases::Case; pub use cases::{ - EffectiveBalanceUpdates, Eth1DataReset, HistoricalRootsUpdate, JustificationAndFinalization, - ParticipationRecordUpdates, RandaoMixesReset, RegistryUpdates, RewardsAndPenalties, Slashings, - SlashingsReset, SyncCommitteeUpdates, + EffectiveBalanceUpdates, Eth1DataReset, HistoricalRootsUpdate, InactivityUpdates, + JustificationAndFinalization, ParticipationFlagUpdates, ParticipationRecordUpdates, + RandaoMixesReset, RegistryUpdates, RewardsAndPenalties, Slashings, SlashingsReset, + SyncCommitteeUpdates, }; pub use decode::log_file_access; pub use error::Error; diff --git a/testing/ef_tests/tests/tests.rs b/testing/ef_tests/tests/tests.rs index 23190791856..d2f6ace9277 100644 --- a/testing/ef_tests/tests/tests.rs +++ b/testing/ef_tests/tests/tests.rs @@ -1,10 +1,11 @@ #![cfg(feature = "ef_tests")] use ef_tests::*; -use std::path::PathBuf; use types::*; +// FIXME(altair): fix these once alpha.7 is released and includes config files // Check that the config from the Eth2.0 spec tests matches our minimal/mainnet config. +/* fn config_test() { let config_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR")) .join("eth2.0-spec-tests") @@ -41,6 +42,7 @@ fn mainnet_config_ok() { fn minimal_config_ok() { config_test::(); } +*/ // Check that the hand-computed multiplications on EthSpec are correctly computed. // This test lives here because one is most likely to muck these up during a spec update. @@ -344,12 +346,30 @@ fn epoch_processing_sync_committee_updates() { EpochProcessingHandler::::default().run(); } +#[test] +fn epoch_processing_inactivity_updates() { + EpochProcessingHandler::::default().run(); + EpochProcessingHandler::::default().run(); +} + +#[test] +fn epoch_processing_participation_flag_updates() { + EpochProcessingHandler::::default().run(); + EpochProcessingHandler::::default().run(); +} + #[test] fn fork_upgrade() { ForkHandler::::default().run(); ForkHandler::::default().run(); } +#[test] +fn transition() { + TransitionHandler::::default().run(); + TransitionHandler::::default().run(); +} + #[test] fn finality() { FinalityHandler::::default().run(); diff --git a/validator_client/src/beacon_node_fallback.rs b/validator_client/src/beacon_node_fallback.rs index 219ac8d72a1..7bc45b8f014 100644 --- a/validator_client/src/beacon_node_fallback.rs +++ b/validator_client/src/beacon_node_fallback.rs @@ -16,7 +16,7 @@ use std::marker::PhantomData; use std::sync::Arc; use std::time::Duration; use tokio::{sync::RwLock, time::sleep}; -use types::{ChainSpec, EthSpec, StandardConfig}; +use types::{ChainSpec, EthSpec}; /// The number of seconds *prior* to slot start that we will try and update the state of fallback /// nodes. @@ -209,7 +209,7 @@ impl CandidateBeaconNode { /// Checks if the node has the correct specification. async fn is_compatible(&self, spec: &ChainSpec, log: &Logger) -> Result<(), CandidateError> { - let std_config = self + let config_and_preset = self .beacon_node .get_config_spec() .await @@ -225,7 +225,7 @@ impl CandidateBeaconNode { .data; let beacon_node_spec = - ChainSpec::from_standard_config::(&std_config).ok_or_else(|| { + ChainSpec::from_config::(&config_and_preset.config).ok_or_else(|| { error!( log, "The minimal/mainnet spec type of the beacon node does not match the validator \ @@ -235,20 +235,12 @@ impl CandidateBeaconNode { CandidateError::Incompatible })?; - if !std_config.extra_fields().is_empty() { + if !config_and_preset.extra_fields.is_empty() { debug!( log, "Beacon spec includes unknown fields"; "endpoint" => %self.beacon_node, - "fields" => ?std_config.extra_fields(), - ); - } - - if let StandardConfig::Base { .. } = std_config { - warn!( - log, - "Beacon spec lacks Altair config"; - "endpoint" => %self.beacon_node, + "fields" => ?config_and_preset.extra_fields, ); } diff --git a/validator_client/src/http_api/mod.rs b/validator_client/src/http_api/mod.rs index b9779e20d25..bc820ce44e5 100644 --- a/validator_client/src/http_api/mod.rs +++ b/validator_client/src/http_api/mod.rs @@ -16,7 +16,7 @@ use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4}; use std::path::PathBuf; use std::sync::{Arc, Weak}; use tokio::runtime::Runtime; -use types::{ChainSpec, EthSpec, StandardConfig}; +use types::{ChainSpec, ConfigAndPreset, EthSpec}; use validator_dir::Builder as ValidatorDirBuilder; use warp::{ http::{ @@ -191,9 +191,9 @@ pub fn serve( .and(signer.clone()) .and_then(|spec: Arc<_>, signer| { blocking_signed_json_task(signer, move || { - Ok(api_types::GenericResponse::from( - StandardConfig::from_chain_spec::(&spec), - )) + let mut config = ConfigAndPreset::from_chain_spec::(&spec); + config.make_backwards_compat(&spec); + Ok(api_types::GenericResponse::from(config)) }) }); diff --git a/validator_client/src/http_api/tests.rs b/validator_client/src/http_api/tests.rs index d8c3db8246b..cf2618bba11 100644 --- a/validator_client/src/http_api/tests.rs +++ b/validator_client/src/http_api/tests.rs @@ -150,7 +150,8 @@ impl ApiTester { pub async fn test_get_lighthouse_spec(self) -> Self { let result = self.client.get_lighthouse_spec().await.unwrap().data; - let expected = StandardConfig::from_chain_spec::(&E::default_spec()); + let mut expected = ConfigAndPreset::from_chain_spec::(&E::default_spec()); + expected.make_backwards_compat(&E::default_spec()); assert_eq!(result, expected);