Gloas envelope consensus and more operations tests (#8781)

- Implement new `process_execution_payload` (as `process_execution_payload_envelope`).
- Implement new processing for deposit requests, including logic for adding new builders to the registry with index reuse.
- Enable a bunch more operations EF tests (most of them except bid processing/payload attestations/etc which we don't have code for yet).


Co-Authored-By: Michael Sproul <michael@sigmaprime.io>
This commit is contained in:
Michael Sproul
2026-02-10 14:59:25 +11:00
committed by GitHub
parent 286b67f048
commit 7e275f8dc2
12 changed files with 643 additions and 34 deletions

View File

@@ -48,19 +48,9 @@ excluded_paths = [
"tests/.*/eip7732",
"tests/.*/eip7805",
# TODO(gloas): remove these ignores as more Gloas operations are implemented
"tests/.*/gloas/operations/attester_slashing/.*",
"tests/.*/gloas/operations/block_header/.*",
"tests/.*/gloas/operations/bls_to_execution_change/.*",
"tests/.*/gloas/operations/consolidation_request/.*",
"tests/.*/gloas/operations/deposit/.*",
"tests/.*/gloas/operations/deposit_request/.*",
"tests/.*/gloas/operations/execution_payload/.*",
"tests/.*/gloas/operations/execution_payload_bid/.*",
"tests/.*/gloas/operations/payload_attestation/.*",
"tests/.*/gloas/operations/proposer_slashing/.*",
"tests/.*/gloas/operations/sync_aggregate/.*",
"tests/.*/gloas/operations/voluntary_exit/.*",
"tests/.*/gloas/operations/withdrawal_request/.*",
# TODO(EIP-7732): remove these ignores as Gloas consensus is implemented
"tests/.*/gloas/epoch_processing/.*",
"tests/.*/gloas/finality/.*",

View File

@@ -7,10 +7,12 @@ use ssz::Decode;
use state_processing::common::update_progressive_balances_cache::initialize_progressive_balances_cache;
use state_processing::epoch_cache::initialize_epoch_cache;
use state_processing::per_block_processing::process_operations::{
process_consolidation_requests, process_deposit_requests, process_withdrawal_requests,
process_consolidation_requests, process_deposit_requests_post_gloas,
process_deposit_requests_pre_gloas, process_withdrawal_requests,
};
use state_processing::{
ConsensusContext,
envelope_processing::{EnvelopeProcessingError, process_execution_payload_envelope},
per_block_processing::{
VerifyBlockRoot, VerifySignatures,
errors::BlockProcessingError,
@@ -29,7 +31,7 @@ use types::{
BeaconBlockBodyCapella, BeaconBlockBodyDeneb, BeaconBlockBodyElectra, BeaconBlockBodyFulu,
BeaconState, BlindedPayload, ConsolidationRequest, Deposit, DepositRequest, ExecutionPayload,
ForkVersionDecode, FullPayload, ProposerSlashing, SignedBlsToExecutionChange,
SignedVoluntaryExit, SyncAggregate, WithdrawalRequest,
SignedExecutionPayloadEnvelope, SignedVoluntaryExit, SyncAggregate, WithdrawalRequest,
};
#[derive(Debug, Clone, Default, Deserialize)]
@@ -59,6 +61,8 @@ pub struct Operations<E: EthSpec, O: Operation<E>> {
}
pub trait Operation<E: EthSpec>: Debug + Sync + Sized {
type Error: Debug;
fn handler_name() -> String;
fn filename() -> String {
@@ -76,10 +80,12 @@ pub trait Operation<E: EthSpec>: Debug + Sync + Sized {
state: &mut BeaconState<E>,
spec: &ChainSpec,
_: &Operations<E, Self>,
) -> Result<(), BlockProcessingError>;
) -> Result<(), Self::Error>;
}
impl<E: EthSpec> Operation<E> for Attestation<E> {
type Error = BlockProcessingError;
fn handler_name() -> String {
"attestation".into()
}
@@ -132,6 +138,8 @@ impl<E: EthSpec> Operation<E> for Attestation<E> {
}
impl<E: EthSpec> Operation<E> for AttesterSlashing<E> {
type Error = BlockProcessingError;
fn handler_name() -> String {
"attester_slashing".into()
}
@@ -163,6 +171,8 @@ impl<E: EthSpec> Operation<E> for AttesterSlashing<E> {
}
impl<E: EthSpec> Operation<E> for Deposit {
type Error = BlockProcessingError;
fn handler_name() -> String {
"deposit".into()
}
@@ -187,6 +197,8 @@ impl<E: EthSpec> Operation<E> for Deposit {
}
impl<E: EthSpec> Operation<E> for ProposerSlashing {
type Error = BlockProcessingError;
fn handler_name() -> String {
"proposer_slashing".into()
}
@@ -214,6 +226,8 @@ impl<E: EthSpec> Operation<E> for ProposerSlashing {
}
impl<E: EthSpec> Operation<E> for SignedVoluntaryExit {
type Error = BlockProcessingError;
fn handler_name() -> String {
"voluntary_exit".into()
}
@@ -238,6 +252,8 @@ impl<E: EthSpec> Operation<E> for SignedVoluntaryExit {
}
impl<E: EthSpec> Operation<E> for BeaconBlock<E> {
type Error = BlockProcessingError;
fn handler_name() -> String {
"block_header".into()
}
@@ -269,6 +285,8 @@ impl<E: EthSpec> Operation<E> for BeaconBlock<E> {
}
impl<E: EthSpec> Operation<E> for SyncAggregate<E> {
type Error = BlockProcessingError;
fn handler_name() -> String {
"sync_aggregate".into()
}
@@ -297,6 +315,8 @@ impl<E: EthSpec> Operation<E> for SyncAggregate<E> {
}
impl<E: EthSpec> Operation<E> for BeaconBlockBody<E, FullPayload<E>> {
type Error = BlockProcessingError;
fn handler_name() -> String {
"execution_payload".into()
}
@@ -306,7 +326,7 @@ impl<E: EthSpec> Operation<E> for BeaconBlockBody<E, FullPayload<E>> {
}
fn is_enabled_for_fork(fork_name: ForkName) -> bool {
fork_name.bellatrix_enabled()
fork_name.bellatrix_enabled() && !fork_name.gloas_enabled()
}
fn decode(path: &Path, fork_name: ForkName, _spec: &ChainSpec) -> Result<Self, Error> {
@@ -317,8 +337,7 @@ impl<E: EthSpec> Operation<E> for BeaconBlockBody<E, FullPayload<E>> {
ForkName::Deneb => BeaconBlockBody::Deneb(<_>::from_ssz_bytes(bytes)?),
ForkName::Electra => BeaconBlockBody::Electra(<_>::from_ssz_bytes(bytes)?),
ForkName::Fulu => BeaconBlockBody::Fulu(<_>::from_ssz_bytes(bytes)?),
// TODO(EIP-7732): See if we need to handle Gloas here
_ => panic!(),
_ => panic!("Not supported after Gloas"),
})
})
}
@@ -340,7 +359,10 @@ impl<E: EthSpec> Operation<E> for BeaconBlockBody<E, FullPayload<E>> {
}
}
}
impl<E: EthSpec> Operation<E> for BeaconBlockBody<E, BlindedPayload<E>> {
type Error = BlockProcessingError;
fn handler_name() -> String {
"execution_payload".into()
}
@@ -350,7 +372,7 @@ impl<E: EthSpec> Operation<E> for BeaconBlockBody<E, BlindedPayload<E>> {
}
fn is_enabled_for_fork(fork_name: ForkName) -> bool {
fork_name.bellatrix_enabled()
fork_name.bellatrix_enabled() && !fork_name.gloas_enabled()
}
fn decode(path: &Path, fork_name: ForkName, _spec: &ChainSpec) -> Result<Self, Error> {
@@ -377,8 +399,7 @@ impl<E: EthSpec> Operation<E> for BeaconBlockBody<E, BlindedPayload<E>> {
let inner = <BeaconBlockBodyFulu<E, FullPayload<E>>>::from_ssz_bytes(bytes)?;
BeaconBlockBody::Fulu(inner.clone_as_blinded())
}
// TODO(EIP-7732): See if we need to handle Gloas here
_ => panic!(),
_ => panic!("Not supported after Gloas"),
})
})
}
@@ -401,7 +422,46 @@ impl<E: EthSpec> Operation<E> for BeaconBlockBody<E, BlindedPayload<E>> {
}
}
impl<E: EthSpec> Operation<E> for SignedExecutionPayloadEnvelope<E> {
type Error = EnvelopeProcessingError;
fn handler_name() -> String {
"execution_payload".into()
}
fn filename() -> String {
"signed_envelope.ssz_snappy".into()
}
fn is_enabled_for_fork(fork_name: ForkName) -> bool {
fork_name.gloas_enabled()
}
fn decode(path: &Path, _: ForkName, _spec: &ChainSpec) -> Result<Self, Error> {
ssz_decode_file(path)
}
fn apply_to(
&self,
state: &mut BeaconState<E>,
spec: &ChainSpec,
extra: &Operations<E, Self>,
) -> Result<(), Self::Error> {
let valid = extra
.execution_metadata
.as_ref()
.is_some_and(|e| e.execution_valid);
if valid {
process_execution_payload_envelope(state, None, self, VerifySignatures::True, spec)
} else {
Err(EnvelopeProcessingError::ExecutionInvalid)
}
}
}
impl<E: EthSpec> Operation<E> for WithdrawalsPayload<E> {
type Error = BlockProcessingError;
fn handler_name() -> String {
"withdrawals".into()
}
@@ -448,6 +508,8 @@ impl<E: EthSpec> Operation<E> for WithdrawalsPayload<E> {
}
impl<E: EthSpec> Operation<E> for SignedBlsToExecutionChange {
type Error = BlockProcessingError;
fn handler_name() -> String {
"bls_to_execution_change".into()
}
@@ -480,6 +542,8 @@ impl<E: EthSpec> Operation<E> for SignedBlsToExecutionChange {
}
impl<E: EthSpec> Operation<E> for WithdrawalRequest {
type Error = BlockProcessingError;
fn handler_name() -> String {
"withdrawal_request".into()
}
@@ -504,6 +568,8 @@ impl<E: EthSpec> Operation<E> for WithdrawalRequest {
}
impl<E: EthSpec> Operation<E> for DepositRequest {
type Error = BlockProcessingError;
fn handler_name() -> String {
"deposit_request".into()
}
@@ -522,11 +588,17 @@ impl<E: EthSpec> Operation<E> for DepositRequest {
spec: &ChainSpec,
_extra: &Operations<E, Self>,
) -> Result<(), BlockProcessingError> {
process_deposit_requests(state, std::slice::from_ref(self), spec)
if state.fork_name_unchecked().gloas_enabled() {
process_deposit_requests_post_gloas(state, std::slice::from_ref(self), spec)
} else {
process_deposit_requests_pre_gloas(state, std::slice::from_ref(self), spec)
}
}
}
impl<E: EthSpec> Operation<E> for ConsolidationRequest {
type Error = BlockProcessingError;
fn handler_name() -> String {
"consolidation_request".into()
}

View File

@@ -1135,11 +1135,20 @@ impl<E: EthSpec + TypeName, O: Operation<E>> Handler for OperationsHandler<E, O>
}
fn is_enabled_for_fork(&self, fork_name: ForkName) -> bool {
// TODO(gloas): So far only withdrawals tests are enabled for Gloas.
Self::Case::is_enabled_for_fork(fork_name)
&& (!fork_name.gloas_enabled()
|| self.handler_name() == "attestation"
|| self.handler_name() == "attester_slashing"
|| self.handler_name() == "bls_to_execution_change"
|| self.handler_name() == "consolidation_request"
|| self.handler_name() == "deposit_request"
|| self.handler_name() == "deposit"
|| self.handler_name() == "execution_payload"
|| self.handler_name() == "proposer_slashing"
|| self.handler_name() == "sync_aggregate"
|| self.handler_name() == "withdrawal_request"
|| self.handler_name() == "withdrawals"
|| self.handler_name() == "attestation")
|| self.handler_name() == "voluntary_exit")
}
}

View File

@@ -87,6 +87,12 @@ fn operations_execution_payload_blinded() {
OperationsHandler::<MainnetEthSpec, BeaconBlockBody<_, BlindedPayload<_>>>::default().run();
}
#[test]
fn operations_execution_payload_envelope() {
OperationsHandler::<MinimalEthSpec, SignedExecutionPayloadEnvelope<_>>::default().run();
OperationsHandler::<MainnetEthSpec, SignedExecutionPayloadEnvelope<_>>::default().run();
}
#[test]
fn operations_withdrawals() {
OperationsHandler::<MinimalEthSpec, WithdrawalsPayload<_>>::default().run();
@@ -94,7 +100,7 @@ fn operations_withdrawals() {
}
#[test]
fn operations_withdrawal_reqeusts() {
fn operations_withdrawal_requests() {
OperationsHandler::<MinimalEthSpec, WithdrawalRequest>::default().run();
OperationsHandler::<MainnetEthSpec, WithdrawalRequest>::default().run();
}