diff --git a/beacon_node/beacon_chain/src/beacon_block_streamer.rs b/beacon_node/beacon_chain/src/beacon_block_streamer.rs index ed74022c3dd..1c12a261279 100644 --- a/beacon_node/beacon_chain/src/beacon_block_streamer.rs +++ b/beacon_node/beacon_chain/src/beacon_block_streamer.rs @@ -16,7 +16,7 @@ use types::{ }; use types::{ ExecutionPayload, ExecutionPayloadBellatrix, ExecutionPayloadCapella, ExecutionPayloadElectra, - ExecutionPayloadFulu, ExecutionPayloadGloas, ExecutionPayloadHeader, + ExecutionPayloadFulu, ExecutionPayloadGloas, ExecutionPayloadHeader, ExecutionPayloadHeze, }; #[derive(PartialEq)] @@ -102,6 +102,7 @@ fn reconstruct_default_header_block( ForkName::Electra => ExecutionPayloadElectra::default().into(), ForkName::Fulu => ExecutionPayloadFulu::default().into(), ForkName::Gloas => ExecutionPayloadGloas::default().into(), + ForkName::Heze => ExecutionPayloadHeze::default().into(), ForkName::Base | ForkName::Altair => { return Err(Error::PayloadReconstruction(format!( "Block with fork variant {} has execution payload", @@ -734,6 +735,7 @@ mod tests { 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 = None; + spec.heze_fork_epoch = None; 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 7eff6fb99a3..88c3f0cae8f 100644 --- a/beacon_node/beacon_chain/src/beacon_chain.rs +++ b/beacon_node/beacon_chain/src/beacon_chain.rs @@ -6167,6 +6167,11 @@ impl BeaconChain { "Attempting to produce gloas beacon block via non gloas code path".to_owned(), )); } + BeaconState::Heze(_) => { + return Err(BlockProductionError::HezeNotImplemented( + "Attempting to produce heze beacon block via non heze code path".to_owned(), + )); + } }; let block = SignedBeaconBlock::from_block( diff --git a/beacon_node/beacon_chain/src/block_production/gloas.rs b/beacon_node/beacon_chain/src/block_production/gloas.rs index f84ad65e12a..ed21c37df3c 100644 --- a/beacon_node/beacon_chain/src/block_production/gloas.rs +++ b/beacon_node/beacon_chain/src/block_production/gloas.rs @@ -600,6 +600,13 @@ impl BeaconChain { _phantom: PhantomData::>, }, }), + // TODO(heze): construct a `BeaconBlockHeze` here once Heze block production is + // wired up end-to-end (get_payload, envelope handling, etc). + BeaconState::Heze(_) => { + return Err(BlockProductionError::InvalidBlockVariant( + "Block production disabled for Heze".to_owned(), + )); + } }; let signed_beacon_block = SignedBeaconBlock::from_block( diff --git a/beacon_node/beacon_chain/src/data_column_verification.rs b/beacon_node/beacon_chain/src/data_column_verification.rs index 45cd687b367..6fbbd2e65cf 100644 --- a/beacon_node/beacon_chain/src/data_column_verification.rs +++ b/beacon_node/beacon_chain/src/data_column_verification.rs @@ -1803,8 +1803,8 @@ mod test { if !spec.is_fulu_scheduled() { return; } - // Gloas is not supported yet. - if spec.is_gloas_scheduled() { + // Gloas and Heze are not supported yet. + if spec.is_gloas_scheduled() || spec.is_heze_scheduled() { return; } diff --git a/beacon_node/beacon_chain/src/errors.rs b/beacon_node/beacon_chain/src/errors.rs index 5efe9a3c232..a37d6703f9f 100644 --- a/beacon_node/beacon_chain/src/errors.rs +++ b/beacon_node/beacon_chain/src/errors.rs @@ -333,6 +333,8 @@ pub enum BlockProductionError { MissingExecutionPayloadEnvelope(Hash256), // TODO(gloas): Remove this once Gloas is implemented GloasNotImplemented(String), + // TODO(heze): Remove this once Heze is implemented + HezeNotImplemented(String), } 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 ce51a82cec9..5f41b591772 100644 --- a/beacon_node/beacon_chain/src/test_utils.rs +++ b/beacon_node/beacon_chain/src/test_utils.rs @@ -705,6 +705,10 @@ pub fn mock_execution_layer_from_parts( HARNESS_GENESIS_TIME + (spec.get_slot_duration().as_secs()) * E::slots_per_epoch() * epoch.as_u64() }); + let heze_time = spec.heze_fork_epoch.map(|epoch| { + HARNESS_GENESIS_TIME + + (spec.get_slot_duration().as_secs()) * E::slots_per_epoch() * epoch.as_u64() + }); let kzg = get_kzg(&spec); @@ -715,6 +719,7 @@ pub fn mock_execution_layer_from_parts( prague_time, osaka_time, amsterdam_time, + heze_time, Some(JwtKey::from_slice(&DEFAULT_JWT_SECRET).unwrap()), spec, Some(kzg), diff --git a/beacon_node/beacon_chain/tests/block_verification.rs b/beacon_node/beacon_chain/tests/block_verification.rs index bf8d7cdae0a..132ac25d459 100644 --- a/beacon_node/beacon_chain/tests/block_verification.rs +++ b/beacon_node/beacon_chain/tests/block_verification.rs @@ -1010,6 +1010,11 @@ async fn invalid_signature_attester_slashing() { .push(attester_slashing.as_electra().unwrap().clone()) .expect("should update attester slashing"); } + BeaconBlockBodyRefMut::Heze(blk) => { + blk.attester_slashings + .push(attester_slashing.as_electra().unwrap().clone()) + .expect("should update attester slashing"); + } } snapshots[block_index].beacon_block = Arc::new(SignedBeaconBlock::from_block(block, signature)); @@ -1075,6 +1080,10 @@ async fn invalid_signature_attestation() { .attestations .get_mut(0) .map(|att| att.signature = junk_aggregate_signature()), + BeaconBlockBodyRefMut::Heze(blk) => blk + .attestations + .get_mut(0) + .map(|att| att.signature = junk_aggregate_signature()), }; if block.body().attestations_len() > 0 { diff --git a/beacon_node/client/src/notifier.rs b/beacon_node/client/src/notifier.rs index 7b7c7beb9bf..a0d46b339da 100644 --- a/beacon_node/client/src/notifier.rs +++ b/beacon_node/client/src/notifier.rs @@ -558,7 +558,7 @@ fn methods_required_for_fork( missing_methods.push(ENGINE_NEW_PAYLOAD_V4); } } - ForkName::Gloas => { + ForkName::Gloas | ForkName::Heze => { if !capabilities.get_payload_v6 { missing_methods.push(ENGINE_GET_PAYLOAD_V6); } diff --git a/beacon_node/execution_layer/src/engine_api.rs b/beacon_node/execution_layer/src/engine_api.rs index 9f32bfdfeba..3aff96c9b15 100644 --- a/beacon_node/execution_layer/src/engine_api.rs +++ b/beacon_node/execution_layer/src/engine_api.rs @@ -25,8 +25,8 @@ pub use types::{ }; use types::{ ExecutionPayloadBellatrix, ExecutionPayloadCapella, ExecutionPayloadDeneb, - ExecutionPayloadElectra, ExecutionPayloadFulu, ExecutionPayloadGloas, ExecutionRequests, - KzgProofs, + ExecutionPayloadElectra, ExecutionPayloadFulu, ExecutionPayloadGloas, ExecutionPayloadHeze, + ExecutionRequests, KzgProofs, }; use types::{GRAFFITI_BYTES_LEN, Graffiti}; @@ -38,7 +38,7 @@ mod new_payload_request; pub use new_payload_request::{ NewPayloadRequest, NewPayloadRequestBellatrix, NewPayloadRequestCapella, NewPayloadRequestDeneb, NewPayloadRequestElectra, NewPayloadRequestFulu, - NewPayloadRequestGloas, + NewPayloadRequestGloas, NewPayloadRequestHeze, }; pub const LATEST_TAG: &str = "latest"; @@ -312,7 +312,7 @@ pub struct ProposeBlindedBlockResponse { } #[superstruct( - variants(Bellatrix, Capella, Deneb, Electra, Fulu, Gloas), + variants(Bellatrix, Capella, Deneb, Electra, Fulu, Gloas, Heze), variant_attributes(derive(Clone, Debug, PartialEq),), map_into(ExecutionPayload), map_ref_into(ExecutionPayloadRef), @@ -336,17 +336,19 @@ pub struct GetPayloadResponse { pub execution_payload: ExecutionPayloadFulu, #[superstruct(only(Gloas), partial_getter(rename = "execution_payload_gloas"))] pub execution_payload: ExecutionPayloadGloas, + #[superstruct(only(Heze), partial_getter(rename = "execution_payload_heze"))] + pub execution_payload: ExecutionPayloadHeze, pub block_value: Uint256, - #[superstruct(only(Deneb, Electra, Fulu, Gloas))] + #[superstruct(only(Deneb, Electra, Fulu, Gloas, Heze))] pub blobs_bundle: BlobsBundle, - #[superstruct(only(Deneb, Electra, Fulu, Gloas), partial_getter(copy))] + #[superstruct(only(Deneb, Electra, Fulu, Gloas, Heze), partial_getter(copy))] pub should_override_builder: bool, #[superstruct( only(Electra, Fulu), partial_getter(rename = "execution_requests_electra") )] pub requests: types::ExecutionRequestsElectra, - #[superstruct(only(Gloas), partial_getter(rename = "execution_requests_gloas"))] + #[superstruct(only(Gloas, Heze), partial_getter(rename = "execution_requests_gloas"))] pub requests: types::ExecutionRequestsGloas, } @@ -426,6 +428,12 @@ impl From> Some(inner.blobs_bundle), Some(ExecutionRequests::Gloas(inner.requests)), ), + GetPayloadResponse::Heze(inner) => ( + ExecutionPayload::Heze(inner.execution_payload), + inner.block_value, + Some(inner.blobs_bundle), + Some(ExecutionRequests::Gloas(inner.requests)), + ), } } } diff --git a/beacon_node/execution_layer/src/engine_api/http.rs b/beacon_node/execution_layer/src/engine_api/http.rs index cb5168b6f81..e38142f21ae 100644 --- a/beacon_node/execution_layer/src/engine_api/http.rs +++ b/beacon_node/execution_layer/src/engine_api/http.rs @@ -1078,6 +1078,7 @@ impl HttpJsonRpc { .try_into() .map_err(Error::BadResponse) } + // TODO(heze): add a Heze arm once Heze payload retrieval is implemented. _ => Err(Error::UnsupportedForkVariant(format!( "called get_payload_v6 with {}", fork_name @@ -1401,6 +1402,11 @@ impl HttpJsonRpc { Err(Error::RequiredMethodUnsupported("engine_newPayloadV5")) } } + // TODO(heze): implement the Heze newPayload path once the engine API for Heze + // is specified. + NewPayloadRequest::Heze(_) => Err(Error::UnsupportedForkVariant( + "newPayload not implemented for Heze".to_string(), + )), } } @@ -1450,6 +1456,11 @@ impl HttpJsonRpc { Err(Error::RequiredMethodUnsupported("engine_getPayloadV6")) } } + // TODO(heze): implement the Heze getPayload path once the engine API for Heze + // is specified. + ForkName::Heze => Err(Error::UnsupportedForkVariant( + "getPayload not implemented for Heze".to_string(), + )), ForkName::Base | ForkName::Altair => Err(Error::UnsupportedForkVariant(format!( "called get_payload with {}", fork_name diff --git a/beacon_node/execution_layer/src/engine_api/json_structures.rs b/beacon_node/execution_layer/src/engine_api/json_structures.rs index dfa1c25282f..8b2a453cb47 100644 --- a/beacon_node/execution_layer/src/engine_api/json_structures.rs +++ b/beacon_node/execution_layer/src/engine_api/json_structures.rs @@ -67,7 +67,7 @@ pub struct JsonPayloadIdResponse { } #[superstruct( - variants(Bellatrix, Capella, Deneb, Electra, Fulu, Gloas), + variants(Bellatrix, Capella, Deneb, Electra, Fulu, Gloas, Heze), variant_attributes( derive(Debug, PartialEq, Default, Serialize, Deserialize,), serde(bound = "E: EthSpec", rename_all = "camelCase"), @@ -102,18 +102,18 @@ pub struct JsonExecutionPayload { pub block_hash: ExecutionBlockHash, #[serde(with = "ssz_types::serde_utils::list_of_hex_var_list")] pub transactions: Transactions, - #[superstruct(only(Capella, Deneb, Electra, Fulu, Gloas))] + #[superstruct(only(Capella, Deneb, Electra, Fulu, Gloas, Heze))] pub withdrawals: VariableList, - #[superstruct(only(Deneb, Electra, Fulu, Gloas))] + #[superstruct(only(Deneb, Electra, Fulu, Gloas, Heze))] #[serde(with = "serde_utils::u64_hex_be")] pub blob_gas_used: u64, - #[superstruct(only(Deneb, Electra, Fulu, Gloas))] + #[superstruct(only(Deneb, Electra, Fulu, Gloas, Heze))] #[serde(with = "serde_utils::u64_hex_be")] pub excess_blob_gas: u64, - #[superstruct(only(Gloas))] + #[superstruct(only(Gloas, Heze))] #[serde(with = "ssz_types::serde_utils::hex_var_list")] pub block_access_list: VariableList, - #[superstruct(only(Gloas))] + #[superstruct(only(Gloas, Heze))] #[serde(with = "serde_utils::u64_hex_be")] pub slot_number: u64, } @@ -267,6 +267,34 @@ impl TryFrom> for JsonExecutionPayloadGloas } } +impl TryFrom> for JsonExecutionPayloadHeze { + type Error = ssz_types::Error; + + fn try_from(payload: ExecutionPayloadHeze) -> Result { + Ok(JsonExecutionPayloadHeze { + 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, + 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, + base_fee_per_gas: payload.base_fee_per_gas, + block_hash: payload.block_hash, + transactions: payload.transactions, + withdrawals: withdrawals_to_json(payload.withdrawals)?, + blob_gas_used: payload.blob_gas_used, + excess_blob_gas: payload.excess_blob_gas, + block_access_list: payload.block_access_list, + slot_number: payload.slot_number.into(), + }) + } +} + impl TryFrom> for JsonExecutionPayload { type Error = ssz_types::Error; @@ -288,6 +316,7 @@ impl TryFrom> for JsonExecutionPayload { ExecutionPayload::Gloas(payload) => { Ok(JsonExecutionPayload::Gloas(payload.try_into()?)) } + ExecutionPayload::Heze(payload) => Ok(JsonExecutionPayload::Heze(payload.try_into()?)), } } } @@ -442,6 +471,34 @@ impl TryFrom> for ExecutionPayloadGloas } } +impl TryFrom> for ExecutionPayloadHeze { + type Error = ssz_types::Error; + + fn try_from(payload: JsonExecutionPayloadHeze) -> Result { + Ok(ExecutionPayloadHeze { + 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, + 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, + base_fee_per_gas: payload.base_fee_per_gas, + block_hash: payload.block_hash, + transactions: payload.transactions, + withdrawals: withdrawals_from_json(payload.withdrawals)?, + blob_gas_used: payload.blob_gas_used, + excess_blob_gas: payload.excess_blob_gas, + block_access_list: payload.block_access_list, + slot_number: payload.slot_number.into(), + }) + } +} + impl TryFrom> for ExecutionPayload { type Error = ssz_types::Error; @@ -463,6 +520,7 @@ impl TryFrom> for ExecutionPayload { JsonExecutionPayload::Gloas(payload) => { Ok(ExecutionPayload::Gloas(payload.try_into()?)) } + JsonExecutionPayload::Heze(payload) => Ok(ExecutionPayload::Heze(payload.try_into()?)), } } } @@ -635,7 +693,7 @@ impl TryFrom for ExecutionRequestsGloas { } #[superstruct( - variants(Bellatrix, Capella, Deneb, Electra, Fulu, Gloas), + variants(Bellatrix, Capella, Deneb, Electra, Fulu, Gloas, Heze), variant_attributes( derive(Debug, PartialEq, Serialize, Deserialize), serde(bound = "E: EthSpec", rename_all = "camelCase") @@ -661,13 +719,15 @@ pub struct JsonGetPayloadResponse { pub execution_payload: JsonExecutionPayloadFulu, #[superstruct(only(Gloas), partial_getter(rename = "execution_payload_gloas"))] pub execution_payload: JsonExecutionPayloadGloas, + #[superstruct(only(Heze), partial_getter(rename = "execution_payload_heze"))] + pub execution_payload: JsonExecutionPayloadHeze, #[serde(with = "serde_utils::u256_hex_be")] pub block_value: Uint256, - #[superstruct(only(Deneb, Electra, Fulu, Gloas))] + #[superstruct(only(Deneb, Electra, Fulu, Gloas, Heze))] pub blobs_bundle: JsonBlobsBundleV1, - #[superstruct(only(Deneb, Electra, Fulu, Gloas))] + #[superstruct(only(Deneb, Electra, Fulu, Gloas, Heze))] pub should_override_builder: bool, - #[superstruct(only(Electra, Fulu, Gloas))] + #[superstruct(only(Electra, Fulu, Gloas, Heze))] pub execution_requests: JsonExecutionRequests, } @@ -738,6 +798,19 @@ impl TryFrom> for GetPayloadResponse { })?, })) } + JsonGetPayloadResponse::Heze(response) => { + Ok(GetPayloadResponse::Heze(GetPayloadResponseHeze { + execution_payload: response.execution_payload.try_into().map_err(|e| { + format!("Failed to convert json to execution payload: {:?}", e) + })?, + block_value: response.block_value, + blobs_bundle: response.blobs_bundle.into(), + should_override_builder: response.should_override_builder, + requests: response.execution_requests.try_into().map_err(|e| { + format!("Failed to convert json to execution requests: {:?}", e) + })?, + })) + } } } } 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 d6b7f018aa5..c2b7cee6433 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 @@ -9,12 +9,12 @@ use types::{ }; use types::{ ExecutionPayloadBellatrix, ExecutionPayloadCapella, ExecutionPayloadDeneb, - ExecutionPayloadElectra, ExecutionPayloadFulu, ExecutionPayloadGloas, ExecutionRequestsElectra, - ExecutionRequestsGloas, ExecutionRequestsRef, + ExecutionPayloadElectra, ExecutionPayloadFulu, ExecutionPayloadGloas, ExecutionPayloadHeze, + ExecutionRequestsElectra, ExecutionRequestsGloas, ExecutionRequestsRef, }; #[superstruct( - variants(Bellatrix, Capella, Deneb, Electra, Fulu, Gloas), + variants(Bellatrix, Capella, Deneb, Electra, Fulu, Gloas, Heze), variant_attributes(derive(Clone, Debug, PartialEq),), map_into(ExecutionPayload), map_ref_into(ExecutionPayloadRef), @@ -44,16 +44,18 @@ pub struct NewPayloadRequest<'block, E: EthSpec> { pub execution_payload: &'block ExecutionPayloadFulu, #[superstruct(only(Gloas), partial_getter(rename = "execution_payload_gloas"))] pub execution_payload: &'block ExecutionPayloadGloas, - #[superstruct(only(Deneb, Electra, Fulu, Gloas))] + #[superstruct(only(Heze), partial_getter(rename = "execution_payload_heze"))] + pub execution_payload: &'block ExecutionPayloadHeze, + #[superstruct(only(Deneb, Electra, Fulu, Gloas, Heze))] pub versioned_hashes: Vec, - #[superstruct(only(Deneb, Electra, Fulu, Gloas))] + #[superstruct(only(Deneb, Electra, Fulu, Gloas, Heze))] pub parent_beacon_block_root: Hash256, #[superstruct( only(Electra, Fulu), partial_getter(rename = "execution_requests_electra") )] pub execution_requests: &'block ExecutionRequestsElectra, - #[superstruct(only(Gloas), partial_getter(rename = "execution_requests_gloas"))] + #[superstruct(only(Gloas, Heze), partial_getter(rename = "execution_requests_gloas"))] pub execution_requests: &'block ExecutionRequestsGloas, } @@ -66,6 +68,7 @@ impl<'block, E: EthSpec> NewPayloadRequest<'block, E> { Self::Electra(payload) => payload.execution_payload.parent_hash, Self::Fulu(payload) => payload.execution_payload.parent_hash, Self::Gloas(payload) => payload.execution_payload.parent_hash, + Self::Heze(payload) => payload.execution_payload.parent_hash, } } @@ -77,6 +80,7 @@ impl<'block, E: EthSpec> NewPayloadRequest<'block, E> { Self::Electra(payload) => payload.execution_payload.block_hash, Self::Fulu(payload) => payload.execution_payload.block_hash, Self::Gloas(payload) => payload.execution_payload.block_hash, + Self::Heze(payload) => payload.execution_payload.block_hash, } } @@ -88,6 +92,7 @@ impl<'block, E: EthSpec> NewPayloadRequest<'block, E> { Self::Electra(payload) => payload.execution_payload.block_number, Self::Fulu(payload) => payload.execution_payload.block_number, Self::Gloas(payload) => payload.execution_payload.block_number, + Self::Heze(payload) => payload.execution_payload.block_number, } } @@ -99,6 +104,7 @@ impl<'block, E: EthSpec> NewPayloadRequest<'block, E> { Self::Electra(request) => ExecutionPayloadRef::Electra(request.execution_payload), Self::Fulu(request) => ExecutionPayloadRef::Fulu(request.execution_payload), Self::Gloas(request) => ExecutionPayloadRef::Gloas(request.execution_payload), + Self::Heze(request) => ExecutionPayloadRef::Heze(request.execution_payload), } } @@ -112,6 +118,7 @@ impl<'block, E: EthSpec> NewPayloadRequest<'block, E> { Self::Electra(request) => ExecutionPayload::Electra(request.execution_payload.clone()), Self::Fulu(request) => ExecutionPayload::Fulu(request.execution_payload.clone()), Self::Gloas(request) => ExecutionPayload::Gloas(request.execution_payload.clone()), + Self::Heze(request) => ExecutionPayload::Heze(request.execution_payload.clone()), } } @@ -135,6 +142,7 @@ impl<'block, E: EthSpec> NewPayloadRequest<'block, E> { Self::Electra(r) => Some(ExecutionRequestsRef::Electra(r.execution_requests)), Self::Fulu(r) => Some(ExecutionRequestsRef::Electra(r.execution_requests)), Self::Gloas(r) => Some(ExecutionRequestsRef::Gloas(r.execution_requests)), + Self::Heze(r) => Some(ExecutionRequestsRef::Gloas(r.execution_requests)), } } @@ -237,6 +245,7 @@ impl<'a, E: EthSpec> TryFrom> for NewPayloadRequest<'a, E> execution_requests: &block_ref.body.execution_requests, })), BeaconBlockRef::Gloas(_) => Err(Self::Error::IncorrectStateVariant), + BeaconBlockRef::Heze(_) => Err(Self::Error::IncorrectStateVariant), } } } @@ -259,6 +268,7 @@ impl<'a, E: EthSpec> TryFrom> for NewPayloadRequest<' ExecutionPayloadRef::Fulu(_) => Err(Self::Error::IncorrectStateVariant), //TODO(EIP7732): Probably time to just get rid of this ExecutionPayloadRef::Gloas(_) => Err(Self::Error::IncorrectStateVariant), + ExecutionPayloadRef::Heze(_) => Err(Self::Error::IncorrectStateVariant), } } } diff --git a/beacon_node/execution_layer/src/lib.rs b/beacon_node/execution_layer/src/lib.rs index 523f06b7ffd..8d6636022de 100644 --- a/beacon_node/execution_layer/src/lib.rs +++ b/beacon_node/execution_layer/src/lib.rs @@ -223,6 +223,8 @@ impl From> for BlockProposalContentsGloas } } +// TODO(heze): add a `BlockProposalContentsHeze` here once Heze block production is wired up. + pub enum BlockProposalContents> { Payload { payload: Payload, @@ -941,6 +943,8 @@ impl ExecutionLayer { Ok(payload_response.into()) } + // TODO(heze): add a `get_payload_heze` here once Heze block production is wired up. + /// Maps to the `engine_getPayload` JSON-RPC call. /// /// However, it will attempt to call `self.prepare_payload` if it cannot find an existing @@ -1701,6 +1705,9 @@ impl ExecutionLayer { ForkName::Gloas => { return Err(Error::InvalidForkForPayload); } + ForkName::Heze => { + 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 b05db6e8bdd..a029725f51e 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 @@ -26,8 +26,8 @@ use tree_hash_derive::TreeHash; use types::{ Blob, ChainSpec, EthSpec, ExecutionBlockHash, ExecutionPayload, ExecutionPayloadBellatrix, ExecutionPayloadCapella, ExecutionPayloadDeneb, ExecutionPayloadElectra, ExecutionPayloadFulu, - ExecutionPayloadGloas, ExecutionPayloadHeader, ExecutionRequests, ForkName, Hash256, KzgProofs, - Transaction, Transactions, Uint256, + ExecutionPayloadGloas, ExecutionPayloadHeader, ExecutionPayloadHeze, ExecutionRequests, + ForkName, Hash256, KzgProofs, Transaction, Transactions, Uint256, }; const TEST_BLOB_BUNDLE: &[u8] = include_bytes!("fixtures/mainnet/test_blobs_bundle.ssz"); @@ -162,6 +162,7 @@ pub struct ExecutionBlockGenerator { pub prague_time: Option, // electra pub osaka_time: Option, // fulu pub amsterdam_time: Option, // gloas + pub heze_time: Option, // heze /* * deneb stuff */ @@ -192,6 +193,7 @@ impl ExecutionBlockGenerator { prague_time: Option, osaka_time: Option, amsterdam_time: Option, + heze_time: Option, kzg: Option>, ) -> Self { let mut generator = Self { @@ -211,6 +213,7 @@ impl ExecutionBlockGenerator { prague_time, osaka_time, amsterdam_time, + heze_time, blobs_bundles: <_>::default(), kzg, rng: make_rng(), @@ -262,6 +265,7 @@ impl ExecutionBlockGenerator { pub fn get_fork_at_timestamp(&self, timestamp: u64) -> ForkName { let forks = [ + (self.heze_time, ForkName::Heze), (self.amsterdam_time, ForkName::Gloas), (self.osaka_time, ForkName::Fulu), (self.prague_time, ForkName::Electra), @@ -798,6 +802,27 @@ impl ExecutionBlockGenerator { block_access_list: VariableList::empty(), slot_number: pa.slot_number.into(), }), + ForkName::Heze => ExecutionPayload::Heze(ExecutionPayloadHeze { + parent_hash: head_block_hash, + fee_recipient: pa.suggested_fee_recipient, + receipts_root: Hash256::repeat_byte(42), + state_root: Hash256::repeat_byte(43), + logs_bloom: vec![0; 256].try_into().unwrap(), + prev_randao: pa.prev_randao, + block_number: parent.block_number() + 1, + gas_limit: DEFAULT_GAS_LIMIT, + gas_used: GAS_USED, + timestamp: pa.timestamp, + extra_data: "block gen was here".as_bytes().to_vec().try_into().unwrap(), + base_fee_per_gas: Uint256::from(1u64), + block_hash: ExecutionBlockHash::zero(), + transactions: vec![].try_into().unwrap(), + withdrawals: pa.withdrawals.clone().try_into().unwrap(), + blob_gas_used: 0, + excess_blob_gas: 0, + block_access_list: VariableList::empty(), + slot_number: pa.slot_number.into(), + }), _ => unreachable!(), }, }; @@ -989,6 +1014,14 @@ pub fn generate_genesis_header(spec: &ChainSpec) -> Option { + // TODO(heze): we are using a Fulu header for now, but this gets fixed up by the + // genesis builder anyway which translates it to bid/latest_block_hash. + let mut header = ExecutionPayloadHeader::Fulu(<_>::default()); + *header.block_hash_mut() = genesis_block_hash.unwrap_or_default(); + *header.transactions_root_mut() = empty_transactions_root; + Some(header) + } } } diff --git a/beacon_node/execution_layer/src/test_utils/handle_rpc.rs b/beacon_node/execution_layer/src/test_utils/handle_rpc.rs index 10eaefaabaf..62564306cc8 100644 --- a/beacon_node/execution_layer/src/test_utils/handle_rpc.rs +++ b/beacon_node/execution_layer/src/test_utils/handle_rpc.rs @@ -126,9 +126,12 @@ pub async fn handle_rpc( .map(|jep| JsonExecutionPayload::Electra(jep)) }) .map_err(|s| (s, BAD_PARAMS_ERROR_CODE))?, - ENGINE_NEW_PAYLOAD_V5 => get_param::>(params, 0) - .map(|jep| JsonExecutionPayload::Gloas(jep)) - .map_err(|s| (s, BAD_PARAMS_ERROR_CODE))?, + ENGINE_NEW_PAYLOAD_V5 => { + // TODO(heze):impl heze variant (probably new payload v6?) + get_param::>(params, 0) + .map(|jep| JsonExecutionPayload::Gloas(jep)) + .map_err(|s| (s, BAD_PARAMS_ERROR_CODE))? + } _ => unreachable!(), }; @@ -238,6 +241,14 @@ pub async fn handle_rpc( )); } } + ForkName::Heze => { + if method != ENGINE_NEW_PAYLOAD_V5 { + return Err(( + format!("{} called after Heze fork!", method), + GENERIC_ERROR_CODE, + )); + } + } _ => unreachable!(), }; @@ -377,6 +388,24 @@ pub async fn handle_rpc( )); } + // validate method called correctly according to heze fork time + if ctx + .execution_block_generator + .read() + .get_fork_at_timestamp(response.timestamp()) + == ForkName::Heze + && (method == ENGINE_GET_PAYLOAD_V1 + || method == ENGINE_GET_PAYLOAD_V2 + || method == ENGINE_GET_PAYLOAD_V3 + || method == ENGINE_GET_PAYLOAD_V4 + || method == ENGINE_GET_PAYLOAD_V5) + { + return Err(( + format!("{} called after Heze fork!", method), + FORK_REQUEST_MISMATCH_ERROR_CODE, + )); + } + match method { ENGINE_GET_PAYLOAD_V1 => Ok(serde_json::to_value( JsonExecutionPayload::try_from(response).unwrap(), @@ -494,6 +523,25 @@ pub async fn handle_rpc( }) .unwrap() } + JsonExecutionPayload::Heze(execution_payload) => { + serde_json::to_value(JsonGetPayloadResponseHeze { + execution_payload, + block_value: Uint256::from(DEFAULT_MOCK_EL_PAYLOAD_VALUE_WEI), + blobs_bundle: maybe_blobs + .ok_or(( + "No blobs returned despite V6 Payload".to_string(), + GENERIC_ERROR_CODE, + ))? + .into(), + should_override_builder: false, + execution_requests: maybe_execution_requests + .unwrap_or_else(|| { + types::ExecutionRequests::Electra(Default::default()) + }) + .into(), + }) + .unwrap() + } _ => unreachable!(), }) } @@ -645,6 +693,14 @@ pub async fn handle_rpc( )); } } + ForkName::Heze => { + if method != ENGINE_FORKCHOICE_UPDATED_V4 { + return Err(( + format!("{} called after Heze fork! Use V4.", method), + FORK_REQUEST_MISMATCH_ERROR_CODE, + )); + } + } _ => unreachable!(), }; } 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 e02107e1166..95028d22b35 100644 --- a/beacon_node/execution_layer/src/test_utils/mock_builder.rs +++ b/beacon_node/execution_layer/src/test_utils/mock_builder.rs @@ -479,6 +479,10 @@ impl MockBuilder { // TODO(EIP7732) Check if this is how we want to do error handling for gloas return Err("invalid fork".to_string()); } + SignedBlindedBeaconBlock::Heze(_) => { + // TODO(heze) Check if this is how we want to do error handling for heze + return Err("invalid fork".to_string()); + } }; let block_hash = block .message() @@ -597,6 +601,10 @@ impl MockBuilder { // TODO(EIP7732) Check if this is how we want to do error handling for gloas return Err("invalid fork".to_string()); } + ForkName::Heze => { + // TODO(heze) Check if this is how we want to do error handling for heze + return Err("invalid fork".to_string()); + } ForkName::Fulu => BuilderBid::Fulu(BuilderBidFulu { header: payload .as_fulu() @@ -930,7 +938,7 @@ impl MockBuilder { None, None, ), - ForkName::Gloas => PayloadAttributes::new( + ForkName::Gloas | ForkName::Heze => PayloadAttributes::new( timestamp, *prev_randao, fee_recipient, diff --git a/beacon_node/execution_layer/src/test_utils/mock_execution_layer.rs b/beacon_node/execution_layer/src/test_utils/mock_execution_layer.rs index 583808281f1..cb1b3a210cb 100644 --- a/beacon_node/execution_layer/src/test_utils/mock_execution_layer.rs +++ b/beacon_node/execution_layer/src/test_utils/mock_execution_layer.rs @@ -24,6 +24,7 @@ impl MockExecutionLayer { None, None, None, + None, Some(JwtKey::from_slice(&DEFAULT_JWT_SECRET).unwrap()), Arc::new(spec), None, @@ -38,6 +39,7 @@ impl MockExecutionLayer { prague_time: Option, osaka_time: Option, amsterdam_time: Option, + heze_time: Option, jwt_key: Option, spec: Arc, kzg: Option>, @@ -53,6 +55,7 @@ impl MockExecutionLayer { prague_time, osaka_time, amsterdam_time, + heze_time, kzg, ); diff --git a/beacon_node/execution_layer/src/test_utils/mod.rs b/beacon_node/execution_layer/src/test_utils/mod.rs index 9317e0f3652..b42ac8c7175 100644 --- a/beacon_node/execution_layer/src/test_utils/mod.rs +++ b/beacon_node/execution_layer/src/test_utils/mod.rs @@ -85,6 +85,7 @@ pub struct MockExecutionConfig { pub prague_time: Option, pub osaka_time: Option, pub amsterdam_time: Option, + pub heze_time: Option, } impl Default for MockExecutionConfig { @@ -97,6 +98,7 @@ impl Default for MockExecutionConfig { prague_time: None, osaka_time: None, amsterdam_time: None, + heze_time: None, } } } @@ -118,6 +120,7 @@ impl MockServer { None, // FIXME(electra): should this be the default? None, // FIXME(fulu): should this be the default? None, // FIXME(gloas): should this be the default? + None, // FIXME(heze): should this be the default? None, ) } @@ -136,6 +139,7 @@ impl MockServer { prague_time, osaka_time, amsterdam_time, + heze_time, } = config; let last_echo_request = Arc::new(RwLock::new(None)); let preloaded_responses = Arc::new(Mutex::new(vec![])); @@ -145,6 +149,7 @@ impl MockServer { prague_time, osaka_time, amsterdam_time, + heze_time, kzg, ); @@ -206,6 +211,7 @@ impl MockServer { prague_time: Option, osaka_time: Option, amsterdam_time: Option, + heze_time: Option, kzg: Option>, ) -> Self { Self::new_with_config( @@ -218,6 +224,7 @@ impl MockServer { prague_time, osaka_time, amsterdam_time, + heze_time, }, kzg, ) diff --git a/beacon_node/http_api/tests/interactive_tests.rs b/beacon_node/http_api/tests/interactive_tests.rs index 437da7d4ea6..e675ad68641 100644 --- a/beacon_node/http_api/tests/interactive_tests.rs +++ b/beacon_node/http_api/tests/interactive_tests.rs @@ -61,7 +61,8 @@ 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(heze): use `ForkName::latest()` once Heze block production is wired up. + let spec = ForkName::Gloas.make_genesis_spec(E::default_spec()); let tester = InteractiveTester::::new_with_initializer_and_mutator( Some(spec.clone()), diff --git a/beacon_node/lighthouse_network/src/rpc/codec.rs b/beacon_node/lighthouse_network/src/rpc/codec.rs index ba95fff5e8e..b5749709115 100644 --- a/beacon_node/lighthouse_network/src/rpc/codec.rs +++ b/beacon_node/lighthouse_network/src/rpc/codec.rs @@ -22,7 +22,7 @@ use types::{ LightClientOptimisticUpdate, LightClientUpdate, SignedBeaconBlock, SignedBeaconBlockAltair, SignedBeaconBlockBase, SignedBeaconBlockBellatrix, SignedBeaconBlockCapella, SignedBeaconBlockDeneb, SignedBeaconBlockElectra, SignedBeaconBlockFulu, - SignedBeaconBlockGloas, + SignedBeaconBlockGloas, SignedBeaconBlockHeze, }; use unsigned_varint::codec::Uvi; @@ -901,6 +901,9 @@ fn handle_rpc_response( Some(ForkName::Gloas) => Ok(Some(RpcSuccessResponse::BlocksByRange(Arc::new( SignedBeaconBlock::Gloas(SignedBeaconBlockGloas::from_ssz_bytes(decoded_buffer)?), )))), + Some(ForkName::Heze) => Ok(Some(RpcSuccessResponse::BlocksByRange(Arc::new( + SignedBeaconBlock::Heze(SignedBeaconBlockHeze::from_ssz_bytes(decoded_buffer)?), + )))), None => Err(RPCError::ErrorResponse( RpcErrorResponse::InvalidRequest, format!( @@ -940,6 +943,9 @@ fn handle_rpc_response( Some(ForkName::Gloas) => Ok(Some(RpcSuccessResponse::BlocksByRoot(Arc::new( SignedBeaconBlock::Gloas(SignedBeaconBlockGloas::from_ssz_bytes(decoded_buffer)?), )))), + Some(ForkName::Heze) => Ok(Some(RpcSuccessResponse::BlocksByRoot(Arc::new( + SignedBeaconBlock::Heze(SignedBeaconBlockHeze::from_ssz_bytes(decoded_buffer)?), + )))), None => Err(RPCError::ErrorResponse( RpcErrorResponse::InvalidRequest, format!( @@ -1009,6 +1015,7 @@ mod tests { chain_spec.electra_fork_epoch = Some(Epoch::new(5)); chain_spec.fulu_fork_epoch = Some(Epoch::new(6)); chain_spec.gloas_fork_epoch = Some(Epoch::new(7)); + chain_spec.heze_fork_epoch = Some(Epoch::new(8)); // check that we have all forks covered assert!(chain_spec.fork_epoch(ForkName::latest()).is_some()); @@ -1025,6 +1032,7 @@ mod tests { ForkName::Electra => spec.electra_fork_epoch, ForkName::Fulu => spec.fulu_fork_epoch, ForkName::Gloas => spec.gloas_fork_epoch, + ForkName::Heze => spec.heze_fork_epoch, }; let current_slot = current_epoch.unwrap().start_slot(Spec::slots_per_epoch()); ForkContext::new::(current_slot, Hash256::zero(), spec) diff --git a/beacon_node/lighthouse_network/src/rpc/protocol.rs b/beacon_node/lighthouse_network/src/rpc/protocol.rs index b444608468a..a25d6983f06 100644 --- a/beacon_node/lighthouse_network/src/rpc/protocol.rs +++ b/beacon_node/lighthouse_network/src/rpc/protocol.rs @@ -155,7 +155,8 @@ pub fn rpc_block_limits_by_fork(current_fork: ForkName) -> RpcLimits { | ForkName::Deneb | ForkName::Electra | ForkName::Fulu - | ForkName::Gloas => RpcLimits::new( + | ForkName::Gloas + | ForkName::Heze => RpcLimits::new( *SIGNED_BEACON_BLOCK_BASE_MIN, *SIGNED_BEACON_BLOCK_BELLATRIX_MAX, ), @@ -184,7 +185,7 @@ fn rpc_light_client_updates_by_range_limits_by_fork(current_fork: ForkName) -> R ForkName::Deneb => { RpcLimits::new(altair_fixed_len, *LIGHT_CLIENT_UPDATES_BY_RANGE_DENEB_MAX) } - ForkName::Electra | ForkName::Fulu | ForkName::Gloas => { + ForkName::Electra | ForkName::Fulu | ForkName::Gloas | ForkName::Heze => { RpcLimits::new(altair_fixed_len, *LIGHT_CLIENT_UPDATES_BY_RANGE_ELECTRA_MAX) } } @@ -204,7 +205,7 @@ fn rpc_light_client_finality_update_limits_by_fork(current_fork: ForkName) -> Rp ForkName::Deneb => { RpcLimits::new(altair_fixed_len, *LIGHT_CLIENT_FINALITY_UPDATE_DENEB_MAX) } - ForkName::Electra | ForkName::Fulu | ForkName::Gloas => { + ForkName::Electra | ForkName::Fulu | ForkName::Gloas | ForkName::Heze => { RpcLimits::new(altair_fixed_len, *LIGHT_CLIENT_FINALITY_UPDATE_ELECTRA_MAX) } } @@ -225,7 +226,7 @@ fn rpc_light_client_optimistic_update_limits_by_fork(current_fork: ForkName) -> ForkName::Deneb => { RpcLimits::new(altair_fixed_len, *LIGHT_CLIENT_OPTIMISTIC_UPDATE_DENEB_MAX) } - ForkName::Electra | ForkName::Fulu | ForkName::Gloas => RpcLimits::new( + ForkName::Electra | ForkName::Fulu | ForkName::Gloas | ForkName::Heze => RpcLimits::new( altair_fixed_len, *LIGHT_CLIENT_OPTIMISTIC_UPDATE_ELECTRA_MAX, ), @@ -242,7 +243,7 @@ fn rpc_light_client_bootstrap_limits_by_fork(current_fork: ForkName) -> RpcLimit } ForkName::Capella => RpcLimits::new(altair_fixed_len, *LIGHT_CLIENT_BOOTSTRAP_CAPELLA_MAX), ForkName::Deneb => RpcLimits::new(altair_fixed_len, *LIGHT_CLIENT_BOOTSTRAP_DENEB_MAX), - ForkName::Electra | ForkName::Fulu | ForkName::Gloas => { + ForkName::Electra | ForkName::Fulu | ForkName::Gloas | ForkName::Heze => { RpcLimits::new(altair_fixed_len, *LIGHT_CLIENT_BOOTSTRAP_ELECTRA_MAX) } } diff --git a/beacon_node/lighthouse_network/src/types/pubsub.rs b/beacon_node/lighthouse_network/src/types/pubsub.rs index 00b2c42629a..5f00517c616 100644 --- a/beacon_node/lighthouse_network/src/types/pubsub.rs +++ b/beacon_node/lighthouse_network/src/types/pubsub.rs @@ -14,10 +14,10 @@ use types::{ SignedAggregateAndProofBase, SignedAggregateAndProofElectra, SignedBeaconBlock, SignedBeaconBlockAltair, SignedBeaconBlockBase, SignedBeaconBlockBellatrix, SignedBeaconBlockCapella, SignedBeaconBlockDeneb, SignedBeaconBlockElectra, - SignedBeaconBlockFulu, SignedBeaconBlockGloas, SignedBlsToExecutionChange, - SignedContributionAndProof, SignedExecutionPayloadBid, SignedExecutionPayloadEnvelope, - SignedProposerPreferences, SignedVoluntaryExit, SingleAttestation, SubnetId, - SyncCommitteeMessage, SyncSubnetId, + SignedBeaconBlockFulu, SignedBeaconBlockGloas, SignedBeaconBlockHeze, + SignedBlsToExecutionChange, SignedContributionAndProof, SignedExecutionPayloadBid, + SignedExecutionPayloadEnvelope, SignedProposerPreferences, SignedVoluntaryExit, + SingleAttestation, SubnetId, SyncCommitteeMessage, SyncSubnetId, }; #[derive(Debug, Clone, PartialEq)] @@ -267,6 +267,10 @@ impl PubsubMessage { SignedBeaconBlockGloas::from_ssz_bytes(data) .map_err(|e| format!("{:?}", e))?, ), + Some(ForkName::Heze) => SignedBeaconBlock::::Heze( + SignedBeaconBlockHeze::from_ssz_bytes(data) + .map_err(|e| format!("{:?}", e))?, + ), None => { return Err(format!( "Unknown gossipsub fork digest: {:?}", diff --git a/beacon_node/lighthouse_network/tests/common.rs b/beacon_node/lighthouse_network/tests/common.rs index 67fe569b723..3ee65e5dedd 100644 --- a/beacon_node/lighthouse_network/tests/common.rs +++ b/beacon_node/lighthouse_network/tests/common.rs @@ -28,6 +28,7 @@ pub fn spec_with_all_forks_enabled() -> ChainSpec { chain_spec.electra_fork_epoch = Some(Epoch::new(5)); chain_spec.fulu_fork_epoch = Some(Epoch::new(6)); chain_spec.gloas_fork_epoch = Some(Epoch::new(7)); + chain_spec.heze_fork_epoch = Some(Epoch::new(8)); // check that we have all forks covered assert!(chain_spec.fork_epoch(ForkName::latest()).is_some()); @@ -45,6 +46,7 @@ pub fn fork_context(fork_name: ForkName, spec: &ChainSpec) -> ForkContext { ForkName::Electra => spec.electra_fork_epoch, ForkName::Fulu => spec.fulu_fork_epoch, ForkName::Gloas => spec.gloas_fork_epoch, + ForkName::Heze => spec.heze_fork_epoch, }; let current_slot = current_epoch .unwrap_or_else(|| panic!("expect fork {fork_name} to be scheduled")) diff --git a/common/eth2/src/types.rs b/common/eth2/src/types.rs index f2b9a5ca64f..a1038e59214 100644 --- a/common/eth2/src/types.rs +++ b/common/eth2/src/types.rs @@ -1191,7 +1191,11 @@ impl<'de> ContextDeserialize<'de, ForkName> for SsePayloadAttributes { ForkName::Capella => { Self::V2(Deserialize::deserialize(deserializer).map_err(convert_err)?) } - ForkName::Deneb | ForkName::Electra | ForkName::Fulu | ForkName::Gloas => { + ForkName::Deneb + | ForkName::Electra + | ForkName::Fulu + | ForkName::Gloas + | ForkName::Heze => { Self::V3(Deserialize::deserialize(deserializer).map_err(convert_err)?) } }) @@ -2596,6 +2600,9 @@ mod test { ExecutionPayload::Gloas( ExecutionPayloadGloas::::arbitrary(&mut u).unwrap(), ), + ExecutionPayload::Heze( + ExecutionPayloadHeze::::arbitrary(&mut u).unwrap(), + ), ]; let merged_forks = &ForkName::list_all()[2..]; assert_eq!( @@ -2657,6 +2664,16 @@ mod test { blobs_bundle, } }, + { + let execution_payload = ExecutionPayload::Heze( + ExecutionPayloadHeze::::arbitrary(&mut u).unwrap(), + ); + let blobs_bundle = BlobsBundle::::arbitrary(&mut u).unwrap(); + ExecutionPayloadAndBlobs { + execution_payload, + blobs_bundle, + } + }, ]; let blob_forks = &ForkName::list_all()[4..]; diff --git a/consensus/state_processing/src/common/get_attestation_participation.rs b/consensus/state_processing/src/common/get_attestation_participation.rs index 2262b59ac1d..8f1f000f401 100644 --- a/consensus/state_processing/src/common/get_attestation_participation.rs +++ b/consensus/state_processing/src/common/get_attestation_participation.rs @@ -17,7 +17,7 @@ use types::{ /// This function will return an error if the source of the attestation doesn't match the /// state's relevant justified checkpoint. /// -/// This function has been abstracted to work for all forks from Altair to Gloas. +/// This function has been abstracted to work for all forks from Altair to Heze. pub fn get_attestation_participation_flag_indices( state: &BeaconState, data: &AttestationData, diff --git a/consensus/state_processing/src/genesis.rs b/consensus/state_processing/src/genesis.rs index c643ad56e34..c2ffcc774e8 100644 --- a/consensus/state_processing/src/genesis.rs +++ b/consensus/state_processing/src/genesis.rs @@ -5,7 +5,7 @@ use crate::common::DepositDataTree; use crate::upgrade::electra::upgrade_state_to_electra; use crate::upgrade::{ upgrade_to_altair, upgrade_to_bellatrix, upgrade_to_capella, upgrade_to_deneb, upgrade_to_fulu, - upgrade_to_gloas, + upgrade_to_gloas, upgrade_to_heze, }; use fixed_bytes::FixedBytesExtended; use safe_arith::{ArithError, SafeArith}; @@ -182,6 +182,17 @@ pub fn initialize_beacon_state_from_eth1( state.latest_block_header_mut().body_root = genesis_body_root; } + // Upgrade to heze if configured from genesis. + if spec + .heze_fork_epoch + .is_some_and(|fork_epoch| fork_epoch == E::genesis_epoch()) + { + upgrade_to_heze(&mut state, spec)?; + + // Remove intermediate Gloas fork from `state.fork`. + state.fork_mut().previous_version = spec.heze_fork_version; + } + // Now that we have our validators, initialize the caches (including the committees) state.build_caches(spec)?; diff --git a/consensus/state_processing/src/per_slot_processing.rs b/consensus/state_processing/src/per_slot_processing.rs index f26ea567a26..eee6d9f0e42 100644 --- a/consensus/state_processing/src/per_slot_processing.rs +++ b/consensus/state_processing/src/per_slot_processing.rs @@ -1,6 +1,6 @@ use crate::upgrade::{ upgrade_to_altair, upgrade_to_bellatrix, upgrade_to_capella, upgrade_to_deneb, - upgrade_to_electra, upgrade_to_fulu, upgrade_to_gloas, + upgrade_to_electra, upgrade_to_fulu, upgrade_to_gloas, upgrade_to_heze, }; use crate::{per_epoch_processing::EpochProcessingSummary, *}; use fixed_bytes::FixedBytesExtended; @@ -103,6 +103,11 @@ pub fn per_slot_processing( upgrade_to_gloas(state, spec)?; } + // Heze. + if spec.heze_fork_epoch == Some(state.current_epoch()) { + upgrade_to_heze(state, spec)?; + } + // Additionally build all caches so that all valid states that are advanced always have // committee caches built, and we don't have to worry about initialising them at higher // layers. diff --git a/consensus/state_processing/src/upgrade.rs b/consensus/state_processing/src/upgrade.rs index d175c3ae408..03c9dad5bcb 100644 --- a/consensus/state_processing/src/upgrade.rs +++ b/consensus/state_processing/src/upgrade.rs @@ -5,6 +5,7 @@ pub mod deneb; pub mod electra; pub mod fulu; pub mod gloas; +pub mod heze; pub use altair::upgrade_to_altair; pub use bellatrix::upgrade_to_bellatrix; @@ -13,3 +14,4 @@ pub use deneb::upgrade_to_deneb; pub use electra::upgrade_to_electra; pub use fulu::upgrade_to_fulu; pub use gloas::upgrade_to_gloas; +pub use heze::upgrade_to_heze; diff --git a/consensus/state_processing/src/upgrade/heze.rs b/consensus/state_processing/src/upgrade/heze.rs new file mode 100644 index 00000000000..e9156418c1e --- /dev/null +++ b/consensus/state_processing/src/upgrade/heze.rs @@ -0,0 +1,103 @@ +use std::mem; +use types::{BeaconState, BeaconStateError as Error, BeaconStateHeze, ChainSpec, EthSpec, Fork}; + +/// Transform a `Gloas` state into a `Heze` state. +pub fn upgrade_to_heze( + pre_state: &mut BeaconState, + spec: &ChainSpec, +) -> Result<(), Error> { + let post = upgrade_state_to_heze(pre_state, spec)?; + + *pre_state = post; + + Ok(()) +} + +pub fn upgrade_state_to_heze( + pre_state: &mut BeaconState, + spec: &ChainSpec, +) -> Result, Error> { + let epoch = pre_state.current_epoch(); + let pre = pre_state.as_gloas_mut()?; + // Where possible, use something like `mem::take` to move fields from behind the &mut + // reference. For other fields that don't have a good default value, use `clone`. + // + // Fixed size vectors get cloned because replacing them would require the same size + // allocation as cloning. + let post = BeaconState::Heze(BeaconStateHeze { + // Versioning + genesis_time: pre.genesis_time, + genesis_validators_root: pre.genesis_validators_root, + slot: pre.slot, + fork: Fork { + previous_version: pre.fork.current_version, + current_version: spec.heze_fork_version, + epoch, + }, + // History + latest_block_header: pre.latest_block_header.clone(), + block_roots: pre.block_roots.clone(), + state_roots: pre.state_roots.clone(), + historical_roots: mem::take(&mut pre.historical_roots), + // Eth1 + eth1_data: pre.eth1_data.clone(), + eth1_data_votes: mem::take(&mut pre.eth1_data_votes), + eth1_deposit_index: pre.eth1_deposit_index, + // Registry + validators: mem::take(&mut pre.validators), + balances: mem::take(&mut pre.balances), + // Randomness + randao_mixes: pre.randao_mixes.clone(), + // Slashings + slashings: pre.slashings.clone(), + // Participation + previous_epoch_participation: mem::take(&mut pre.previous_epoch_participation), + current_epoch_participation: mem::take(&mut pre.current_epoch_participation), + // Finality + justification_bits: pre.justification_bits.clone(), + previous_justified_checkpoint: pre.previous_justified_checkpoint, + current_justified_checkpoint: pre.current_justified_checkpoint, + finalized_checkpoint: pre.finalized_checkpoint, + // Inactivity + inactivity_scores: mem::take(&mut pre.inactivity_scores), + // Sync committees + current_sync_committee: pre.current_sync_committee.clone(), + next_sync_committee: pre.next_sync_committee.clone(), + // Execution Bid + latest_execution_payload_bid: pre.latest_execution_payload_bid.clone(), + // Capella + next_withdrawal_index: pre.next_withdrawal_index, + next_withdrawal_validator_index: pre.next_withdrawal_validator_index, + historical_summaries: pre.historical_summaries.clone(), + // Electra + deposit_requests_start_index: pre.deposit_requests_start_index, + deposit_balance_to_consume: pre.deposit_balance_to_consume, + exit_balance_to_consume: pre.exit_balance_to_consume, + earliest_exit_epoch: pre.earliest_exit_epoch, + consolidation_balance_to_consume: pre.consolidation_balance_to_consume, + earliest_consolidation_epoch: pre.earliest_consolidation_epoch, + pending_deposits: pre.pending_deposits.clone(), + pending_partial_withdrawals: pre.pending_partial_withdrawals.clone(), + pending_consolidations: pre.pending_consolidations.clone(), + proposer_lookahead: mem::take(&mut pre.proposer_lookahead), + // Gloas + builders: mem::take(&mut pre.builders), + next_withdrawal_builder_index: pre.next_withdrawal_builder_index, + execution_payload_availability: pre.execution_payload_availability.clone(), + builder_pending_payments: pre.builder_pending_payments.clone(), + builder_pending_withdrawals: mem::take(&mut pre.builder_pending_withdrawals), + latest_block_hash: pre.latest_block_hash, + payload_expected_withdrawals: mem::take(&mut pre.payload_expected_withdrawals), + ptc_window: pre.ptc_window.clone(), + // Caches + total_active_balance: pre.total_active_balance, + progressive_balances_cache: mem::take(&mut pre.progressive_balances_cache), + committee_caches: mem::take(&mut pre.committee_caches), + pubkey_cache: mem::take(&mut pre.pubkey_cache), + exit_cache: mem::take(&mut pre.exit_cache), + slashings_cache: mem::take(&mut pre.slashings_cache), + epoch_cache: mem::take(&mut pre.epoch_cache), + }); + + Ok(post) +} diff --git a/consensus/types/src/block/beacon_block.rs b/consensus/types/src/block/beacon_block.rs index a307c9bd954..e8861de91cd 100644 --- a/consensus/types/src/block/beacon_block.rs +++ b/consensus/types/src/block/beacon_block.rs @@ -19,8 +19,8 @@ use crate::{ block::{ BeaconBlockBodyAltair, BeaconBlockBodyBase, BeaconBlockBodyBellatrix, BeaconBlockBodyCapella, BeaconBlockBodyDeneb, BeaconBlockBodyElectra, BeaconBlockBodyFulu, - BeaconBlockBodyGloas, BeaconBlockBodyRef, BeaconBlockBodyRefMut, BeaconBlockHeader, - SignedBeaconBlock, SignedBeaconBlockHeader, + BeaconBlockBodyGloas, BeaconBlockBodyHeze, BeaconBlockBodyRef, BeaconBlockBodyRefMut, + BeaconBlockHeader, SignedBeaconBlock, SignedBeaconBlockHeader, }, core::{ChainSpec, Domain, Epoch, EthSpec, Graffiti, Hash256, SignedRoot, Slot}, deposit::{Deposit, DepositData}, @@ -37,7 +37,7 @@ use crate::{ /// A block of the `BeaconChain`. #[superstruct( - variants(Base, Altair, Bellatrix, Capella, Deneb, Electra, Fulu, Gloas), + variants(Base, Altair, Bellatrix, Capella, Deneb, Electra, Fulu, Gloas, Heze), variant_attributes( derive( Debug, @@ -104,6 +104,8 @@ pub struct BeaconBlock = FullPayload pub body: BeaconBlockBodyFulu, #[superstruct(only(Gloas), partial_getter(rename = "body_gloas"))] pub body: BeaconBlockBodyGloas, + #[superstruct(only(Heze), partial_getter(rename = "body_heze"))] + pub body: BeaconBlockBodyHeze, } pub type BlindedBeaconBlock = BeaconBlock>; @@ -156,6 +158,8 @@ impl> BeaconBlock { /// Usually it's better to prefer `from_ssz_bytes` which will decode the correct variant based /// on the fork slot. pub fn any_from_ssz_bytes(bytes: &[u8]) -> Result { + // TODO(heze): decode Heze here once it diverges from Gloas. While the two variants are + // SSZ-identical, trying Heze first would mis-tag every Gloas block as Heze. BeaconBlockGloas::from_ssz_bytes(bytes) .map(BeaconBlock::Gloas) .or_else(|_| BeaconBlockFulu::from_ssz_bytes(bytes).map(BeaconBlock::Fulu)) @@ -259,6 +263,7 @@ impl<'a, E: EthSpec, Payload: AbstractExecPayload> BeaconBlockRef<'a, E, Payl BeaconBlockRef::Electra { .. } => ForkName::Electra, BeaconBlockRef::Fulu { .. } => ForkName::Fulu, BeaconBlockRef::Gloas { .. } => ForkName::Gloas, + BeaconBlockRef::Heze { .. } => ForkName::Heze, } } @@ -324,6 +329,14 @@ impl<'a, E: EthSpec, Payload: AbstractExecPayload> BeaconBlockRef<'a, E, Payl .blob_kzg_commitments .len(), ), + BeaconBlockRef::Heze(block) => Some( + block + .body + .signed_execution_payload_bid + .message + .blob_kzg_commitments + .len(), + ), } } } @@ -722,6 +735,38 @@ impl> EmptyBlock for BeaconBlockGloa } } +impl> EmptyBlock for BeaconBlockHeze { + /// Returns an empty Heze block to be used during genesis. + fn empty(spec: &ChainSpec) -> Self { + BeaconBlockHeze { + slot: spec.genesis_slot, + proposer_index: 0, + parent_root: Hash256::zero(), + state_root: Hash256::zero(), + body: BeaconBlockBodyHeze { + randao_reveal: Signature::empty(), + eth1_data: Eth1Data { + deposit_root: Hash256::zero(), + block_hash: Hash256::zero(), + deposit_count: 0, + }, + graffiti: Graffiti::default(), + proposer_slashings: VariableList::empty(), + attester_slashings: VariableList::empty(), + attestations: VariableList::empty(), + deposits: VariableList::empty(), + voluntary_exits: VariableList::empty(), + sync_aggregate: SyncAggregate::empty(), + bls_to_execution_changes: VariableList::empty(), + parent_execution_requests: ExecutionRequestsGloas::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 { @@ -748,6 +793,29 @@ impl From>> } } +// TODO(heze) Look into whether we can remove this in the future since no blinded blocks post-gloas +impl From>> + for BeaconBlockHeze> +{ + fn from(block: BeaconBlockHeze>) -> Self { + let BeaconBlockHeze { + slot, + proposer_index, + parent_root, + state_root, + body, + } = block; + + BeaconBlockHeze { + 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> @@ -831,6 +899,7 @@ impl_from!(BeaconBlockDeneb, >, >, |body: impl_from!(BeaconBlockElectra, >, >, |body: BeaconBlockBodyElectra<_, _>| body.into()); impl_from!(BeaconBlockFulu, >, >, |body: BeaconBlockBodyFulu<_, _>| body.into()); impl_from!(BeaconBlockGloas, >, >, |body: BeaconBlockBodyGloas<_, _>| body.into()); +impl_from!(BeaconBlockHeze, >, >, |body: BeaconBlockBodyHeze<_, _>| body.into()); // We can clone blocks with payloads to blocks without payloads, without cloning the payload. macro_rules! impl_clone_as_blinded { @@ -866,6 +935,7 @@ impl_clone_as_blinded!(BeaconBlockDeneb, >, >, >); impl_clone_as_blinded!(BeaconBlockFulu, >, >); impl_clone_as_blinded!(BeaconBlockGloas, >, >); +impl_clone_as_blinded!(BeaconBlockHeze, >, >); // A reference to a full beacon block can be cloned into a blinded beacon block, without cloning the // execution payload. @@ -1018,6 +1088,19 @@ mod tests { }); } + #[test] + fn roundtrip_heze_block() { + let mut u = crate::test_utils::test_unstructured(); + let spec = &ForkName::Heze.make_genesis_spec(MainnetEthSpec::default_spec()); + + let inner_block = BeaconBlockHeze::arbitrary(&mut u).unwrap(); + let block = BeaconBlock::Heze(inner_block.clone()); + + test_ssz_tree_hash_pair_with(&block, &inner_block, |bytes| { + BeaconBlock::from_ssz_bytes(bytes, spec) + }); + } + #[test] fn roundtrip_gloas_block() { let mut u = crate::test_utils::test_unstructured(); @@ -1054,6 +1137,8 @@ mod tests { let fulu_slot = fulu_epoch.start_slot(E::slots_per_epoch()); let gloas_epoch = fulu_epoch + 1; let gloas_slot = gloas_epoch.start_slot(E::slots_per_epoch()); + let heze_epoch = gloas_epoch + 1; + let heze_slot = heze_epoch.start_slot(E::slots_per_epoch()); spec.altair_fork_epoch = Some(altair_epoch); spec.capella_fork_epoch = Some(capella_epoch); @@ -1061,6 +1146,7 @@ mod tests { spec.electra_fork_epoch = Some(electra_epoch); spec.fulu_fork_epoch = Some(fulu_epoch); spec.gloas_fork_epoch = Some(gloas_epoch); + spec.heze_fork_epoch = Some(heze_epoch); // BeaconBlockBase { @@ -1210,5 +1296,29 @@ mod tests { //BeaconBlock::from_ssz_bytes(&bad_block.as_ssz_bytes(), &spec) // .expect_err("bad gloas block cannot be decoded"); } + + // BeaconBlockHeze + { + let good_block = BeaconBlock::Heze(BeaconBlockHeze { + slot: heze_slot, + ..<_>::arbitrary(&mut u).unwrap() + }); + let _bad_block = { + let mut bad = good_block.clone(); + *bad.slot_mut() = gloas_slot; + bad + }; + + assert_eq!( + BeaconBlock::from_ssz_bytes(&good_block.as_ssz_bytes(), &spec) + .expect("good heze block can be decoded"), + good_block + ); + + // TODO(heze): Uncomment once Heze has features since without features + // and with a Gloas slot it decodes successfully to Gloas. + //BeaconBlock::from_ssz_bytes(&bad_block.as_ssz_bytes(), &spec) + // .expect_err("bad heze block cannot be decoded"); + } } } diff --git a/consensus/types/src/block/beacon_block_body.rs b/consensus/types/src/block/beacon_block_body.rs index f8e6ad6ae72..3e6e66b3a12 100644 --- a/consensus/types/src/block/beacon_block_body.rs +++ b/consensus/types/src/block/beacon_block_body.rs @@ -54,7 +54,7 @@ pub const BLOB_KZG_COMMITMENTS_INDEX: usize = 11; /// /// This *superstruct* abstracts over the hard-fork. #[superstruct( - variants(Base, Altair, Bellatrix, Capella, Deneb, Electra, Fulu, Gloas), + variants(Base, Altair, Bellatrix, Capella, Deneb, Electra, Fulu, Gloas, Heze), variant_attributes( derive( Debug, @@ -87,6 +87,7 @@ pub const BLOB_KZG_COMMITMENTS_INDEX: usize = 11; Electra(metastruct(mappings(beacon_block_body_electra_fields(groups(fields))))), Fulu(metastruct(mappings(beacon_block_body_fulu_fields(groups(fields))))), Gloas(metastruct(mappings(beacon_block_body_gloas_fields(groups(fields))))), + Heze(metastruct(mappings(beacon_block_body_heze_fields(groups(fields))))), ), cast_error( ty = "BeaconStateError", @@ -118,7 +119,7 @@ pub struct BeaconBlockBody = FullPay )] pub attester_slashings: VariableList, E::MaxAttesterSlashings>, #[superstruct( - only(Electra, Fulu, Gloas), + only(Electra, Fulu, Gloas, Heze), partial_getter(rename = "attester_slashings_electra") )] pub attester_slashings: @@ -129,13 +130,13 @@ pub struct BeaconBlockBody = FullPay )] pub attestations: VariableList, E::MaxAttestations>, #[superstruct( - only(Electra, Fulu, Gloas), + only(Electra, Fulu, Gloas, Heze), partial_getter(rename = "attestations_electra") )] pub attestations: VariableList, E::MaxAttestationsElectra>, pub deposits: VariableList, pub voluntary_exits: VariableList, - #[superstruct(only(Altair, Bellatrix, Capella, Deneb, Electra, Fulu, Gloas))] + #[superstruct(only(Altair, Bellatrix, Capella, Deneb, Electra, Fulu, Gloas, Heze))] pub sync_aggregate: SyncAggregate, // We flatten the execution payload so that serde can use the name of the inner type, // either `execution_payload` for full payloads, or `execution_payload_header` for blinded @@ -158,20 +159,20 @@ pub struct BeaconBlockBody = FullPay #[superstruct(only(Fulu), partial_getter(rename = "execution_payload_fulu"))] #[serde(flatten)] pub execution_payload: Payload::Fulu, - #[superstruct(only(Capella, Deneb, Electra, Fulu, Gloas))] + #[superstruct(only(Capella, Deneb, Electra, Fulu, Gloas, Heze))] pub bls_to_execution_changes: VariableList, #[superstruct(only(Deneb, Electra, Fulu))] pub blob_kzg_commitments: KzgCommitments, #[superstruct(only(Electra, Fulu))] pub execution_requests: ExecutionRequestsElectra, - #[superstruct(only(Gloas))] + #[superstruct(only(Gloas, Heze))] pub signed_execution_payload_bid: SignedExecutionPayloadBid, - #[superstruct(only(Gloas))] + #[superstruct(only(Gloas, Heze))] pub payload_attestations: VariableList, E::MaxPayloadAttestations>, - #[superstruct(only(Gloas))] + #[superstruct(only(Gloas, Heze))] pub parent_execution_requests: ExecutionRequestsGloas, - #[superstruct(only(Base, Altair, Gloas))] + #[superstruct(only(Base, Altair, Gloas, Heze))] #[metastruct(exclude_from(fields))] #[ssz(skip_serializing, skip_deserializing)] #[tree_hash(skip_hashing)] @@ -201,6 +202,7 @@ impl<'a, E: EthSpec, Payload: AbstractExecPayload> BeaconBlockBodyRef<'a, E, Self::Electra(body) => Ok(Payload::Ref::from(&body.execution_payload)), Self::Fulu(body) => Ok(Payload::Ref::from(&body.execution_payload)), Self::Gloas(_) => Err(BeaconStateError::IncorrectStateVariant), + Self::Heze(_) => Err(BeaconStateError::IncorrectStateVariant), } } @@ -239,6 +241,10 @@ impl<'a, E: EthSpec, Payload: AbstractExecPayload> BeaconBlockBodyRef<'a, E, beacon_block_body_gloas_fields!(body, |_, field| leaves .push(field.tree_hash_root())); } + Self::Heze(body) => { + beacon_block_body_heze_fields!(body, |_, field| leaves + .push(field.tree_hash_root())); + } } leaves } @@ -269,7 +275,8 @@ impl<'a, E: EthSpec, Payload: AbstractExecPayload> BeaconBlockBodyRef<'a, E, | Self::Altair(_) | Self::Bellatrix(_) | Self::Capella(_) - | Self::Gloas(_) => Err(BeaconStateError::IncorrectStateVariant), + | Self::Gloas(_) + | Self::Heze(_) => Err(BeaconStateError::IncorrectStateVariant), Self::Deneb(_) | Self::Electra(_) | Self::Fulu(_) => { complete_kzg_commitment_merkle_proof::( self.blob_kzg_commitments()?, @@ -354,6 +361,7 @@ impl<'a, E: EthSpec, Payload: AbstractExecPayload> BeaconBlockBodyRef<'a, E, Self::Electra(body) => Box::new(body.attestations.iter().map(AttestationRef::Electra)), Self::Fulu(body) => Box::new(body.attestations.iter().map(AttestationRef::Electra)), Self::Gloas(body) => Box::new(body.attestations.iter().map(AttestationRef::Electra)), + Self::Heze(body) => Box::new(body.attestations.iter().map(AttestationRef::Electra)), } } @@ -399,6 +407,11 @@ impl<'a, E: EthSpec, Payload: AbstractExecPayload> BeaconBlockBodyRef<'a, E, .iter() .map(AttesterSlashingRef::Electra), ), + Self::Heze(body) => Box::new( + body.attester_slashings + .iter() + .map(AttesterSlashingRef::Electra), + ), } } } @@ -430,6 +443,9 @@ impl<'a, E: EthSpec, Payload: AbstractExecPayload> BeaconBlockBodyRefMut<'a, Self::Gloas(body) => { Box::new(body.attestations.iter_mut().map(AttestationRefMut::Electra)) } + Self::Heze(body) => { + Box::new(body.attestations.iter_mut().map(AttestationRefMut::Electra)) + } } } } @@ -446,6 +462,7 @@ impl> BeaconBlockBodyRef<'_, E, Payl BeaconBlockBodyRef::Electra { .. } => ForkName::Electra, BeaconBlockBodyRef::Fulu { .. } => ForkName::Fulu, BeaconBlockBodyRef::Gloas { .. } => ForkName::Gloas, + BeaconBlockBodyRef::Heze { .. } => ForkName::Heze, } } } @@ -555,6 +572,48 @@ impl From>> } } +// Post-Fulu block bodies without payloads can be converted into block bodies with payloads +// TODO(heze) Look into whether we can remove this in the future since no blinded blocks post-gloas +impl From>> + for BeaconBlockBodyHeze> +{ + fn from(body: BeaconBlockBodyHeze>) -> Self { + let BeaconBlockBodyHeze { + randao_reveal, + eth1_data, + graffiti, + proposer_slashings, + attester_slashings, + attestations, + deposits, + voluntary_exits, + sync_aggregate, + bls_to_execution_changes, + parent_execution_requests, + signed_execution_payload_bid, + payload_attestations, + _phantom, + } = body; + + BeaconBlockBodyHeze { + randao_reveal, + eth1_data, + graffiti, + proposer_slashings, + attester_slashings, + attestations, + deposits, + voluntary_exits, + sync_aggregate, + bls_to_execution_changes, + parent_execution_requests, + signed_execution_payload_bid, + payload_attestations, + _phantom: PhantomData, + } + } +} + // Likewise bodies with payloads can be transformed into bodies without. impl From>> for ( @@ -894,6 +953,52 @@ impl From>> } } +impl From>> + for ( + BeaconBlockBodyHeze>, + Option>, + ) +{ + fn from(body: BeaconBlockBodyHeze>) -> Self { + let BeaconBlockBodyHeze { + randao_reveal, + eth1_data, + graffiti, + proposer_slashings, + attester_slashings, + attestations, + deposits, + voluntary_exits, + sync_aggregate, + bls_to_execution_changes, + parent_execution_requests, + signed_execution_payload_bid, + payload_attestations, + _phantom, + } = body; + + ( + BeaconBlockBodyHeze { + randao_reveal, + eth1_data, + graffiti, + proposer_slashings, + attester_slashings, + attestations, + deposits, + voluntary_exits, + sync_aggregate, + bls_to_execution_changes, + parent_execution_requests, + signed_execution_payload_bid, + payload_attestations, + _phantom: PhantomData, + }, + None, + ) + } +} + // We can clone a full block into a blinded block, without cloning the payload. impl BeaconBlockBodyBase> { pub fn clone_as_blinded(&self) -> BeaconBlockBodyBase> { @@ -1094,6 +1199,13 @@ impl BeaconBlockBodyGloas> { } } +impl BeaconBlockBodyHeze> { + pub fn clone_as_blinded(&self) -> BeaconBlockBodyHeze> { + let (block_body, _payload) = self.clone().into(); + block_body + } +} + impl From>> for ( BeaconBlockBody>, diff --git a/consensus/types/src/block/mod.rs b/consensus/types/src/block/mod.rs index 81c8ffbd639..d7e58f025f3 100644 --- a/consensus/types/src/block/mod.rs +++ b/consensus/types/src/block/mod.rs @@ -6,21 +6,21 @@ mod signed_beacon_block_header; pub use beacon_block::{ BeaconBlock, BeaconBlockAltair, BeaconBlockBase, BeaconBlockBellatrix, BeaconBlockCapella, - BeaconBlockDeneb, BeaconBlockElectra, BeaconBlockFulu, BeaconBlockGloas, BeaconBlockRef, - BeaconBlockRefMut, BlindedBeaconBlock, BlockImportSource, EmptyBlock, + BeaconBlockDeneb, BeaconBlockElectra, BeaconBlockFulu, BeaconBlockGloas, BeaconBlockHeze, + BeaconBlockRef, BeaconBlockRefMut, BlindedBeaconBlock, BlockImportSource, EmptyBlock, }; pub use beacon_block_body::{ BLOB_KZG_COMMITMENTS_INDEX, BeaconBlockBody, BeaconBlockBodyAltair, BeaconBlockBodyBase, BeaconBlockBodyBellatrix, BeaconBlockBodyCapella, BeaconBlockBodyDeneb, BeaconBlockBodyElectra, - BeaconBlockBodyFulu, BeaconBlockBodyGloas, BeaconBlockBodyRef, BeaconBlockBodyRefMut, - NUM_BEACON_BLOCK_BODY_HASH_TREE_ROOT_LEAVES, + BeaconBlockBodyFulu, BeaconBlockBodyGloas, BeaconBlockBodyHeze, BeaconBlockBodyRef, + BeaconBlockBodyRefMut, NUM_BEACON_BLOCK_BODY_HASH_TREE_ROOT_LEAVES, }; pub use beacon_block_header::BeaconBlockHeader; pub use signed_beacon_block::{ SignedBeaconBlock, SignedBeaconBlockAltair, SignedBeaconBlockBase, SignedBeaconBlockBellatrix, SignedBeaconBlockCapella, SignedBeaconBlockDeneb, SignedBeaconBlockElectra, - SignedBeaconBlockFulu, SignedBeaconBlockGloas, SignedBeaconBlockHash, SignedBlindedBeaconBlock, - ssz_tagged_signed_beacon_block, ssz_tagged_signed_beacon_block_arc, + SignedBeaconBlockFulu, SignedBeaconBlockGloas, SignedBeaconBlockHash, SignedBeaconBlockHeze, + SignedBlindedBeaconBlock, ssz_tagged_signed_beacon_block, ssz_tagged_signed_beacon_block_arc, }; pub use signed_beacon_block_header::SignedBeaconBlockHeader; diff --git a/consensus/types/src/block/signed_beacon_block.rs b/consensus/types/src/block/signed_beacon_block.rs index 1a87a519d0f..d30a2d14da5 100644 --- a/consensus/types/src/block/signed_beacon_block.rs +++ b/consensus/types/src/block/signed_beacon_block.rs @@ -19,7 +19,7 @@ use crate::{ BeaconBlockBellatrix, BeaconBlockBodyBellatrix, BeaconBlockBodyCapella, BeaconBlockBodyDeneb, BeaconBlockBodyElectra, BeaconBlockBodyFulu, BeaconBlockCapella, BeaconBlockDeneb, BeaconBlockElectra, BeaconBlockFulu, BeaconBlockGloas, BeaconBlockHeader, - BeaconBlockRef, BeaconBlockRefMut, SignedBeaconBlockHeader, + BeaconBlockHeze, BeaconBlockRef, BeaconBlockRefMut, SignedBeaconBlockHeader, }, core::{ChainSpec, Domain, Epoch, EthSpec, Hash256, SignedRoot, SigningData, Slot}, execution::{ @@ -64,7 +64,7 @@ impl From for Hash256 { /// A `BeaconBlock` and a signature from its proposer. #[superstruct( - variants(Base, Altair, Bellatrix, Capella, Deneb, Electra, Fulu, Gloas), + variants(Base, Altair, Bellatrix, Capella, Deneb, Electra, Fulu, Gloas, Heze), variant_attributes( derive( Debug, @@ -116,6 +116,8 @@ pub struct SignedBeaconBlock = FullP pub message: BeaconBlockFulu, #[superstruct(only(Gloas), partial_getter(rename = "message_gloas"))] pub message: BeaconBlockGloas, + #[superstruct(only(Heze), partial_getter(rename = "message_heze"))] + pub message: BeaconBlockHeze, pub signature: Signature, } @@ -205,6 +207,9 @@ impl> SignedBeaconBlock BeaconBlock::Gloas(message) => { SignedBeaconBlock::Gloas(SignedBeaconBlockGloas { message, signature }) } + BeaconBlock::Heze(message) => { + SignedBeaconBlock::Heze(SignedBeaconBlockHeze { message, signature }) + } } } @@ -527,6 +532,19 @@ impl From>> } } +// TODO(heze) Look into whether we can remove this in the future since no blinded blocks post-gloas +impl From>> + for SignedBeaconBlockHeze> +{ + fn from(signed_block: SignedBeaconBlockHeze>) -> Self { + let SignedBeaconBlockHeze { message, signature } = signed_block; + SignedBeaconBlockHeze { + message: message.into(), + signature, + } + } +} + impl SignedBeaconBlock> { pub fn try_into_full_block( self, @@ -551,6 +569,7 @@ impl SignedBeaconBlock> { SignedBeaconBlock::Fulu(block.into_full_block(payload)) } (SignedBeaconBlock::Gloas(block), _) => SignedBeaconBlock::Gloas(block.into()), + (SignedBeaconBlock::Heze(block), _) => SignedBeaconBlock::Heze(block.into()), // avoid wildcard matching forks so that compiler will // direct us here when a new fork has been added (SignedBeaconBlock::Bellatrix(_), _) => return None, @@ -558,7 +577,7 @@ impl SignedBeaconBlock> { (SignedBeaconBlock::Deneb(_), _) => return None, (SignedBeaconBlock::Electra(_), _) => return None, (SignedBeaconBlock::Fulu(_), _) => return None, - // TODO(EIP-7732) Determine if need a match arm for gloas here + // TODO(EIP-7732) Determine if need a match arm for gloas/heze here }; Some(full_block) } @@ -707,6 +726,9 @@ pub mod ssz_tagged_signed_beacon_block { ForkName::Gloas => Ok(SignedBeaconBlock::Gloas( SignedBeaconBlockGloas::from_ssz_bytes(body)?, )), + ForkName::Heze => Ok(SignedBeaconBlock::Heze( + SignedBeaconBlockHeze::from_ssz_bytes(body)?, + )), } } } @@ -788,6 +810,7 @@ mod test { chain_spec.electra_fork_epoch = Some(Epoch::new(5)); chain_spec.fulu_fork_epoch = Some(Epoch::new(6)); chain_spec.gloas_fork_epoch = Some(Epoch::new(7)); + chain_spec.heze_fork_epoch = Some(Epoch::new(8)); // check that we have all forks covered assert!(chain_spec.fork_epoch(ForkName::latest()).is_some()); @@ -829,7 +852,11 @@ mod test { BeaconBlock::Fulu(BeaconBlockFulu::empty(spec)), sig.clone(), ), - SignedBeaconBlock::from_block(BeaconBlock::Gloas(BeaconBlockGloas::empty(spec)), sig), + SignedBeaconBlock::from_block( + BeaconBlock::Gloas(BeaconBlockGloas::empty(spec)), + sig.clone(), + ), + SignedBeaconBlock::from_block(BeaconBlock::Heze(BeaconBlockHeze::empty(spec)), sig), ]; for block in blocks { diff --git a/consensus/types/src/builder/builder_bid.rs b/consensus/types/src/builder/builder_bid.rs index ddd877c46f9..be706a03601 100644 --- a/consensus/types/src/builder/builder_bid.rs +++ b/consensus/types/src/builder/builder_bid.rs @@ -91,7 +91,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::Gloas => { + ForkName::Altair | ForkName::Base | ForkName::Gloas | ForkName::Heze => { return Err(ssz::DecodeError::BytesInvalid(format!( "unsupported fork for ExecutionPayloadHeader: {fork_name}", ))); @@ -158,7 +158,7 @@ impl<'de, E: EthSpec> ContextDeserialize<'de, ForkName> for BuilderBid { ForkName::Fulu => { Self::Fulu(Deserialize::deserialize(deserializer).map_err(convert_err)?) } - ForkName::Base | ForkName::Altair | ForkName::Gloas => { + ForkName::Base | ForkName::Altair | ForkName::Gloas | ForkName::Heze => { return Err(serde::de::Error::custom(format!( "BuilderBid failed to deserialize: unsupported fork '{}'", context diff --git a/consensus/types/src/core/chain_spec.rs b/consensus/types/src/core/chain_spec.rs index 73163060e3b..d850b689502 100644 --- a/consensus/types/src/core/chain_spec.rs +++ b/consensus/types/src/core/chain_spec.rs @@ -259,6 +259,13 @@ pub struct ChainSpec { pub consolidation_churn_limit_quotient: u64, pub max_per_epoch_activation_churn_limit_gloas: u64, + /* + * Heze hard fork params + */ + pub heze_fork_version: [u8; 4], + /// The Heze fork epoch is optional, with `None` representing "Heze never happens". + pub heze_fork_epoch: Option, + /* * Networking */ @@ -381,6 +388,7 @@ impl ChainSpec { /// Returns the name of the fork which is active at `epoch`. pub fn fork_name_at_epoch(&self, epoch: Epoch) -> ForkName { let forks = [ + (self.heze_fork_epoch, ForkName::Heze), (self.gloas_fork_epoch, ForkName::Gloas), (self.fulu_fork_epoch, ForkName::Fulu), (self.electra_fork_epoch, ForkName::Electra), @@ -413,6 +421,7 @@ impl ChainSpec { ForkName::Electra => self.electra_fork_version, ForkName::Fulu => self.fulu_fork_version, ForkName::Gloas => self.gloas_fork_version, + ForkName::Heze => self.heze_fork_version, } } @@ -432,6 +441,7 @@ impl ChainSpec { ForkName::Electra => self.electra_fork_epoch, ForkName::Fulu => self.fulu_fork_epoch, ForkName::Gloas => self.gloas_fork_epoch, + ForkName::Heze => self.heze_fork_epoch, } } @@ -476,6 +486,12 @@ impl ChainSpec { .is_some_and(|gloas_fork_epoch| gloas_fork_epoch != self.far_future_epoch) } + /// Returns true if `HEZE_FORK_EPOCH` is set and is not set to `FAR_FUTURE_EPOCH`. + pub fn is_heze_scheduled(&self) -> bool { + self.heze_fork_epoch + .is_some_and(|heze_fork_epoch| heze_fork_epoch != self.far_future_epoch) + } + /// Returns a full `Fork` struct for a given epoch. pub fn fork_at_epoch(&self, epoch: Epoch) -> Fork { let current_fork_name = self.fork_name_at_epoch(epoch); @@ -1297,6 +1313,12 @@ impl ChainSpec { .expect("calculation does not overflow"), max_request_payloads: 128, + /* + * Heze hard fork params + */ + heze_fork_version: [0x08, 0x00, 0x00, 0x00], + heze_fork_epoch: None, + /* * Network specific */ @@ -1449,6 +1471,9 @@ impl ChainSpec { u64::checked_pow(2, 7)?.checked_mul(u64::checked_pow(10, 9)?) }) .expect("calculation does not overflow"), + // Heze + heze_fork_version: [0x08, 0x00, 0x00, 0x01], + heze_fork_epoch: None, /* * Derived time values (set by `compute_derived_values()`) @@ -1724,6 +1749,12 @@ impl ChainSpec { .expect("calculation does not overflow"), max_request_payloads: 128, + /* + * Heze hard fork params + */ + heze_fork_version: [0xff, 0xff, 0xff, 0xff], + heze_fork_epoch: None, + /* * Network specific */ @@ -1998,6 +2029,14 @@ pub struct Config { #[serde(deserialize_with = "deserialize_fork_epoch")] pub gloas_fork_epoch: Option>, + #[serde(default = "default_heze_fork_version")] + #[serde(with = "serde_utils::bytes_4_hex")] + heze_fork_version: [u8; 4], + #[serde(default)] + #[serde(serialize_with = "serialize_fork_epoch")] + #[serde(deserialize_with = "deserialize_fork_epoch")] + pub heze_fork_epoch: Option>, + #[serde(default)] #[serde(skip_serializing_if = "Option::is_none")] seconds_per_slot: Option>, @@ -2219,6 +2258,11 @@ fn default_gloas_fork_version() -> [u8; 4] { [0xff, 0xff, 0xff, 0xff] } +fn default_heze_fork_version() -> [u8; 4] { + // This value shouldn't be used. + [0xff, 0xff, 0xff, 0xff] +} + /// Placeholder value: 2^256-2^10 (115792089237316195423570985008687907853269984665640564039457584007913129638912). /// /// Taken from https://github.com/ethereum/consensus-specs/blob/d5e4828aecafaf1c57ef67a5f23c4ae7b08c5137/configs/mainnet.yaml#L15-L16 @@ -2623,6 +2667,11 @@ impl Config { .gloas_fork_epoch .map(|epoch| MaybeQuoted { value: epoch }), + heze_fork_version: spec.heze_fork_version, + heze_fork_epoch: spec + .heze_fork_epoch + .map(|epoch| MaybeQuoted { value: epoch }), + seconds_per_slot: Some(MaybeQuoted { value: spec.seconds_per_slot, }), @@ -2742,6 +2791,8 @@ impl Config { fulu_fork_version, gloas_fork_version, gloas_fork_epoch, + heze_fork_version, + heze_fork_epoch, seconds_per_slot, slot_duration_ms, seconds_per_eth1_block, @@ -2841,6 +2892,8 @@ impl Config { fulu_fork_version, gloas_fork_version, gloas_fork_epoch: gloas_fork_epoch.map(|q| q.value), + heze_fork_version, + heze_fork_epoch: heze_fork_epoch.map(|q| q.value), seconds_per_slot: seconds_per_slot .map(|q| q.value) .or_else(|| slot_duration_ms.and_then(|q| q.value.checked_div(1000)))?, @@ -3879,8 +3932,6 @@ mod yaml_tests { /// list as new forks are added. const UPSTREAM_KEYS_NOT_IN_LIGHTHOUSE: &[&str] = &[ // Forks not yet implemented - "HEZE_FORK_VERSION", - "HEZE_FORK_EPOCH", "EIP7928_FORK_VERSION", "EIP7928_FORK_EPOCH", // Gloas params not yet in Config diff --git a/consensus/types/src/core/config_and_preset.rs b/consensus/types/src/core/config_and_preset.rs index 8538e6e6096..f3e5bd5d8c2 100644 --- a/consensus/types/src/core/config_and_preset.rs +++ b/consensus/types/src/core/config_and_preset.rs @@ -6,14 +6,14 @@ use superstruct::superstruct; use crate::core::{ AltairPreset, BasePreset, BellatrixPreset, CapellaPreset, ChainSpec, Config, DenebPreset, - ElectraPreset, EthSpec, FuluPreset, GloasPreset, consts, + ElectraPreset, EthSpec, FuluPreset, GloasPreset, HezePreset, consts, }; /// Fusion of a runtime-config with the compile-time preset values. /// /// Mostly useful for the API. #[superstruct( - variants(Deneb, Electra, Fulu, Gloas), + variants(Deneb, Electra, Fulu, Gloas, Heze), variant_attributes(derive(Serialize, Deserialize, Debug, PartialEq, Clone)) )] #[derive(Serialize, Deserialize, Debug, PartialEq, Clone)] @@ -32,15 +32,18 @@ pub struct ConfigAndPreset { pub capella_preset: CapellaPreset, #[serde(flatten)] pub deneb_preset: DenebPreset, - #[superstruct(only(Electra, Fulu, Gloas))] + #[superstruct(only(Electra, Fulu, Gloas, Heze))] #[serde(flatten)] pub electra_preset: ElectraPreset, - #[superstruct(only(Fulu, Gloas))] + #[superstruct(only(Fulu, Gloas, Heze))] #[serde(flatten)] pub fulu_preset: FuluPreset, - #[superstruct(only(Gloas))] + #[superstruct(only(Gloas, Heze))] #[serde(flatten)] pub gloas_preset: GloasPreset, + #[superstruct(only(Heze))] + #[serde(flatten)] + pub heze_preset: HezePreset, /// The `extra_fields` map allows us to gracefully decode fields intended for future hard forks. #[serde(flatten)] pub extra_fields: HashMap, @@ -56,7 +59,26 @@ impl ConfigAndPreset { let deneb_preset = DenebPreset::from_chain_spec::(spec); let extra_fields = get_extra_fields(spec); - if spec.is_gloas_scheduled() { + if spec.is_heze_scheduled() { + let electra_preset = ElectraPreset::from_chain_spec::(spec); + let fulu_preset = FuluPreset::from_chain_spec::(spec); + let gloas_preset = GloasPreset::from_chain_spec::(spec); + let heze_preset = HezePreset::from_chain_spec::(spec); + + ConfigAndPreset::Heze(ConfigAndPresetHeze { + config, + base_preset, + altair_preset, + bellatrix_preset, + capella_preset, + deneb_preset, + electra_preset, + fulu_preset, + gloas_preset, + heze_preset, + extra_fields, + }) + } else if spec.is_gloas_scheduled() { let electra_preset = ElectraPreset::from_chain_spec::(spec); let fulu_preset = FuluPreset::from_chain_spec::(spec); let gloas_preset = GloasPreset::from_chain_spec::(spec); @@ -166,6 +188,7 @@ mod test { .open(tmp_file.as_ref()) .expect("error opening file"); let mut mainnet_spec = ChainSpec::mainnet(); + // TODO(heze): bump this test to roundtrip a heze config once Heze is enabled. // setting gloas_fork_epoch because we are roundtripping a gloas config mainnet_spec.gloas_fork_epoch = Some(Epoch::new(42)); let mut yamlconfig = ConfigAndPreset::from_chain_spec::(&mainnet_spec); diff --git a/consensus/types/src/core/mod.rs b/consensus/types/src/core/mod.rs index f722ac51917..471e53309d2 100644 --- a/consensus/types/src/core/mod.rs +++ b/consensus/types/src/core/mod.rs @@ -22,7 +22,7 @@ pub use application_domain::{APPLICATION_DOMAIN_BUILDER, ApplicationDomain}; pub use chain_spec::{BlobParameters, BlobSchedule, ChainSpec, Config, Domain}; pub use config_and_preset::{ ConfigAndPreset, ConfigAndPresetDeneb, ConfigAndPresetElectra, ConfigAndPresetFulu, - ConfigAndPresetGloas, get_extra_fields, + ConfigAndPresetGloas, ConfigAndPresetHeze, get_extra_fields, }; pub use enr_fork_id::EnrForkId; pub use eth_spec::{EthSpec, EthSpecId, GNOSIS, GnosisEthSpec, MainnetEthSpec, MinimalEthSpec}; @@ -31,7 +31,7 @@ pub use graffiti::{GRAFFITI_BYTES_LEN, Graffiti, GraffitiString}; pub use non_zero_usize::new_non_zero_usize; pub use preset::{ AltairPreset, BasePreset, BellatrixPreset, CapellaPreset, DenebPreset, ElectraPreset, - FuluPreset, GloasPreset, + FuluPreset, GloasPreset, HezePreset, }; pub use relative_epoch::{Error as RelativeEpochError, RelativeEpoch}; pub use signing_data::{SignedRoot, SigningData}; diff --git a/consensus/types/src/core/preset.rs b/consensus/types/src/core/preset.rs index d9043a5d778..0d8fe35933d 100644 --- a/consensus/types/src/core/preset.rs +++ b/consensus/types/src/core/preset.rs @@ -364,6 +364,16 @@ impl GloasPreset { } } +#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)] +#[serde(rename_all = "UPPERCASE")] +pub struct HezePreset {} + +impl HezePreset { + pub fn from_chain_spec(_spec: &ChainSpec) -> Self { + Self {} + } +} + #[cfg(test)] mod test { use super::*; diff --git a/consensus/types/src/data/data_column_sidecar.rs b/consensus/types/src/data/data_column_sidecar.rs index d15651730fe..48b86328bd2 100644 --- a/consensus/types/src/data/data_column_sidecar.rs +++ b/consensus/types/src/data/data_column_sidecar.rs @@ -132,7 +132,7 @@ impl DataColumnSidecar { ForkName::Fulu => Ok(DataColumnSidecar::Fulu( DataColumnSidecarFulu::from_ssz_bytes(bytes)?, )), - ForkName::Gloas => Ok(DataColumnSidecar::Gloas( + ForkName::Gloas | ForkName::Heze => Ok(DataColumnSidecar::Gloas( DataColumnSidecarGloas::from_ssz_bytes(bytes)?, )), } diff --git a/consensus/types/src/execution/dumb_macros.rs b/consensus/types/src/execution/dumb_macros.rs index 4eae416bb56..98958da2e46 100644 --- a/consensus/types/src/execution/dumb_macros.rs +++ b/consensus/types/src/execution/dumb_macros.rs @@ -30,6 +30,7 @@ macro_rules! map_execution_payload_into_full_payload { f(inner, FullPayload::Fulu) } ExecutionPayload::Gloas(_) => panic!("FullPayload::Gloas does not exist!"), + ExecutionPayload::Heze(_) => panic!("FullPayload::Heze does not exist!"), } }; } @@ -59,6 +60,7 @@ macro_rules! map_execution_payload_into_blinded_payload { f(inner, BlindedPayload::Fulu) } ExecutionPayload::Gloas(_) => panic!("BlindedPayload::Gloas does not exist!"), + ExecutionPayload::Heze(_) => panic!("BlindedPayload::Heze does not exist!"), } }; } @@ -103,6 +105,7 @@ macro_rules! map_execution_payload_ref_into_execution_payload_header { f(inner, ExecutionPayloadHeader::Fulu) } ExecutionPayloadRef::Gloas(_) => panic!("ExecutionPayloadHeader::Gloas does not exist!"), + ExecutionPayloadRef::Heze(_) => panic!("ExecutionPayloadHeader::Heze does not exist!"), } } } diff --git a/consensus/types/src/execution/execution_payload.rs b/consensus/types/src/execution/execution_payload.rs index c444c03157b..f5509ee06d5 100644 --- a/consensus/types/src/execution/execution_payload.rs +++ b/consensus/types/src/execution/execution_payload.rs @@ -22,7 +22,7 @@ pub type Transactions = VariableList< >; #[superstruct( - variants(Bellatrix, Capella, Deneb, Electra, Fulu, Gloas), + variants(Bellatrix, Capella, Deneb, Electra, Fulu, Gloas, Heze), variant_attributes( derive( Default, @@ -98,19 +98,19 @@ pub struct ExecutionPayload { pub block_hash: ExecutionBlockHash, #[serde(with = "ssz_types::serde_utils::list_of_hex_var_list")] pub transactions: Transactions, - #[superstruct(only(Capella, Deneb, Electra, Fulu, Gloas))] + #[superstruct(only(Capella, Deneb, Electra, Fulu, Gloas, Heze))] pub withdrawals: Withdrawals, - #[superstruct(only(Deneb, Electra, Fulu, Gloas), partial_getter(copy))] + #[superstruct(only(Deneb, Electra, Fulu, Gloas, Heze), 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, Gloas, Heze), partial_getter(copy))] #[serde(with = "serde_utils::quoted_u64")] pub excess_blob_gas: u64, /// EIP-7928: Block access list - #[superstruct(only(Gloas))] + #[superstruct(only(Gloas, Heze))] #[serde(with = "ssz_types::serde_utils::hex_var_list")] pub block_access_list: VariableList, - #[superstruct(only(Gloas), partial_getter(copy))] + #[superstruct(only(Gloas, Heze), partial_getter(copy))] pub slot_number: Slot, } @@ -139,6 +139,7 @@ impl ForkVersionDecode for ExecutionPayload { ForkName::Electra => ExecutionPayloadElectra::from_ssz_bytes(bytes).map(Self::Electra), ForkName::Fulu => ExecutionPayloadFulu::from_ssz_bytes(bytes).map(Self::Fulu), ForkName::Gloas => ExecutionPayloadGloas::from_ssz_bytes(bytes).map(Self::Gloas), + ForkName::Heze => ExecutionPayloadHeze::from_ssz_bytes(bytes).map(Self::Heze), } } } @@ -190,6 +191,9 @@ impl<'de, E: EthSpec> ContextDeserialize<'de, ForkName> for ExecutionPayload ForkName::Gloas => { Self::Gloas(Deserialize::deserialize(deserializer).map_err(convert_err)?) } + ForkName::Heze => { + Self::Heze(Deserialize::deserialize(deserializer).map_err(convert_err)?) + } }) } } @@ -203,6 +207,7 @@ impl ExecutionPayload { ExecutionPayload::Electra(_) => ForkName::Electra, ExecutionPayload::Fulu(_) => ForkName::Fulu, ExecutionPayload::Gloas(_) => ForkName::Gloas, + ExecutionPayload::Heze(_) => ForkName::Heze, } } } diff --git a/consensus/types/src/execution/execution_payload_header.rs b/consensus/types/src/execution/execution_payload_header.rs index 54cc1824489..cbbbfecbe7e 100644 --- a/consensus/types/src/execution/execution_payload_header.rs +++ b/consensus/types/src/execution/execution_payload_header.rs @@ -133,7 +133,7 @@ impl ExecutionPayloadHeader { ExecutionPayloadHeaderElectra::from_ssz_bytes(bytes).map(Self::Electra) } ForkName::Fulu => ExecutionPayloadHeaderFulu::from_ssz_bytes(bytes).map(Self::Fulu), - ForkName::Gloas => Err(ssz::DecodeError::BytesInvalid(format!( + ForkName::Gloas | ForkName::Heze => Err(ssz::DecodeError::BytesInvalid(format!( "unsupported fork for ExecutionPayloadHeader: {fork_name}", ))), } @@ -142,7 +142,10 @@ impl ExecutionPayloadHeader { #[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.gloas_enabled() { + if fork_name.heze_enabled() { + // TODO(Heze): check this + 0 + } else if fork_name.gloas_enabled() { // TODO(EIP7732): check this 0 } else if fork_name.bellatrix_enabled() { @@ -530,7 +533,7 @@ impl<'de, E: EthSpec> ContextDeserialize<'de, ForkName> for ExecutionPayloadHead Self::Fulu(Deserialize::deserialize(deserializer).map_err(convert_err)?) } - ForkName::Base | ForkName::Altair | ForkName::Gloas => { + ForkName::Base | ForkName::Altair | ForkName::Gloas | ForkName::Heze => { return Err(serde::de::Error::custom(format!( "ExecutionPayloadHeader failed to deserialize: unsupported fork '{}'", context diff --git a/consensus/types/src/execution/execution_requests.rs b/consensus/types/src/execution/execution_requests.rs index dc14b71cd5d..0643d4d06f8 100644 --- a/consensus/types/src/execution/execution_requests.rs +++ b/consensus/types/src/execution/execution_requests.rs @@ -176,7 +176,9 @@ impl ForkVersionDecode for ExecutionRequests { ForkName::Electra | ForkName::Fulu => { ExecutionRequestsElectra::from_ssz_bytes(bytes).map(Self::Electra) } - ForkName::Gloas => ExecutionRequestsGloas::from_ssz_bytes(bytes).map(Self::Gloas), + ForkName::Gloas | ForkName::Heze => { + ExecutionRequestsGloas::from_ssz_bytes(bytes).map(Self::Gloas) + } } } } diff --git a/consensus/types/src/execution/mod.rs b/consensus/types/src/execution/mod.rs index befc27ceab6..380fd378a94 100644 --- a/consensus/types/src/execution/mod.rs +++ b/consensus/types/src/execution/mod.rs @@ -18,8 +18,8 @@ pub use eth1_data::Eth1Data; pub use execution_block_header::{EncodableExecutionBlockHeader, ExecutionBlockHeader}; pub use execution_payload::{ ExecutionPayload, ExecutionPayloadBellatrix, ExecutionPayloadCapella, ExecutionPayloadDeneb, - ExecutionPayloadElectra, ExecutionPayloadFulu, ExecutionPayloadGloas, ExecutionPayloadRef, - Transaction, Transactions, + ExecutionPayloadElectra, ExecutionPayloadFulu, ExecutionPayloadGloas, ExecutionPayloadHeze, + ExecutionPayloadRef, Transaction, Transactions, }; pub use execution_payload_bid::ExecutionPayloadBid; pub use execution_payload_envelope::ExecutionPayloadEnvelope; diff --git a/consensus/types/src/execution/payload.rs b/consensus/types/src/execution/payload.rs index 0b3ba23e121..1abfe741274 100644 --- a/consensus/types/src/execution/payload.rs +++ b/consensus/types/src/execution/payload.rs @@ -359,7 +359,7 @@ impl FullPayload { ForkName::Deneb => Ok(FullPayloadDeneb::default().into()), ForkName::Electra => Ok(FullPayloadElectra::default().into()), ForkName::Fulu => Ok(FullPayloadFulu::default().into()), - ForkName::Gloas => Err(BeaconStateError::IncorrectStateVariant), + ForkName::Gloas | ForkName::Heze => Err(BeaconStateError::IncorrectStateVariant), } } } diff --git a/consensus/types/src/fork/fork_macros.rs b/consensus/types/src/fork/fork_macros.rs index 0c7f382ffc5..3f1d12f0a1e 100644 --- a/consensus/types/src/fork/fork_macros.rs +++ b/consensus/types/src/fork/fork_macros.rs @@ -55,6 +55,10 @@ macro_rules! map_fork_name_with { let (value, extra_data) = $body; ($t::Gloas(value), extra_data) } + $crate::fork::ForkName::Heze => { + let (value, extra_data) = $body; + ($t::Heze(value), extra_data) + } } }; } diff --git a/consensus/types/src/fork/fork_name.rs b/consensus/types/src/fork/fork_name.rs index e9ec5fbe41e..3b5c1467150 100644 --- a/consensus/types/src/fork/fork_name.rs +++ b/consensus/types/src/fork/fork_name.rs @@ -23,6 +23,7 @@ pub enum ForkName { Electra, Fulu, Gloas, + Heze, } impl ForkName { @@ -36,6 +37,7 @@ impl ForkName { ForkName::Electra, ForkName::Fulu, ForkName::Gloas, + ForkName::Heze, ] } @@ -71,6 +73,7 @@ impl ForkName { spec.electra_fork_epoch = None; spec.fulu_fork_epoch = None; spec.gloas_fork_epoch = None; + spec.heze_fork_epoch = None; spec } ForkName::Altair => { @@ -81,6 +84,7 @@ impl ForkName { spec.electra_fork_epoch = None; spec.fulu_fork_epoch = None; spec.gloas_fork_epoch = None; + spec.heze_fork_epoch = None; spec } ForkName::Bellatrix => { @@ -91,6 +95,7 @@ impl ForkName { spec.electra_fork_epoch = None; spec.fulu_fork_epoch = None; spec.gloas_fork_epoch = None; + spec.heze_fork_epoch = None; spec } ForkName::Capella => { @@ -101,6 +106,7 @@ impl ForkName { spec.electra_fork_epoch = None; spec.fulu_fork_epoch = None; spec.gloas_fork_epoch = None; + spec.heze_fork_epoch = None; spec } ForkName::Deneb => { @@ -111,6 +117,7 @@ impl ForkName { spec.electra_fork_epoch = None; spec.fulu_fork_epoch = None; spec.gloas_fork_epoch = None; + spec.heze_fork_epoch = None; spec } ForkName::Electra => { @@ -121,6 +128,7 @@ impl ForkName { spec.electra_fork_epoch = Some(Epoch::new(0)); spec.fulu_fork_epoch = None; spec.gloas_fork_epoch = None; + spec.heze_fork_epoch = None; spec } ForkName::Fulu => { @@ -131,6 +139,7 @@ impl ForkName { spec.electra_fork_epoch = Some(Epoch::new(0)); spec.fulu_fork_epoch = Some(Epoch::new(0)); spec.gloas_fork_epoch = None; + spec.heze_fork_epoch = None; spec } ForkName::Gloas => { @@ -141,6 +150,18 @@ impl ForkName { spec.electra_fork_epoch = Some(Epoch::new(0)); spec.fulu_fork_epoch = Some(Epoch::new(0)); spec.gloas_fork_epoch = Some(Epoch::new(0)); + spec.heze_fork_epoch = None; + spec + } + ForkName::Heze => { + spec.altair_fork_epoch = Some(Epoch::new(0)); + spec.bellatrix_fork_epoch = Some(Epoch::new(0)); + spec.capella_fork_epoch = Some(Epoch::new(0)); + spec.deneb_fork_epoch = Some(Epoch::new(0)); + spec.electra_fork_epoch = Some(Epoch::new(0)); + spec.fulu_fork_epoch = Some(Epoch::new(0)); + spec.gloas_fork_epoch = Some(Epoch::new(0)); + spec.heze_fork_epoch = Some(Epoch::new(0)); spec } } @@ -159,6 +180,7 @@ impl ForkName { ForkName::Electra => Some(ForkName::Deneb), ForkName::Fulu => Some(ForkName::Electra), ForkName::Gloas => Some(ForkName::Fulu), + ForkName::Heze => Some(ForkName::Gloas), } } @@ -174,7 +196,8 @@ impl ForkName { ForkName::Deneb => Some(ForkName::Electra), ForkName::Electra => Some(ForkName::Fulu), ForkName::Fulu => Some(ForkName::Gloas), - ForkName::Gloas => None, + ForkName::Gloas => Some(ForkName::Heze), + ForkName::Heze => None, } } @@ -206,6 +229,10 @@ impl ForkName { self >= ForkName::Gloas } + pub fn heze_enabled(self) -> bool { + self >= ForkName::Heze + } + pub fn fork_ascii(self) { if self == ForkName::Fulu { println!( @@ -260,6 +287,7 @@ impl FromStr for ForkName { "electra" => ForkName::Electra, "fulu" => ForkName::Fulu, "gloas" => ForkName::Gloas, + "heze" => ForkName::Heze, _ => return Err(format!("unknown fork name: {}", fork_name)), }) } @@ -276,6 +304,7 @@ impl Display for ForkName { ForkName::Electra => "electra".fmt(f), ForkName::Fulu => "fulu".fmt(f), ForkName::Gloas => "gloas".fmt(f), + ForkName::Heze => "heze".fmt(f), } } } diff --git a/consensus/types/src/light_client/error.rs b/consensus/types/src/light_client/error.rs index 4c7a30db5e6..17a499962c1 100644 --- a/consensus/types/src/light_client/error.rs +++ b/consensus/types/src/light_client/error.rs @@ -15,6 +15,7 @@ pub enum LightClientError { BeaconBlockBodyError, InconsistentFork, GloasNotImplemented, + HezeNotImplemented, } 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 18ff246df7c..2f9c3a3f931 100644 --- a/consensus/types/src/light_client/light_client_bootstrap.rs +++ b/consensus/types/src/light_client/light_client_bootstrap.rs @@ -106,7 +106,7 @@ impl LightClientBootstrap { ForkName::Electra => Self::Electra(LightClientBootstrapElectra::from_ssz_bytes(bytes)?), ForkName::Fulu => Self::Fulu(LightClientBootstrapFulu::from_ssz_bytes(bytes)?), // TODO(gloas): implement Gloas light client - ForkName::Base | ForkName::Gloas => { + ForkName::Base | ForkName::Gloas | ForkName::Heze => { return Err(ssz::DecodeError::BytesInvalid(format!( "LightClientBootstrap decoding for {fork_name} not implemented" ))); @@ -128,7 +128,9 @@ impl LightClientBootstrap { ForkName::Electra => as Encode>::ssz_fixed_len(), ForkName::Fulu => as Encode>::ssz_fixed_len(), // TODO(gloas): implement Gloas light client - ForkName::Gloas => as Encode>::ssz_fixed_len(), + ForkName::Gloas | ForkName::Heze => { + as Encode>::ssz_fixed_len() + } }; fixed_len + LightClientHeader::::ssz_max_var_len_for_fork(fork_name) } @@ -181,6 +183,7 @@ impl LightClientBootstrap { }), // TODO(gloas): implement Gloas light client ForkName::Gloas => return Err(LightClientError::GloasNotImplemented), + ForkName::Heze => return Err(LightClientError::HezeNotImplemented), }; Ok(light_client_bootstrap) @@ -236,6 +239,7 @@ impl LightClientBootstrap { }), // TODO(gloas): implement Gloas light client ForkName::Gloas => return Err(LightClientError::GloasNotImplemented), + ForkName::Heze => return Err(LightClientError::HezeNotImplemented), }; Ok(light_client_bootstrap) @@ -275,7 +279,7 @@ impl<'de, E: EthSpec> ContextDeserialize<'de, ForkName> for LightClientBootstrap ForkName::Fulu => { Self::Fulu(Deserialize::deserialize(deserializer).map_err(convert_err)?) } - ForkName::Gloas => { + ForkName::Gloas | ForkName::Heze => { // TODO(EIP-7732): check if this is correct return Err(serde::de::Error::custom(format!( "LightClientBootstrap failed to deserialize: unsupported fork '{}'", 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 42afbdfc4b4..ef23a0584ac 100644 --- a/consensus/types/src/light_client/light_client_finality_update.rs +++ b/consensus/types/src/light_client/light_client_finality_update.rs @@ -166,6 +166,7 @@ impl LightClientFinalityUpdate { signature_slot, }), ForkName::Gloas => return Err(LightClientError::GloasNotImplemented), + ForkName::Heze => return Err(LightClientError::HezeNotImplemented), ForkName::Base => return Err(LightClientError::AltairForkNotActive), }; @@ -220,7 +221,7 @@ impl LightClientFinalityUpdate { } ForkName::Fulu => Self::Fulu(LightClientFinalityUpdateFulu::from_ssz_bytes(bytes)?), // TODO(gloas): implement Gloas light client - ForkName::Base | ForkName::Gloas => { + ForkName::Base | ForkName::Gloas | ForkName::Heze => { return Err(ssz::DecodeError::BytesInvalid(format!( "LightClientFinalityUpdate decoding for {fork_name} not implemented" ))); @@ -242,7 +243,7 @@ impl LightClientFinalityUpdate { ForkName::Electra => as Encode>::ssz_fixed_len(), ForkName::Fulu => as Encode>::ssz_fixed_len(), // TODO(gloas): implement Gloas light client - ForkName::Gloas => 0, + ForkName::Gloas | ForkName::Heze => 0, }; // `2 *` because there are two headers in the update fixed_size + 2 * LightClientHeader::::ssz_max_var_len_for_fork(fork_name) @@ -295,7 +296,7 @@ impl<'de, E: EthSpec> ContextDeserialize<'de, ForkName> for LightClientFinalityU ForkName::Fulu => { Self::Fulu(Deserialize::deserialize(deserializer).map_err(convert_err)?) } - ForkName::Gloas => { + ForkName::Gloas | ForkName::Heze => { // TODO(EIP-7732): check if this is correct return Err(serde::de::Error::custom(format!( "LightClientBootstrap failed to deserialize: unsupported fork '{}'", diff --git a/consensus/types/src/light_client/light_client_header.rs b/consensus/types/src/light_client/light_client_header.rs index df6d884ba8c..0dcef6d1a02 100644 --- a/consensus/types/src/light_client/light_client_header.rs +++ b/consensus/types/src/light_client/light_client_header.rs @@ -99,6 +99,7 @@ impl LightClientHeader { } // TODO(gloas): implement Gloas light client ForkName::Gloas => return Err(LightClientError::GloasNotImplemented), + ForkName::Heze => return Err(LightClientError::HezeNotImplemented), }; Ok(header) } @@ -121,7 +122,7 @@ impl LightClientHeader { LightClientHeader::Fulu(LightClientHeaderFulu::from_ssz_bytes(bytes)?) } // TODO(gloas): implement Gloas light client - ForkName::Base | ForkName::Gloas => { + ForkName::Base | ForkName::Gloas | ForkName::Heze => { return Err(ssz::DecodeError::BytesInvalid(format!( "LightClientHeader decoding for {fork_name} not implemented" ))); @@ -140,7 +141,7 @@ impl LightClientHeader { } pub fn ssz_max_var_len_for_fork(fork_name: ForkName) -> usize { - if fork_name.gloas_enabled() { + if fork_name.gloas_enabled() || fork_name.heze_enabled() { // TODO(EIP7732): check this 0 } else if fork_name.capella_enabled() { @@ -352,7 +353,7 @@ impl<'de, E: EthSpec> ContextDeserialize<'de, ForkName> for LightClientHeader }; Ok(match context { // TODO(gloas): implement Gloas light client - ForkName::Base | ForkName::Gloas => { + ForkName::Base | ForkName::Gloas | ForkName::Heze => { return Err(serde::de::Error::custom(format!( "LightClientFinalityUpdate failed to deserialize: unsupported fork '{}'", context 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 f762c4ad61b..f6038c00ed1 100644 --- a/consensus/types/src/light_client/light_client_optimistic_update.rs +++ b/consensus/types/src/light_client/light_client_optimistic_update.rs @@ -112,6 +112,7 @@ impl LightClientOptimisticUpdate { signature_slot, }), ForkName::Gloas => return Err(LightClientError::GloasNotImplemented), + ForkName::Heze => return Err(LightClientError::HezeNotImplemented), ForkName::Base => return Err(LightClientError::AltairForkNotActive), }; @@ -168,7 +169,7 @@ impl LightClientOptimisticUpdate { } ForkName::Fulu => Self::Fulu(LightClientOptimisticUpdateFulu::from_ssz_bytes(bytes)?), // TODO(gloas): implement Gloas light client - ForkName::Base | ForkName::Gloas => { + ForkName::Base | ForkName::Gloas | ForkName::Heze => { return Err(ssz::DecodeError::BytesInvalid(format!( "LightClientOptimisticUpdate decoding for {fork_name} not implemented" ))); @@ -190,7 +191,7 @@ impl LightClientOptimisticUpdate { ForkName::Electra => as Encode>::ssz_fixed_len(), ForkName::Fulu => as Encode>::ssz_fixed_len(), // TODO(gloas): implement Gloas light client - ForkName::Gloas => 0, + ForkName::Gloas | ForkName::Heze => 0, }; fixed_len + LightClientHeader::::ssz_max_var_len_for_fork(fork_name) } @@ -242,7 +243,7 @@ impl<'de, E: EthSpec> ContextDeserialize<'de, ForkName> for LightClientOptimisti ForkName::Fulu => { Self::Fulu(Deserialize::deserialize(deserializer).map_err(convert_err)?) } - ForkName::Gloas => { + ForkName::Gloas | ForkName::Heze => { // TODO(EIP-7732): check if this is correct return Err(serde::de::Error::custom(format!( "LightClientBootstrap failed to deserialize: unsupported fork '{}'", diff --git a/consensus/types/src/light_client/light_client_update.rs b/consensus/types/src/light_client/light_client_update.rs index 0e7e2856516..25e0f25dbd6 100644 --- a/consensus/types/src/light_client/light_client_update.rs +++ b/consensus/types/src/light_client/light_client_update.rs @@ -129,7 +129,7 @@ impl<'de, E: EthSpec> ContextDeserialize<'de, ForkName> for LightClientUpdate }; Ok(match context { // TODO(gloas): implement Gloas light client - ForkName::Base | ForkName::Gloas => { + ForkName::Base | ForkName::Gloas | ForkName::Heze => { return Err(serde::de::Error::custom(format!( "LightClientUpdate failed to deserialize: unsupported fork '{}'", context @@ -316,6 +316,7 @@ impl LightClientUpdate { // if you need to test or support lightclient usages // TODO(gloas): implement Gloas light client ForkName::Gloas => return Err(LightClientError::GloasNotImplemented), + ForkName::Heze => return Err(LightClientError::HezeNotImplemented), }; Ok(light_client_update) @@ -331,7 +332,7 @@ impl LightClientUpdate { ForkName::Electra => Self::Electra(LightClientUpdateElectra::from_ssz_bytes(bytes)?), ForkName::Fulu => Self::Fulu(LightClientUpdateFulu::from_ssz_bytes(bytes)?), // TODO(gloas): implement Gloas light client - ForkName::Base | ForkName::Gloas => { + ForkName::Base | ForkName::Gloas | ForkName::Heze => { return Err(ssz::DecodeError::BytesInvalid(format!( "LightClientUpdate decoding for {fork_name} not implemented" ))); @@ -488,7 +489,7 @@ impl LightClientUpdate { ForkName::Electra => as Encode>::ssz_fixed_len(), ForkName::Fulu => as Encode>::ssz_fixed_len(), // TODO(gloas): implement Gloas light client - ForkName::Gloas => 0, + ForkName::Gloas | ForkName::Heze => 0, }; fixed_len + 2 * LightClientHeader::::ssz_max_var_len_for_fork(fork_name) } diff --git a/consensus/types/src/state/beacon_state.rs b/consensus/types/src/state/beacon_state.rs index 181245c7477..2c5628a5efd 100644 --- a/consensus/types/src/state/beacon_state.rs +++ b/consensus/types/src/state/beacon_state.rs @@ -276,7 +276,7 @@ impl From for Hash256 { /// /// https://github.com/sigp/milhouse/issues/43 #[superstruct( - variants(Base, Altair, Bellatrix, Capella, Deneb, Electra, Fulu, Gloas), + variants(Base, Altair, Bellatrix, Capella, Deneb, Electra, Fulu, Gloas, Heze), variant_attributes( derive( Educe, @@ -409,6 +409,20 @@ impl From for Hash256 { groups(tree_lists) )), num_fields(all()), + )), + Heze(metastruct( + mappings( + map_beacon_state_heze_fields(), + map_beacon_state_heze_tree_list_fields(mutable, fallible, groups(tree_lists)), + map_beacon_state_heze_tree_list_fields_immutable(groups(tree_lists)), + ), + bimappings(bimap_beacon_state_heze_tree_list_fields( + other_type = "BeaconStateHeze", + self_mutable, + fallible, + groups(tree_lists) + )), + num_fields(all()), )) ), cast_error( @@ -501,11 +515,11 @@ where // Participation (Altair and later) #[compare_fields(as_iter)] - #[superstruct(only(Altair, Bellatrix, Capella, Deneb, Electra, Fulu, Gloas))] + #[superstruct(only(Altair, Bellatrix, Capella, Deneb, Electra, Fulu, Gloas, Heze))] #[cfg_attr(feature = "arbitrary", arbitrary(default))] #[compare_fields(as_iter)] pub previous_epoch_participation: List, - #[superstruct(only(Altair, Bellatrix, Capella, Deneb, Electra, Fulu, Gloas))] + #[superstruct(only(Altair, Bellatrix, Capella, Deneb, Electra, Fulu, Gloas, Heze))] #[cfg_attr(feature = "arbitrary", arbitrary(default))] pub current_epoch_participation: List, @@ -525,15 +539,15 @@ where // Inactivity #[serde(with = "ssz_types::serde_utils::quoted_u64_var_list")] - #[superstruct(only(Altair, Bellatrix, Capella, Deneb, Electra, Fulu, Gloas))] + #[superstruct(only(Altair, Bellatrix, Capella, Deneb, Electra, Fulu, Gloas, Heze))] #[cfg_attr(feature = "arbitrary", arbitrary(default))] pub inactivity_scores: List, // Light-client sync committees - #[superstruct(only(Altair, Bellatrix, Capella, Deneb, Electra, Fulu, Gloas))] + #[superstruct(only(Altair, Bellatrix, Capella, Deneb, Electra, Fulu, Gloas, Heze))] #[metastruct(exclude_from(tree_lists))] pub current_sync_committee: Arc>, - #[superstruct(only(Altair, Bellatrix, Capella, Deneb, Electra, Fulu, Gloas))] + #[superstruct(only(Altair, Bellatrix, Capella, Deneb, Electra, Fulu, Gloas, Heze))] #[metastruct(exclude_from(tree_lists))] pub next_sync_committee: Arc>, @@ -569,105 +583,105 @@ where #[metastruct(exclude_from(tree_lists))] pub latest_execution_payload_header: ExecutionPayloadHeaderFulu, #[cfg_attr(feature = "arbitrary", arbitrary(default))] - #[superstruct(only(Gloas))] + #[superstruct(only(Gloas, Heze))] #[metastruct(exclude_from(tree_lists))] pub latest_block_hash: ExecutionBlockHash, - #[superstruct(only(Capella, Deneb, Electra, Fulu, Gloas), partial_getter(copy))] + #[superstruct(only(Capella, Deneb, Electra, Fulu, Gloas, Heze), partial_getter(copy))] #[serde(with = "serde_utils::quoted_u64")] #[metastruct(exclude_from(tree_lists))] pub next_withdrawal_index: u64, - #[superstruct(only(Capella, Deneb, Electra, Fulu, Gloas), partial_getter(copy))] + #[superstruct(only(Capella, Deneb, Electra, Fulu, Gloas, Heze), partial_getter(copy))] #[serde(with = "serde_utils::quoted_u64")] #[metastruct(exclude_from(tree_lists))] pub next_withdrawal_validator_index: u64, // Deep history valid from Capella onwards. - #[superstruct(only(Capella, Deneb, Electra, Fulu, Gloas))] + #[superstruct(only(Capella, Deneb, Electra, Fulu, Gloas, Heze))] #[cfg_attr(feature = "arbitrary", arbitrary(default))] pub historical_summaries: List, // Electra - #[superstruct(only(Electra, Fulu, Gloas), partial_getter(copy))] + #[superstruct(only(Electra, Fulu, Gloas, Heze), partial_getter(copy))] #[metastruct(exclude_from(tree_lists))] #[serde(with = "serde_utils::quoted_u64")] pub deposit_requests_start_index: u64, - #[superstruct(only(Electra, Fulu, Gloas), partial_getter(copy))] + #[superstruct(only(Electra, Fulu, Gloas, Heze), partial_getter(copy))] #[metastruct(exclude_from(tree_lists))] #[serde(with = "serde_utils::quoted_u64")] pub deposit_balance_to_consume: u64, - #[superstruct(only(Electra, Fulu, Gloas), partial_getter(copy))] + #[superstruct(only(Electra, Fulu, Gloas, Heze), partial_getter(copy))] #[metastruct(exclude_from(tree_lists))] #[serde(with = "serde_utils::quoted_u64")] pub exit_balance_to_consume: u64, - #[superstruct(only(Electra, Fulu, Gloas), partial_getter(copy))] + #[superstruct(only(Electra, Fulu, Gloas, Heze), partial_getter(copy))] #[metastruct(exclude_from(tree_lists))] pub earliest_exit_epoch: Epoch, - #[superstruct(only(Electra, Fulu, Gloas), partial_getter(copy))] + #[superstruct(only(Electra, Fulu, Gloas, Heze), partial_getter(copy))] #[metastruct(exclude_from(tree_lists))] #[serde(with = "serde_utils::quoted_u64")] pub consolidation_balance_to_consume: u64, - #[superstruct(only(Electra, Fulu, Gloas), partial_getter(copy))] + #[superstruct(only(Electra, Fulu, Gloas, Heze), partial_getter(copy))] #[metastruct(exclude_from(tree_lists))] pub earliest_consolidation_epoch: Epoch, #[compare_fields(as_iter)] #[cfg_attr(feature = "arbitrary", arbitrary(default))] - #[superstruct(only(Electra, Fulu, Gloas))] + #[superstruct(only(Electra, Fulu, Gloas, Heze))] pub pending_deposits: List, #[compare_fields(as_iter)] #[cfg_attr(feature = "arbitrary", arbitrary(default))] - #[superstruct(only(Electra, Fulu, Gloas))] + #[superstruct(only(Electra, Fulu, Gloas, Heze))] pub pending_partial_withdrawals: List, #[compare_fields(as_iter)] #[cfg_attr(feature = "arbitrary", arbitrary(default))] - #[superstruct(only(Electra, Fulu, Gloas))] + #[superstruct(only(Electra, Fulu, Gloas, Heze))] pub pending_consolidations: List, // Fulu #[compare_fields(as_iter)] #[cfg_attr(feature = "arbitrary", arbitrary(default))] - #[superstruct(only(Fulu, Gloas))] + #[superstruct(only(Fulu, Gloas, Heze))] #[serde(with = "ssz_types::serde_utils::quoted_u64_fixed_vec")] pub proposer_lookahead: Vector, // Gloas #[compare_fields(as_iter)] #[cfg_attr(feature = "arbitrary", arbitrary(default))] - #[superstruct(only(Gloas))] + #[superstruct(only(Gloas, Heze))] pub builders: List, #[metastruct(exclude_from(tree_lists))] #[serde(with = "serde_utils::quoted_u64")] - #[superstruct(only(Gloas), partial_getter(copy))] + #[superstruct(only(Gloas, Heze), partial_getter(copy))] pub next_withdrawal_builder_index: BuilderIndex, #[cfg_attr(feature = "arbitrary", arbitrary(default))] - #[superstruct(only(Gloas))] + #[superstruct(only(Gloas, Heze))] #[metastruct(exclude_from(tree_lists))] pub execution_payload_availability: BitVector, #[compare_fields(as_iter)] #[cfg_attr(feature = "arbitrary", arbitrary(default))] - #[superstruct(only(Gloas))] + #[superstruct(only(Gloas, Heze))] pub builder_pending_payments: Vector, #[compare_fields(as_iter)] #[cfg_attr(feature = "arbitrary", arbitrary(default))] - #[superstruct(only(Gloas))] + #[superstruct(only(Gloas, Heze))] pub builder_pending_withdrawals: List, #[cfg_attr(feature = "arbitrary", arbitrary(default))] - #[superstruct(only(Gloas))] + #[superstruct(only(Gloas, Heze))] #[metastruct(exclude_from(tree_lists))] pub latest_execution_payload_bid: ExecutionPayloadBid, #[compare_fields(as_iter)] #[cfg_attr(feature = "arbitrary", arbitrary(default))] - #[superstruct(only(Gloas))] + #[superstruct(only(Gloas, Heze))] pub payload_expected_withdrawals: List, #[compare_fields(as_iter)] #[cfg_attr(feature = "arbitrary", arbitrary(default))] - #[superstruct(only(Gloas))] + #[superstruct(only(Gloas, Heze))] pub ptc_window: Vector, E::PtcWindowLength>, // Caching (not in the spec) @@ -810,6 +824,7 @@ impl BeaconState { BeaconState::Electra { .. } => ForkName::Electra, BeaconState::Fulu { .. } => ForkName::Fulu, BeaconState::Gloas { .. } => ForkName::Gloas, + BeaconState::Heze { .. } => ForkName::Heze, } } @@ -1253,6 +1268,7 @@ impl BeaconState { )), // TODO(EIP-7732): investigate calling functions BeaconState::Gloas(_) => Err(BeaconStateError::IncorrectStateVariant), + BeaconState::Heze(_) => Err(BeaconStateError::IncorrectStateVariant), } } @@ -1280,6 +1296,7 @@ impl BeaconState { )), // TODO(EIP-7732): investigate calling functions BeaconState::Gloas(_) => Err(BeaconStateError::IncorrectStateVariant), + BeaconState::Heze(_) => Err(BeaconStateError::IncorrectStateVariant), } } @@ -1892,6 +1909,16 @@ impl BeaconState { &mut state.exit_cache, &mut state.epoch_cache, )), + BeaconState::Heze(state) => Ok(( + &mut state.validators, + &mut state.balances, + &state.previous_epoch_participation, + &state.current_epoch_participation, + &mut state.inactivity_scores, + &mut state.progressive_balances_cache, + &mut state.exit_cache, + &mut state.epoch_cache, + )), } } @@ -2153,7 +2180,8 @@ impl BeaconState { BeaconState::Deneb(_) | BeaconState::Electra(_) | BeaconState::Fulu(_) - | BeaconState::Gloas(_) => std::cmp::min( + | BeaconState::Gloas(_) + | BeaconState::Heze(_) => std::cmp::min( spec.max_per_epoch_activation_churn_limit, self.get_validator_churn_limit(spec)?, ), @@ -2302,6 +2330,7 @@ impl BeaconState { BeaconState::Electra(state) => Ok(&mut state.current_epoch_participation), BeaconState::Fulu(state) => Ok(&mut state.current_epoch_participation), BeaconState::Gloas(state) => Ok(&mut state.current_epoch_participation), + BeaconState::Heze(state) => Ok(&mut state.current_epoch_participation), } } else if epoch == previous_epoch { match self { @@ -2313,6 +2342,7 @@ impl BeaconState { BeaconState::Electra(state) => Ok(&mut state.previous_epoch_participation), BeaconState::Fulu(state) => Ok(&mut state.previous_epoch_participation), BeaconState::Gloas(state) => Ok(&mut state.previous_epoch_participation), + BeaconState::Heze(state) => Ok(&mut state.previous_epoch_participation), } } else { Err(BeaconStateError::EpochOutOfBounds) @@ -2616,6 +2646,11 @@ impl BeaconState { any_pending_mutations |= self_field.has_pending_updates(); }); } + Self::Heze(self_inner) => { + map_beacon_state_heze_tree_list_fields_immutable!(self_inner, |_, self_field| { + any_pending_mutations |= self_field.has_pending_updates(); + }); + } }; any_pending_mutations } @@ -2912,7 +2947,10 @@ impl BeaconState { | BeaconState::Bellatrix(_) | BeaconState::Capella(_) | BeaconState::Deneb(_) => Err(BeaconStateError::IncorrectStateVariant), - BeaconState::Electra(_) | BeaconState::Fulu(_) | BeaconState::Gloas(_) => { + BeaconState::Electra(_) + | BeaconState::Fulu(_) + | BeaconState::Gloas(_) + | BeaconState::Heze(_) => { // Consume the balance and update state variables *self.exit_balance_to_consume_mut()? = exit_balance_to_consume.safe_sub(exit_balance)?; @@ -2959,7 +2997,10 @@ impl BeaconState { | BeaconState::Bellatrix(_) | BeaconState::Capella(_) | BeaconState::Deneb(_) => Err(BeaconStateError::IncorrectStateVariant), - BeaconState::Electra(_) | BeaconState::Fulu(_) | BeaconState::Gloas(_) => { + BeaconState::Electra(_) + | BeaconState::Fulu(_) + | BeaconState::Gloas(_) + | BeaconState::Heze(_) => { // Consume the balance and update state variables. *self.consolidation_balance_to_consume_mut()? = consolidation_balance_to_consume.safe_sub(consolidation_balance)?; @@ -3037,6 +3078,14 @@ impl BeaconState { ); } (Self::Gloas(_), _) => (), + (Self::Heze(self_inner), Self::Heze(base_inner)) => { + bimap_beacon_state_heze_tree_list_fields!( + self_inner, + base_inner, + |_, self_field, base_field| { self_field.rebase_on(base_field) } + ); + } + (Self::Heze(_), _) => (), } // Use sync committees from `base` if they are equal. @@ -3358,6 +3407,7 @@ impl BeaconState { ForkName::Electra => BeaconStateElectra::::NUM_FIELDS.next_power_of_two(), ForkName::Fulu => BeaconStateFulu::::NUM_FIELDS.next_power_of_two(), ForkName::Gloas => BeaconStateGloas::::NUM_FIELDS.next_power_of_two(), + ForkName::Heze => BeaconStateHeze::::NUM_FIELDS.next_power_of_two(), } } @@ -3411,6 +3461,9 @@ impl BeaconState { Self::Gloas(inner) => { map_beacon_state_gloas_tree_list_fields!(inner, |_, x| { x.apply_updates() }) } + Self::Heze(inner) => { + map_beacon_state_heze_tree_list_fields!(inner, |_, x| { x.apply_updates() }) + } } Ok(()) } @@ -3528,6 +3581,11 @@ impl BeaconState { leaves.push(field.tree_hash_root()); }); } + BeaconState::Heze(state) => { + map_beacon_state_heze_fields!(state, |_, field| { + leaves.push(field.tree_hash_root()); + }); + } }; leaves @@ -3587,6 +3645,7 @@ impl CompareFields for BeaconState { (BeaconState::Electra(x), BeaconState::Electra(y)) => x.compare_fields(y), (BeaconState::Fulu(x), BeaconState::Fulu(y)) => x.compare_fields(y), (BeaconState::Gloas(x), BeaconState::Gloas(y)) => x.compare_fields(y), + (BeaconState::Heze(x), BeaconState::Heze(y)) => x.compare_fields(y), _ => panic!("compare_fields: mismatched state variants",), } } diff --git a/consensus/types/src/state/mod.rs b/consensus/types/src/state/mod.rs index a3bb1b8c9f0..eae0fb7241e 100644 --- a/consensus/types/src/state/mod.rs +++ b/consensus/types/src/state/mod.rs @@ -17,7 +17,8 @@ pub use balance::Balance; pub use beacon_state::{ BeaconState, BeaconStateAltair, BeaconStateBase, BeaconStateBellatrix, BeaconStateCapella, BeaconStateDeneb, BeaconStateElectra, BeaconStateError, BeaconStateFulu, BeaconStateGloas, - BeaconStateHash, BeaconStateRef, CACHED_EPOCHS, DEFAULT_PRE_ELECTRA_WS_PERIOD, Validators, + BeaconStateHash, BeaconStateHeze, BeaconStateRef, CACHED_EPOCHS, DEFAULT_PRE_ELECTRA_WS_PERIOD, + Validators, }; pub use committee_cache::{ CommitteeCache, compute_committee_index_in_epoch, compute_committee_range_in_epoch, diff --git a/consensus/types/src/withdrawal/expected_withdrawals.rs b/consensus/types/src/withdrawal/expected_withdrawals.rs index f9809e6e73d..1c8932a7ad7 100644 --- a/consensus/types/src/withdrawal/expected_withdrawals.rs +++ b/consensus/types/src/withdrawal/expected_withdrawals.rs @@ -2,17 +2,17 @@ use crate::{EthSpec, Withdrawals}; use superstruct::superstruct; #[superstruct( - variants(Capella, Electra, Gloas), + variants(Capella, Electra, Gloas, Heze), variant_attributes(derive(Debug, PartialEq, Clone)) )] #[derive(Debug, PartialEq, Clone)] pub struct ExpectedWithdrawals { pub withdrawals: Withdrawals, - #[superstruct(only(Gloas), partial_getter(copy))] + #[superstruct(only(Gloas, Heze), partial_getter(copy))] pub processed_builder_withdrawals_count: u64, - #[superstruct(only(Electra, Gloas), partial_getter(copy))] + #[superstruct(only(Electra, Gloas, Heze), partial_getter(copy))] pub processed_partial_withdrawals_count: u64, - #[superstruct(only(Gloas), partial_getter(copy))] + #[superstruct(only(Gloas, Heze), partial_getter(copy))] pub processed_builders_sweep_count: u64, #[superstruct(getter(copy))] pub processed_sweep_withdrawals_count: u64, @@ -24,6 +24,7 @@ impl From> for Withdrawals { ExpectedWithdrawals::Capella(ew) => ew.withdrawals, ExpectedWithdrawals::Electra(ew) => ew.withdrawals, ExpectedWithdrawals::Gloas(ew) => ew.withdrawals, + ExpectedWithdrawals::Heze(ew) => ew.withdrawals, } } } diff --git a/consensus/types/src/withdrawal/mod.rs b/consensus/types/src/withdrawal/mod.rs index fbe73517545..696dbbd64c1 100644 --- a/consensus/types/src/withdrawal/mod.rs +++ b/consensus/types/src/withdrawal/mod.rs @@ -6,7 +6,7 @@ mod withdrawal_request; pub use expected_withdrawals::{ ExpectedWithdrawals, ExpectedWithdrawalsCapella, ExpectedWithdrawalsElectra, - ExpectedWithdrawalsGloas, + ExpectedWithdrawalsGloas, ExpectedWithdrawalsHeze, }; pub use pending_partial_withdrawal::PendingPartialWithdrawal; pub use withdrawal::{Withdrawal, Withdrawals}; diff --git a/lcli/src/main.rs b/lcli/src/main.rs index 63dd0f2c5bb..9279bcb3d55 100644 --- a/lcli/src/main.rs +++ b/lcli/src/main.rs @@ -570,6 +570,24 @@ fn main() { until Osaka is triggered on mainnet.") .display_order(0) ) + .arg( + Arg::new("amsterdam-time") + .long("amsterdam-time") + .value_name("UNIX_TIMESTAMP") + .action(ArgAction::Set) + .help("The payload timestamp that enables Amsterdam. No default is provided \ + until Amsterdam is triggered on mainnet.") + .display_order(0) + ) + .arg( + Arg::new("heze-time") + .long("heze-time") + .value_name("UNIX_TIMESTAMP") + .action(ArgAction::Set) + .help("The payload timestamp that enables Heze. No default is provided \ + until Heze is triggered on mainnet.") + .display_order(0) + ) ) .subcommand( Command::new("http-sync") diff --git a/lcli/src/mock_el.rs b/lcli/src/mock_el.rs index 6086067a477..628f2cd4d56 100644 --- a/lcli/src/mock_el.rs +++ b/lcli/src/mock_el.rs @@ -20,6 +20,7 @@ pub fn run(mut env: Environment, matches: &ArgMatches) -> Result< let prague_time = parse_optional(matches, "prague-time")?; let osaka_time = parse_optional(matches, "osaka-time")?; let amsterdam_time = parse_optional(matches, "amsterdam-time")?; + let heze_time = parse_optional(matches, "heze-time")?; let handle = env.core_context().executor.handle().unwrap(); @@ -51,6 +52,7 @@ pub fn run(mut env: Environment, matches: &ArgMatches) -> Result< prague_time, osaka_time, amsterdam_time, + heze_time, }; let kzg = None; let server: MockServer = MockServer::new_with_config(&handle, config, kzg); diff --git a/testing/ef_tests/src/cases/fork.rs b/testing/ef_tests/src/cases/fork.rs index 54efb9f9cec..ba5dce04c96 100644 --- a/testing/ef_tests/src/cases/fork.rs +++ b/testing/ef_tests/src/cases/fork.rs @@ -4,7 +4,7 @@ use crate::decode::{ssz_decode_state, yaml_decode_file}; use serde::Deserialize; use state_processing::upgrade::{ upgrade_to_altair, upgrade_to_bellatrix, upgrade_to_capella, upgrade_to_deneb, - upgrade_to_electra, upgrade_to_fulu, upgrade_to_gloas, + upgrade_to_electra, upgrade_to_fulu, upgrade_to_gloas, upgrade_to_heze, }; use types::BeaconState; @@ -73,6 +73,7 @@ impl Case for ForkTest { ForkName::Electra => upgrade_to_electra(&mut result_state, spec).map(|_| result_state), ForkName::Fulu => upgrade_to_fulu(&mut result_state, spec).map(|_| result_state), ForkName::Gloas => upgrade_to_gloas(&mut result_state, spec).map(|_| result_state), + ForkName::Heze => upgrade_to_heze(&mut result_state, spec).map(|_| result_state), }; compare_beacon_state_results_without_caches(&mut result, &mut expected) diff --git a/testing/ef_tests/src/cases/merkle_proof_validity.rs b/testing/ef_tests/src/cases/merkle_proof_validity.rs index 4aa9f980d40..587673ddcb9 100644 --- a/testing/ef_tests/src/cases/merkle_proof_validity.rs +++ b/testing/ef_tests/src/cases/merkle_proof_validity.rs @@ -6,7 +6,8 @@ use tree_hash::Hash256; use typenum::Unsigned; use types::{ BeaconBlockBody, BeaconBlockBodyCapella, BeaconBlockBodyDeneb, BeaconBlockBodyElectra, - BeaconBlockBodyFulu, BeaconBlockBodyGloas, BeaconState, FullPayload, light_client, + BeaconBlockBodyFulu, BeaconBlockBodyGloas, BeaconBlockBodyHeze, BeaconState, FullPayload, + light_client, }; #[derive(Debug, Clone, Deserialize)] @@ -177,6 +178,9 @@ impl LoadCase for KzgInclusionMerkleProofValidity { ForkName::Gloas => { ssz_decode_file::>(&path.join("object.ssz_snappy"))?.into() } + ForkName::Heze => { + ssz_decode_file::>(&path.join("object.ssz_snappy"))?.into() + } }; let merkle_proof = yaml_decode_file(&path.join("proof.yaml"))?; // Metadata does not exist in these tests but it is left like this just in case. @@ -298,6 +302,9 @@ impl LoadCase for BeaconBlockBodyMerkleProofValidity { ForkName::Gloas => { ssz_decode_file::>(&path.join("object.ssz_snappy"))?.into() } + ForkName::Heze => { + ssz_decode_file::>(&path.join("object.ssz_snappy"))?.into() + } }; let merkle_proof = yaml_decode_file(&path.join("proof.yaml"))?; // Metadata does not exist in these tests but it is left like this just in case. diff --git a/testing/ef_tests/src/cases/transition.rs b/testing/ef_tests/src/cases/transition.rs index 06aa8136506..2e7c5b6b725 100644 --- a/testing/ef_tests/src/cases/transition.rs +++ b/testing/ef_tests/src/cases/transition.rs @@ -77,6 +77,16 @@ impl LoadCase for TransitionTest { spec.fulu_fork_epoch = Some(Epoch::new(0)); spec.gloas_fork_epoch = Some(metadata.fork_epoch); } + ForkName::Heze => { + spec.altair_fork_epoch = Some(Epoch::new(0)); + spec.bellatrix_fork_epoch = Some(Epoch::new(0)); + spec.capella_fork_epoch = Some(Epoch::new(0)); + spec.deneb_fork_epoch = Some(Epoch::new(0)); + spec.electra_fork_epoch = Some(Epoch::new(0)); + spec.fulu_fork_epoch = Some(Epoch::new(0)); + spec.gloas_fork_epoch = Some(Epoch::new(0)); + spec.heze_fork_epoch = Some(metadata.fork_epoch); + } } // Load blocks diff --git a/testing/ef_tests/src/handler.rs b/testing/ef_tests/src/handler.rs index a438fcc91c1..ad7499b1bd6 100644 --- a/testing/ef_tests/src/handler.rs +++ b/testing/ef_tests/src/handler.rs @@ -35,6 +35,11 @@ pub trait Handler { fn run(&self) { for fork_name in ForkName::list_all() { + // TODO(heze): remove this skip once Heze spec test vectors are published in + // consensus-spec-tests. + if fork_name == ForkName::Heze { + continue; + } if !self.disabled_forks().contains(&fork_name) && self.is_enabled_for_fork(fork_name) { self.run_for_fork(fork_name); } @@ -309,6 +314,10 @@ impl SszStaticHandler { Self::for_forks(vec![ForkName::Gloas]) } + pub fn heze_only() -> Self { + Self::for_forks(vec![ForkName::Heze]) + } + pub fn altair_and_later() -> Self { Self::for_forks(ForkName::list_all()[1..].to_vec()) } @@ -337,6 +346,10 @@ impl SszStaticHandler { Self::for_forks(ForkName::list_all()[7..].to_vec()) } + pub fn heze_and_later() -> Self { + Self::for_forks(ForkName::list_all()[8..].to_vec()) + } + pub fn pre_electra() -> Self { Self::for_forks(ForkName::list_all()[0..5].to_vec()) } @@ -772,7 +785,7 @@ impl Handler for OptimisticSyncHandler { fn disabled_forks(&self) -> Vec { // TODO(gloas): remove once we have Gloas optimistic sync tests - vec![ForkName::Gloas] + vec![ForkName::Gloas, ForkName::Heze] } } @@ -1027,7 +1040,7 @@ impl Handler for KZGComputeCellsHandler { fn disabled_forks(&self) -> Vec { // TODO(gloas): remove once we have Gloas KZG tests - vec![ForkName::Gloas] + vec![ForkName::Gloas, ForkName::Heze] } } @@ -1052,7 +1065,7 @@ impl Handler for KZGComputeCellsAndKZGProofHandler { fn disabled_forks(&self) -> Vec { // TODO(gloas): remove once we have Gloas KZG tests - vec![ForkName::Gloas] + vec![ForkName::Gloas, ForkName::Heze] } } @@ -1077,7 +1090,7 @@ impl Handler for KZGVerifyCellKZGProofBatchHandler { fn disabled_forks(&self) -> Vec { // TODO(gloas): remove once we have Gloas KZG tests - vec![ForkName::Gloas] + vec![ForkName::Gloas, ForkName::Heze] } } @@ -1102,7 +1115,7 @@ impl Handler for KZGRecoverCellsAndKZGProofHandler { fn disabled_forks(&self) -> Vec { // TODO(gloas): remove once we have Gloas KZG tests - vec![ForkName::Gloas] + vec![ForkName::Gloas, ForkName::Heze] } } @@ -1131,7 +1144,7 @@ impl Handler for KzgInclusionMerkleProofValidityHandler Vec { // TODO(gloas): remove once we have Gloas KZG merkle proof tests - vec![ForkName::Gloas] + vec![ForkName::Gloas, ForkName::Heze] } } @@ -1160,7 +1173,7 @@ impl Handler for MerkleProofValidityHandler { fn disabled_forks(&self) -> Vec { // TODO(gloas): remove once we have Gloas light client tests - vec![ForkName::Gloas] + vec![ForkName::Gloas, ForkName::Heze] } } @@ -1190,7 +1203,7 @@ impl Handler for LightClientUpdateHandler { fn disabled_forks(&self) -> Vec { // TODO(gloas): remove once we have Gloas light client tests - vec![ForkName::Gloas] + vec![ForkName::Gloas, ForkName::Heze] } } diff --git a/testing/ef_tests/src/type_name.rs b/testing/ef_tests/src/type_name.rs index 199de1d5ab1..836510c68fa 100644 --- a/testing/ef_tests/src/type_name.rs +++ b/testing/ef_tests/src/type_name.rs @@ -56,6 +56,7 @@ type_name_generic!(BeaconBlockBodyDeneb, "BeaconBlockBody"); type_name_generic!(BeaconBlockBodyElectra, "BeaconBlockBody"); type_name_generic!(BeaconBlockBodyFulu, "BeaconBlockBody"); type_name_generic!(BeaconBlockBodyGloas, "BeaconBlockBody"); +type_name_generic!(BeaconBlockBodyHeze, "BeaconBlockBody"); type_name!(BeaconBlockHeader); type_name_generic!(BeaconState); type_name!(BlobIdentifier); @@ -85,6 +86,7 @@ type_name_generic!(ExecutionPayloadDeneb, "ExecutionPayload"); type_name_generic!(ExecutionPayloadElectra, "ExecutionPayload"); type_name_generic!(ExecutionPayloadFulu, "ExecutionPayload"); type_name_generic!(ExecutionPayloadGloas, "ExecutionPayload"); +type_name_generic!(ExecutionPayloadHeze, "ExecutionPayload"); type_name_generic!(FullPayload, "ExecutionPayload"); type_name_generic!(ExecutionPayloadHeader); type_name_generic!(ExecutionPayloadHeaderBellatrix, "ExecutionPayloadHeader"); diff --git a/testing/ef_tests/tests/tests.rs b/testing/ef_tests/tests/tests.rs index 5222634c906..53404be2cea 100644 --- a/testing/ef_tests/tests/tests.rs +++ b/testing/ef_tests/tests/tests.rs @@ -430,6 +430,8 @@ mod ssz_static { .run(); SszStaticHandler::, MainnetEthSpec>::gloas_only() .run(); + SszStaticHandler::, MinimalEthSpec>::heze_only().run(); + SszStaticHandler::, MainnetEthSpec>::heze_only().run(); } // Altair and later @@ -661,6 +663,8 @@ mod ssz_static { .run(); SszStaticHandler::, MainnetEthSpec>::gloas_only() .run(); + SszStaticHandler::, MinimalEthSpec>::heze_only().run(); + SszStaticHandler::, MainnetEthSpec>::heze_only().run(); } #[test] @@ -751,6 +755,10 @@ mod ssz_static { .run(); SszStaticHandler::, MainnetEthSpec>::gloas_only() .run(); + SszStaticHandler::, MinimalEthSpec>::heze_only() + .run(); + SszStaticHandler::, MainnetEthSpec>::heze_only() + .run(); } #[test] diff --git a/validator_client/beacon_node_fallback/src/lib.rs b/validator_client/beacon_node_fallback/src/lib.rs index b36ec70aa3a..bf67205bd74 100644 --- a/validator_client/beacon_node_fallback/src/lib.rs +++ b/validator_client/beacon_node_fallback/src/lib.rs @@ -400,6 +400,13 @@ impl CandidateBeaconNode { hint = UPDATE_REQUIRED_LOG_HINT, "Beacon node has mismatched Gloas fork epoch" ); + } else if beacon_node_spec.heze_fork_epoch != spec.heze_fork_epoch { + warn!( + endpoint = %self.beacon_node, + endpoint_heze_fork_epoch = ?beacon_node_spec.heze_fork_epoch, + hint = UPDATE_REQUIRED_LOG_HINT, + "Beacon node has mismatched Heze fork epoch" + ); } Ok(()) diff --git a/validator_client/signing_method/src/web3signer.rs b/validator_client/signing_method/src/web3signer.rs index baabb379479..8548a933e66 100644 --- a/validator_client/signing_method/src/web3signer.rs +++ b/validator_client/signing_method/src/web3signer.rs @@ -36,6 +36,7 @@ pub enum ForkName { Electra, Fulu, Gloas, + Heze, } #[derive(Debug, PartialEq, Serialize)] @@ -127,6 +128,11 @@ impl<'a, E: EthSpec, Payload: AbstractExecPayload> Web3SignerObject<'a, E, Pa block: None, block_header: Some(block.block_header()), }), + BeaconBlock::Heze(_) => Ok(Web3SignerObject::BeaconBlock { + version: ForkName::Heze, + block: None, + block_header: Some(block.block_header()), + }), } }