Add new field

This commit is contained in:
Eitan Seri-Levi
2026-04-30 11:20:50 +02:00
parent 87dee4bd23
commit 71fb4c7346
30 changed files with 449 additions and 246 deletions

View File

@@ -15,7 +15,7 @@ use tree_hash_derive::TreeHash;
use typenum::Unsigned;
use crate::{
SignedExecutionPayloadBid,
SignedExecutionPayloadBidGloas, SignedExecutionPayloadBidHeze,
attestation::{AttestationBase, AttestationData, IndexedAttestationBase},
block::{
BeaconBlockBodyAltair, BeaconBlockBodyBase, BeaconBlockBodyBellatrix,
@@ -729,7 +729,7 @@ impl<E: EthSpec, Payload: AbstractExecPayload<E>> EmptyBlock for BeaconBlockGloa
sync_aggregate: SyncAggregate::empty(),
bls_to_execution_changes: VariableList::empty(),
parent_execution_requests: ExecutionRequests::default(),
signed_execution_payload_bid: SignedExecutionPayloadBid::empty(),
signed_execution_payload_bid: SignedExecutionPayloadBidGloas::empty(),
payload_attestations: VariableList::empty(),
_phantom: PhantomData,
},
@@ -761,7 +761,7 @@ impl<E: EthSpec, Payload: AbstractExecPayload<E>> EmptyBlock for BeaconBlockHeze
sync_aggregate: SyncAggregate::empty(),
bls_to_execution_changes: VariableList::empty(),
parent_execution_requests: ExecutionRequests::default(),
signed_execution_payload_bid: SignedExecutionPayloadBid::empty(),
signed_execution_payload_bid: SignedExecutionPayloadBidHeze::empty(),
payload_attestations: VariableList::empty(),
_phantom: PhantomData,
},

View File

@@ -14,7 +14,7 @@ use tree_hash::TreeHash;
use tree_hash_derive::TreeHash;
use crate::{
SignedExecutionPayloadBid,
SignedExecutionPayloadBidGloas, SignedExecutionPayloadBidHeze, SignedExecutionPayloadBidRef,
attestation::{
AttestationBase, AttestationElectra, AttestationRef, AttestationRefMut, PayloadAttestation,
},
@@ -169,8 +169,16 @@ pub struct BeaconBlockBody<E: EthSpec, Payload: AbstractExecPayload<E> = FullPay
pub blob_kzg_commitments: KzgCommitments<E>,
#[superstruct(only(Electra, Fulu))]
pub execution_requests: ExecutionRequests<E>,
#[superstruct(only(Gloas, Heze))]
pub signed_execution_payload_bid: SignedExecutionPayloadBid<E>,
#[superstruct(
only(Gloas),
partial_getter(rename = "signed_execution_payload_bid_gloas")
)]
pub signed_execution_payload_bid: SignedExecutionPayloadBidGloas<E>,
#[superstruct(
only(Heze),
partial_getter(rename = "signed_execution_payload_bid_heze")
)]
pub signed_execution_payload_bid: SignedExecutionPayloadBidHeze<E>,
#[superstruct(only(Gloas, Heze))]
pub payload_attestations: VariableList<PayloadAttestation<E>, E::MaxPayloadAttestations>,
#[superstruct(only(Gloas, Heze))]
@@ -196,6 +204,20 @@ impl<E: EthSpec, Payload: AbstractExecPayload<E>> BeaconBlockBody<E, Payload> {
}
impl<'a, E: EthSpec, Payload: AbstractExecPayload<E>> BeaconBlockBodyRef<'a, E, Payload> {
pub fn signed_execution_payload_bid(
&self,
) -> Result<SignedExecutionPayloadBidRef<'a, E>, BeaconStateError> {
match self {
Self::Gloas(body) => Ok(SignedExecutionPayloadBidRef::Gloas(
&body.signed_execution_payload_bid,
)),
Self::Heze(body) => Ok(SignedExecutionPayloadBidRef::Heze(
&body.signed_execution_payload_bid,
)),
_ => Err(BeaconStateError::IncorrectStateVariant),
}
}
pub fn execution_payload(&self) -> Result<Payload::Ref<'a>, BeaconStateError> {
match self {
Self::Base(_) | Self::Altair(_) => Err(BeaconStateError::IncorrectStateVariant),

View File

@@ -383,7 +383,7 @@ impl<E: EthSpec, Payload: AbstractExecPayload<E>> SignedBeaconBlock<E, Payload>
self.message()
.body()
.signed_execution_payload_bid()
.map(|bid| bid.message.block_hash)
.map(|bid| bid.message().block_hash())
}
/// Convenience accessor for the block's bid's `parent_block_hash`.
@@ -393,7 +393,7 @@ impl<E: EthSpec, Payload: AbstractExecPayload<E>> SignedBeaconBlock<E, Payload>
self.message()
.body()
.signed_execution_payload_bid()
.map(|bid| bid.message.parent_block_hash)
.map(|bid| bid.message().parent_block_hash())
}
/// Check if the `parent_hash` in this block's `signed_payload_bid` matches `parent_block_hash`.
@@ -409,7 +409,7 @@ impl<E: EthSpec, Payload: AbstractExecPayload<E>> SignedBeaconBlock<E, Payload>
// Prior to Gloas.
return false;
};
signed_payload_bid.message.parent_block_hash == parent_block_hash
signed_payload_bid.message().parent_block_hash() == parent_block_hash
}
}

View File

@@ -1,51 +1,106 @@
use crate::kzg_ext::KzgCommitments;
use crate::state::BeaconStateError;
use crate::test_utils::TestRandom;
use crate::{Address, EthSpec, ExecutionBlockHash, ForkName, Hash256, SignedRoot, Slot};
use context_deserialize::context_deserialize;
use educe::Educe;
use serde::{Deserialize, Serialize};
use ssz_derive::{Decode, Encode};
use ssz_types::BitVector;
use superstruct::superstruct;
use test_random_derive::TestRandom;
use tree_hash_derive::TreeHash;
#[derive(
Default, Debug, Clone, Serialize, Encode, Decode, Deserialize, TreeHash, Educe, TestRandom,
#[superstruct(
variants(Gloas, Heze),
variant_attributes(
derive(
Default,
Debug,
Clone,
Serialize,
Deserialize,
Encode,
Decode,
TreeHash,
TestRandom,
Educe,
),
educe(PartialEq, Hash(bound(E: EthSpec))),
serde(bound = "E: EthSpec", deny_unknown_fields),
cfg_attr(
feature = "arbitrary",
derive(arbitrary::Arbitrary),
arbitrary(bound = "E: EthSpec"),
),
context_deserialize(ForkName),
),
ref_attributes(
derive(PartialEq, TreeHash, Debug),
tree_hash(enum_behaviour = "transparent")
),
cast_error(
ty = "BeaconStateError",
expr = "BeaconStateError::IncorrectStateVariant"
),
partial_getter_error(
ty = "BeaconStateError",
expr = "BeaconStateError::IncorrectStateVariant"
),
)]
#[cfg_attr(
feature = "arbitrary",
derive(arbitrary::Arbitrary),
arbitrary(bound = "E: EthSpec")
)]
#[educe(PartialEq, Hash)]
#[serde(bound = "E: EthSpec")]
#[context_deserialize(ForkName)]
// https://github.com/ethereum/consensus-specs/blob/master/specs/gloas/beacon-chain.md#executionpayloadbid
#[derive(Debug, Clone, Serialize, Deserialize, Encode, TreeHash, Educe)]
#[educe(PartialEq, Hash(bound(E: EthSpec)))]
#[serde(bound = "E: EthSpec", untagged)]
#[tree_hash(enum_behaviour = "transparent")]
#[ssz(enum_behaviour = "transparent")]
pub struct ExecutionPayloadBid<E: EthSpec> {
#[superstruct(getter(copy))]
pub parent_block_hash: ExecutionBlockHash,
#[superstruct(getter(copy))]
pub parent_block_root: Hash256,
#[superstruct(getter(copy))]
pub block_hash: ExecutionBlockHash,
#[superstruct(getter(copy))]
pub prev_randao: Hash256,
#[superstruct(getter(copy))]
#[serde(with = "serde_utils::address_hex")]
pub fee_recipient: Address,
#[serde(with = "serde_utils::quoted_u64")]
#[superstruct(getter(copy))]
pub gas_limit: u64,
#[serde(with = "serde_utils::quoted_u64")]
#[superstruct(getter(copy))]
pub builder_index: u64,
#[superstruct(getter(copy))]
pub slot: Slot,
#[serde(with = "serde_utils::quoted_u64")]
#[superstruct(getter(copy))]
pub value: u64,
#[serde(with = "serde_utils::quoted_u64")]
#[superstruct(getter(copy))]
pub execution_payment: u64,
pub blob_kzg_commitments: KzgCommitments<E>,
#[superstruct(getter(copy))]
pub execution_requests_root: Hash256,
#[superstruct(only(Heze))]
pub inclusion_list_bits: BitVector<E::InclusionListCommitteeSize>,
}
impl<E: EthSpec> SignedRoot for ExecutionPayloadBid<E> {}
impl<E: EthSpec> SignedRoot for ExecutionPayloadBidGloas<E> {}
impl<E: EthSpec> SignedRoot for ExecutionPayloadBidHeze<E> {}
impl<'a, E: EthSpec> SignedRoot for ExecutionPayloadBidRef<'a, E> {}
#[cfg(test)]
mod tests {
use super::*;
use crate::MainnetEthSpec;
ssz_and_tree_hash_tests!(ExecutionPayloadBid<MainnetEthSpec>);
ssz_and_tree_hash_tests!(ExecutionPayloadBidGloas<MainnetEthSpec>);
ssz_and_tree_hash_tests!(ExecutionPayloadBidHeze<MainnetEthSpec>);
}

View File

@@ -22,7 +22,10 @@ pub use execution_payload::{
ExecutionPayloadElectra, ExecutionPayloadFulu, ExecutionPayloadGloas, ExecutionPayloadHeze,
ExecutionPayloadRef, Transaction, Transactions,
};
pub use execution_payload_bid::ExecutionPayloadBid;
pub use execution_payload_bid::{
ExecutionPayloadBid, ExecutionPayloadBidGloas, ExecutionPayloadBidHeze,
ExecutionPayloadBidRef,
};
pub use execution_payload_envelope::ExecutionPayloadEnvelope;
pub use execution_payload_header::{
ExecutionPayloadHeader, ExecutionPayloadHeaderBellatrix, ExecutionPayloadHeaderCapella,
@@ -43,5 +46,7 @@ pub use payload::{
FullPayloadElectra, FullPayloadFulu, FullPayloadRef, OwnedExecPayload,
};
pub use signed_bls_to_execution_change::SignedBlsToExecutionChange;
pub use signed_execution_payload_bid::SignedExecutionPayloadBid;
pub use signed_execution_payload_bid::{
SignedExecutionPayloadBidGloas, SignedExecutionPayloadBidHeze, SignedExecutionPayloadBidRef,
};
pub use signed_execution_payload_envelope::SignedExecutionPayloadEnvelope;

View File

@@ -1,4 +1,4 @@
use crate::execution::ExecutionPayloadBid;
use crate::execution::{ExecutionPayloadBidGloas, ExecutionPayloadBidHeze, ExecutionPayloadBidRef};
use crate::test_utils::TestRandom;
use crate::{EthSpec, ForkName};
use bls::Signature;
@@ -18,25 +18,69 @@ use tree_hash_derive::TreeHash;
#[educe(PartialEq, Hash)]
#[serde(bound = "E: EthSpec")]
#[context_deserialize(ForkName)]
// https://github.com/ethereum/consensus-specs/blob/master/specs/gloas/beacon-chain.md#signedexecutionpayloadbid
pub struct SignedExecutionPayloadBid<E: EthSpec> {
pub message: ExecutionPayloadBid<E>,
pub struct SignedExecutionPayloadBidGloas<E: EthSpec> {
pub message: ExecutionPayloadBidGloas<E>,
pub signature: Signature,
}
impl<E: EthSpec> SignedExecutionPayloadBid<E> {
impl<E: EthSpec> SignedExecutionPayloadBidGloas<E> {
pub fn empty() -> Self {
Self {
message: ExecutionPayloadBid::default(),
message: ExecutionPayloadBidGloas::default(),
signature: Signature::empty(),
}
}
}
#[derive(TestRandom, TreeHash, Debug, Clone, Encode, Decode, Serialize, Deserialize, Educe)]
#[cfg_attr(
feature = "arbitrary",
derive(arbitrary::Arbitrary),
arbitrary(bound = "E: EthSpec")
)]
#[educe(PartialEq, Hash)]
#[serde(bound = "E: EthSpec")]
#[context_deserialize(ForkName)]
pub struct SignedExecutionPayloadBidHeze<E: EthSpec> {
pub message: ExecutionPayloadBidHeze<E>,
pub signature: Signature,
}
impl<E: EthSpec> SignedExecutionPayloadBidHeze<E> {
pub fn empty() -> Self {
Self {
message: ExecutionPayloadBidHeze::default(),
signature: Signature::empty(),
}
}
}
pub enum SignedExecutionPayloadBidRef<'a, E: EthSpec> {
Gloas(&'a SignedExecutionPayloadBidGloas<E>),
Heze(&'a SignedExecutionPayloadBidHeze<E>),
}
impl<'a, E: EthSpec> SignedExecutionPayloadBidRef<'a, E> {
pub fn message(&self) -> ExecutionPayloadBidRef<'a, E> {
match self {
Self::Gloas(inner) => ExecutionPayloadBidRef::Gloas(&inner.message),
Self::Heze(inner) => ExecutionPayloadBidRef::Heze(&inner.message),
}
}
pub fn signature(&self) -> &'a Signature {
match self {
Self::Gloas(inner) => &inner.signature,
Self::Heze(inner) => &inner.signature,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::MainnetEthSpec;
ssz_and_tree_hash_tests!(SignedExecutionPayloadBid<MainnetEthSpec>);
ssz_and_tree_hash_tests!(SignedExecutionPayloadBidGloas<MainnetEthSpec>);
ssz_and_tree_hash_tests!(SignedExecutionPayloadBidHeze<MainnetEthSpec>);
}

View File

@@ -24,7 +24,8 @@ use tree_hash_derive::TreeHash;
use typenum::Unsigned;
use crate::{
Address, ExecutionBlockHash, ExecutionPayloadBid, ProposerPreferences, Withdrawal,
Address, ExecutionBlockHash, ExecutionPayloadBidGloas, ExecutionPayloadBidHeze,
ExecutionPayloadBidRef, ProposerPreferences, Withdrawal,
attestation::{
AttestationData, AttestationDuty, BeaconCommittee, Checkpoint, CommitteeIndex, PTC,
ParticipationFlags, PendingAttestation,
@@ -673,9 +674,18 @@ where
pub builder_pending_withdrawals:
List<BuilderPendingWithdrawal, E::BuilderPendingWithdrawalsLimit>,
#[superstruct(only(Gloas, Heze))]
#[superstruct(
only(Gloas),
partial_getter(rename = "latest_execution_payload_bid_gloas")
)]
#[metastruct(exclude_from(tree_lists))]
pub latest_execution_payload_bid: ExecutionPayloadBid<E>,
pub latest_execution_payload_bid: ExecutionPayloadBidGloas<E>,
#[superstruct(
only(Heze),
partial_getter(rename = "latest_execution_payload_bid_heze")
)]
#[metastruct(exclude_from(tree_lists))]
pub latest_execution_payload_bid: ExecutionPayloadBidHeze<E>,
#[compare_fields(as_iter)]
#[test_random(default)]
@@ -1341,6 +1351,20 @@ impl<E: EthSpec> BeaconState<E> {
}
}
pub fn latest_execution_payload_bid(
&self,
) -> Result<ExecutionPayloadBidRef<'_, E>, BeaconStateError> {
match self {
BeaconState::Gloas(state) => Ok(ExecutionPayloadBidRef::Gloas(
&state.latest_execution_payload_bid,
)),
BeaconState::Heze(state) => Ok(ExecutionPayloadBidRef::Heze(
&state.latest_execution_payload_bid,
)),
_ => Err(BeaconStateError::IncorrectStateVariant),
}
}
/// Return `true` if the validator who produced `slot_signature` is eligible to aggregate.
///
/// Spec v0.12.1
@@ -2613,11 +2637,13 @@ impl<E: EthSpec> BeaconState<E> {
| BeaconState::Capella(_)
| BeaconState::Deneb(_)
| BeaconState::Electra(_)
| BeaconState::Fulu(_)
| BeaconState::Heze(_) => true,
| BeaconState::Fulu(_) => true,
BeaconState::Gloas(state) => {
state.latest_execution_payload_bid.block_hash == state.latest_block_hash
}
BeaconState::Heze(state) => {
state.latest_execution_payload_bid.block_hash == state.latest_block_hash
}
}
}