Merge branch 'alpha-spec-11' into glamsterdam-devnet-6

This commit is contained in:
Eitan Seri-Levi
2026-06-23 12:15:09 +03:00
12 changed files with 374 additions and 316 deletions

View File

@@ -31,11 +31,10 @@ use types::{
Address, Attestation, AttestationElectra, AttesterSlashing, AttesterSlashingElectra,
BeaconBlock, BeaconBlockBodyGloas, BeaconBlockGloas, BeaconState, BeaconStateError,
BuilderIndex, ChainSpec, Deposit, Eth1Data, EthSpec, ExecutionBlockHash, ExecutionPayloadBid,
ExecutionPayloadEnvelope, ExecutionPayloadGloas, ExecutionRequests, ExecutionRequestsGloas,
FullPayload, Graffiti, Hash256, PayloadAttestation, ProposerSlashing, RelativeEpoch,
SignedBeaconBlock, SignedBlsToExecutionChange, SignedExecutionPayloadBid,
SignedExecutionPayloadEnvelope, SignedVoluntaryExit, Slot, SyncAggregate, Withdrawal,
Withdrawals,
ExecutionPayloadEnvelope, ExecutionPayloadGloas, ExecutionRequestsGloas, FullPayload, Graffiti,
Hash256, PayloadAttestation, ProposerSlashing, RelativeEpoch, SignedBeaconBlock,
SignedBlsToExecutionChange, SignedExecutionPayloadBid, SignedExecutionPayloadEnvelope,
SignedVoluntaryExit, Slot, SyncAggregate, Withdrawal, Withdrawals,
};
use crate::pending_payload_envelopes::PendingEnvelopeData;
@@ -810,11 +809,6 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
should_override_builder,
} = block_proposal_contents;
// The EL get_payload response carries the standard (Electra-shaped) requests; lift them
// into the Gloas variant carried by the envelope and committed to by the bid.
// TODO(gloas): plumb builder deposit/exit requests from the EL.
let execution_requests = to_gloas_execution_requests(execution_requests);
// TODO(gloas) since we are defaulting to local building, execution payment is 0
// execution payment should only be set to > 0 for trusted building.
let bid = ExecutionPayloadBid::<T::EthSpec> {
@@ -1113,26 +1107,6 @@ where
/// processing. EL-triggered withdrawal-full-exit requests (EIP-7002) and cross-pubkey
/// consolidation requests (EIP-7251) call `initiate_validator_exit`, setting the target's
/// `exit_epoch`. A voluntary exit for the same validator would then fail with `AlreadyExited`.
/// Lift a fork-agnostic `ExecutionRequests` (as received from the EL) into the Gloas variant.
///
/// The standard request types are carried over; the Gloas-only builder deposit/exit lists are
/// left empty.
/// TODO(gloas): plumb builder deposit/exit requests from the EL.
fn to_gloas_execution_requests<E: EthSpec>(
requests: ExecutionRequests<E>,
) -> ExecutionRequestsGloas<E> {
match requests {
ExecutionRequests::Gloas(requests) => requests,
other => ExecutionRequestsGloas {
deposits: other.deposits().clone(),
withdrawals: other.withdrawals().clone(),
consolidations: other.consolidations().clone(),
builder_deposits: <_>::default(),
builder_exits: <_>::default(),
},
}
}
fn filter_voluntary_exits_for_parent_execution_requests<E: EthSpec>(
voluntary_exits: &mut Vec<SignedVoluntaryExit>,
parent_execution_requests: &ExecutionRequestsGloas<E>,

View File

@@ -1,5 +1,5 @@
use std::assert_matches;
use std::sync::Arc;
use std::time::Duration;
use bls::{Keypair, PublicKeyBytes, Signature};
@@ -195,6 +195,40 @@ impl TestContext {
}
}
fn expected_prev_randao(&self) -> Hash256 {
let current_slot = self.slot_clock.now().expect("should read slot clock");
let head = self.canonical_head.cached_head();
*head
.snapshot
.beacon_state
.get_randao_mix(current_slot.epoch(E::slots_per_epoch()))
.expect("should read current epoch randao mix")
}
fn make_signed_bid(
&self,
slot: Slot,
builder_index: u64,
fee_recipient: Address,
gas_limit: u64,
value: u64,
parent_block_root: Hash256,
) -> Arc<SignedExecutionPayloadBid<E>> {
Arc::new(SignedExecutionPayloadBid {
message: ExecutionPayloadBid {
slot,
builder_index,
fee_recipient,
gas_limit,
value,
parent_block_root,
prev_randao: self.expected_prev_randao(),
..ExecutionPayloadBid::default()
},
signature: Signature::empty(),
})
}
fn insert_non_canonical_block(&self) -> Hash256 {
let shuffling_id = AttestationShufflingId {
shuffling_epoch: Epoch::new(0),
@@ -237,28 +271,6 @@ impl TestContext {
}
}
fn make_signed_bid(
slot: Slot,
builder_index: u64,
fee_recipient: Address,
gas_limit: u64,
value: u64,
parent_block_root: Hash256,
) -> Arc<SignedExecutionPayloadBid<E>> {
Arc::new(SignedExecutionPayloadBid {
message: ExecutionPayloadBid {
slot,
builder_index,
fee_recipient,
gas_limit,
value,
parent_block_root,
..ExecutionPayloadBid::default()
},
signature: Signature::empty(),
})
}
fn make_signed_preferences(
proposal_slot: Slot,
validator_index: u64,
@@ -309,7 +321,7 @@ fn no_proposer_preferences_for_slot() {
}
let ctx = TestContext::new();
let gossip = ctx.gossip_ctx();
let bid = make_signed_bid(
let bid = ctx.make_signed_bid(
Slot::new(0),
0,
Address::ZERO,
@@ -335,7 +347,7 @@ fn builder_already_seen_for_slot() {
let slot = Slot::new(1);
seed_preferences(&ctx, slot, Address::ZERO, 30_000_000);
let bid = make_signed_bid(slot, 42, Address::ZERO, 30_000_000, 100, Hash256::ZERO);
let bid = ctx.make_signed_bid(slot, 42, Address::ZERO, 30_000_000, 100, Hash256::ZERO);
let verified = GossipVerifiedPayloadBid {
signed_bid: bid.clone(),
};
@@ -362,11 +374,11 @@ fn bid_value_below_cached() {
seed_preferences(&ctx, slot, Address::ZERO, 30_000_000);
let high_bid = GossipVerifiedPayloadBid {
signed_bid: make_signed_bid(slot, 99, Address::ZERO, 30_000_000, 500, Hash256::ZERO),
signed_bid: ctx.make_signed_bid(slot, 99, Address::ZERO, 30_000_000, 500, Hash256::ZERO),
};
ctx.bid_cache.insert_highest_bid(high_bid);
let low_bid = make_signed_bid(slot, 1, Address::ZERO, 30_000_000, 100, Hash256::ZERO);
let low_bid = ctx.make_signed_bid(slot, 1, Address::ZERO, 30_000_000, 100, Hash256::ZERO);
let result = GossipVerifiedPayloadBid::new(low_bid, &gossip);
assert!(matches!(
result,
@@ -384,7 +396,7 @@ fn invalid_bid_slot() {
let slot = Slot::new(5);
seed_preferences(&ctx, slot, Address::ZERO, 30_000_000);
let bid = make_signed_bid(
let bid = ctx.make_signed_bid(
slot,
0,
Address::ZERO,
@@ -393,10 +405,7 @@ fn invalid_bid_slot() {
ctx.genesis_block_root,
);
let result = GossipVerifiedPayloadBid::new(bid, &gossip);
assert!(matches!(
result,
Err(PayloadBidError::InvalidBidSlot { .. })
));
assert_matches!(result, Err(PayloadBidError::InvalidBidSlot { .. }));
}
#[test]
@@ -409,7 +418,7 @@ fn fee_recipient_mismatch() {
let slot = Slot::new(1);
seed_preferences(&ctx, slot, Address::repeat_byte(0xaa), 30_000_000);
let bid = make_signed_bid(
let bid = ctx.make_signed_bid(
slot,
0,
Address::ZERO,
@@ -431,7 +440,7 @@ fn gas_limit_mismatch() {
let slot = Slot::new(1);
seed_preferences(&ctx, slot, Address::ZERO, 30_000_000);
let bid = make_signed_bid(
let bid = ctx.make_signed_bid(
slot,
0,
Address::ZERO,
@@ -459,6 +468,7 @@ fn execution_payment_nonzero() {
gas_limit: 30_000_000,
execution_payment: 42,
parent_block_root: ctx.genesis_block_root,
prev_randao: ctx.expected_prev_randao(),
..ExecutionPayloadBid::default()
},
signature: Signature::empty(),
@@ -481,7 +491,7 @@ fn unknown_builder_index() {
seed_preferences(&ctx, slot, Address::ZERO, 30_000_000);
// Use a builder_index that doesn't exist in the registry.
let bid = make_signed_bid(
let bid = ctx.make_signed_bid(
slot,
9999,
Address::ZERO,
@@ -508,7 +518,7 @@ fn inactive_builder() {
let slot = Slot::new(1);
seed_preferences(&ctx, slot, Address::ZERO, 30_000_000);
let bid = make_signed_bid(
let bid = ctx.make_signed_bid(
slot,
ctx.inactive_builder_index,
Address::ZERO,
@@ -534,7 +544,7 @@ fn builder_cant_cover_bid() {
seed_preferences(&ctx, slot, Address::ZERO, 30_000_000);
// Builder index 0 exists but bid value far exceeds their balance.
let bid = make_signed_bid(
let bid = ctx.make_signed_bid(
slot,
0,
Address::ZERO,
@@ -561,7 +571,7 @@ fn parent_block_root_unknown() {
// Parent block root not in fork choice.
let unknown_root = Hash256::repeat_byte(0xff);
let bid = make_signed_bid(slot, 0, Address::ZERO, 30_000_000, 0, unknown_root);
let bid = ctx.make_signed_bid(slot, 0, Address::ZERO, 30_000_000, 0, unknown_root);
let result = GossipVerifiedPayloadBid::new(bid, &gossip);
assert!(result.is_err(), "expected error, got Ok");
let err = result.unwrap_err();
@@ -584,7 +594,7 @@ fn parent_block_root_not_canonical() {
seed_preferences(&ctx, slot, Address::ZERO, 30_000_000);
let fork_root = ctx.insert_non_canonical_block();
let bid = make_signed_bid(slot, 0, Address::ZERO, 30_000_000, 0, fork_root);
let bid = ctx.make_signed_bid(slot, 0, Address::ZERO, 30_000_000, 0, fork_root);
let result = GossipVerifiedPayloadBid::new(bid, &gossip);
assert!(result.is_err(), "expected error, got Ok");
let err = result.unwrap_err();
@@ -606,7 +616,7 @@ fn bid_slot_not_after_parent() {
let slot = Slot::new(0);
seed_preferences(&ctx, slot, Address::ZERO, 30_000_000);
let bid = make_signed_bid(
let bid = ctx.make_signed_bid(
slot,
0,
Address::ZERO,
@@ -649,6 +659,7 @@ fn invalid_blob_kzg_commitments() {
gas_limit: 30_000_000,
value: 0,
parent_block_root: ctx.genesis_block_root,
prev_randao: ctx.expected_prev_randao(),
blob_kzg_commitments: VariableList::new(commitments).unwrap(),
..ExecutionPayloadBid::default()
},
@@ -672,7 +683,7 @@ fn bad_signature() {
seed_preferences(&ctx, slot, Address::ZERO, 30_000_000);
// All checks pass but signature is empty/invalid.
let bid = make_signed_bid(
let bid = ctx.make_signed_bid(
slot,
0,
Address::ZERO,
@@ -707,6 +718,7 @@ fn valid_bid() {
gas_limit: 30_000_000,
value: 0,
parent_block_root: ctx.genesis_block_root,
prev_randao: ctx.expected_prev_randao(),
..ExecutionPayloadBid::default()
});
let result = GossipVerifiedPayloadBid::new(bid, &gossip);
@@ -734,6 +746,7 @@ fn two_builders_coexist_in_cache() {
gas_limit: 30_000_000,
value: 0,
parent_block_root: ctx.genesis_block_root,
prev_randao: ctx.expected_prev_randao(),
..ExecutionPayloadBid::default()
});
let result_0 = GossipVerifiedPayloadBid::new(bid_0, &gossip);
@@ -751,6 +764,7 @@ fn two_builders_coexist_in_cache() {
gas_limit: 30_000_000,
value: 1,
parent_block_root: ctx.genesis_block_root,
prev_randao: ctx.expected_prev_randao(),
..ExecutionPayloadBid::default()
});
let result_1 = GossipVerifiedPayloadBid::new(bid_1, &gossip);
@@ -784,7 +798,7 @@ fn bid_equal_to_cached_value_rejected() {
// Seed a cached bid with value 100.
let high_bid = GossipVerifiedPayloadBid {
signed_bid: make_signed_bid(
signed_bid: ctx.make_signed_bid(
slot,
99,
Address::ZERO,
@@ -796,7 +810,7 @@ fn bid_equal_to_cached_value_rejected() {
ctx.bid_cache.insert_highest_bid(high_bid);
// Submit a bid with exactly the same value — should be rejected.
let equal_bid = make_signed_bid(
let equal_bid = ctx.make_signed_bid(
slot,
1,
Address::ZERO,