Fixed a ton of state_processing stuff (#3642)

FIXME's:
 * consensus/fork_choice/src/fork_choice.rs
 * consensus/state_processing/src/per_epoch_processing/capella.rs
 * consensus/types/src/execution_payload_header.rs
 
TODO's:
 * consensus/state_processing/src/per_epoch_processing/capella/partial_withdrawals.rs
 * consensus/state_processing/src/per_epoch_processing/capella/full_withdrawals.rs
This commit is contained in:
ethDreamer 2022-10-14 17:35:10 -05:00 committed by GitHub
parent c1c5dc0a64
commit 221c433d62
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 538 additions and 55 deletions

View File

@ -428,7 +428,7 @@ impl<E: EthSpec, Hot: ItemStore<E>, Cold: ItemStore<E>> HotColdDB<E, Hot, Cold>
}
/// Fetch a block from the store, ignoring which fork variant it *should* be for.
pub fn get_block_any_variant<Payload: ExecPayload<E>>(
pub fn get_block_any_variant<Payload: AbstractExecPayload<E>>(
&self,
block_root: &Hash256,
) -> Result<Option<SignedBeaconBlock<E, Payload>>, Error> {
@ -439,7 +439,7 @@ impl<E: EthSpec, Hot: ItemStore<E>, Cold: ItemStore<E>> HotColdDB<E, Hot, Cold>
///
/// This is useful for e.g. ignoring the slot-indicated fork to forcefully load a block as if it
/// were for a different fork.
pub fn get_block_with<Payload: ExecPayload<E>>(
pub fn get_block_with<Payload: AbstractExecPayload<E>>(
&self,
block_root: &Hash256,
decoder: impl FnOnce(&[u8]) -> Result<SignedBeaconBlock<E, Payload>, ssz::DecodeError>,

View File

@ -1,7 +1,35 @@
use crate::{DBColumn, Error, StoreItem};
use ssz::{Decode, Encode};
use types::{EthSpec, ExecutionPayload};
use types::{
EthSpec, ExecutionPayload, ExecutionPayloadCapella, ExecutionPayloadEip4844,
ExecutionPayloadMerge,
};
macro_rules! impl_store_item {
($ty_name:ident) => {
impl<E: EthSpec> StoreItem for $ty_name<E> {
fn db_column() -> DBColumn {
DBColumn::ExecPayload
}
fn as_store_bytes(&self) -> Vec<u8> {
self.as_ssz_bytes()
}
fn from_store_bytes(bytes: &[u8]) -> Result<Self, Error> {
Ok(Self::from_ssz_bytes(bytes)?)
}
}
};
}
impl_store_item!(ExecutionPayloadMerge);
impl_store_item!(ExecutionPayloadCapella);
impl_store_item!(ExecutionPayloadEip4844);
/// This fork-agnostic implementation should be only used for writing.
///
/// It is very inefficient at reading, and decoding the desired fork-specific variant is recommended
/// instead.
impl<E: EthSpec> StoreItem for ExecutionPayload<E> {
fn db_column() -> DBColumn {
DBColumn::ExecPayload
@ -12,6 +40,13 @@ impl<E: EthSpec> StoreItem for ExecutionPayload<E> {
}
fn from_store_bytes(bytes: &[u8]) -> Result<Self, Error> {
Ok(Self::from_ssz_bytes(bytes)?)
ExecutionPayloadEip4844::from_ssz_bytes(bytes)
.map(Self::Eip4844)
.or_else(|_| {
ExecutionPayloadCapella::from_ssz_bytes(bytes)
.map(Self::Capella)
.or_else(|_| ExecutionPayloadMerge::from_ssz_bytes(bytes).map(Self::Merge))
})
.map_err(Into::into)
}
}

View File

@ -14,7 +14,7 @@ use types::*;
///
/// Utilises lazy-loading from separate storage for its vector fields.
#[superstruct(
variants(Base, Altair, Merge, Eip4844),
variants(Base, Altair, Merge, Capella, Eip4844),
variant_attributes(derive(Debug, PartialEq, Clone, Encode, Decode))
)]
#[derive(Debug, PartialEq, Clone, Encode)]
@ -66,9 +66,9 @@ where
pub current_epoch_attestations: VariableList<PendingAttestation<T>, T::MaxPendingAttestations>,
// Participation (Altair and later)
#[superstruct(only(Altair, Merge, Eip4844))]
#[superstruct(only(Altair, Merge, Capella, Eip4844))]
pub previous_epoch_participation: VariableList<ParticipationFlags, T::ValidatorRegistryLimit>,
#[superstruct(only(Altair, Merge, Eip4844))]
#[superstruct(only(Altair, Merge, Capella, Eip4844))]
pub current_epoch_participation: VariableList<ParticipationFlags, T::ValidatorRegistryLimit>,
// Finality
@ -78,18 +78,39 @@ where
pub finalized_checkpoint: Checkpoint,
// Inactivity
#[superstruct(only(Altair, Merge, Eip4844))]
#[superstruct(only(Altair, Merge, Capella, Eip4844))]
pub inactivity_scores: VariableList<u64, T::ValidatorRegistryLimit>,
// Light-client sync committees
#[superstruct(only(Altair, Merge, Eip4844))]
#[superstruct(only(Altair, Merge, Capella, Eip4844))]
pub current_sync_committee: Arc<SyncCommittee<T>>,
#[superstruct(only(Altair, Merge, Eip4844))]
#[superstruct(only(Altair, Merge, Capella, Eip4844))]
pub next_sync_committee: Arc<SyncCommittee<T>>,
// Execution
#[superstruct(only(Merge, Eip4844))]
pub latest_execution_payload_header: ExecutionPayloadHeader<T>,
#[superstruct(
only(Merge),
partial_getter(rename = "latest_execution_payload_header_merge")
)]
pub latest_execution_payload_header: ExecutionPayloadHeaderMerge<T>,
#[superstruct(
only(Capella),
partial_getter(rename = "latest_execution_payload_header_capella")
)]
pub latest_execution_payload_header: ExecutionPayloadHeaderCapella<T>,
#[superstruct(
only(Eip4844),
partial_getter(rename = "latest_execution_payload_header_eip4844")
)]
pub latest_execution_payload_header: ExecutionPayloadHeaderEip4844<T>,
// Withdrawals
#[superstruct(only(Capella, Eip4844))]
pub withdrawal_queue: VariableList<Withdrawal, T::WithdrawalQueueLimit>,
#[superstruct(only(Capella, Eip4844))]
pub next_withdrawal_index: u64,
#[superstruct(only(Capella, Eip4844))]
pub next_partial_withdrawal_validator_index: u64,
}
/// Implement the conversion function from BeaconState -> PartialBeaconState.
@ -178,6 +199,23 @@ impl<T: EthSpec> PartialBeaconState<T> {
latest_execution_payload_header
]
),
BeaconState::Capella(s) => impl_from_state_forgetful!(
s,
outer,
Capella,
PartialBeaconStateCapella,
[
previous_epoch_participation,
current_epoch_participation,
current_sync_committee,
next_sync_committee,
inactivity_scores,
latest_execution_payload_header,
withdrawal_queue,
next_withdrawal_index,
next_partial_withdrawal_validator_index
]
),
BeaconState::Eip4844(s) => impl_from_state_forgetful!(
s,
outer,
@ -189,7 +227,10 @@ impl<T: EthSpec> PartialBeaconState<T> {
current_sync_committee,
next_sync_committee,
inactivity_scores,
latest_execution_payload_header
latest_execution_payload_header,
withdrawal_queue,
next_withdrawal_index,
next_partial_withdrawal_validator_index
]
),
}
@ -379,6 +420,22 @@ impl<E: EthSpec> TryInto<BeaconState<E>> for PartialBeaconState<E> {
latest_execution_payload_header
]
),
PartialBeaconState::Capella(inner) => impl_try_into_beacon_state!(
inner,
Capella,
BeaconStateCapella,
[
previous_epoch_participation,
current_epoch_participation,
current_sync_committee,
next_sync_committee,
inactivity_scores,
latest_execution_payload_header,
withdrawal_queue,
next_withdrawal_index,
next_partial_withdrawal_validator_index
]
),
PartialBeaconState::Eip4844(inner) => impl_try_into_beacon_state!(
inner,
Eip4844,
@ -389,7 +446,10 @@ impl<E: EthSpec> TryInto<BeaconState<E>> for PartialBeaconState<E> {
current_sync_committee,
next_sync_committee,
inactivity_scores,
latest_execution_payload_header
latest_execution_payload_header,
withdrawal_queue,
next_withdrawal_index,
next_partial_withdrawal_validator_index
]
),
};

View File

@ -12,9 +12,10 @@ use std::collections::BTreeSet;
use std::marker::PhantomData;
use std::time::Duration;
use types::{
consts::merge::INTERVALS_PER_SLOT, AttestationShufflingId, AttesterSlashing, BeaconBlockRef,
BeaconState, BeaconStateError, ChainSpec, Checkpoint, Epoch, EthSpec, ExecPayload,
ExecutionBlockHash, Hash256, IndexedAttestation, RelativeEpoch, SignedBeaconBlock, Slot,
consts::merge::INTERVALS_PER_SLOT, AbstractExecPayload, AttestationShufflingId,
AttesterSlashing, BeaconBlockRef, BeaconState, BeaconStateError, ChainSpec, Checkpoint, Epoch,
EthSpec, ExecPayload, ExecutionBlockHash, Hash256, IndexedAttestation, RelativeEpoch,
SignedBeaconBlock, Slot,
};
#[derive(Debug)]
@ -665,7 +666,7 @@ where
/// The supplied block **must** pass the `state_transition` function as it will not be run
/// here.
#[allow(clippy::too_many_arguments)]
pub fn on_block<Payload: ExecPayload<E>>(
pub fn on_block<Payload: AbstractExecPayload<E>>(
&mut self,
system_time_current_slot: Slot,
block: BeaconBlockRef<E, Payload>,
@ -777,7 +778,10 @@ where
(parent_justified, parent_finalized)
} else {
let justification_and_finalization_state = match block {
// FIXME: verify this is correct for Capella/Eip4844 because
// epoch processing changes in Capella..
BeaconBlockRef::Eip4844(_)
| BeaconBlockRef::Capella(_)
| BeaconBlockRef::Merge(_)
| BeaconBlockRef::Altair(_) => {
let participation_cache =

View File

@ -1,6 +1,6 @@
use std::collections::BTreeSet;
use std::fmt::Debug;
use types::{BeaconBlockRef, BeaconState, Checkpoint, EthSpec, ExecPayload, Hash256, Slot};
use types::{AbstractExecPayload, BeaconBlockRef, BeaconState, Checkpoint, EthSpec, Hash256, Slot};
/// Approximates the `Store` in "Ethereum 2.0 Phase 0 -- Beacon Chain Fork Choice":
///
@ -33,7 +33,7 @@ pub trait ForkChoiceStore<T: EthSpec>: Sized {
/// Called whenever `ForkChoice::on_block` has verified a block, but not yet added it to fork
/// choice. Allows the implementer to performing caching or other housekeeping duties.
fn on_verified_block<Payload: ExecPayload<T>>(
fn on_verified_block<Payload: AbstractExecPayload<T>>(
&mut self,
block: BeaconBlockRef<T, Payload>,
block_root: Hash256,

View File

@ -45,11 +45,12 @@ pub fn slash_validator<T: EthSpec>(
validator_effective_balance.safe_div(spec.whistleblower_reward_quotient)?;
let proposer_reward = match state {
BeaconState::Base(_) => whistleblower_reward.safe_div(spec.proposer_reward_quotient)?,
BeaconState::Altair(_) | BeaconState::Merge(_) | BeaconState::Eip4844(_) => {
whistleblower_reward
.safe_mul(PROPOSER_WEIGHT)?
.safe_div(WEIGHT_DENOMINATOR)?
}
BeaconState::Altair(_)
| BeaconState::Merge(_)
| BeaconState::Capella(_)
| BeaconState::Eip4844(_) => whistleblower_reward
.safe_mul(PROPOSER_WEIGHT)?
.safe_div(WEIGHT_DENOMINATOR)?,
};
// Ensure the whistleblower index is in the validator registry.

View File

@ -2,7 +2,9 @@ use super::per_block_processing::{
errors::BlockProcessingError, process_operations::process_deposit,
};
use crate::common::DepositDataTree;
use crate::upgrade::{upgrade_to_altair, upgrade_to_bellatrix};
use crate::upgrade::{
upgrade_to_altair, upgrade_to_bellatrix, upgrade_to_capella, upgrade_to_eip4844,
};
use safe_arith::{ArithError, SafeArith};
use tree_hash::TreeHash;
use types::DEPOSIT_TREE_DEPTH;
@ -61,6 +63,7 @@ pub fn initialize_beacon_state_from_eth1<T: EthSpec>(
.bellatrix_fork_epoch
.map_or(false, |fork_epoch| fork_epoch == T::genesis_epoch())
{
// this will set state.latest_execution_payload_header = ExecutionPayloadHeaderMerge::default()
upgrade_to_bellatrix(&mut state, spec)?;
// Remove intermediate Altair fork from `state.fork`.
@ -68,8 +71,43 @@ pub fn initialize_beacon_state_from_eth1<T: EthSpec>(
// Override latest execution payload header.
// See https://github.com/ethereum/consensus-specs/blob/v1.1.0/specs/bellatrix/beacon-chain.md#testing
*state.latest_execution_payload_header_mut()? =
execution_payload_header.unwrap_or_default();
if let Some(ExecutionPayloadHeader::Merge(ref header)) = execution_payload_header {
*state.latest_execution_payload_header_merge_mut()? = header.clone();
}
}
// Upgrade to capella if configured from genesis
if spec
.capella_fork_epoch
.map_or(false, |fork_epoch| fork_epoch == T::genesis_epoch())
{
upgrade_to_capella(&mut state, spec)?;
// Remove intermediate Bellatrix fork from `state.fork`.
state.fork_mut().previous_version = spec.capella_fork_version;
// Override latest execution payload header.
// See https://github.com/ethereum/consensus-specs/blob/dev/specs/capella/beacon-chain.md#testing
if let Some(ExecutionPayloadHeader::Capella(ref header)) = execution_payload_header {
*state.latest_execution_payload_header_capella_mut()? = header.clone();
}
}
// Upgrade to eip4844 if configured from genesis
if spec
.eip4844_fork_epoch
.map_or(false, |fork_epoch| fork_epoch == T::genesis_epoch())
{
upgrade_to_eip4844(&mut state, spec)?;
// Remove intermediate Capella fork from `state.fork`.
state.fork_mut().previous_version = spec.eip4844_fork_version;
// Override latest execution payload header.
// See https://github.com/ethereum/consensus-specs/blob/dev/specs/eip4844/beacon-chain.md#testing
if let Some(ExecutionPayloadHeader::Eip4844(header)) = execution_payload_header {
*state.latest_execution_payload_header_eip4844_mut()? = header;
}
}
// Now that we have our validators, initialize the caches (including the committees)

View File

@ -154,7 +154,7 @@ pub fn per_block_processing<T: EthSpec, Payload: AbstractExecPayload<T>>(
// previous block.
if is_execution_enabled(state, block.body()) {
let payload = block.body().execution_payload()?;
process_execution_payload(state, payload, spec)?;
process_execution_payload::<T, Payload>(state, payload, spec)?;
}
process_randao(state, block, verify_randao, spec)?;
@ -319,16 +319,16 @@ pub fn get_new_eth1_data<T: EthSpec>(
/// Contains a partial set of checks from the `process_execution_payload` function:
///
/// https://github.com/ethereum/consensus-specs/blob/v1.1.5/specs/merge/beacon-chain.md#process_execution_payload
pub fn partially_verify_execution_payload<T: EthSpec, Payload: ExecPayload<T>>(
pub fn partially_verify_execution_payload<'payload, T: EthSpec, Payload: AbstractExecPayload<T>>(
state: &BeaconState<T>,
payload: &Payload,
payload: Payload::Ref<'payload>,
spec: &ChainSpec,
) -> Result<(), BlockProcessingError> {
if is_merge_transition_complete(state) {
block_verify!(
payload.parent_hash() == state.latest_execution_payload_header()?.block_hash,
payload.parent_hash() == *state.latest_execution_payload_header()?.block_hash(),
BlockProcessingError::ExecutionHashChainIncontiguous {
expected: state.latest_execution_payload_header()?.block_hash,
expected: *state.latest_execution_payload_header()?.block_hash(),
found: payload.parent_hash(),
}
);
@ -360,14 +360,33 @@ pub fn partially_verify_execution_payload<T: EthSpec, Payload: ExecPayload<T>>(
/// Partially equivalent to the `process_execution_payload` function:
///
/// https://github.com/ethereum/consensus-specs/blob/v1.1.5/specs/merge/beacon-chain.md#process_execution_payload
pub fn process_execution_payload<T: EthSpec, Payload: ExecPayload<T>>(
pub fn process_execution_payload<'payload, T: EthSpec, Payload: AbstractExecPayload<T>>(
state: &mut BeaconState<T>,
payload: &Payload,
payload: Payload::Ref<'payload>,
spec: &ChainSpec,
) -> Result<(), BlockProcessingError> {
partially_verify_execution_payload(state, payload, spec)?;
partially_verify_execution_payload::<T, Payload>(state, payload, spec)?;
*state.latest_execution_payload_header_mut()? = payload.to_execution_payload_header();
match state.latest_execution_payload_header_mut()? {
ExecutionPayloadHeaderRefMut::Merge(header_mut) => {
match payload.to_execution_payload_header() {
ExecutionPayloadHeader::Merge(header) => *header_mut = header,
_ => return Err(BlockProcessingError::IncorrectStateType),
}
}
ExecutionPayloadHeaderRefMut::Capella(header_mut) => {
match payload.to_execution_payload_header() {
ExecutionPayloadHeader::Capella(header) => *header_mut = header,
_ => return Err(BlockProcessingError::IncorrectStateType),
}
}
ExecutionPayloadHeaderRefMut::Eip4844(header_mut) => {
match payload.to_execution_payload_header() {
ExecutionPayloadHeader::Eip4844(header) => *header_mut = header,
_ => return Err(BlockProcessingError::IncorrectStateType),
}
}
}
Ok(())
}
@ -380,7 +399,7 @@ pub fn process_execution_payload<T: EthSpec, Payload: ExecPayload<T>>(
pub fn is_merge_transition_complete<T: EthSpec>(state: &BeaconState<T>) -> bool {
state
.latest_execution_payload_header()
.map(|header| *header != <ExecutionPayloadHeader<T>>::default())
.map(|header| !header.is_default())
.unwrap_or(false)
}
/// https://github.com/ethereum/consensus-specs/blob/dev/specs/bellatrix/beacon-chain.md#is_merge_transition_block

View File

@ -232,6 +232,7 @@ pub fn process_attestations<'a, T: EthSpec, Payload: AbstractExecPayload<T>>(
}
BeaconBlockBodyRef::Altair(_)
| BeaconBlockBodyRef::Merge(_)
| BeaconBlockBodyRef::Capella(_)
| BeaconBlockBodyRef::Eip4844(_) => {
altair::process_attestations(
state,

View File

@ -8,7 +8,7 @@ use std::borrow::Cow;
use tree_hash::TreeHash;
use types::{
AbstractExecPayload, AggregateSignature, AttesterSlashing, BeaconBlockRef, BeaconState,
BeaconStateError, ChainSpec, DepositData, Domain, Epoch, EthSpec, ExecPayload, Fork, Hash256,
BeaconStateError, ChainSpec, DepositData, Domain, Epoch, EthSpec, Fork, Hash256,
InconsistentFork, IndexedAttestation, ProposerSlashing, PublicKey, PublicKeyBytes, Signature,
SignedAggregateAndProof, SignedBeaconBlock, SignedBeaconBlockHeader,
SignedContributionAndProof, SignedRoot, SignedVoluntaryExit, SigningData, Slot, SyncAggregate,

View File

@ -11,6 +11,7 @@ pub use weigh_justification_and_finalization::weigh_justification_and_finalizati
pub mod altair;
pub mod base;
pub mod capella;
pub mod effective_balance_updates;
pub mod epoch_processing_summary;
pub mod errors;
@ -37,9 +38,8 @@ pub fn process_epoch<T: EthSpec>(
match state {
BeaconState::Base(_) => base::process_epoch(state, spec),
BeaconState::Altair(_) | BeaconState::Merge(_) | BeaconState::Eip4844(_) => {
altair::process_epoch(state, spec)
}
BeaconState::Altair(_) | BeaconState::Merge(_) => altair::process_epoch(state, spec),
BeaconState::Capella(_) | BeaconState::Eip4844(_) => capella::process_epoch(state, spec),
}
}

View File

@ -0,0 +1,81 @@
use super::{process_registry_updates, process_slashings, EpochProcessingSummary, Error};
use crate::per_epoch_processing::{
altair,
effective_balance_updates::process_effective_balance_updates,
historical_roots_update::process_historical_roots_update,
resets::{process_eth1_data_reset, process_randao_mixes_reset, process_slashings_reset},
};
pub use full_withdrawals::process_full_withdrawals;
pub use partial_withdrawals::process_partial_withdrawals;
use types::{BeaconState, ChainSpec, EthSpec, RelativeEpoch};
pub mod full_withdrawals;
pub mod partial_withdrawals;
pub fn process_epoch<T: EthSpec>(
state: &mut BeaconState<T>,
spec: &ChainSpec,
) -> Result<EpochProcessingSummary<T>, Error> {
// Ensure the committee caches are built.
state.build_committee_cache(RelativeEpoch::Previous, spec)?;
state.build_committee_cache(RelativeEpoch::Current, spec)?;
state.build_committee_cache(RelativeEpoch::Next, spec)?;
// Pre-compute participating indices and total balances.
let participation_cache = altair::ParticipationCache::new(state, spec)?;
let sync_committee = state.current_sync_committee()?.clone();
// Justification and finalization.
let justification_and_finalization_state =
altair::process_justification_and_finalization(state, &participation_cache)?;
justification_and_finalization_state.apply_changes_to_state(state);
altair::process_inactivity_updates(state, &participation_cache, spec)?;
// Rewards and Penalties.
altair::process_rewards_and_penalties(state, &participation_cache, spec)?;
// Registry Updates.
process_registry_updates(state, spec)?;
// Slashings.
process_slashings(
state,
participation_cache.current_epoch_total_active_balance(),
spec,
)?;
// Reset eth1 data votes.
process_eth1_data_reset(state)?;
// Update effective balances with hysteresis (lag).
process_effective_balance_updates(state, spec)?;
// Reset slashings
process_slashings_reset(state)?;
// Set randao mix
process_randao_mixes_reset(state)?;
// Set historical root accumulator
process_historical_roots_update(state)?;
// Rotate current/previous epoch participation
altair::process_participation_flag_updates(state)?;
altair::process_sync_committee_updates(state, spec)?;
// Withdrawals
process_full_withdrawals(state)?;
process_partial_withdrawals(state)?;
// Rotate the epoch caches to suit the epoch transition.
state.advance_caches(spec)?;
// FIXME: do we need a Capella variant for this?
Ok(EpochProcessingSummary::Altair {
participation_cache,
sync_committee,
})
}

View File

@ -0,0 +1,10 @@
use crate::EpochProcessingError;
use types::beacon_state::BeaconState;
use types::eth_spec::EthSpec;
pub fn process_full_withdrawals<T: EthSpec>(
state: &mut BeaconState<T>,
) -> Result<(), EpochProcessingError> {
todo!("implement this");
Ok(())
}

View File

@ -0,0 +1,10 @@
use crate::EpochProcessingError;
use types::beacon_state::BeaconState;
use types::eth_spec::EthSpec;
pub fn process_partial_withdrawals<T: EthSpec>(
state: &mut BeaconState<T>,
) -> Result<(), EpochProcessingError> {
todo!("implement this");
Ok(())
}

View File

@ -1,5 +1,9 @@
pub mod altair;
pub mod capella;
pub mod eip4844;
pub mod merge;
pub use altair::upgrade_to_altair;
pub use capella::upgrade_to_capella;
pub use eip4844::upgrade_to_eip4844;
pub use merge::upgrade_to_bellatrix;

View File

@ -0,0 +1,74 @@
use ssz_types::VariableList;
use std::mem;
use types::{BeaconState, BeaconStateCapella, BeaconStateError as Error, ChainSpec, EthSpec, Fork};
/// Transform a `Merge` state into an `Capella` state.
pub fn upgrade_to_capella<E: EthSpec>(
pre_state: &mut BeaconState<E>,
spec: &ChainSpec,
) -> Result<(), Error> {
let epoch = pre_state.current_epoch();
let pre = pre_state.as_merge_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::Capella(BeaconStateCapella {
// 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.capella_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: mem::take(&mut pre.previous_epoch_participation),
current_epoch_participation: mem::take(&mut pre.current_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: mem::take(&mut pre.inactivity_scores),
// Sync committees
current_sync_committee: pre.current_sync_committee.clone(),
next_sync_committee: pre.next_sync_committee.clone(),
// Execution
latest_execution_payload_header: pre.latest_execution_payload_header.upgrade_to_capella(),
// Withdrawals
withdrawal_queue: VariableList::empty(),
next_withdrawal_index: 0,
next_partial_withdrawal_validator_index: 0,
// Caches
total_active_balance: pre.total_active_balance,
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),
});
*pre_state = post;
Ok(())
}

View File

@ -0,0 +1,73 @@
use std::mem;
use types::{BeaconState, BeaconStateEip4844, BeaconStateError as Error, ChainSpec, EthSpec, Fork};
/// Transform a `Capella` state into an `Eip4844` state.
pub fn upgrade_to_eip4844<E: EthSpec>(
pre_state: &mut BeaconState<E>,
spec: &ChainSpec,
) -> Result<(), Error> {
let epoch = pre_state.current_epoch();
let pre = pre_state.as_capella_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::Eip4844(BeaconStateEip4844 {
// 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.eip4844_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: mem::take(&mut pre.previous_epoch_participation),
current_epoch_participation: mem::take(&mut pre.current_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: mem::take(&mut pre.inactivity_scores),
// Sync committees
current_sync_committee: pre.current_sync_committee.clone(),
next_sync_committee: pre.next_sync_committee.clone(),
// Execution
latest_execution_payload_header: pre.latest_execution_payload_header.upgrade_to_eip4844(),
// Withdrawals
withdrawal_queue: mem::take(&mut pre.withdrawal_queue),
next_withdrawal_index: pre.next_withdrawal_index,
next_partial_withdrawal_validator_index: pre.next_partial_withdrawal_validator_index,
// Caches
total_active_balance: pre.total_active_balance,
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),
});
*pre_state = post;
Ok(())
}

View File

@ -1,7 +1,7 @@
use std::mem;
use types::{
BeaconState, BeaconStateError as Error, BeaconStateMerge, ChainSpec, EthSpec,
ExecutionPayloadHeader, Fork,
ExecutionPayloadHeaderMerge, Fork,
};
/// Transform a `Altair` state into an `Merge` state.
@ -57,7 +57,7 @@ pub fn upgrade_to_bellatrix<E: EthSpec>(
current_sync_committee: pre.current_sync_committee.clone(),
next_sync_committee: pre.next_sync_committee.clone(),
// Execution
latest_execution_payload_header: <ExecutionPayloadHeader<E>>::default(),
latest_execution_payload_header: <ExecutionPayloadHeaderMerge<E>>::default(),
// Caches
total_active_balance: pre.total_active_balance,
committee_caches: mem::take(&mut pre.committee_caches),

View File

@ -718,6 +718,23 @@ impl<T: EthSpec> BeaconState<T> {
}
}
pub fn latest_execution_payload_header_mut(
&mut self,
) -> Result<ExecutionPayloadHeaderRefMut<T>, Error> {
match self {
BeaconState::Base(_) | BeaconState::Altair(_) => Err(Error::IncorrectStateVariant),
BeaconState::Merge(state) => Ok(ExecutionPayloadHeaderRefMut::Merge(
&mut state.latest_execution_payload_header,
)),
BeaconState::Capella(state) => Ok(ExecutionPayloadHeaderRefMut::Capella(
&mut state.latest_execution_payload_header,
)),
BeaconState::Eip4844(state) => Ok(ExecutionPayloadHeaderRefMut::Eip4844(
&mut state.latest_execution_payload_header,
)),
}
}
/// Return `true` if the validator who produced `slot_signature` is eligible to aggregate.
///
/// Spec v0.12.1

View File

@ -65,6 +65,73 @@ pub struct ExecutionPayloadHeader<T: EthSpec> {
pub withdrawals_root: Hash256,
}
impl<'a, T: EthSpec> ExecutionPayloadHeaderRef<'a, T> {
// FIXME: maybe this could be a derived trait..
pub fn is_default(self) -> bool {
match self {
ExecutionPayloadHeaderRef::Merge(header) => {
*header == ExecutionPayloadHeaderMerge::default()
}
ExecutionPayloadHeaderRef::Capella(header) => {
*header == ExecutionPayloadHeaderCapella::default()
}
ExecutionPayloadHeaderRef::Eip4844(header) => {
*header == ExecutionPayloadHeaderEip4844::default()
}
}
}
}
impl<T: EthSpec> ExecutionPayloadHeaderMerge<T> {
pub fn upgrade_to_capella(&self) -> ExecutionPayloadHeaderCapella<T> {
// TODO: if this is correct we should calculate and hardcode this..
let empty_withdrawals_root =
VariableList::<Withdrawal, T::MaxWithdrawalsPerPayload>::empty().tree_hash_root();
ExecutionPayloadHeaderCapella {
parent_hash: self.parent_hash,
fee_recipient: self.fee_recipient,
state_root: self.state_root,
receipts_root: self.receipts_root,
logs_bloom: self.logs_bloom.clone(),
prev_randao: self.prev_randao,
block_number: self.block_number,
gas_limit: self.gas_limit,
gas_used: self.gas_used,
timestamp: self.timestamp,
extra_data: self.extra_data.clone(),
base_fee_per_gas: self.base_fee_per_gas,
block_hash: self.block_hash,
transactions_root: self.transactions_root,
// FIXME: the spec doesn't seem to define what to do here..
withdrawals_root: empty_withdrawals_root,
}
}
}
impl<T: EthSpec> ExecutionPayloadHeaderCapella<T> {
pub fn upgrade_to_eip4844(&self) -> ExecutionPayloadHeaderEip4844<T> {
ExecutionPayloadHeaderEip4844 {
parent_hash: self.parent_hash,
fee_recipient: self.fee_recipient,
state_root: self.state_root,
receipts_root: self.receipts_root,
logs_bloom: self.logs_bloom.clone(),
prev_randao: self.prev_randao,
block_number: self.block_number,
gas_limit: self.gas_limit,
gas_used: self.gas_used,
timestamp: self.timestamp,
extra_data: self.extra_data.clone(),
base_fee_per_gas: self.base_fee_per_gas,
// TODO: verify if this is correct
excess_blobs: 0,
block_hash: self.block_hash,
transactions_root: self.transactions_root,
withdrawals_root: self.withdrawals_root,
}
}
}
impl<T: EthSpec> From<ExecutionPayloadMerge<T>> for ExecutionPayloadHeaderMerge<T> {
fn from(payload: ExecutionPayloadMerge<T>) -> Self {
Self {

View File

@ -621,17 +621,6 @@ impl<T: EthSpec> ExecPayload<T> for BlindedPayload<T> {
// TODO: can this function be optimized?
fn is_default(&self) -> bool {
match self {
/*
Self::Merge(payload) => {
payload.execution_payload_header == ExecutionPayloadHeaderMerge::default()
}
Self::Capella(payload) => {
payload.execution_payload_header == ExecutionPayloadHeaderCapella::default()
}
Self::Eip4844(payload) => {
payload.execution_payload_header == ExecutionPayloadHeaderEip4844::default()
}
*/
Self::Merge(payload) => payload.is_default(),
Self::Capella(payload) => payload.is_default(),
Self::Eip4844(payload) => payload.is_default(),