|
| 1 | +# EIP7594 -- The Beacon Chain |
| 2 | + |
| 3 | +**Notice**: This document is a work-in-progress for researchers and implementers. |
| 4 | + |
| 5 | +## Table of contents |
| 6 | + |
| 7 | +<!-- TOC --> |
| 8 | +<!-- START doctoc generated TOC please keep comment here to allow auto update --> |
| 9 | +<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE --> |
| 10 | + |
| 11 | +- [Introduction](#introduction) |
| 12 | +- [Configuration](#configuration) |
| 13 | + - [Execution](#execution) |
| 14 | + - [Execution payload](#execution-payload) |
| 15 | + - [Modified `process_execution_payload`](#modified-process_execution_payload) |
| 16 | +- [Testing](#testing) |
| 17 | + |
| 18 | +<!-- END doctoc generated TOC please keep comment here to allow auto update --> |
| 19 | +<!-- /TOC --> |
| 20 | + |
| 21 | +## Introduction |
| 22 | + |
| 23 | +*Note:* This specification is built upon [Electra](../electra/beacon-chain.md) and is under active development. |
| 24 | + |
| 25 | +## Configuration |
| 26 | + |
| 27 | +### Execution |
| 28 | + |
| 29 | +| Name | Value | Description | |
| 30 | +| - | - | - | |
| 31 | +| `MAX_BLOBS_PER_BLOCK_EIP7594` | `uint64(8)` | *[New in EIP7594]* Maximum number of blobs in a single block limited by `MAX_BLOB_COMMITMENTS_PER_BLOCK` | |
| 32 | + |
| 33 | +#### Execution payload |
| 34 | + |
| 35 | +##### Modified `process_execution_payload` |
| 36 | + |
| 37 | +```python |
| 38 | +def process_execution_payload(state: BeaconState, body: BeaconBlockBody, execution_engine: ExecutionEngine) -> None: |
| 39 | + payload = body.execution_payload |
| 40 | + |
| 41 | + # Verify consistency of the parent hash with respect to the previous execution payload header |
| 42 | + assert payload.parent_hash == state.latest_execution_payload_header.block_hash |
| 43 | + # Verify prev_randao |
| 44 | + assert payload.prev_randao == get_randao_mix(state, get_current_epoch(state)) |
| 45 | + # Verify timestamp |
| 46 | + assert payload.timestamp == compute_timestamp_at_slot(state, state.slot) |
| 47 | + # Verify commitments are under limit |
| 48 | + assert len(body.blob_kzg_commitments) <= MAX_BLOBS_PER_BLOCK_EIP7594 # [Modified in EIP7594] |
| 49 | + # Verify the execution payload is valid |
| 50 | + versioned_hashes = [kzg_commitment_to_versioned_hash(commitment) for commitment in body.blob_kzg_commitments] |
| 51 | + assert execution_engine.verify_and_notify_new_payload( |
| 52 | + NewPayloadRequest( |
| 53 | + execution_payload=payload, |
| 54 | + versioned_hashes=versioned_hashes, |
| 55 | + parent_beacon_block_root=state.latest_block_header.parent_root, |
| 56 | + execution_requests=body.execution_requests, |
| 57 | + ) |
| 58 | + ) |
| 59 | + # Cache execution payload header |
| 60 | + state.latest_execution_payload_header = ExecutionPayloadHeader( |
| 61 | + parent_hash=payload.parent_hash, |
| 62 | + fee_recipient=payload.fee_recipient, |
| 63 | + state_root=payload.state_root, |
| 64 | + receipts_root=payload.receipts_root, |
| 65 | + logs_bloom=payload.logs_bloom, |
| 66 | + prev_randao=payload.prev_randao, |
| 67 | + block_number=payload.block_number, |
| 68 | + gas_limit=payload.gas_limit, |
| 69 | + gas_used=payload.gas_used, |
| 70 | + timestamp=payload.timestamp, |
| 71 | + extra_data=payload.extra_data, |
| 72 | + base_fee_per_gas=payload.base_fee_per_gas, |
| 73 | + block_hash=payload.block_hash, |
| 74 | + transactions_root=hash_tree_root(payload.transactions), |
| 75 | + withdrawals_root=hash_tree_root(payload.withdrawals), |
| 76 | + blob_gas_used=payload.blob_gas_used, |
| 77 | + excess_blob_gas=payload.excess_blob_gas, |
| 78 | + ) |
| 79 | +``` |
| 80 | + |
| 81 | +## Testing |
| 82 | + |
| 83 | +*Note*: The function `initialize_beacon_state_from_eth1` is modified for pure EIP7594 testing only. |
| 84 | + |
| 85 | +```python |
| 86 | +def initialize_beacon_state_from_eth1(eth1_block_hash: Hash32, |
| 87 | + eth1_timestamp: uint64, |
| 88 | + deposits: Sequence[Deposit], |
| 89 | + execution_payload_header: ExecutionPayloadHeader=ExecutionPayloadHeader() |
| 90 | + ) -> BeaconState: |
| 91 | + fork = Fork( |
| 92 | + previous_version=EIP7594_FORK_VERSION, # [Modified in EIP7594] for testing only |
| 93 | + current_version=EIP7594_FORK_VERSION, # [Modified in EIP7594] |
| 94 | + epoch=GENESIS_EPOCH, |
| 95 | + ) |
| 96 | + state = BeaconState( |
| 97 | + genesis_time=eth1_timestamp + GENESIS_DELAY, |
| 98 | + fork=fork, |
| 99 | + eth1_data=Eth1Data(block_hash=eth1_block_hash, deposit_count=uint64(len(deposits))), |
| 100 | + latest_block_header=BeaconBlockHeader(body_root=hash_tree_root(BeaconBlockBody())), |
| 101 | + randao_mixes=[eth1_block_hash] * EPOCHS_PER_HISTORICAL_VECTOR, # Seed RANDAO with Eth1 entropy |
| 102 | + deposit_requests_start_index=UNSET_DEPOSIT_REQUESTS_START_INDEX, |
| 103 | + ) |
| 104 | + |
| 105 | + # Process deposits |
| 106 | + leaves = list(map(lambda deposit: deposit.data, deposits)) |
| 107 | + for index, deposit in enumerate(deposits): |
| 108 | + deposit_data_list = List[DepositData, 2**DEPOSIT_CONTRACT_TREE_DEPTH](*leaves[:index + 1]) |
| 109 | + state.eth1_data.deposit_root = hash_tree_root(deposit_data_list) |
| 110 | + process_deposit(state, deposit) |
| 111 | + |
| 112 | + # Process deposit balance updates |
| 113 | + validator_pubkeys = [v.pubkey for v in state.validators] |
| 114 | + for deposit in state.pending_deposits: |
| 115 | + validator_index = ValidatorIndex(validator_pubkeys.index(deposit.pubkey)) |
| 116 | + increase_balance(state, validator_index, deposit.amount) |
| 117 | + state.pending_deposits = [] |
| 118 | + |
| 119 | + # Process activations |
| 120 | + for index, validator in enumerate(state.validators): |
| 121 | + balance = state.balances[index] |
| 122 | + validator.effective_balance = min( |
| 123 | + balance - balance % EFFECTIVE_BALANCE_INCREMENT, get_max_effective_balance(validator)) |
| 124 | + if validator.effective_balance >= MIN_ACTIVATION_BALANCE: |
| 125 | + validator.activation_eligibility_epoch = GENESIS_EPOCH |
| 126 | + validator.activation_epoch = GENESIS_EPOCH |
| 127 | + |
| 128 | + # Set genesis validators root for domain separation and chain versioning |
| 129 | + state.genesis_validators_root = hash_tree_root(state.validators) |
| 130 | + |
| 131 | + # Fill in sync committees |
| 132 | + # Note: A duplicate committee is assigned for the current and next committee at genesis |
| 133 | + state.current_sync_committee = get_next_sync_committee(state) |
| 134 | + state.next_sync_committee = get_next_sync_committee(state) |
| 135 | + |
| 136 | + # Initialize the execution payload header |
| 137 | + state.latest_execution_payload_header = execution_payload_header |
| 138 | + |
| 139 | + return state |
| 140 | +``` |
0 commit comments