diff --git a/specs/_features/eip7732/beacon-chain.md b/specs/_features/eip7732/beacon-chain.md index fdcb2b3008..6c37104e9d 100644 --- a/specs/_features/eip7732/beacon-chain.md +++ b/specs/_features/eip7732/beacon-chain.md @@ -206,7 +206,6 @@ class BeaconBlockBody(Container): class ExecutionPayloadHeader(Container): parent_block_hash: Hash32 parent_block_root: Root - block_hash: Hash32 gas_limit: uint64 builder_index: ValidatorIndex slot: Slot @@ -330,15 +329,6 @@ def is_valid_indexed_payload_attestation( return bls.FastAggregateVerify(pubkeys, signing_root, indexed_payload_attestation.signature) ``` -#### `is_parent_block_full` - -This function returns true if the last committed payload header was fulfilled with a payload, this can only happen when both beacon block and payload were present. This function must be called on a beacon state before processing the execution payload header in the block. - -```python -def is_parent_block_full(state: BeaconState) -> bool: - return state.latest_execution_payload_header.block_hash == state.latest_block_hash -``` - ### Beacon State accessors #### `get_ptc` @@ -426,7 +416,7 @@ The post-state corresponding to a pre-state `state` and a signed execution paylo ```python def process_block(state: BeaconState, block: BeaconBlock) -> None: process_block_header(state, block) - process_withdrawals(state) # [Modified in EIP-7732] + # Removed process_withdrawals(state) in EIP-7732 process_execution_payload_header(state, block) # [Modified in EIP-7732, removed process_execution_payload] process_randao(state, block.body) process_eth1_data(state, block.body) @@ -434,44 +424,6 @@ def process_block(state: BeaconState, block: BeaconBlock) -> None: process_sync_aggregate(state, block.body.sync_aggregate) ``` -#### Withdrawals - -##### Modified `process_withdrawals` - -**Note:** This is modified to take only the `state` as parameter. Withdrawals are deterministic given the beacon state, any execution payload that has the corresponding block as parent beacon block is required to honor these withdrawals in the execution layer. This function must be called before `process_execution_payload_header` as this latter function affects validator balances. - -```python -def process_withdrawals(state: BeaconState) -> None: - # return early if the parent block was empty - if not is_parent_block_full(state): - return - - withdrawals, partial_withdrawals_count = get_expected_withdrawals(state) - withdrawals_list = List[Withdrawal, MAX_WITHDRAWALS_PER_PAYLOAD](withdrawals) - state.latest_withdrawals_root = hash_tree_root(withdrawals_list) - for withdrawal in withdrawals: - decrease_balance(state, withdrawal.validator_index, withdrawal.amount) - - # Update pending partial withdrawals - state.pending_partial_withdrawals = state.pending_partial_withdrawals[partial_withdrawals_count:] - - # Update the next withdrawal index if this block contained withdrawals - if len(withdrawals) != 0: - latest_withdrawal = withdrawals[-1] - state.next_withdrawal_index = WithdrawalIndex(latest_withdrawal.index + 1) - - # Update the next validator index to start the next withdrawal sweep - if len(withdrawals) == MAX_WITHDRAWALS_PER_PAYLOAD: - # Next sweep starts after the latest withdrawal's validator index - next_validator_index = ValidatorIndex((withdrawals[-1].validator_index + 1) % len(state.validators)) - state.next_withdrawal_validator_index = next_validator_index - else: - # Advance sweep by the max length of the sweep if there was not a full set of withdrawals - next_index = state.next_withdrawal_validator_index + MAX_VALIDATORS_PER_WITHDRAWALS_SWEEP - next_validator_index = ValidatorIndex(next_index % len(state.validators)) - state.next_withdrawal_validator_index = next_validator_index -``` - #### Execution payload header ##### New `verify_execution_payload_header_signature` @@ -629,13 +581,9 @@ def process_execution_payload(state: BeaconState, assert committed_header.blob_kzg_commitments_root == hash_tree_root(envelope.blob_kzg_commitments) if not envelope.payload_withheld: - # Verify the withdrawals root - assert hash_tree_root(payload.withdrawals) == state.latest_withdrawals_root - # Verify the gas_limit assert committed_header.gas_limit == payload.gas_limit - assert committed_header.block_hash == payload.block_hash # Verify consistency of the parent hash with respect to the previous execution payload assert payload.parent_hash == state.latest_block_hash # Verify prev_randao @@ -655,6 +603,8 @@ def process_execution_payload(state: BeaconState, ) ) + # Process withdrawals + process_withdrawals(state, payload) # Process Electra operations def for_ops(operations: Sequence[Any], fn: Callable[[BeaconState, Any], None]) -> None: for operation in operations: diff --git a/specs/_features/eip7732/builder.md b/specs/_features/eip7732/builder.md index 491f625d89..427fd47b9d 100644 --- a/specs/_features/eip7732/builder.md +++ b/specs/_features/eip7732/builder.md @@ -31,12 +31,11 @@ Builders can broadcast a payload bid for the current or the next slot's proposer 1. Set `header.parent_block_hash` to the current head of the execution chain (this can be obtained from the beacon state as `state.last_block_hash`). 2. Set `header.parent_block_root` to be the head of the consensus chain (this can be obtained from the beacon state as `hash_tree_root(state.latest_block_header)`. The `parent_block_root` and `parent_block_hash` must be compatible, in the sense that they both should come from the same `state` by the method described in this and the previous point. 3. Construct an execution payload. This can be performed with an external execution engine with a call to `engine_getPayloadV4`. -4. Set `header.block_hash` to be the block hash of the constructed payload, that is `payload.block_hash`. -5. Set `header.gas_limit` to be the gas limit of the constructed payload, that is `payload.gas_limit`. -6. Set `header.builder_index` to be the validator index of the builder performing these actions. -7. Set `header.slot` to be the slot for which this bid is aimed. This slot **MUST** be either the current slot or the next slot. -8. Set `header.value` to be the value that the builder will pay the proposer if the bid is accepted. The builder **MUST** have balance enough to fulfill this bid. -9. Set `header.kzg_commitments_root` to be the `hash_tree_root` of the `blobsbundle.commitments` field returned by `engine_getPayloadV4`. +4. Set `header.gas_limit` to be the gas limit of the constructed payload, that is `payload.gas_limit`. +5. Set `header.builder_index` to be the validator index of the builder performing these actions. +6. Set `header.slot` to be the slot for which this bid is aimed. This slot **MUST** be either the current slot or the next slot. +7. Set `header.value` to be the value that the builder will pay the proposer if the bid is accepted. The builder **MUST** have balance enough to fulfill this bid. +8. Set `header.kzg_commitments_root` to be the `hash_tree_root` of the `blobsbundle.commitments` field returned by `engine_getPayloadV4`. After building the `header`, the builder obtains a `signature` of the header by using @@ -104,7 +103,7 @@ When the proposer publishes a valid `SignedBeaconBlock` containing a signed comm To construct the `execution_payload_envelope` the builder must perform the following steps, we alias `header` to be the committed `ExecutionPayloadHeader` in the beacon block. -1. Set the `payload` field to be the `ExecutionPayload` constructed when creating the corresponding bid. This payload **MUST** have the same block hash as `header.block_hash`. +1. Set the `payload` field to be the `ExecutionPayload` constructed when creating the corresponding bid. 2. Set the `builder_index` field to be the validator index of the builder performing these steps. This field **MUST** be `header.builder_index`. 3. Set `beacon_block_root` to be the `hash_tree_root` of the corresponding beacon block. 4. Set `blob_kzg_commitments` to be the `commitments` field of the blobs bundle constructed when constructing the bid. This field **MUST** have a `hash_tree_root` equal to `header.blob_kzg_commitments_root`. diff --git a/specs/_features/eip7732/fork-choice.md b/specs/_features/eip7732/fork-choice.md index 0eb49ddfc1..2c21ff4775 100644 --- a/specs/_features/eip7732/fork-choice.md +++ b/specs/_features/eip7732/fork-choice.md @@ -186,10 +186,7 @@ def is_payload_present(store: Store, beacon_block_root: Root) -> bool: ```python def is_parent_node_full(store: Store, block: BeaconBlock) -> bool: - parent = store.blocks[block.parent_root] - parent_block_hash = block.body.signed_execution_payload_header.message.parent_block_hash - message_block_hash = parent.body.signed_execution_payload_header.message.block_hash - return parent_block_hash == message_block_hash + return block.parent_root in store.execution_payload_states ``` ### Modified `get_ancestor` diff --git a/specs/_features/eip7732/p2p-interface.md b/specs/_features/eip7732/p2p-interface.md index 52546070f3..894fb44757 100644 --- a/specs/_features/eip7732/p2p-interface.md +++ b/specs/_features/eip7732/p2p-interface.md @@ -144,8 +144,6 @@ Let `block` be the block with `envelope.beacon_block_root`. Let `header` alias `block.body.signed_execution_payload_header.message` (notice that this can be obtained from the `state.signed_execution_payload_header`) - _[REJECT]_ `block` passes validation. - _[REJECT]_ `envelope.builder_index == header.builder_index` -- if `envelope.payload_withheld == False` then - - _[REJECT]_ `payload.block_hash == header.block_hash` - _[REJECT]_ The builder signature, `signed_execution_payload_envelope.signature`, is valid with respect to the builder's public key. ###### `payload_attestation_message`