Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
09a8573
enable re-orgs and post-gloas re-orgs tests
hopinheimer Jun 2, 2026
fc8b5ea
Merge branch 'unstable' of github.com:sigp/lighthouse into re-enable-…
hopinheimer Jun 2, 2026
9f3499b
fix merge changes
hopinheimer Jun 2, 2026
1ffe508
working interactive tests
hopinheimer Jun 3, 2026
5d35329
fix `parent_payload_status` in block production state
hopinheimer Jun 4, 2026
0af1503
Merge branch 'unstable' of github.com:sigp/lighthouse into re-enable-…
hopinheimer Jun 4, 2026
fc2753c
Use canonical payload status in reorg helper
michaelsproul Jun 4, 2026
ad16845
WIP gloas reorg tests
michaelsproul Jun 4, 2026
76eb7ab
BeaconChainHarness support for payload attestation messages
michaelsproul Jun 4, 2026
21bb53f
WIP
michaelsproul Jun 4, 2026
d829d37
Fix prepare payload lookahead
michaelsproul Jun 4, 2026
79b4f76
Harder test case
michaelsproul Jun 4, 2026
8096b65
Three variants of test (but they use natural reorgs)
michaelsproul Jun 4, 2026
0d15b05
Allow setting parent payload status
michaelsproul Jun 4, 2026
43cf850
Just use parent payload status!
michaelsproul Jun 4, 2026
7162a30
Don't swallow payload load errors
michaelsproul Jun 4, 2026
7f21431
empty parent `proposer-re-org-test` added
hopinheimer Jun 10, 2026
8e9b59a
Merge branch 'unstable' of github.com:sigp/lighthouse into re-enable-…
hopinheimer Jun 10, 2026
8ace75d
linty happy
hopinheimer Jun 15, 2026
b09e65a
Merge branch 'unstable' of github.com:sigp/lighthouse into re-enable-…
hopinheimer Jun 15, 2026
3b768f4
linty linty happy
hopinheimer Jun 15, 2026
e45599e
my bad
hopinheimer Jun 15, 2026
83b89f4
lint
hopinheimer Jun 15, 2026
d6473e0
Merge remote-tracking branch 'origin/unstable' into re-enable-re-orgs
michaelsproul Jun 16, 2026
a573289
Revert overridden fork choice changes
michaelsproul Jun 16, 2026
c1d1554
Disable overriding fork choice update for Gloas
michaelsproul Jun 16, 2026
7401697
Revert changes to should_extend_payload
michaelsproul Jun 16, 2026
557bb9b
Fix payload attestation tests for latest spec
michaelsproul Jun 16, 2026
759d83e
Remove TODO
michaelsproul Jun 16, 2026
1d728cf
Codex test fix (needs review)
michaelsproul Jun 16, 2026
2119829
Fork gate interactive_tests to run pre-gloas forks only.
hopinheimer Jun 17, 2026
239fbc5
Merge branch 'unstable' of github.com:sigp/lighthouse into re-enable-…
hopinheimer Jun 17, 2026
8527b76
Fix overlapping sync committee bug in testing harness
hopinheimer Jun 18, 2026
bc2bcd5
Lint
hopinheimer Jun 18, 2026
0d461cb
Addressing comments
hopinheimer Jun 18, 2026
082f325
Use test_spec in `proposer_reorg_test`
hopinheimer Jun 18, 2026
0f9601c
Use test_spec in Gloas tests so we run on future forks
michaelsproul Jun 18, 2026
59443c8
Merge of #9405
mergify[bot] Jun 18, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 15 additions & 6 deletions beacon_node/beacon_chain/src/beacon_chain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5138,7 +5138,6 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
})
}

// TODO(gloas): wrong for Gloas, needs an update
pub fn overridden_forkchoice_update_params_or_failure_reason(
&self,
canonical_forkchoice_params: &ForkchoiceUpdateParameters,
Expand Down Expand Up @@ -5169,6 +5168,11 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
)
.map_err(|e| e.map_inner_error(Error::ProposerHeadForkChoiceError))?;

// We don't need to override fork choice updates for Gloas.
if info.head_node.is_gloas() {
return Ok(*canonical_forkchoice_params);
}

// The slot of our potential re-org block is always 1 greater than the head block because we
// only attempt single-slot re-orgs.
let head_slot = info.head_node.slot();
Expand Down Expand Up @@ -5302,9 +5306,7 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
return Err(Box::new(DoNotReOrg::NotProposing.into()));
}

// TODO(gloas): V29 nodes don't carry execution_status, so this returns
// None for post-Gloas re-orgs. Need to source the EL block hash from
// the bid's block_hash instead. Re-org is disabled for Gloas for now.
// This only works pre-Gloas, but we don't run this code for Gloas anyway.
let parent_head_hash = info
.parent_node
.execution_status()
Expand Down Expand Up @@ -6341,8 +6343,15 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
}

let canonical_fcu_params = cached_head.forkchoice_update_parameters();
let fcu_params =
chain.overridden_forkchoice_update_params(canonical_fcu_params)?;
let fcu_params = if chain
.spec
.fork_name_at_slot::<T::EthSpec>(head_slot)
.gloas_enabled()
{
canonical_fcu_params
} else {
chain.overridden_forkchoice_update_params(canonical_fcu_params)?
};
let pre_payload_attributes = chain.get_pre_payload_attributes(
prepare_slot,
fcu_params.head_root,
Expand Down
79 changes: 54 additions & 25 deletions beacon_node/beacon_chain/src/block_production/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use fork_choice::PayloadStatus;
use proto_array::{ProposerHeadError, ReOrgThreshold};
use slot_clock::SlotClock;
use tracing::{debug, error, info, instrument, warn};
use types::{BeaconState, Epoch, Hash256, SignedExecutionPayloadEnvelope, Slot};
use types::{BeaconState, Epoch, EthSpec, Hash256, SignedExecutionPayloadEnvelope, Slot};

use crate::{
BeaconChain, BeaconChainTypes, BlockProductionError, StateSkipConfig,
Expand All @@ -14,13 +14,21 @@ use crate::{
mod gloas;

/// State loaded from the database for block production.
pub(crate) struct BlockProductionState<E: types::EthSpec> {
pub(crate) struct BlockProductionState<E: EthSpec> {
pub state: BeaconState<E>,
pub state_root: Option<Hash256>,
pub parent_payload_status: PayloadStatus,
pub parent_envelope: Option<Arc<SignedExecutionPayloadEnvelope<E>>>,
}

/// Inputs assembled for producing a block via a proposer re-org.
struct ReOrgInputs<E: EthSpec> {
state: BeaconState<E>,
state_root: Hash256,
parent_payload_status: PayloadStatus,
parent_envelope: Option<Arc<SignedExecutionPayloadEnvelope<E>>>,
}

impl<T: BeaconChainTypes> BeaconChain<T> {
/// Load a beacon state from the database for block production. This is a long-running process
/// that should not be performed in an `async` context.
Expand Down Expand Up @@ -50,39 +58,32 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
head.snapshot.execution_envelope.clone(),
)
};

let result = if head_slot < slot {
// Attempt an aggressive re-org if configured and the conditions are right.
// TODO(gloas): re-enable reorgs
let gloas_enabled = self
.spec
.fork_name_at_slot::<T::EthSpec>(slot)
.gloas_enabled();
if !gloas_enabled
&& let Some((re_org_state, re_org_state_root)) =
self.get_state_for_re_org(slot, head_slot, head_block_root)
{
if let Some(inputs) = self.get_state_for_re_org(slot, head_slot, head_block_root) {
info!(
%slot,
head_to_reorg = %head_block_root,
"Proposing block to re-org current head"
);
// TODO(gloas): ensure we use a sensible payload status when we enable reorgs
// for Gloas
BlockProductionState {
state: re_org_state,
state_root: Some(re_org_state_root),
parent_payload_status: PayloadStatus::Pending,
parent_envelope: None,
state: inputs.state,
state_root: Some(inputs.state_root),
parent_payload_status: inputs.parent_payload_status,
parent_envelope: inputs.parent_envelope,
}
} else {
// Fetch the head state advanced through to `slot`, which should be present in the
// state cache thanks to the state advance timer.
// Continuation: the new block builds on the current head. Fetch the head state
// advanced through to `slot`, which should be present in the state cache thanks to
// the state advance timer.
let parent_state_root = head_state_root;
let (state_root, state) = self
.store
.get_advanced_hot_state(head_block_root, slot, parent_state_root)
.map_err(BlockProductionError::FailedToLoadState)?
.ok_or(BlockProductionError::UnableToProduceAtSlot(slot))?;

BlockProductionState {
state,
state_root: Some(state_root),
Expand All @@ -100,13 +101,11 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
.state_at_slot(slot - 1, StateSkipConfig::WithStateRoots)
.map_err(|_| BlockProductionError::UnableToProduceAtSlot(slot))?;

// TODO(gloas): update this to read payload canonicity from fork choice once ready
let parent_payload_status = PayloadStatus::Pending;
BlockProductionState {
state,
state_root: None,
parent_payload_status,
parent_envelope: None,
parent_payload_status: head_payload_status,
parent_envelope: head_envelope,
}
};

Expand Down Expand Up @@ -173,7 +172,7 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
slot: Slot,
head_slot: Slot,
canonical_head: Hash256,
) -> Option<(BeaconState<T::EthSpec>, Hash256)> {
) -> Option<ReOrgInputs<T::EthSpec>> {
let re_org_head_threshold = ReOrgThreshold(self.spec.reorg_head_weight_threshold);
let re_org_parent_threshold = ReOrgThreshold(self.spec.reorg_parent_weight_threshold);
let re_org_max_epochs_since_finalization =
Expand Down Expand Up @@ -237,9 +236,15 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
}
})
.ok()?;

drop(proposer_head_timer);
let re_org_parent_block = proposer_head.parent_node.root();

// The head uniquely determines the parent payload status for the re-org block, whichever
// variant (full or empty) it builds on must have more weight, or else we would have already
// re-orged away from this block naturally, and it would not be the head, by definition.
let parent_payload_status = proposer_head.head_node.get_parent_payload_status();

let (state_root, state) = self
.store
.get_advanced_hot_state_from_cache(re_org_parent_block, slot)
Expand All @@ -248,6 +253,25 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
None
})?;

let parent_envelope = if parent_payload_status == PayloadStatus::Full {
let envelope = self
.store
.get_payload_envelope(&re_org_parent_block)
.ok()
.flatten()
.map(Arc::new)
.or_else(|| {
warn!(
reason = "missing execution payload envelope",
"Not attempting re-org"
);
None
})?;
Some(envelope)
} else {
None
};

info!(
weak_head = ?canonical_head,
parent = ?re_org_parent_block,
Expand All @@ -256,6 +280,11 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
"Attempting re-org due to weak head"
);

Some((state, state_root))
Some(ReOrgInputs {
state,
state_root,
parent_payload_status,
parent_envelope,
})
}
}
Loading
Loading