Merge branch 'unstable' of https://github.com/sigp/lighthouse into gloas-payload-cache

This commit is contained in:
Eitan Seri-Levi
2026-05-01 02:22:42 +02:00
22 changed files with 458 additions and 118 deletions

View File

@@ -64,7 +64,7 @@ impl GossipVerifiedProposerPreferences {
ctx: &GossipVerificationContext<'_, T>,
) -> Result<Self, ProposerPreferencesError> {
let proposal_slot = signed_preferences.message.proposal_slot;
let checkpoint_root = signed_preferences.message.checkpoint_root;
let dependent_root = signed_preferences.message.dependent_root;
let validator_index = signed_preferences.message.validator_index;
let cached_head = ctx.canonical_head.cached_head();
let current_slot = ctx
@@ -75,7 +75,7 @@ impl GossipVerifiedProposerPreferences {
if ctx
.gossip_verified_proposer_preferences_cache
.get_seen_validator(&proposal_slot, checkpoint_root, validator_index)
.get_seen_validator(&proposal_slot, dependent_root, validator_index)
{
return Err(ProposerPreferencesError::AlreadySeen {
validator_index,
@@ -163,7 +163,7 @@ mod tests {
fn make_preferences(proposal_slot: Slot, validator_index: u64) -> ProposerPreferences {
ProposerPreferences {
checkpoint_root: types::Hash256::ZERO,
dependent_root: types::Hash256::ZERO,
proposal_slot,
validator_index,
fee_recipient: Address::ZERO,

View File

@@ -37,24 +37,24 @@ impl GossipVerifiedProposerPreferenceCache {
pub fn get_seen_validator(
&self,
slot: &Slot,
checkpoint_root: Hash256,
dependent_root: Hash256,
validator_index: u64,
) -> bool {
self.seen
.read()
.get(slot)
.is_some_and(|seen| seen.contains(&(checkpoint_root, validator_index)))
.is_some_and(|seen| seen.contains(&(dependent_root, validator_index)))
}
pub fn insert_seen_validator(&self, preferences: &GossipVerifiedProposerPreferences) {
let slot = preferences.signed_preferences.message.proposal_slot;
let checkpoint_root = preferences.signed_preferences.message.checkpoint_root;
let dependent_root = preferences.signed_preferences.message.dependent_root;
let validator_index = preferences.signed_preferences.message.validator_index;
self.seen
.write()
.entry(slot)
.or_default()
.insert((checkpoint_root, validator_index));
.insert((dependent_root, validator_index));
}
pub fn prune(&self, current_slot: Slot) {

View File

@@ -256,6 +256,41 @@ fn validator_index_out_of_bounds() {
));
}
/// Same (slot, validator_index) but different dependent_root should NOT be deduplicated.
#[test]
fn same_validator_different_dependent_root_not_deduplicated() {
if !fork_name_from_env().is_some_and(|f| f.gloas_enabled()) {
return;
}
let ctx = TestContext::new();
let slot = Slot::new(1);
let verified_a = GossipVerifiedProposerPreferences {
signed_preferences: Arc::new(SignedProposerPreferences {
message: ProposerPreferences {
proposal_slot: slot,
validator_index: 42,
dependent_root: Hash256::repeat_byte(0xaa),
fee_recipient: Address::ZERO,
gas_limit: 30_000_000,
},
signature: Signature::empty(),
}),
};
ctx.preferences_cache.insert_seen_validator(&verified_a);
// Different dependent_root — should not be seen.
assert!(
!ctx.preferences_cache
.get_seen_validator(&slot, Hash256::repeat_byte(0xbb), 42,)
);
// Same dependent_root — should be seen.
assert!(
ctx.preferences_cache
.get_seen_validator(&slot, Hash256::repeat_byte(0xaa), 42,)
);
}
// TODO(gloas) add successful proposer preferences check once we have proposer preferences signing logic
#[test]

View File

@@ -1017,6 +1017,28 @@ where
assert_ne!(slot, 0, "can't produce a block at slot 0");
assert!(slot >= state.slot());
// For Gloas, blinded and full blocks are structurally identical (no payload in body).
// Produce via the Gloas path and convert to blinded.
if self.spec.fork_name_at_slot::<E>(slot).gloas_enabled() {
let (block_contents, _envelope, pending_state) =
Box::pin(self.make_block_with_envelope(state, slot)).await;
let (signed_block, _blobs) = block_contents;
let signed_blinded = signed_block.clone_as_blinded();
let (mut blinded_block, _signature) = signed_blinded.deconstruct();
block_modifier(&mut blinded_block);
let proposer_index = pending_state
.get_beacon_proposer_index(slot, &self.spec)
.unwrap();
// Re-sign after modification.
let signed_blinded = blinded_block.sign(
&self.validator_keypairs[proposer_index].sk,
&pending_state.fork(),
pending_state.genesis_validators_root(),
&self.spec,
);
return (signed_blinded, pending_state);
}
complete_state_advance(&mut state, None, slot, &self.spec)
.expect("should be able to advance state to slot");
@@ -1238,6 +1260,21 @@ where
assert_ne!(slot, 0, "can't produce a block at slot 0");
assert!(slot >= state.slot());
// For Gloas forks, delegate to make_block_with_envelope which uses the
// Gloas-specific block production path, and return the pre-state.
if self.spec.fork_name_at_slot::<E>(slot).gloas_enabled() {
let pre_state = {
let mut s = state.clone();
complete_state_advance(&mut s, None, slot, &self.spec)
.expect("should be able to advance state to slot");
s.build_caches(&self.spec).expect("should build caches");
s
};
let (block_contents, _envelope, _state) =
Box::pin(self.make_block_with_envelope(state, slot)).await;
return (block_contents, pre_state);
}
complete_state_advance(&mut state, None, slot, &self.spec)
.expect("should be able to advance state to slot");