From 355a9a3d337ad057159ac5f2f3c77aeac9c337e0 Mon Sep 17 00:00:00 2001 From: Lucas Saldanha Date: Fri, 9 Aug 2024 12:05:23 +1200 Subject: [PATCH 01/24] Introducing ExecutionPayloadEnvelope --- specs/electra/beacon-chain.md | 79 ++++++++++++++++++++++------------- 1 file changed, 51 insertions(+), 28 deletions(-) diff --git a/specs/electra/beacon-chain.md b/specs/electra/beacon-chain.md index cb5ee6a7a9..14e1cca8e3 100644 --- a/specs/electra/beacon-chain.md +++ b/specs/electra/beacon-chain.md @@ -30,12 +30,14 @@ - [`WithdrawalRequest`](#withdrawalrequest) - [`ConsolidationRequest`](#consolidationrequest) - [`PendingConsolidation`](#pendingconsolidation) + - [`ValidatorRequests`](#validatorrequests) + - [`ExecutionPayloadEnvelope`](#executionpayloadenvelope) - [Modified Containers](#modified-containers) - [`AttesterSlashing`](#attesterslashing) + - [`BeaconBlockBody`](#beaconblockbody) - [Extended Containers](#extended-containers) - [`Attestation`](#attestation) - [`IndexedAttestation`](#indexedattestation) - - [`BeaconBlockBody`](#beaconblockbody) - [`ExecutionPayload`](#executionpayload) - [`ExecutionPayloadHeader`](#executionpayloadheader) - [`BeaconState`](#beaconstate) @@ -258,36 +260,35 @@ class PendingConsolidation(Container): target_index: ValidatorIndex ``` -### Modified Containers +#### `ValidatorRequests` -#### `AttesterSlashing` +*Note*: The container is new in EIP????. ```python -class AttesterSlashing(Container): - attestation_1: IndexedAttestation # [Modified in Electra:EIP7549] - attestation_2: IndexedAttestation # [Modified in Electra:EIP7549] +class ValidatorRequests(Container): + deposit_requests: List[DepositRequest, MAX_DEPOSIT_REQUESTS_PER_PAYLOAD] # [New in Electra:EIP6110] + withdrawal_requests: List[WithdrawalRequest, MAX_WITHDRAWAL_REQUESTS_PER_PAYLOAD] # [New in Electra:EIP7002:EIP7251] + consolidation_requests: List[ConsolidationRequest, MAX_CONSOLIDATION_REQUESTS_PER_PAYLOAD] # [New in Electra:EIP7251] ``` -### Extended Containers +#### `ExecutionPayloadEnvelope` -#### `Attestation` +*Note*: The container is new in EIP????. ```python -class Attestation(Container): - aggregation_bits: Bitlist[MAX_VALIDATORS_PER_COMMITTEE * MAX_COMMITTEES_PER_SLOT] # [Modified in Electra:EIP7549] - data: AttestationData - signature: BLSSignature - committee_bits: Bitvector[MAX_COMMITTEES_PER_SLOT] # [New in Electra:EIP7549] +class ExecutionPayloadEnvelope(Container): + execution_payload: ExecutionPayload # [Modified in Electra:EIP6110:EIP7002] + requests: ValidatorRequests ``` -#### `IndexedAttestation` +### Modified Containers + +#### `AttesterSlashing` ```python -class IndexedAttestation(Container): - # [Modified in Electra:EIP7549] - attesting_indices: List[ValidatorIndex, MAX_VALIDATORS_PER_COMMITTEE * MAX_COMMITTEES_PER_SLOT] - data: AttestationData - signature: BLSSignature +class AttesterSlashing(Container): + attestation_1: IndexedAttestation # [Modified in Electra:EIP7549] + attestation_2: IndexedAttestation # [Modified in Electra:EIP7549] ``` #### `BeaconBlockBody` @@ -305,11 +306,33 @@ class BeaconBlockBody(Container): voluntary_exits: List[SignedVoluntaryExit, MAX_VOLUNTARY_EXITS] sync_aggregate: SyncAggregate # Execution - execution_payload: ExecutionPayload # [Modified in Electra:EIP6110:EIP7002] + execution_payload_envelope: ExecutionPayloadEnvelope # [Modified in Electra:EIP????] bls_to_execution_changes: List[SignedBLSToExecutionChange, MAX_BLS_TO_EXECUTION_CHANGES] blob_kzg_commitments: List[KZGCommitment, MAX_BLOB_COMMITMENTS_PER_BLOCK] ``` +### Extended Containers + +#### `Attestation` + +```python +class Attestation(Container): + aggregation_bits: Bitlist[MAX_VALIDATORS_PER_COMMITTEE * MAX_COMMITTEES_PER_SLOT] # [Modified in Electra:EIP7549] + data: AttestationData + signature: BLSSignature + committee_bits: Bitvector[MAX_COMMITTEES_PER_SLOT] # [New in Electra:EIP7549] +``` + +#### `IndexedAttestation` + +```python +class IndexedAttestation(Container): + # [Modified in Electra:EIP7549] + attesting_indices: List[ValidatorIndex, MAX_VALIDATORS_PER_COMMITTEE * MAX_COMMITTEES_PER_SLOT] + data: AttestationData + signature: BLSSignature +``` + #### `ExecutionPayload` ```python @@ -875,7 +898,7 @@ def process_pending_balance_deposits(state: BeaconState) -> None: if processed_amount + deposit.amount > available_for_processing: break # Deposit fits in the churn, process it. Increase balance and consume churn. - else: + else: increase_balance(state, deposit.index, deposit.amount) processed_amount += deposit.amount # Regardless of how the deposit was handled, we move on in the queue. @@ -946,7 +969,7 @@ def process_effective_balance_updates(state: BeaconState) -> None: ```python def process_block(state: BeaconState, block: BeaconBlock) -> None: process_block_header(state, block) - process_withdrawals(state, block.body.execution_payload) # [Modified in Electra:EIP7251] + process_withdrawals(state, block.body.execution_payload_envelope.execution_payload) # [Modified in Electra:EIP7251:EIP????] process_execution_payload(state, block.body, EXECUTION_ENGINE) # [Modified in Electra:EIP6110] process_randao(state, block.body) process_eth1_data(state, block.body) @@ -1056,7 +1079,7 @@ def process_withdrawals(state: BeaconState, payload: ExecutionPayload) -> None: ```python def process_execution_payload(state: BeaconState, body: BeaconBlockBody, execution_engine: ExecutionEngine) -> None: - payload = body.execution_payload + payload = body.execution_payload_envelope.execution_payload # Verify consistency of the parent hash with respect to the previous execution payload header assert payload.parent_hash == state.latest_execution_payload_header.block_hash @@ -1126,11 +1149,11 @@ def process_operations(state: BeaconState, body: BeaconBlockBody) -> None: for_ops(body.deposits, process_deposit) # [Modified in Electra:EIP7251] for_ops(body.voluntary_exits, process_voluntary_exit) # [Modified in Electra:EIP7251] for_ops(body.bls_to_execution_changes, process_bls_to_execution_change) - for_ops(body.execution_payload.deposit_requests, process_deposit_request) # [New in Electra:EIP6110] - # [New in Electra:EIP7002:EIP7251] - for_ops(body.execution_payload.withdrawal_requests, process_withdrawal_request) - # [New in Electra:EIP7251] - for_ops(body.execution_payload.consolidation_requests, process_consolidation_request) + for_ops(body.execution_payload_envelope.requests.deposit_requests, process_deposit_request) # [New in Electra:EIP6110:EIP????] + # [New in Electra:EIP7002:EIP7251:EIP????] + for_ops(body.execution_payload_envelope.requests.withdrawal_requests, process_withdrawal_request) + # [New in Electra:EIP7251:EIP????] + for_ops(body.execution_payload_envelope.requests.consolidation_requests, process_consolidation_request) ``` ##### Attestations From ed9b061fdc93850cf1bba7104dd3b0ebb4e96d2b Mon Sep 17 00:00:00 2001 From: Lucas Saldanha Date: Fri, 9 Aug 2024 12:15:54 +1200 Subject: [PATCH 02/24] Comments --- specs/electra/beacon-chain.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/specs/electra/beacon-chain.md b/specs/electra/beacon-chain.md index 14e1cca8e3..ccc55d59e6 100644 --- a/specs/electra/beacon-chain.md +++ b/specs/electra/beacon-chain.md @@ -970,7 +970,7 @@ def process_effective_balance_updates(state: BeaconState) -> None: def process_block(state: BeaconState, block: BeaconBlock) -> None: process_block_header(state, block) process_withdrawals(state, block.body.execution_payload_envelope.execution_payload) # [Modified in Electra:EIP7251:EIP????] - process_execution_payload(state, block.body, EXECUTION_ENGINE) # [Modified in Electra:EIP6110] + process_execution_payload(state, block.body, EXECUTION_ENGINE) # [Modified in Electra:EIP6110:EIP????] process_randao(state, block.body) process_eth1_data(state, block.body) process_operations(state, block.body) # [Modified in Electra:EIP6110:EIP7002:EIP7549:EIP7251] @@ -1075,11 +1075,11 @@ def process_withdrawals(state: BeaconState, payload: ExecutionPayload) -> None: ##### Modified `process_execution_payload` -*Note*: The function `process_execution_payload` is modified to use the new `ExecutionPayloadHeader` type. +*Note*: The function `process_execution_payload` is modified to use the new `ExecutionPayloadHeader` and `ExecutionPayloadEnveloped` types. ```python def process_execution_payload(state: BeaconState, body: BeaconBlockBody, execution_engine: ExecutionEngine) -> None: - payload = body.execution_payload_envelope.execution_payload + payload = body.execution_payload_envelope.execution_payload # [Modified in EIP????] # Verify consistency of the parent hash with respect to the previous execution payload header assert payload.parent_hash == state.latest_execution_payload_header.block_hash From f26c9be1567992c6be4aaef3c740bb7501081eef Mon Sep 17 00:00:00 2001 From: Lucas Saldanha Date: Mon, 12 Aug 2024 10:24:53 +1200 Subject: [PATCH 03/24] Removing EL requests from ExecutionPayload --- specs/electra/beacon-chain.md | 5 ----- 1 file changed, 5 deletions(-) diff --git a/specs/electra/beacon-chain.md b/specs/electra/beacon-chain.md index ccc55d59e6..1b95fa35b2 100644 --- a/specs/electra/beacon-chain.md +++ b/specs/electra/beacon-chain.md @@ -356,11 +356,6 @@ class ExecutionPayload(Container): withdrawals: List[Withdrawal, MAX_WITHDRAWALS_PER_PAYLOAD] blob_gas_used: uint64 excess_blob_gas: uint64 - deposit_requests: List[DepositRequest, MAX_DEPOSIT_REQUESTS_PER_PAYLOAD] # [New in Electra:EIP6110] - # [New in Electra:EIP7002:EIP7251] - withdrawal_requests: List[WithdrawalRequest, MAX_WITHDRAWAL_REQUESTS_PER_PAYLOAD] - # [New in Electra:EIP7251] - consolidation_requests: List[ConsolidationRequest, MAX_CONSOLIDATION_REQUESTS_PER_PAYLOAD] ``` #### `ExecutionPayloadHeader` From f9ac90200ae0109c0510f784b01bc732fff1812a Mon Sep 17 00:00:00 2001 From: Lucas Saldanha Date: Mon, 12 Aug 2024 10:53:47 +1200 Subject: [PATCH 04/24] Updated light-client block -> header function --- specs/electra/light-client/full-node.md | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/specs/electra/light-client/full-node.md b/specs/electra/light-client/full-node.md index f08a2cc5ed..8bf340419b 100644 --- a/specs/electra/light-client/full-node.md +++ b/specs/electra/light-client/full-node.md @@ -26,9 +26,14 @@ Execution payload data is updated to account for the Electra upgrade. ```python def block_to_light_client_header(block: SignedBeaconBlock) -> LightClientHeader: epoch = compute_epoch_at_slot(block.message.slot) - + if epoch >= CAPELLA_FORK_EPOCH: - payload = block.message.body.execution_payload + # [New in Electra:EIP6110:EIP7002:EIP7251:EIP????] + if epoch >= ELECTRA_FORK_EPOCH: + payload = block.message.body.execution_payload_envelope.execution_payload + else: + payload = block.message.body.execution_payload + execution_header = ExecutionPayloadHeader( parent_hash=payload.parent_hash, fee_recipient=payload.fee_recipient, @@ -50,11 +55,12 @@ def block_to_light_client_header(block: SignedBeaconBlock) -> LightClientHeader: execution_header.blob_gas_used = payload.blob_gas_used execution_header.excess_blob_gas = payload.excess_blob_gas - # [New in Electra:EIP6110:EIP7002:EIP7251] + # [New in Electra:EIP6110:EIP7002:EIP7251:EIP????] if epoch >= ELECTRA_FORK_EPOCH: - execution_header.deposit_requests_root = hash_tree_root(payload.deposit_requests) - execution_header.withdrawal_requests_root = hash_tree_root(payload.withdrawal_requests) - execution_header.consolidation_requests_root = hash_tree_root(payload.consolidation_requests) + requests = block.message.body.execution_payload_envelope.requests + execution_header.deposit_requests_root = hash_tree_root(requests.deposit_requests) + execution_header.withdrawal_requests_root = hash_tree_root(requests.withdrawal_requests) + execution_header.consolidation_requests_root = hash_tree_root(requests.consolidation_requests) execution_branch = ExecutionBranch( compute_merkle_proof(block.message.body, EXECUTION_PAYLOAD_GINDEX)) From e26a3e04b387bf445a6b4119da77630f00ba7683 Mon Sep 17 00:00:00 2001 From: Lucas Saldanha Date: Mon, 12 Aug 2024 10:54:21 +1200 Subject: [PATCH 05/24] New execution payload global index --- pysetup/spec_builders/electra.py | 1 + specs/electra/light-client/sync-protocol.md | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/pysetup/spec_builders/electra.py b/pysetup/spec_builders/electra.py index ca02ee927c..bc54b0cc06 100644 --- a/pysetup/spec_builders/electra.py +++ b/pysetup/spec_builders/electra.py @@ -18,4 +18,5 @@ def hardcoded_ssz_dep_constants(cls) -> Dict[str, str]: 'FINALIZED_ROOT_GINDEX_ELECTRA': 'GeneralizedIndex(169)', 'CURRENT_SYNC_COMMITTEE_GINDEX_ELECTRA': 'GeneralizedIndex(86)', 'NEXT_SYNC_COMMITTEE_GINDEX_ELECTRA': 'GeneralizedIndex(87)', + 'EXECUTION_PAYLOAD_GINDEX': 'GeneralizedIndex(50)', } diff --git a/specs/electra/light-client/sync-protocol.md b/specs/electra/light-client/sync-protocol.md index ef9dcd5987..f304211b2b 100644 --- a/specs/electra/light-client/sync-protocol.md +++ b/specs/electra/light-client/sync-protocol.md @@ -41,6 +41,10 @@ Additional documents describes the impact of the upgrade on certain roles: ## Constants +| Name | Value | +| - | - | +| `EXECUTION_PAYLOAD_GINDEX` | `get_generalized_index(BeaconBlockBody, 'execution_payload_envelope', 'execution_payload')` (= 50) | + ### Frozen constants Existing `GeneralizedIndex` constants are frozen at their [Altair](../../altair/light-client/sync-protocol.md#constants) values. From 9a2e08808ed60b345124436f268e9ff2fe0789c1 Mon Sep 17 00:00:00 2001 From: Lucas Saldanha Date: Mon, 12 Aug 2024 20:17:49 +1200 Subject: [PATCH 06/24] requests_root --- specs/electra/beacon-chain.md | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/specs/electra/beacon-chain.md b/specs/electra/beacon-chain.md index 1b95fa35b2..e376ce0789 100644 --- a/specs/electra/beacon-chain.md +++ b/specs/electra/beacon-chain.md @@ -381,9 +381,7 @@ class ExecutionPayloadHeader(Container): withdrawals_root: Root blob_gas_used: uint64 excess_blob_gas: uint64 - deposit_requests_root: Root # [New in Electra:EIP6110] - withdrawal_requests_root: Root # [New in Electra:EIP7002:EIP7251] - consolidation_requests_root: Root # [New in Electra:EIP7251] + requests_root: Root # [New in Electra:EIP6110:EIP7002:EIP7251] ``` #### `BeaconState` @@ -1112,9 +1110,7 @@ def process_execution_payload(state: BeaconState, body: BeaconBlockBody, executi withdrawals_root=hash_tree_root(payload.withdrawals), blob_gas_used=payload.blob_gas_used, excess_blob_gas=payload.excess_blob_gas, - deposit_requests_root=hash_tree_root(payload.deposit_requests), # [New in Electra:EIP6110] - withdrawal_requests_root=hash_tree_root(payload.withdrawal_requests), # [New in Electra:EIP7002:EIP7251] - consolidation_requests_root=hash_tree_root(payload.consolidation_requests), # [New in Electra:EIP7251] + requests_root=hash_tree_root(body.execution_payload_envelope.requests), # [New in Electra:EIP6110:EIP7002:EIP7251] ) ``` From 858402fc8a481c8110ca7882e79777ace3450be7 Mon Sep 17 00:00:00 2001 From: Lucas Saldanha Date: Tue, 13 Aug 2024 12:29:27 +1200 Subject: [PATCH 07/24] Updated with requests on block body --- specs/electra/beacon-chain.md | 104 ++-------------------------------- 1 file changed, 6 insertions(+), 98 deletions(-) diff --git a/specs/electra/beacon-chain.md b/specs/electra/beacon-chain.md index e376ce0789..a70960c4d5 100644 --- a/specs/electra/beacon-chain.md +++ b/specs/electra/beacon-chain.md @@ -31,7 +31,6 @@ - [`ConsolidationRequest`](#consolidationrequest) - [`PendingConsolidation`](#pendingconsolidation) - [`ValidatorRequests`](#validatorrequests) - - [`ExecutionPayloadEnvelope`](#executionpayloadenvelope) - [Modified Containers](#modified-containers) - [`AttesterSlashing`](#attesterslashing) - [`BeaconBlockBody`](#beaconblockbody) @@ -39,7 +38,6 @@ - [`Attestation`](#attestation) - [`IndexedAttestation`](#indexedattestation) - [`ExecutionPayload`](#executionpayload) - - [`ExecutionPayloadHeader`](#executionpayloadheader) - [`BeaconState`](#beaconstate) - [Helper functions](#helper-functions) - [Predicates](#predicates) @@ -80,8 +78,6 @@ - [Withdrawals](#withdrawals) - [Modified `get_expected_withdrawals`](#modified-get_expected_withdrawals) - [Modified `process_withdrawals`](#modified-process_withdrawals) - - [Execution payload](#execution-payload) - - [Modified `process_execution_payload`](#modified-process_execution_payload) - [Operations](#operations) - [Modified `process_operations`](#modified-process_operations) - [Attestations](#attestations) @@ -262,8 +258,6 @@ class PendingConsolidation(Container): #### `ValidatorRequests` -*Note*: The container is new in EIP????. - ```python class ValidatorRequests(Container): deposit_requests: List[DepositRequest, MAX_DEPOSIT_REQUESTS_PER_PAYLOAD] # [New in Electra:EIP6110] @@ -271,16 +265,6 @@ class ValidatorRequests(Container): consolidation_requests: List[ConsolidationRequest, MAX_CONSOLIDATION_REQUESTS_PER_PAYLOAD] # [New in Electra:EIP7251] ``` -#### `ExecutionPayloadEnvelope` - -*Note*: The container is new in EIP????. - -```python -class ExecutionPayloadEnvelope(Container): - execution_payload: ExecutionPayload # [Modified in Electra:EIP6110:EIP7002] - requests: ValidatorRequests -``` - ### Modified Containers #### `AttesterSlashing` @@ -306,9 +290,10 @@ class BeaconBlockBody(Container): voluntary_exits: List[SignedVoluntaryExit, MAX_VOLUNTARY_EXITS] sync_aggregate: SyncAggregate # Execution - execution_payload_envelope: ExecutionPayloadEnvelope # [Modified in Electra:EIP????] + execution_payload: ExecutionPayload bls_to_execution_changes: List[SignedBLSToExecutionChange, MAX_BLS_TO_EXECUTION_CHANGES] blob_kzg_commitments: List[KZGCommitment, MAX_BLOB_COMMITMENTS_PER_BLOCK] + requests: ValidatorRequests # [New in Electra:EIP????] ``` ### Extended Containers @@ -358,32 +343,6 @@ class ExecutionPayload(Container): excess_blob_gas: uint64 ``` -#### `ExecutionPayloadHeader` - -```python -class ExecutionPayloadHeader(Container): - # Execution block header fields - parent_hash: Hash32 - fee_recipient: ExecutionAddress - state_root: Bytes32 - receipts_root: Bytes32 - logs_bloom: ByteVector[BYTES_PER_LOGS_BLOOM] - prev_randao: Bytes32 - block_number: uint64 - gas_limit: uint64 - gas_used: uint64 - timestamp: uint64 - extra_data: ByteList[MAX_EXTRA_DATA_BYTES] - base_fee_per_gas: uint256 - # Extra payload fields - block_hash: Hash32 - transactions_root: Root - withdrawals_root: Root - blob_gas_used: uint64 - excess_blob_gas: uint64 - requests_root: Root # [New in Electra:EIP6110:EIP7002:EIP7251] -``` - #### `BeaconState` ```python @@ -962,7 +921,7 @@ def process_effective_balance_updates(state: BeaconState) -> None: ```python def process_block(state: BeaconState, block: BeaconBlock) -> None: process_block_header(state, block) - process_withdrawals(state, block.body.execution_payload_envelope.execution_payload) # [Modified in Electra:EIP7251:EIP????] + process_withdrawals(state, block.body.execution_payload) # [Modified in Electra:EIP7251:EIP????] process_execution_payload(state, block.body, EXECUTION_ENGINE) # [Modified in Electra:EIP6110:EIP????] process_randao(state, block.body) process_eth1_data(state, block.body) @@ -1063,57 +1022,6 @@ def process_withdrawals(state: BeaconState, payload: ExecutionPayload) -> None: next_validator_index = ValidatorIndex(next_index % len(state.validators)) state.next_withdrawal_validator_index = next_validator_index ``` - -#### Execution payload - -##### Modified `process_execution_payload` - -*Note*: The function `process_execution_payload` is modified to use the new `ExecutionPayloadHeader` and `ExecutionPayloadEnveloped` types. - -```python -def process_execution_payload(state: BeaconState, body: BeaconBlockBody, execution_engine: ExecutionEngine) -> None: - payload = body.execution_payload_envelope.execution_payload # [Modified in EIP????] - - # Verify consistency of the parent hash with respect to the previous execution payload header - assert payload.parent_hash == state.latest_execution_payload_header.block_hash - # Verify prev_randao - assert payload.prev_randao == get_randao_mix(state, get_current_epoch(state)) - # Verify timestamp - assert payload.timestamp == compute_timestamp_at_slot(state, state.slot) - # Verify commitments are under limit - assert len(body.blob_kzg_commitments) <= MAX_BLOBS_PER_BLOCK - # Verify the execution payload is valid - versioned_hashes = [kzg_commitment_to_versioned_hash(commitment) for commitment in body.blob_kzg_commitments] - assert execution_engine.verify_and_notify_new_payload( - NewPayloadRequest( - execution_payload=payload, - versioned_hashes=versioned_hashes, - parent_beacon_block_root=state.latest_block_header.parent_root, - ) - ) - # Cache execution payload header - state.latest_execution_payload_header = ExecutionPayloadHeader( - parent_hash=payload.parent_hash, - fee_recipient=payload.fee_recipient, - state_root=payload.state_root, - receipts_root=payload.receipts_root, - logs_bloom=payload.logs_bloom, - prev_randao=payload.prev_randao, - block_number=payload.block_number, - gas_limit=payload.gas_limit, - gas_used=payload.gas_used, - timestamp=payload.timestamp, - extra_data=payload.extra_data, - base_fee_per_gas=payload.base_fee_per_gas, - block_hash=payload.block_hash, - transactions_root=hash_tree_root(payload.transactions), - withdrawals_root=hash_tree_root(payload.withdrawals), - blob_gas_used=payload.blob_gas_used, - excess_blob_gas=payload.excess_blob_gas, - requests_root=hash_tree_root(body.execution_payload_envelope.requests), # [New in Electra:EIP6110:EIP7002:EIP7251] - ) -``` - #### Operations ##### Modified `process_operations` @@ -1140,11 +1048,11 @@ def process_operations(state: BeaconState, body: BeaconBlockBody) -> None: for_ops(body.deposits, process_deposit) # [Modified in Electra:EIP7251] for_ops(body.voluntary_exits, process_voluntary_exit) # [Modified in Electra:EIP7251] for_ops(body.bls_to_execution_changes, process_bls_to_execution_change) - for_ops(body.execution_payload_envelope.requests.deposit_requests, process_deposit_request) # [New in Electra:EIP6110:EIP????] + for_ops(body.requests.deposit_requests, process_deposit_request) # [New in Electra:EIP6110:EIP????] # [New in Electra:EIP7002:EIP7251:EIP????] - for_ops(body.execution_payload_envelope.requests.withdrawal_requests, process_withdrawal_request) + for_ops(body.requests.withdrawal_requests, process_withdrawal_request) # [New in Electra:EIP7251:EIP????] - for_ops(body.execution_payload_envelope.requests.consolidation_requests, process_consolidation_request) + for_ops(body.requests.consolidation_requests, process_consolidation_request) ``` ##### Attestations From 794b942c9b07450abbe31c0a1e3b8772397408dc Mon Sep 17 00:00:00 2001 From: Lucas Saldanha Date: Tue, 13 Aug 2024 17:47:50 +1200 Subject: [PATCH 08/24] Undo execution_payload gsync change --- pysetup/spec_builders/electra.py | 1 - specs/electra/light-client/sync-protocol.md | 4 ---- 2 files changed, 5 deletions(-) diff --git a/pysetup/spec_builders/electra.py b/pysetup/spec_builders/electra.py index bc54b0cc06..ca02ee927c 100644 --- a/pysetup/spec_builders/electra.py +++ b/pysetup/spec_builders/electra.py @@ -18,5 +18,4 @@ def hardcoded_ssz_dep_constants(cls) -> Dict[str, str]: 'FINALIZED_ROOT_GINDEX_ELECTRA': 'GeneralizedIndex(169)', 'CURRENT_SYNC_COMMITTEE_GINDEX_ELECTRA': 'GeneralizedIndex(86)', 'NEXT_SYNC_COMMITTEE_GINDEX_ELECTRA': 'GeneralizedIndex(87)', - 'EXECUTION_PAYLOAD_GINDEX': 'GeneralizedIndex(50)', } diff --git a/specs/electra/light-client/sync-protocol.md b/specs/electra/light-client/sync-protocol.md index f304211b2b..ef9dcd5987 100644 --- a/specs/electra/light-client/sync-protocol.md +++ b/specs/electra/light-client/sync-protocol.md @@ -41,10 +41,6 @@ Additional documents describes the impact of the upgrade on certain roles: ## Constants -| Name | Value | -| - | - | -| `EXECUTION_PAYLOAD_GINDEX` | `get_generalized_index(BeaconBlockBody, 'execution_payload_envelope', 'execution_payload')` (= 50) | - ### Frozen constants Existing `GeneralizedIndex` constants are frozen at their [Altair](../../altair/light-client/sync-protocol.md#constants) values. From 5c88de8bb917d3384c5b278ad656bbc37b02c80d Mon Sep 17 00:00:00 2001 From: Lucas Saldanha Date: Tue, 13 Aug 2024 17:50:31 +1200 Subject: [PATCH 09/24] Remove requests in execution_payload from full-node lightclient spec --- specs/electra/light-client/full-node.md | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/specs/electra/light-client/full-node.md b/specs/electra/light-client/full-node.md index 8bf340419b..0393aaec24 100644 --- a/specs/electra/light-client/full-node.md +++ b/specs/electra/light-client/full-node.md @@ -26,14 +26,9 @@ Execution payload data is updated to account for the Electra upgrade. ```python def block_to_light_client_header(block: SignedBeaconBlock) -> LightClientHeader: epoch = compute_epoch_at_slot(block.message.slot) - - if epoch >= CAPELLA_FORK_EPOCH: - # [New in Electra:EIP6110:EIP7002:EIP7251:EIP????] - if epoch >= ELECTRA_FORK_EPOCH: - payload = block.message.body.execution_payload_envelope.execution_payload - else: - payload = block.message.body.execution_payload + if epoch >= CAPELLA_FORK_EPOCH: + payload = block.message.body.execution_payload execution_header = ExecutionPayloadHeader( parent_hash=payload.parent_hash, fee_recipient=payload.fee_recipient, @@ -55,13 +50,6 @@ def block_to_light_client_header(block: SignedBeaconBlock) -> LightClientHeader: execution_header.blob_gas_used = payload.blob_gas_used execution_header.excess_blob_gas = payload.excess_blob_gas - # [New in Electra:EIP6110:EIP7002:EIP7251:EIP????] - if epoch >= ELECTRA_FORK_EPOCH: - requests = block.message.body.execution_payload_envelope.requests - execution_header.deposit_requests_root = hash_tree_root(requests.deposit_requests) - execution_header.withdrawal_requests_root = hash_tree_root(requests.withdrawal_requests) - execution_header.consolidation_requests_root = hash_tree_root(requests.consolidation_requests) - execution_branch = ExecutionBranch( compute_merkle_proof(block.message.body, EXECUTION_PAYLOAD_GINDEX)) else: From 666967502b357adfab907d64a656b0f7e5803afe Mon Sep 17 00:00:00 2001 From: Lucas Saldanha Date: Tue, 13 Aug 2024 18:16:11 +1200 Subject: [PATCH 10/24] Test updates --- .../test/electra/sanity/blocks/test_blocks.py | 8 +++---- .../sanity/blocks/test_deposit_transition.py | 10 ++++----- .../pyspec/eth2spec/test/helpers/block.py | 7 +++++- .../test/helpers/execution_payload.py | 22 +------------------ 4 files changed, 16 insertions(+), 31 deletions(-) diff --git a/tests/core/pyspec/eth2spec/test/electra/sanity/blocks/test_blocks.py b/tests/core/pyspec/eth2spec/test/electra/sanity/blocks/test_blocks.py index 9fa4d609fc..8f890b4501 100644 --- a/tests/core/pyspec/eth2spec/test/electra/sanity/blocks/test_blocks.py +++ b/tests/core/pyspec/eth2spec/test/electra/sanity/blocks/test_blocks.py @@ -41,7 +41,7 @@ def test_basic_el_withdrawal_request(spec, state): validator_pubkey=validator_pubkey, ) block = build_empty_block_for_next_slot(spec, state) - block.body.execution_payload.withdrawal_requests = [withdrawal_request] + block.body.requests.withdrawal_requests = [withdrawal_request] block.body.execution_payload.block_hash = compute_el_block_hash(spec, block.body.execution_payload, state) signed_block = state_transition_and_sign_block(spec, state, block) @@ -77,7 +77,7 @@ def test_basic_btec_and_el_withdrawal_request_in_same_block(spec, state): source_address=address, validator_pubkey=validator_pubkey, ) - block.body.execution_payload.withdrawal_requests = [withdrawal_request] + block.body.requests.withdrawal_requests = [withdrawal_request] block.body.execution_payload.block_hash = compute_el_block_hash(spec, block.body.execution_payload, state) signed_block = state_transition_and_sign_block(spec, state, block) @@ -130,7 +130,7 @@ def test_basic_btec_before_el_withdrawal_request(spec, state): validator_pubkey=validator_pubkey, ) block_2 = build_empty_block_for_next_slot(spec, state) - block_2.body.execution_payload.withdrawal_requests = [withdrawal_request] + block_2.body.requests.withdrawal_requests = [withdrawal_request] block_2.body.execution_payload.block_hash = compute_el_block_hash(spec, block_2.body.execution_payload, state) signed_block_2 = state_transition_and_sign_block(spec, state, block_2) @@ -163,7 +163,7 @@ def test_cl_exit_and_el_withdrawal_request_in_same_block(spec, state): ) block = build_empty_block_for_next_slot(spec, state) block.body.voluntary_exits = signed_voluntary_exits - block.body.execution_payload.withdrawal_requests = [withdrawal_request] + block.body.requests.withdrawal_requests = [withdrawal_request] block.body.execution_payload.block_hash = compute_el_block_hash(spec, block.body.execution_payload, state) signed_block = state_transition_and_sign_block(spec, state, block) diff --git a/tests/core/pyspec/eth2spec/test/electra/sanity/blocks/test_deposit_transition.py b/tests/core/pyspec/eth2spec/test/electra/sanity/blocks/test_deposit_transition.py index 4b8c1cd4f8..a0b3b83956 100644 --- a/tests/core/pyspec/eth2spec/test/electra/sanity/blocks/test_deposit_transition.py +++ b/tests/core/pyspec/eth2spec/test/electra/sanity/blocks/test_deposit_transition.py @@ -38,7 +38,7 @@ def run_deposit_transition_block(spec, state, block, top_up_keys=[], valid=True) # Check that deposits are applied if valid: expected_pubkeys = [d.data.pubkey for d in block.body.deposits] - deposit_requests = block.body.execution_payload.deposit_requests + deposit_requests = block.body.requests.deposit_requests expected_pubkeys = expected_pubkeys + [d.pubkey for d in deposit_requests if (d.pubkey not in top_up_keys)] actual_pubkeys = [v.pubkey for v in state.validators[len(state.validators) - len(expected_pubkeys):]] @@ -102,7 +102,7 @@ def prepare_state_and_block(spec, # Assign deposits and deposit requests block.body.deposits = deposits - block.body.execution_payload.deposit_requests = deposit_requests + block.body.requests.deposit_requests = deposit_requests block.body.execution_payload.block_hash = compute_el_block_hash(spec, block.body.execution_payload, state) return state, block @@ -120,7 +120,7 @@ def test_deposit_transition__start_index_is_set(spec, state): yield from run_deposit_transition_block(spec, state, block) # deposit_requests_start_index must be set to the index of the first request - assert state.deposit_requests_start_index == block.body.execution_payload.deposit_requests[0].index + assert state.deposit_requests_start_index == block.body.requests.deposit_requests[0].index @with_phases([ELECTRA]) @@ -219,7 +219,7 @@ def test_deposit_transition__deposit_and_top_up_same_block(spec, state): # Artificially assign deposit's pubkey to a deposit request of the same block top_up_keys = [block.body.deposits[0].data.pubkey] - block.body.execution_payload.deposit_requests[0].pubkey = top_up_keys[0] + block.body.requests.deposit_requests[0].pubkey = top_up_keys[0] block.body.execution_payload.block_hash = compute_el_block_hash(spec, block.body.execution_payload, state) pre_pending_deposits = len(state.pending_balance_deposits) @@ -229,5 +229,5 @@ def test_deposit_transition__deposit_and_top_up_same_block(spec, state): # Check the top up assert len(state.pending_balance_deposits) == pre_pending_deposits + 2 assert state.pending_balance_deposits[pre_pending_deposits].amount == block.body.deposits[0].data.amount - amount_from_deposit = block.body.execution_payload.deposit_requests[0].amount + amount_from_deposit = block.body.requests.deposit_requests[0].amount assert state.pending_balance_deposits[pre_pending_deposits + 1].amount == amount_from_deposit diff --git a/tests/core/pyspec/eth2spec/test/helpers/block.py b/tests/core/pyspec/eth2spec/test/helpers/block.py index 96a0155732..4aa593898c 100644 --- a/tests/core/pyspec/eth2spec/test/helpers/block.py +++ b/tests/core/pyspec/eth2spec/test/helpers/block.py @@ -1,6 +1,6 @@ from eth2spec.test.helpers.execution_payload import build_empty_execution_payload from eth2spec.test.helpers.execution_payload import build_empty_signed_execution_payload_header -from eth2spec.test.helpers.forks import is_post_whisk, is_post_altair, is_post_bellatrix, is_post_eip7732 +from eth2spec.test.helpers.forks import is_post_whisk, is_post_altair, is_post_bellatrix, is_post_eip7732, is_post_electra from eth2spec.test.helpers.keys import privkeys, whisk_ks_initial, whisk_ks_final from eth2spec.utils import bls from eth2spec.utils.bls import only_with_bls @@ -126,6 +126,11 @@ def build_empty_block(spec, state, slot=None, proposer_index=None): if is_post_bellatrix(spec): empty_block.body.execution_payload = build_empty_execution_payload(spec, state) + if is_post_electra(spec): + empty_block.body.requests.deposit_requests = [] + empty_block.body.requests.withdrawal_requests = [] + empty_block.body.requests.consolidation_requests = [] + if is_post_whisk(spec): # Whisk opening proof ####### diff --git a/tests/core/pyspec/eth2spec/test/helpers/execution_payload.py b/tests/core/pyspec/eth2spec/test/helpers/execution_payload.py index 1fbb12d7ba..647f6adb5c 100644 --- a/tests/core/pyspec/eth2spec/test/helpers/execution_payload.py +++ b/tests/core/pyspec/eth2spec/test/helpers/execution_payload.py @@ -49,10 +49,6 @@ def get_execution_payload_header(spec, execution_payload): if is_post_deneb(spec): payload_header.blob_gas_used = execution_payload.blob_gas_used payload_header.excess_blob_gas = execution_payload.excess_blob_gas - if is_post_electra(spec): - payload_header.deposit_requests_root = spec.hash_tree_root(execution_payload.deposit_requests) - payload_header.withdrawal_requests_root = spec.hash_tree_root(execution_payload.withdrawal_requests) - payload_header.consolidation_requests_root = spec.hash_tree_root(execution_payload.consolidation_requests) return payload_header @@ -74,8 +70,7 @@ def compute_el_header_block_hash(spec, payload_header, transactions_trie_root, withdrawals_trie_root=None, - parent_beacon_block_root=None, - requests_trie_root=None): + parent_beacon_block_root=None): """ Computes the RLP execution block hash described by an `ExecutionPayloadHeader`. """ @@ -126,9 +121,6 @@ def compute_el_header_block_hash(spec, execution_payload_header_rlp.append((big_endian_int, payload_header.excess_blob_gas)) # parent_beacon_root execution_payload_header_rlp.append((Binary(32, 32), parent_beacon_block_root)) - if is_post_electra(spec): - # requests_root - execution_payload_header_rlp.append((Binary(32, 32), requests_trie_root)) sedes = List([schema for schema, _ in execution_payload_header_rlp]) values = [value for _, value in execution_payload_header_rlp] @@ -216,13 +208,6 @@ def compute_el_block_hash(spec, payload, pre_state): withdrawals_trie_root = compute_trie_root_from_indexed_data(withdrawals_encoded) if is_post_deneb(spec): parent_beacon_block_root = pre_state.latest_block_header.hash_tree_root() - if is_post_electra(spec): - requests_encoded = [] - requests_encoded += [get_deposit_request_rlp_bytes(request) for request in payload.deposit_requests] - requests_encoded += [get_withdrawal_request_rlp_bytes(request) for request in payload.withdrawal_requests] - requests_encoded += [get_consolidation_request_rlp_bytes(request) for request in payload.consolidation_requests] - - requests_trie_root = compute_trie_root_from_indexed_data(requests_encoded) payload_header = get_execution_payload_header(spec, payload) @@ -232,7 +217,6 @@ def compute_el_block_hash(spec, payload, pre_state): transactions_trie_root, withdrawals_trie_root, parent_beacon_block_root, - requests_trie_root, ) @@ -296,10 +280,6 @@ def build_empty_execution_payload(spec, state, randao_mix=None): if is_post_deneb(spec): payload.blob_gas_used = 0 payload.excess_blob_gas = 0 - if is_post_electra(spec): - payload.deposit_requests = [] - payload.withdrawal_requests = [] - payload.consolidation_requests = [] payload.block_hash = compute_el_block_hash(spec, payload, state) From 4185c00d233e982ace4af025a06eaf7d7dc0991b Mon Sep 17 00:00:00 2001 From: Lucas Saldanha Date: Tue, 13 Aug 2024 20:53:44 +1200 Subject: [PATCH 11/24] Fork fix and tests --- specs/electra/fork.md | 23 +------------------ .../eth2spec/test/helpers/electra/fork.py | 3 ++- .../test/helpers/execution_payload.py | 8 +------ .../pyspec/eth2spec/test/helpers/genesis.py | 4 ---- 4 files changed, 4 insertions(+), 34 deletions(-) diff --git a/specs/electra/fork.md b/specs/electra/fork.md index fab02ddf25..44c41ac0bf 100644 --- a/specs/electra/fork.md +++ b/specs/electra/fork.md @@ -72,28 +72,7 @@ an irregular state change is made to upgrade to Electra. ```python def upgrade_to_electra(pre: deneb.BeaconState) -> BeaconState: epoch = deneb.get_current_epoch(pre) - latest_execution_payload_header = ExecutionPayloadHeader( - parent_hash=pre.latest_execution_payload_header.parent_hash, - fee_recipient=pre.latest_execution_payload_header.fee_recipient, - state_root=pre.latest_execution_payload_header.state_root, - receipts_root=pre.latest_execution_payload_header.receipts_root, - logs_bloom=pre.latest_execution_payload_header.logs_bloom, - prev_randao=pre.latest_execution_payload_header.prev_randao, - block_number=pre.latest_execution_payload_header.block_number, - gas_limit=pre.latest_execution_payload_header.gas_limit, - gas_used=pre.latest_execution_payload_header.gas_used, - timestamp=pre.latest_execution_payload_header.timestamp, - extra_data=pre.latest_execution_payload_header.extra_data, - base_fee_per_gas=pre.latest_execution_payload_header.base_fee_per_gas, - block_hash=pre.latest_execution_payload_header.block_hash, - transactions_root=pre.latest_execution_payload_header.transactions_root, - withdrawals_root=pre.latest_execution_payload_header.withdrawals_root, - blob_gas_used=pre.latest_execution_payload_header.blob_gas_used, - excess_blob_gas=pre.latest_execution_payload_header.excess_blob_gas, - deposit_requests_root=Root(), # [New in Electra:EIP6110] - withdrawal_requests_root=Root(), # [New in Electra:EIP7002] - consolidation_requests_root=Root(), # [New in Electra:EIP7251] - ) + latest_execution_payload_header = pre.latest_execution_payload_header exit_epochs = [v.exit_epoch for v in pre.validators if v.exit_epoch != FAR_FUTURE_EPOCH] if not exit_epochs: diff --git a/tests/core/pyspec/eth2spec/test/helpers/electra/fork.py b/tests/core/pyspec/eth2spec/test/helpers/electra/fork.py index 0067a8cc07..886fc7cce0 100644 --- a/tests/core/pyspec/eth2spec/test/helpers/electra/fork.py +++ b/tests/core/pyspec/eth2spec/test/helpers/electra/fork.py @@ -38,13 +38,14 @@ def run_fork_test(post_spec, pre_state): 'next_withdrawal_index', 'next_withdrawal_validator_index', # Deep history valid from Capella onwards 'historical_summaries', + 'latest_execution_payload_header' ] for field in stable_fields: assert getattr(pre_state, field) == getattr(post_state, field) # Modified fields - modified_fields = ['fork', 'latest_execution_payload_header'] + modified_fields = ['fork'] for field in modified_fields: assert getattr(pre_state, field) != getattr(post_state, field) diff --git a/tests/core/pyspec/eth2spec/test/helpers/execution_payload.py b/tests/core/pyspec/eth2spec/test/helpers/execution_payload.py index 647f6adb5c..c2876133d4 100644 --- a/tests/core/pyspec/eth2spec/test/helpers/execution_payload.py +++ b/tests/core/pyspec/eth2spec/test/helpers/execution_payload.py @@ -7,12 +7,7 @@ from eth2spec.utils.ssz.ssz_impl import hash_tree_root from eth2spec.debug.random_value import get_random_bytes_list from eth2spec.test.helpers.withdrawals import get_expected_withdrawals -from eth2spec.test.helpers.forks import ( - is_post_capella, - is_post_deneb, - is_post_electra, - is_post_eip7732, -) +from eth2spec.test.helpers.forks import is_post_capella, is_post_deneb, is_post_eip7732 def get_execution_payload_header(spec, execution_payload): @@ -201,7 +196,6 @@ def compute_el_block_hash(spec, payload, pre_state): withdrawals_trie_root = None parent_beacon_block_root = None - requests_trie_root = None if is_post_capella(spec): withdrawals_encoded = [get_withdrawal_rlp(withdrawal) for withdrawal in payload.withdrawals] diff --git a/tests/core/pyspec/eth2spec/test/helpers/genesis.py b/tests/core/pyspec/eth2spec/test/helpers/genesis.py index 95c1e97e55..bc7d891855 100644 --- a/tests/core/pyspec/eth2spec/test/helpers/genesis.py +++ b/tests/core/pyspec/eth2spec/test/helpers/genesis.py @@ -66,14 +66,11 @@ def get_sample_genesis_execution_payload_header(spec, transactions_trie_root = bytes.fromhex("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421") withdrawals_trie_root = None parent_beacon_block_root = None - requests_trie_root = None if is_post_capella(spec): withdrawals_trie_root = bytes.fromhex("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421") if is_post_deneb(spec): parent_beacon_block_root = bytes.fromhex("0000000000000000000000000000000000000000000000000000000000000000") - if is_post_electra(spec): - requests_trie_root = bytes.fromhex("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421") payload_header.block_hash = compute_el_header_block_hash( spec, @@ -81,7 +78,6 @@ def get_sample_genesis_execution_payload_header(spec, transactions_trie_root, withdrawals_trie_root, parent_beacon_block_root, - requests_trie_root, ) return payload_header From fa78e0d30194e08e6c3b329ce75271cb63107dd8 Mon Sep 17 00:00:00 2001 From: Lucas Saldanha Date: Tue, 13 Aug 2024 21:24:28 +1200 Subject: [PATCH 12/24] PR comments --- specs/electra/beacon-chain.md | 31 ++++++++++--------- specs/electra/light-client/fork.md | 23 +------------- specs/electra/light-client/sync-protocol.md | 9 ------ .../test/electra/sanity/blocks/test_blocks.py | 8 ++--- .../sanity/blocks/test_deposit_transition.py | 10 +++--- .../pyspec/eth2spec/test/helpers/block.py | 6 ++-- 6 files changed, 30 insertions(+), 57 deletions(-) diff --git a/specs/electra/beacon-chain.md b/specs/electra/beacon-chain.md index a70960c4d5..7decb37659 100644 --- a/specs/electra/beacon-chain.md +++ b/specs/electra/beacon-chain.md @@ -30,7 +30,7 @@ - [`WithdrawalRequest`](#withdrawalrequest) - [`ConsolidationRequest`](#consolidationrequest) - [`PendingConsolidation`](#pendingconsolidation) - - [`ValidatorRequests`](#validatorrequests) + - [`ExecutionLayerRequests`](#executionlayerrequests) - [Modified Containers](#modified-containers) - [`AttesterSlashing`](#attesterslashing) - [`BeaconBlockBody`](#beaconblockbody) @@ -256,13 +256,16 @@ class PendingConsolidation(Container): target_index: ValidatorIndex ``` -#### `ValidatorRequests` +#### `ExecutionLayerRequests` + +*Note*: This container contains request from the execution layer that are received in the Execution Payload via +Engine API. These requests are required for CL state transition (see **BeaconBlockBody**). ```python -class ValidatorRequests(Container): - deposit_requests: List[DepositRequest, MAX_DEPOSIT_REQUESTS_PER_PAYLOAD] # [New in Electra:EIP6110] - withdrawal_requests: List[WithdrawalRequest, MAX_WITHDRAWAL_REQUESTS_PER_PAYLOAD] # [New in Electra:EIP7002:EIP7251] - consolidation_requests: List[ConsolidationRequest, MAX_CONSOLIDATION_REQUESTS_PER_PAYLOAD] # [New in Electra:EIP7251] +class ExecutionLayerRequests(Container): + deposits: List[DepositRequest, MAX_DEPOSIT_REQUESTS_PER_PAYLOAD] # [New in Electra:EIP6110] + withdrawals: List[WithdrawalRequest, MAX_WITHDRAWAL_REQUESTS_PER_PAYLOAD] # [New in Electra:EIP7002:EIP7251] + consolidations: List[ConsolidationRequest, MAX_CONSOLIDATION_REQUESTS_PER_PAYLOAD] # [New in Electra:EIP7251] ``` ### Modified Containers @@ -293,7 +296,7 @@ class BeaconBlockBody(Container): execution_payload: ExecutionPayload bls_to_execution_changes: List[SignedBLSToExecutionChange, MAX_BLS_TO_EXECUTION_CHANGES] blob_kzg_commitments: List[KZGCommitment, MAX_BLOB_COMMITMENTS_PER_BLOCK] - requests: ValidatorRequests # [New in Electra:EIP????] + requests: ExecutionLayerRequests # [New in Electra] ``` ### Extended Containers @@ -921,8 +924,8 @@ def process_effective_balance_updates(state: BeaconState) -> None: ```python def process_block(state: BeaconState, block: BeaconBlock) -> None: process_block_header(state, block) - process_withdrawals(state, block.body.execution_payload) # [Modified in Electra:EIP7251:EIP????] - process_execution_payload(state, block.body, EXECUTION_ENGINE) # [Modified in Electra:EIP6110:EIP????] + process_withdrawals(state, block.body.execution_payload) # [Modified in Electra:EIP7251] + process_execution_payload(state, block.body, EXECUTION_ENGINE) # [Modified in Electra:EIP6110] process_randao(state, block.body) process_eth1_data(state, block.body) process_operations(state, block.body) # [Modified in Electra:EIP6110:EIP7002:EIP7549:EIP7251] @@ -1048,11 +1051,11 @@ def process_operations(state: BeaconState, body: BeaconBlockBody) -> None: for_ops(body.deposits, process_deposit) # [Modified in Electra:EIP7251] for_ops(body.voluntary_exits, process_voluntary_exit) # [Modified in Electra:EIP7251] for_ops(body.bls_to_execution_changes, process_bls_to_execution_change) - for_ops(body.requests.deposit_requests, process_deposit_request) # [New in Electra:EIP6110:EIP????] - # [New in Electra:EIP7002:EIP7251:EIP????] - for_ops(body.requests.withdrawal_requests, process_withdrawal_request) - # [New in Electra:EIP7251:EIP????] - for_ops(body.requests.consolidation_requests, process_consolidation_request) + for_ops(body.requests.deposits, process_deposit_request) # [New in Electra:EIP6110] + # [New in Electra:EIP7002:EIP7251] + for_ops(body.requests.withdrawals, process_withdrawal_request) + # [New in Electra:EIP7251] + for_ops(body.requests.consolidations, process_consolidation_request) ``` ##### Attestations diff --git a/specs/electra/light-client/fork.md b/specs/electra/light-client/fork.md index d613df56a9..a315146b0e 100644 --- a/specs/electra/light-client/fork.md +++ b/specs/electra/light-client/fork.md @@ -39,28 +39,7 @@ A Electra `LightClientStore` can still process earlier light client data. In ord def upgrade_lc_header_to_electra(pre: deneb.LightClientHeader) -> LightClientHeader: return LightClientHeader( beacon=pre.beacon, - execution=ExecutionPayloadHeader( - parent_hash=pre.execution.parent_hash, - fee_recipient=pre.execution.fee_recipient, - state_root=pre.execution.state_root, - receipts_root=pre.execution.receipts_root, - logs_bloom=pre.execution.logs_bloom, - prev_randao=pre.execution.prev_randao, - block_number=pre.execution.block_number, - gas_limit=pre.execution.gas_limit, - gas_used=pre.execution.gas_used, - timestamp=pre.execution.timestamp, - extra_data=pre.execution.extra_data, - base_fee_per_gas=pre.execution.base_fee_per_gas, - block_hash=pre.execution.block_hash, - transactions_root=pre.execution.transactions_root, - withdrawals_root=pre.execution.withdrawals_root, - blob_gas_used=pre.execution.blob_gas_used, - excess_blob_gas=pre.execution.blob_gas_used, - deposit_requests_root=Root(), # [New in Electra:EIP6110] - withdrawal_requests_root=Root(), # [New in Electra:EIP7002:EIP7251] - consolidation_requests_root=Root(), # [New in Electra:EIP7251] - ), + execution=pre.execution, execution_branch=pre.execution_branch, ) ``` diff --git a/specs/electra/light-client/sync-protocol.md b/specs/electra/light-client/sync-protocol.md index ef9dcd5987..26da70ee34 100644 --- a/specs/electra/light-client/sync-protocol.md +++ b/specs/electra/light-client/sync-protocol.md @@ -159,15 +159,6 @@ def get_lc_execution_root(header: LightClientHeader) -> Root: def is_valid_light_client_header(header: LightClientHeader) -> bool: epoch = compute_epoch_at_slot(header.beacon.slot) - # [New in Electra:EIP6110:EIP7002:EIP7251] - if epoch < ELECTRA_FORK_EPOCH: - if ( - header.execution.deposit_requests_root != Root() - or header.execution.withdrawal_requests_root != Root() - or header.execution.consolidation_requests_root != Root() - ): - return False - if epoch < DENEB_FORK_EPOCH: if header.execution.blob_gas_used != uint64(0) or header.execution.excess_blob_gas != uint64(0): return False diff --git a/tests/core/pyspec/eth2spec/test/electra/sanity/blocks/test_blocks.py b/tests/core/pyspec/eth2spec/test/electra/sanity/blocks/test_blocks.py index 8f890b4501..8371e71f66 100644 --- a/tests/core/pyspec/eth2spec/test/electra/sanity/blocks/test_blocks.py +++ b/tests/core/pyspec/eth2spec/test/electra/sanity/blocks/test_blocks.py @@ -41,7 +41,7 @@ def test_basic_el_withdrawal_request(spec, state): validator_pubkey=validator_pubkey, ) block = build_empty_block_for_next_slot(spec, state) - block.body.requests.withdrawal_requests = [withdrawal_request] + block.body.requests.withdrawals = [withdrawal_request] block.body.execution_payload.block_hash = compute_el_block_hash(spec, block.body.execution_payload, state) signed_block = state_transition_and_sign_block(spec, state, block) @@ -77,7 +77,7 @@ def test_basic_btec_and_el_withdrawal_request_in_same_block(spec, state): source_address=address, validator_pubkey=validator_pubkey, ) - block.body.requests.withdrawal_requests = [withdrawal_request] + block.body.requests.withdrawals = [withdrawal_request] block.body.execution_payload.block_hash = compute_el_block_hash(spec, block.body.execution_payload, state) signed_block = state_transition_and_sign_block(spec, state, block) @@ -130,7 +130,7 @@ def test_basic_btec_before_el_withdrawal_request(spec, state): validator_pubkey=validator_pubkey, ) block_2 = build_empty_block_for_next_slot(spec, state) - block_2.body.requests.withdrawal_requests = [withdrawal_request] + block_2.body.requests.withdrawals = [withdrawal_request] block_2.body.execution_payload.block_hash = compute_el_block_hash(spec, block_2.body.execution_payload, state) signed_block_2 = state_transition_and_sign_block(spec, state, block_2) @@ -163,7 +163,7 @@ def test_cl_exit_and_el_withdrawal_request_in_same_block(spec, state): ) block = build_empty_block_for_next_slot(spec, state) block.body.voluntary_exits = signed_voluntary_exits - block.body.requests.withdrawal_requests = [withdrawal_request] + block.body.requests.withdrawals = [withdrawal_request] block.body.execution_payload.block_hash = compute_el_block_hash(spec, block.body.execution_payload, state) signed_block = state_transition_and_sign_block(spec, state, block) diff --git a/tests/core/pyspec/eth2spec/test/electra/sanity/blocks/test_deposit_transition.py b/tests/core/pyspec/eth2spec/test/electra/sanity/blocks/test_deposit_transition.py index a0b3b83956..98fc707d41 100644 --- a/tests/core/pyspec/eth2spec/test/electra/sanity/blocks/test_deposit_transition.py +++ b/tests/core/pyspec/eth2spec/test/electra/sanity/blocks/test_deposit_transition.py @@ -38,7 +38,7 @@ def run_deposit_transition_block(spec, state, block, top_up_keys=[], valid=True) # Check that deposits are applied if valid: expected_pubkeys = [d.data.pubkey for d in block.body.deposits] - deposit_requests = block.body.requests.deposit_requests + deposit_requests = block.body.requests.deposits expected_pubkeys = expected_pubkeys + [d.pubkey for d in deposit_requests if (d.pubkey not in top_up_keys)] actual_pubkeys = [v.pubkey for v in state.validators[len(state.validators) - len(expected_pubkeys):]] @@ -102,7 +102,7 @@ def prepare_state_and_block(spec, # Assign deposits and deposit requests block.body.deposits = deposits - block.body.requests.deposit_requests = deposit_requests + block.body.requests.deposits = deposit_requests block.body.execution_payload.block_hash = compute_el_block_hash(spec, block.body.execution_payload, state) return state, block @@ -120,7 +120,7 @@ def test_deposit_transition__start_index_is_set(spec, state): yield from run_deposit_transition_block(spec, state, block) # deposit_requests_start_index must be set to the index of the first request - assert state.deposit_requests_start_index == block.body.requests.deposit_requests[0].index + assert state.deposit_requests_start_index == block.body.requests.deposits[0].index @with_phases([ELECTRA]) @@ -219,7 +219,7 @@ def test_deposit_transition__deposit_and_top_up_same_block(spec, state): # Artificially assign deposit's pubkey to a deposit request of the same block top_up_keys = [block.body.deposits[0].data.pubkey] - block.body.requests.deposit_requests[0].pubkey = top_up_keys[0] + block.body.requests.deposits[0].pubkey = top_up_keys[0] block.body.execution_payload.block_hash = compute_el_block_hash(spec, block.body.execution_payload, state) pre_pending_deposits = len(state.pending_balance_deposits) @@ -229,5 +229,5 @@ def test_deposit_transition__deposit_and_top_up_same_block(spec, state): # Check the top up assert len(state.pending_balance_deposits) == pre_pending_deposits + 2 assert state.pending_balance_deposits[pre_pending_deposits].amount == block.body.deposits[0].data.amount - amount_from_deposit = block.body.requests.deposit_requests[0].amount + amount_from_deposit = block.body.requests.deposits[0].amount assert state.pending_balance_deposits[pre_pending_deposits + 1].amount == amount_from_deposit diff --git a/tests/core/pyspec/eth2spec/test/helpers/block.py b/tests/core/pyspec/eth2spec/test/helpers/block.py index 4aa593898c..1f96f1f608 100644 --- a/tests/core/pyspec/eth2spec/test/helpers/block.py +++ b/tests/core/pyspec/eth2spec/test/helpers/block.py @@ -127,9 +127,9 @@ def build_empty_block(spec, state, slot=None, proposer_index=None): empty_block.body.execution_payload = build_empty_execution_payload(spec, state) if is_post_electra(spec): - empty_block.body.requests.deposit_requests = [] - empty_block.body.requests.withdrawal_requests = [] - empty_block.body.requests.consolidation_requests = [] + empty_block.body.requests.deposits = [] + empty_block.body.requests.withdrawals = [] + empty_block.body.requests.consolidations = [] if is_post_whisk(spec): # Whisk opening proof From e3ec53fcdcb058cd402dee3d0bba97b5b998dc00 Mon Sep 17 00:00:00 2001 From: Lucas Saldanha Date: Wed, 14 Aug 2024 10:24:55 +1200 Subject: [PATCH 13/24] Fix lint --- specs/electra/beacon-chain.md | 2 +- tests/core/pyspec/eth2spec/test/helpers/block.py | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/specs/electra/beacon-chain.md b/specs/electra/beacon-chain.md index 7decb37659..681a1092fd 100644 --- a/specs/electra/beacon-chain.md +++ b/specs/electra/beacon-chain.md @@ -296,7 +296,7 @@ class BeaconBlockBody(Container): execution_payload: ExecutionPayload bls_to_execution_changes: List[SignedBLSToExecutionChange, MAX_BLS_TO_EXECUTION_CHANGES] blob_kzg_commitments: List[KZGCommitment, MAX_BLOB_COMMITMENTS_PER_BLOCK] - requests: ExecutionLayerRequests # [New in Electra] + requests: ExecutionLayerRequests # [New in Electra] ``` ### Extended Containers diff --git a/tests/core/pyspec/eth2spec/test/helpers/block.py b/tests/core/pyspec/eth2spec/test/helpers/block.py index 1f96f1f608..c62d70005a 100644 --- a/tests/core/pyspec/eth2spec/test/helpers/block.py +++ b/tests/core/pyspec/eth2spec/test/helpers/block.py @@ -1,6 +1,7 @@ from eth2spec.test.helpers.execution_payload import build_empty_execution_payload from eth2spec.test.helpers.execution_payload import build_empty_signed_execution_payload_header -from eth2spec.test.helpers.forks import is_post_whisk, is_post_altair, is_post_bellatrix, is_post_eip7732, is_post_electra +from eth2spec.test.helpers.forks import is_post_whisk, is_post_altair, is_post_bellatrix, is_post_eip7732, \ + is_post_electra from eth2spec.test.helpers.keys import privkeys, whisk_ks_initial, whisk_ks_final from eth2spec.utils import bls from eth2spec.utils.bls import only_with_bls From 3527a9b64113386dfc83a182d77f29ca75bd42dc Mon Sep 17 00:00:00 2001 From: Lucas Saldanha Date: Wed, 14 Aug 2024 23:16:09 +1200 Subject: [PATCH 14/24] Cleaning unchanged ExecutionPayload --- specs/electra/beacon-chain.md | 26 -------------------------- 1 file changed, 26 deletions(-) diff --git a/specs/electra/beacon-chain.md b/specs/electra/beacon-chain.md index 681a1092fd..58e0d55cdf 100644 --- a/specs/electra/beacon-chain.md +++ b/specs/electra/beacon-chain.md @@ -37,7 +37,6 @@ - [Extended Containers](#extended-containers) - [`Attestation`](#attestation) - [`IndexedAttestation`](#indexedattestation) - - [`ExecutionPayload`](#executionpayload) - [`BeaconState`](#beaconstate) - [Helper functions](#helper-functions) - [Predicates](#predicates) @@ -321,31 +320,6 @@ class IndexedAttestation(Container): signature: BLSSignature ``` -#### `ExecutionPayload` - -```python -class ExecutionPayload(Container): - # Execution block header fields - parent_hash: Hash32 - fee_recipient: ExecutionAddress - state_root: Bytes32 - receipts_root: Bytes32 - logs_bloom: ByteVector[BYTES_PER_LOGS_BLOOM] - prev_randao: Bytes32 - block_number: uint64 - gas_limit: uint64 - gas_used: uint64 - timestamp: uint64 - extra_data: ByteList[MAX_EXTRA_DATA_BYTES] - base_fee_per_gas: uint256 - # Extra payload fields - block_hash: Hash32 - transactions: List[Transaction, MAX_TRANSACTIONS_PER_PAYLOAD] - withdrawals: List[Withdrawal, MAX_WITHDRAWALS_PER_PAYLOAD] - blob_gas_used: uint64 - excess_blob_gas: uint64 -``` - #### `BeaconState` ```python From b84316de3ff86d354ad6be15563a6a73209b6913 Mon Sep 17 00:00:00 2001 From: Lucas Saldanha Date: Fri, 16 Aug 2024 18:30:06 +1200 Subject: [PATCH 15/24] PR Comments --- specs/electra/beacon-chain.md | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/specs/electra/beacon-chain.md b/specs/electra/beacon-chain.md index 58e0d55cdf..1f5246814b 100644 --- a/specs/electra/beacon-chain.md +++ b/specs/electra/beacon-chain.md @@ -257,8 +257,9 @@ class PendingConsolidation(Container): #### `ExecutionLayerRequests` -*Note*: This container contains request from the execution layer that are received in the Execution Payload via -Engine API. These requests are required for CL state transition (see **BeaconBlockBody**). +*Note*: This container holds requests from the execution layer that are received in [ +`ExecutionPayloadV4`](https://github.com/ethereum/execution-apis/blob/main/src/engine/prague.md#executionpayloadv4) via +the Engine API. These requests are required for CL state transition (see `BeaconBlockBody`). ```python class ExecutionLayerRequests(Container): @@ -1026,10 +1027,8 @@ def process_operations(state: BeaconState, body: BeaconBlockBody) -> None: for_ops(body.voluntary_exits, process_voluntary_exit) # [Modified in Electra:EIP7251] for_ops(body.bls_to_execution_changes, process_bls_to_execution_change) for_ops(body.requests.deposits, process_deposit_request) # [New in Electra:EIP6110] - # [New in Electra:EIP7002:EIP7251] - for_ops(body.requests.withdrawals, process_withdrawal_request) - # [New in Electra:EIP7251] - for_ops(body.requests.consolidations, process_consolidation_request) + for_ops(body.requests.withdrawals, process_withdrawal_request) # [New in Electra:EIP7002:EIP7251] + for_ops(body.requests.consolidations, process_consolidation_request) # [New in Electra:EIP7251] ``` ##### Attestations From 98dd1884aea37fae2fc7e3e5462a4abde34c7ced Mon Sep 17 00:00:00 2001 From: Lucas Saldanha Date: Fri, 16 Aug 2024 18:34:22 +1200 Subject: [PATCH 16/24] Rename requests to execution_requests --- specs/electra/beacon-chain.md | 8 ++++---- .../eth2spec/test/electra/sanity/blocks/test_blocks.py | 8 ++++---- .../electra/sanity/blocks/test_deposit_transition.py | 10 +++++----- tests/core/pyspec/eth2spec/test/helpers/block.py | 6 +++--- 4 files changed, 16 insertions(+), 16 deletions(-) diff --git a/specs/electra/beacon-chain.md b/specs/electra/beacon-chain.md index 1f5246814b..92be2ce253 100644 --- a/specs/electra/beacon-chain.md +++ b/specs/electra/beacon-chain.md @@ -296,7 +296,7 @@ class BeaconBlockBody(Container): execution_payload: ExecutionPayload bls_to_execution_changes: List[SignedBLSToExecutionChange, MAX_BLS_TO_EXECUTION_CHANGES] blob_kzg_commitments: List[KZGCommitment, MAX_BLOB_COMMITMENTS_PER_BLOCK] - requests: ExecutionLayerRequests # [New in Electra] + execution_requests: ExecutionLayerRequests # [New in Electra] ``` ### Extended Containers @@ -1026,9 +1026,9 @@ def process_operations(state: BeaconState, body: BeaconBlockBody) -> None: for_ops(body.deposits, process_deposit) # [Modified in Electra:EIP7251] for_ops(body.voluntary_exits, process_voluntary_exit) # [Modified in Electra:EIP7251] for_ops(body.bls_to_execution_changes, process_bls_to_execution_change) - for_ops(body.requests.deposits, process_deposit_request) # [New in Electra:EIP6110] - for_ops(body.requests.withdrawals, process_withdrawal_request) # [New in Electra:EIP7002:EIP7251] - for_ops(body.requests.consolidations, process_consolidation_request) # [New in Electra:EIP7251] + for_ops(body.execution_requests.deposits, process_deposit_request) # [New in Electra:EIP6110] + for_ops(body.execution_requests.withdrawals, process_withdrawal_request) # [New in Electra:EIP7002:EIP7251] + for_ops(body.execution_requests.consolidations, process_consolidation_request) # [New in Electra:EIP7251] ``` ##### Attestations diff --git a/tests/core/pyspec/eth2spec/test/electra/sanity/blocks/test_blocks.py b/tests/core/pyspec/eth2spec/test/electra/sanity/blocks/test_blocks.py index 8371e71f66..0bb8f32d46 100644 --- a/tests/core/pyspec/eth2spec/test/electra/sanity/blocks/test_blocks.py +++ b/tests/core/pyspec/eth2spec/test/electra/sanity/blocks/test_blocks.py @@ -41,7 +41,7 @@ def test_basic_el_withdrawal_request(spec, state): validator_pubkey=validator_pubkey, ) block = build_empty_block_for_next_slot(spec, state) - block.body.requests.withdrawals = [withdrawal_request] + block.body.execution_requests.withdrawals = [withdrawal_request] block.body.execution_payload.block_hash = compute_el_block_hash(spec, block.body.execution_payload, state) signed_block = state_transition_and_sign_block(spec, state, block) @@ -77,7 +77,7 @@ def test_basic_btec_and_el_withdrawal_request_in_same_block(spec, state): source_address=address, validator_pubkey=validator_pubkey, ) - block.body.requests.withdrawals = [withdrawal_request] + block.body.execution_requests.withdrawals = [withdrawal_request] block.body.execution_payload.block_hash = compute_el_block_hash(spec, block.body.execution_payload, state) signed_block = state_transition_and_sign_block(spec, state, block) @@ -130,7 +130,7 @@ def test_basic_btec_before_el_withdrawal_request(spec, state): validator_pubkey=validator_pubkey, ) block_2 = build_empty_block_for_next_slot(spec, state) - block_2.body.requests.withdrawals = [withdrawal_request] + block_2.body.execution_requests.withdrawals = [withdrawal_request] block_2.body.execution_payload.block_hash = compute_el_block_hash(spec, block_2.body.execution_payload, state) signed_block_2 = state_transition_and_sign_block(spec, state, block_2) @@ -163,7 +163,7 @@ def test_cl_exit_and_el_withdrawal_request_in_same_block(spec, state): ) block = build_empty_block_for_next_slot(spec, state) block.body.voluntary_exits = signed_voluntary_exits - block.body.requests.withdrawals = [withdrawal_request] + block.body.execution_requests.withdrawals = [withdrawal_request] block.body.execution_payload.block_hash = compute_el_block_hash(spec, block.body.execution_payload, state) signed_block = state_transition_and_sign_block(spec, state, block) diff --git a/tests/core/pyspec/eth2spec/test/electra/sanity/blocks/test_deposit_transition.py b/tests/core/pyspec/eth2spec/test/electra/sanity/blocks/test_deposit_transition.py index 98fc707d41..e846543f23 100644 --- a/tests/core/pyspec/eth2spec/test/electra/sanity/blocks/test_deposit_transition.py +++ b/tests/core/pyspec/eth2spec/test/electra/sanity/blocks/test_deposit_transition.py @@ -38,7 +38,7 @@ def run_deposit_transition_block(spec, state, block, top_up_keys=[], valid=True) # Check that deposits are applied if valid: expected_pubkeys = [d.data.pubkey for d in block.body.deposits] - deposit_requests = block.body.requests.deposits + deposit_requests = block.body.execution_requests.deposits expected_pubkeys = expected_pubkeys + [d.pubkey for d in deposit_requests if (d.pubkey not in top_up_keys)] actual_pubkeys = [v.pubkey for v in state.validators[len(state.validators) - len(expected_pubkeys):]] @@ -102,7 +102,7 @@ def prepare_state_and_block(spec, # Assign deposits and deposit requests block.body.deposits = deposits - block.body.requests.deposits = deposit_requests + block.body.execution_requests.deposits = deposit_requests block.body.execution_payload.block_hash = compute_el_block_hash(spec, block.body.execution_payload, state) return state, block @@ -120,7 +120,7 @@ def test_deposit_transition__start_index_is_set(spec, state): yield from run_deposit_transition_block(spec, state, block) # deposit_requests_start_index must be set to the index of the first request - assert state.deposit_requests_start_index == block.body.requests.deposits[0].index + assert state.deposit_requests_start_index == block.body.execution_requests.deposits[0].index @with_phases([ELECTRA]) @@ -219,7 +219,7 @@ def test_deposit_transition__deposit_and_top_up_same_block(spec, state): # Artificially assign deposit's pubkey to a deposit request of the same block top_up_keys = [block.body.deposits[0].data.pubkey] - block.body.requests.deposits[0].pubkey = top_up_keys[0] + block.body.execution_requests.deposits[0].pubkey = top_up_keys[0] block.body.execution_payload.block_hash = compute_el_block_hash(spec, block.body.execution_payload, state) pre_pending_deposits = len(state.pending_balance_deposits) @@ -229,5 +229,5 @@ def test_deposit_transition__deposit_and_top_up_same_block(spec, state): # Check the top up assert len(state.pending_balance_deposits) == pre_pending_deposits + 2 assert state.pending_balance_deposits[pre_pending_deposits].amount == block.body.deposits[0].data.amount - amount_from_deposit = block.body.requests.deposits[0].amount + amount_from_deposit = block.body.execution_requests.deposits[0].amount assert state.pending_balance_deposits[pre_pending_deposits + 1].amount == amount_from_deposit diff --git a/tests/core/pyspec/eth2spec/test/helpers/block.py b/tests/core/pyspec/eth2spec/test/helpers/block.py index c62d70005a..f862488c11 100644 --- a/tests/core/pyspec/eth2spec/test/helpers/block.py +++ b/tests/core/pyspec/eth2spec/test/helpers/block.py @@ -128,9 +128,9 @@ def build_empty_block(spec, state, slot=None, proposer_index=None): empty_block.body.execution_payload = build_empty_execution_payload(spec, state) if is_post_electra(spec): - empty_block.body.requests.deposits = [] - empty_block.body.requests.withdrawals = [] - empty_block.body.requests.consolidations = [] + empty_block.body.execution_requests.deposits = [] + empty_block.body.execution_requests.withdrawals = [] + empty_block.body.execution_requests.consolidations = [] if is_post_whisk(spec): # Whisk opening proof From dc1892e1131aa8b515983ffcbc7726ae85357d45 Mon Sep 17 00:00:00 2001 From: Lucas Saldanha Date: Thu, 22 Aug 2024 21:08:08 +1200 Subject: [PATCH 17/24] Updated NewPayloadRequest --- specs/electra/beacon-chain.md | 71 +++++++++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) diff --git a/specs/electra/beacon-chain.md b/specs/electra/beacon-chain.md index 92be2ce253..3c04947d4b 100644 --- a/specs/electra/beacon-chain.md +++ b/specs/electra/beacon-chain.md @@ -73,10 +73,15 @@ - [New `process_pending_balance_deposits`](#new-process_pending_balance_deposits) - [New `process_pending_consolidations`](#new-process_pending_consolidations) - [Modified `process_effective_balance_updates`](#modified-process_effective_balance_updates) + - [Execution engine](#execution-engine) + - [Request data](#request-data) + - [Modified `NewPayloadRequest`](#modified-newpayloadrequest) - [Block processing](#block-processing) - [Withdrawals](#withdrawals) - [Modified `get_expected_withdrawals`](#modified-get_expected_withdrawals) - [Modified `process_withdrawals`](#modified-process_withdrawals) + - [Execution payload](#execution-payload) + - [Modified `process_execution_payload`](#modified-process_execution_payload) - [Operations](#operations) - [Modified `process_operations`](#modified-process_operations) - [Attestations](#attestations) @@ -894,6 +899,21 @@ def process_effective_balance_updates(state: BeaconState) -> None: validator.effective_balance = min(balance - balance % EFFECTIVE_BALANCE_INCREMENT, EFFECTIVE_BALANCE_LIMIT) ``` +### Execution engine + +#### Request data + +##### Modified `NewPayloadRequest` + +```python +@dataclass +class NewPayloadRequest(object): + execution_payload: ExecutionPayload + execution_requests: ExecutionLayerRequests + versioned_hashes: Sequence[VersionedHash] + parent_beacon_block_root: Root +``` + ### Block processing ```python @@ -1000,6 +1020,57 @@ def process_withdrawals(state: BeaconState, payload: ExecutionPayload) -> None: next_validator_index = ValidatorIndex(next_index % len(state.validators)) state.next_withdrawal_validator_index = next_validator_index ``` + +#### Execution payload + +##### Modified `process_execution_payload` + +*Note*: The function `process_execution_payload` is modified to pass `execution_requests` into `execution_engine.verify_and_notify_new_payload` (via the updated `NewPayloadRequest`). + +```python +def process_execution_payload(state: BeaconState, body: BeaconBlockBody, execution_engine: ExecutionEngine) -> None: + payload = body.execution_payload + + # Verify consistency of the parent hash with respect to the previous execution payload header + assert payload.parent_hash == state.latest_execution_payload_header.block_hash + # Verify prev_randao + assert payload.prev_randao == get_randao_mix(state, get_current_epoch(state)) + # Verify timestamp + assert payload.timestamp == compute_timestamp_at_slot(state, state.slot) + # Verify commitments are under limit + assert len(body.blob_kzg_commitments) <= MAX_BLOBS_PER_BLOCK + # Verify the execution payload is valid + versioned_hashes = [kzg_commitment_to_versioned_hash(commitment) for commitment in body.blob_kzg_commitments] + assert execution_engine.verify_and_notify_new_payload( + NewPayloadRequest( + execution_payload=payload, + execution_requests=body.execution_requests, # [New in Electra] + versioned_hashes=versioned_hashes, + parent_beacon_block_root=state.latest_block_header.parent_root, + ) + ) + # Cache execution payload header + state.latest_execution_payload_header = ExecutionPayloadHeader( + parent_hash=payload.parent_hash, + fee_recipient=payload.fee_recipient, + state_root=payload.state_root, + receipts_root=payload.receipts_root, + logs_bloom=payload.logs_bloom, + prev_randao=payload.prev_randao, + block_number=payload.block_number, + gas_limit=payload.gas_limit, + gas_used=payload.gas_used, + timestamp=payload.timestamp, + extra_data=payload.extra_data, + base_fee_per_gas=payload.base_fee_per_gas, + block_hash=payload.block_hash, + transactions_root=hash_tree_root(payload.transactions), + withdrawals_root=hash_tree_root(payload.withdrawals), + blob_gas_used=payload.blob_gas_used, + excess_blob_gas=payload.excess_blob_gas + ) +``` + #### Operations ##### Modified `process_operations` From b8ca7cc87b158e52110db698af5a23cf54c2754c Mon Sep 17 00:00:00 2001 From: Lucas Saldanha Date: Fri, 23 Aug 2024 10:12:19 +1200 Subject: [PATCH 18/24] PR comments --- specs/electra/beacon-chain.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/specs/electra/beacon-chain.md b/specs/electra/beacon-chain.md index 3c04947d4b..12de51e290 100644 --- a/specs/electra/beacon-chain.md +++ b/specs/electra/beacon-chain.md @@ -909,9 +909,9 @@ def process_effective_balance_updates(state: BeaconState) -> None: @dataclass class NewPayloadRequest(object): execution_payload: ExecutionPayload - execution_requests: ExecutionLayerRequests versioned_hashes: Sequence[VersionedHash] parent_beacon_block_root: Root + execution_requests: ExecutionLayerRequests # [New in Electra] ``` ### Block processing @@ -1067,7 +1067,7 @@ def process_execution_payload(state: BeaconState, body: BeaconBlockBody, executi transactions_root=hash_tree_root(payload.transactions), withdrawals_root=hash_tree_root(payload.withdrawals), blob_gas_used=payload.blob_gas_used, - excess_blob_gas=payload.excess_blob_gas + excess_blob_gas=payload.excess_blob_gas, ) ``` From 38baa573c7bde6df0e1bac8e42a9b32743a19ab3 Mon Sep 17 00:00:00 2001 From: Lucas Saldanha Date: Mon, 2 Sep 2024 11:30:54 +1200 Subject: [PATCH 19/24] Rename ExecutionLayerRequests to ExecutionRequests --- specs/electra/beacon-chain.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/specs/electra/beacon-chain.md b/specs/electra/beacon-chain.md index f93c327caa..f3d5667770 100644 --- a/specs/electra/beacon-chain.md +++ b/specs/electra/beacon-chain.md @@ -30,7 +30,7 @@ - [`WithdrawalRequest`](#withdrawalrequest) - [`ConsolidationRequest`](#consolidationrequest) - [`PendingConsolidation`](#pendingconsolidation) - - [`ExecutionLayerRequests`](#executionlayerrequests) + - [`ExecutionRequests`](#executionrequests) - [Modified Containers](#modified-containers) - [`AttesterSlashing`](#attesterslashing) - [`BeaconBlockBody`](#beaconblockbody) @@ -260,14 +260,14 @@ class PendingConsolidation(Container): target_index: ValidatorIndex ``` -#### `ExecutionLayerRequests` +#### `ExecutionRequests` *Note*: This container holds requests from the execution layer that are received in [ `ExecutionPayloadV4`](https://github.com/ethereum/execution-apis/blob/main/src/engine/prague.md#executionpayloadv4) via the Engine API. These requests are required for CL state transition (see `BeaconBlockBody`). ```python -class ExecutionLayerRequests(Container): +class ExecutionRequests(Container): deposits: List[DepositRequest, MAX_DEPOSIT_REQUESTS_PER_PAYLOAD] # [New in Electra:EIP6110] withdrawals: List[WithdrawalRequest, MAX_WITHDRAWAL_REQUESTS_PER_PAYLOAD] # [New in Electra:EIP7002:EIP7251] consolidations: List[ConsolidationRequest, MAX_CONSOLIDATION_REQUESTS_PER_PAYLOAD] # [New in Electra:EIP7251] @@ -301,7 +301,7 @@ class BeaconBlockBody(Container): execution_payload: ExecutionPayload bls_to_execution_changes: List[SignedBLSToExecutionChange, MAX_BLS_TO_EXECUTION_CHANGES] blob_kzg_commitments: List[KZGCommitment, MAX_BLOB_COMMITMENTS_PER_BLOCK] - execution_requests: ExecutionLayerRequests # [New in Electra] + execution_requests: ExecutionRequests # [New in Electra] ``` ### Extended Containers @@ -911,7 +911,7 @@ class NewPayloadRequest(object): execution_payload: ExecutionPayload versioned_hashes: Sequence[VersionedHash] parent_beacon_block_root: Root - execution_requests: ExecutionLayerRequests # [New in Electra] + execution_requests: ExecutionRequests # [New in Electra] ``` ### Block processing From 31225f1acf3f1e3f1e50033fdb314a4a6e82a4bc Mon Sep 17 00:00:00 2001 From: Lucas Saldanha Date: Mon, 2 Sep 2024 13:56:57 +1200 Subject: [PATCH 20/24] Temp fix for linter on eip-7732 beacon chain spec --- specs/_features/eip7732/beacon-chain.md | 1 + 1 file changed, 1 insertion(+) diff --git a/specs/_features/eip7732/beacon-chain.md b/specs/_features/eip7732/beacon-chain.md index 6ce30cea72..068fff0b01 100644 --- a/specs/_features/eip7732/beacon-chain.md +++ b/specs/_features/eip7732/beacon-chain.md @@ -655,6 +655,7 @@ def process_execution_payload(state: BeaconState, execution_payload=payload, versioned_hashes=versioned_hashes, parent_beacon_block_root=state.latest_block_header.parent_root, + execution_requests=ExecutionRequests(), # TODO: fix me (making linter happy) ) ) From abf382a60760a9bf60d660ada6a117f57fb2ac45 Mon Sep 17 00:00:00 2001 From: Potuz Date: Wed, 4 Sep 2024 12:58:50 -0300 Subject: [PATCH 21/24] Fix 7732 --- specs/_features/eip7732/beacon-chain.md | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/specs/_features/eip7732/beacon-chain.md b/specs/_features/eip7732/beacon-chain.md index 068fff0b01..9df736750a 100644 --- a/specs/_features/eip7732/beacon-chain.md +++ b/specs/_features/eip7732/beacon-chain.md @@ -156,6 +156,7 @@ class SignedExecutionPayloadHeader(Container): ```python class ExecutionPayloadEnvelope(Container): payload: ExecutionPayload + execution_requests: ExecutionRequests builder_index: ValidatorIndex beacon_block_root: Root blob_kzg_commitments: List[KZGCommitment, MAX_BLOB_COMMITMENTS_PER_BLOCK] @@ -175,7 +176,7 @@ class SignedExecutionPayloadEnvelope(Container): #### `BeaconBlockBody` -**Note:** The Beacon Block body is modified to contain a `Signed ExecutionPayloadHeader`. The containers `BeaconBlock` and `SignedBeaconBlock` are modified indirectly. +**Note:** The Beacon Block body is modified to contain a `Signed ExecutionPayloadHeader`. The containers `BeaconBlock` and `SignedBeaconBlock` are modified indirectly. The field `execution_requests` is removed from the beacon block body and moved into the signed execution payload envelope. ```python class BeaconBlockBody(Container): @@ -191,8 +192,9 @@ class BeaconBlockBody(Container): sync_aggregate: SyncAggregate # Execution # Removed execution_payload [Removed in EIP-7732] - # Removed blob_kzg_commitments [Removed in EIP-7732] bls_to_execution_changes: List[SignedBLSToExecutionChange, MAX_BLS_TO_EXECUTION_CHANGES] + # Removed blob_kzg_commitments [Removed in EIP-7732] + # Removed execution_requests [Removed in EIP-7732] # PBS signed_execution_payload_header: SignedExecutionPayloadHeader # [New in EIP-7732] payload_attestations: List[PayloadAttestation, MAX_PAYLOAD_ATTESTATIONS] # [New in EIP-7732] @@ -650,12 +652,13 @@ def process_execution_payload(state: BeaconState, # Verify the execution payload is valid versioned_hashes = [kzg_commitment_to_versioned_hash(commitment) for commitment in envelope.blob_kzg_commitments] + requests = envelope.execution_requests assert execution_engine.verify_and_notify_new_payload( NewPayloadRequest( execution_payload=payload, versioned_hashes=versioned_hashes, parent_beacon_block_root=state.latest_block_header.parent_root, - execution_requests=ExecutionRequests(), # TODO: fix me (making linter happy) + execution_requests=requests, ) ) @@ -664,9 +667,9 @@ def process_execution_payload(state: BeaconState, for operation in operations: fn(state, operation) - for_ops(payload.deposit_requests, process_deposit_request) - for_ops(payload.withdrawal_requests, process_withdrawal_request) - for_ops(payload.consolidation_requests, process_consolidation_request) + for_ops(requests.deposit_requests, process_deposit_request) + for_ops(requests.withdrawal_requests, process_withdrawal_request) + for_ops(requests.consolidation_requests, process_consolidation_request) # Cache the execution payload header and proposer state.latest_block_hash = payload.block_hash From beff03d4e0b330323a89669754ebdc9a1b308cfb Mon Sep 17 00:00:00 2001 From: Lucas Saldanha Date: Fri, 6 Sep 2024 09:18:26 +1200 Subject: [PATCH 22/24] Updated verify_and_notify_new_payload and notify_new_payload --- specs/electra/beacon-chain.md | 48 +++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/specs/electra/beacon-chain.md b/specs/electra/beacon-chain.md index f3d5667770..8f6ef2d351 100644 --- a/specs/electra/beacon-chain.md +++ b/specs/electra/beacon-chain.md @@ -76,6 +76,9 @@ - [Execution engine](#execution-engine) - [Request data](#request-data) - [Modified `NewPayloadRequest`](#modified-newpayloadrequest) + - [Engine APIs](#engine-apis) + - [Modified `notify_new_payload`](#modified-notify_new_payload) + - [Modified `verify_and_notify_new_payload`](#modified-verify_and_notify_new_payload) - [Block processing](#block-processing) - [Withdrawals](#withdrawals) - [Modified `get_expected_withdrawals`](#modified-get_expected_withdrawals) @@ -914,6 +917,51 @@ class NewPayloadRequest(object): execution_requests: ExecutionRequests # [New in Electra] ``` +#### Engine APIs + +##### Modified `notify_new_payload` + +*Note*: The function `notify_new_payload` is modified to include the additional `execution_requests` parameter in Electra. + +```python +def notify_new_payload(self: ExecutionEngine, + execution_payload: ExecutionPayload, + execution_requests: ExecutionRequests, + parent_beacon_block_root: Root) -> bool: + """ + Return ``True`` if and only if ``execution_payload`` and ``execution_requests`` are valid with respect to ``self.execution_state``. + """ + ... +``` + +##### Modified `verify_and_notify_new_payload` + +*Note*: The function `verify_and_notify_new_payload` is modified to pass the additional parameter `execution_requests` +when calling `notify_new_payload` in Electra. + +```python +def verify_and_notify_new_payload(self: ExecutionEngine, + new_payload_request: NewPayloadRequest) -> bool: + """ + Return ``True`` if and only if ``new_payload_request`` is valid with respect to ``self.execution_state``. + """ + execution_payload = new_payload_request.execution_payload + execution_requests = new_payload_request.execution_requests # [New in Electra] + parent_beacon_block_root = new_payload_request.parent_beacon_block_root + + if not self.is_valid_block_hash(execution_payload, parent_beacon_block_root): + return False + + if not self.is_valid_versioned_hashes(new_payload_request): + return False + + # [Modified in Electra] + if not self.notify_new_payload(execution_payload, execution_requests, parent_beacon_block_root): + return False + + return True +``` + ### Block processing ```python From c8dd790484cc75a4d2873b9120cf4928ceb428a6 Mon Sep 17 00:00:00 2001 From: Lucas Saldanha Date: Fri, 6 Sep 2024 09:51:34 +1200 Subject: [PATCH 23/24] Fix linter --- specs/electra/beacon-chain.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/specs/electra/beacon-chain.md b/specs/electra/beacon-chain.md index 8f6ef2d351..8e54914367 100644 --- a/specs/electra/beacon-chain.md +++ b/specs/electra/beacon-chain.md @@ -929,7 +929,8 @@ def notify_new_payload(self: ExecutionEngine, execution_requests: ExecutionRequests, parent_beacon_block_root: Root) -> bool: """ - Return ``True`` if and only if ``execution_payload`` and ``execution_requests`` are valid with respect to ``self.execution_state``. + Return ``True`` if and only if ``execution_payload`` and ``execution_requests`` + are valid with respect to ``self.execution_state``. """ ... ``` @@ -956,7 +957,10 @@ def verify_and_notify_new_payload(self: ExecutionEngine, return False # [Modified in Electra] - if not self.notify_new_payload(execution_payload, execution_requests, parent_beacon_block_root): + if not self.notify_new_payload( + execution_payload, + execution_requests, + parent_beacon_block_root): return False return True From 622ccd1d4bd1a06e51a381ecb98fc65ea63aa41b Mon Sep 17 00:00:00 2001 From: Lucas Saldanha Date: Fri, 6 Sep 2024 10:08:36 +1200 Subject: [PATCH 24/24] Updated ElectraSpecBuilder (NoopExecutionEngine#notify_new_payload) --- pysetup/spec_builders/electra.py | 38 ++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/pysetup/spec_builders/electra.py b/pysetup/spec_builders/electra.py index ca02ee927c..2ab1f5ecfb 100644 --- a/pysetup/spec_builders/electra.py +++ b/pysetup/spec_builders/electra.py @@ -19,3 +19,41 @@ def hardcoded_ssz_dep_constants(cls) -> Dict[str, str]: 'CURRENT_SYNC_COMMITTEE_GINDEX_ELECTRA': 'GeneralizedIndex(86)', 'NEXT_SYNC_COMMITTEE_GINDEX_ELECTRA': 'GeneralizedIndex(87)', } + + + @classmethod + def execution_engine_cls(cls) -> str: + return """ +class NoopExecutionEngine(ExecutionEngine): + + def notify_new_payload(self: ExecutionEngine, + execution_payload: ExecutionPayload, + execution_requests: ExecutionRequests, + parent_beacon_block_root: Root) -> bool: + return True + + def notify_forkchoice_updated(self: ExecutionEngine, + head_block_hash: Hash32, + safe_block_hash: Hash32, + finalized_block_hash: Hash32, + payload_attributes: Optional[PayloadAttributes]) -> Optional[PayloadId]: + pass + + def get_payload(self: ExecutionEngine, payload_id: PayloadId) -> GetPayloadResponse: + # pylint: disable=unused-argument + raise NotImplementedError("no default block production") + + def is_valid_block_hash(self: ExecutionEngine, + execution_payload: ExecutionPayload, + parent_beacon_block_root: Root) -> bool: + return True + + def is_valid_versioned_hashes(self: ExecutionEngine, new_payload_request: NewPayloadRequest) -> bool: + return True + + def verify_and_notify_new_payload(self: ExecutionEngine, + new_payload_request: NewPayloadRequest) -> bool: + return True + + +EXECUTION_ENGINE = NoopExecutionEngine()""" \ No newline at end of file