fix claude dummy

This commit is contained in:
Eitan Seri-Levi
2026-04-30 16:08:10 +02:00
parent 4e3a3c1d7e
commit e75eb4758c
11 changed files with 296 additions and 213 deletions

View File

@@ -32,9 +32,9 @@ use types::{
ExecutionBlockHash, ExecutionPayloadBidGloas, ExecutionPayloadBidHeze,
ExecutionPayloadEnvelope, ExecutionPayloadGloas, ExecutionRequests, FullPayload, Graffiti,
Hash256, PayloadAttestation, ProposerSlashing, RelativeEpoch, SignedBeaconBlock,
SignedBlsToExecutionChange, SignedExecutionPayloadBidGloas, SignedExecutionPayloadBidHeze,
SignedExecutionPayloadEnvelope, SignedVoluntaryExit, Slot, SyncAggregate, Withdrawal,
Withdrawals,
SignedBlsToExecutionChange, SignedExecutionPayloadBid, SignedExecutionPayloadBidGloas,
SignedExecutionPayloadBidHeze, SignedExecutionPayloadEnvelope, SignedVoluntaryExit,
Slot, SyncAggregate, Withdrawal, Withdrawals,
};
use crate::pending_payload_envelopes::PendingEnvelopeData;
@@ -513,7 +513,7 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
fn complete_partial_beacon_block_gloas(
&self,
partial_beacon_block: PartialBeaconBlock<T::EthSpec>,
signed_execution_payload_bid: SignedExecutionPayloadBidGloas<T::EthSpec>,
signed_execution_payload_bid: SignedExecutionPayloadBid<T::EthSpec>,
parent_execution_requests: ExecutionRequests<T::EthSpec>,
payload_data: Option<ExecutionPayloadData<T::EthSpec>>,
mut state: BeaconState<T::EthSpec>,
@@ -548,44 +548,53 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
"complete_partial_beacon_block_gloas called with pre-Gloas state".to_owned(),
));
}
BeaconState::Gloas(_) => BeaconBlock::Gloas(BeaconBlockGloas {
slot,
proposer_index,
parent_root,
state_root: Hash256::ZERO,
body: BeaconBlockBodyGloas {
randao_reveal,
eth1_data,
graffiti,
proposer_slashings: proposer_slashings
.try_into()
.map_err(BlockProductionError::SszTypesError)?,
attester_slashings: attester_slashings
.try_into()
.map_err(BlockProductionError::SszTypesError)?,
attestations: attestations
.try_into()
.map_err(BlockProductionError::SszTypesError)?,
deposits: deposits
.try_into()
.map_err(BlockProductionError::SszTypesError)?,
voluntary_exits: voluntary_exits
.try_into()
.map_err(BlockProductionError::SszTypesError)?,
sync_aggregate,
bls_to_execution_changes: bls_to_execution_changes
.try_into()
.map_err(BlockProductionError::SszTypesError)?,
parent_execution_requests,
signed_execution_payload_bid,
payload_attestations: payload_attestations
.try_into()
.map_err(BlockProductionError::SszTypesError)?,
_phantom: PhantomData::<FullPayload<T::EthSpec>>,
},
}),
BeaconState::Gloas(_) => {
let gloas_bid = match signed_execution_payload_bid {
SignedExecutionPayloadBid::Gloas(bid) => bid,
SignedExecutionPayloadBid::Heze(_) => {
return Err(BlockProductionError::GloasNotImplemented(
"Heze bid variant used with Gloas state".to_owned(),
));
}
};
BeaconBlock::Gloas(BeaconBlockGloas {
slot,
proposer_index,
parent_root,
state_root: Hash256::ZERO,
body: BeaconBlockBodyGloas {
randao_reveal,
eth1_data,
graffiti,
proposer_slashings: proposer_slashings
.try_into()
.map_err(BlockProductionError::SszTypesError)?,
attester_slashings: attester_slashings
.try_into()
.map_err(BlockProductionError::SszTypesError)?,
attestations: attestations
.try_into()
.map_err(BlockProductionError::SszTypesError)?,
deposits: deposits
.try_into()
.map_err(BlockProductionError::SszTypesError)?,
voluntary_exits: voluntary_exits
.try_into()
.map_err(BlockProductionError::SszTypesError)?,
sync_aggregate,
bls_to_execution_changes: bls_to_execution_changes
.try_into()
.map_err(BlockProductionError::SszTypesError)?,
parent_execution_requests,
signed_execution_payload_bid: gloas_bid,
payload_attestations: payload_attestations
.try_into()
.map_err(BlockProductionError::SszTypesError)?,
_phantom: PhantomData::<FullPayload<T::EthSpec>>,
},
})
}
BeaconState::Heze(_) => {
let gloas_bid = signed_execution_payload_bid;
// Compute inclusion_list_bits for the previous slot's ILs
let il_slot = slot.saturating_sub(1_u64);
let inclusion_list_bits = state
@@ -596,23 +605,28 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
.get_inclusion_list_bits(il_slot, &committee, false)
})
.unwrap_or_default();
let heze_bid = SignedExecutionPayloadBidHeze {
message: ExecutionPayloadBidHeze {
parent_block_hash: gloas_bid.message.parent_block_hash,
parent_block_root: gloas_bid.message.parent_block_root,
block_hash: gloas_bid.message.block_hash,
prev_randao: gloas_bid.message.prev_randao,
fee_recipient: gloas_bid.message.fee_recipient,
gas_limit: gloas_bid.message.gas_limit,
builder_index: gloas_bid.message.builder_index,
slot: gloas_bid.message.slot,
value: gloas_bid.message.value,
execution_payment: gloas_bid.message.execution_payment,
blob_kzg_commitments: gloas_bid.message.blob_kzg_commitments,
execution_requests_root: gloas_bid.message.execution_requests_root,
inclusion_list_bits,
},
signature: gloas_bid.signature,
let heze_bid = match signed_execution_payload_bid {
SignedExecutionPayloadBid::Heze(bid) => bid,
SignedExecutionPayloadBid::Gloas(gloas_bid) => {
SignedExecutionPayloadBidHeze {
message: ExecutionPayloadBidHeze {
parent_block_hash: gloas_bid.message.parent_block_hash,
parent_block_root: gloas_bid.message.parent_block_root,
block_hash: gloas_bid.message.block_hash,
prev_randao: gloas_bid.message.prev_randao,
fee_recipient: gloas_bid.message.fee_recipient,
gas_limit: gloas_bid.message.gas_limit,
builder_index: gloas_bid.message.builder_index,
slot: gloas_bid.message.slot,
value: gloas_bid.message.value,
execution_payment: gloas_bid.message.execution_payment,
blob_kzg_commitments: gloas_bid.message.blob_kzg_commitments,
execution_requests_root: gloas_bid.message.execution_requests_root,
inclusion_list_bits,
},
signature: gloas_bid.signature,
}
}
};
BeaconBlock::Heze(BeaconBlockHeze {
slot,
@@ -781,7 +795,7 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
builder_index: BuilderIndex,
) -> Result<
(
SignedExecutionPayloadBidGloas<T::EthSpec>,
SignedExecutionPayloadBid<T::EthSpec>,
BeaconState<T::EthSpec>,
LocalBuildResult<T::EthSpec>,
),
@@ -889,10 +903,10 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
};
Ok((
SignedExecutionPayloadBidGloas {
SignedExecutionPayloadBid::Gloas(SignedExecutionPayloadBidGloas {
message: bid,
signature: Signature::infinity().map_err(BlockProductionError::BlsError)?,
},
}),
state,
LocalBuildResult {
payload_data,
@@ -904,19 +918,24 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
/// Look up the highest gossip-verified bid for the `(slot, parent_block_hash,
/// parent_block_root)` of the local bid, then choose the winner.
// TODO(focil): When the bid cache supports Heze-typed bids, validate that any external
// builder bid's `inclusion_list_bits` satisfies `is_inclusion_list_bits_inclusive` with
// `only_timely=False` before accepting it. Currently the cache is Gloas-typed so this
// check cannot be performed.
// See: https://github.com/ethereum/consensus-specs/blob/master/specs/heze/validator.md#signed-execution-payload-bid
fn select_payload_bid(
&self,
local_signed_bid: SignedExecutionPayloadBidGloas<T::EthSpec>,
local_signed_bid: SignedExecutionPayloadBid<T::EthSpec>,
local_build: LocalBuildResult<T::EthSpec>,
builder_boost_factor: Option<u64>,
) -> (
SignedExecutionPayloadBidGloas<T::EthSpec>,
SignedExecutionPayloadBid<T::EthSpec>,
Option<ExecutionPayloadData<T::EthSpec>>,
) {
let cached_bid = self.gossip_verified_payload_bid_cache.get_highest_bid(
local_signed_bid.message.slot,
local_signed_bid.message.parent_block_hash,
local_signed_bid.message.parent_block_root,
local_signed_bid.message().slot(),
local_signed_bid.message().parent_block_hash(),
local_signed_bid.message().parent_block_root(),
);
select_payload_bid_pure(
local_signed_bid,
@@ -938,12 +957,12 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
///
/// `cached_bid.value` is in gwei (`u64`); `payload_value` is in wei (`Uint256`); compared in wei.
pub(crate) fn select_payload_bid_pure<E: EthSpec>(
local_signed_bid: SignedExecutionPayloadBidGloas<E>,
local_signed_bid: SignedExecutionPayloadBid<E>,
local_build: LocalBuildResult<E>,
cached_bid: Option<Arc<SignedExecutionPayloadBidGloas<E>>>,
cached_bid: Option<Arc<SignedExecutionPayloadBid<E>>>,
builder_boost_factor: Option<u64>,
) -> (
SignedExecutionPayloadBidGloas<E>,
SignedExecutionPayloadBid<E>,
Option<ExecutionPayloadData<E>>,
) {
let LocalBuildResult {
@@ -956,19 +975,19 @@ pub(crate) fn select_payload_bid_pure<E: EthSpec>(
return (local_signed_bid, Some(payload_data));
};
let slot = local_signed_bid.message.slot;
let slot = local_signed_bid.message().slot();
if should_override_builder {
debug!(
%slot,
cached_bid_value = cached_bid.message.value,
cached_bid_value = cached_bid.message().value(),
"Using local payload because EL signaled shouldOverrideBuilder"
);
return (local_signed_bid, Some(payload_data));
}
// Convert bid value (gwei) to wei for comparison with `payload_value` (wei).
let bid_value_wei = types::Uint256::from(cached_bid.message.value)
let bid_value_wei = types::Uint256::from(cached_bid.message().value())
.saturating_mul(types::Uint256::from(1_000_000_000u64));
let boosted_bid_wei = match builder_boost_factor {
Some(factor) => {
@@ -981,7 +1000,7 @@ pub(crate) fn select_payload_bid_pure<E: EthSpec>(
debug!(
%slot,
%payload_value,
cached_bid_value_gwei = cached_bid.message.value,
cached_bid_value_gwei = cached_bid.message().value(),
?builder_boost_factor,
"Local payload is more profitable than cached builder bid"
);
@@ -990,8 +1009,8 @@ pub(crate) fn select_payload_bid_pure<E: EthSpec>(
debug!(
%slot,
%payload_value,
cached_bid_value_gwei = cached_bid.message.value,
cached_bid_builder_index = cached_bid.message.builder_index,
cached_bid_value_gwei = cached_bid.message().value(),
cached_bid_builder_index = cached_bid.message().builder_index(),
?builder_boost_factor,
"Including cached builder bid"
);
@@ -1356,25 +1375,27 @@ mod tests {
types::Uint256::from(n).saturating_mul(types::Uint256::from(1_000_000_000u64))
}
fn local_bid() -> SignedExecutionPayloadBidGloas<TestSpec> {
SignedExecutionPayloadBidGloas {
fn local_bid() -> SignedExecutionPayloadBid<TestSpec> {
SignedExecutionPayloadBid::Gloas(SignedExecutionPayloadBidGloas {
message: ExecutionPayloadBidGloas {
builder_index: BUILDER_INDEX_SELF_BUILD,
..Default::default()
},
signature: Signature::empty(),
}
})
}
fn cached_bid(value_gwei: u64) -> Arc<SignedExecutionPayloadBidGloas<TestSpec>> {
Arc::new(SignedExecutionPayloadBidGloas {
message: ExecutionPayloadBidGloas {
builder_index: REMOTE_BUILDER,
value: value_gwei,
..Default::default()
fn cached_bid(value_gwei: u64) -> Arc<SignedExecutionPayloadBid<TestSpec>> {
Arc::new(SignedExecutionPayloadBid::Gloas(
SignedExecutionPayloadBidGloas {
message: ExecutionPayloadBidGloas {
builder_index: REMOTE_BUILDER,
value: value_gwei,
..Default::default()
},
signature: Signature::empty(),
},
signature: Signature::empty(),
})
))
}
fn local_build(payload_gwei: u64, should_override_builder: bool) -> LocalBuildResult<TestSpec> {
@@ -1410,7 +1431,7 @@ mod tests {
let build = local_build(local_payload_gwei, should_override);
let cache = cached_gwei.map(cached_bid);
let (out, data) = select_payload_bid_pure::<TestSpec>(local_bid(), build, cache, boost);
(out.message.builder_index, data.is_some())
(out.message().builder_index(), data.is_some())
}
#[test]

View File

@@ -13,51 +13,47 @@ use state_processing::signature_sets::{
};
use tracing::debug;
use types::{
BeaconState, ChainSpec, EthSpec, ExecutionPayloadBidGloas, SignedExecutionPayloadBidGloas,
SignedExecutionPayloadBidRef, SignedProposerPreferences, Slot,
BeaconState, ChainSpec, EthSpec, ExecutionPayloadBidRef, SignedExecutionPayloadBid,
SignedProposerPreferences, Slot,
};
/// Verify that an execution payload bid is consistent with the current chain state
/// and proposer preferences.
pub(crate) fn verify_bid_consistency<E: EthSpec>(
bid: &ExecutionPayloadBidGloas<E>,
bid: ExecutionPayloadBidRef<'_, E>,
current_slot: Slot,
proposer_preferences: &SignedProposerPreferences,
head_state: &BeaconState<E>,
spec: &ChainSpec,
) -> Result<(), PayloadBidError> {
let bid_slot = bid.slot;
let bid_slot = bid.slot();
if bid_slot != current_slot && bid_slot != current_slot.saturating_add(1u64) {
return Err(PayloadBidError::InvalidBidSlot { bid_slot });
}
// Execution payments are used by off protocol builders. In protocol bids
// should always have this value set to zero.
if bid.execution_payment != 0 {
if bid.execution_payment() != 0 {
return Err(PayloadBidError::ExecutionPaymentNonZero {
execution_payment: bid.execution_payment,
execution_payment: bid.execution_payment(),
});
}
if bid.fee_recipient != proposer_preferences.message.fee_recipient {
if bid.fee_recipient() != proposer_preferences.message.fee_recipient {
return Err(PayloadBidError::InvalidFeeRecipient);
}
if bid.gas_limit != proposer_preferences.message.gas_limit {
if bid.gas_limit() != proposer_preferences.message.gas_limit {
return Err(PayloadBidError::InvalidGasLimit);
}
let max_blobs_per_block =
spec.max_blobs_per_block(bid_slot.epoch(E::slots_per_epoch())) as usize;
if bid.blob_kzg_commitments.len() > max_blobs_per_block {
if bid.blob_kzg_commitments().len() > max_blobs_per_block {
return Err(PayloadBidError::InvalidBlobKzgCommitments {
max_blobs_per_block,
blob_kzg_commitments_len: bid.blob_kzg_commitments.len(),
blob_kzg_commitments_len: bid.blob_kzg_commitments().len(),
});
}
let builder_index = bid.builder_index;
let builder_index = bid.builder_index();
let is_active_builder = head_state
.is_active_builder(builder_index, spec)
@@ -67,10 +63,10 @@ pub(crate) fn verify_bid_consistency<E: EthSpec>(
return Err(PayloadBidError::InvalidBuilder { builder_index });
}
if !head_state.can_builder_cover_bid(builder_index, bid.value, spec)? {
if !head_state.can_builder_cover_bid(builder_index, bid.value(), spec)? {
return Err(PayloadBidError::BuilderCantCoverBid {
builder_index,
builder_bid: bid.value,
builder_bid: bid.value(),
});
}
@@ -85,47 +81,44 @@ pub struct GossipVerificationContext<'a, T: BeaconChainTypes> {
pub spec: &'a ChainSpec,
}
/// A wrapper around a `SignedExecutionPayloadBidGloas` that indicates it has been approved for re-gossiping on
/// the p2p network.
#[derive(Educe)]
#[educe(
Debug(bound = "T: BeaconChainTypes"),
Clone(bound = "T: BeaconChainTypes")
)]
pub struct GossipVerifiedPayloadBid<T: BeaconChainTypes> {
pub signed_bid: Arc<SignedExecutionPayloadBidGloas<T::EthSpec>>,
pub signed_bid: Arc<SignedExecutionPayloadBid<T::EthSpec>>,
}
impl<T: BeaconChainTypes> GossipVerifiedPayloadBid<T> {
pub fn new(
signed_bid: Arc<SignedExecutionPayloadBidGloas<T::EthSpec>>,
signed_bid: Arc<SignedExecutionPayloadBid<T::EthSpec>>,
ctx: &GossipVerificationContext<'_, T>,
) -> Result<Self, PayloadBidError> {
let bid_slot = signed_bid.message.slot;
let bid_parent_block_hash = signed_bid.message.parent_block_hash;
let bid_parent_block_root = signed_bid.message.parent_block_root;
let bid_value = signed_bid.message.value;
let bid_msg = signed_bid.message();
let bid_slot = bid_msg.slot();
let bid_parent_block_hash = bid_msg.parent_block_hash();
let bid_parent_block_root = bid_msg.parent_block_root();
let bid_value = bid_msg.value();
if ctx
.gossip_verified_payload_bid_cache
.seen_builder_index(&bid_slot, signed_bid.message.builder_index)
.seen_builder_index(&bid_slot, bid_msg.builder_index())
{
return Err(PayloadBidError::BuilderAlreadySeen {
builder_index: signed_bid.message.builder_index,
builder_index: bid_msg.builder_index(),
slot: bid_slot,
});
}
// TODO(gloas): Extract into `bid_value_over_threshold` on the bid cache and potentially
// make this more sophisticate than just a <= check.
if let Some(cached_bid) = ctx.gossip_verified_payload_bid_cache.get_highest_bid(
bid_slot,
bid_parent_block_hash,
bid_parent_block_root,
) && bid_value <= cached_bid.message.value
) && bid_value <= cached_bid.message().value()
{
return Err(PayloadBidError::BidValueBelowCached {
cached_value: cached_bid.message.value,
cached_value: cached_bid.message().value(),
incoming_value: bid_value,
});
}
@@ -146,14 +139,12 @@ impl<T: BeaconChainTypes> GossipVerifiedPayloadBid<T> {
let fork_choice = ctx.canonical_head.fork_choice_read_lock();
// TODO(gloas) reprocess bids whose parent_block_root becomes known & canonical after a reorg?
if !fork_choice.contains_block(&bid_parent_block_root) {
return Err(PayloadBidError::ParentBlockRootUnknown {
parent_block_root: bid_parent_block_root,
});
}
// TODO(gloas) reprocess bids whose parent_block_root becomes canonical after a reorg.
let head_root = cached_head.head_block_root();
if !fork_choice.is_descendant(bid_parent_block_root, head_root) {
return Err(PayloadBidError::ParentBlockRootNotCanonical {
@@ -161,23 +152,20 @@ impl<T: BeaconChainTypes> GossipVerifiedPayloadBid<T> {
});
}
// TODO(gloas) [IGNORE] bid.parent_block_hash is the block hash of a known execution payload in fork choice.
drop(fork_choice);
verify_bid_consistency(
&signed_bid.message,
signed_bid.message(),
current_slot,
&proposer_preferences,
head_state,
ctx.spec,
)?;
// Verify signature
execution_payload_bid_signature_set(
head_state,
|i| get_builder_pubkey_from_state(head_state, i),
SignedExecutionPayloadBidRef::Gloas(&signed_bid),
signed_bid.to_ref(),
ctx.spec,
)
.map_err(|_| PayloadBidError::BadSignature)?
@@ -199,7 +187,6 @@ impl<T: BeaconChainTypes> GossipVerifiedPayloadBid<T> {
}
impl<T: BeaconChainTypes> BeaconChain<T> {
/// Build a `GossipVerificationContext` from this `BeaconChain` for `GossipVerifiedPayloadBid`.
pub fn payload_bid_gossip_verification_context(&self) -> GossipVerificationContext<'_, T> {
GossipVerificationContext {
canonical_head: &self.canonical_head,
@@ -211,19 +198,14 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
}
}
/// Returns `Ok(GossipVerifiedPayloadBid)` if the supplied `bid` should be forwarded onto the
/// gossip network and cached.
///
/// ## Errors
///
/// Returns an `Err` if the given bid was invalid, or an error was encountered during verification.
pub fn verify_payload_bid_for_gossip(
&self,
bid: Arc<SignedExecutionPayloadBidGloas<T::EthSpec>>,
bid: Arc<SignedExecutionPayloadBid<T::EthSpec>>,
) -> Result<GossipVerifiedPayloadBid<T>, PayloadBidError> {
let slot = bid.message.slot;
let parent_block_root = bid.message.parent_block_root;
let parent_block_hash = bid.message.parent_block_hash;
let bid_msg = bid.message();
let slot = bid_msg.slot();
let parent_block_root = bid_msg.parent_block_root();
let parent_block_hash = bid_msg.parent_block_hash();
let ctx = self.payload_bid_gossip_verification_context();
match GossipVerifiedPayloadBid::new(bid, &ctx) {
@@ -269,8 +251,9 @@ mod tests {
use kzg::KzgCommitment;
use ssz_types::VariableList;
use types::{
Address, BeaconState, ChainSpec, EthSpec, ExecutionPayloadBidGloas, MinimalEthSpec,
ProposerPreferences, SignedProposerPreferences, Slot,
Address, BeaconState, ChainSpec, EthSpec, ExecutionPayloadBidGloas,
ExecutionPayloadBidRef, MinimalEthSpec, ProposerPreferences, SignedProposerPreferences,
Slot,
};
use super::verify_bid_consistency;
@@ -312,7 +295,13 @@ mod tests {
let bid = make_bid(Slot::new(5), Address::ZERO, 30_000_000);
let prefs = make_preferences(Address::ZERO, 30_000_000);
let result = verify_bid_consistency::<E>(&bid, current_slot, &prefs, &state, &spec);
let result = verify_bid_consistency::<E>(
ExecutionPayloadBidRef::Gloas(&bid),
current_slot,
&prefs,
&state,
&spec,
);
assert!(matches!(
result,
Err(PayloadBidError::InvalidBidSlot { .. })
@@ -326,7 +315,13 @@ mod tests {
let bid = make_bid(Slot::new(12), Address::ZERO, 30_000_000);
let prefs = make_preferences(Address::ZERO, 30_000_000);
let result = verify_bid_consistency::<E>(&bid, current_slot, &prefs, &state, &spec);
let result = verify_bid_consistency::<E>(
ExecutionPayloadBidRef::Gloas(&bid),
current_slot,
&prefs,
&state,
&spec,
);
assert!(matches!(
result,
Err(PayloadBidError::InvalidBidSlot { .. })
@@ -341,7 +336,13 @@ mod tests {
bid.execution_payment = 42;
let prefs = make_preferences(Address::ZERO, 30_000_000);
let result = verify_bid_consistency::<E>(&bid, current_slot, &prefs, &state, &spec);
let result = verify_bid_consistency::<E>(
ExecutionPayloadBidRef::Gloas(&bid),
current_slot,
&prefs,
&state,
&spec,
);
assert!(matches!(
result,
Err(PayloadBidError::ExecutionPaymentNonZero {
@@ -357,7 +358,13 @@ mod tests {
let bid = make_bid(current_slot, Address::ZERO, 30_000_000);
let prefs = make_preferences(Address::repeat_byte(0xaa), 30_000_000);
let result = verify_bid_consistency::<E>(&bid, current_slot, &prefs, &state, &spec);
let result = verify_bid_consistency::<E>(
ExecutionPayloadBidRef::Gloas(&bid),
current_slot,
&prefs,
&state,
&spec,
);
assert!(matches!(result, Err(PayloadBidError::InvalidFeeRecipient)));
}
@@ -374,7 +381,13 @@ mod tests {
.collect();
bid.blob_kzg_commitments = VariableList::new(commitments).unwrap();
let result = verify_bid_consistency::<E>(&bid, current_slot, &prefs, &state, &spec);
let result = verify_bid_consistency::<E>(
ExecutionPayloadBidRef::Gloas(&bid),
current_slot,
&prefs,
&state,
&spec,
);
assert!(matches!(
result,
Err(PayloadBidError::InvalidBlobKzgCommitments { .. })
@@ -388,7 +401,13 @@ mod tests {
let bid = make_bid(current_slot, Address::ZERO, 30_000_000);
let prefs = make_preferences(Address::ZERO, 50_000_000);
let result = verify_bid_consistency::<E>(&bid, current_slot, &prefs, &state, &spec);
let result = verify_bid_consistency::<E>(
ExecutionPayloadBidRef::Gloas(&bid),
current_slot,
&prefs,
&state,
&spec,
);
assert!(matches!(result, Err(PayloadBidError::InvalidGasLimit)));
}
}

View File

@@ -7,7 +7,7 @@ use crate::{
BeaconChainTypes, payload_bid_verification::gossip_verified_bid::GossipVerifiedPayloadBid,
};
use parking_lot::RwLock;
use types::{BuilderIndex, ExecutionBlockHash, Hash256, SignedExecutionPayloadBidGloas, Slot};
use types::{BuilderIndex, ExecutionBlockHash, Hash256, SignedExecutionPayloadBid, Slot};
type HighestBidMap<T> =
BTreeMap<Slot, HashMap<(ExecutionBlockHash, Hash256), GossipVerifiedPayloadBid<T>>>;
@@ -27,38 +27,35 @@ impl<T: BeaconChainTypes> Default for GossipVerifiedPayloadBidCache<T> {
}
impl<T: BeaconChainTypes> GossipVerifiedPayloadBidCache<T> {
/// Get the cached bid for the tuple `(slot, parent_block_hash, parent_block_root)`.
pub fn get_highest_bid(
&self,
slot: Slot,
parent_block_hash: ExecutionBlockHash,
parent_block_root: Hash256,
) -> Option<Arc<SignedExecutionPayloadBidGloas<T::EthSpec>>> {
) -> Option<Arc<SignedExecutionPayloadBid<T::EthSpec>>> {
self.highest_bid.read().get(&slot).and_then(|map| {
map.get(&(parent_block_hash, parent_block_root))
.map(|b| b.signed_bid.clone())
})
}
/// Insert a bid for the tuple `(slot, parent_block_hash, parent_block_root)` only if
/// its value is higher than the currently cached bid for that tuple.
pub fn insert_highest_bid(&self, bid: GossipVerifiedPayloadBid<T>) {
let key = (
bid.signed_bid.message.parent_block_hash,
bid.signed_bid.message.parent_block_root,
);
let bid_msg = bid.signed_bid.message();
let key = (bid_msg.parent_block_hash(), bid_msg.parent_block_root());
let slot = bid_msg.slot();
let value = bid_msg.value();
let mut highest_bid = self.highest_bid.write();
let slot_map = highest_bid.entry(bid.signed_bid.message.slot).or_default();
let slot_map = highest_bid.entry(slot).or_default();
if let Some(existing) = slot_map.get(&key)
&& existing.signed_bid.message.value >= bid.signed_bid.message.value
&& existing.signed_bid.message().value() >= value
{
return;
}
slot_map.insert(key, bid);
}
/// A gossip verified bid for `BuilderIndex` already exists at `slot`
pub fn seen_builder_index(&self, slot: &Slot, builder_index: BuilderIndex) -> bool {
self.seen_builder
.read()
@@ -66,16 +63,15 @@ impl<T: BeaconChainTypes> GossipVerifiedPayloadBidCache<T> {
.is_some_and(|seen_builders| seen_builders.contains(&builder_index))
}
/// Insert a builder into the seen cache.
pub fn insert_seen_builder(&self, bid: &GossipVerifiedPayloadBid<T>) {
let bid_msg = bid.signed_bid.message();
let mut seen_builder = self.seen_builder.write();
seen_builder
.entry(bid.signed_bid.message.slot)
.entry(bid_msg.slot())
.or_default()
.insert(bid.signed_bid.message.builder_index);
.insert(bid_msg.builder_index());
}
/// Prune anything before `current_slot`
pub fn prune(&self, current_slot: Slot) {
self.highest_bid
.write()
@@ -94,7 +90,7 @@ mod tests {
use bls::Signature;
use types::{
ExecutionBlockHash, ExecutionPayloadBidGloas, Hash256, MinimalEthSpec,
SignedExecutionPayloadBidGloas, Slot,
SignedExecutionPayloadBid, Slot,
};
use super::GossipVerifiedPayloadBidCache;
@@ -114,17 +110,19 @@ mod tests {
value: u64,
) -> GossipVerifiedPayloadBid<T> {
GossipVerifiedPayloadBid {
signed_bid: Arc::new(SignedExecutionPayloadBidGloas {
message: ExecutionPayloadBidGloas {
slot,
builder_index,
parent_block_hash,
parent_block_root,
value,
..ExecutionPayloadBidGloas::default()
signed_bid: Arc::new(SignedExecutionPayloadBid::Gloas(
types::SignedExecutionPayloadBidGloas {
message: ExecutionPayloadBidGloas {
slot,
builder_index,
parent_block_hash,
parent_block_root,
value,
..ExecutionPayloadBidGloas::default()
},
signature: Signature::empty(),
},
signature: Signature::empty(),
}),
)),
}
}
@@ -142,12 +140,10 @@ mod tests {
cache.prune(Slot::new(8));
// Slots 1-7 pruned from both maps.
for slot in [1, 2, 3, 7] {
assert!(cache.get_highest_bid(Slot::new(slot), hash, root).is_none());
assert!(!cache.seen_builder_index(&Slot::new(slot), slot));
}
// Slots 8-10 retained in both maps.
for slot in [8, 9, 10] {
assert!(cache.get_highest_bid(Slot::new(slot), hash, root).is_some());
assert!(cache.seen_builder_index(&Slot::new(slot), slot));

View File

@@ -15,7 +15,8 @@ use store::{HotColdDB, StoreConfig};
use types::{
Address, ChainSpec, Checkpoint, Domain, Epoch, EthSpec, ExecutionBlockHash,
ExecutionPayloadBidGloas, Hash256, MinimalEthSpec, ProposerPreferences, SignedBeaconBlock,
SignedExecutionPayloadBidGloas, SignedProposerPreferences, SignedRoot, Slot,
SignedExecutionPayloadBid, SignedExecutionPayloadBidGloas, SignedProposerPreferences,
SignedRoot, Slot,
};
use proto_array::{Block as ProtoBlock, ExecutionStatus, PayloadStatus};
@@ -154,7 +155,7 @@ impl TestContext {
}
}
fn sign_bid(&self, bid: ExecutionPayloadBidGloas<E>) -> Arc<SignedExecutionPayloadBidGloas<E>> {
fn sign_bid(&self, bid: ExecutionPayloadBidGloas<E>) -> Arc<SignedExecutionPayloadBid<E>> {
let head = self.canonical_head.cached_head();
let state = &head.snapshot.beacon_state;
let domain = self.spec.get_domain(
@@ -165,10 +166,10 @@ impl TestContext {
);
let message = bid.signing_root(domain);
let signature = self.keypairs[bid.builder_index as usize].sk.sign(message);
Arc::new(SignedExecutionPayloadBidGloas {
Arc::new(SignedExecutionPayloadBid::Gloas(SignedExecutionPayloadBidGloas {
message: bid,
signature,
})
}))
}
fn gossip_ctx(&self) -> GossipVerificationContext<'_, T> {
@@ -229,19 +230,21 @@ fn make_signed_bid(
gas_limit: u64,
value: u64,
parent_block_root: Hash256,
) -> Arc<SignedExecutionPayloadBidGloas<E>> {
Arc::new(SignedExecutionPayloadBidGloas {
message: ExecutionPayloadBidGloas {
slot,
builder_index,
fee_recipient,
gas_limit,
value,
parent_block_root,
..ExecutionPayloadBidGloas::default()
) -> Arc<SignedExecutionPayloadBid<E>> {
Arc::new(SignedExecutionPayloadBid::Gloas(
SignedExecutionPayloadBidGloas {
message: ExecutionPayloadBidGloas {
slot,
builder_index,
fee_recipient,
gas_limit,
value,
parent_block_root,
..ExecutionPayloadBidGloas::default()
},
signature: Signature::empty(),
},
signature: Signature::empty(),
})
))
}
fn make_signed_preferences(
@@ -420,7 +423,7 @@ fn execution_payment_nonzero() {
let slot = Slot::new(0);
seed_preferences(&ctx, slot, Address::ZERO, 30_000_000);
let bid = Arc::new(SignedExecutionPayloadBidGloas {
let bid = Arc::new(SignedExecutionPayloadBid::Gloas(SignedExecutionPayloadBidGloas {
message: ExecutionPayloadBidGloas {
slot,
gas_limit: 30_000_000,
@@ -429,7 +432,7 @@ fn execution_payment_nonzero() {
..ExecutionPayloadBidGloas::default()
},
signature: Signature::empty(),
});
}));
let result = GossipVerifiedPayloadBid::new(bid, &gossip);
assert!(matches!(
result,
@@ -576,7 +579,7 @@ fn invalid_blob_kzg_commitments() {
.map(|_| KzgCommitment::empty_for_testing())
.collect();
let bid = Arc::new(SignedExecutionPayloadBidGloas {
let bid = Arc::new(SignedExecutionPayloadBid::Gloas(SignedExecutionPayloadBidGloas {
message: ExecutionPayloadBidGloas {
slot,
builder_index: 0,
@@ -588,7 +591,7 @@ fn invalid_blob_kzg_commitments() {
..ExecutionPayloadBidGloas::default()
},
signature: Signature::empty(),
});
}));
let result = GossipVerifiedPayloadBid::new(bid, &gossip);
assert!(matches!(
result,
@@ -703,8 +706,8 @@ fn two_builders_coexist_in_cache() {
.bid_cache
.get_highest_bid(slot, ExecutionBlockHash::zero(), ctx.genesis_block_root)
.expect("should have highest bid");
assert_eq!(highest.message.value, 1);
assert_eq!(highest.message.builder_index, 1);
assert_eq!(highest.message().value(), 1);
assert_eq!(highest.message().builder_index(), 1);
}
#[test]

View File

@@ -97,11 +97,11 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
// Per spec: record_payload_inclusion_list_satisfaction after payload verification.
// Call the EL to check if the payload satisfies the aggregated IL constraints.
if let ExecutedEnvelope::Available(ref envelope) = executed_envelope {
if chain_ref
if let ExecutedEnvelope::Available(ref envelope) = executed_envelope
&& chain_ref
.spec
.is_focil_enabled_for_epoch(block_slot.epoch(T::EthSpec::slots_per_epoch()))
{
{
let payload_block_hash = envelope.envelope.message().payload.block_hash;
let il_slot = block_slot.saturating_sub(1_u64);
let il_txs = chain_ref
@@ -129,7 +129,6 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
);
}
}
}
}
match executed_envelope {