-
-
Published
Linked with GitHub
# proto-eip: beacon state root in the EVM
## Simple Summary
Commit to the state root of the beacon chain in the `ommers` field in the post-merge execution block. Reflect the changes in the `ommersHash` field of the execution block header.
Store each beacon chain state root into a contract and add a new opcode that reads this contract.
## Motivation
Exposing the beacon chain state root allows for proofs about the beacon state to be verified inside the EVM. This functionality supports a wide variety of use cases in smart contracts involving validator status and finality produced by the consensus layer.
In particular, this functionality is required for beacon chain validator withdrawals to the EVM.
## Specification
| constants | value | units
|--- |--- |---
| `FORK_TIMESTAMP` | TBD |
| `FORK_EPOCH` | TBD |
|`OPCODE_VALUE` | `0x48` |
|`G_beacon_state_root` | 20 | gas
| `WINDOW_LENGTH` | 256 | slots
### Background
The method of injecting the beacon state root in this EIP follows the general strategy of [EIP-4399](https://eips.ethereum.org/EIPS/eip-4399) to make a post-merge change to the EVM integrating information from the beacon chain. This EIP along with [EIP-3675](https://eips.ethereum.org/EIPS/eip-3675) should be taken as relevant background to understand the particular approach of this EIP.
The method exposing the state root data is inspired by [EIP-2935](https://eips.ethereum.org/EIPS/eip-2935).
### block structure
beginning with `FORK_BLOCK_NUMBER`, execution clients **MUST**:
1) set the value of the `ommers` field in the block to an RLP list with one element: the 32 byte [hash tree root](https://github.com/ethereum/consensus-specs/blob/dev/ssz/simple-serialize.md#merkleization) of the [beacon state](https://github.com/ethereum/consensus-specs/blob/dev/specs/bellatrix/beacon-chain.md#beaconstate) from the previous slot to this block.
2) set the value of the `ommersHash` field in the block header to the Keccak256 hash of the `ommers` field.
```python
beaconStateRoot = <32 byte value> # provided by consensus client
ommers = RLP([beaconStateRoot]) # in the block body
ommersHash = Keccak256(ommers) # in the block header
```
3. Re-instate the block validation that the `ommersHash` does indeed match the expected committment given the `ommers` value.
### EVM changes
beginning with `FORK_BLOCK_NUMBER`, introduce a new opcode `BEACON_STATE_ROOT` at `OPCODE_VALUE`.
This opcode must return the value of the single element in the `ommers` field of the execution block. This value is set in the EVM execution context before processing a given execution block. The opcode consumes no words from the stack and places one word on the stack. The opcode has a gas cost of `G_beacon_state_root`.
For example, assume the beacon state root at slot 3,000,000 is `0x8ff077430957727dbace82d868a4f514d3720594727deaaafded1ee2e9e486f1`. If processing a transaction that executes `BEACON_STATE_ROOT` at slot 3,000,001, the EVM should place on the stack this value of the state root `0x8ff0...86f1`.
## implementation notes and other considerations
The [Engine API `PayloadAttributes` message](https://github.com/ethereum/execution-apis/blob/main/src/engine/specification.md#payloadattributesv1) will be updated with an additional field to send the relevant beacon state root from the consensus client to the execution client when preparing a block.
This field **MUST** be sent beginning with `FORK_EPOCH` at the consensus layer.
## rationale, notes, etc.
### general strategy
See the rationale for EIP-4399 for discussion about this general strategy of reusing execution block elements for beacon chain data.
### consensus layer validations
The [`ExecutionPayload` and `ExecutionPayloadHeader`](https://github.com/ethereum/consensus-specs/blob/dev/specs/bellatrix/beacon-chain.md#executionpayload) will be updated with a 32 byte field `beacon_state_root` for the relevant beacon state root for the corresponding execution block. This way the beacon state root committed to in the block can be verified against the beacon state root recorded in the beacon chain (e.g. `state.state_roots[state.slot-1]`). A future PR to the `consensus-specs` repo with this change is forthcoming.
### execution layer validations
By including the beacon state root in the execution block in the deprecated `ommers` field, execution clients can still verify the chain in a self-contained way without relying on an available consensus client. This property is important during syncing (and likely other phases of execution node operation).
### minimizing client code change
By including the `ommersHash` validation, clients can use existing code with only minimal changes (supplying the actual state root) during block production and verification.
Having the beacon state root value in the `ommers` field means that it is fairly straightforward to provide the value from the block data to the EVM execution context for client implementations as they stand today.
### gas cost of opcode
the suggested gas cost is just using the value for the `BLOCKHASH` opcode as `BEACON_STATE_ROOT` is an analogous operation.
## acknowledgments
Thanks to Danny Ryan for helpful feedback and discussions.