Compare commits

...

7 Commits

Author SHA1 Message Date
Josh King
aa6fdb8d6a fix: tighten genesis block fallback to match empty body root only 2026-04-30 17:28:09 +02:00
jking-aus
6177213a3d Merge pull request #9246 from jking-aus/fix-ef-tests-genesis-block
fix: restore genesis_block bid population for ef-tests and add fallback for external genesis for kurtosis
2026-04-30 17:02:50 +02:00
Josh King
22a207ffa8 fix: fallback to empty genesis block for external genesis states 2026-04-30 15:26:20 +02:00
Josh King
98d858d942 fix: restore genesis_block bid population for ef-tests
The alpha-7 spec tests expect the Gloas genesis block body to contain
the execution payload bid from state. Restores the genesis_block()
function and body_root fixup that were removed in PR #9244.

The fork choice from_anchor fix (reading latest_block_hash when bid
hashes are zero) remains for Kurtosis/external genesis compatibility.
2026-04-30 14:21:02 +02:00
Eitan Seri-Levi
0fe75382da fmt 2026-04-30 13:05:30 +02:00
hopinheimer
5360e76696 fix genesis_block init in tests 2026-04-30 12:52:17 +02:00
Josh King
0078b6be89 fix: gloas from genesis
- Fix forkchoice update sending zero-hash head to EL at genesis by reading
  latest_block_hash from state when the genesis bid hashes are all zeros
- Simplify genesis block construction — the genesis block body is empty per
  spec, remove the incorrect bid-copying logic and body root override in
  initialize_beacon_state_from_eth1
2026-04-30 12:52:01 +02:00
2 changed files with 30 additions and 5 deletions

View File

@@ -46,8 +46,8 @@ use tracing::{debug, error, info, warn};
use tree_hash::TreeHash;
use types::data::CustodyIndex;
use types::{
BeaconState, BlobSidecarList, ChainSpec, ColumnIndex, DataColumnSidecarList, Epoch, EthSpec,
Hash256, SignedBeaconBlock, Slot,
BeaconBlock, BeaconState, BlobSidecarList, ChainSpec, ColumnIndex, DataColumnSidecarList,
Epoch, EthSpec, Hash256, SignedBeaconBlock, Slot,
};
/// An empty struct used to "witness" all the `BeaconChainTypes` traits. It has no user-facing
@@ -1177,9 +1177,21 @@ fn make_genesis_block<E: EthSpec>(
genesis_state: &mut BeaconState<E>,
spec: &ChainSpec,
) -> Result<SignedBeaconBlock<E>, String> {
// For Gloas, genesis_block() populates the bid in the block body. However, if
// the genesis state was produced by an external tool (e.g. ethereum-genesis-generator),
// its latest_block_header.body_root may correspond to an empty block. In that case,
// use an empty block so the stored block root matches what fork choice derives from
// the state's latest_block_header.
let mut block = genesis_block(genesis_state, spec)
.map_err(|e| format!("Error building genesis block: {:?}", e))?;
let state_body_root = genesis_state.latest_block_header().body_root;
if state_body_root != block.body_root()
&& state_body_root == BeaconBlock::<E>::empty(spec).body_root()
{
block = BeaconBlock::empty(spec);
}
*block.state_root_mut() = genesis_state
.update_tree_hash_cache()
.map_err(|e| format!("Error hashing genesis state: {:?}", e))?;

View File

@@ -416,11 +416,24 @@ where
let (execution_status, execution_payload_parent_hash, execution_payload_block_hash) =
if let Ok(signed_bid) = anchor_block.message().body().signed_execution_payload_bid() {
// Gloas: execution status is irrelevant post-Gloas; payload validation
// is decoupled from beacon blocks.
// At Gloas genesis the block bid is empty (all zeros) per spec, but the
// state holds the EL genesis hash in `latest_block_hash`. Use it so the
// first forkchoice update sends a valid head to the EL.
let parent_hash = if anchor_block.slot() == spec.genesis_slot
&& anchor_state.slot() == spec.genesis_slot
&& signed_bid.message.parent_block_hash.into_root().is_zero()
&& signed_bid.message.block_hash.into_root().is_zero()
{
*anchor_state
.latest_block_hash()
.map_err(Error::BeaconStateError)?
} else {
signed_bid.message.parent_block_hash
};
(
ExecutionStatus::irrelevant(),
Some(signed_bid.message.parent_block_hash),
Some(parent_hash),
Some(signed_bid.message.block_hash),
)
} else if let Ok(execution_payload) = anchor_block.message().execution_payload() {