Gloas(EIP-7732): Containers / Constants (#7923)

* #7850

This is the first round of the conga line! 🎉

Just spec constants and container changes so far.


  


Co-Authored-By: shane-moore <skm1790@gmail.com>

Co-Authored-By: Mark Mackey <mark@sigmaprime.io>

Co-Authored-By: Shane K Moore <41407272+shane-moore@users.noreply.github.com>

Co-Authored-By: Eitan Seri- Levi <eserilev@gmail.com>

Co-Authored-By: ethDreamer <37123614+ethDreamer@users.noreply.github.com>

Co-Authored-By: Jimmy Chen <jchen.tc@gmail.com>

Co-Authored-By: Jimmy Chen <jimmy@sigmaprime.io>

Co-Authored-By: Michael Sproul <michael@sigmaprime.io>
This commit is contained in:
ethDreamer
2025-12-16 00:45:45 -06:00
committed by GitHub
parent 86c2b7cfbe
commit a39e991557
52 changed files with 930 additions and 689 deletions

View File

@@ -715,8 +715,9 @@ mod tests {
harness
}
// TODO(EIP-7732) Extend this test for gloas
#[tokio::test]
async fn check_all_blocks_from_altair_to_gloas() {
async fn check_all_blocks_from_altair_to_fulu() {
let slots_per_epoch = MinimalEthSpec::slots_per_epoch() as usize;
let num_epochs = 12;
let bellatrix_fork_epoch = 2usize;
@@ -724,7 +725,6 @@ mod tests {
let deneb_fork_epoch = 6usize;
let electra_fork_epoch = 8usize;
let fulu_fork_epoch = 10usize;
let gloas_fork_epoch = 12usize;
let num_blocks_produced = num_epochs * slots_per_epoch;
let mut spec = test_spec::<MinimalEthSpec>();
@@ -734,7 +734,6 @@ mod tests {
spec.deneb_fork_epoch = Some(Epoch::new(deneb_fork_epoch as u64));
spec.electra_fork_epoch = Some(Epoch::new(electra_fork_epoch as u64));
spec.fulu_fork_epoch = Some(Epoch::new(fulu_fork_epoch as u64));
spec.gloas_fork_epoch = Some(Epoch::new(gloas_fork_epoch as u64));
let spec = Arc::new(spec);
let harness = get_harness(VALIDATOR_COUNT, spec.clone());

View File

@@ -5795,60 +5795,7 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
execution_payload_value,
)
}
BeaconState::Gloas(_) => {
let (
payload,
kzg_commitments,
maybe_blobs_and_proofs,
maybe_requests,
execution_payload_value,
) = block_contents
.ok_or(BlockProductionError::MissingExecutionPayload)?
.deconstruct();
(
BeaconBlock::Gloas(BeaconBlockGloas {
slot,
proposer_index,
parent_root,
state_root: Hash256::zero(),
body: BeaconBlockBodyGloas {
randao_reveal,
eth1_data,
graffiti,
proposer_slashings: proposer_slashings
.try_into()
.map_err(BlockProductionError::SszTypesError)?,
attester_slashings: attester_slashings_electra
.try_into()
.map_err(BlockProductionError::SszTypesError)?,
attestations: attestations_electra
.try_into()
.map_err(BlockProductionError::SszTypesError)?,
deposits: deposits
.try_into()
.map_err(BlockProductionError::SszTypesError)?,
voluntary_exits: voluntary_exits
.try_into()
.map_err(BlockProductionError::SszTypesError)?,
sync_aggregate: sync_aggregate
.ok_or(BlockProductionError::MissingSyncAggregate)?,
execution_payload: payload
.try_into()
.map_err(|_| BlockProductionError::InvalidPayloadFork)?,
bls_to_execution_changes: bls_to_execution_changes
.try_into()
.map_err(BlockProductionError::SszTypesError)?,
blob_kzg_commitments: kzg_commitments
.ok_or(BlockProductionError::InvalidPayloadFork)?,
execution_requests: maybe_requests
.ok_or(BlockProductionError::MissingExecutionRequests)?,
},
}),
maybe_blobs_and_proofs,
execution_payload_value,
)
}
BeaconState::Gloas(_) => return Err(BlockProductionError::GloasNotImplemented),
};
let block = SignedBeaconBlock::from_block(

View File

@@ -320,6 +320,8 @@ pub enum BlockProductionError {
FailedToBuildBlobSidecars(String),
MissingExecutionRequests,
SszTypesError(ssz_types::Error),
// TODO(gloas): Remove this once Gloas is implemented
GloasNotImplemented,
}
easy_from_to!(BlockProcessingError, BlockProductionError);

View File

@@ -3300,9 +3300,7 @@ pub fn generate_rand_block_and_blobs<E: EthSpec>(
SignedBeaconBlock::Fulu(SignedBeaconBlockFulu {
ref mut message, ..
}) => add_blob_transactions!(message, FullPayloadFulu<E>, num_blobs, rng, fork_name),
SignedBeaconBlock::Gloas(SignedBeaconBlockGloas {
ref mut message, ..
}) => add_blob_transactions!(message, FullPayloadGloas<E>, num_blobs, rng, fork_name),
// TODO(EIP-7732) Add `SignedBeaconBlock::Gloas` variant
_ => return (block, blob_sidecars),
};

View File

@@ -159,6 +159,7 @@ fn get_states_descendant_of_block(
.collect()
}
// TODO(EIP-7732) Extend to support gloas
#[tokio::test]
async fn light_client_bootstrap_test() {
let spec = test_spec::<E>();
@@ -206,7 +207,6 @@ async fn light_client_bootstrap_test() {
LightClientBootstrap::Deneb(lc_bootstrap) => lc_bootstrap.header.beacon.slot,
LightClientBootstrap::Electra(lc_bootstrap) => lc_bootstrap.header.beacon.slot,
LightClientBootstrap::Fulu(lc_bootstrap) => lc_bootstrap.header.beacon.slot,
LightClientBootstrap::Gloas(lc_bootstrap) => lc_bootstrap.header.beacon.slot,
};
assert_eq!(
@@ -1581,6 +1581,10 @@ async fn proposer_duties_from_head_fulu() {
}
/// Test that we can compute the proposer shuffling for the Gloas fork epoch itself using lookahead!
// TODO(EIP-7732): Extend to gloas
// `state.latest_execution_payload_header()` not available in Gloas
// called from `add_block_at_slot` -> `make_block` -> `produce_block_on_state` -> `produce_partial_beacon_block` -> `get_execution_payload` -> `Error`
#[ignore]
#[tokio::test]
async fn proposer_lookahead_gloas_fork_epoch() {
let gloas_fork_epoch = Epoch::new(4);

View File

@@ -541,34 +541,6 @@ impl<E: EthSpec> ExecutionPayloadBodyV1<E> {
))
}
}
ExecutionPayloadHeader::Gloas(header) => {
if let Some(withdrawals) = self.withdrawals {
Ok(ExecutionPayload::Gloas(ExecutionPayloadGloas {
parent_hash: header.parent_hash,
fee_recipient: header.fee_recipient,
state_root: header.state_root,
receipts_root: header.receipts_root,
logs_bloom: header.logs_bloom,
prev_randao: header.prev_randao,
block_number: header.block_number,
gas_limit: header.gas_limit,
gas_used: header.gas_used,
timestamp: header.timestamp,
extra_data: header.extra_data,
base_fee_per_gas: header.base_fee_per_gas,
block_hash: header.block_hash,
transactions: self.transactions,
withdrawals,
blob_gas_used: header.blob_gas_used,
excess_blob_gas: header.excess_blob_gas,
}))
} else {
Err(format!(
"block {} is post capella but payload body doesn't have withdrawals",
header.block_hash
))
}
}
}
}
}

View File

@@ -172,6 +172,7 @@ impl<'block, E: EthSpec> NewPayloadRequest<'block, E> {
}
}
//TODO(EIP7732): Consider implementing these as methods on the NewPayloadRequest struct
impl<'a, E: EthSpec> TryFrom<BeaconBlockRef<'a, E>> for NewPayloadRequest<'a, E> {
type Error = BeaconStateError;
@@ -220,17 +221,7 @@ impl<'a, E: EthSpec> TryFrom<BeaconBlockRef<'a, E>> for NewPayloadRequest<'a, E>
parent_beacon_block_root: block_ref.parent_root,
execution_requests: &block_ref.body.execution_requests,
})),
BeaconBlockRef::Gloas(block_ref) => Ok(Self::Gloas(NewPayloadRequestGloas {
execution_payload: &block_ref.body.execution_payload.execution_payload,
versioned_hashes: block_ref
.body
.blob_kzg_commitments
.iter()
.map(kzg_commitment_to_versioned_hash)
.collect(),
parent_beacon_block_root: block_ref.parent_root,
execution_requests: &block_ref.body.execution_requests,
})),
BeaconBlockRef::Gloas(_) => Err(Self::Error::IncorrectStateVariant),
}
}
}
@@ -251,11 +242,15 @@ impl<'a, E: EthSpec> TryFrom<ExecutionPayloadRef<'a, E>> for NewPayloadRequest<'
ExecutionPayloadRef::Deneb(_) => Err(Self::Error::IncorrectStateVariant),
ExecutionPayloadRef::Electra(_) => Err(Self::Error::IncorrectStateVariant),
ExecutionPayloadRef::Fulu(_) => Err(Self::Error::IncorrectStateVariant),
//TODO(EIP7732): Probably time to just get rid of this
ExecutionPayloadRef::Gloas(_) => Err(Self::Error::IncorrectStateVariant),
}
}
}
// TODO(EIP-7732) build out the following when it's needed like in Mark's branch
// impl<'a, E: EthSpec> TryFrom<ExecutionEnvelopeRef<'a, E>> for NewPayloadRequest<E> {
#[cfg(test)]
mod test {
use crate::versioned_hashes::Error as VersionedHashError;

View File

@@ -55,8 +55,8 @@ use types::{
};
use types::{
BeaconStateError, BlindedPayload, ChainSpec, Epoch, ExecPayload, ExecutionPayloadBellatrix,
ExecutionPayloadCapella, ExecutionPayloadElectra, ExecutionPayloadFulu, ExecutionPayloadGloas,
FullPayload, ProposerPreparationData, Slot,
ExecutionPayloadCapella, ExecutionPayloadElectra, ExecutionPayloadFulu, FullPayload,
ProposerPreparationData, Slot,
};
mod block_hash;
@@ -131,13 +131,6 @@ impl<E: EthSpec> TryFrom<BuilderBid<E>> for ProvenancedPayload<BlockProposalCont
blobs_and_proofs: None,
requests: Some(builder_bid.execution_requests),
},
BuilderBid::Gloas(builder_bid) => BlockProposalContents::PayloadAndBlobs {
payload: ExecutionPayloadHeader::Gloas(builder_bid.header).into(),
block_value: builder_bid.value,
kzg_commitments: builder_bid.blob_kzg_commitments,
blobs_and_proofs: None,
requests: Some(builder_bid.execution_requests),
},
};
Ok(ProvenancedPayload::Builder(
BlockProposalContentsType::Blinded(block_proposal_contents),
@@ -1368,6 +1361,7 @@ impl<E: EthSpec> ExecutionLayer<E> {
}
/// Maps to the `engine_newPayload` JSON-RPC call.
/// TODO(EIP-7732) figure out how and why Mark relaxed new_payload_request param's typ to NewPayloadRequest<E>
pub async fn notify_new_payload(
&self,
new_payload_request: NewPayloadRequest<'_, E>,
@@ -1839,10 +1833,12 @@ impl<E: EthSpec> ExecutionLayer<E> {
ForkName::Deneb => ExecutionPayloadDeneb::default().into(),
ForkName::Electra => ExecutionPayloadElectra::default().into(),
ForkName::Fulu => ExecutionPayloadFulu::default().into(),
ForkName::Gloas => ExecutionPayloadGloas::default().into(),
ForkName::Base | ForkName::Altair => {
return Err(Error::InvalidForkForPayload);
}
ForkName::Gloas => {
return Err(Error::InvalidForkForPayload);
}
};
return Ok(Some(payload));
}

View File

@@ -909,12 +909,8 @@ pub fn generate_genesis_header<E: EthSpec>(
*header.transactions_root_mut() = empty_transactions_root;
Some(header)
}
ForkName::Gloas => {
let mut header = ExecutionPayloadHeader::Gloas(<_>::default());
*header.block_hash_mut() = genesis_block_hash.unwrap_or_default();
*header.transactions_root_mut() = empty_transactions_root;
Some(header)
}
// TODO(EIP-7732): need to look into this
ForkName::Gloas => None,
}
}

View File

@@ -31,7 +31,7 @@ use tree_hash::TreeHash;
use types::ExecutionBlockHash;
use types::builder_bid::{
BuilderBid, BuilderBidBellatrix, BuilderBidCapella, BuilderBidDeneb, BuilderBidElectra,
BuilderBidFulu, BuilderBidGloas, SignedBuilderBid,
BuilderBidFulu, SignedBuilderBid,
};
use types::{
Address, BeaconState, ChainSpec, Epoch, EthSpec, ExecPayload, ExecutionPayload,
@@ -117,9 +117,6 @@ impl<E: EthSpec> BidStuff<E> for BuilderBid<E> {
ExecutionPayloadHeaderRefMut::Fulu(header) => {
header.fee_recipient = fee_recipient;
}
ExecutionPayloadHeaderRefMut::Gloas(header) => {
header.fee_recipient = fee_recipient;
}
}
}
@@ -140,9 +137,6 @@ impl<E: EthSpec> BidStuff<E> for BuilderBid<E> {
ExecutionPayloadHeaderRefMut::Fulu(header) => {
header.gas_limit = gas_limit;
}
ExecutionPayloadHeaderRefMut::Gloas(header) => {
header.gas_limit = gas_limit;
}
}
}
@@ -167,9 +161,6 @@ impl<E: EthSpec> BidStuff<E> for BuilderBid<E> {
ExecutionPayloadHeaderRefMut::Fulu(header) => {
header.parent_hash = ExecutionBlockHash::from_root(parent_hash);
}
ExecutionPayloadHeaderRefMut::Gloas(header) => {
header.parent_hash = ExecutionBlockHash::from_root(parent_hash);
}
}
}
@@ -190,9 +181,6 @@ impl<E: EthSpec> BidStuff<E> for BuilderBid<E> {
ExecutionPayloadHeaderRefMut::Fulu(header) => {
header.prev_randao = prev_randao;
}
ExecutionPayloadHeaderRefMut::Gloas(header) => {
header.prev_randao = prev_randao;
}
}
}
@@ -213,9 +201,6 @@ impl<E: EthSpec> BidStuff<E> for BuilderBid<E> {
ExecutionPayloadHeaderRefMut::Fulu(header) => {
header.block_number = block_number;
}
ExecutionPayloadHeaderRefMut::Gloas(header) => {
header.block_number = block_number;
}
}
}
@@ -236,9 +221,6 @@ impl<E: EthSpec> BidStuff<E> for BuilderBid<E> {
ExecutionPayloadHeaderRefMut::Fulu(header) => {
header.timestamp = timestamp;
}
ExecutionPayloadHeaderRefMut::Gloas(header) => {
header.timestamp = timestamp;
}
}
}
@@ -259,9 +241,6 @@ impl<E: EthSpec> BidStuff<E> for BuilderBid<E> {
ExecutionPayloadHeaderRefMut::Fulu(header) => {
header.withdrawals_root = withdrawals_root;
}
ExecutionPayloadHeaderRefMut::Gloas(header) => {
header.withdrawals_root = withdrawals_root;
}
}
}
@@ -295,10 +274,6 @@ impl<E: EthSpec> BidStuff<E> for BuilderBid<E> {
header.extra_data = extra_data;
header.block_hash = ExecutionBlockHash::from_root(header.tree_hash_root());
}
ExecutionPayloadHeaderRefMut::Gloas(header) => {
header.extra_data = extra_data;
header.block_hash = ExecutionBlockHash::from_root(header.tree_hash_root());
}
}
}
}
@@ -496,8 +471,9 @@ impl<E: EthSpec> MockBuilder<E> {
SignedBlindedBeaconBlock::Fulu(block) => {
block.message.body.execution_payload.tree_hash_root()
}
SignedBlindedBeaconBlock::Gloas(block) => {
block.message.body.execution_payload.tree_hash_root()
SignedBlindedBeaconBlock::Gloas(_) => {
// TODO(EIP7732) Check if this is how we want to do error handling for gloas
return Err("invalid fork".to_string());
}
};
let block_hash = block
@@ -613,18 +589,10 @@ impl<E: EthSpec> MockBuilder<E> {
) = payload_response.into();
match fork {
ForkName::Gloas => BuilderBid::Gloas(BuilderBidGloas {
header: payload
.as_gloas()
.map_err(|_| "incorrect payload variant".to_string())?
.into(),
blob_kzg_commitments: maybe_blobs_bundle
.map(|b| b.commitments.clone())
.unwrap_or_default(),
value: self.get_bid_value(value),
pubkey: self.builder_sk.public_key().compress(),
execution_requests: maybe_requests.unwrap_or_default(),
}),
ForkName::Gloas => {
// TODO(EIP7732) Check if this is how we want to do error handling for gloas
return Err("invalid fork".to_string());
}
ForkName::Fulu => BuilderBid::Fulu(BuilderBidFulu {
header: payload
.as_fulu()

View File

@@ -61,7 +61,10 @@ async fn state_by_root_pruned_from_fork_choice() {
type E = MinimalEthSpec;
let validator_count = 24;
let spec = ForkName::latest().make_genesis_spec(E::default_spec());
// TODO(EIP-7732): extend test for Gloas by reverting back to using `ForkName::latest()`
// Issue is that this test does block production via `extend_chain_with_sync` which expects to be able to use `state.latest_execution_payload_header` during block production, but Gloas uses `latest_execution_bid` instead
// This will be resolved in a subsequent block processing PR
let spec = ForkName::Fulu.make_genesis_spec(E::default_spec());
let tester = InteractiveTester::<E>::new_with_initializer_and_mutator(
Some(spec.clone()),
@@ -401,7 +404,10 @@ pub async fn proposer_boost_re_org_test(
assert!(head_slot > 0);
// Test using the latest fork so that we simulate conditions as similar to mainnet as possible.
let mut spec = ForkName::latest().make_genesis_spec(E::default_spec());
// TODO(EIP-7732): extend test for Gloas by reverting back to using `ForkName::latest()`
// Issue is that `get_validator_blocks_v3` below expects to be able to use `state.latest_execution_payload_header` during `produce_block_on_state` -> `produce_partial_beacon_block` -> `get_execution_payload`, but gloas will no longer support this state field
// This will be resolved in a subsequent block processing PR
let mut spec = ForkName::Fulu.make_genesis_spec(E::default_spec());
spec.terminal_total_difficulty = Uint256::from(1);
// Ensure there are enough validators to have `attesters_per_slot`.

View File

@@ -12,8 +12,10 @@ type E = MinimalEthSpec;
/// Create a new test environment that is post-merge with `chain_depth` blocks.
async fn post_merge_tester(chain_depth: u64, validator_count: u64) -> InteractiveTester<E> {
// Test using latest fork so that we simulate conditions as similar to mainnet as possible.
let mut spec = ForkName::latest().make_genesis_spec(E::default_spec());
// TODO(EIP-7732): extend tests for Gloas by reverting back to using `ForkName::latest()`
// Issue is that these tests do block production via `extend_chain_with_sync` which expects to be able to use `state.latest_execution_payload_header` during block production, but Gloas uses `latest_execution_bid` instead
// This will be resolved in a subsequent block processing PR
let mut spec = ForkName::Fulu.make_genesis_spec(E::default_spec());
spec.terminal_total_difficulty = Uint256::from(1);
let tester = InteractiveTester::<E>::new(Some(spec), validator_count as usize).await;

View File

@@ -1699,8 +1699,9 @@ async fn test_blobs_by_range_spans_fulu_fork() {
spec.fulu_fork_epoch = Some(Epoch::new(1));
spec.gloas_fork_epoch = Some(Epoch::new(2));
// This test focuses on Electra→Fulu blob counts (epoch 0 to 1). Build 62 blocks since no need for Gloas activation at slot 64.
let mut rig = TestRig::new_parametric(
64,
62,
BeaconProcessorConfig::default(),
NodeCustodyType::Fullnode,
spec,

View File

@@ -116,11 +116,12 @@ where
partial_getter(rename = "latest_execution_payload_header_fulu")
)]
pub latest_execution_payload_header: ExecutionPayloadHeaderFulu<E>,
#[superstruct(
only(Gloas),
partial_getter(rename = "latest_execution_payload_header_gloas")
partial_getter(rename = "latest_execution_payload_bid_gloas")
)]
pub latest_execution_payload_header: ExecutionPayloadHeaderGloas<E>,
pub latest_execution_payload_bid: ExecutionPayloadBid,
// Capella
#[superstruct(only(Capella, Deneb, Electra, Fulu, Gloas))]
@@ -155,6 +156,23 @@ where
pub pending_consolidations: List<PendingConsolidation, E::PendingConsolidationsLimit>,
#[superstruct(only(Fulu, Gloas))]
pub proposer_lookahead: Vector<u64, E::ProposerLookaheadSlots>,
// Gloas
#[superstruct(only(Gloas))]
pub execution_payload_availability: BitVector<E::SlotsPerHistoricalRoot>,
#[superstruct(only(Gloas))]
pub builder_pending_payments: Vector<BuilderPendingPayment, E::BuilderPendingPaymentsLimit>,
#[superstruct(only(Gloas))]
pub builder_pending_withdrawals:
List<BuilderPendingWithdrawal, E::BuilderPendingWithdrawalsLimit>,
#[superstruct(only(Gloas))]
pub latest_block_hash: ExecutionBlockHash,
#[superstruct(only(Gloas))]
pub latest_withdrawals_root: Hash256,
}
impl<E: EthSpec> PartialBeaconState<E> {
@@ -466,7 +484,7 @@ impl<E: EthSpec> TryInto<BeaconState<E>> for PartialBeaconState<E> {
current_sync_committee,
next_sync_committee,
inactivity_scores,
latest_execution_payload_header,
latest_execution_payload_bid,
next_withdrawal_index,
next_withdrawal_validator_index,
deposit_requests_start_index,
@@ -478,7 +496,12 @@ impl<E: EthSpec> TryInto<BeaconState<E>> for PartialBeaconState<E> {
pending_deposits,
pending_partial_withdrawals,
pending_consolidations,
proposer_lookahead
proposer_lookahead,
execution_payload_availability,
builder_pending_payments,
builder_pending_withdrawals,
latest_block_hash,
latest_withdrawals_root
],
[historical_summaries]
),