Payload builder version

This commit is contained in:
Eitan Seri-Levi
2026-06-21 17:57:16 +03:00
parent e35a96cc1c
commit affdfb0d13
10 changed files with 49 additions and 9 deletions

View File

@@ -14,7 +14,7 @@ use state_processing::signature_sets::{
use tracing::debug;
use types::{
BeaconState, ChainSpec, EthSpec, ExecutionPayloadBid, SignedExecutionPayloadBid,
SignedProposerPreferences, Slot,
SignedProposerPreferences, Slot, consts::gloas::PAYLOAD_BUILDER_VERSION,
};
/// Verify that an execution payload bid is consistent with the current chain state
@@ -64,6 +64,14 @@ pub(crate) fn verify_bid_consistency<E: EthSpec>(
return Err(PayloadBidError::InvalidBuilder { builder_index });
}
let builder_version = head_state.get_builder(builder_index)?.version;
if builder_version != PAYLOAD_BUILDER_VERSION {
return Err(PayloadBidError::InvalidBuilderVersion {
builder_index,
version: builder_version,
});
}
if !head_state.can_builder_cover_bid(builder_index, bid.value, spec)? {
return Err(PayloadBidError::BuilderCantCoverBid {
builder_index,

View File

@@ -30,6 +30,8 @@ pub enum PayloadBidError {
BuilderAlreadySeen { builder_index: u64, slot: Slot },
/// Builder is not valid/active for the given epoch
InvalidBuilder { builder_index: u64 },
/// The builder's version is not `PAYLOAD_BUILDER_VERSION`.
InvalidBuilderVersion { builder_index: u64, version: u8 },
/// The bid value is lower than the currently cached bid.
BidValueBelowCached {
cached_value: u64,

View File

@@ -16,6 +16,7 @@ use types::{
Address, ChainSpec, Checkpoint, Domain, Epoch, EthSpec, ExecutionBlockHash,
ExecutionPayloadBid, Hash256, MinimalEthSpec, ProposerPreferences, SignedBeaconBlock,
SignedExecutionPayloadBid, SignedProposerPreferences, SignedRoot, Slot,
consts::gloas::PAYLOAD_BUILDER_VERSION,
};
use proto_array::{Block as ProtoBlock, ExecutionStatus, PayloadStatus};
@@ -86,6 +87,7 @@ impl TestContext {
state
.add_builder_to_registry(
PublicKeyBytes::from(keypair.pk.clone()),
PAYLOAD_BUILDER_VERSION,
creds,
BUILDER_BALANCE,
Slot::new(0),
@@ -117,6 +119,7 @@ impl TestContext {
let inactive_builder_index = state
.add_builder_to_registry(
PublicKeyBytes::from(inactive_keypair.pk.clone()),
PAYLOAD_BUILDER_VERSION,
inactive_creds,
BUILDER_BALANCE,
Slot::new(E::slots_per_epoch()),

View File

@@ -4021,10 +4021,11 @@ impl<T: BeaconChainTypes> NetworkBeaconProcessor<T> {
Err(
PayloadBidError::BadSignature
| PayloadBidError::InvalidBuilder { .. }
| PayloadBidError::InvalidBuilderVersion { .. }
| PayloadBidError::InvalidFeeRecipient
| PayloadBidError::ExecutionPaymentNonZero { .. }
| PayloadBidError::InvalidBlobKzgCommitments { .. }
| PayloadBidError::BidNotDescendantOfParent { .. },
| PayloadBidError::BidNotDescendantOfParent { .. }
| PayloadBidError::InvalidPrevRandao { .. },
) => {
self.propagate_validation_result(message_id, peer_id, MessageAcceptance::Reject);

View File

@@ -11,7 +11,10 @@ use signature_sets::{
use std::borrow::Cow;
use tree_hash::TreeHash;
use typenum::Unsigned;
use types::{consts::gloas::BUILDER_INDEX_SELF_BUILD, *};
use types::{
consts::gloas::{BUILDER_INDEX_SELF_BUILD, PAYLOAD_BUILDER_VERSION},
*,
};
pub use self::verify_attester_slashing::{
get_slashable_indices, get_slashable_indices_modular, verify_attester_slashing,
@@ -698,6 +701,16 @@ pub fn process_execution_payload_bid<E: EthSpec, Payload: AbstractExecPayload<E>
ExecutionPayloadBidInvalid::BuilderNotActive(builder_index).into()
);
// Verify that the builder is a payload builder
block_verify!(
builder.version == PAYLOAD_BUILDER_VERSION,
ExecutionPayloadBidInvalid::InvalidBuilderVersion {
builder_index,
version: builder.version,
}
.into()
);
// Verify that the builder has funds to cover the bid
block_verify!(
state.can_builder_cover_bid(builder_index, amount, spec)?,

View File

@@ -527,6 +527,8 @@ pub enum ExecutionPayloadBidInvalid {
BadSignature,
/// The builder is not active.
BuilderNotActive(u64),
/// The builder's version is not `PAYLOAD_BUILDER_VERSION`.
InvalidBuilderVersion { builder_index: u64, version: u8 },
/// The builder has insufficient balance to cover the bid
InsufficientBalance {
builder_index: u64,

View File

@@ -970,11 +970,18 @@ pub fn process_deposit_request_post_gloas<E: EthSpec>(
&& !is_validator
&& !is_pending_validator(state.pending_deposits()?, &deposit_request.pubkey, spec))
{
// Apply builder deposits immediately
// Apply builder deposits immediately. The builder version is taken from the
// withdrawal credentials prefix byte (spec: `process_builder_deposit_request`).
let version = *deposit_request
.withdrawal_credentials
.as_slice()
.first()
.ok_or(BeaconStateError::WithdrawalCredentialMissingVersion)?;
apply_deposit_for_builder(
state,
builder_index,
deposit_request.pubkey,
version,
deposit_request.withdrawal_credentials,
deposit_request.amount,
deposit_request.signature.clone(),
@@ -1002,6 +1009,7 @@ pub fn apply_deposit_for_builder<E: EthSpec>(
state: &mut BeaconState<E>,
builder_index_opt: Option<BuilderIndex>,
pubkey: PublicKeyBytes,
version: u8,
withdrawal_credentials: Hash256,
amount: u64,
signature: SignatureBytes,
@@ -1020,6 +1028,7 @@ pub fn apply_deposit_for_builder<E: EthSpec>(
if is_valid_deposit_signature(&deposit_data, spec).is_ok() {
let builder_index = state.add_builder_to_registry(
pubkey,
version,
withdrawal_credentials,
amount,
slot,

View File

@@ -10,7 +10,8 @@ use tree_hash::TreeHash;
use typenum::Unsigned;
use types::{
BeaconState, BeaconStateError as Error, BeaconStateGloas, BuilderPendingPayment, ChainSpec,
EthSpec, ExecutionPayloadBid, ExecutionRequests, Fork, is_builder_withdrawal_credential,
EthSpec, ExecutionPayloadBid, ExecutionRequests, Fork, consts::gloas::PAYLOAD_BUILDER_VERSION,
is_builder_withdrawal_credential,
};
/// Transform a `Fulu` state into a `Gloas` state.
@@ -208,6 +209,7 @@ fn onboard_builders_from_pending_deposits<E: EthSpec>(
state,
builder_index,
deposit.pubkey,
PAYLOAD_BUILDER_VERSION,
deposit.withdrawal_credentials,
deposit.amount,
deposit.signature.clone(),

View File

@@ -29,6 +29,9 @@ pub mod gloas {
pub const BUILDER_INDEX_SELF_BUILD: u64 = u64::MAX;
pub const BUILDER_INDEX_FLAG: u64 = 1 << 40;
/// Version for an execution payload builder.
pub const PAYLOAD_BUILDER_VERSION: u8 = 0;
// Fork choice constants
pub type PayloadStatus = u8;
pub const PAYLOAD_STATUS_EMPTY: PayloadStatus = 0;

View File

@@ -2061,6 +2061,7 @@ impl<E: EthSpec> BeaconState<E> {
pub fn add_builder_to_registry(
&mut self,
pubkey: PublicKeyBytes,
version: u8,
withdrawal_credentials: Hash256,
amount: u64,
slot: Slot,
@@ -2072,10 +2073,6 @@ impl<E: EthSpec> BeaconState<E> {
let builder_index = self.get_index_for_new_builder()?;
let builders = self.builders_mut()?;
let version = *withdrawal_credentials
.as_slice()
.first()
.ok_or(BeaconStateError::WithdrawalCredentialMissingVersion)?;
let execution_address = withdrawal_credentials
.as_slice()
.get(12..)