From a80b94c88ba49862409b4d3ff5fcb6261cb6fac4 Mon Sep 17 00:00:00 2001 From: realbigsean Date: Thu, 25 Apr 2024 13:17:07 -0400 Subject: [PATCH 01/13] add new fields to execution payload and header --- beacon_node/execution_layer/src/engine_api.rs | 3 +++ .../execution_layer/src/engine_api/json_structures.rs | 3 +++ beacon_node/execution_layer/src/lib.rs | 5 +++++ .../src/test_utils/execution_block_generator.rs | 2 ++ consensus/types/src/execution_payload.rs | 5 +++++ consensus/types/src/execution_payload_header.rs | 8 ++++++++ 6 files changed, 26 insertions(+) diff --git a/beacon_node/execution_layer/src/engine_api.rs b/beacon_node/execution_layer/src/engine_api.rs index d422994c595..a1b9223e65e 100644 --- a/beacon_node/execution_layer/src/engine_api.rs +++ b/beacon_node/execution_layer/src/engine_api.rs @@ -627,6 +627,9 @@ impl ExecutionPayloadBodyV1 { withdrawals, blob_gas_used: header.blob_gas_used, excess_blob_gas: header.excess_blob_gas, + // TODO(electra) + deposit_receipts: <_>::default(), + withdrawal_requests: <_>::default(), })) } else { Err(format!( diff --git a/beacon_node/execution_layer/src/engine_api/json_structures.rs b/beacon_node/execution_layer/src/engine_api/json_structures.rs index d784aa4cd9c..64c3932c6d2 100644 --- a/beacon_node/execution_layer/src/engine_api/json_structures.rs +++ b/beacon_node/execution_layer/src/engine_api/json_structures.rs @@ -319,6 +319,9 @@ impl From> for ExecutionPayloadElectra .into(), blob_gas_used: payload.blob_gas_used, excess_blob_gas: payload.excess_blob_gas, + // TODO(electra) + deposit_receipts: Default::default(), + withdrawal_requests: Default::default(), } } } diff --git a/beacon_node/execution_layer/src/lib.rs b/beacon_node/execution_layer/src/lib.rs index 60f450a39de..25770c3a7d4 100644 --- a/beacon_node/execution_layer/src/lib.rs +++ b/beacon_node/execution_layer/src/lib.rs @@ -2003,6 +2003,11 @@ impl ExecutionLayer { withdrawals, blob_gas_used: electra_block.blob_gas_used, excess_blob_gas: electra_block.excess_blob_gas, + // TODO(elecrta) + // deposit_receipts: electra_block.deposit_receipts, + // withdrawal_requests: electra_block.withdrawal_requests, + deposit_receipts: <_>::default(), + withdrawal_requests: <_>::default(), }) } }; diff --git a/beacon_node/execution_layer/src/test_utils/execution_block_generator.rs b/beacon_node/execution_layer/src/test_utils/execution_block_generator.rs index bac2304fa85..a4c4dffe5b2 100644 --- a/beacon_node/execution_layer/src/test_utils/execution_block_generator.rs +++ b/beacon_node/execution_layer/src/test_utils/execution_block_generator.rs @@ -659,6 +659,8 @@ impl ExecutionBlockGenerator { withdrawals: pa.withdrawals.clone().into(), blob_gas_used: 0, excess_blob_gas: 0, + deposit_receipts: vec![].into(), + withdrawal_requests: vec![].into(), }), _ => unreachable!(), }, diff --git a/consensus/types/src/execution_payload.rs b/consensus/types/src/execution_payload.rs index 27dc8cab0a4..9612ab83134 100644 --- a/consensus/types/src/execution_payload.rs +++ b/consensus/types/src/execution_payload.rs @@ -89,6 +89,11 @@ pub struct ExecutionPayload { #[superstruct(only(Deneb, Electra), partial_getter(copy))] #[serde(with = "serde_utils::quoted_u64")] pub excess_blob_gas: u64, + #[superstruct(only(Electra))] + pub deposit_receipts: VariableList, + #[superstruct(only(Electra))] + pub withdrawal_requests: + VariableList, } impl<'a, E: EthSpec> ExecutionPayloadRef<'a, E> { diff --git a/consensus/types/src/execution_payload_header.rs b/consensus/types/src/execution_payload_header.rs index 02850304f1d..59b6930c907 100644 --- a/consensus/types/src/execution_payload_header.rs +++ b/consensus/types/src/execution_payload_header.rs @@ -88,6 +88,10 @@ pub struct ExecutionPayloadHeader { #[serde(with = "serde_utils::quoted_u64")] #[superstruct(getter(copy))] pub excess_blob_gas: u64, + #[superstruct(only(Electra), partial_getter(copy))] + pub deposit_receipts_root: Hash256, + #[superstruct(only(Electra), partial_getter(copy))] + pub withdrawal_requests_root: Hash256, } impl ExecutionPayloadHeader { @@ -204,6 +208,8 @@ impl ExecutionPayloadHeaderDeneb { withdrawals_root: self.withdrawals_root, blob_gas_used: self.blob_gas_used, excess_blob_gas: self.excess_blob_gas, + deposit_receipts_root: Hash256::zero(), + withdrawal_requests_root: Hash256::zero(), } } } @@ -295,6 +301,8 @@ impl<'a, E: EthSpec> From<&'a ExecutionPayloadElectra> for ExecutionPayloadHe withdrawals_root: payload.withdrawals.tree_hash_root(), blob_gas_used: payload.blob_gas_used, excess_blob_gas: payload.excess_blob_gas, + deposit_receipts_root: payload.deposit_receipts.tree_hash_root(), + withdrawal_requests_root: payload.withdrawal_requests.tree_hash_root(), } } } From dd63bf48bcd0cbecb2bb75cc71f8c2f992e5acc4 Mon Sep 17 00:00:00 2001 From: realbigsean Date: Thu, 25 Apr 2024 15:57:13 -0400 Subject: [PATCH 02/13] beacon state changes --- .../state_processing/src/upgrade/electra.rs | 58 ++++++++- consensus/types/src/beacon_state.rs | 111 ++++++++++++++++++ consensus/types/src/validator.rs | 16 +++ 3 files changed, 183 insertions(+), 2 deletions(-) diff --git a/consensus/state_processing/src/upgrade/electra.rs b/consensus/state_processing/src/upgrade/electra.rs index f64228f050b..36af3d1f387 100644 --- a/consensus/state_processing/src/upgrade/electra.rs +++ b/consensus/state_processing/src/upgrade/electra.rs @@ -10,14 +10,27 @@ pub fn upgrade_to_electra( spec: &ChainSpec, ) -> Result<(), Error> { let epoch = pre_state.current_epoch(); - let pre = pre_state.as_deneb_mut()?; + let exit_balance_to_consume = pre_state.get_activation_exit_churn_limit(spec)?; + let earliest_exit_epoch = pre_state + .validators() + .iter() + .filter(|v| v.exit_epoch != spec.far_future_epoch) + .map(|v| v.exit_epoch) + .max() + .unwrap_or(epoch) + + 1; + + let consolidation_balance_to_consume = pre_state.get_consolidation_churn_limit(spec)?; + let earliest_consolidation_epoch = spec.compute_activation_exit_epoch(epoch)?; + + let pre = pre_state.as_deneb_mut()?; // 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 post = BeaconState::Electra(BeaconStateElectra { + let mut post = BeaconState::Electra(BeaconStateElectra { // Versioning genesis_time: pre.genesis_time, genesis_validators_root: pre.genesis_validators_root, @@ -62,6 +75,16 @@ pub fn upgrade_to_electra( next_withdrawal_index: pre.next_withdrawal_index, next_withdrawal_validator_index: pre.next_withdrawal_validator_index, historical_summaries: pre.historical_summaries.clone(), + // Electra + deposit_receipts_start_index: spec.unset_deposit_receipts_start_index, + deposit_balance_to_consume: 0, + exit_balance_to_consume, + earliest_exit_epoch, + consolidation_balance_to_consume, + earliest_consolidation_epoch, + pending_balance_deposits: Default::default(), + pending_partial_withdrawals: Default::default(), + pending_consolidations: Default::default(), // Caches total_active_balance: pre.total_active_balance, progressive_balances_cache: mem::take(&mut pre.progressive_balances_cache), @@ -72,6 +95,37 @@ pub fn upgrade_to_electra( epoch_cache: EpochCache::default(), }); + // Add validators that are not yet active to pending balance deposits + let validators = post.validators().clone(); + let mut pre_activation = validators + .iter() + .enumerate() + .filter(|(_, validator)| validator.activation_epoch == spec.far_future_epoch) + .collect::>(); + + // Sort the indices by activation_eligibility_epoch and then by index + pre_activation.sort_by(|(index_a, val_a), (index_b, val_b)| { + if val_a.activation_eligibility_epoch == val_b.activation_eligibility_epoch { + index_a.cmp(index_b) + } else { + val_a + .activation_eligibility_epoch + .cmp(&val_b.activation_eligibility_epoch) + } + }); + + // Process validators to queue entire balance and reset them + for (index, _) in pre_activation { + post.queue_entire_balance_and_reset_validator(index, spec)?; + } + + // Ensure early adopters of compounding credentials go through the activation churn + for (index, validator) in validators.iter().enumerate() { + if validator.has_compounding_withdrawal_credential(spec) { + post.queue_excess_active_balance(index, spec)?; + } + } + *pre_state = post; Ok(()) diff --git a/consensus/types/src/beacon_state.rs b/consensus/types/src/beacon_state.rs index 5da81f6a752..1504f1f6eee 100644 --- a/consensus/types/src/beacon_state.rs +++ b/consensus/types/src/beacon_state.rs @@ -467,6 +467,40 @@ where #[test_random(default)] pub historical_summaries: List, + // Electra + #[superstruct(only(Electra), partial_getter(copy))] + #[metastruct(exclude_from(tree_lists))] + #[serde(with = "serde_utils::quoted_u64")] + pub deposit_receipts_start_index: u64, + #[superstruct(only(Electra), partial_getter(copy))] + #[metastruct(exclude_from(tree_lists))] + #[serde(with = "serde_utils::quoted_u64")] + pub deposit_balance_to_consume: u64, + #[superstruct(only(Electra), partial_getter(copy))] + #[metastruct(exclude_from(tree_lists))] + #[serde(with = "serde_utils::quoted_u64")] + pub exit_balance_to_consume: u64, + #[superstruct(only(Electra), partial_getter(copy))] + #[metastruct(exclude_from(tree_lists))] + pub earliest_exit_epoch: Epoch, + #[superstruct(only(Electra), partial_getter(copy))] + #[metastruct(exclude_from(tree_lists))] + #[serde(with = "serde_utils::quoted_u64")] + pub consolidation_balance_to_consume: u64, + #[superstruct(only(Electra), partial_getter(copy))] + #[metastruct(exclude_from(tree_lists))] + pub earliest_consolidation_epoch: Epoch, + #[test_random(default)] + #[superstruct(only(Electra))] + pub pending_balance_deposits: List, + #[test_random(default)] + #[superstruct(only(Electra))] + pub pending_partial_withdrawals: + List, + #[test_random(default)] + #[superstruct(only(Electra))] + pub pending_consolidations: List, + // Caching (not in the spec) #[serde(skip_serializing, skip_deserializing)] #[ssz(skip_serializing, skip_deserializing)] @@ -2031,6 +2065,83 @@ impl BeaconState { self.epoch_cache().get_base_reward(validator_index) } + // ******* Electra accessors ******* + + /// Return the churn limit for the current epoch. + pub fn get_balance_churn_limit(&self, spec: &ChainSpec) -> Result { + let total_active_balance = self.get_total_active_balance()?; + let churn = std::cmp::max( + spec.min_per_epoch_churn_limit_electra, + total_active_balance.safe_div(spec.churn_limit_quotient)?, + ); + + Ok(churn.safe_sub(churn.safe_rem(spec.effective_balance_increment)?)?) + } + + /// Return the churn limit for the current epoch dedicated to activations and exits. + pub fn get_activation_exit_churn_limit(&self, spec: &ChainSpec) -> Result { + Ok(std::cmp::min( + spec.max_per_epoch_activation_exit_churn_limit, + self.get_balance_churn_limit(spec)?, + )) + } + + pub fn get_consolidation_churn_limit(&self, spec: &ChainSpec) -> Result { + self.get_balance_churn_limit(spec)? + .safe_sub(self.get_activation_exit_churn_limit(spec)?) + .map_err(Into::into) + } + + // ******* Electra mutators ******* + + pub fn queue_excess_active_balance( + &mut self, + validator_index: usize, + spec: &ChainSpec, + ) -> Result<(), Error> { + let balance = self + .balances_mut() + .get_mut(validator_index) + .ok_or(Error::UnknownValidator(validator_index))?; + if *balance > spec.min_activation_balance { + let excess_balance = balance.safe_sub(spec.min_activation_balance)?; + *balance = spec.min_activation_balance; + self.pending_balance_deposits_mut()? + .push(PendingBalanceDeposit { + index: validator_index as u64, + amount: excess_balance, + })?; + } + Ok(()) + } + + pub fn queue_entire_balance_and_reset_validator( + &mut self, + validator_index: usize, + spec: &ChainSpec, + ) -> Result<(), Error> { + let balance = self + .balances_mut() + .get_mut(validator_index) + .ok_or(Error::UnknownValidator(validator_index))?; + let balance_copy = *balance; + *balance = 0_u64; + + let validator = self + .validators_mut() + .get_mut(validator_index) + .ok_or(Error::UnknownValidator(validator_index))?; + validator.effective_balance = 0; + validator.activation_eligibility_epoch = spec.far_future_epoch; + + self.pending_balance_deposits_mut()? + .push(PendingBalanceDeposit { + index: validator_index as u64, + amount: balance_copy, + }) + .map_err(Into::into) + } + #[allow(clippy::arithmetic_side_effects)] pub fn rebase_on(&mut self, base: &Self, spec: &ChainSpec) -> Result<(), Error> { // Required for macros (which use type-hints internally). diff --git a/consensus/types/src/validator.rs b/consensus/types/src/validator.rs index 98567cd1e6c..5fd18552f6b 100644 --- a/consensus/types/src/validator.rs +++ b/consensus/types/src/validator.rs @@ -102,6 +102,11 @@ impl Validator { .unwrap_or(false) } + /// Check if ``validator`` has an 0x02 prefixed "compounding" withdrawal credential. + pub fn has_compounding_withdrawal_credential(&self, spec: &ChainSpec) -> bool { + is_compounding_withdrawal_credential(self.withdrawal_credentials, spec) + } + /// Get the eth1 withdrawal address if this validator has one initialized. pub fn get_eth1_withdrawal_address(&self, spec: &ChainSpec) -> Option
{ self.has_eth1_withdrawal_credential(spec) @@ -153,6 +158,17 @@ impl Default for Validator { } } +pub fn is_compounding_withdrawal_credential( + withdrawal_credentials: Hash256, + spec: &ChainSpec, +) -> bool { + withdrawal_credentials + .as_bytes() + .first() + .map(|prefix_byte| *prefix_byte == spec.compounding_withdrawal_prefix_byte) + .unwrap_or(false) +} + #[cfg(test)] mod tests { use super::*; From bd9b179ab0066f32259176a80992d8ad64131c82 Mon Sep 17 00:00:00 2001 From: realbigsean Date: Thu, 25 Apr 2024 16:14:17 -0400 Subject: [PATCH 03/13] partial beacon state --- beacon_node/store/src/partial_beacon_state.rs | 45 ++++++++++++++++++- 1 file changed, 43 insertions(+), 2 deletions(-) diff --git a/beacon_node/store/src/partial_beacon_state.rs b/beacon_node/store/src/partial_beacon_state.rs index 25438fc7e0a..c106a0aec31 100644 --- a/beacon_node/store/src/partial_beacon_state.rs +++ b/beacon_node/store/src/partial_beacon_state.rs @@ -118,6 +118,29 @@ where #[ssz(skip_serializing, skip_deserializing)] #[superstruct(only(Capella, Deneb, Electra))] pub historical_summaries: Option>, + + // Electra + #[superstruct(only(Electra))] + pub deposit_receipts_start_index: u64, + #[superstruct(only(Electra))] + pub deposit_balance_to_consume: u64, + #[superstruct(only(Electra))] + pub exit_balance_to_consume: u64, + #[superstruct(only(Electra))] + pub earliest_exit_epoch: Epoch, + #[superstruct(only(Electra))] + pub consolidation_balance_to_consume: u64, + #[superstruct(only(Electra))] + pub earliest_consolidation_epoch: Epoch, + + // TODO(electra) should these be optional? + #[superstruct(only(Electra))] + pub pending_balance_deposits: List, + #[superstruct(only(Electra))] + pub pending_partial_withdrawals: + List, + #[superstruct(only(Electra))] + pub pending_consolidations: List, } /// Implement the conversion function from BeaconState -> PartialBeaconState. @@ -261,7 +284,16 @@ impl PartialBeaconState { inactivity_scores, latest_execution_payload_header, next_withdrawal_index, - next_withdrawal_validator_index + next_withdrawal_validator_index, + deposit_receipts_start_index, + deposit_balance_to_consume, + exit_balance_to_consume, + earliest_exit_epoch, + consolidation_balance_to_consume, + earliest_consolidation_epoch, + pending_balance_deposits, + pending_partial_withdrawals, + pending_consolidations ], [historical_summaries] ), @@ -525,7 +557,16 @@ impl TryInto> for PartialBeaconState { inactivity_scores, latest_execution_payload_header, next_withdrawal_index, - next_withdrawal_validator_index + next_withdrawal_validator_index, + deposit_receipts_start_index, + deposit_balance_to_consume, + exit_balance_to_consume, + earliest_exit_epoch, + consolidation_balance_to_consume, + earliest_consolidation_epoch, + pending_balance_deposits, + pending_partial_withdrawals, + pending_consolidations ], [historical_summaries] ), From 9ee134dcd8ef9f9d07f1da3c3913c74de144d4c8 Mon Sep 17 00:00:00 2001 From: realbigsean Date: Thu, 25 Apr 2024 16:15:49 -0400 Subject: [PATCH 04/13] safe arith in upgrade to electra --- consensus/state_processing/src/upgrade/electra.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/consensus/state_processing/src/upgrade/electra.rs b/consensus/state_processing/src/upgrade/electra.rs index 36af3d1f387..f988b7abd67 100644 --- a/consensus/state_processing/src/upgrade/electra.rs +++ b/consensus/state_processing/src/upgrade/electra.rs @@ -1,3 +1,4 @@ +use safe_arith::SafeArith; use std::mem; use types::{ BeaconState, BeaconStateElectra, BeaconStateError as Error, ChainSpec, EpochCache, EthSpec, @@ -19,7 +20,7 @@ pub fn upgrade_to_electra( .map(|v| v.exit_epoch) .max() .unwrap_or(epoch) - + 1; + .safe_add(1)?; let consolidation_balance_to_consume = pre_state.get_consolidation_churn_limit(spec)?; let earliest_consolidation_epoch = spec.compute_activation_exit_epoch(epoch)?; From c60b522865177fe7f53c6b3be4e2e12567b27c53 Mon Sep 17 00:00:00 2001 From: realbigsean Date: Thu, 25 Apr 2024 16:59:00 -0400 Subject: [PATCH 05/13] initialize balances cache in interop genesis state --- lcli/src/new_testnet.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/lcli/src/new_testnet.rs b/lcli/src/new_testnet.rs index edba4249966..de56d0f8127 100644 --- a/lcli/src/new_testnet.rs +++ b/lcli/src/new_testnet.rs @@ -292,6 +292,7 @@ fn initialize_state_with_validators( } process_activations(&mut state, spec).unwrap(); + state.build_total_active_balance_cache(spec).unwrap(); if spec .altair_fork_epoch From 605726cc12d1208afe49b12795979f82e518c05a Mon Sep 17 00:00:00 2001 From: realbigsean Date: Thu, 25 Apr 2024 17:14:12 -0400 Subject: [PATCH 06/13] Revert "initialize balances cache in interop genesis state" This reverts commit c60b522865177fe7f53c6b3be4e2e12567b27c53. --- lcli/src/new_testnet.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/lcli/src/new_testnet.rs b/lcli/src/new_testnet.rs index de56d0f8127..edba4249966 100644 --- a/lcli/src/new_testnet.rs +++ b/lcli/src/new_testnet.rs @@ -292,7 +292,6 @@ fn initialize_state_with_validators( } process_activations(&mut state, spec).unwrap(); - state.build_total_active_balance_cache(spec).unwrap(); if spec .altair_fork_epoch From 5abe624f441dbd24edc29cc7cff7597125d80593 Mon Sep 17 00:00:00 2001 From: realbigsean Date: Thu, 25 Apr 2024 17:14:45 -0400 Subject: [PATCH 07/13] always initialize balances cache if necessary in electra upgrade --- consensus/state_processing/src/upgrade/electra.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/consensus/state_processing/src/upgrade/electra.rs b/consensus/state_processing/src/upgrade/electra.rs index f988b7abd67..7fe243eee3f 100644 --- a/consensus/state_processing/src/upgrade/electra.rs +++ b/consensus/state_processing/src/upgrade/electra.rs @@ -22,6 +22,9 @@ pub fn upgrade_to_electra( .unwrap_or(epoch) .safe_add(1)?; + // The total active balance cache must be built before the consolidation churn limit + // is calculated. + pre_state.build_total_active_balance_cache(spec)?; let consolidation_balance_to_consume = pre_state.get_consolidation_churn_limit(spec)?; let earliest_consolidation_epoch = spec.compute_activation_exit_epoch(epoch)?; From d2de5f38a0d9050d5500a0eefd73ebf21e6d30a2 Mon Sep 17 00:00:00 2001 From: realbigsean Date: Thu, 25 Apr 2024 17:17:31 -0400 Subject: [PATCH 08/13] build cache earlier --- consensus/state_processing/src/upgrade/electra.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/consensus/state_processing/src/upgrade/electra.rs b/consensus/state_processing/src/upgrade/electra.rs index 7fe243eee3f..31995f3a526 100644 --- a/consensus/state_processing/src/upgrade/electra.rs +++ b/consensus/state_processing/src/upgrade/electra.rs @@ -12,6 +12,9 @@ pub fn upgrade_to_electra( ) -> Result<(), Error> { let epoch = pre_state.current_epoch(); + // The total active balance cache must be built before the consolidation churn limit + // is calculated. + pre_state.build_total_active_balance_cache(spec)?; let exit_balance_to_consume = pre_state.get_activation_exit_churn_limit(spec)?; let earliest_exit_epoch = pre_state .validators() @@ -22,9 +25,6 @@ pub fn upgrade_to_electra( .unwrap_or(epoch) .safe_add(1)?; - // The total active balance cache must be built before the consolidation churn limit - // is calculated. - pre_state.build_total_active_balance_cache(spec)?; let consolidation_balance_to_consume = pre_state.get_consolidation_churn_limit(spec)?; let earliest_consolidation_epoch = spec.compute_activation_exit_epoch(epoch)?; From cbbb8442a0bf2905690b149223febda0e35203ab Mon Sep 17 00:00:00 2001 From: realbigsean Date: Fri, 26 Apr 2024 09:13:55 -0400 Subject: [PATCH 09/13] fix block test --- consensus/types/src/beacon_block.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/consensus/types/src/beacon_block.rs b/consensus/types/src/beacon_block.rs index 14874f0204f..40e0738c410 100644 --- a/consensus/types/src/beacon_block.rs +++ b/consensus/types/src/beacon_block.rs @@ -1074,9 +1074,8 @@ mod tests { .expect("good electra block can be decoded"), good_block ); - // TODO(electra): once the Electra block is changed from Deneb, update this to match - // the other forks. - assert!(BeaconBlock::from_ssz_bytes(&bad_block.as_ssz_bytes(), &spec).is_ok()); + BeaconBlock::from_ssz_bytes(&bad_block.as_ssz_bytes(), &spec) + .expect_err("bad electra block cannot be decoded"); } } } From 736fcfc2adb3b78b347196e4ecf436489f5b9c9d Mon Sep 17 00:00:00 2001 From: realbigsean Date: Fri, 26 Apr 2024 10:06:39 -0400 Subject: [PATCH 10/13] per fork NUM_FIELDS_POW2 --- consensus/types/src/beacon_state.rs | 19 +++++++++++++------ consensus/types/src/beacon_state/tests.rs | 21 --------------------- 2 files changed, 13 insertions(+), 27 deletions(-) diff --git a/consensus/types/src/beacon_state.rs b/consensus/types/src/beacon_state.rs index 1504f1f6eee..cf8433447fc 100644 --- a/consensus/types/src/beacon_state.rs +++ b/consensus/types/src/beacon_state.rs @@ -2258,10 +2258,17 @@ impl BeaconState { /// The number of fields of the `BeaconState` rounded up to the nearest power of two. /// /// This is relevant to tree-hashing of the `BeaconState`. - /// - /// We assume this value is stable across forks. This assumption is checked in the - /// `check_num_fields_pow2` test. - pub const NUM_FIELDS_POW2: usize = BeaconStateMerge::::NUM_FIELDS.next_power_of_two(); + pub fn num_fields_pow2(&self) -> usize { + let fork_name = self.fork_name_unchecked(); + match fork_name { + ForkName::Base => BeaconStateBase::::NUM_FIELDS.next_power_of_two(), + ForkName::Altair => BeaconStateAltair::::NUM_FIELDS.next_power_of_two(), + ForkName::Merge => BeaconStateMerge::::NUM_FIELDS.next_power_of_two(), + ForkName::Capella => BeaconStateCapella::::NUM_FIELDS.next_power_of_two(), + ForkName::Deneb => BeaconStateDeneb::::NUM_FIELDS.next_power_of_two(), + ForkName::Electra => BeaconStateElectra::::NUM_FIELDS.next_power_of_two(), + } + } /// Specialised deserialisation method that uses the `ChainSpec` as context. #[allow(clippy::arithmetic_side_effects)] @@ -2322,7 +2329,7 @@ impl BeaconState { // in the `BeaconState`: // https://github.com/ethereum/consensus-specs/blob/dev/specs/altair/beacon-chain.md#beaconstate generalized_index - .checked_sub(Self::NUM_FIELDS_POW2) + .checked_sub(self.num_fields_pow2()) .ok_or(Error::IndexNotSupported(generalized_index))? } light_client_update::FINALIZED_ROOT_INDEX => { @@ -2332,7 +2339,7 @@ impl BeaconState { // Subtract off the internal nodes. Result should be 105/2 - 32 = 20 which matches // position of `finalized_checkpoint` in `BeaconState`. finalized_checkpoint_generalized_index - .checked_sub(Self::NUM_FIELDS_POW2) + .checked_sub(self.num_fields_pow2()) .ok_or(Error::IndexNotSupported(generalized_index))? } _ => return Err(Error::IndexNotSupported(generalized_index)), diff --git a/consensus/types/src/beacon_state/tests.rs b/consensus/types/src/beacon_state/tests.rs index 012c063afef..a061f4c7c40 100644 --- a/consensus/types/src/beacon_state/tests.rs +++ b/consensus/types/src/beacon_state/tests.rs @@ -403,24 +403,3 @@ fn decode_base_and_altair() { .expect_err("bad altair state cannot be decoded"); } } - -#[test] -fn check_num_fields_pow2() { - use metastruct::NumFields; - pub type E = MainnetEthSpec; - - for fork_name in ForkName::list_all() { - let num_fields = match fork_name { - ForkName::Base => BeaconStateBase::::NUM_FIELDS, - ForkName::Altair => BeaconStateAltair::::NUM_FIELDS, - ForkName::Merge => BeaconStateMerge::::NUM_FIELDS, - ForkName::Capella => BeaconStateCapella::::NUM_FIELDS, - ForkName::Deneb => BeaconStateDeneb::::NUM_FIELDS, - ForkName::Electra => BeaconStateElectra::::NUM_FIELDS, - }; - assert_eq!( - num_fields.next_power_of_two(), - BeaconState::::NUM_FIELDS_POW2 - ); - } -} From 9e96cc55bccdc59b94955cbf7263b6c10d7f5c6b Mon Sep 17 00:00:00 2001 From: realbigsean Date: Fri, 26 Apr 2024 10:13:36 -0400 Subject: [PATCH 11/13] fix lints --- consensus/types/src/beacon_state/tests.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/consensus/types/src/beacon_state/tests.rs b/consensus/types/src/beacon_state/tests.rs index a444692dbcf..38a76e44c50 100644 --- a/consensus/types/src/beacon_state/tests.rs +++ b/consensus/types/src/beacon_state/tests.rs @@ -1,10 +1,10 @@ #![cfg(test)] -use crate::{test_utils::*, ForkName}; +use crate::test_utils::*; use beacon_chain::test_utils::{BeaconChainHarness, EphemeralHarnessType}; use beacon_chain::types::{ - test_utils::TestRandom, BeaconState, BeaconStateAltair, BeaconStateBase, BeaconStateBellatrix, - BeaconStateCapella, BeaconStateDeneb, BeaconStateElectra, BeaconStateError, ChainSpec, Domain, - Epoch, EthSpec, Hash256, Keypair, MainnetEthSpec, MinimalEthSpec, RelativeEpoch, Slot, Vector, + test_utils::TestRandom, BeaconState, BeaconStateAltair, BeaconStateBase, BeaconStateError, + ChainSpec, Domain, Epoch, EthSpec, Hash256, Keypair, MainnetEthSpec, MinimalEthSpec, + RelativeEpoch, Slot, Vector, }; use ssz::Encode; use std::ops::Mul; From 687c325528dd6b37b77d94ace66476d20ae26947 Mon Sep 17 00:00:00 2001 From: realbigsean Date: Fri, 26 Apr 2024 15:33:47 -0400 Subject: [PATCH 12/13] get fields based on post state, as is spec'd --- consensus/state_processing/src/upgrade/electra.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/consensus/state_processing/src/upgrade/electra.rs b/consensus/state_processing/src/upgrade/electra.rs index 31995f3a526..2f0f6b476b1 100644 --- a/consensus/state_processing/src/upgrade/electra.rs +++ b/consensus/state_processing/src/upgrade/electra.rs @@ -15,7 +15,6 @@ pub fn upgrade_to_electra( // The total active balance cache must be built before the consolidation churn limit // is calculated. pre_state.build_total_active_balance_cache(spec)?; - let exit_balance_to_consume = pre_state.get_activation_exit_churn_limit(spec)?; let earliest_exit_epoch = pre_state .validators() .iter() @@ -25,7 +24,6 @@ pub fn upgrade_to_electra( .unwrap_or(epoch) .safe_add(1)?; - let consolidation_balance_to_consume = pre_state.get_consolidation_churn_limit(spec)?; let earliest_consolidation_epoch = spec.compute_activation_exit_epoch(epoch)?; let pre = pre_state.as_deneb_mut()?; @@ -82,9 +80,9 @@ pub fn upgrade_to_electra( // Electra deposit_receipts_start_index: spec.unset_deposit_receipts_start_index, deposit_balance_to_consume: 0, - exit_balance_to_consume, + exit_balance_to_consume: 0, earliest_exit_epoch, - consolidation_balance_to_consume, + consolidation_balance_to_consume: 0, earliest_consolidation_epoch, pending_balance_deposits: Default::default(), pending_partial_withdrawals: Default::default(), @@ -98,6 +96,8 @@ pub fn upgrade_to_electra( slashings_cache: mem::take(&mut pre.slashings_cache), epoch_cache: EpochCache::default(), }); + *post.exit_balance_to_consume_mut()? = post.get_activation_exit_churn_limit(spec)?; + *post.consolidation_balance_to_consume_mut()? = post.get_consolidation_churn_limit(spec)?; // Add validators that are not yet active to pending balance deposits let validators = post.validators().clone(); From 026c58b7fd2169e2918ec330ae1403a2d3f10e40 Mon Sep 17 00:00:00 2001 From: realbigsean Date: Fri, 26 Apr 2024 15:35:32 -0400 Subject: [PATCH 13/13] fix type and move cache build --- beacon_node/execution_layer/src/lib.rs | 2 +- consensus/state_processing/src/upgrade/electra.rs | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/beacon_node/execution_layer/src/lib.rs b/beacon_node/execution_layer/src/lib.rs index 5d2fa420d5c..d441596edda 100644 --- a/beacon_node/execution_layer/src/lib.rs +++ b/beacon_node/execution_layer/src/lib.rs @@ -2003,7 +2003,7 @@ impl ExecutionLayer { withdrawals, blob_gas_used: electra_block.blob_gas_used, excess_blob_gas: electra_block.excess_blob_gas, - // TODO(elecrta) + // TODO(electra) // deposit_receipts: electra_block.deposit_receipts, // withdrawal_requests: electra_block.withdrawal_requests, deposit_receipts: <_>::default(), diff --git a/consensus/state_processing/src/upgrade/electra.rs b/consensus/state_processing/src/upgrade/electra.rs index 2f0f6b476b1..1e60bf488db 100644 --- a/consensus/state_processing/src/upgrade/electra.rs +++ b/consensus/state_processing/src/upgrade/electra.rs @@ -12,9 +12,6 @@ pub fn upgrade_to_electra( ) -> Result<(), Error> { let epoch = pre_state.current_epoch(); - // The total active balance cache must be built before the consolidation churn limit - // is calculated. - pre_state.build_total_active_balance_cache(spec)?; let earliest_exit_epoch = pre_state .validators() .iter() @@ -24,6 +21,9 @@ pub fn upgrade_to_electra( .unwrap_or(epoch) .safe_add(1)?; + // The total active balance cache must be built before the consolidation churn limit + // is calculated. + pre_state.build_total_active_balance_cache(spec)?; let earliest_consolidation_epoch = spec.compute_activation_exit_epoch(epoch)?; let pre = pre_state.as_deneb_mut()?;