mirror of
https://github.com/sigp/lighthouse.git
synced 2026-05-30 12:47:05 +00:00
Spec v1.7.0-alpha.6 and Gloas genesis (#9190)
Co-Authored-By: Josh King <josh@sigmaprime.io> Co-Authored-By: Jimmy Chen <jchen.tc@gmail.com> Co-Authored-By: Michael Sproul <michael@sigmaprime.io>
This commit is contained in:
@@ -26,6 +26,12 @@ pub enum EnvelopeProcessingError {
|
||||
envelope_root: Hash256,
|
||||
block_header_root: Hash256,
|
||||
},
|
||||
/// Envelope's `parent_beacon_block_root` doesn't match the parent root of the latest
|
||||
/// block header.
|
||||
ParentBeaconBlockRootMismatch {
|
||||
envelope: Hash256,
|
||||
state: Hash256,
|
||||
},
|
||||
/// Envelope doesn't match latest beacon block slot
|
||||
SlotMismatch {
|
||||
envelope_slot: Slot,
|
||||
@@ -126,6 +132,13 @@ pub fn verify_execution_payload_envelope<E: EthSpec>(
|
||||
block_header_root: latest_block_header_root,
|
||||
}
|
||||
);
|
||||
envelope_verify!(
|
||||
envelope.parent_beacon_block_root == state.latest_block_header().parent_root,
|
||||
EnvelopeProcessingError::ParentBeaconBlockRootMismatch {
|
||||
envelope: envelope.parent_beacon_block_root,
|
||||
state: state.latest_block_header().parent_root,
|
||||
}
|
||||
);
|
||||
envelope_verify!(
|
||||
envelope.slot() == state.slot(),
|
||||
EnvelopeProcessingError::SlotMismatch {
|
||||
|
||||
@@ -175,13 +175,11 @@ pub fn initialize_beacon_state_from_eth1<E: EthSpec>(
|
||||
bid.parent_block_hash = el_genesis_hash;
|
||||
bid.block_hash = ExecutionBlockHash::default();
|
||||
|
||||
// Update latest_block_header to reflect the Gloas genesis block body which contains
|
||||
// the EL genesis hash in the signed_execution_payload_bid. This is needed because
|
||||
// BeaconState::new() created the header from BeaconBlock::empty() which has zero bid
|
||||
// fields, but the spec requires the genesis block's bid to contain the EL block hash
|
||||
// and the tree hash root of empty ExecutionRequests.
|
||||
let block = genesis_block(&state, spec)?;
|
||||
state.latest_block_header_mut().body_root = block.body_root();
|
||||
// Update the `latest_block_header.body_root` so that it matches the body of the
|
||||
// Gloas genesis block, which embeds `state.latest_execution_payload_bid` in its
|
||||
// `signed_execution_payload_bid` field (see `genesis_block`).
|
||||
let genesis_body_root = genesis_block(&state, spec)?.body_root();
|
||||
state.latest_block_header_mut().body_root = genesis_body_root;
|
||||
}
|
||||
|
||||
// Now that we have our validators, initialize the caches (including the committees)
|
||||
@@ -193,24 +191,23 @@ pub fn initialize_beacon_state_from_eth1<E: EthSpec>(
|
||||
Ok(state)
|
||||
}
|
||||
|
||||
/// Create an unsigned genesis `BeaconBlock` whose body matches the genesis state.
|
||||
/// Create an unsigned genesis `BeaconBlock`.
|
||||
///
|
||||
/// For Gloas, the block's `signed_execution_payload_bid` is populated from the state's
|
||||
/// `latest_execution_payload_bid` so that the body root is consistent with
|
||||
/// `state.latest_block_header.body_root`.
|
||||
/// Per spec, the genesis block body is empty (all default fields) except for Gloas,
|
||||
/// where `body.signed_execution_payload_bid.message` is initialised from
|
||||
/// `state.latest_execution_payload_bid` so that the first post-genesis proposer can
|
||||
/// build on the correct execution layer head.
|
||||
///
|
||||
/// The returned block has `state_root == Hash256::ZERO`; callers that need the real
|
||||
/// state root should set it themselves.
|
||||
/// `state.latest_block_header.body_root` is set from this same block's body, so the
|
||||
/// two must stay in sync.
|
||||
pub fn genesis_block<E: EthSpec>(
|
||||
genesis_state: &BeaconState<E>,
|
||||
state: &BeaconState<E>,
|
||||
spec: &ChainSpec,
|
||||
) -> Result<BeaconBlock<E>, BeaconStateError> {
|
||||
let mut block = BeaconBlock::empty(spec);
|
||||
if let Ok(block) = block.as_gloas_mut() {
|
||||
let state_bid = genesis_state.latest_execution_payload_bid()?;
|
||||
let bid = &mut block.body.signed_execution_payload_bid.message;
|
||||
bid.block_hash = state_bid.block_hash;
|
||||
bid.execution_requests_root = state_bid.execution_requests_root;
|
||||
if let BeaconBlock::Gloas(ref mut gloas_block) = block {
|
||||
let bid = state.latest_execution_payload_bid()?.clone();
|
||||
gloas_block.body.signed_execution_payload_bid.message = bid;
|
||||
}
|
||||
Ok(block)
|
||||
}
|
||||
|
||||
@@ -555,13 +555,10 @@ pub fn process_parent_execution_payload<E: EthSpec, Payload: AbstractExecPayload
|
||||
.signed_execution_payload_bid()?
|
||||
.message
|
||||
.parent_block_hash;
|
||||
let parent_bid = state.latest_execution_payload_bid()?.clone();
|
||||
let parent_bid = state.latest_execution_payload_bid()?;
|
||||
let requests = block.body().parent_execution_requests()?;
|
||||
|
||||
let is_genesis_block = parent_bid.block_hash == ExecutionBlockHash::zero();
|
||||
let is_parent_block_empty = bid_parent_block_hash != parent_bid.block_hash;
|
||||
|
||||
if is_genesis_block || is_parent_block_empty {
|
||||
if bid_parent_block_hash != parent_bid.block_hash {
|
||||
// Parent was EMPTY -- no execution requests expected
|
||||
block_verify!(
|
||||
*requests == ExecutionRequests::default(),
|
||||
@@ -580,7 +577,7 @@ pub fn process_parent_execution_payload<E: EthSpec, Payload: AbstractExecPayload
|
||||
}
|
||||
);
|
||||
|
||||
apply_parent_execution_payload(state, &parent_bid, requests, spec)
|
||||
apply_parent_execution_payload(state, requests, spec)
|
||||
}
|
||||
|
||||
/// Apply the parent execution payload's deferred effects to the state.
|
||||
@@ -591,10 +588,10 @@ pub fn process_parent_execution_payload<E: EthSpec, Payload: AbstractExecPayload
|
||||
/// 3. Updates `execution_payload_availability` and `latest_block_hash`
|
||||
pub fn apply_parent_execution_payload<E: EthSpec>(
|
||||
state: &mut BeaconState<E>,
|
||||
parent_bid: &ExecutionPayloadBid<E>,
|
||||
requests: &ExecutionRequests<E>,
|
||||
spec: &ChainSpec,
|
||||
) -> Result<(), BlockProcessingError> {
|
||||
let parent_bid = state.latest_execution_payload_bid()?.clone();
|
||||
let parent_slot = parent_bid.slot;
|
||||
let parent_epoch = parent_slot.epoch(E::slots_per_epoch());
|
||||
|
||||
|
||||
@@ -9,8 +9,8 @@ use safe_arith::{SafeArith, SafeArithIter};
|
||||
use tree_hash::TreeHash;
|
||||
use types::{
|
||||
AbstractExecPayload, BeaconState, BeaconStateError, ChainSpec, EthSpec, ExecPayload,
|
||||
ExecutionBlockHash, ExpectedWithdrawals, ExpectedWithdrawalsCapella,
|
||||
ExpectedWithdrawalsElectra, ExpectedWithdrawalsGloas, Validator, Withdrawal, Withdrawals,
|
||||
ExpectedWithdrawals, ExpectedWithdrawalsCapella, ExpectedWithdrawalsElectra,
|
||||
ExpectedWithdrawalsGloas, Validator, Withdrawal, Withdrawals,
|
||||
};
|
||||
|
||||
/// Compute the next batch of withdrawals which should be included in a block.
|
||||
@@ -495,10 +495,7 @@ pub mod gloas {
|
||||
spec: &ChainSpec,
|
||||
) -> Result<(), BlockProcessingError> {
|
||||
// Return early if the parent block is empty.
|
||||
let is_genesis_block = *state.latest_block_hash()? == ExecutionBlockHash::default();
|
||||
let is_parent_block_empty =
|
||||
*state.latest_block_hash()? != state.latest_execution_payload_bid()?.block_hash;
|
||||
if is_genesis_block || is_parent_block_empty {
|
||||
if *state.latest_block_hash()? != state.latest_execution_payload_bid()?.block_hash {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
|
||||
@@ -962,7 +962,11 @@ fn compute_exit_epoch_and_update_churn(
|
||||
spec.compute_activation_exit_epoch(state_ctxt.current_epoch)?,
|
||||
);
|
||||
|
||||
let per_epoch_churn = get_activation_exit_churn_limit(state_ctxt, spec)?;
|
||||
let per_epoch_churn = if state_ctxt.fork_name.gloas_enabled() {
|
||||
get_balance_churn_limit(state_ctxt, spec)?
|
||||
} else {
|
||||
get_activation_exit_churn_limit(state_ctxt, spec)?
|
||||
};
|
||||
// New epoch for exits
|
||||
let mut exit_balance_to_consume = if *earliest_exit_epoch_state < earliest_exit_epoch {
|
||||
per_epoch_churn
|
||||
@@ -991,17 +995,27 @@ fn get_activation_exit_churn_limit(
|
||||
state_ctxt: &StateContext,
|
||||
spec: &ChainSpec,
|
||||
) -> Result<u64, Error> {
|
||||
let max_limit = if state_ctxt.fork_name.gloas_enabled() {
|
||||
spec.max_per_epoch_activation_churn_limit_gloas
|
||||
} else {
|
||||
spec.max_per_epoch_activation_exit_churn_limit
|
||||
};
|
||||
Ok(std::cmp::min(
|
||||
spec.max_per_epoch_activation_exit_churn_limit,
|
||||
max_limit,
|
||||
get_balance_churn_limit(state_ctxt, spec)?,
|
||||
))
|
||||
}
|
||||
|
||||
fn get_balance_churn_limit(state_ctxt: &StateContext, spec: &ChainSpec) -> Result<u64, Error> {
|
||||
let total_active_balance = state_ctxt.total_active_balance;
|
||||
let quotient = if state_ctxt.fork_name.gloas_enabled() {
|
||||
spec.churn_limit_quotient_gloas
|
||||
} else {
|
||||
spec.churn_limit_quotient
|
||||
};
|
||||
let churn = std::cmp::max(
|
||||
spec.min_per_epoch_churn_limit_electra,
|
||||
total_active_balance.safe_div(spec.churn_limit_quotient)?,
|
||||
total_active_balance.safe_div(quotient)?,
|
||||
);
|
||||
|
||||
Ok(churn.safe_sub(churn.safe_rem(spec.effective_balance_increment)?)?)
|
||||
|
||||
Reference in New Issue
Block a user