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

@@ -150,16 +150,16 @@ pub fn verify_execution_payload_envelope<E: EthSpec>(
// Verify consistency with the committed bid
let committed_bid = state.latest_execution_payload_bid()?;
envelope_verify!(
envelope.builder_index == committed_bid.builder_index,
envelope.builder_index == committed_bid.builder_index(),
EnvelopeProcessingError::BuilderIndexMismatch {
committed_bid: committed_bid.builder_index,
committed_bid: committed_bid.builder_index(),
envelope: envelope.builder_index,
}
);
envelope_verify!(
committed_bid.prev_randao == payload.prev_randao,
committed_bid.prev_randao() == payload.prev_randao,
EnvelopeProcessingError::PrevRandaoMismatch {
committed_bid: committed_bid.prev_randao,
committed_bid: committed_bid.prev_randao(),
envelope: payload.prev_randao,
}
);
@@ -183,18 +183,18 @@ pub fn verify_execution_payload_envelope<E: EthSpec>(
// Verify the gas limit
envelope_verify!(
committed_bid.gas_limit == payload.gas_limit,
committed_bid.gas_limit() == payload.gas_limit,
EnvelopeProcessingError::GasLimitMismatch {
committed_bid: committed_bid.gas_limit,
committed_bid: committed_bid.gas_limit(),
envelope: payload.gas_limit,
}
);
// Verify the block hash
envelope_verify!(
committed_bid.block_hash == payload.block_hash,
committed_bid.block_hash() == payload.block_hash,
EnvelopeProcessingError::BlockHashMismatch {
committed_bid: committed_bid.block_hash,
committed_bid: committed_bid.block_hash(),
envelope: payload.block_hash,
}
);
@@ -221,9 +221,9 @@ pub fn verify_execution_payload_envelope<E: EthSpec>(
// Verify execution requests root matches committed bid
let execution_requests_root = envelope.execution_requests.tree_hash_root();
envelope_verify!(
execution_requests_root == committed_bid.execution_requests_root,
execution_requests_root == committed_bid.execution_requests_root(),
EnvelopeProcessingError::ExecutionRequestsRootMismatch {
committed_bid: committed_bid.execution_requests_root,
committed_bid: committed_bid.execution_requests_root(),
envelope: execution_requests_root,
}
);

View File

@@ -170,10 +170,12 @@ pub fn initialize_beacon_state_from_eth1<E: EthSpec>(
// The genesis block's bid must have block_hash = 0x00 per spec (empty payload).
// Retain the EL genesis hash in latest_block_hash and parent_block_hash so the
// first post-genesis proposer can build on the correct EL head.
let el_genesis_hash = state.latest_execution_payload_bid()?.block_hash;
let bid = state.latest_execution_payload_bid_mut()?;
bid.parent_block_hash = el_genesis_hash;
bid.block_hash = ExecutionBlockHash::default();
let el_genesis_hash = state.latest_execution_payload_bid()?.block_hash();
{
let bid = state.latest_execution_payload_bid_gloas_mut()?;
bid.parent_block_hash = el_genesis_hash;
bid.block_hash = ExecutionBlockHash::default();
}
// Update the `latest_block_header.body_root` so that it matches the body of the
// Gloas genesis block, which embeds `state.latest_execution_payload_bid` in its
@@ -219,13 +221,13 @@ pub fn genesis_block<E: EthSpec>(
if let Ok(block) = block.as_gloas_mut() {
let state_bid = state.latest_execution_payload_bid()?;
let bid = &mut block.body.signed_execution_payload_bid.message;
bid.block_hash = state_bid.block_hash;
bid.execution_requests_root = state_bid.execution_requests_root;
bid.block_hash = state_bid.block_hash();
bid.execution_requests_root = state_bid.execution_requests_root();
} else if let Ok(block) = block.as_heze_mut() {
let state_bid = state.latest_execution_payload_bid()?;
let bid = &mut block.body.signed_execution_payload_bid.message;
bid.block_hash = state_bid.block_hash;
bid.execution_requests_root = state_bid.execution_requests_root;
bid.block_hash = state_bid.block_hash();
bid.execution_requests_root = state_bid.execution_requests_root();
}
Ok(block)
}

View File

@@ -559,12 +559,12 @@ pub fn process_parent_execution_payload<E: EthSpec, Payload: AbstractExecPayload
let bid_parent_block_hash = block
.body()
.signed_execution_payload_bid()?
.message
.parent_block_hash;
.message()
.parent_block_hash();
let parent_bid = state.latest_execution_payload_bid()?;
let requests = block.body().parent_execution_requests()?;
if bid_parent_block_hash != parent_bid.block_hash {
if bid_parent_block_hash != parent_bid.block_hash() {
// Parent was EMPTY -- no execution requests expected
block_verify!(
*requests == ExecutionRequests::default(),
@@ -576,9 +576,9 @@ pub fn process_parent_execution_payload<E: EthSpec, Payload: AbstractExecPayload
// Parent was FULL -- verify the bid commitment and apply the payload
let requests_root = requests.tree_hash_root();
block_verify!(
requests_root == parent_bid.execution_requests_root,
requests_root == parent_bid.execution_requests_root(),
BlockProcessingError::ExecutionRequestsRootMismatch {
expected: parent_bid.execution_requests_root,
expected: parent_bid.execution_requests_root(),
found: requests_root,
}
);
@@ -597,8 +597,12 @@ pub fn apply_parent_execution_payload<E: EthSpec>(
requests: &ExecutionRequests<E>,
spec: &ChainSpec,
) -> Result<(), BlockProcessingError> {
let parent_bid = state.latest_execution_payload_bid()?.clone();
let parent_slot = parent_bid.slot;
let parent_bid = state.latest_execution_payload_bid()?;
let parent_slot = parent_bid.slot();
let parent_value = parent_bid.value();
let parent_fee_recipient = parent_bid.fee_recipient();
let parent_builder_index = parent_bid.builder_index();
let parent_block_hash = parent_bid.block_hash();
let parent_epoch = parent_slot.epoch(E::slots_per_epoch());
// Process execution requests from the parent's payload
@@ -615,16 +619,16 @@ pub fn apply_parent_execution_payload<E: EthSpec>(
} else if parent_epoch == state.previous_epoch() {
let payment_index = parent_slot.as_u64().safe_rem(E::slots_per_epoch())? as usize;
settle_builder_payment(state, payment_index)?;
} else if parent_bid.value > 0 {
} else if parent_value > 0 {
// Parent is older than previous epoch -- payment entry has already been
// settled or evicted by process_builder_pending_payments at epoch boundaries.
// Append the withdrawal directly from the bid.
state
.builder_pending_withdrawals_mut()?
.push(BuilderPendingWithdrawal {
fee_recipient: parent_bid.fee_recipient,
amount: parent_bid.value,
builder_index: parent_bid.builder_index,
fee_recipient: parent_fee_recipient,
amount: parent_value,
builder_index: parent_builder_index,
})
.map_err(|e| BlockProcessingError::BeaconStateError(e.into()))?;
}
@@ -639,7 +643,7 @@ pub fn apply_parent_execution_payload<E: EthSpec>(
.map_err(BlockProcessingError::BitfieldError)?;
// Update latest_block_hash to the parent bid's block_hash
*state.latest_block_hash_mut()? = parent_bid.block_hash;
*state.latest_block_hash_mut()? = parent_block_hash;
Ok(())
}
@@ -681,9 +685,9 @@ pub fn process_execution_payload_bid<E: EthSpec, Payload: AbstractExecPayload<E>
// Verify the bid signature
let signed_bid = block.body().signed_execution_payload_bid()?;
let bid = &signed_bid.message;
let amount = bid.value;
let builder_index = bid.builder_index;
let bid = signed_bid.message();
let amount = bid.value();
let builder_index = bid.builder_index();
// For self-builds, amount must be zero regardless of withdrawal credential prefix
if builder_index == BUILDER_INDEX_SELF_BUILD {
@@ -692,7 +696,7 @@ pub fn process_execution_payload_bid<E: EthSpec, Payload: AbstractExecPayload<E>
ExecutionPayloadBidInvalid::SelfBuildNonZeroAmount.into()
);
block_verify!(
signed_bid.signature.is_infinity(),
signed_bid.signature().is_infinity(),
ExecutionPayloadBidInvalid::BadSignature.into()
);
} else {
@@ -735,19 +739,19 @@ pub fn process_execution_payload_bid<E: EthSpec, Payload: AbstractExecPayload<E>
// Verify commitments are under limit
let max_blobs_per_block = spec.max_blobs_per_block(state.current_epoch()) as usize;
block_verify!(
bid.blob_kzg_commitments.len() <= max_blobs_per_block,
bid.blob_kzg_commitments().len() <= max_blobs_per_block,
ExecutionPayloadBidInvalid::ExcessBlobCommitments {
max: max_blobs_per_block,
bid: bid.blob_kzg_commitments.len(),
bid: bid.blob_kzg_commitments().len(),
}
.into()
);
// Verify that the bid is for the current slot
block_verify!(
bid.slot == block.slot(),
bid.slot() == block.slot(),
ExecutionPayloadBidInvalid::SlotMismatch {
bid_slot: bid.slot,
bid_slot: bid.slot(),
block_slot: block.slot(),
}
.into()
@@ -756,29 +760,29 @@ pub fn process_execution_payload_bid<E: EthSpec, Payload: AbstractExecPayload<E>
// Verify that the bid is for the right parent block
let latest_block_hash = state.latest_block_hash()?;
block_verify!(
bid.parent_block_hash == *latest_block_hash,
bid.parent_block_hash() == *latest_block_hash,
ExecutionPayloadBidInvalid::ParentBlockHashMismatch {
state_block_hash: *latest_block_hash,
bid_parent_hash: bid.parent_block_hash,
bid_parent_hash: bid.parent_block_hash(),
}
.into()
);
block_verify!(
bid.parent_block_root == block.parent_root(),
bid.parent_block_root() == block.parent_root(),
ExecutionPayloadBidInvalid::ParentBlockRootMismatch {
block_parent_root: block.parent_root(),
bid_parent_root: bid.parent_block_root,
bid_parent_root: bid.parent_block_root(),
}
.into()
);
let expected_randao = *state.get_randao_mix(state.current_epoch())?;
block_verify!(
bid.prev_randao == expected_randao,
bid.prev_randao() == expected_randao,
ExecutionPayloadBidInvalid::PrevRandaoMismatch {
expected: expected_randao,
bid: bid.prev_randao,
bid: bid.prev_randao(),
}
.into()
);
@@ -788,14 +792,14 @@ pub fn process_execution_payload_bid<E: EthSpec, Payload: AbstractExecPayload<E>
let pending_payment = BuilderPendingPayment {
weight: 0,
withdrawal: BuilderPendingWithdrawal {
fee_recipient: bid.fee_recipient,
fee_recipient: bid.fee_recipient(),
amount,
builder_index,
},
};
let payment_index = E::SlotsPerEpoch::to_usize()
.safe_add(bid.slot.as_usize().safe_rem(E::SlotsPerEpoch::to_usize())?)?;
.safe_add(bid.slot().as_usize().safe_rem(E::SlotsPerEpoch::to_usize())?)?;
*state
.builder_pending_payments_mut()?
@@ -806,7 +810,14 @@ pub fn process_execution_payload_bid<E: EthSpec, Payload: AbstractExecPayload<E>
}
// Cache the execution bid
*state.latest_execution_payload_bid_mut()? = bid.clone();
match block.body().signed_execution_payload_bid()? {
SignedExecutionPayloadBidRef::Gloas(signed) => {
*state.latest_execution_payload_bid_gloas_mut()? = signed.message.clone();
}
SignedExecutionPayloadBidRef::Heze(signed) => {
*state.latest_execution_payload_bid_heze_mut()? = signed.message.clone();
}
}
Ok(())
}

View File

@@ -13,7 +13,7 @@ use types::{
BuilderIndex, ChainSpec, DepositData, Domain, Epoch, EthSpec, Fork, Hash256, InconsistentFork,
IndexedAttestation, IndexedAttestationRef, IndexedPayloadAttestation, ProposerSlashing,
SignedAggregateAndProof, SignedBeaconBlock, SignedBeaconBlockHeader,
SignedBlsToExecutionChange, SignedContributionAndProof, SignedExecutionPayloadBid,
SignedBlsToExecutionChange, SignedContributionAndProof, SignedExecutionPayloadBidRef,
SignedProposerPreferences, SignedRoot, SignedVoluntaryExit, SigningData, Slot, SyncAggregate,
SyncAggregatorSelectionData, consts::gloas::BUILDER_INDEX_SELF_BUILD,
};
@@ -424,15 +424,15 @@ where
pub fn execution_payload_bid_signature_set<'a, E, F>(
state: &'a BeaconState<E>,
get_builder_pubkey: F,
signed_execution_payload_bid: &'a SignedExecutionPayloadBid<E>,
signed_execution_payload_bid: SignedExecutionPayloadBidRef<'a, E>,
spec: &'a ChainSpec,
) -> Result<Option<SignatureSet<'a>>>
where
E: EthSpec,
F: Fn(BuilderIndex) -> Option<Cow<'a, PublicKey>>,
{
let execution_payload_bid = &signed_execution_payload_bid.message;
let builder_index = execution_payload_bid.builder_index;
let bid = signed_execution_payload_bid.message();
let builder_index = bid.builder_index();
if builder_index == BUILDER_INDEX_SELF_BUILD {
// No signatures to verify in case of a self-build, but consensus code MUST check that
// the signature is the point at infinity.
@@ -440,10 +440,7 @@ where
return Ok(None);
}
let bid_epoch = signed_execution_payload_bid
.message
.slot
.epoch(E::slots_per_epoch());
let bid_epoch = bid.slot().epoch(E::slots_per_epoch());
let bid_fork = spec.fork_at_epoch(bid_epoch);
let domain = spec.get_domain(
bid_epoch,
@@ -453,10 +450,10 @@ where
);
let pubkey = get_builder_pubkey(builder_index).ok_or(Error::BuilderUnknown(builder_index))?;
let message = execution_payload_bid.signing_root(domain);
let message = bid.signing_root(domain);
Ok(Some(SignatureSet::single_pubkey(
&signed_execution_payload_bid.signature,
signed_execution_payload_bid.signature(),
pubkey,
message,
)))

View File

@@ -495,7 +495,7 @@ pub mod gloas {
spec: &ChainSpec,
) -> Result<(), BlockProcessingError> {
// Return early if the parent block is empty.
if *state.latest_block_hash()? != state.latest_execution_payload_bid()?.block_hash {
if *state.latest_block_hash()? != state.latest_execution_payload_bid()?.block_hash() {
return Ok(());
}

View File

@@ -11,7 +11,7 @@ use tree_hash::TreeHash;
use typenum::Unsigned;
use types::{
BeaconState, BeaconStateError as Error, BeaconStateGloas, BuilderPendingPayment, ChainSpec,
DepositData, EthSpec, ExecutionPayloadBid, ExecutionRequests, Fork,
DepositData, EthSpec, ExecutionPayloadBidGloas, ExecutionRequests, Fork,
is_builder_withdrawal_credential,
};
@@ -78,7 +78,7 @@ pub fn upgrade_state_to_gloas<E: EthSpec>(
current_sync_committee: pre.current_sync_committee.clone(),
next_sync_committee: pre.next_sync_committee.clone(),
// Execution Bid
latest_execution_payload_bid: ExecutionPayloadBid {
latest_execution_payload_bid: ExecutionPayloadBidGloas {
block_hash: pre.latest_execution_payload_header.block_hash,
execution_requests_root: ExecutionRequests::<E>::default().tree_hash_root(),
..Default::default()

View File

@@ -1,5 +1,9 @@
use ssz_types::BitVector;
use std::mem;
use types::{BeaconState, BeaconStateError as Error, BeaconStateHeze, ChainSpec, EthSpec, Fork};
use types::{
BeaconState, BeaconStateError as Error, BeaconStateHeze, ChainSpec, EthSpec,
ExecutionPayloadBidHeze, Fork,
};
/// Transform a `Gloas` state into a `Heze` state.
pub fn upgrade_to_heze<E: EthSpec>(
@@ -64,7 +68,21 @@ pub fn upgrade_state_to_heze<E: EthSpec>(
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(),
latest_execution_payload_bid: ExecutionPayloadBidHeze {
parent_block_hash: pre.latest_execution_payload_bid.parent_block_hash,
parent_block_root: pre.latest_execution_payload_bid.parent_block_root,
block_hash: pre.latest_execution_payload_bid.block_hash,
prev_randao: pre.latest_execution_payload_bid.prev_randao,
fee_recipient: pre.latest_execution_payload_bid.fee_recipient,
gas_limit: pre.latest_execution_payload_bid.gas_limit,
builder_index: pre.latest_execution_payload_bid.builder_index,
slot: pre.latest_execution_payload_bid.slot,
value: pre.latest_execution_payload_bid.value,
execution_payment: pre.latest_execution_payload_bid.execution_payment,
blob_kzg_commitments: pre.latest_execution_payload_bid.blob_kzg_commitments.clone(),
execution_requests_root: pre.latest_execution_payload_bid.execution_requests_root,
inclusion_list_bits: BitVector::new(),
},
// Capella
next_withdrawal_index: pre.next_withdrawal_index,
next_withdrawal_validator_index: pre.next_withdrawal_validator_index,