From a39e991557f6d16f0529eaca1b94de57ccc47f2f Mon Sep 17 00:00:00 2001 From: ethDreamer <37123614+ethDreamer@users.noreply.github.com> Date: Tue, 16 Dec 2025 00:45:45 -0600 Subject: [PATCH] Gloas(EIP-7732): Containers / Constants (#7923) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * #7850 This is the first round of the conga line! 🎉 Just spec constants and container changes so far. Co-Authored-By: shane-moore Co-Authored-By: Mark Mackey Co-Authored-By: Shane K Moore <41407272+shane-moore@users.noreply.github.com> Co-Authored-By: Eitan Seri- Levi Co-Authored-By: ethDreamer <37123614+ethDreamer@users.noreply.github.com> Co-Authored-By: Jimmy Chen Co-Authored-By: Jimmy Chen Co-Authored-By: Michael Sproul --- Makefile | 19 ++- .../beacon_chain/src/beacon_block_streamer.rs | 5 +- beacon_node/beacon_chain/src/beacon_chain.rs | 55 +------- beacon_node/beacon_chain/src/errors.rs | 2 + beacon_node/beacon_chain/src/test_utils.rs | 4 +- beacon_node/beacon_chain/tests/store_tests.rs | 6 +- beacon_node/execution_layer/src/engine_api.rs | 28 ---- .../src/engine_api/new_payload_request.rs | 17 +-- beacon_node/execution_layer/src/lib.rs | 16 +-- .../test_utils/execution_block_generator.rs | 8 +- .../src/test_utils/mock_builder.rs | 48 ++----- .../http_api/tests/interactive_tests.rs | 10 +- beacon_node/http_api/tests/status_tests.rs | 6 +- .../src/network_beacon_processor/tests.rs | 3 +- beacon_node/store/src/partial_beacon_state.rs | 31 ++++- consensus/state_processing/src/genesis.rs | 5 +- .../src/per_block_processing.rs | 13 +- .../state_processing/src/upgrade/gloas.rs | 21 ++- .../indexed_payload_attestation.rs | 36 +++++ consensus/types/src/attestation/mod.rs | 8 ++ .../src/attestation/payload_attestation.rs | 31 +++++ .../attestation/payload_attestation_data.rs | 28 ++++ .../payload_attestation_message.rs | 26 ++++ consensus/types/src/block/beacon_block.rs | 33 ++++- .../types/src/block/beacon_block_body.rs | 130 ++++++++++-------- .../types/src/block/signed_beacon_block.rs | 82 +++-------- consensus/types/src/builder/builder_bid.rs | 19 +-- .../src/builder/builder_pending_payment.rs | 36 +++++ .../src/builder/builder_pending_withdrawal.rs | 40 ++++++ consensus/types/src/builder/mod.rs | 6 +- consensus/types/src/core/chain_spec.rs | 21 +++ consensus/types/src/core/eth_spec.rs | 42 +++++- consensus/types/src/execution/dumb_macros.rs | 108 +++++++++++++++ .../types/src/execution/execution_payload.rs | 5 +- .../src/execution/execution_payload_bid.rs | 40 ++++++ .../execution/execution_payload_envelope.rs | 36 +++++ .../src/execution/execution_payload_header.rs | 104 +++----------- consensus/types/src/execution/mod.rs | 19 ++- consensus/types/src/execution/payload.rs | 53 ++----- .../execution/signed_execution_payload_bid.rs | 35 +++++ .../signed_execution_payload_envelope.rs | 24 ++++ consensus/types/src/fork/fork_context.rs | 2 + consensus/types/src/lib.rs | 10 ++ consensus/types/src/light_client/error.rs | 1 + .../light_client/light_client_bootstrap.rs | 45 ++---- .../light_client_finality_update.rs | 45 ++---- .../src/light_client/light_client_header.rs | 78 ++--------- .../light_client_optimistic_update.rs | 35 ++--- .../src/light_client/light_client_update.rs | 69 ++-------- consensus/types/src/light_client/mod.rs | 10 +- consensus/types/src/state/beacon_state.rs | 62 +++++++-- testing/ef_tests/src/cases/operations.rs | 3 + 52 files changed, 930 insertions(+), 689 deletions(-) create mode 100644 consensus/types/src/attestation/indexed_payload_attestation.rs create mode 100644 consensus/types/src/attestation/payload_attestation.rs create mode 100644 consensus/types/src/attestation/payload_attestation_data.rs create mode 100644 consensus/types/src/attestation/payload_attestation_message.rs create mode 100644 consensus/types/src/builder/builder_pending_payment.rs create mode 100644 consensus/types/src/builder/builder_pending_withdrawal.rs create mode 100644 consensus/types/src/execution/dumb_macros.rs create mode 100644 consensus/types/src/execution/execution_payload_bid.rs create mode 100644 consensus/types/src/execution/execution_payload_envelope.rs create mode 100644 consensus/types/src/execution/signed_execution_payload_bid.rs create mode 100644 consensus/types/src/execution/signed_execution_payload_envelope.rs diff --git a/Makefile b/Makefile index c14f1d712a..c1cccb9270 100644 --- a/Makefile +++ b/Makefile @@ -30,6 +30,11 @@ TEST_FEATURES ?= # Cargo profile for regular builds. PROFILE ?= release +# List of all hard forks up to gloas. This list is used to set env variables for several tests so that +# they run for different forks. +# TODO(EIP-7732) Remove this once we extend network tests to support gloas and use RECENT_FORKS instead +RECENT_FORKS_BEFORE_GLOAS=electra fulu + # List of all recent hard forks. This list is used to set env variables for http_api tests RECENT_FORKS=electra fulu gloas @@ -197,29 +202,31 @@ run-ef-tests: cargo nextest run --release -p ef_tests --features "ef_tests,$(EF_TEST_FEATURES),fake_crypto" ./$(EF_TESTS)/check_all_files_accessed.py $(EF_TESTS)/.accessed_file_log.txt $(EF_TESTS)/consensus-spec-tests -# Run the tests in the `beacon_chain` crate for recent forks. -test-beacon-chain: $(patsubst %,test-beacon-chain-%,$(RECENT_FORKS)) +# Run the tests in the `beacon_chain` crate for all known forks. +# TODO(EIP-7732) Extend to support gloas by using RECENT_FORKS instead +test-beacon-chain: $(patsubst %,test-beacon-chain-%,$(RECENT_FORKS_BEFORE_GLOAS)) test-beacon-chain-%: env FORK_NAME=$* cargo nextest run --release --features "fork_from_env,slasher/lmdb,$(TEST_FEATURES)" -p beacon_chain # Run the tests in the `http_api` crate for recent forks. -test-http-api: $(patsubst %,test-http-api-%,$(RECENT_FORKS)) +test-http-api: $(patsubst %,test-http-api-%,$(RECENT_FORKS_BEFORE_GLOAS)) test-http-api-%: env FORK_NAME=$* cargo nextest run --release --features "beacon_chain/fork_from_env" -p http_api # Run the tests in the `operation_pool` crate for all known forks. -test-op-pool: $(patsubst %,test-op-pool-%,$(RECENT_FORKS)) +test-op-pool: $(patsubst %,test-op-pool-%,$(RECENT_FORKS_BEFORE_GLOAS)) test-op-pool-%: env FORK_NAME=$* cargo nextest run --release \ --features "beacon_chain/fork_from_env,$(TEST_FEATURES)"\ -p operation_pool -# Run the tests in the `network` crate for recent forks. -test-network: $(patsubst %,test-network-%,$(RECENT_FORKS)) +# Run the tests in the `network` crate for all known forks. +# TODO(EIP-7732) Extend to support gloas by using RECENT_FORKS instead +test-network: $(patsubst %,test-network-%,$(RECENT_FORKS_BEFORE_GLOAS)) test-network-%: env FORK_NAME=$* cargo nextest run --release \ diff --git a/beacon_node/beacon_chain/src/beacon_block_streamer.rs b/beacon_node/beacon_chain/src/beacon_block_streamer.rs index 7b3bb03e56..a462376cc0 100644 --- a/beacon_node/beacon_chain/src/beacon_block_streamer.rs +++ b/beacon_node/beacon_chain/src/beacon_block_streamer.rs @@ -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::(); @@ -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()); diff --git a/beacon_node/beacon_chain/src/beacon_chain.rs b/beacon_node/beacon_chain/src/beacon_chain.rs index 2107f06e1e..46ba14f596 100644 --- a/beacon_node/beacon_chain/src/beacon_chain.rs +++ b/beacon_node/beacon_chain/src/beacon_chain.rs @@ -5795,60 +5795,7 @@ impl BeaconChain { 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( diff --git a/beacon_node/beacon_chain/src/errors.rs b/beacon_node/beacon_chain/src/errors.rs index 8f615baab4..b021df2c33 100644 --- a/beacon_node/beacon_chain/src/errors.rs +++ b/beacon_node/beacon_chain/src/errors.rs @@ -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); diff --git a/beacon_node/beacon_chain/src/test_utils.rs b/beacon_node/beacon_chain/src/test_utils.rs index 500c0b22d6..6d17d6d85c 100644 --- a/beacon_node/beacon_chain/src/test_utils.rs +++ b/beacon_node/beacon_chain/src/test_utils.rs @@ -3300,9 +3300,7 @@ pub fn generate_rand_block_and_blobs( SignedBeaconBlock::Fulu(SignedBeaconBlockFulu { ref mut message, .. }) => add_blob_transactions!(message, FullPayloadFulu, num_blobs, rng, fork_name), - SignedBeaconBlock::Gloas(SignedBeaconBlockGloas { - ref mut message, .. - }) => add_blob_transactions!(message, FullPayloadGloas, num_blobs, rng, fork_name), + // TODO(EIP-7732) Add `SignedBeaconBlock::Gloas` variant _ => return (block, blob_sidecars), }; diff --git a/beacon_node/beacon_chain/tests/store_tests.rs b/beacon_node/beacon_chain/tests/store_tests.rs index cc49f87184..ba0621ae72 100644 --- a/beacon_node/beacon_chain/tests/store_tests.rs +++ b/beacon_node/beacon_chain/tests/store_tests.rs @@ -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::(); @@ -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); diff --git a/beacon_node/execution_layer/src/engine_api.rs b/beacon_node/execution_layer/src/engine_api.rs index 88567ac6e1..32090bccfc 100644 --- a/beacon_node/execution_layer/src/engine_api.rs +++ b/beacon_node/execution_layer/src/engine_api.rs @@ -541,34 +541,6 @@ impl ExecutionPayloadBodyV1 { )) } } - 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 - )) - } - } } } } diff --git a/beacon_node/execution_layer/src/engine_api/new_payload_request.rs b/beacon_node/execution_layer/src/engine_api/new_payload_request.rs index 617d2e0112..ba94296b85 100644 --- a/beacon_node/execution_layer/src/engine_api/new_payload_request.rs +++ b/beacon_node/execution_layer/src/engine_api/new_payload_request.rs @@ -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> for NewPayloadRequest<'a, E> { type Error = BeaconStateError; @@ -220,17 +221,7 @@ impl<'a, E: EthSpec> TryFrom> 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> 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> for NewPayloadRequest { + #[cfg(test)] mod test { use crate::versioned_hashes::Error as VersionedHashError; diff --git a/beacon_node/execution_layer/src/lib.rs b/beacon_node/execution_layer/src/lib.rs index 34b1832894..554668dd8a 100644 --- a/beacon_node/execution_layer/src/lib.rs +++ b/beacon_node/execution_layer/src/lib.rs @@ -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 TryFrom> for ProvenancedPayload 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 ExecutionLayer { } /// 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 pub async fn notify_new_payload( &self, new_payload_request: NewPayloadRequest<'_, E>, @@ -1839,10 +1833,12 @@ impl ExecutionLayer { 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)); } 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 89d2994ce2..6b247a4cd4 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 @@ -909,12 +909,8 @@ pub fn generate_genesis_header( *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, } } diff --git a/beacon_node/execution_layer/src/test_utils/mock_builder.rs b/beacon_node/execution_layer/src/test_utils/mock_builder.rs index 1d4f36b62c..884aa9bf47 100644 --- a/beacon_node/execution_layer/src/test_utils/mock_builder.rs +++ b/beacon_node/execution_layer/src/test_utils/mock_builder.rs @@ -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 BidStuff for BuilderBid { ExecutionPayloadHeaderRefMut::Fulu(header) => { header.fee_recipient = fee_recipient; } - ExecutionPayloadHeaderRefMut::Gloas(header) => { - header.fee_recipient = fee_recipient; - } } } @@ -140,9 +137,6 @@ impl BidStuff for BuilderBid { ExecutionPayloadHeaderRefMut::Fulu(header) => { header.gas_limit = gas_limit; } - ExecutionPayloadHeaderRefMut::Gloas(header) => { - header.gas_limit = gas_limit; - } } } @@ -167,9 +161,6 @@ impl BidStuff for BuilderBid { 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 BidStuff for BuilderBid { ExecutionPayloadHeaderRefMut::Fulu(header) => { header.prev_randao = prev_randao; } - ExecutionPayloadHeaderRefMut::Gloas(header) => { - header.prev_randao = prev_randao; - } } } @@ -213,9 +201,6 @@ impl BidStuff for BuilderBid { ExecutionPayloadHeaderRefMut::Fulu(header) => { header.block_number = block_number; } - ExecutionPayloadHeaderRefMut::Gloas(header) => { - header.block_number = block_number; - } } } @@ -236,9 +221,6 @@ impl BidStuff for BuilderBid { ExecutionPayloadHeaderRefMut::Fulu(header) => { header.timestamp = timestamp; } - ExecutionPayloadHeaderRefMut::Gloas(header) => { - header.timestamp = timestamp; - } } } @@ -259,9 +241,6 @@ impl BidStuff for BuilderBid { ExecutionPayloadHeaderRefMut::Fulu(header) => { header.withdrawals_root = withdrawals_root; } - ExecutionPayloadHeaderRefMut::Gloas(header) => { - header.withdrawals_root = withdrawals_root; - } } } @@ -295,10 +274,6 @@ impl BidStuff for BuilderBid { 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 MockBuilder { 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 MockBuilder { ) = 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() diff --git a/beacon_node/http_api/tests/interactive_tests.rs b/beacon_node/http_api/tests/interactive_tests.rs index ce61c821b5..b04c812773 100644 --- a/beacon_node/http_api/tests/interactive_tests.rs +++ b/beacon_node/http_api/tests/interactive_tests.rs @@ -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::::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`. diff --git a/beacon_node/http_api/tests/status_tests.rs b/beacon_node/http_api/tests/status_tests.rs index fd5e282c5b..556b75cb85 100644 --- a/beacon_node/http_api/tests/status_tests.rs +++ b/beacon_node/http_api/tests/status_tests.rs @@ -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 { - // 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::::new(Some(spec), validator_count as usize).await; diff --git a/beacon_node/network/src/network_beacon_processor/tests.rs b/beacon_node/network/src/network_beacon_processor/tests.rs index 841a8679cf..ed04fe7bb9 100644 --- a/beacon_node/network/src/network_beacon_processor/tests.rs +++ b/beacon_node/network/src/network_beacon_processor/tests.rs @@ -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, diff --git a/beacon_node/store/src/partial_beacon_state.rs b/beacon_node/store/src/partial_beacon_state.rs index 8ee37169ac..9e5e1ebbb4 100644 --- a/beacon_node/store/src/partial_beacon_state.rs +++ b/beacon_node/store/src/partial_beacon_state.rs @@ -116,11 +116,12 @@ where partial_getter(rename = "latest_execution_payload_header_fulu") )] pub latest_execution_payload_header: ExecutionPayloadHeaderFulu, + #[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, + pub latest_execution_payload_bid: ExecutionPayloadBid, // Capella #[superstruct(only(Capella, Deneb, Electra, Fulu, Gloas))] @@ -155,6 +156,23 @@ where pub pending_consolidations: List, #[superstruct(only(Fulu, Gloas))] pub proposer_lookahead: Vector, + + // Gloas + #[superstruct(only(Gloas))] + pub execution_payload_availability: BitVector, + + #[superstruct(only(Gloas))] + pub builder_pending_payments: Vector, + + #[superstruct(only(Gloas))] + pub builder_pending_withdrawals: + List, + + #[superstruct(only(Gloas))] + pub latest_block_hash: ExecutionBlockHash, + + #[superstruct(only(Gloas))] + pub latest_withdrawals_root: Hash256, } impl PartialBeaconState { @@ -466,7 +484,7 @@ impl TryInto> for PartialBeaconState { 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 TryInto> for PartialBeaconState { 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] ), diff --git a/consensus/state_processing/src/genesis.rs b/consensus/state_processing/src/genesis.rs index d00e1fcfac..1575fce22f 100644 --- a/consensus/state_processing/src/genesis.rs +++ b/consensus/state_processing/src/genesis.rs @@ -168,9 +168,8 @@ pub fn initialize_beacon_state_from_eth1( state.fork_mut().previous_version = spec.gloas_fork_version; // Override latest execution payload header. - if let Some(ExecutionPayloadHeader::Gloas(header)) = execution_payload_header { - *state.latest_execution_payload_header_gloas_mut()? = header.clone(); - } + // Here's where we *would* clone the header but there is no header here so.. + // TODO(EIP7732): check this } // Now that we have our validators, initialize the caches (including the committees) diff --git a/consensus/state_processing/src/per_block_processing.rs b/consensus/state_processing/src/per_block_processing.rs index f78c8c4eb3..07149ff2ee 100644 --- a/consensus/state_processing/src/per_block_processing.rs +++ b/consensus/state_processing/src/per_block_processing.rs @@ -41,7 +41,6 @@ mod verify_exit; mod verify_proposer_slashing; use crate::common::decrease_balance; - use crate::common::update_progressive_balances_cache::{ initialize_progressive_balances_cache, update_progressive_balances_metrics, }; @@ -173,10 +172,14 @@ pub fn per_block_processing>( // previous block. if is_execution_enabled(state, block.body()) { let body = block.body(); + // TODO(EIP-7732): build out process_withdrawals variant for gloas process_withdrawals::(state, body.execution_payload()?, spec)?; process_execution_payload::(state, body, spec)?; } + // TODO(EIP-7732): build out process_execution_bid + // process_execution_bid(state, block, verify_signatures, spec)?; + process_randao(state, block, verify_randao, ctxt, spec)?; process_eth1_data(state, block.body().eth1_data())?; process_operations(state, block.body(), verify_signatures, ctxt, spec)?; @@ -453,12 +456,6 @@ pub fn process_execution_payload>( _ => return Err(BlockProcessingError::IncorrectStateType), } } - ExecutionPayloadHeaderRefMut::Gloas(header_mut) => { - match payload.to_execution_payload_header() { - ExecutionPayloadHeader::Gloas(header) => *header_mut = header, - _ => return Err(BlockProcessingError::IncorrectStateType), - } - } } Ok(()) @@ -470,6 +467,7 @@ pub fn process_execution_payload>( /// repeatedly write code to treat these errors as false. /// https://github.com/ethereum/consensus-specs/blob/dev/specs/bellatrix/beacon-chain.md#is_merge_transition_complete pub fn is_merge_transition_complete(state: &BeaconState) -> bool { + // TODO(EIP7732): check this cause potuz modified this function for god knows what reason if state.fork_name_unchecked().capella_enabled() { true } else if state.fork_name_unchecked().bellatrix_enabled() { @@ -638,6 +636,7 @@ pub fn get_expected_withdrawals( } /// Apply withdrawals to the state. +/// TODO(EIP-7732): abstract this out and create gloas variant pub fn process_withdrawals>( state: &mut BeaconState, payload: Payload::Ref<'_>, diff --git a/consensus/state_processing/src/upgrade/gloas.rs b/consensus/state_processing/src/upgrade/gloas.rs index 8bb6991bfb..d6c353cc2a 100644 --- a/consensus/state_processing/src/upgrade/gloas.rs +++ b/consensus/state_processing/src/upgrade/gloas.rs @@ -1,5 +1,11 @@ +use bls::Hash256; +use milhouse::{List, Vector}; +use ssz_types::BitVector; use std::mem; -use types::{BeaconState, BeaconStateError as Error, BeaconStateGloas, ChainSpec, EthSpec, Fork}; +use types::{ + BeaconState, BeaconStateError as Error, BeaconStateGloas, BuilderPendingPayment, ChainSpec, + EthSpec, ExecutionPayloadBid, Fork, +}; /// Transform a `Fulu` state into a `Gloas` state. pub fn upgrade_to_gloas( @@ -63,8 +69,8 @@ pub fn upgrade_state_to_gloas( // 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_gloas(), + // Execution Bid + latest_execution_payload_bid: ExecutionPayloadBid::default(), // Capella next_withdrawal_index: pre.next_withdrawal_index, next_withdrawal_validator_index: pre.next_withdrawal_validator_index, @@ -79,6 +85,15 @@ pub fn upgrade_state_to_gloas( pending_deposits: pre.pending_deposits.clone(), pending_partial_withdrawals: pre.pending_partial_withdrawals.clone(), pending_consolidations: pre.pending_consolidations.clone(), + // Gloas + execution_payload_availability: BitVector::default(), // All bits set to false initially + builder_pending_payments: Vector::new(vec![ + BuilderPendingPayment::default(); + E::builder_pending_payments_limit() + ])?, + builder_pending_withdrawals: List::default(), // Empty list initially, + latest_block_hash: pre.latest_execution_payload_header.block_hash, + latest_withdrawals_root: Hash256::default(), // Caches total_active_balance: pre.total_active_balance, progressive_balances_cache: mem::take(&mut pre.progressive_balances_cache), diff --git a/consensus/types/src/attestation/indexed_payload_attestation.rs b/consensus/types/src/attestation/indexed_payload_attestation.rs new file mode 100644 index 0000000000..4de805570c --- /dev/null +++ b/consensus/types/src/attestation/indexed_payload_attestation.rs @@ -0,0 +1,36 @@ +use crate::test_utils::TestRandom; +use crate::{EthSpec, ForkName, PayloadAttestationData}; +use bls::AggregateSignature; +use context_deserialize::context_deserialize; +use core::slice::Iter; +use serde::{Deserialize, Serialize}; +use ssz_derive::{Decode, Encode}; +use ssz_types::VariableList; +use test_random_derive::TestRandom; +use tree_hash_derive::TreeHash; + +#[derive(TestRandom, TreeHash, Debug, Clone, PartialEq, Encode, Decode, Serialize, Deserialize)] +#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] +#[serde(bound = "E: EthSpec", deny_unknown_fields)] +#[cfg_attr(feature = "arbitrary", arbitrary(bound = "E: EthSpec"))] +#[context_deserialize(ForkName)] +pub struct IndexedPayloadAttestation { + #[serde(with = "ssz_types::serde_utils::quoted_u64_var_list")] + pub attesting_indices: VariableList, + pub data: PayloadAttestationData, + pub signature: AggregateSignature, +} + +impl IndexedPayloadAttestation { + pub fn attesting_indices_iter(&self) -> Iter<'_, u64> { + self.attesting_indices.iter() + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::MainnetEthSpec; + + ssz_and_tree_hash_tests!(IndexedPayloadAttestation); +} diff --git a/consensus/types/src/attestation/mod.rs b/consensus/types/src/attestation/mod.rs index 2d2bf74e49..586d99bd90 100644 --- a/consensus/types/src/attestation/mod.rs +++ b/consensus/types/src/attestation/mod.rs @@ -5,7 +5,11 @@ mod attestation_duty; mod beacon_committee; mod checkpoint; mod indexed_attestation; +mod indexed_payload_attestation; mod participation_flags; +mod payload_attestation; +mod payload_attestation_data; +mod payload_attestation_message; mod pending_attestation; mod selection_proof; mod shuffling_id; @@ -26,7 +30,11 @@ pub use checkpoint::Checkpoint; pub use indexed_attestation::{ IndexedAttestation, IndexedAttestationBase, IndexedAttestationElectra, IndexedAttestationRef, }; +pub use indexed_payload_attestation::IndexedPayloadAttestation; pub use participation_flags::ParticipationFlags; +pub use payload_attestation::PayloadAttestation; +pub use payload_attestation_data::PayloadAttestationData; +pub use payload_attestation_message::PayloadAttestationMessage; pub use pending_attestation::PendingAttestation; pub use selection_proof::SelectionProof; pub use shuffling_id::AttestationShufflingId; diff --git a/consensus/types/src/attestation/payload_attestation.rs b/consensus/types/src/attestation/payload_attestation.rs new file mode 100644 index 0000000000..192a4a8fea --- /dev/null +++ b/consensus/types/src/attestation/payload_attestation.rs @@ -0,0 +1,31 @@ +use crate::attestation::payload_attestation_data::PayloadAttestationData; +use crate::test_utils::TestRandom; +use crate::{EthSpec, ForkName}; +use bls::AggregateSignature; +use context_deserialize::context_deserialize; +use educe::Educe; +use serde::{Deserialize, Serialize}; +use ssz::BitList; +use ssz_derive::{Decode, Encode}; +use test_random_derive::TestRandom; +use tree_hash_derive::TreeHash; + +#[derive(TestRandom, TreeHash, Debug, Clone, Encode, Decode, Serialize, Deserialize, Educe)] +#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] +#[serde(bound = "E: EthSpec", deny_unknown_fields)] +#[cfg_attr(feature = "arbitrary", arbitrary(bound = "E: EthSpec"))] +#[educe(PartialEq, Hash)] +#[context_deserialize(ForkName)] +pub struct PayloadAttestation { + pub aggregation_bits: BitList, + pub data: PayloadAttestationData, + pub signature: AggregateSignature, +} + +#[cfg(test)] +mod payload_attestation_tests { + use super::*; + use crate::MinimalEthSpec; + + ssz_and_tree_hash_tests!(PayloadAttestation); +} diff --git a/consensus/types/src/attestation/payload_attestation_data.rs b/consensus/types/src/attestation/payload_attestation_data.rs new file mode 100644 index 0000000000..58d36fd01d --- /dev/null +++ b/consensus/types/src/attestation/payload_attestation_data.rs @@ -0,0 +1,28 @@ +use crate::test_utils::TestRandom; +use crate::{ForkName, Hash256, SignedRoot, Slot}; +use context_deserialize::context_deserialize; +use serde::{Deserialize, Serialize}; +use ssz_derive::{Decode, Encode}; +use test_random_derive::TestRandom; +use tree_hash_derive::TreeHash; + +#[derive( + TestRandom, TreeHash, Debug, Clone, PartialEq, Eq, Encode, Decode, Serialize, Deserialize, Hash, +)] +#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] +#[context_deserialize(ForkName)] +pub struct PayloadAttestationData { + pub beacon_block_root: Hash256, + pub slot: Slot, + pub payload_present: bool, + pub blob_data_available: bool, +} + +impl SignedRoot for PayloadAttestationData {} + +#[cfg(test)] +mod payload_attestation_data_tests { + use super::*; + + ssz_and_tree_hash_tests!(PayloadAttestationData); +} diff --git a/consensus/types/src/attestation/payload_attestation_message.rs b/consensus/types/src/attestation/payload_attestation_message.rs new file mode 100644 index 0000000000..82e2137b09 --- /dev/null +++ b/consensus/types/src/attestation/payload_attestation_message.rs @@ -0,0 +1,26 @@ +use crate::ForkName; +use crate::attestation::payload_attestation_data::PayloadAttestationData; +use crate::test_utils::TestRandom; +use bls::Signature; +use context_deserialize::context_deserialize; +use serde::{Deserialize, Serialize}; +use ssz_derive::{Decode, Encode}; +use test_random_derive::TestRandom; +use tree_hash_derive::TreeHash; + +#[derive(TestRandom, TreeHash, Debug, Clone, PartialEq, Encode, Decode, Serialize, Deserialize)] +#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] +#[context_deserialize(ForkName)] +pub struct PayloadAttestationMessage { + #[serde(with = "serde_utils::quoted_u64")] + pub validator_index: u64, + pub data: PayloadAttestationData, + pub signature: Signature, +} + +#[cfg(test)] +mod tests { + use super::*; + + ssz_and_tree_hash_tests!(PayloadAttestationMessage); +} diff --git a/consensus/types/src/block/beacon_block.rs b/consensus/types/src/block/beacon_block.rs index a4e7e800bc..bee3cdb274 100644 --- a/consensus/types/src/block/beacon_block.rs +++ b/consensus/types/src/block/beacon_block.rs @@ -15,6 +15,7 @@ use tree_hash_derive::TreeHash; use typenum::Unsigned; use crate::{ + SignedExecutionPayloadBid, attestation::{AttestationBase, AttestationData, IndexedAttestationBase}, block::{ BeaconBlockBodyAltair, BeaconBlockBodyBase, BeaconBlockBodyBellatrix, @@ -694,15 +695,41 @@ impl> EmptyBlock for BeaconBlockGloa deposits: VariableList::empty(), voluntary_exits: VariableList::empty(), sync_aggregate: SyncAggregate::empty(), - execution_payload: Payload::Gloas::default(), bls_to_execution_changes: VariableList::empty(), - blob_kzg_commitments: VariableList::empty(), - execution_requests: ExecutionRequests::default(), + signed_execution_payload_bid: SignedExecutionPayloadBid::empty(), + payload_attestations: VariableList::empty(), + _phantom: PhantomData, }, } } } +// TODO(EIP-7732) Mark's branch had the following implementation but not sure if it's needed so will just add header below for reference +// impl> BeaconBlockEIP7732 { + +// TODO(EIP-7732) Look into whether we can remove this in the future since no blinded blocks post-gloas +impl From>> + for BeaconBlockGloas> +{ + fn from(block: BeaconBlockGloas>) -> Self { + let BeaconBlockGloas { + slot, + proposer_index, + parent_root, + state_root, + body, + } = block; + + BeaconBlockGloas { + slot, + proposer_index, + parent_root, + state_root, + body: body.into(), + } + } +} + // We can convert pre-Bellatrix blocks without payloads into blocks "with" payloads. impl From>> for BeaconBlockBase> diff --git a/consensus/types/src/block/beacon_block_body.rs b/consensus/types/src/block/beacon_block_body.rs index f85dd8909e..1a0b385900 100644 --- a/consensus/types/src/block/beacon_block_body.rs +++ b/consensus/types/src/block/beacon_block_body.rs @@ -13,18 +13,19 @@ use test_random_derive::TestRandom; use tree_hash::{BYTES_PER_CHUNK, TreeHash}; use tree_hash_derive::TreeHash; +use crate::payload_attestation::PayloadAttestation; use crate::{ + SignedExecutionPayloadBid, attestation::{AttestationBase, AttestationElectra, AttestationRef, AttestationRefMut}, core::{EthSpec, Graffiti, Hash256}, deposit::Deposit, execution::{ AbstractExecPayload, BlindedPayload, BlindedPayloadBellatrix, BlindedPayloadCapella, - BlindedPayloadDeneb, BlindedPayloadElectra, BlindedPayloadFulu, BlindedPayloadGloas, - Eth1Data, ExecutionPayload, ExecutionPayloadBellatrix, ExecutionPayloadCapella, - ExecutionPayloadDeneb, ExecutionPayloadElectra, ExecutionPayloadFulu, - ExecutionPayloadGloas, ExecutionRequests, FullPayload, FullPayloadBellatrix, - FullPayloadCapella, FullPayloadDeneb, FullPayloadElectra, FullPayloadFulu, - FullPayloadGloas, SignedBlsToExecutionChange, + BlindedPayloadDeneb, BlindedPayloadElectra, BlindedPayloadFulu, Eth1Data, ExecutionPayload, + ExecutionPayloadBellatrix, ExecutionPayloadCapella, ExecutionPayloadDeneb, + ExecutionPayloadElectra, ExecutionPayloadFulu, ExecutionPayloadGloas, ExecutionRequests, + FullPayload, FullPayloadBellatrix, FullPayloadCapella, FullPayloadDeneb, + FullPayloadElectra, FullPayloadFulu, SignedBlsToExecutionChange, }, exit::SignedVoluntaryExit, fork::{ForkName, map_fork_name}, @@ -157,17 +158,18 @@ pub struct BeaconBlockBody = FullPay #[superstruct(only(Fulu), partial_getter(rename = "execution_payload_fulu"))] #[serde(flatten)] pub execution_payload: Payload::Fulu, - #[superstruct(only(Gloas), partial_getter(rename = "execution_payload_gloas"))] - #[serde(flatten)] - pub execution_payload: Payload::Gloas, #[superstruct(only(Capella, Deneb, Electra, Fulu, Gloas))] pub bls_to_execution_changes: VariableList, - #[superstruct(only(Deneb, Electra, Fulu, Gloas))] + #[superstruct(only(Deneb, Electra, Fulu))] pub blob_kzg_commitments: KzgCommitments, - #[superstruct(only(Electra, Fulu, Gloas))] + #[superstruct(only(Electra, Fulu))] pub execution_requests: ExecutionRequests, - #[superstruct(only(Base, Altair))] + #[superstruct(only(Gloas))] + pub signed_execution_payload_bid: SignedExecutionPayloadBid, + #[superstruct(only(Gloas))] + pub payload_attestations: VariableList, E::MaxPayloadAttestations>, + #[superstruct(only(Base, Altair, Gloas))] #[metastruct(exclude_from(fields))] #[ssz(skip_serializing, skip_deserializing)] #[tree_hash(skip_hashing)] @@ -196,7 +198,7 @@ impl<'a, E: EthSpec, Payload: AbstractExecPayload> BeaconBlockBodyRef<'a, E, Self::Deneb(body) => Ok(Payload::Ref::from(&body.execution_payload)), Self::Electra(body) => Ok(Payload::Ref::from(&body.execution_payload)), Self::Fulu(body) => Ok(Payload::Ref::from(&body.execution_payload)), - Self::Gloas(body) => Ok(Payload::Ref::from(&body.execution_payload)), + Self::Gloas(_) => Err(BeaconStateError::IncorrectStateVariant), } } @@ -254,16 +256,19 @@ impl<'a, E: EthSpec, Payload: AbstractExecPayload> BeaconBlockBodyRef<'a, E, /// Produces the proof of inclusion for a `KzgCommitment` in `self.blob_kzg_commitments` /// at `index` using an existing proof for the `blob_kzg_commitments` field. + /// TODO(EIP7732) Investigate calling functions since this will no longer work for glas since no block_kzg_commitments in the body anymore pub fn complete_kzg_commitment_merkle_proof( &self, index: usize, kzg_commitments_proof: &[Hash256], ) -> Result, BeaconStateError> { match self { - Self::Base(_) | Self::Altair(_) | Self::Bellatrix(_) | Self::Capella(_) => { - Err(BeaconStateError::IncorrectStateVariant) - } - Self::Deneb(_) | Self::Electra(_) | Self::Fulu(_) | Self::Gloas(_) => { + Self::Base(_) + | Self::Altair(_) + | Self::Bellatrix(_) + | Self::Capella(_) + | Self::Gloas(_) => Err(BeaconStateError::IncorrectStateVariant), + Self::Deneb(_) | Self::Electra(_) | Self::Fulu(_) => { // We compute the branches by generating 2 merkle trees: // 1. Merkle tree for the `blob_kzg_commitments` List object // 2. Merkle tree for the `BeaconBlockBody` container @@ -541,6 +546,46 @@ impl From>> } } +// Post-Fulu block bodies without payloads can be converted into block bodies with payloads +// TODO(EIP-7732) Look into whether we can remove this in the future since no blinded blocks post-gloas +impl From>> + for BeaconBlockBodyGloas> +{ + fn from(body: BeaconBlockBodyGloas>) -> Self { + let BeaconBlockBodyGloas { + randao_reveal, + eth1_data, + graffiti, + proposer_slashings, + attester_slashings, + attestations, + deposits, + voluntary_exits, + sync_aggregate, + bls_to_execution_changes, + signed_execution_payload_bid, + payload_attestations, + _phantom, + } = body; + + BeaconBlockBodyGloas { + randao_reveal, + eth1_data, + graffiti, + proposer_slashings, + attester_slashings, + attestations, + deposits, + voluntary_exits, + sync_aggregate, + bls_to_execution_changes, + signed_execution_payload_bid, + payload_attestations, + _phantom: PhantomData, + } + } +} + // Likewise bodies with payloads can be transformed into bodies without. impl From>> for ( @@ -851,10 +896,10 @@ impl From>> deposits, voluntary_exits, sync_aggregate, - execution_payload: FullPayloadGloas { execution_payload }, bls_to_execution_changes, - blob_kzg_commitments, - execution_requests, + signed_execution_payload_bid, + payload_attestations, + _phantom, } = body; ( @@ -868,14 +913,12 @@ impl From>> deposits, voluntary_exits, sync_aggregate, - execution_payload: BlindedPayloadGloas { - execution_payload_header: From::from(&execution_payload), - }, bls_to_execution_changes, - blob_kzg_commitments: blob_kzg_commitments.clone(), - execution_requests, + signed_execution_payload_bid, + payload_attestations, + _phantom: PhantomData, }, - Some(execution_payload), + None, ) } } @@ -1075,39 +1118,8 @@ impl BeaconBlockBodyFulu> { impl BeaconBlockBodyGloas> { pub fn clone_as_blinded(&self) -> BeaconBlockBodyGloas> { - let BeaconBlockBodyGloas { - randao_reveal, - eth1_data, - graffiti, - proposer_slashings, - attester_slashings, - attestations, - deposits, - voluntary_exits, - sync_aggregate, - execution_payload: FullPayloadGloas { execution_payload }, - bls_to_execution_changes, - blob_kzg_commitments, - execution_requests, - } = self; - - BeaconBlockBodyGloas { - randao_reveal: randao_reveal.clone(), - eth1_data: eth1_data.clone(), - graffiti: *graffiti, - proposer_slashings: proposer_slashings.clone(), - attester_slashings: attester_slashings.clone(), - attestations: attestations.clone(), - deposits: deposits.clone(), - voluntary_exits: voluntary_exits.clone(), - sync_aggregate: sync_aggregate.clone(), - execution_payload: BlindedPayloadGloas { - execution_payload_header: execution_payload.into(), - }, - bls_to_execution_changes: bls_to_execution_changes.clone(), - blob_kzg_commitments: blob_kzg_commitments.clone(), - execution_requests: execution_requests.clone(), - } + let (block_body, _payload) = self.clone().into(); + block_body } } diff --git a/consensus/types/src/block/signed_beacon_block.rs b/consensus/types/src/block/signed_beacon_block.rs index e8927ee765..aeb3c18d95 100644 --- a/consensus/types/src/block/signed_beacon_block.rs +++ b/consensus/types/src/block/signed_beacon_block.rs @@ -17,19 +17,17 @@ use crate::{ block::{ BLOB_KZG_COMMITMENTS_INDEX, BeaconBlock, BeaconBlockAltair, BeaconBlockBase, BeaconBlockBellatrix, BeaconBlockBodyBellatrix, BeaconBlockBodyCapella, - BeaconBlockBodyDeneb, BeaconBlockBodyElectra, BeaconBlockBodyFulu, BeaconBlockBodyGloas, - BeaconBlockCapella, BeaconBlockDeneb, BeaconBlockElectra, BeaconBlockFulu, - BeaconBlockGloas, BeaconBlockHeader, BeaconBlockRef, BeaconBlockRefMut, - SignedBeaconBlockHeader, + BeaconBlockBodyDeneb, BeaconBlockBodyElectra, BeaconBlockBodyFulu, BeaconBlockCapella, + BeaconBlockDeneb, BeaconBlockElectra, BeaconBlockFulu, BeaconBlockGloas, BeaconBlockHeader, + BeaconBlockRef, BeaconBlockRefMut, SignedBeaconBlockHeader, }, core::{ChainSpec, Domain, Epoch, EthSpec, Hash256, SignedRoot, SigningData, Slot}, execution::{ AbstractExecPayload, BlindedPayload, BlindedPayloadBellatrix, BlindedPayloadCapella, - BlindedPayloadDeneb, BlindedPayloadElectra, BlindedPayloadFulu, BlindedPayloadGloas, - ExecutionPayload, ExecutionPayloadBellatrix, ExecutionPayloadCapella, - ExecutionPayloadDeneb, ExecutionPayloadElectra, ExecutionPayloadFulu, - ExecutionPayloadGloas, FullPayload, FullPayloadBellatrix, FullPayloadCapella, - FullPayloadDeneb, FullPayloadElectra, FullPayloadFulu, FullPayloadGloas, + BlindedPayloadDeneb, BlindedPayloadElectra, BlindedPayloadFulu, ExecutionPayload, + ExecutionPayloadBellatrix, ExecutionPayloadCapella, ExecutionPayloadDeneb, + ExecutionPayloadElectra, ExecutionPayloadFulu, FullPayload, FullPayloadBellatrix, + FullPayloadCapella, FullPayloadDeneb, FullPayloadElectra, FullPayloadFulu, }, fork::{Fork, ForkName, ForkVersionDecode, InconsistentFork, map_fork_name}, kzg_ext::format_kzg_commitments, @@ -675,59 +673,15 @@ impl SignedBeaconBlockFulu> { } } -impl SignedBeaconBlockGloas> { - pub fn into_full_block( - self, - execution_payload: ExecutionPayloadGloas, - ) -> SignedBeaconBlockGloas> { - let SignedBeaconBlockGloas { - message: - BeaconBlockGloas { - slot, - proposer_index, - parent_root, - state_root, - body: - BeaconBlockBodyGloas { - randao_reveal, - eth1_data, - graffiti, - proposer_slashings, - attester_slashings, - attestations, - deposits, - voluntary_exits, - sync_aggregate, - execution_payload: BlindedPayloadGloas { .. }, - bls_to_execution_changes, - blob_kzg_commitments, - execution_requests, - }, - }, - signature, - } = self; +// We can convert gloas blocks without payloads into blocks "with" payloads. +// TODO(EIP-7732) Look into whether we can remove this in the future since no blinded blocks post-gloas +impl From>> + for SignedBeaconBlockGloas> +{ + fn from(signed_block: SignedBeaconBlockGloas>) -> Self { + let SignedBeaconBlockGloas { message, signature } = signed_block; SignedBeaconBlockGloas { - message: BeaconBlockGloas { - slot, - proposer_index, - parent_root, - state_root, - body: BeaconBlockBodyGloas { - randao_reveal, - eth1_data, - graffiti, - proposer_slashings, - attester_slashings, - attestations, - deposits, - voluntary_exits, - sync_aggregate, - execution_payload: FullPayloadGloas { execution_payload }, - bls_to_execution_changes, - blob_kzg_commitments, - execution_requests, - }, - }, + message: message.into(), signature, } } @@ -756,9 +710,7 @@ impl SignedBeaconBlock> { (SignedBeaconBlock::Fulu(block), Some(ExecutionPayload::Fulu(payload))) => { SignedBeaconBlock::Fulu(block.into_full_block(payload)) } - (SignedBeaconBlock::Gloas(block), Some(ExecutionPayload::Gloas(payload))) => { - SignedBeaconBlock::Gloas(block.into_full_block(payload)) - } + (SignedBeaconBlock::Gloas(block), _) => SignedBeaconBlock::Gloas(block.into()), // avoid wildcard matching forks so that compiler will // direct us here when a new fork has been added (SignedBeaconBlock::Bellatrix(_), _) => return None, @@ -766,7 +718,7 @@ impl SignedBeaconBlock> { (SignedBeaconBlock::Deneb(_), _) => return None, (SignedBeaconBlock::Electra(_), _) => return None, (SignedBeaconBlock::Fulu(_), _) => return None, - (SignedBeaconBlock::Gloas(_), _) => return None, + // TODO(EIP-7732) Determine if need a match arm for gloas here }; Some(full_block) } diff --git a/consensus/types/src/builder/builder_bid.rs b/consensus/types/src/builder/builder_bid.rs index be9bb28155..1018fadb64 100644 --- a/consensus/types/src/builder/builder_bid.rs +++ b/consensus/types/src/builder/builder_bid.rs @@ -13,8 +13,7 @@ use crate::{ execution::{ ExecutionPayloadHeaderBellatrix, ExecutionPayloadHeaderCapella, ExecutionPayloadHeaderDeneb, ExecutionPayloadHeaderElectra, ExecutionPayloadHeaderFulu, - ExecutionPayloadHeaderGloas, ExecutionPayloadHeaderRef, ExecutionPayloadHeaderRefMut, - ExecutionRequests, + ExecutionPayloadHeaderRef, ExecutionPayloadHeaderRefMut, ExecutionRequests, }, fork::{ForkName, ForkVersionDecode}, kzg_ext::KzgCommitments, @@ -22,7 +21,7 @@ use crate::{ }; #[superstruct( - variants(Bellatrix, Capella, Deneb, Electra, Fulu, Gloas), + variants(Bellatrix, Capella, Deneb, Electra, Fulu), variant_attributes( derive( PartialEq, @@ -55,11 +54,9 @@ pub struct BuilderBid { pub header: ExecutionPayloadHeaderElectra, #[superstruct(only(Fulu), partial_getter(rename = "header_fulu"))] pub header: ExecutionPayloadHeaderFulu, - #[superstruct(only(Gloas), partial_getter(rename = "header_gloas"))] - pub header: ExecutionPayloadHeaderGloas, - #[superstruct(only(Deneb, Electra, Fulu, Gloas))] + #[superstruct(only(Deneb, Electra, Fulu))] pub blob_kzg_commitments: KzgCommitments, - #[superstruct(only(Electra, Fulu, Gloas))] + #[superstruct(only(Electra, Fulu))] pub execution_requests: ExecutionRequests, #[serde(with = "serde_utils::quoted_u256")] pub value: Uint256, @@ -92,7 +89,7 @@ impl ForkVersionDecode for BuilderBid { /// SSZ decode with explicit fork variant. fn from_ssz_bytes_by_fork(bytes: &[u8], fork_name: ForkName) -> Result { let builder_bid = match fork_name { - ForkName::Altair | ForkName::Base => { + ForkName::Altair | ForkName::Base | ForkName::Gloas => { return Err(ssz::DecodeError::BytesInvalid(format!( "unsupported fork for ExecutionPayloadHeader: {fork_name}", ))); @@ -104,7 +101,6 @@ impl ForkVersionDecode for BuilderBid { ForkName::Deneb => BuilderBid::Deneb(BuilderBidDeneb::from_ssz_bytes(bytes)?), ForkName::Electra => BuilderBid::Electra(BuilderBidElectra::from_ssz_bytes(bytes)?), ForkName::Fulu => BuilderBid::Fulu(BuilderBidFulu::from_ssz_bytes(bytes)?), - ForkName::Gloas => BuilderBid::Gloas(BuilderBidGloas::from_ssz_bytes(bytes)?), }; Ok(builder_bid) } @@ -160,10 +156,7 @@ impl<'de, E: EthSpec> ContextDeserialize<'de, ForkName> for BuilderBid { ForkName::Fulu => { Self::Fulu(Deserialize::deserialize(deserializer).map_err(convert_err)?) } - ForkName::Gloas => { - Self::Gloas(Deserialize::deserialize(deserializer).map_err(convert_err)?) - } - ForkName::Base | ForkName::Altair => { + ForkName::Base | ForkName::Altair | ForkName::Gloas => { return Err(serde::de::Error::custom(format!( "BuilderBid failed to deserialize: unsupported fork '{}'", context diff --git a/consensus/types/src/builder/builder_pending_payment.rs b/consensus/types/src/builder/builder_pending_payment.rs new file mode 100644 index 0000000000..0f1b68ad97 --- /dev/null +++ b/consensus/types/src/builder/builder_pending_payment.rs @@ -0,0 +1,36 @@ +use crate::test_utils::TestRandom; +use crate::{BuilderPendingWithdrawal, ForkName}; +use context_deserialize::context_deserialize; +use serde::{Deserialize, Serialize}; +use ssz_derive::{Decode, Encode}; +use test_random_derive::TestRandom; +use tree_hash_derive::TreeHash; + +#[derive( + Debug, + PartialEq, + Eq, + Hash, + Clone, + Default, + Serialize, + Deserialize, + Encode, + Decode, + TreeHash, + TestRandom, +)] +#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] +#[context_deserialize(ForkName)] +pub struct BuilderPendingPayment { + #[serde(with = "serde_utils::quoted_u64")] + pub weight: u64, + pub withdrawal: BuilderPendingWithdrawal, +} + +#[cfg(test)] +mod tests { + use super::*; + + ssz_and_tree_hash_tests!(BuilderPendingPayment); +} diff --git a/consensus/types/src/builder/builder_pending_withdrawal.rs b/consensus/types/src/builder/builder_pending_withdrawal.rs new file mode 100644 index 0000000000..436d331c00 --- /dev/null +++ b/consensus/types/src/builder/builder_pending_withdrawal.rs @@ -0,0 +1,40 @@ +use crate::test_utils::TestRandom; +use crate::{Address, Epoch, ForkName}; +use context_deserialize::context_deserialize; +use serde::{Deserialize, Serialize}; +use ssz_derive::{Decode, Encode}; +use test_random_derive::TestRandom; +use tree_hash_derive::TreeHash; + +#[derive( + Debug, + PartialEq, + Eq, + Hash, + Clone, + Default, + Serialize, + Deserialize, + Encode, + Decode, + TreeHash, + TestRandom, +)] +#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] +#[context_deserialize(ForkName)] +pub struct BuilderPendingWithdrawal { + #[serde(with = "serde_utils::address_hex")] + pub fee_recipient: Address, + #[serde(with = "serde_utils::quoted_u64")] + pub amount: u64, + #[serde(with = "serde_utils::quoted_u64")] + pub builder_index: u64, + pub withdrawable_epoch: Epoch, +} + +#[cfg(test)] +mod tests { + use super::*; + + ssz_and_tree_hash_tests!(BuilderPendingWithdrawal); +} diff --git a/consensus/types/src/builder/mod.rs b/consensus/types/src/builder/mod.rs index 88a8e6a01a..54d0ae4eb7 100644 --- a/consensus/types/src/builder/mod.rs +++ b/consensus/types/src/builder/mod.rs @@ -1,6 +1,10 @@ mod builder_bid; +mod builder_pending_payment; +mod builder_pending_withdrawal; pub use builder_bid::{ BuilderBid, BuilderBidBellatrix, BuilderBidCapella, BuilderBidDeneb, BuilderBidElectra, - BuilderBidFulu, BuilderBidGloas, SignedBuilderBid, + BuilderBidFulu, SignedBuilderBid, }; +pub use builder_pending_payment::BuilderPendingPayment; +pub use builder_pending_withdrawal::BuilderPendingWithdrawal; diff --git a/consensus/types/src/core/chain_spec.rs b/consensus/types/src/core/chain_spec.rs index c8052b502b..da3f9b90cc 100644 --- a/consensus/types/src/core/chain_spec.rs +++ b/consensus/types/src/core/chain_spec.rs @@ -36,6 +36,8 @@ pub enum Domain { SyncCommittee, ContributionAndProof, SyncCommitteeSelectionProof, + BeaconBuilder, + PTCAttester, ApplicationMask(ApplicationDomain), } @@ -89,6 +91,7 @@ pub struct ChainSpec { pub bls_withdrawal_prefix_byte: u8, pub eth1_address_withdrawal_prefix_byte: u8, pub compounding_withdrawal_prefix_byte: u8, + pub builder_withdrawal_prefix_byte: u8, /* * Time parameters @@ -127,6 +130,8 @@ pub struct ChainSpec { pub(crate) domain_voluntary_exit: u32, pub(crate) domain_selection_proof: u32, pub(crate) domain_aggregate_and_proof: u32, + pub(crate) domain_beacon_builder: u32, + pub(crate) domain_ptc_attester: u32, /* * Fork choice @@ -228,6 +233,8 @@ pub struct ChainSpec { pub gloas_fork_version: [u8; 4], /// The Gloas fork epoch is optional, with `None` representing "Gloas never happens". pub gloas_fork_epoch: Option, + pub builder_payment_threshold_numerator: u64, + pub builder_payment_threshold_denominator: u64, /* * Networking @@ -535,6 +542,8 @@ impl ChainSpec { Domain::VoluntaryExit => self.domain_voluntary_exit, Domain::SelectionProof => self.domain_selection_proof, Domain::AggregateAndProof => self.domain_aggregate_and_proof, + Domain::BeaconBuilder => self.domain_beacon_builder, + Domain::PTCAttester => self.domain_ptc_attester, Domain::SyncCommittee => self.domain_sync_committee, Domain::ContributionAndProof => self.domain_contribution_and_proof, Domain::SyncCommitteeSelectionProof => self.domain_sync_committee_selection_proof, @@ -972,6 +981,7 @@ impl ChainSpec { bls_withdrawal_prefix_byte: 0x00, eth1_address_withdrawal_prefix_byte: 0x01, compounding_withdrawal_prefix_byte: 0x02, + builder_withdrawal_prefix_byte: 0x03, /* * Time parameters @@ -1011,6 +1021,8 @@ impl ChainSpec { domain_voluntary_exit: 4, domain_selection_proof: 5, domain_aggregate_and_proof: 6, + domain_beacon_builder: 0x1B, + domain_ptc_attester: 0x0C, /* * Fork choice @@ -1131,6 +1143,8 @@ impl ChainSpec { */ gloas_fork_version: [0x07, 0x00, 0x00, 0x00], gloas_fork_epoch: None, + builder_payment_threshold_numerator: 6, + builder_payment_threshold_denominator: 10, /* * Network specific @@ -1333,6 +1347,7 @@ impl ChainSpec { bls_withdrawal_prefix_byte: 0x00, eth1_address_withdrawal_prefix_byte: 0x01, compounding_withdrawal_prefix_byte: 0x02, + builder_withdrawal_prefix_byte: 0x03, /* * Time parameters @@ -1372,6 +1387,8 @@ impl ChainSpec { domain_voluntary_exit: 4, domain_selection_proof: 5, domain_aggregate_and_proof: 6, + domain_beacon_builder: 0x1B, + domain_ptc_attester: 0x0C, /* * Fork choice @@ -1491,6 +1508,8 @@ impl ChainSpec { */ gloas_fork_version: [0x07, 0x00, 0x00, 0x64], gloas_fork_epoch: None, + builder_payment_threshold_numerator: 6, + builder_payment_threshold_denominator: 10, /* * Network specific @@ -2517,6 +2536,8 @@ mod tests { &spec, ); test_domain(Domain::SyncCommittee, spec.domain_sync_committee, &spec); + test_domain(Domain::BeaconBuilder, spec.domain_beacon_builder, &spec); + test_domain(Domain::PTCAttester, spec.domain_ptc_attester, &spec); // The builder domain index is zero let builder_domain_pre_mask = [0; 4]; diff --git a/consensus/types/src/core/eth_spec.rs b/consensus/types/src/core/eth_spec.rs index 72fd1ebc9e..74795fdfc3 100644 --- a/consensus/types/src/core/eth_spec.rs +++ b/consensus/types/src/core/eth_spec.rs @@ -171,6 +171,14 @@ pub trait EthSpec: 'static + Default + Sync + Send + Clone + Debug + PartialEq + type MaxWithdrawalRequestsPerPayload: Unsigned + Clone + Sync + Send + Debug + PartialEq; type MaxPendingDepositsPerEpoch: Unsigned + Clone + Sync + Send + Debug + PartialEq; + /* + * New in Gloas + */ + type PTCSize: Unsigned + Clone + Sync + Send + Debug + PartialEq; + type MaxPayloadAttestations: Unsigned + Clone + Sync + Send + Debug + PartialEq; + type BuilderPendingPaymentsLimit: Unsigned + Clone + Sync + Send + Debug + PartialEq; + type BuilderPendingWithdrawalsLimit: Unsigned + Clone + Sync + Send + Debug + PartialEq; + fn default_spec() -> ChainSpec; fn spec_name() -> EthSpecId; @@ -357,6 +365,16 @@ pub trait EthSpec: 'static + Default + Sync + Send + Clone + Debug + PartialEq + Self::PendingConsolidationsLimit::to_usize() } + /// Returns the `BUILDER_PENDING_PAYMENTS_LIMIT` constant for this specification. + fn builder_pending_payments_limit() -> usize { + Self::BuilderPendingPaymentsLimit::to_usize() + } + + /// Returns the `BUILDER_PENDING_WITHDRAWALS_LIMIT` constant for this specification. + fn builder_pending_withdrawals_limit() -> usize { + Self::BuilderPendingWithdrawalsLimit::to_usize() + } + /// Returns the `MAX_CONSOLIDATION_REQUESTS_PER_PAYLOAD` constant for this specification. fn max_consolidation_requests_per_payload() -> usize { Self::MaxConsolidationRequestsPerPayload::to_usize() @@ -402,6 +420,16 @@ pub trait EthSpec: 'static + Default + Sync + Send + Clone + Debug + PartialEq + fn proposer_lookahead_slots() -> usize { Self::ProposerLookaheadSlots::to_usize() } + + /// Returns the `PTCSize` constant for this specification. + fn ptc_size() -> usize { + Self::PTCSize::to_usize() + } + + /// Returns the `MaxPayloadAttestations` constant for this specification. + fn max_payload_attestations() -> usize { + Self::MaxPayloadAttestations::to_usize() + } } /// Macro to inherit some type values from another EthSpec. @@ -431,6 +459,8 @@ impl EthSpec for MainnetEthSpec { type EpochsPerSlashingsVector = U8192; type HistoricalRootsLimit = U16777216; type ValidatorRegistryLimit = U1099511627776; + type BuilderPendingPaymentsLimit = U64; // 2 * SLOTS_PER_EPOCH = 2 * 32 = 64 + type BuilderPendingWithdrawalsLimit = U1048576; type MaxProposerSlashings = U16; type MaxAttesterSlashings = U2; type MaxAttestations = U128; @@ -471,6 +501,8 @@ impl EthSpec for MainnetEthSpec { type MaxAttestationsElectra = U8; type MaxWithdrawalRequestsPerPayload = U16; type MaxPendingDepositsPerEpoch = U16; + type PTCSize = U512; + type MaxPayloadAttestations = U4; fn default_spec() -> ChainSpec { ChainSpec::mainnet() @@ -513,6 +545,7 @@ impl EthSpec for MinimalEthSpec { type CellsPerExtBlob = U128; type NumberOfColumns = U128; type ProposerLookaheadSlots = U16; // Derived from (MIN_SEED_LOOKAHEAD + 1) * SLOTS_PER_EPOCH + type BuilderPendingPaymentsLimit = U16; // 2 * SLOTS_PER_EPOCH = 2 * 8 = 16 params_from_eth_spec!(MainnetEthSpec { JustificationBitsLength, @@ -522,6 +555,7 @@ impl EthSpec for MinimalEthSpec { GenesisEpoch, HistoricalRootsLimit, ValidatorRegistryLimit, + BuilderPendingWithdrawalsLimit, MaxProposerSlashings, MaxAttesterSlashings, MaxAttestations, @@ -541,7 +575,9 @@ impl EthSpec for MinimalEthSpec { MaxAttesterSlashingsElectra, MaxAttestationsElectra, MaxDepositRequestsPerPayload, - MaxWithdrawalRequestsPerPayload + MaxWithdrawalRequestsPerPayload, + PTCSize, + MaxPayloadAttestations }); fn default_spec() -> ChainSpec { @@ -572,6 +608,8 @@ impl EthSpec for GnosisEthSpec { type EpochsPerSlashingsVector = U8192; type HistoricalRootsLimit = U16777216; type ValidatorRegistryLimit = U1099511627776; + type BuilderPendingPaymentsLimit = U32; // 2 * SLOTS_PER_EPOCH = 2 * 16 = 32 + type BuilderPendingWithdrawalsLimit = U1048576; type MaxProposerSlashings = U16; type MaxAttesterSlashings = U2; type MaxAttestations = U128; @@ -612,6 +650,8 @@ impl EthSpec for GnosisEthSpec { type CellsPerExtBlob = U128; type NumberOfColumns = U128; type ProposerLookaheadSlots = U32; // Derived from (MIN_SEED_LOOKAHEAD + 1) * SLOTS_PER_EPOCH + type PTCSize = U512; + type MaxPayloadAttestations = U2; fn default_spec() -> ChainSpec { ChainSpec::gnosis() diff --git a/consensus/types/src/execution/dumb_macros.rs b/consensus/types/src/execution/dumb_macros.rs new file mode 100644 index 0000000000..4eae416bb5 --- /dev/null +++ b/consensus/types/src/execution/dumb_macros.rs @@ -0,0 +1,108 @@ +// These would usually be created by superstuct but now there's no longer a 1:1 mapping between +// the variants for ExecutionPayload and the variants for +// - ExecutionPayloadHeader +// - FullPayload +// - BlindedPayload +// TODO(EIP-7732): get rid of this whole file and panics once the engine_api is refactored for ePBS + +#[macro_export] +macro_rules! map_execution_payload_into_full_payload { + ($value:expr, $f:expr) => { + match $value { + ExecutionPayload::Bellatrix(inner) => { + let f: fn(ExecutionPayloadBellatrix<_>, fn(_) -> _) -> _ = $f; + f(inner, FullPayload::Bellatrix) + } + ExecutionPayload::Capella(inner) => { + let f: fn(ExecutionPayloadCapella<_>, fn(_) -> _) -> _ = $f; + f(inner, FullPayload::Capella) + } + ExecutionPayload::Deneb(inner) => { + let f: fn(ExecutionPayloadDeneb<_>, fn(_) -> _) -> _ = $f; + f(inner, FullPayload::Deneb) + } + ExecutionPayload::Electra(inner) => { + let f: fn(ExecutionPayloadElectra<_>, fn(_) -> _) -> _ = $f; + f(inner, FullPayload::Electra) + } + ExecutionPayload::Fulu(inner) => { + let f: fn(ExecutionPayloadFulu<_>, fn(_) -> _) -> _ = $f; + f(inner, FullPayload::Fulu) + } + ExecutionPayload::Gloas(_) => panic!("FullPayload::Gloas does not exist!"), + } + }; +} + +#[macro_export] +macro_rules! map_execution_payload_into_blinded_payload { + ($value:expr, $f:expr) => { + match $value { + ExecutionPayload::Bellatrix(inner) => { + let f: fn(ExecutionPayloadBellatrix<_>, fn(_) -> _) -> _ = $f; + f(inner, BlindedPayload::Bellatrix) + } + ExecutionPayload::Capella(inner) => { + let f: fn(ExecutionPayloadCapella<_>, fn(_) -> _) -> _ = $f; + f(inner, BlindedPayload::Capella) + } + ExecutionPayload::Deneb(inner) => { + let f: fn(ExecutionPayloadDeneb<_>, fn(_) -> _) -> _ = $f; + f(inner, BlindedPayload::Deneb) + } + ExecutionPayload::Electra(inner) => { + let f: fn(ExecutionPayloadElectra<_>, fn(_) -> _) -> _ = $f; + f(inner, BlindedPayload::Electra) + } + ExecutionPayload::Fulu(inner) => { + let f: fn(ExecutionPayloadFulu<_>, fn(_) -> _) -> _ = $f; + f(inner, BlindedPayload::Fulu) + } + ExecutionPayload::Gloas(_) => panic!("BlindedPayload::Gloas does not exist!"), + } + }; +} + +#[macro_export] +macro_rules! map_execution_payload_ref_into_execution_payload_header { + (&$lifetime:tt _, $value:expr, $f:expr) => { + match $value { + ExecutionPayloadRef::Bellatrix(inner) => { + let f: fn( + &$lifetime ExecutionPayloadBellatrix<_>, + fn(_) -> _, + ) -> _ = $f; + f(inner, ExecutionPayloadHeader::Bellatrix) + } + ExecutionPayloadRef::Capella(inner) => { + let f: fn( + &$lifetime ExecutionPayloadCapella<_>, + fn(_) -> _, + ) -> _ = $f; + f(inner, ExecutionPayloadHeader::Capella) + } + ExecutionPayloadRef::Deneb(inner) => { + let f: fn( + &$lifetime ExecutionPayloadDeneb<_>, + fn(_) -> _, + ) -> _ = $f; + f(inner, ExecutionPayloadHeader::Deneb) + } + ExecutionPayloadRef::Electra(inner) => { + let f: fn( + &$lifetime ExecutionPayloadElectra<_>, + fn(_) -> _, + ) -> _ = $f; + f(inner, ExecutionPayloadHeader::Electra) + } + ExecutionPayloadRef::Fulu(inner) => { + let f: fn( + &$lifetime ExecutionPayloadFulu<_>, + fn(_) -> _, + ) -> _ = $f; + f(inner, ExecutionPayloadHeader::Fulu) + } + ExecutionPayloadRef::Gloas(_) => panic!("ExecutionPayloadHeader::Gloas does not exist!"), + } + } +} diff --git a/consensus/types/src/execution/execution_payload.rs b/consensus/types/src/execution/execution_payload.rs index 7973b7efdc..b2278c9166 100644 --- a/consensus/types/src/execution/execution_payload.rs +++ b/consensus/types/src/execution/execution_payload.rs @@ -55,9 +55,7 @@ pub type Transactions = VariableList< partial_getter_error( ty = "BeaconStateError", expr = "BeaconStateError::IncorrectStateVariant" - ), - map_into(FullPayload, BlindedPayload), - map_ref_into(ExecutionPayloadHeader) + ) )] #[cfg_attr( feature = "arbitrary", @@ -146,6 +144,7 @@ impl ForkVersionDecode for ExecutionPayload { impl ExecutionPayload { #[allow(clippy::arithmetic_side_effects)] /// Returns the maximum size of an execution payload. + /// TODO(EIP-7732): this seems to only exist for the Bellatrix fork, but Mark's branch has it for all the forks, i.e. max_execution_payload_eip7732_size pub fn max_execution_payload_bellatrix_size() -> usize { // Fixed part ExecutionPayloadBellatrix::::default().as_ssz_bytes().len() diff --git a/consensus/types/src/execution/execution_payload_bid.rs b/consensus/types/src/execution/execution_payload_bid.rs new file mode 100644 index 0000000000..20e461334d --- /dev/null +++ b/consensus/types/src/execution/execution_payload_bid.rs @@ -0,0 +1,40 @@ +use crate::test_utils::TestRandom; +use crate::{Address, ExecutionBlockHash, ForkName, Hash256, SignedRoot, Slot}; +use context_deserialize::context_deserialize; +use educe::Educe; +use serde::{Deserialize, Serialize}; +use ssz_derive::{Decode, Encode}; +use test_random_derive::TestRandom; +use tree_hash_derive::TreeHash; + +#[derive( + Default, Debug, Clone, Serialize, Encode, Decode, Deserialize, TreeHash, Educe, TestRandom, +)] +#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] +#[educe(PartialEq, Hash)] +#[context_deserialize(ForkName)] +// https://github.com/ethereum/consensus-specs/blob/master/specs/gloas/beacon-chain.md#executionpayloadbid +pub struct ExecutionPayloadBid { + pub parent_block_hash: ExecutionBlockHash, + pub parent_block_root: Hash256, + pub block_hash: ExecutionBlockHash, + #[serde(with = "serde_utils::address_hex")] + pub fee_recipient: Address, + #[serde(with = "serde_utils::quoted_u64")] + pub gas_limit: u64, + #[serde(with = "serde_utils::quoted_u64")] + pub builder_index: u64, + pub slot: Slot, + #[serde(with = "serde_utils::quoted_u64")] + pub value: u64, + pub blob_kzg_commitments_root: Hash256, +} + +impl SignedRoot for ExecutionPayloadBid {} + +#[cfg(test)] +mod tests { + use super::*; + + ssz_and_tree_hash_tests!(ExecutionPayloadBid); +} diff --git a/consensus/types/src/execution/execution_payload_envelope.rs b/consensus/types/src/execution/execution_payload_envelope.rs new file mode 100644 index 0000000000..64e03cec5a --- /dev/null +++ b/consensus/types/src/execution/execution_payload_envelope.rs @@ -0,0 +1,36 @@ +use crate::test_utils::TestRandom; +use crate::{ + EthSpec, ExecutionPayloadGloas, ExecutionRequests, ForkName, Hash256, KzgCommitments, + SignedRoot, Slot, +}; +use context_deserialize::context_deserialize; +use educe::Educe; +use serde::{Deserialize, Serialize}; +use ssz_derive::{Decode, Encode}; +use test_random_derive::TestRandom; +use tree_hash_derive::TreeHash; + +#[derive(Debug, Clone, Serialize, Encode, Decode, Deserialize, TestRandom, TreeHash, Educe)] +#[educe(PartialEq, Hash(bound(E: EthSpec)))] +#[context_deserialize(ForkName)] +#[serde(bound = "E: EthSpec")] +pub struct ExecutionPayloadEnvelope { + pub payload: ExecutionPayloadGloas, + pub execution_requests: ExecutionRequests, + #[serde(with = "serde_utils::quoted_u64")] + pub builder_index: u64, + pub beacon_block_root: Hash256, + pub slot: Slot, + pub blob_kzg_commitments: KzgCommitments, + pub state_root: Hash256, +} + +impl SignedRoot for ExecutionPayloadEnvelope {} + +#[cfg(test)] +mod tests { + use super::*; + use crate::MainnetEthSpec; + + ssz_and_tree_hash_tests!(ExecutionPayloadEnvelope); +} diff --git a/consensus/types/src/execution/execution_payload_header.rs b/consensus/types/src/execution/execution_payload_header.rs index bd91a6471b..cf78f7871b 100644 --- a/consensus/types/src/execution/execution_payload_header.rs +++ b/consensus/types/src/execution/execution_payload_header.rs @@ -14,16 +14,17 @@ use crate::{ core::{Address, EthSpec, Hash256, Uint256}, execution::{ ExecutionBlockHash, ExecutionPayloadBellatrix, ExecutionPayloadCapella, - ExecutionPayloadDeneb, ExecutionPayloadElectra, ExecutionPayloadFulu, - ExecutionPayloadGloas, ExecutionPayloadRef, Transactions, + ExecutionPayloadDeneb, ExecutionPayloadElectra, ExecutionPayloadFulu, ExecutionPayloadRef, + Transactions, }, fork::ForkName, + map_execution_payload_ref_into_execution_payload_header, state::BeaconStateError, test_utils::TestRandom, }; #[superstruct( - variants(Bellatrix, Capella, Deneb, Electra, Fulu, Gloas), + variants(Bellatrix, Capella, Deneb, Electra, Fulu), variant_attributes( derive( Default, @@ -105,12 +106,12 @@ pub struct ExecutionPayloadHeader { pub block_hash: ExecutionBlockHash, #[superstruct(getter(copy))] pub transactions_root: Hash256, - #[superstruct(only(Capella, Deneb, Electra, Fulu, Gloas), partial_getter(copy))] + #[superstruct(only(Capella, Deneb, Electra, Fulu), partial_getter(copy))] pub withdrawals_root: Hash256, - #[superstruct(only(Deneb, Electra, Fulu, Gloas), partial_getter(copy))] + #[superstruct(only(Deneb, Electra, Fulu), partial_getter(copy))] #[serde(with = "serde_utils::quoted_u64")] pub blob_gas_used: u64, - #[superstruct(only(Deneb, Electra, Fulu, Gloas), partial_getter(copy))] + #[superstruct(only(Deneb, Electra, Fulu), partial_getter(copy))] #[serde(with = "serde_utils::quoted_u64")] pub excess_blob_gas: u64, } @@ -136,14 +137,19 @@ impl ExecutionPayloadHeader { ExecutionPayloadHeaderElectra::from_ssz_bytes(bytes).map(Self::Electra) } ForkName::Fulu => ExecutionPayloadHeaderFulu::from_ssz_bytes(bytes).map(Self::Fulu), - ForkName::Gloas => ExecutionPayloadHeaderGloas::from_ssz_bytes(bytes).map(Self::Gloas), + ForkName::Gloas => Err(ssz::DecodeError::BytesInvalid(format!( + "unsupported fork for ExecutionPayloadHeader: {fork_name}", + ))), } } #[allow(clippy::arithmetic_side_effects)] pub fn ssz_max_var_len_for_fork(fork_name: ForkName) -> usize { // TODO(newfork): Add a new case here if there are new variable fields - if fork_name.bellatrix_enabled() { + if fork_name.gloas_enabled() { + // TODO(EIP7732): check this + 0 + } else if fork_name.bellatrix_enabled() { // Max size of variable length `extra_data` field E::max_extra_data_bytes() * ::ssz_fixed_len() } else { @@ -158,7 +164,6 @@ impl ExecutionPayloadHeader { ExecutionPayloadHeader::Deneb(_) => ForkName::Deneb, ExecutionPayloadHeader::Electra(_) => ForkName::Electra, ExecutionPayloadHeader::Fulu(_) => ForkName::Fulu, - ExecutionPayloadHeader::Gloas(_) => ForkName::Gloas, } } } @@ -266,30 +271,6 @@ impl ExecutionPayloadHeaderElectra { } } -impl ExecutionPayloadHeaderFulu { - pub fn upgrade_to_gloas(&self) -> ExecutionPayloadHeaderGloas { - ExecutionPayloadHeaderGloas { - 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, - withdrawals_root: self.withdrawals_root, - blob_gas_used: self.blob_gas_used, - excess_blob_gas: self.excess_blob_gas, - } - } -} - impl<'a, E: EthSpec> From<&'a ExecutionPayloadBellatrix> for ExecutionPayloadHeaderBellatrix { fn from(payload: &'a ExecutionPayloadBellatrix) -> Self { Self { @@ -405,30 +386,6 @@ impl<'a, E: EthSpec> From<&'a ExecutionPayloadFulu> for ExecutionPayloadHeade } } -impl<'a, E: EthSpec> From<&'a ExecutionPayloadGloas> for ExecutionPayloadHeaderGloas { - fn from(payload: &'a ExecutionPayloadGloas) -> Self { - Self { - parent_hash: payload.parent_hash, - fee_recipient: payload.fee_recipient, - state_root: payload.state_root, - receipts_root: payload.receipts_root, - logs_bloom: payload.logs_bloom.clone(), - prev_randao: payload.prev_randao, - block_number: payload.block_number, - gas_limit: payload.gas_limit, - gas_used: payload.gas_used, - timestamp: payload.timestamp, - extra_data: payload.extra_data.clone(), - base_fee_per_gas: payload.base_fee_per_gas, - block_hash: payload.block_hash, - transactions_root: payload.transactions.tree_hash_root(), - withdrawals_root: payload.withdrawals.tree_hash_root(), - blob_gas_used: payload.blob_gas_used, - excess_blob_gas: payload.excess_blob_gas, - } - } -} - // These impls are required to work around an inelegance in `to_execution_payload_header`. // They only clone headers so they should be relatively cheap. impl<'a, E: EthSpec> From<&'a Self> for ExecutionPayloadHeaderBellatrix { @@ -461,12 +418,6 @@ impl<'a, E: EthSpec> From<&'a Self> for ExecutionPayloadHeaderFulu { } } -impl<'a, E: EthSpec> From<&'a Self> for ExecutionPayloadHeaderGloas { - fn from(payload: &'a Self) -> Self { - payload.clone() - } -} - impl<'a, E: EthSpec> From> for ExecutionPayloadHeader { fn from(payload: ExecutionPayloadRef<'a, E>) -> Self { map_execution_payload_ref_into_execution_payload_header!( @@ -528,9 +479,6 @@ impl ExecutionPayloadHeaderRefMut<'_, E> { ExecutionPayloadHeaderRefMut::Fulu(mut_ref) => { *mut_ref = header.try_into()?; } - ExecutionPayloadHeaderRefMut::Gloas(mut_ref) => { - *mut_ref = header.try_into()?; - } } Ok(()) } @@ -558,16 +506,6 @@ impl TryFrom> for ExecutionPayloadHeaderFu } } -impl TryFrom> for ExecutionPayloadHeaderGloas { - type Error = BeaconStateError; - fn try_from(header: ExecutionPayloadHeader) -> Result { - match header { - ExecutionPayloadHeader::Gloas(execution_payload_header) => Ok(execution_payload_header), - _ => Err(BeaconStateError::IncorrectStateVariant), - } - } -} - impl<'de, E: EthSpec> ContextDeserialize<'de, ForkName> for ExecutionPayloadHeader { fn context_deserialize(deserializer: D, context: ForkName) -> Result where @@ -580,12 +518,6 @@ impl<'de, E: EthSpec> ContextDeserialize<'de, ForkName> for ExecutionPayloadHead )) }; Ok(match context { - ForkName::Base | ForkName::Altair => { - return Err(serde::de::Error::custom(format!( - "ExecutionPayloadHeader failed to deserialize: unsupported fork '{}'", - context - ))); - } ForkName::Bellatrix => { Self::Bellatrix(Deserialize::deserialize(deserializer).map_err(convert_err)?) } @@ -601,8 +533,12 @@ impl<'de, E: EthSpec> ContextDeserialize<'de, ForkName> for ExecutionPayloadHead ForkName::Fulu => { Self::Fulu(Deserialize::deserialize(deserializer).map_err(convert_err)?) } - ForkName::Gloas => { - Self::Gloas(Deserialize::deserialize(deserializer).map_err(convert_err)?) + + ForkName::Base | ForkName::Altair | ForkName::Gloas => { + return Err(serde::de::Error::custom(format!( + "ExecutionPayloadHeader failed to deserialize: unsupported fork '{}'", + context + ))); } }) } diff --git a/consensus/types/src/execution/mod.rs b/consensus/types/src/execution/mod.rs index 0708bc5d96..da6c860600 100644 --- a/consensus/types/src/execution/mod.rs +++ b/consensus/types/src/execution/mod.rs @@ -4,10 +4,15 @@ mod execution_block_header; #[macro_use] mod execution_payload; mod bls_to_execution_change; +mod dumb_macros; +mod execution_payload_bid; +mod execution_payload_envelope; mod execution_payload_header; mod execution_requests; mod payload; mod signed_bls_to_execution_change; +mod signed_execution_payload_bid; +mod signed_execution_payload_envelope; pub use bls_to_execution_change::BlsToExecutionChange; pub use eth1_data::Eth1Data; @@ -18,19 +23,23 @@ pub use execution_payload::{ ExecutionPayloadElectra, ExecutionPayloadFulu, ExecutionPayloadGloas, ExecutionPayloadRef, Transaction, Transactions, }; +pub use execution_payload_bid::ExecutionPayloadBid; +pub use execution_payload_envelope::ExecutionPayloadEnvelope; pub use execution_payload_header::{ ExecutionPayloadHeader, ExecutionPayloadHeaderBellatrix, ExecutionPayloadHeaderCapella, ExecutionPayloadHeaderDeneb, ExecutionPayloadHeaderElectra, ExecutionPayloadHeaderFulu, - ExecutionPayloadHeaderGloas, ExecutionPayloadHeaderRef, ExecutionPayloadHeaderRefMut, + ExecutionPayloadHeaderRef, ExecutionPayloadHeaderRefMut, }; pub use execution_requests::{ ConsolidationRequests, DepositRequests, ExecutionRequests, RequestType, WithdrawalRequests, }; pub use payload::{ AbstractExecPayload, BlindedPayload, BlindedPayloadBellatrix, BlindedPayloadCapella, - BlindedPayloadDeneb, BlindedPayloadElectra, BlindedPayloadFulu, BlindedPayloadGloas, - BlindedPayloadRef, BlockProductionVersion, BlockType, ExecPayload, FullPayload, - FullPayloadBellatrix, FullPayloadCapella, FullPayloadDeneb, FullPayloadElectra, - FullPayloadFulu, FullPayloadGloas, FullPayloadRef, OwnedExecPayload, + BlindedPayloadDeneb, BlindedPayloadElectra, BlindedPayloadFulu, BlindedPayloadRef, + BlockProductionVersion, BlockType, ExecPayload, FullPayload, FullPayloadBellatrix, + FullPayloadCapella, FullPayloadDeneb, FullPayloadElectra, FullPayloadFulu, FullPayloadRef, + OwnedExecPayload, }; pub use signed_bls_to_execution_change::SignedBlsToExecutionChange; +pub use signed_execution_payload_bid::SignedExecutionPayloadBid; +pub use signed_execution_payload_envelope::SignedExecutionPayloadEnvelope; diff --git a/consensus/types/src/execution/payload.rs b/consensus/types/src/execution/payload.rs index c1cc6c4eb6..703b082c18 100644 --- a/consensus/types/src/execution/payload.rs +++ b/consensus/types/src/execution/payload.rs @@ -15,11 +15,12 @@ use crate::{ execution::{ ExecutionBlockHash, ExecutionPayload, ExecutionPayloadBellatrix, ExecutionPayloadCapella, ExecutionPayloadDeneb, ExecutionPayloadElectra, ExecutionPayloadFulu, - ExecutionPayloadGloas, ExecutionPayloadHeader, ExecutionPayloadHeaderBellatrix, - ExecutionPayloadHeaderCapella, ExecutionPayloadHeaderDeneb, ExecutionPayloadHeaderElectra, - ExecutionPayloadHeaderFulu, ExecutionPayloadHeaderGloas, ExecutionPayloadRef, Transactions, + ExecutionPayloadHeader, ExecutionPayloadHeaderBellatrix, ExecutionPayloadHeaderCapella, + ExecutionPayloadHeaderDeneb, ExecutionPayloadHeaderElectra, ExecutionPayloadHeaderFulu, + ExecutionPayloadRef, Transactions, }, fork::ForkName, + map_execution_payload_into_blinded_payload, map_execution_payload_into_full_payload, state::BeaconStateError, test_utils::TestRandom, }; @@ -118,7 +119,6 @@ pub trait AbstractExecPayload: + TryInto + TryInto + TryInto - + TryInto + Sync { type Ref<'a>: ExecPayload @@ -127,8 +127,7 @@ pub trait AbstractExecPayload: + From<&'a Self::Capella> + From<&'a Self::Deneb> + From<&'a Self::Electra> - + From<&'a Self::Fulu> - + From<&'a Self::Gloas>; + + From<&'a Self::Fulu>; type Bellatrix: OwnedExecPayload + Into @@ -155,15 +154,10 @@ pub trait AbstractExecPayload: + for<'a> From>> + TryFrom> + Sync; - type Gloas: OwnedExecPayload - + Into - + for<'a> From>> - + TryFrom> - + Sync; } #[superstruct( - variants(Bellatrix, Capella, Deneb, Electra, Fulu, Gloas), + variants(Bellatrix, Capella, Deneb, Electra, Fulu), variant_attributes( derive( Debug, @@ -224,8 +218,6 @@ pub struct FullPayload { pub execution_payload: ExecutionPayloadElectra, #[superstruct(only(Fulu), partial_getter(rename = "execution_payload_fulu"))] pub execution_payload: ExecutionPayloadFulu, - #[superstruct(only(Gloas), partial_getter(rename = "execution_payload_gloas"))] - pub execution_payload: ExecutionPayloadGloas, } impl From> for ExecutionPayload { @@ -337,7 +329,6 @@ impl ExecPayload for FullPayload { FullPayload::Deneb(inner) => Ok(inner.execution_payload.withdrawals.tree_hash_root()), FullPayload::Electra(inner) => Ok(inner.execution_payload.withdrawals.tree_hash_root()), FullPayload::Fulu(inner) => Ok(inner.execution_payload.withdrawals.tree_hash_root()), - FullPayload::Gloas(inner) => Ok(inner.execution_payload.withdrawals.tree_hash_root()), } } @@ -349,7 +340,6 @@ impl ExecPayload for FullPayload { FullPayload::Deneb(inner) => Ok(inner.execution_payload.blob_gas_used), FullPayload::Electra(inner) => Ok(inner.execution_payload.blob_gas_used), FullPayload::Fulu(inner) => Ok(inner.execution_payload.blob_gas_used), - FullPayload::Gloas(inner) => Ok(inner.execution_payload.blob_gas_used), } } @@ -381,7 +371,7 @@ impl FullPayload { ForkName::Deneb => Ok(FullPayloadDeneb::default().into()), ForkName::Electra => Ok(FullPayloadElectra::default().into()), ForkName::Fulu => Ok(FullPayloadFulu::default().into()), - ForkName::Gloas => Ok(FullPayloadGloas::default().into()), + ForkName::Gloas => Err(BeaconStateError::IncorrectStateVariant), } } } @@ -482,9 +472,6 @@ impl ExecPayload for FullPayloadRef<'_, E> { Ok(inner.execution_payload.withdrawals.tree_hash_root()) } FullPayloadRef::Fulu(inner) => Ok(inner.execution_payload.withdrawals.tree_hash_root()), - FullPayloadRef::Gloas(inner) => { - Ok(inner.execution_payload.withdrawals.tree_hash_root()) - } } } @@ -496,7 +483,6 @@ impl ExecPayload for FullPayloadRef<'_, E> { FullPayloadRef::Deneb(inner) => Ok(inner.execution_payload.blob_gas_used), FullPayloadRef::Electra(inner) => Ok(inner.execution_payload.blob_gas_used), FullPayloadRef::Fulu(inner) => Ok(inner.execution_payload.blob_gas_used), - FullPayloadRef::Gloas(inner) => Ok(inner.execution_payload.blob_gas_used), } } @@ -520,7 +506,6 @@ impl AbstractExecPayload for FullPayload { type Deneb = FullPayloadDeneb; type Electra = FullPayloadElectra; type Fulu = FullPayloadFulu; - type Gloas = FullPayloadGloas; } impl From> for FullPayload { @@ -539,7 +524,7 @@ impl TryFrom> for FullPayload { } #[superstruct( - variants(Bellatrix, Capella, Deneb, Electra, Fulu, Gloas), + variants(Bellatrix, Capella, Deneb, Electra, Fulu), variant_attributes( derive( Debug, @@ -599,8 +584,6 @@ pub struct BlindedPayload { pub execution_payload_header: ExecutionPayloadHeaderElectra, #[superstruct(only(Fulu), partial_getter(rename = "execution_payload_fulu"))] pub execution_payload_header: ExecutionPayloadHeaderFulu, - #[superstruct(only(Gloas), partial_getter(rename = "execution_payload_gloas"))] - pub execution_payload_header: ExecutionPayloadHeaderGloas, } impl<'a, E: EthSpec> From> for BlindedPayload { @@ -690,7 +673,6 @@ impl ExecPayload for BlindedPayload { BlindedPayload::Deneb(inner) => Ok(inner.execution_payload_header.withdrawals_root), BlindedPayload::Electra(inner) => Ok(inner.execution_payload_header.withdrawals_root), BlindedPayload::Fulu(inner) => Ok(inner.execution_payload_header.withdrawals_root), - BlindedPayload::Gloas(inner) => Ok(inner.execution_payload_header.withdrawals_root), } } @@ -702,7 +684,6 @@ impl ExecPayload for BlindedPayload { BlindedPayload::Deneb(inner) => Ok(inner.execution_payload_header.blob_gas_used), BlindedPayload::Electra(inner) => Ok(inner.execution_payload_header.blob_gas_used), BlindedPayload::Fulu(inner) => Ok(inner.execution_payload_header.blob_gas_used), - BlindedPayload::Gloas(inner) => Ok(inner.execution_payload_header.blob_gas_used), } } @@ -802,7 +783,6 @@ impl<'b, E: EthSpec> ExecPayload for BlindedPayloadRef<'b, E> { Ok(inner.execution_payload_header.withdrawals_root) } BlindedPayloadRef::Fulu(inner) => Ok(inner.execution_payload_header.withdrawals_root), - BlindedPayloadRef::Gloas(inner) => Ok(inner.execution_payload_header.withdrawals_root), } } @@ -814,7 +794,6 @@ impl<'b, E: EthSpec> ExecPayload for BlindedPayloadRef<'b, E> { BlindedPayloadRef::Deneb(inner) => Ok(inner.execution_payload_header.blob_gas_used), BlindedPayloadRef::Electra(inner) => Ok(inner.execution_payload_header.blob_gas_used), BlindedPayloadRef::Fulu(inner) => Ok(inner.execution_payload_header.blob_gas_used), - BlindedPayloadRef::Gloas(inner) => Ok(inner.execution_payload_header.blob_gas_used), } } @@ -1126,13 +1105,6 @@ impl_exec_payload_for_fork!( ExecutionPayloadFulu, Fulu ); -impl_exec_payload_for_fork!( - BlindedPayloadGloas, - FullPayloadGloas, - ExecutionPayloadHeaderGloas, - ExecutionPayloadGloas, - Gloas -); impl AbstractExecPayload for BlindedPayload { type Ref<'a> = BlindedPayloadRef<'a, E>; @@ -1141,7 +1113,6 @@ impl AbstractExecPayload for BlindedPayload { type Deneb = BlindedPayloadDeneb; type Electra = BlindedPayloadElectra; type Fulu = BlindedPayloadFulu; - type Gloas = BlindedPayloadGloas; } impl From> for BlindedPayload { @@ -1183,11 +1154,6 @@ impl From> for BlindedPayload { execution_payload_header, }) } - ExecutionPayloadHeader::Gloas(execution_payload_header) => { - Self::Gloas(BlindedPayloadGloas { - execution_payload_header, - }) - } } } } @@ -1210,9 +1176,6 @@ impl From> for ExecutionPayloadHeader { BlindedPayload::Fulu(blinded_payload) => { ExecutionPayloadHeader::Fulu(blinded_payload.execution_payload_header) } - BlindedPayload::Gloas(blinded_payload) => { - ExecutionPayloadHeader::Gloas(blinded_payload.execution_payload_header) - } } } } diff --git a/consensus/types/src/execution/signed_execution_payload_bid.rs b/consensus/types/src/execution/signed_execution_payload_bid.rs new file mode 100644 index 0000000000..29dfd03ba0 --- /dev/null +++ b/consensus/types/src/execution/signed_execution_payload_bid.rs @@ -0,0 +1,35 @@ +use crate::test_utils::TestRandom; +use crate::{ExecutionPayloadBid, ForkName}; +use bls::Signature; +use context_deserialize::context_deserialize; +use educe::Educe; +use serde::{Deserialize, Serialize}; +use ssz_derive::{Decode, Encode}; +use test_random_derive::TestRandom; +use tree_hash_derive::TreeHash; + +#[derive(TestRandom, TreeHash, Debug, Clone, Encode, Decode, Serialize, Deserialize, Educe)] +#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] +#[educe(PartialEq, Hash)] +#[context_deserialize(ForkName)] +// https://github.com/ethereum/consensus-specs/blob/master/specs/gloas/beacon-chain.md#signedexecutionpayloadbid +pub struct SignedExecutionPayloadBid { + pub message: ExecutionPayloadBid, + pub signature: Signature, +} + +impl SignedExecutionPayloadBid { + pub fn empty() -> Self { + Self { + message: ExecutionPayloadBid::default(), + signature: Signature::empty(), + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + ssz_and_tree_hash_tests!(SignedExecutionPayloadBid); +} diff --git a/consensus/types/src/execution/signed_execution_payload_envelope.rs b/consensus/types/src/execution/signed_execution_payload_envelope.rs new file mode 100644 index 0000000000..1641041615 --- /dev/null +++ b/consensus/types/src/execution/signed_execution_payload_envelope.rs @@ -0,0 +1,24 @@ +use crate::test_utils::TestRandom; +use crate::{EthSpec, ExecutionPayloadEnvelope}; +use bls::Signature; +use educe::Educe; +use serde::{Deserialize, Serialize}; +use ssz_derive::{Decode, Encode}; +use test_random_derive::TestRandom; +use tree_hash_derive::TreeHash; + +#[derive(Debug, Clone, Serialize, Encode, Decode, Deserialize, TestRandom, TreeHash, Educe)] +#[educe(PartialEq, Hash(bound(E: EthSpec)))] +#[serde(bound = "E: EthSpec")] +pub struct SignedExecutionPayloadEnvelope { + pub message: ExecutionPayloadEnvelope, + pub signature: Signature, +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::MainnetEthSpec; + + ssz_and_tree_hash_tests!(SignedExecutionPayloadEnvelope); +} diff --git a/consensus/types/src/fork/fork_context.rs b/consensus/types/src/fork/fork_context.rs index 89f69bcbb6..3407689e79 100644 --- a/consensus/types/src/fork/fork_context.rs +++ b/consensus/types/src/fork/fork_context.rs @@ -182,6 +182,7 @@ mod tests { spec.deneb_fork_epoch = Some(Epoch::new(4)); spec.electra_fork_epoch = Some(Epoch::new(5)); spec.fulu_fork_epoch = Some(Epoch::new(6)); + spec.gloas_fork_epoch = Some(Epoch::new(7)); spec.blob_schedule = BlobSchedule::new(blob_parameters); spec } @@ -196,6 +197,7 @@ mod tests { assert!(context.fork_exists(ForkName::Electra)); assert!(context.fork_exists(ForkName::Fulu)); + assert!(context.fork_exists(ForkName::Gloas)); } #[test] diff --git a/consensus/types/src/lib.rs b/consensus/types/src/lib.rs index cd9252bde8..5a89fcb1d4 100644 --- a/consensus/types/src/lib.rs +++ b/consensus/types/src/lib.rs @@ -124,6 +124,10 @@ pub mod execution_requests { }; } +pub mod execution_payload_envelope { + pub use crate::execution::{ExecutionPayloadEnvelope, SignedExecutionPayloadEnvelope}; +} + pub mod data_column_custody_group { pub use crate::data::{ CustodyIndex, compute_columns_for_custody_group, compute_ordered_custody_column_indices, @@ -157,6 +161,12 @@ pub mod signed_aggregate_and_proof { pub use crate::attestation::SignedAggregateAndProofRefMut; } +pub mod payload_attestation { + pub use crate::attestation::{ + PayloadAttestation, PayloadAttestationData, PayloadAttestationMessage, + }; +} + pub mod application_domain { pub use crate::core::ApplicationDomain; } diff --git a/consensus/types/src/light_client/error.rs b/consensus/types/src/light_client/error.rs index c492cfcbde..4c7a30db5e 100644 --- a/consensus/types/src/light_client/error.rs +++ b/consensus/types/src/light_client/error.rs @@ -14,6 +14,7 @@ pub enum LightClientError { InvalidFinalizedBlock, BeaconBlockBodyError, InconsistentFork, + GloasNotImplemented, } impl From for LightClientError { diff --git a/consensus/types/src/light_client/light_client_bootstrap.rs b/consensus/types/src/light_client/light_client_bootstrap.rs index 847b2a2a96..fbcc0ef2b0 100644 --- a/consensus/types/src/light_client/light_client_bootstrap.rs +++ b/consensus/types/src/light_client/light_client_bootstrap.rs @@ -18,7 +18,6 @@ use crate::{ CurrentSyncCommitteeProofLen, CurrentSyncCommitteeProofLenElectra, LightClientError, LightClientHeader, LightClientHeaderAltair, LightClientHeaderCapella, LightClientHeaderDeneb, LightClientHeaderElectra, LightClientHeaderFulu, - LightClientHeaderGloas, }, state::BeaconState, sync_committee::SyncCommittee, @@ -28,7 +27,7 @@ use crate::{ /// A LightClientBootstrap is the initializer we send over to light_client nodes /// that are trying to generate their basic storage when booting up. #[superstruct( - variants(Altair, Capella, Deneb, Electra, Fulu, Gloas), + variants(Altair, Capella, Deneb, Electra, Fulu), variant_attributes( derive( Debug, @@ -73,8 +72,6 @@ pub struct LightClientBootstrap { pub header: LightClientHeaderElectra, #[superstruct(only(Fulu), partial_getter(rename = "header_fulu"))] pub header: LightClientHeaderFulu, - #[superstruct(only(Gloas), partial_getter(rename = "header_gloas"))] - pub header: LightClientHeaderGloas, /// The `SyncCommittee` used in the requested period. pub current_sync_committee: Arc>, /// Merkle proof for sync committee @@ -84,7 +81,7 @@ pub struct LightClientBootstrap { )] pub current_sync_committee_branch: FixedVector, #[superstruct( - only(Electra, Fulu, Gloas), + only(Electra, Fulu), partial_getter(rename = "current_sync_committee_branch_electra") )] pub current_sync_committee_branch: FixedVector, @@ -101,7 +98,6 @@ impl LightClientBootstrap { Self::Deneb(_) => func(ForkName::Deneb), Self::Electra(_) => func(ForkName::Electra), Self::Fulu(_) => func(ForkName::Fulu), - Self::Gloas(_) => func(ForkName::Gloas), } } @@ -121,8 +117,8 @@ impl LightClientBootstrap { ForkName::Deneb => Self::Deneb(LightClientBootstrapDeneb::from_ssz_bytes(bytes)?), ForkName::Electra => Self::Electra(LightClientBootstrapElectra::from_ssz_bytes(bytes)?), ForkName::Fulu => Self::Fulu(LightClientBootstrapFulu::from_ssz_bytes(bytes)?), - ForkName::Gloas => Self::Gloas(LightClientBootstrapGloas::from_ssz_bytes(bytes)?), - ForkName::Base => { + // TODO(gloas): implement Gloas light client + ForkName::Base | ForkName::Gloas => { return Err(ssz::DecodeError::BytesInvalid(format!( "LightClientBootstrap decoding for {fork_name} not implemented" ))); @@ -143,7 +139,8 @@ impl LightClientBootstrap { ForkName::Deneb => as Encode>::ssz_fixed_len(), ForkName::Electra => as Encode>::ssz_fixed_len(), ForkName::Fulu => as Encode>::ssz_fixed_len(), - ForkName::Gloas => as Encode>::ssz_fixed_len(), + // TODO(gloas): implement Gloas light client + ForkName::Gloas => as Encode>::ssz_fixed_len(), }; fixed_len + LightClientHeader::::ssz_max_var_len_for_fork(fork_name) } @@ -194,13 +191,8 @@ impl LightClientBootstrap { .try_into() .map_err(LightClientError::SszTypesError)?, }), - ForkName::Gloas => Self::Gloas(LightClientBootstrapGloas { - header: LightClientHeaderGloas::block_to_light_client_header(block)?, - current_sync_committee, - current_sync_committee_branch: current_sync_committee_branch - .try_into() - .map_err(LightClientError::SszTypesError)?, - }), + // TODO(gloas): implement Gloas light client + ForkName::Gloas => return Err(LightClientError::GloasNotImplemented), }; Ok(light_client_bootstrap) @@ -254,13 +246,8 @@ impl LightClientBootstrap { .try_into() .map_err(LightClientError::SszTypesError)?, }), - ForkName::Gloas => Self::Gloas(LightClientBootstrapGloas { - header: LightClientHeaderGloas::block_to_light_client_header(block)?, - current_sync_committee, - current_sync_committee_branch: current_sync_committee_branch - .try_into() - .map_err(LightClientError::SszTypesError)?, - }), + // TODO(gloas): implement Gloas light client + ForkName::Gloas => return Err(LightClientError::GloasNotImplemented), }; Ok(light_client_bootstrap) @@ -301,7 +288,11 @@ impl<'de, E: EthSpec> ContextDeserialize<'de, ForkName> for LightClientBootstrap Self::Fulu(Deserialize::deserialize(deserializer).map_err(convert_err)?) } ForkName::Gloas => { - Self::Gloas(Deserialize::deserialize(deserializer).map_err(convert_err)?) + // TODO(EIP-7732): check if this is correct + return Err(serde::de::Error::custom(format!( + "LightClientBootstrap failed to deserialize: unsupported fork '{}'", + context + ))); } }) } @@ -339,10 +330,4 @@ mod tests { use crate::{LightClientBootstrapFulu, MainnetEthSpec}; ssz_tests!(LightClientBootstrapFulu); } - - #[cfg(test)] - mod gloas { - use crate::{LightClientBootstrapGloas, MainnetEthSpec}; - ssz_tests!(LightClientBootstrapGloas); - } } diff --git a/consensus/types/src/light_client/light_client_finality_update.rs b/consensus/types/src/light_client/light_client_finality_update.rs index 04374edcd9..b503785b85 100644 --- a/consensus/types/src/light_client/light_client_finality_update.rs +++ b/consensus/types/src/light_client/light_client_finality_update.rs @@ -16,14 +16,14 @@ use crate::{ light_client::{ FinalizedRootProofLen, FinalizedRootProofLenElectra, LightClientError, LightClientHeader, LightClientHeaderAltair, LightClientHeaderCapella, LightClientHeaderDeneb, - LightClientHeaderElectra, LightClientHeaderFulu, LightClientHeaderGloas, + LightClientHeaderElectra, LightClientHeaderFulu, }, sync_committee::SyncAggregate, test_utils::TestRandom, }; #[superstruct( - variants(Altair, Capella, Deneb, Electra, Fulu, Gloas), + variants(Altair, Capella, Deneb, Electra, Fulu), variant_attributes( derive( Debug, @@ -68,8 +68,6 @@ pub struct LightClientFinalityUpdate { pub attested_header: LightClientHeaderElectra, #[superstruct(only(Fulu), partial_getter(rename = "attested_header_fulu"))] pub attested_header: LightClientHeaderFulu, - #[superstruct(only(Gloas), partial_getter(rename = "attested_header_gloas"))] - pub attested_header: LightClientHeaderGloas, /// The last `BeaconBlockHeader` from the last attested finalized block (end of epoch). #[superstruct(only(Altair), partial_getter(rename = "finalized_header_altair"))] pub finalized_header: LightClientHeaderAltair, @@ -81,8 +79,6 @@ pub struct LightClientFinalityUpdate { pub finalized_header: LightClientHeaderElectra, #[superstruct(only(Fulu), partial_getter(rename = "finalized_header_fulu"))] pub finalized_header: LightClientHeaderFulu, - #[superstruct(only(Gloas), partial_getter(rename = "finalized_header_gloas"))] - pub finalized_header: LightClientHeaderGloas, /// Merkle proof attesting finalized header. #[superstruct( only(Altair, Capella, Deneb), @@ -90,7 +86,7 @@ pub struct LightClientFinalityUpdate { )] pub finality_branch: FixedVector, #[superstruct( - only(Electra, Fulu, Gloas), + only(Electra, Fulu), partial_getter(rename = "finality_branch_electra") )] pub finality_branch: FixedVector, @@ -181,20 +177,7 @@ impl LightClientFinalityUpdate { sync_aggregate, signature_slot, }), - ForkName::Gloas => Self::Gloas(LightClientFinalityUpdateGloas { - attested_header: LightClientHeaderGloas::block_to_light_client_header( - attested_block, - )?, - finalized_header: LightClientHeaderGloas::block_to_light_client_header( - finalized_block, - )?, - finality_branch: finality_branch - .try_into() - .map_err(LightClientError::SszTypesError)?, - sync_aggregate, - signature_slot, - }), - + ForkName::Gloas => return Err(LightClientError::GloasNotImplemented), ForkName::Base => return Err(LightClientError::AltairForkNotActive), }; @@ -211,7 +194,6 @@ impl LightClientFinalityUpdate { Self::Deneb(_) => func(ForkName::Deneb), Self::Electra(_) => func(ForkName::Electra), Self::Fulu(_) => func(ForkName::Fulu), - Self::Gloas(_) => func(ForkName::Gloas), } } @@ -249,8 +231,8 @@ impl LightClientFinalityUpdate { Self::Electra(LightClientFinalityUpdateElectra::from_ssz_bytes(bytes)?) } ForkName::Fulu => Self::Fulu(LightClientFinalityUpdateFulu::from_ssz_bytes(bytes)?), - ForkName::Gloas => Self::Gloas(LightClientFinalityUpdateGloas::from_ssz_bytes(bytes)?), - ForkName::Base => { + // TODO(gloas): implement Gloas light client + ForkName::Base | ForkName::Gloas => { return Err(ssz::DecodeError::BytesInvalid(format!( "LightClientFinalityUpdate decoding for {fork_name} not implemented" ))); @@ -271,7 +253,8 @@ impl LightClientFinalityUpdate { ForkName::Deneb => as Encode>::ssz_fixed_len(), ForkName::Electra => as Encode>::ssz_fixed_len(), ForkName::Fulu => as Encode>::ssz_fixed_len(), - ForkName::Gloas => as Encode>::ssz_fixed_len(), + // TODO(gloas): implement Gloas light client + ForkName::Gloas => 0, }; // `2 *` because there are two headers in the update fixed_size + 2 * LightClientHeader::::ssz_max_var_len_for_fork(fork_name) @@ -325,7 +308,11 @@ impl<'de, E: EthSpec> ContextDeserialize<'de, ForkName> for LightClientFinalityU Self::Fulu(Deserialize::deserialize(deserializer).map_err(convert_err)?) } ForkName::Gloas => { - Self::Gloas(Deserialize::deserialize(deserializer).map_err(convert_err)?) + // TODO(EIP-7732): check if this is correct + return Err(serde::de::Error::custom(format!( + "LightClientBootstrap failed to deserialize: unsupported fork '{}'", + context + ))); } }) } @@ -363,10 +350,4 @@ mod tests { use crate::{LightClientFinalityUpdateFulu, MainnetEthSpec}; ssz_tests!(LightClientFinalityUpdateFulu); } - - #[cfg(test)] - mod gloas { - use crate::{LightClientFinalityUpdateGloas, MainnetEthSpec}; - ssz_tests!(LightClientFinalityUpdateGloas); - } } diff --git a/consensus/types/src/light_client/light_client_header.rs b/consensus/types/src/light_client/light_client_header.rs index a7ecd3b7fb..fdf9f234ef 100644 --- a/consensus/types/src/light_client/light_client_header.rs +++ b/consensus/types/src/light_client/light_client_header.rs @@ -15,7 +15,7 @@ use crate::{ core::{ChainSpec, EthSpec, Hash256}, execution::{ ExecutionPayloadHeader, ExecutionPayloadHeaderCapella, ExecutionPayloadHeaderDeneb, - ExecutionPayloadHeaderElectra, ExecutionPayloadHeaderFulu, ExecutionPayloadHeaderGloas, + ExecutionPayloadHeaderElectra, ExecutionPayloadHeaderFulu, }, fork::ForkName, light_client::{ExecutionPayloadProofLen, LightClientError, consts::EXECUTION_PAYLOAD_INDEX}, @@ -23,7 +23,7 @@ use crate::{ }; #[superstruct( - variants(Altair, Capella, Deneb, Electra, Fulu, Gloas), + variants(Altair, Capella, Deneb, Electra, Fulu,), variant_attributes( derive( Debug, @@ -73,10 +73,8 @@ pub struct LightClientHeader { pub execution: ExecutionPayloadHeaderElectra, #[superstruct(only(Fulu), partial_getter(rename = "execution_payload_header_fulu"))] pub execution: ExecutionPayloadHeaderFulu, - #[superstruct(only(Gloas), partial_getter(rename = "execution_payload_header_gloas"))] - pub execution: ExecutionPayloadHeaderGloas, - #[superstruct(only(Capella, Deneb, Electra, Fulu, Gloas))] + #[superstruct(only(Capella, Deneb, Electra, Fulu))] pub execution_branch: FixedVector, #[ssz(skip_serializing, skip_deserializing)] @@ -111,9 +109,8 @@ impl LightClientHeader { ForkName::Fulu => { LightClientHeader::Fulu(LightClientHeaderFulu::block_to_light_client_header(block)?) } - ForkName::Gloas => LightClientHeader::Gloas( - LightClientHeaderGloas::block_to_light_client_header(block)?, - ), + // TODO(gloas): implement Gloas light client + ForkName::Gloas => return Err(LightClientError::GloasNotImplemented), }; Ok(header) } @@ -135,10 +132,8 @@ impl LightClientHeader { ForkName::Fulu => { LightClientHeader::Fulu(LightClientHeaderFulu::from_ssz_bytes(bytes)?) } - ForkName::Gloas => { - LightClientHeader::Gloas(LightClientHeaderGloas::from_ssz_bytes(bytes)?) - } - ForkName::Base => { + // TODO(gloas): implement Gloas light client + ForkName::Base | ForkName::Gloas => { return Err(ssz::DecodeError::BytesInvalid(format!( "LightClientHeader decoding for {fork_name} not implemented" ))); @@ -157,7 +152,10 @@ impl LightClientHeader { } pub fn ssz_max_var_len_for_fork(fork_name: ForkName) -> usize { - if fork_name.capella_enabled() { + if fork_name.gloas_enabled() { + // TODO(EIP7732): check this + 0 + } else if fork_name.capella_enabled() { ExecutionPayloadHeader::::ssz_max_var_len_for_fork(fork_name) } else { 0 @@ -353,48 +351,6 @@ impl Default for LightClientHeaderFulu { } } -impl LightClientHeaderGloas { - pub fn block_to_light_client_header( - block: &SignedBlindedBeaconBlock, - ) -> Result { - let payload = block - .message() - .execution_payload()? - .execution_payload_gloas()?; - - let header = ExecutionPayloadHeaderGloas::from(payload); - let beacon_block_body = BeaconBlockBody::from( - block - .message() - .body_gloas() - .map_err(|_| LightClientError::BeaconBlockBodyError)? - .to_owned(), - ); - - let execution_branch = beacon_block_body - .to_ref() - .block_body_merkle_proof(EXECUTION_PAYLOAD_INDEX)?; - - Ok(LightClientHeaderGloas { - beacon: block.message().block_header(), - execution: header, - execution_branch: FixedVector::new(execution_branch)?, - _phantom_data: PhantomData, - }) - } -} - -impl Default for LightClientHeaderGloas { - fn default() -> Self { - Self { - beacon: BeaconBlockHeader::empty(), - execution: ExecutionPayloadHeaderGloas::default(), - execution_branch: FixedVector::default(), - _phantom_data: PhantomData, - } - } -} - impl<'de, E: EthSpec> ContextDeserialize<'de, ForkName> for LightClientHeader { fn context_deserialize(deserializer: D, context: ForkName) -> Result where @@ -407,7 +363,8 @@ impl<'de, E: EthSpec> ContextDeserialize<'de, ForkName> for LightClientHeader )) }; Ok(match context { - ForkName::Base => { + // TODO(gloas): implement Gloas light client + ForkName::Base | ForkName::Gloas => { return Err(serde::de::Error::custom(format!( "LightClientFinalityUpdate failed to deserialize: unsupported fork '{}'", context @@ -428,9 +385,6 @@ impl<'de, E: EthSpec> ContextDeserialize<'de, ForkName> for LightClientHeader ForkName::Fulu => { Self::Fulu(Deserialize::deserialize(deserializer).map_err(convert_err)?) } - ForkName::Gloas => { - Self::Gloas(Deserialize::deserialize(deserializer).map_err(convert_err)?) - } }) } } @@ -467,10 +421,4 @@ mod tests { use crate::{LightClientHeaderFulu, MainnetEthSpec}; ssz_tests!(LightClientHeaderFulu); } - - #[cfg(test)] - mod gloas { - use crate::{LightClientHeaderGloas, MainnetEthSpec}; - ssz_tests!(LightClientHeaderGloas); - } } diff --git a/consensus/types/src/light_client/light_client_optimistic_update.rs b/consensus/types/src/light_client/light_client_optimistic_update.rs index 9266ce647a..139c4b6a08 100644 --- a/consensus/types/src/light_client/light_client_optimistic_update.rs +++ b/consensus/types/src/light_client/light_client_optimistic_update.rs @@ -15,7 +15,6 @@ use crate::{ light_client::{ LightClientError, LightClientHeader, LightClientHeaderAltair, LightClientHeaderCapella, LightClientHeaderDeneb, LightClientHeaderElectra, LightClientHeaderFulu, - LightClientHeaderGloas, }, sync_committee::SyncAggregate, test_utils::TestRandom, @@ -24,7 +23,7 @@ use crate::{ /// A LightClientOptimisticUpdate is the update we send on each slot, /// it is based off the current unfinalized epoch is verified only against BLS signature. #[superstruct( - variants(Altair, Capella, Deneb, Electra, Fulu, Gloas), + variants(Altair, Capella, Deneb, Electra, Fulu), variant_attributes( derive( Debug, @@ -69,8 +68,6 @@ pub struct LightClientOptimisticUpdate { pub attested_header: LightClientHeaderElectra, #[superstruct(only(Fulu), partial_getter(rename = "attested_header_fulu"))] pub attested_header: LightClientHeaderFulu, - #[superstruct(only(Gloas), partial_getter(rename = "attested_header_gloas"))] - pub attested_header: LightClientHeaderGloas, /// current sync aggregate pub sync_aggregate: SyncAggregate, /// Slot of the sync aggregated signature @@ -126,13 +123,7 @@ impl LightClientOptimisticUpdate { sync_aggregate, signature_slot, }), - ForkName::Gloas => Self::Gloas(LightClientOptimisticUpdateGloas { - attested_header: LightClientHeaderGloas::block_to_light_client_header( - attested_block, - )?, - sync_aggregate, - signature_slot, - }), + ForkName::Gloas => return Err(LightClientError::GloasNotImplemented), ForkName::Base => return Err(LightClientError::AltairForkNotActive), }; @@ -149,7 +140,6 @@ impl LightClientOptimisticUpdate { Self::Deneb(_) => func(ForkName::Deneb), Self::Electra(_) => func(ForkName::Electra), Self::Fulu(_) => func(ForkName::Fulu), - Self::Gloas(_) => func(ForkName::Gloas), } } @@ -189,10 +179,8 @@ impl LightClientOptimisticUpdate { Self::Electra(LightClientOptimisticUpdateElectra::from_ssz_bytes(bytes)?) } ForkName::Fulu => Self::Fulu(LightClientOptimisticUpdateFulu::from_ssz_bytes(bytes)?), - ForkName::Gloas => { - Self::Gloas(LightClientOptimisticUpdateGloas::from_ssz_bytes(bytes)?) - } - ForkName::Base => { + // TODO(gloas): implement Gloas light client + ForkName::Base | ForkName::Gloas => { return Err(ssz::DecodeError::BytesInvalid(format!( "LightClientOptimisticUpdate decoding for {fork_name} not implemented" ))); @@ -213,7 +201,8 @@ impl LightClientOptimisticUpdate { ForkName::Deneb => as Encode>::ssz_fixed_len(), ForkName::Electra => as Encode>::ssz_fixed_len(), ForkName::Fulu => as Encode>::ssz_fixed_len(), - ForkName::Gloas => as Encode>::ssz_fixed_len(), + // TODO(gloas): implement Gloas light client + ForkName::Gloas => 0, }; fixed_len + LightClientHeader::::ssz_max_var_len_for_fork(fork_name) } @@ -266,7 +255,11 @@ impl<'de, E: EthSpec> ContextDeserialize<'de, ForkName> for LightClientOptimisti Self::Fulu(Deserialize::deserialize(deserializer).map_err(convert_err)?) } ForkName::Gloas => { - Self::Gloas(Deserialize::deserialize(deserializer).map_err(convert_err)?) + // TODO(EIP-7732): check if this is correct + return Err(serde::de::Error::custom(format!( + "LightClientBootstrap failed to deserialize: unsupported fork '{}'", + context + ))); } }) } @@ -304,10 +297,4 @@ mod tests { use crate::{LightClientOptimisticUpdateFulu, MainnetEthSpec}; ssz_tests!(LightClientOptimisticUpdateFulu); } - - #[cfg(test)] - mod gloas { - use crate::{LightClientOptimisticUpdateGloas, MainnetEthSpec}; - ssz_tests!(LightClientOptimisticUpdateGloas); - } } diff --git a/consensus/types/src/light_client/light_client_update.rs b/consensus/types/src/light_client/light_client_update.rs index aa7b800cc8..cd33f6ae54 100644 --- a/consensus/types/src/light_client/light_client_update.rs +++ b/consensus/types/src/light_client/light_client_update.rs @@ -21,7 +21,6 @@ use crate::{ light_client::{ LightClientError, LightClientHeader, LightClientHeaderAltair, LightClientHeaderCapella, LightClientHeaderDeneb, LightClientHeaderElectra, LightClientHeaderFulu, - LightClientHeaderGloas, }, sync_committee::{SyncAggregate, SyncCommittee}, test_utils::TestRandom, @@ -46,7 +45,7 @@ type NextSyncCommitteeBranchElectra = FixedVector { pub attested_header: LightClientHeaderElectra, #[superstruct(only(Fulu), partial_getter(rename = "attested_header_fulu"))] pub attested_header: LightClientHeaderFulu, - #[superstruct(only(Gloas), partial_getter(rename = "attested_header_gloas"))] - pub attested_header: LightClientHeaderGloas, /// The `SyncCommittee` used in the next period. pub next_sync_committee: Arc>, // Merkle proof for next sync committee @@ -102,7 +99,7 @@ pub struct LightClientUpdate { )] pub next_sync_committee_branch: NextSyncCommitteeBranch, #[superstruct( - only(Electra, Fulu, Gloas), + only(Electra, Fulu), partial_getter(rename = "next_sync_committee_branch_electra") )] pub next_sync_committee_branch: NextSyncCommitteeBranchElectra, @@ -117,8 +114,6 @@ pub struct LightClientUpdate { pub finalized_header: LightClientHeaderElectra, #[superstruct(only(Fulu), partial_getter(rename = "finalized_header_fulu"))] pub finalized_header: LightClientHeaderFulu, - #[superstruct(only(Gloas), partial_getter(rename = "finalized_header_gloas"))] - pub finalized_header: LightClientHeaderGloas, /// Merkle proof attesting finalized header. #[superstruct( only(Altair, Capella, Deneb), @@ -126,7 +121,7 @@ pub struct LightClientUpdate { )] pub finality_branch: FinalityBranch, #[superstruct( - only(Electra, Fulu, Gloas), + only(Electra, Fulu), partial_getter(rename = "finality_branch_electra") )] pub finality_branch: FinalityBranchElectra, @@ -145,7 +140,8 @@ impl<'de, E: EthSpec> ContextDeserialize<'de, ForkName> for LightClientUpdate serde::de::Error::custom(format!("LightClientUpdate failed to deserialize: {:?}", e)) }; Ok(match context { - ForkName::Base => { + // TODO(gloas): implement Gloas light client + ForkName::Base | ForkName::Gloas => { return Err(serde::de::Error::custom(format!( "LightClientUpdate failed to deserialize: unsupported fork '{}'", context @@ -166,9 +162,6 @@ impl<'de, E: EthSpec> ContextDeserialize<'de, ForkName> for LightClientUpdate ForkName::Fulu => { Self::Fulu(Deserialize::deserialize(deserializer).map_err(convert_err)?) } - ForkName::Gloas => { - Self::Gloas(Deserialize::deserialize(deserializer).map_err(convert_err)?) - } }) } } @@ -330,36 +323,11 @@ impl LightClientUpdate { signature_slot: block_slot, }) } - fork_name @ ForkName::Gloas => { - let attested_header = - LightClientHeaderGloas::block_to_light_client_header(attested_block)?; - - let finalized_header = if let Some(finalized_block) = finalized_block { - if finalized_block.fork_name_unchecked() == fork_name { - LightClientHeaderGloas::block_to_light_client_header(finalized_block)? - } else { - LightClientHeaderGloas::default() - } - } else { - LightClientHeaderGloas::default() - }; - - Self::Gloas(LightClientUpdateGloas { - attested_header, - next_sync_committee, - next_sync_committee_branch: next_sync_committee_branch - .try_into() - .map_err(LightClientError::SszTypesError)?, - finalized_header, - finality_branch: finality_branch - .try_into() - .map_err(LightClientError::SszTypesError)?, - sync_aggregate: sync_aggregate.clone(), - signature_slot: block_slot, - }) - } // To add a new fork, just append the new fork variant on the latest fork. Forks that - // have a distinct execution header will need a new LightClientUpdate variant only - // if you need to test or support lightclient usages + // To add a new fork, just append the new fork variant on the latest fork. Forks that + // have a distinct execution header will need a new LightClientUpdate variant only + // if you need to test or support lightclient usages + // TODO(gloas): implement Gloas light client + ForkName::Gloas => return Err(LightClientError::GloasNotImplemented), }; Ok(light_client_update) @@ -374,8 +342,8 @@ impl LightClientUpdate { ForkName::Deneb => Self::Deneb(LightClientUpdateDeneb::from_ssz_bytes(bytes)?), ForkName::Electra => Self::Electra(LightClientUpdateElectra::from_ssz_bytes(bytes)?), ForkName::Fulu => Self::Fulu(LightClientUpdateFulu::from_ssz_bytes(bytes)?), - ForkName::Gloas => Self::Gloas(LightClientUpdateGloas::from_ssz_bytes(bytes)?), - ForkName::Base => { + // TODO(gloas): implement Gloas light client + ForkName::Base | ForkName::Gloas => { return Err(ssz::DecodeError::BytesInvalid(format!( "LightClientUpdate decoding for {fork_name} not implemented" ))); @@ -392,7 +360,6 @@ impl LightClientUpdate { LightClientUpdate::Deneb(update) => update.attested_header.beacon.slot, LightClientUpdate::Electra(update) => update.attested_header.beacon.slot, LightClientUpdate::Fulu(update) => update.attested_header.beacon.slot, - LightClientUpdate::Gloas(update) => update.attested_header.beacon.slot, } } @@ -403,7 +370,6 @@ impl LightClientUpdate { LightClientUpdate::Deneb(update) => update.finalized_header.beacon.slot, LightClientUpdate::Electra(update) => update.finalized_header.beacon.slot, LightClientUpdate::Fulu(update) => update.finalized_header.beacon.slot, - LightClientUpdate::Gloas(update) => update.finalized_header.beacon.slot, } } @@ -533,7 +499,8 @@ impl LightClientUpdate { ForkName::Deneb => as Encode>::ssz_fixed_len(), ForkName::Electra => as Encode>::ssz_fixed_len(), ForkName::Fulu => as Encode>::ssz_fixed_len(), - ForkName::Gloas => as Encode>::ssz_fixed_len(), + // TODO(gloas): implement Gloas light client + ForkName::Gloas => 0, }; fixed_len + 2 * LightClientHeader::::ssz_max_var_len_for_fork(fork_name) } @@ -548,7 +515,6 @@ impl LightClientUpdate { Self::Deneb(_) => func(ForkName::Deneb), Self::Electra(_) => func(ForkName::Electra), Self::Fulu(_) => func(ForkName::Fulu), - Self::Gloas(_) => func(ForkName::Gloas), } } } @@ -612,13 +578,6 @@ mod tests { ssz_tests!(LightClientUpdateFulu); } - #[cfg(test)] - mod gloas { - use super::*; - use crate::MainnetEthSpec; - ssz_tests!(LightClientUpdateGloas); - } - #[test] fn finalized_root_params() { assert!(2usize.pow(FINALIZED_ROOT_PROOF_LEN as u32) <= FINALIZED_ROOT_INDEX); diff --git a/consensus/types/src/light_client/mod.rs b/consensus/types/src/light_client/mod.rs index 4e287c2294..24f3fdbb55 100644 --- a/consensus/types/src/light_client/mod.rs +++ b/consensus/types/src/light_client/mod.rs @@ -11,27 +11,25 @@ pub use error::LightClientError; pub use light_client_bootstrap::{ LightClientBootstrap, LightClientBootstrapAltair, LightClientBootstrapCapella, LightClientBootstrapDeneb, LightClientBootstrapElectra, LightClientBootstrapFulu, - LightClientBootstrapGloas, }; pub use light_client_finality_update::{ LightClientFinalityUpdate, LightClientFinalityUpdateAltair, LightClientFinalityUpdateCapella, LightClientFinalityUpdateDeneb, LightClientFinalityUpdateElectra, - LightClientFinalityUpdateFulu, LightClientFinalityUpdateGloas, + LightClientFinalityUpdateFulu, }; pub use light_client_header::{ LightClientHeader, LightClientHeaderAltair, LightClientHeaderCapella, LightClientHeaderDeneb, - LightClientHeaderElectra, LightClientHeaderFulu, LightClientHeaderGloas, + LightClientHeaderElectra, LightClientHeaderFulu, }; pub use light_client_optimistic_update::{ LightClientOptimisticUpdate, LightClientOptimisticUpdateAltair, LightClientOptimisticUpdateCapella, LightClientOptimisticUpdateDeneb, LightClientOptimisticUpdateElectra, LightClientOptimisticUpdateFulu, - LightClientOptimisticUpdateGloas, }; pub use light_client_update::{ CurrentSyncCommitteeProofLen, CurrentSyncCommitteeProofLenElectra, ExecutionPayloadProofLen, FinalizedRootProofLen, FinalizedRootProofLenElectra, LightClientUpdate, LightClientUpdateAltair, LightClientUpdateCapella, LightClientUpdateDeneb, - LightClientUpdateElectra, LightClientUpdateFulu, LightClientUpdateGloas, - NextSyncCommitteeProofLen, NextSyncCommitteeProofLenElectra, + LightClientUpdateElectra, LightClientUpdateFulu, NextSyncCommitteeProofLen, + NextSyncCommitteeProofLenElectra, }; diff --git a/consensus/types/src/state/beacon_state.rs b/consensus/types/src/state/beacon_state.rs index f36c02ce6b..c1b6f0dc0c 100644 --- a/consensus/types/src/state/beacon_state.rs +++ b/consensus/types/src/state/beacon_state.rs @@ -23,6 +23,7 @@ use tree_hash_derive::TreeHash; use typenum::Unsigned; use crate::{ + BuilderPendingPayment, BuilderPendingWithdrawal, ExecutionBlockHash, ExecutionPayloadBid, attestation::{ AttestationDuty, BeaconCommittee, Checkpoint, CommitteeIndex, ParticipationFlags, PendingAttestation, @@ -34,7 +35,7 @@ use crate::{ execution::{ Eth1Data, ExecutionPayloadHeaderBellatrix, ExecutionPayloadHeaderCapella, ExecutionPayloadHeaderDeneb, ExecutionPayloadHeaderElectra, ExecutionPayloadHeaderFulu, - ExecutionPayloadHeaderGloas, ExecutionPayloadHeaderRef, ExecutionPayloadHeaderRefMut, + ExecutionPayloadHeaderRef, ExecutionPayloadHeaderRefMut, }, fork::{Fork, ForkName, ForkVersionDecode, InconsistentFork, map_fork_name}, light_client::consts::{ @@ -542,14 +543,9 @@ where )] #[metastruct(exclude_from(tree_lists))] pub latest_execution_payload_header: ExecutionPayloadHeaderFulu, - #[superstruct( - only(Gloas), - partial_getter(rename = "latest_execution_payload_header_gloas") - )] + #[superstruct(only(Gloas))] #[metastruct(exclude_from(tree_lists))] - pub latest_execution_payload_header: ExecutionPayloadHeaderGloas, - - // Capella + pub latest_execution_payload_bid: ExecutionPayloadBid, #[superstruct(only(Capella, Deneb, Electra, Fulu, Gloas), partial_getter(copy))] #[serde(with = "serde_utils::quoted_u64")] #[metastruct(exclude_from(tree_lists))] @@ -608,6 +604,31 @@ where pub proposer_lookahead: Vector, // Gloas + #[test_random(default)] + #[superstruct(only(Gloas))] + #[metastruct(exclude_from(tree_lists))] + pub execution_payload_availability: BitVector, + + #[compare_fields(as_iter)] + #[test_random(default)] + #[superstruct(only(Gloas))] + pub builder_pending_payments: Vector, + + #[compare_fields(as_iter)] + #[test_random(default)] + #[superstruct(only(Gloas))] + pub builder_pending_withdrawals: + List, + + #[test_random(default)] + #[superstruct(only(Gloas))] + #[metastruct(exclude_from(tree_lists))] + pub latest_block_hash: ExecutionBlockHash, + + #[test_random(default)] + #[superstruct(only(Gloas))] + #[metastruct(exclude_from(tree_lists))] + pub latest_withdrawals_root: Hash256, // Caching (not in the spec) #[serde(skip_serializing, skip_deserializing)] @@ -1169,9 +1190,8 @@ impl BeaconState { BeaconState::Fulu(state) => Ok(ExecutionPayloadHeaderRef::Fulu( &state.latest_execution_payload_header, )), - BeaconState::Gloas(state) => Ok(ExecutionPayloadHeaderRef::Gloas( - &state.latest_execution_payload_header, - )), + // TODO(EIP-7732): investigate calling functions + BeaconState::Gloas(_) => Err(BeaconStateError::IncorrectStateVariant), } } @@ -1197,9 +1217,8 @@ impl BeaconState { BeaconState::Fulu(state) => Ok(ExecutionPayloadHeaderRefMut::Fulu( &mut state.latest_execution_payload_header, )), - BeaconState::Gloas(state) => Ok(ExecutionPayloadHeaderRefMut::Gloas( - &mut state.latest_execution_payload_header, - )), + // TODO(EIP-7732): investigate calling functions + BeaconState::Gloas(_) => Err(BeaconStateError::IncorrectStateVariant), } } @@ -2273,6 +2292,21 @@ impl BeaconState { } } + pub fn is_parent_block_full(&self) -> bool { + match self { + BeaconState::Base(_) | BeaconState::Altair(_) => false, + // TODO(EIP-7732): check the implications of this when we get to forkchoice modifications + BeaconState::Bellatrix(_) + | BeaconState::Capella(_) + | BeaconState::Deneb(_) + | BeaconState::Electra(_) + | BeaconState::Fulu(_) => true, + BeaconState::Gloas(state) => { + state.latest_execution_payload_bid.block_hash == state.latest_block_hash + } + } + } + /// Get the committee cache for some `slot`. /// /// Return an error if the cache for the slot's epoch is not initialized. diff --git a/testing/ef_tests/src/cases/operations.rs b/testing/ef_tests/src/cases/operations.rs index 379fcb1bb4..a53bce927c 100644 --- a/testing/ef_tests/src/cases/operations.rs +++ b/testing/ef_tests/src/cases/operations.rs @@ -307,6 +307,7 @@ impl Operation for BeaconBlockBody> { 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!(), }) }) @@ -366,6 +367,7 @@ impl Operation for BeaconBlockBody> { let inner = >>::from_ssz_bytes(bytes)?; BeaconBlockBody::Fulu(inner.clone_as_blinded()) } + // TODO(EIP-7732): See if we need to handle Gloas here _ => panic!(), }) }) @@ -417,6 +419,7 @@ impl Operation for WithdrawalsPayload { spec: &ChainSpec, _: &Operations, ) -> Result<(), BlockProcessingError> { + // TODO(EIP-7732): implement separate gloas and non-gloas variants of process_withdrawals process_withdrawals::<_, FullPayload<_>>(state, self.payload.to_ref(), spec) } }