# ePBS / Gloas: Beacon Root Gaps in EIP-4788 ## Status quo In EIP-4788, the beacon root contract is updated during execution of an execution payload. Under normal (pre-ePBS) conditions: - Every slot has both: - a beacon block `B` - an execution payload `E` - Each payload inserts the **previous beacon root** - As a result, **all beacon roots appear on chain with a 1-slot delay** ### Example (normal operation) ``` Slot: 0 1 2 3 4 5 Beacon: B0 B1 B2 - B4 B5 Execution: E0 E1 E2 - E4 E5 Inserted: B0 B1 - B2 B4 ``` So effectively: - continuous coverage (no gaps) --- ## What changes with ePBS / Gloas With ePBS, some slots may **not include an execution payload**. When that happens: - no contract update occurs in that slot - the chain of insertions is broken ### Example ``` Slot: 0 1 2 3 4 5 Beacon: B0 B1 B2 B3 B4 B5 Execution: E0 E1 - - E4 E5 Inserted: B0 - - B3 B4 Roots available on chain: B0, B3, B4, ... Missing: B1, B2 ``` Insertions: - `E1` inserts `B0` root - no `E2` → `B1` not inserted - no `E3` → `B2` not inserted - `E4` inserts `B3` - `E5` inserts `B4` More generally: > Any missed payload creates a gap in the on-chain beacon root history. --- ## Why this matters Applications using EIP-4788 implicitly rely on: - continuous beacon root availability - ability to proove any operation within beacon blocks (withdrawals, slashings, etc.) With ePBS: - some roots never appear on chain - proofs involving those blocks require: - additional parent-root traversal (+3 hashes per parent block, or +22 hases static by proving through the state/parent_roots list) - larger witnesses This mainly affects: - protocols verifying operations included in beacon block (withdrawals, deposits, slashings, ...) - any contract assuming dense root availability --- ## Options forward ### 1. Do nothing Accept gaps and shift responsibility to applications. - Missing roots are reconstructed via parent traversal - Proofs become larger (extra hashes per missing slot, or large static overhead) --- ### 2. Insert root of last block with payload instead of direct parent When execution resumes after skipped slots, insert the root of the last block with a payload. Example: ``` Slot: 0 1 2 3 4 5 Beacon: B0 B1 B2 B3 B4 B5 Execution: E0 E1 - - E4 E5 Inserted: B0 - - B1 B4 ``` - All beacon blocks with execution payloads are available on-chain - Still leaves gaps for empty beacon blocks --- ### 3. Backfill all missed roots When execution resumes, insert all missing roots: ``` Slot: 0 1 2 3 4 5 Beacon: B0 B1 B2 B3 B4 B5 Execution: E0 E1 - - E4 E5 Inserted: B0 - - B1-3 B4 ``` - Requires passing multiple `(timestamp, root)` pairs - Requires multiple execution frames with the block timestamps of missed payloads for inserting the missed roots (system contract limitation) --- ### 4. Backfill all missed roots & batch insert to a new system contract Modify the system contract to accept a list of roots instead of only a single one: ``` [(ts0, R0), (ts1, R1), (ts2, R2)] ``` - Simplifies insertion logic - Breaks existing contract interface assumptions (new contract address) --- ## Core issue The key question is: > Should EIP-4788 guarantee continuous, gap-free beacon root availability on chain, or is partial availability acceptable with reconstruction pushed to the application layer?