How to EIP-4788

Dmitry Chernukhin, CSM Team Contributor from the liquid staking protocol Lido.

Automatically translated by AI

About CSM

CSM — Community Staking Module — is a community staking module. Its purpose is to allow community members to become stakers and join node operators currently in the Lido set. This is designed to attract a small amount of ETH into the protocol, with the remaining ETH (up to the 32 ETH required) deposited to the validator used by the staker. This way, a staker can run a validator with a smaller ETH amount and take part in network decentralization.

Talk topics

  • Does EIP-4788 make Ethereum more secure, cheaper, and faster?
  • How does EIP-4788 replace oracles?
  • What is a ring buffer and why is it needed?
  • How does EIP-4788 impact liquid staking and restaking protocols?

EIP-4788

The EIP-4788 update, titled Beacon Block Root in the EVM, was highly anticipated by the community and was even called revolutionary because it brings various use cases for different liquid staking protocols.

1

Although the Merge has happened and we now have the Consensus and Execution layers, for smart contracts they are still two separate entities. Since a smart contract lives on the Execution layer, it knows almost nothing about the Consensus layer — there is no communication channel between them. The only way to pass information is via ETH transfers. When a validator is created on the Consensus layer by depositing from the Execution layer, ETH is sent to the Consensus layer, from where it can later be withdrawn in the event of a full or partial validator exit. In that case, ETH is sent back to the Execution layer. Thus, the communication format is limited to sending ETH — a unit of data.

2

Block Root

EIP-4788 adds an additional channel — "Block Roots" — so the Consensus layer now pushes block roots it creates into the Execution layer. This establishes a new communication channel between the Consensus and Execution layers.

3

Block Roots are pushed into a dedicated smart contract called the Block Roots contract at a fixed address:
0x000F3df6D732807Ef1319fB7B8bB8522d0Beac02. The Consensus layer adds roots to it via a special system transaction. For the end PoS system, it works as follows:

  1. A timestamp from a specific slot on the Consensus layer is chosen.
  2. This timestamp is sent to the smart contract on the Execution layer.
  3. In return, the Block Root corresponding to that timestamp is returned and becomes available.

4

Block Roots can be used to build inclusion proofs for specific data included in a Beacon Block. To understand inclusion proofs, consider an airdrop: when an address is entitled to claim tokens from a contract.

The standard approach is to gather a list of addresses included in the airdrop. From this list, a Merkle tree is built — a binary tree whose nodes are hashed pairwise until only one hash remains, called the Root Hash (sum of all list hashes). This root is stored in the airdrop contract.

5

To prove that an address is on the list, you must pass the proof — the required hash obtained by pairwise hashing of specific tree nodes — to the smart contract.

6

If this hash matches the root stored in the contract by its developers, it proves the address is indeed eligible to receive the airdrop tokens.

Beacon structures

This works with EIP-4788 because Beacon structures, such as the Beacon Block, are also Merkle trees. Their representation method is called merkleization. This is essentially what’s stored in the Consensus layer. Merkleization builds a tree from actual data structures, and the root of this tree is the Beacon Block Root, now available on the current layer.

7

A Beacon Block contains a state_root, which is the root of another structure called the Beacon state. This state root stores all additional information, and the Beacon Block Root is effectively a commitment to everything contained in the Beacon state at a given time.

8

However, having only the state_root is not enough to provide proofs. A Generalized index is also needed — an index of the node in the tree that mathematically specifies the exact path to the required address in the structure. This index is built as follows: the root node is assigned the value 1 in binary form, meaning each node can have a maximum of two children. A left turn adds "0" to the path, and a right turn adds "1". The result is a binary number. The contract reads these 0s and 1s to navigate the tree and verify the correct branch.

9

An alternative algorithm starts at 1 at the root. A left turn multiplies the index by 2. A right turn multiplies it by 2 and adds 1.

10

Applications of EIP-4788

This approach to staking pools and restaking allows delivering fully verifiable validator state information via proofs. Any validator state can now be proven throughout its lifecycle.

11

Limitations of EIP-4788

Gas cost

Proving a single validator state with EIP-4788 requires about 100,000 gas. Proving the states of many validators (e.g., 300,000) would require enormous ETH. Direct proofs via EIP-4788 are inefficient in such cases. Currently, Trusted Oracles or ZKP Solutions are better suited here, using EIP-4788 as an additional input for more efficient solutions.

27 hours

Another issue is that Block Roots are not stored on the Execution layer for the entire history — because there’s no need to query them all. Developers opted for a different approach: a 27-hour window during which Block Roots are available. This means a transaction must be included within that time for the proof’s Beacon Block Root to still be present in the contract and ensure success.

For older block data, historical accumulators in Beacon structures are used. The Beacon state stores several accumulators — historical roots and historical summaries. They store lists of past Block Roots and State Roots. Using them, you can access older data for proofs.

The proof is built against an available Beacon Block Root, which accesses the historical accumulator to retrieve an old root, attach it to the Beacon state structure, and access the desired field or data from the old block.

12

Generalized indices source

Currently, the Execution layer has no decentralized source for obtaining generalized indices for various structures. Developers must decide how to provide these indices for their app. The simplest approach is to hardcode them, mapping specific fields to specific indices. But generalized indices can change between hard forks due to structural changes in Merkle trees.

For example, if the second field’s index is 5, but after a fork a new field is added, the number of leaves changes to the next power of two, making the tree taller and shifting the index — the field may now be under index 9. This must be considered, or proofs may break or lead to vulnerabilities.

13

Parent Block Root

The Block Root Contract in EIP-4788 stores the parent block root. This is because a block cannot include its own root — adding the root changes the block root itself, breaking closure.

Thus, it stores the previous block’s root. But Consensus layer slots can be skipped, so a timestamp query may return the root of an earlier block. On-chain, you cannot definitively match a Block Root to a specific slot by timestamp. Apps depending on precise mapping must use other approaches, like recalculating structures on-chain.

14

Ring buffer

A cyclic ring buffer means the Execution layer always has the last 8,191 block roots available. It’s just a storage stack: when full, the oldest root is removed when a new one is added. This ensures the stack always contains the most recent 8,191 block roots.

Link to a GitHub project showing how proof generation works in JavaScript and how it’s implemented in smart contracts. The repo contains Solidity code that verifies proofs.

15

Read more

More Events