diff --git a/specs/merge/beacon-chain.md b/specs/merge/beacon-chain.md index b966c6811..697bd0c96 100644 --- a/specs/merge/beacon-chain.md +++ b/specs/merge/beacon-chain.md @@ -33,6 +33,7 @@ - [Block processing](#block-processing) - [Execution payload processing](#execution-payload-processing) - [`process_execution_payload`](#process_execution_payload) +- [Initialize state for pure Merge testnets and test vectors](#initialize-state-for-pure-merge-testnets-and-test-vectors) @@ -233,3 +234,63 @@ def process_execution_payload(state: BeaconState, transactions_root=hash_tree_root(execution_payload.transactions), ) ``` + +## Initialize state for pure Merge testnets and test vectors + +This helper function is only for initializing the state for pure Merge testnets and tests. + +*Note*: The function `initialize_beacon_state_from_eth1` is modified: (1) using `MERGE_FORK_VERSION` as the current fork version, (2) utilizing the Merge `BeaconBlockBody` when constructing the initial `latest_block_header`, and (3) adding initial `latest_execution_payload_header`. + +```python +def initialize_beacon_state_from_eth1(eth1_block_hash: Bytes32, + eth1_timestamp: uint64, + deposits: Sequence[Deposit]) -> BeaconState: + fork = Fork( + previous_version=GENESIS_FORK_VERSION, + current_version=MERGE_FORK_VERSION, # [Modified in Merge] + epoch=GENESIS_EPOCH, + ) + state = BeaconState( + genesis_time=eth1_timestamp + GENESIS_DELAY, + fork=fork, + eth1_data=Eth1Data(block_hash=eth1_block_hash, deposit_count=uint64(len(deposits))), + latest_block_header=BeaconBlockHeader(body_root=hash_tree_root(BeaconBlockBody())), + randao_mixes=[eth1_block_hash] * EPOCHS_PER_HISTORICAL_VECTOR, # Seed RANDAO with Eth1 entropy + ) + + # Process deposits + leaves = list(map(lambda deposit: deposit.data, deposits)) + for index, deposit in enumerate(deposits): + deposit_data_list = List[DepositData, 2**DEPOSIT_CONTRACT_TREE_DEPTH](*leaves[:index + 1]) + state.eth1_data.deposit_root = hash_tree_root(deposit_data_list) + process_deposit(state, deposit) + + # Process activations + for index, validator in enumerate(state.validators): + balance = state.balances[index] + validator.effective_balance = min(balance - balance % EFFECTIVE_BALANCE_INCREMENT, MAX_EFFECTIVE_BALANCE) + if validator.effective_balance == MAX_EFFECTIVE_BALANCE: + validator.activation_eligibility_epoch = GENESIS_EPOCH + validator.activation_epoch = GENESIS_EPOCH + + # Set genesis validators root for domain separation and chain versioning + state.genesis_validators_root = hash_tree_root(state.validators) + + # [New in Merge] Construct execution payload header + # Note: initialized with zero block height + state.latest_execution_payload_header = ExecutionPayloadHeader( + block_hash=eth1_block_hash, + parent_hash=Hash32(), + coinbase=Bytes20(), + state_root=Bytes32(), + number=uint64(0), + gas_limit=uint64(0), + gas_used=uint64(0), + timestamp=eth1_timestamp, + receipt_root=Bytes32(), + logs_bloom=ByteVector[BYTES_PER_LOGS_BLOOM](), + transactions_root=Root(), + ) + + return state +```