mirror of
https://github.com/status-im/eth2.0-specs.git
synced 2025-02-26 01:05:15 +00:00
Merge branch 'dev' into deneb-tests
This commit is contained in:
commit
f1765dfef3
@ -60,7 +60,7 @@ commands:
|
||||
jobs:
|
||||
checkout_specs:
|
||||
docker:
|
||||
- image: circleci/python:3.8
|
||||
- image: circleci/python:3.9
|
||||
working_directory: ~/specs-repo
|
||||
steps:
|
||||
# Restore git repo at point close to target branch/revision, to speed up checkout
|
||||
@ -80,7 +80,7 @@ jobs:
|
||||
- ~/specs-repo
|
||||
install_pyspec_test:
|
||||
docker:
|
||||
- image: circleci/python:3.8
|
||||
- image: circleci/python:3.9
|
||||
working_directory: ~/specs-repo
|
||||
steps:
|
||||
- restore_cache:
|
||||
@ -92,7 +92,7 @@ jobs:
|
||||
- save_pyspec_cached_venv
|
||||
test-phase0:
|
||||
docker:
|
||||
- image: circleci/python:3.8
|
||||
- image: circleci/python:3.9
|
||||
working_directory: ~/specs-repo
|
||||
steps:
|
||||
- restore_cache:
|
||||
@ -105,7 +105,7 @@ jobs:
|
||||
path: tests/core/pyspec/test-reports
|
||||
test-altair:
|
||||
docker:
|
||||
- image: circleci/python:3.8
|
||||
- image: circleci/python:3.9
|
||||
working_directory: ~/specs-repo
|
||||
steps:
|
||||
- restore_cache:
|
||||
@ -118,7 +118,7 @@ jobs:
|
||||
path: tests/core/pyspec/test-reports
|
||||
test-bellatrix:
|
||||
docker:
|
||||
- image: circleci/python:3.8
|
||||
- image: circleci/python:3.9
|
||||
working_directory: ~/specs-repo
|
||||
steps:
|
||||
- restore_cache:
|
||||
@ -131,7 +131,7 @@ jobs:
|
||||
path: tests/core/pyspec/test-reports
|
||||
test-capella:
|
||||
docker:
|
||||
- image: circleci/python:3.8
|
||||
- image: circleci/python:3.9
|
||||
working_directory: ~/specs-repo
|
||||
steps:
|
||||
- restore_cache:
|
||||
@ -144,7 +144,7 @@ jobs:
|
||||
path: tests/core/pyspec/test-reports
|
||||
test-deneb:
|
||||
docker:
|
||||
- image: circleci/python:3.8
|
||||
- image: circleci/python:3.9
|
||||
working_directory: ~/specs-repo
|
||||
steps:
|
||||
- restore_cache:
|
||||
@ -155,6 +155,19 @@ jobs:
|
||||
command: make citest fork=deneb
|
||||
- store_test_results:
|
||||
path: tests/core/pyspec/test-reports
|
||||
test-eip6110:
|
||||
docker:
|
||||
- image: circleci/python:3.8
|
||||
working_directory: ~/specs-repo
|
||||
steps:
|
||||
- restore_cache:
|
||||
key: v3-specs-repo-{{ .Branch }}-{{ .Revision }}
|
||||
- restore_pyspec_cached_venv
|
||||
- run:
|
||||
name: Run py-tests
|
||||
command: make citest fork=eip6110
|
||||
- store_test_results:
|
||||
path: tests/core/pyspec/test-reports
|
||||
table_of_contents:
|
||||
docker:
|
||||
- image: circleci/node:10.16.3
|
||||
@ -166,7 +179,7 @@ jobs:
|
||||
command: sudo npm install -g doctoc@2 && make check_toc
|
||||
codespell:
|
||||
docker:
|
||||
- image: circleci/python:3.8
|
||||
- image: circleci/python:3.9
|
||||
working_directory: ~/specs-repo
|
||||
steps:
|
||||
- checkout
|
||||
@ -175,7 +188,7 @@ jobs:
|
||||
command: pip install 'codespell<3.0.0,>=2.0.0' --user && make codespell
|
||||
lint:
|
||||
docker:
|
||||
- image: circleci/python:3.8
|
||||
- image: circleci/python:3.9
|
||||
working_directory: ~/specs-repo
|
||||
steps:
|
||||
- restore_cache:
|
||||
@ -231,7 +244,7 @@ jobs:
|
||||
- /nix
|
||||
install_deposit_contract_web3_tester:
|
||||
docker:
|
||||
- image: circleci/python:3.8
|
||||
- image: circleci/python:3.9
|
||||
working_directory: ~/specs-repo
|
||||
steps:
|
||||
- restore_cache:
|
||||
@ -243,7 +256,7 @@ jobs:
|
||||
- save_deposit_contract_tester_cached_venv
|
||||
test_deposit_contract_web3_tests:
|
||||
docker:
|
||||
- image: circleci/python:3.8
|
||||
- image: circleci/python:3.9
|
||||
working_directory: ~/specs-repo
|
||||
steps:
|
||||
- restore_cache:
|
||||
@ -275,6 +288,9 @@ workflows:
|
||||
- test-deneb:
|
||||
requires:
|
||||
- install_pyspec_test
|
||||
- test-eip6110:
|
||||
requires:
|
||||
- install_pyspec_test
|
||||
- table_of_contents
|
||||
- codespell
|
||||
- lint:
|
||||
|
2
.github/workflows/run-tests.yml
vendored
2
.github/workflows/run-tests.yml
vendored
@ -83,7 +83,7 @@ jobs:
|
||||
needs: [preclear,lint,codespell,table_of_contents]
|
||||
strategy:
|
||||
matrix:
|
||||
version: ["phase0", "altair", "bellatrix", "capella", "deneb"]
|
||||
version: ["phase0", "altair", "bellatrix", "capella", "deneb", "eip6110"]
|
||||
steps:
|
||||
- name: Checkout this repo
|
||||
uses: actions/checkout@v3.2.0
|
||||
|
@ -50,8 +50,9 @@ CAPELLA_FORK_EPOCH: 194048 # April 12, 2023, 10:27:35pm UTC
|
||||
# Deneb
|
||||
DENEB_FORK_VERSION: 0x04000000
|
||||
DENEB_FORK_EPOCH: 18446744073709551615
|
||||
|
||||
|
||||
# EIP6110
|
||||
EIP6110_FORK_VERSION: 0x05000000 # temporary stub
|
||||
EIP6110_FORK_EPOCH: 18446744073709551615
|
||||
|
||||
|
||||
# Time parameters
|
||||
|
@ -49,6 +49,9 @@ CAPELLA_FORK_EPOCH: 18446744073709551615
|
||||
# DENEB
|
||||
DENEB_FORK_VERSION: 0x04000001
|
||||
DENEB_FORK_EPOCH: 18446744073709551615
|
||||
# EIP6110
|
||||
EIP6110_FORK_VERSION: 0x05000001
|
||||
EIP6110_FORK_EPOCH: 18446744073709551615
|
||||
|
||||
|
||||
# Time parameters
|
||||
|
6
presets/mainnet/eip6110.yaml
Normal file
6
presets/mainnet/eip6110.yaml
Normal file
@ -0,0 +1,6 @@
|
||||
# Mainnet preset - EIP6110
|
||||
|
||||
# Execution
|
||||
# ---------------------------------------------------------------
|
||||
# 2**13 (= 8192) receipts
|
||||
MAX_DEPOSIT_RECEIPTS_PER_PAYLOAD: 8192
|
6
presets/minimal/eip6110.yaml
Normal file
6
presets/minimal/eip6110.yaml
Normal file
@ -0,0 +1,6 @@
|
||||
# Minimal preset - EIP6110
|
||||
|
||||
# Execution
|
||||
# ---------------------------------------------------------------
|
||||
# [customized]
|
||||
MAX_DEPOSIT_RECEIPTS_PER_PAYLOAD: 4
|
12
setup.py
12
setup.py
@ -671,13 +671,13 @@ def retrieve_blobs_and_proofs(beacon_block_root: Root) -> PyUnion[Tuple[Blob, KZ
|
||||
#
|
||||
# EIP6110SpecBuilder
|
||||
#
|
||||
class EIP6110SpecBuilder(CapellaSpecBuilder):
|
||||
class EIP6110SpecBuilder(DenebSpecBuilder):
|
||||
fork: str = EIP6110
|
||||
|
||||
@classmethod
|
||||
def imports(cls, preset_name: str):
|
||||
return super().imports(preset_name) + f'''
|
||||
from eth2spec.capella import {preset_name} as capella
|
||||
from eth2spec.deneb import {preset_name} as deneb
|
||||
'''
|
||||
|
||||
|
||||
@ -1022,7 +1022,7 @@ class PySpecCommand(Command):
|
||||
specs/capella/validator.md
|
||||
specs/capella/p2p-interface.md
|
||||
"""
|
||||
if self.spec_fork == DENEB:
|
||||
if self.spec_fork in (DENEB, EIP6110):
|
||||
self.md_doc_paths += """
|
||||
specs/deneb/light-client/fork.md
|
||||
specs/deneb/light-client/full-node.md
|
||||
@ -1037,6 +1037,10 @@ class PySpecCommand(Command):
|
||||
"""
|
||||
if self.spec_fork == EIP6110:
|
||||
self.md_doc_paths += """
|
||||
specs/_features/eip6110/light-client/fork.md
|
||||
specs/_features/eip6110/light-client/full-node.md
|
||||
specs/_features/eip6110/light-client/p2p-interface.md
|
||||
specs/_features/eip6110/light-client/sync-protocol.md
|
||||
specs/_features/eip6110/beacon-chain.md
|
||||
specs/_features/eip6110/fork.md
|
||||
"""
|
||||
@ -1176,7 +1180,7 @@ setup(
|
||||
packages=find_packages(where='tests/core/pyspec') + ['configs', 'specs'],
|
||||
py_modules=["eth2spec"],
|
||||
cmdclass=commands,
|
||||
python_requires=">=3.8, <4",
|
||||
python_requires=">=3.9, <4",
|
||||
extras_require={
|
||||
"test": ["pytest>=4.4", "pytest-cov", "pytest-xdist"],
|
||||
"lint": ["flake8==5.0.4", "mypy==0.981", "pylint==2.15.3"],
|
||||
|
@ -33,7 +33,7 @@
|
||||
This is the beacon chain specification of in-protocol deposits processing mechanism.
|
||||
This mechanism relies on the changes proposed by [EIP-6110](http://eips.ethereum.org/EIPS/eip-6110).
|
||||
|
||||
*Note:* This specification is built upon [Capella](../../capella/beacon-chain.md) and is under active development.
|
||||
*Note:* This specification is built upon [Deneb](../../deneb/beacon-chain.md) and is under active development.
|
||||
|
||||
## Constants
|
||||
|
||||
@ -91,7 +91,8 @@ class ExecutionPayload(Container):
|
||||
block_hash: Hash32
|
||||
transactions: List[Transaction, MAX_TRANSACTIONS_PER_PAYLOAD]
|
||||
withdrawals: List[Withdrawal, MAX_WITHDRAWALS_PER_PAYLOAD]
|
||||
deposit_receipts: List[DepositReceipt, MAX_DEPOSIT_RECEIPTS_PER_PAYLOAD] # [New in EIP-6110]
|
||||
excess_data_gas: uint256
|
||||
deposit_receipts: List[DepositReceipt, MAX_DEPOSIT_RECEIPTS_PER_PAYLOAD] # [New in EIP6110]
|
||||
```
|
||||
|
||||
#### `ExecutionPayloadHeader`
|
||||
@ -115,7 +116,8 @@ class ExecutionPayloadHeader(Container):
|
||||
block_hash: Hash32
|
||||
transactions_root: Root
|
||||
withdrawals_root: Root
|
||||
deposit_receipts_root: Root # [New in EIP-6110]
|
||||
excess_data_gas: uint256
|
||||
deposit_receipts_root: Root # [New in EIP6110]
|
||||
```
|
||||
|
||||
#### `BeaconState`
|
||||
@ -157,13 +159,13 @@ class BeaconState(Container):
|
||||
current_sync_committee: SyncCommittee
|
||||
next_sync_committee: SyncCommittee
|
||||
# Execution
|
||||
latest_execution_payload_header: ExecutionPayloadHeader
|
||||
latest_execution_payload_header: ExecutionPayloadHeader # [Modified in EIP6110]
|
||||
# Withdrawals
|
||||
next_withdrawal_index: WithdrawalIndex
|
||||
next_withdrawal_validator_index: ValidatorIndex
|
||||
# Deep history valid from Capella onwards
|
||||
historical_summaries: List[HistoricalSummary, HISTORICAL_ROOTS_LIMIT]
|
||||
# [New in EIP-6110]
|
||||
# [New in EIP6110]
|
||||
deposit_receipts_start_index: uint64
|
||||
```
|
||||
|
||||
@ -176,11 +178,12 @@ def process_block(state: BeaconState, block: BeaconBlock) -> None:
|
||||
process_block_header(state, block)
|
||||
if is_execution_enabled(state, block.body):
|
||||
process_withdrawals(state, block.body.execution_payload)
|
||||
process_execution_payload(state, block.body.execution_payload, EXECUTION_ENGINE) # [Modified in EIP-6110]
|
||||
process_execution_payload(state, block.body.execution_payload, EXECUTION_ENGINE) # [Modified in EIP6110]
|
||||
process_randao(state, block.body)
|
||||
process_eth1_data(state, block.body)
|
||||
process_operations(state, block.body) # [Modified in EIP-6110]
|
||||
process_operations(state, block.body) # [Modified in EIP6110]
|
||||
process_sync_aggregate(state, block.body.sync_aggregate)
|
||||
process_blob_kzg_commitments(block.body)
|
||||
```
|
||||
|
||||
#### Modified `process_operations`
|
||||
@ -189,7 +192,7 @@ def process_block(state: BeaconState, block: BeaconBlock) -> None:
|
||||
|
||||
```python
|
||||
def process_operations(state: BeaconState, body: BeaconBlockBody) -> None:
|
||||
# [Modified in EIP-6110]
|
||||
# [Modified in EIP6110]
|
||||
# Disable former deposit mechanism once all prior deposits are processed
|
||||
eth1_deposit_index_limit = min(state.eth1_data.deposit_count, state.deposit_receipts_start_index)
|
||||
if state.eth1_deposit_index < eth1_deposit_index_limit:
|
||||
@ -204,11 +207,11 @@ def process_operations(state: BeaconState, body: BeaconBlockBody) -> None:
|
||||
for_ops(body.proposer_slashings, process_proposer_slashing)
|
||||
for_ops(body.attester_slashings, process_attester_slashing)
|
||||
for_ops(body.attestations, process_attestation)
|
||||
for_ops(body.deposits, process_deposit) # [Modified in EIP-6110]
|
||||
for_ops(body.deposits, process_deposit)
|
||||
for_ops(body.voluntary_exits, process_voluntary_exit)
|
||||
for_ops(body.bls_to_execution_changes, process_bls_to_execution_change)
|
||||
|
||||
# [New in EIP-6110]
|
||||
# [New in EIP6110]
|
||||
if is_execution_enabled(state, body):
|
||||
for_ops(body.execution_payload.deposit_receipts, process_deposit_receipt)
|
||||
```
|
||||
@ -262,7 +265,8 @@ def process_execution_payload(state: BeaconState, payload: ExecutionPayload, exe
|
||||
block_hash=payload.block_hash,
|
||||
transactions_root=hash_tree_root(payload.transactions),
|
||||
withdrawals_root=hash_tree_root(payload.withdrawals),
|
||||
deposit_receipts_root=hash_tree_root(payload.deposit_receipts), # [New in EIP-6110]
|
||||
excess_data_gas=payload.excess_data_gas,
|
||||
deposit_receipts_root=hash_tree_root(payload.deposit_receipts), # [New in EIP6110]
|
||||
)
|
||||
```
|
||||
|
||||
|
@ -43,7 +43,9 @@ def compute_fork_version(epoch: Epoch) -> Version:
|
||||
Return the fork version at the given ``epoch``.
|
||||
"""
|
||||
if epoch >= EIP6110_FORK_EPOCH:
|
||||
return EIP6110_FORK_EPOCH
|
||||
return EIP6110_FORK_VERSION
|
||||
if epoch >= DENEB_FORK_EPOCH:
|
||||
return DENEB_FORK_VERSION
|
||||
if epoch >= CAPELLA_FORK_EPOCH:
|
||||
return CAPELLA_FORK_VERSION
|
||||
if epoch >= BELLATRIX_FORK_EPOCH:
|
||||
@ -68,8 +70,8 @@ If `state.slot % SLOTS_PER_EPOCH == 0` and `compute_epoch_at_slot(state.slot) ==
|
||||
an irregular state change is made to upgrade to EIP-6110.
|
||||
|
||||
```python
|
||||
def upgrade_to_eip6110(pre: capella.BeaconState) -> BeaconState:
|
||||
epoch = capella.get_current_epoch(pre)
|
||||
def upgrade_to_eip6110(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,
|
||||
@ -86,6 +88,7 @@ def upgrade_to_eip6110(pre: capella.BeaconState) -> BeaconState:
|
||||
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,
|
||||
excess_data_gas=uint256(0),
|
||||
deposit_receipts_root=Root(), # [New in EIP-6110]
|
||||
)
|
||||
post = BeaconState(
|
||||
|
112
specs/_features/eip6110/light-client/fork.md
Normal file
112
specs/_features/eip6110/light-client/fork.md
Normal file
@ -0,0 +1,112 @@
|
||||
# EIP-6110 Light Client -- Fork Logic
|
||||
|
||||
## Table of contents
|
||||
|
||||
<!-- TOC -->
|
||||
<!-- START doctoc generated TOC please keep comment here to allow auto update -->
|
||||
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
|
||||
|
||||
- [Introduction](#introduction)
|
||||
- [Upgrading light client data](#upgrading-light-client-data)
|
||||
- [Upgrading the store](#upgrading-the-store)
|
||||
|
||||
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
|
||||
<!-- /TOC -->
|
||||
|
||||
## Introduction
|
||||
|
||||
This document describes how to upgrade existing light client objects based on the [Deneb specification](../../deneb/light-client/sync-protocol.md) to eip6110. This is necessary when processing pre-eip6110 data with a post-eip6110 `LightClientStore`. Note that the data being exchanged over the network protocols uses the original format.
|
||||
|
||||
### Upgrading light client data
|
||||
|
||||
A eip6110 `LightClientStore` can still process earlier light client data. In order to do so, that pre-eip6110 data needs to be locally upgraded to eip6110 before processing.
|
||||
|
||||
```python
|
||||
def upgrade_lc_header_to_eip6110(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,
|
||||
excess_data_gas=pre.execution.excess_data_gas,
|
||||
deposit_receipts_root=Root(), # [New in EIP6110]
|
||||
),
|
||||
execution_branch=pre.execution_branch,
|
||||
)
|
||||
```
|
||||
|
||||
```python
|
||||
def upgrade_lc_bootstrap_to_eip6110(pre: deneb.LightClientBootstrap) -> LightClientBootstrap:
|
||||
return LightClientBootstrap(
|
||||
header=upgrade_lc_header_to_eip6110(pre.header),
|
||||
current_sync_committee=pre.current_sync_committee,
|
||||
current_sync_committee_branch=pre.current_sync_committee_branch,
|
||||
)
|
||||
```
|
||||
|
||||
```python
|
||||
def upgrade_lc_update_to_eip6110(pre: deneb.LightClientUpdate) -> LightClientUpdate:
|
||||
return LightClientUpdate(
|
||||
attested_header=upgrade_lc_header_to_eip6110(pre.attested_header),
|
||||
next_sync_committee=pre.next_sync_committee,
|
||||
next_sync_committee_branch=pre.next_sync_committee_branch,
|
||||
finalized_header=upgrade_lc_header_to_eip6110(pre.finalized_header),
|
||||
finality_branch=pre.finality_branch,
|
||||
sync_aggregate=pre.sync_aggregate,
|
||||
signature_slot=pre.signature_slot,
|
||||
)
|
||||
```
|
||||
|
||||
```python
|
||||
def upgrade_lc_finality_update_to_eip6110(pre: deneb.LightClientFinalityUpdate) -> LightClientFinalityUpdate:
|
||||
return LightClientFinalityUpdate(
|
||||
attested_header=upgrade_lc_header_to_eip6110(pre.attested_header),
|
||||
finalized_header=upgrade_lc_header_to_eip6110(pre.finalized_header),
|
||||
finality_branch=pre.finality_branch,
|
||||
sync_aggregate=pre.sync_aggregate,
|
||||
signature_slot=pre.signature_slot,
|
||||
)
|
||||
```
|
||||
|
||||
```python
|
||||
def upgrade_lc_optimistic_update_to_eip6110(pre: deneb.LightClientOptimisticUpdate) -> LightClientOptimisticUpdate:
|
||||
return LightClientOptimisticUpdate(
|
||||
attested_header=upgrade_lc_header_to_eip6110(pre.attested_header),
|
||||
sync_aggregate=pre.sync_aggregate,
|
||||
signature_slot=pre.signature_slot,
|
||||
)
|
||||
```
|
||||
|
||||
### Upgrading the store
|
||||
|
||||
Existing `LightClientStore` objects based on Deneb MUST be upgraded to eip6110 before eip6110 based light client data can be processed. The `LightClientStore` upgrade MAY be performed before `EIP6110_FORK_EPOCH`.
|
||||
|
||||
```python
|
||||
def upgrade_lc_store_to_eip6110(pre: deneb.LightClientStore) -> LightClientStore:
|
||||
if pre.best_valid_update is None:
|
||||
best_valid_update = None
|
||||
else:
|
||||
best_valid_update = upgrade_lc_update_to_eip6110(pre.best_valid_update)
|
||||
return LightClientStore(
|
||||
finalized_header=upgrade_lc_header_to_eip6110(pre.finalized_header),
|
||||
current_sync_committee=pre.current_sync_committee,
|
||||
next_sync_committee=pre.next_sync_committee,
|
||||
best_valid_update=best_valid_update,
|
||||
optimistic_header=upgrade_lc_header_to_eip6110(pre.optimistic_header),
|
||||
previous_max_active_participants=pre.previous_max_active_participants,
|
||||
current_max_active_participants=pre.current_max_active_participants,
|
||||
)
|
||||
```
|
77
specs/_features/eip6110/light-client/full-node.md
Normal file
77
specs/_features/eip6110/light-client/full-node.md
Normal file
@ -0,0 +1,77 @@
|
||||
# EIP-6110 Light Client -- Full Node
|
||||
|
||||
**Notice**: This document is a work-in-progress for researchers and implementers.
|
||||
|
||||
## Table of contents
|
||||
|
||||
<!-- TOC -->
|
||||
<!-- START doctoc generated TOC please keep comment here to allow auto update -->
|
||||
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
|
||||
|
||||
- [Introduction](#introduction)
|
||||
- [Helper functions](#helper-functions)
|
||||
- [Modified `block_to_light_client_header`](#modified-block_to_light_client_header)
|
||||
|
||||
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
|
||||
<!-- /TOC -->
|
||||
|
||||
## Introduction
|
||||
|
||||
This upgrade adds information about the execution payload to light client data as part of the EIP-6110 upgrade.
|
||||
|
||||
## Helper functions
|
||||
|
||||
### Modified `block_to_light_client_header`
|
||||
|
||||
```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
|
||||
execution_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),
|
||||
)
|
||||
|
||||
if epoch >= DENEB_FORK_EPOCH:
|
||||
execution_header.excess_data_gas = payload.excess_data_gas
|
||||
|
||||
# [New in EIP6110]
|
||||
if epoch >= EIP6110_FORK_EPOCH:
|
||||
execution_header.deposit_receipts_root = hash_tree_root(payload.deposit_receipts)
|
||||
|
||||
execution_branch = compute_merkle_proof_for_block_body(block.message.body, EXECUTION_PAYLOAD_INDEX)
|
||||
else:
|
||||
# Note that during fork transitions, `finalized_header` may still point to earlier forks.
|
||||
# While Bellatrix blocks also contain an `ExecutionPayload` (minus `withdrawals_root`),
|
||||
# it was not included in the corresponding light client data. To ensure compatibility
|
||||
# with legacy data going through `upgrade_lc_header_to_capella`, leave out execution data.
|
||||
execution_header = ExecutionPayloadHeader()
|
||||
execution_branch = [Bytes32() for _ in range(floorlog2(EXECUTION_PAYLOAD_INDEX))]
|
||||
|
||||
return LightClientHeader(
|
||||
beacon=BeaconBlockHeader(
|
||||
slot=block.message.slot,
|
||||
proposer_index=block.message.proposer_index,
|
||||
parent_root=block.message.parent_root,
|
||||
state_root=block.message.state_root,
|
||||
body_root=hash_tree_root(block.message.body),
|
||||
),
|
||||
execution=execution_header,
|
||||
execution_branch=execution_branch,
|
||||
)
|
||||
```
|
111
specs/_features/eip6110/light-client/p2p-interface.md
Normal file
111
specs/_features/eip6110/light-client/p2p-interface.md
Normal file
@ -0,0 +1,111 @@
|
||||
# EIP-6110 Light Client -- Networking
|
||||
|
||||
**Notice**: This document is a work-in-progress for researchers and implementers.
|
||||
|
||||
## Table of contents
|
||||
|
||||
<!-- TOC -->
|
||||
<!-- START doctoc generated TOC please keep comment here to allow auto update -->
|
||||
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
|
||||
|
||||
- [Networking](#networking)
|
||||
- [The gossip domain: gossipsub](#the-gossip-domain-gossipsub)
|
||||
- [Topics and messages](#topics-and-messages)
|
||||
- [Global topics](#global-topics)
|
||||
- [`light_client_finality_update`](#light_client_finality_update)
|
||||
- [`light_client_optimistic_update`](#light_client_optimistic_update)
|
||||
- [The Req/Resp domain](#the-reqresp-domain)
|
||||
- [Messages](#messages)
|
||||
- [GetLightClientBootstrap](#getlightclientbootstrap)
|
||||
- [LightClientUpdatesByRange](#lightclientupdatesbyrange)
|
||||
- [GetLightClientFinalityUpdate](#getlightclientfinalityupdate)
|
||||
- [GetLightClientOptimisticUpdate](#getlightclientoptimisticupdate)
|
||||
|
||||
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
|
||||
<!-- /TOC -->
|
||||
|
||||
## Networking
|
||||
|
||||
The [Deneb light client networking specification](../../deneb/light-client/p2p-interface.md) is extended to exchange [EIP-6110 light client data](./sync-protocol.md).
|
||||
|
||||
### The gossip domain: gossipsub
|
||||
|
||||
#### Topics and messages
|
||||
|
||||
##### Global topics
|
||||
|
||||
###### `light_client_finality_update`
|
||||
|
||||
[0]: # (eth2spec: skip)
|
||||
|
||||
| `fork_version` | Message SSZ type |
|
||||
|--------------------------------------------------------|-------------------------------------|
|
||||
| `GENESIS_FORK_VERSION` | n/a |
|
||||
| `ALTAIR_FORK_VERSION` through `BELLATRIX_FORK_VERSION` | `altair.LightClientFinalityUpdate` |
|
||||
| `CAPELLA_FORK_VERSION` | `capella.LightClientFinalityUpdate` |
|
||||
| `DENEB_FORK_VERSION` | `deneb.LightClientFinalityUpdate` |
|
||||
| `EIP6110_FORK_VERSION` and later | `eip6110.LightClientFinalityUpdate` |
|
||||
|
||||
###### `light_client_optimistic_update`
|
||||
|
||||
[0]: # (eth2spec: skip)
|
||||
|
||||
| `fork_version` | Message SSZ type |
|
||||
|--------------------------------------------------------|---------------------------------------|
|
||||
| `GENESIS_FORK_VERSION` | n/a |
|
||||
| `ALTAIR_FORK_VERSION` through `BELLATRIX_FORK_VERSION` | `altair.LightClientOptimisticUpdate` |
|
||||
| `CAPELLA_FORK_VERSION` | `capella.LightClientOptimisticUpdate` |
|
||||
| `DENEB_FORK_VERSION` | `deneb.LightClientOptimisticUpdate` |
|
||||
| `EIP6110_FORK_VERSION` and later | `eip6110.LightClientOptimisticUpdate` |
|
||||
|
||||
### The Req/Resp domain
|
||||
|
||||
#### Messages
|
||||
|
||||
##### GetLightClientBootstrap
|
||||
|
||||
[0]: # (eth2spec: skip)
|
||||
|
||||
| `fork_version` | Response SSZ type |
|
||||
|--------------------------------------------------------|------------------------------------|
|
||||
| `GENESIS_FORK_VERSION` | n/a |
|
||||
| `ALTAIR_FORK_VERSION` through `BELLATRIX_FORK_VERSION` | `altair.LightClientBootstrap` |
|
||||
| `CAPELLA_FORK_VERSION` | `capella.LightClientBootstrap` |
|
||||
| `DENEB_FORK_VERSION` | `deneb.LightClientBootstrap` |
|
||||
| `EIP6110_FORK_VERSION` and later | `eip6110.LightClientBootstrap` |
|
||||
|
||||
##### LightClientUpdatesByRange
|
||||
|
||||
[0]: # (eth2spec: skip)
|
||||
|
||||
| `fork_version` | Response chunk SSZ type |
|
||||
|--------------------------------------------------------|----------------------------------|
|
||||
| `GENESIS_FORK_VERSION` | n/a |
|
||||
| `ALTAIR_FORK_VERSION` through `BELLATRIX_FORK_VERSION` | `altair.LightClientUpdate` |
|
||||
| `CAPELLA_FORK_VERSION` | `capella.LightClientUpdate` |
|
||||
| `DENEB_FORK_VERSION` | `deneb.LightClientUpdate` |
|
||||
| `EIP6110_FORK_VERSION` and later | `eip6110.LightClientUpdate` |
|
||||
|
||||
##### GetLightClientFinalityUpdate
|
||||
|
||||
[0]: # (eth2spec: skip)
|
||||
|
||||
| `fork_version` | Response SSZ type |
|
||||
|--------------------------------------------------------|-------------------------------------|
|
||||
| `GENESIS_FORK_VERSION` | n/a |
|
||||
| `ALTAIR_FORK_VERSION` through `BELLATRIX_FORK_VERSION` | `altair.LightClientFinalityUpdate` |
|
||||
| `CAPELLA_FORK_VERSION` | `capella.LightClientFinalityUpdate` |
|
||||
| `DENEB_FORK_VERSION` | `deneb.LightClientFinalityUpdate` |
|
||||
| `EIP6110_FORK_VERSION` and later | `eip6110.LightClientFinalityUpdate` |
|
||||
|
||||
##### GetLightClientOptimisticUpdate
|
||||
|
||||
[0]: # (eth2spec: skip)
|
||||
|
||||
| `fork_version` | Response SSZ type |
|
||||
|--------------------------------------------------------|---------------------------------------|
|
||||
| `GENESIS_FORK_VERSION` | n/a |
|
||||
| `ALTAIR_FORK_VERSION` through `BELLATRIX_FORK_VERSION` | `altair.LightClientOptimisticUpdate` |
|
||||
| `CAPELLA_FORK_VERSION` | `capella.LightClientOptimisticUpdate` |
|
||||
| `DENEB_FORK_VERSION` | `deneb.LightClientOptimisticUpdate` |
|
||||
| `EIP6110_FORK_VERSION` and later | `eip6110.LightClientOptimisticUpdate` |
|
89
specs/_features/eip6110/light-client/sync-protocol.md
Normal file
89
specs/_features/eip6110/light-client/sync-protocol.md
Normal file
@ -0,0 +1,89 @@
|
||||
# EIP-6110 Light Client -- Sync Protocol
|
||||
|
||||
**Notice**: This document is a work-in-progress for researchers and implementers.
|
||||
|
||||
## Table of contents
|
||||
|
||||
<!-- TOC -->
|
||||
<!-- START doctoc generated TOC please keep comment here to allow auto update -->
|
||||
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
|
||||
|
||||
- [Introduction](#introduction)
|
||||
- [Helper functions](#helper-functions)
|
||||
- [Modified `get_lc_execution_root`](#modified-get_lc_execution_root)
|
||||
- [Modified `is_valid_light_client_header`](#modified-is_valid_light_client_header)
|
||||
|
||||
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
|
||||
<!-- /TOC -->
|
||||
|
||||
## Introduction
|
||||
|
||||
This upgrade updates light client data to include the EIP-6110 changes to the [`ExecutionPayload`](../beacon-chain.md) structure. It extends the [Deneb Light Client specifications](../../deneb/light-client/sync-protocol.md). The [fork document](./fork.md) explains how to upgrade existing Deneb based deployments to EIP-6110.
|
||||
|
||||
Additional documents describes the impact of the upgrade on certain roles:
|
||||
- [Full node](./full-node.md)
|
||||
- [Networking](./p2p-interface.md)
|
||||
|
||||
## Helper functions
|
||||
|
||||
### Modified `get_lc_execution_root`
|
||||
|
||||
```python
|
||||
def get_lc_execution_root(header: LightClientHeader) -> Root:
|
||||
epoch = compute_epoch_at_slot(header.beacon.slot)
|
||||
|
||||
if epoch >= DENEB_FORK_EPOCH:
|
||||
return hash_tree_root(header.execution)
|
||||
|
||||
if epoch >= CAPELLA_FORK_EPOCH:
|
||||
execution_header = capella.ExecutionPayloadHeader(
|
||||
parent_hash=header.execution.parent_hash,
|
||||
fee_recipient=header.execution.fee_recipient,
|
||||
state_root=header.execution.state_root,
|
||||
receipts_root=header.execution.receipts_root,
|
||||
logs_bloom=header.execution.logs_bloom,
|
||||
prev_randao=header.execution.prev_randao,
|
||||
block_number=header.execution.block_number,
|
||||
gas_limit=header.execution.gas_limit,
|
||||
gas_used=header.execution.gas_used,
|
||||
timestamp=header.execution.timestamp,
|
||||
extra_data=header.execution.extra_data,
|
||||
base_fee_per_gas=header.execution.base_fee_per_gas,
|
||||
block_hash=header.execution.block_hash,
|
||||
transactions_root=header.execution.transactions_root,
|
||||
withdrawals_root=header.execution.withdrawals_root,
|
||||
)
|
||||
return hash_tree_root(execution_header)
|
||||
|
||||
return Root()
|
||||
```
|
||||
|
||||
### Modified `is_valid_light_client_header`
|
||||
|
||||
```python
|
||||
def is_valid_light_client_header(header: LightClientHeader) -> bool:
|
||||
epoch = compute_epoch_at_slot(header.beacon.slot)
|
||||
|
||||
# [New in EIP-6110]
|
||||
if epoch < EIP6110_FORK_EPOCH:
|
||||
if header.execution.deposit_receipts_root != Root():
|
||||
return False
|
||||
|
||||
if epoch < DENEB_FORK_EPOCH:
|
||||
if header.execution.excess_data_gas != uint256(0):
|
||||
return False
|
||||
|
||||
if epoch < CAPELLA_FORK_EPOCH:
|
||||
return (
|
||||
header.execution == ExecutionPayloadHeader()
|
||||
and header.execution_branch == [Bytes32() for _ in range(floorlog2(EXECUTION_PAYLOAD_INDEX))]
|
||||
)
|
||||
|
||||
return is_valid_merkle_branch(
|
||||
leaf=get_lc_execution_root(header),
|
||||
branch=header.execution_branch,
|
||||
depth=floorlog2(EXECUTION_PAYLOAD_INDEX),
|
||||
index=get_subtree_index(EXECUTION_PAYLOAD_INDEX),
|
||||
root=header.beacon.body_root,
|
||||
)
|
||||
```
|
@ -20,7 +20,7 @@ This document represents the changes to be made in the code of an "honest valida
|
||||
|
||||
## Prerequisites
|
||||
|
||||
This document is an extension of the [Capella -- Honest Validator](../../capella/validator.md) guide.
|
||||
This document is an extension of the [Deneb -- Honest Validator](../../deneb/validator.md) guide.
|
||||
All behaviors and definitions defined in this document, and documents it extends, carry over unless explicitly noted or overridden.
|
||||
|
||||
All terminology, constants, functions, and protocol mechanics defined in the updated Beacon Chain doc of [EIP-6110](./beacon-chain.md) are requisite for this document and used throughout.
|
||||
|
@ -170,7 +170,12 @@ def on_block(store: Store, signed_block: SignedBeaconBlock) -> None:
|
||||
finalized_slot = compute_start_slot_at_epoch(store.finalized_checkpoint.epoch)
|
||||
assert block.slot > finalized_slot
|
||||
# Check block is a descendant of the finalized block at the checkpoint finalized slot
|
||||
assert get_ancestor(store, block.parent_root, finalized_slot) == store.finalized_checkpoint.root
|
||||
finalized_checkpoint_block = get_checkpoint_block(
|
||||
store,
|
||||
block.parent_root,
|
||||
store.finalized_checkpoint.epoch,
|
||||
)
|
||||
assert store.finalized_checkpoint.root == finalized_checkpoint_block
|
||||
|
||||
# Check the block is valid and compute the post-state
|
||||
state = pre_state.copy()
|
||||
|
@ -82,7 +82,12 @@ def on_block(store: Store, signed_block: SignedBeaconBlock) -> None:
|
||||
finalized_slot = compute_start_slot_at_epoch(store.finalized_checkpoint.epoch)
|
||||
assert block.slot > finalized_slot
|
||||
# Check block is a descendant of the finalized block at the checkpoint finalized slot
|
||||
assert get_ancestor(store, block.parent_root, finalized_slot) == store.finalized_checkpoint.root
|
||||
finalized_checkpoint_block = get_checkpoint_block(
|
||||
store,
|
||||
block.parent_root,
|
||||
store.finalized_checkpoint.epoch,
|
||||
)
|
||||
assert store.finalized_checkpoint.root == finalized_checkpoint_block
|
||||
|
||||
# [New in Deneb]
|
||||
# Check if blob data is available
|
||||
|
@ -41,6 +41,7 @@ def upgrade_lc_header_to_deneb(pre: capella.LightClientHeader) -> LightClientHea
|
||||
block_hash=pre.execution.block_hash,
|
||||
transactions_root=pre.execution.transactions_root,
|
||||
withdrawals_root=pre.execution.withdrawals_root,
|
||||
excess_data_gas=uint256(0), # [New in Deneb]
|
||||
),
|
||||
execution_branch=pre.execution_branch,
|
||||
)
|
||||
|
@ -18,6 +18,7 @@
|
||||
- [`get_current_slot`](#get_current_slot)
|
||||
- [`compute_slots_since_epoch_start`](#compute_slots_since_epoch_start)
|
||||
- [`get_ancestor`](#get_ancestor)
|
||||
- [`get_checkpoint_block`](#get_checkpoint_block)
|
||||
- [`get_weight`](#get_weight)
|
||||
- [`get_voting_source`](#get_voting_source)
|
||||
- [`filter_block_tree`](#filter_block_tree)
|
||||
@ -190,6 +191,17 @@ def get_ancestor(store: Store, root: Root, slot: Slot) -> Root:
|
||||
return root
|
||||
```
|
||||
|
||||
#### `get_checkpoint_block`
|
||||
|
||||
```python
|
||||
def get_checkpoint_block(store: Store, root: Root, epoch: Epoch) -> Root:
|
||||
"""
|
||||
Compute the checkpoint block for epoch ``epoch`` in the chain of block ``root``
|
||||
"""
|
||||
epoch_first_slot = compute_start_slot_at_epoch(epoch)
|
||||
return get_ancestor(store, root, epoch_first_slot)
|
||||
```
|
||||
|
||||
#### `get_weight`
|
||||
|
||||
```python
|
||||
@ -276,10 +288,15 @@ def filter_block_tree(store: Store, block_root: Root, blocks: Dict[Root, BeaconB
|
||||
voting_source.epoch + 2 >= current_epoch
|
||||
)
|
||||
|
||||
finalized_slot = compute_start_slot_at_epoch(store.finalized_checkpoint.epoch)
|
||||
finalized_checkpoint_block = get_checkpoint_block(
|
||||
store,
|
||||
block_root,
|
||||
store.finalized_checkpoint.epoch,
|
||||
)
|
||||
|
||||
correct_finalized = (
|
||||
store.finalized_checkpoint.epoch == GENESIS_EPOCH
|
||||
or store.finalized_checkpoint.root == get_ancestor(store, block_root, finalized_slot)
|
||||
or store.finalized_checkpoint.root == finalized_checkpoint_block
|
||||
)
|
||||
|
||||
# If expected finalized/justified, add to viable block-tree and signal viability to parent.
|
||||
@ -440,8 +457,7 @@ def validate_on_attestation(store: Store, attestation: Attestation, is_from_bloc
|
||||
assert store.blocks[attestation.data.beacon_block_root].slot <= attestation.data.slot
|
||||
|
||||
# LMD vote must be consistent with FFG vote target
|
||||
target_slot = compute_start_slot_at_epoch(target.epoch)
|
||||
assert target.root == get_ancestor(store, attestation.data.beacon_block_root, target_slot)
|
||||
assert target.root == get_checkpoint_block(store, attestation.data.beacon_block_root, target.epoch)
|
||||
|
||||
# Attestations can only affect the fork choice of subsequent slots.
|
||||
# Delay consideration in the fork choice until their slot is in the past.
|
||||
@ -504,7 +520,12 @@ def on_block(store: Store, signed_block: SignedBeaconBlock) -> None:
|
||||
finalized_slot = compute_start_slot_at_epoch(store.finalized_checkpoint.epoch)
|
||||
assert block.slot > finalized_slot
|
||||
# Check block is a descendant of the finalized block at the checkpoint finalized slot
|
||||
assert get_ancestor(store, block.parent_root, finalized_slot) == store.finalized_checkpoint.root
|
||||
finalized_checkpoint_block = get_checkpoint_block(
|
||||
store,
|
||||
block.parent_root,
|
||||
store.finalized_checkpoint.epoch,
|
||||
)
|
||||
assert store.finalized_checkpoint.root == finalized_checkpoint_block
|
||||
|
||||
# Check the block is valid and compute the post-state
|
||||
state = pre_state.copy()
|
||||
|
@ -317,7 +317,7 @@ The following validations MUST pass before forwarding the `signed_beacon_block`
|
||||
- _[REJECT]_ The block's parent (defined by `block.parent_root`) passes validation.
|
||||
- _[REJECT]_ The block is from a higher slot than its parent.
|
||||
- _[REJECT]_ The current `finalized_checkpoint` is an ancestor of `block` -- i.e.
|
||||
`get_ancestor(store, block.parent_root, compute_start_slot_at_epoch(store.finalized_checkpoint.epoch))
|
||||
`get_checkpoint_block(store, block.parent_root, store.finalized_checkpoint.epoch)
|
||||
== store.finalized_checkpoint.root`
|
||||
- _[REJECT]_ The block is proposed by the expected `proposer_index` for the block's slot
|
||||
in the context of the current shuffling (defined by `parent_root`/`slot`).
|
||||
@ -356,7 +356,7 @@ The following validations MUST pass before forwarding the `signed_aggregate_and_
|
||||
(a client MAY queue aggregates for processing once block is retrieved).
|
||||
- _[REJECT]_ The block being voted for (`aggregate.data.beacon_block_root`) passes validation.
|
||||
- _[IGNORE]_ The current `finalized_checkpoint` is an ancestor of the `block` defined by `aggregate.data.beacon_block_root` -- i.e.
|
||||
`get_ancestor(store, aggregate.data.beacon_block_root, compute_start_slot_at_epoch(store.finalized_checkpoint.epoch))
|
||||
`get_checkpoint_block(store, aggregate.data.beacon_block_root, finalized_checkpoint.epoch)
|
||||
== store.finalized_checkpoint.root`
|
||||
|
||||
|
||||
@ -425,9 +425,9 @@ The following validations MUST pass before forwarding the `attestation` on the s
|
||||
(a client MAY queue attestations for processing once block is retrieved).
|
||||
- _[REJECT]_ The block being voted for (`attestation.data.beacon_block_root`) passes validation.
|
||||
- _[REJECT]_ The attestation's target block is an ancestor of the block named in the LMD vote -- i.e.
|
||||
`get_ancestor(store, attestation.data.beacon_block_root, compute_start_slot_at_epoch(attestation.data.target.epoch)) == attestation.data.target.root`
|
||||
`get_checkpoint_block(store, attestation.data.beacon_block_root, attestation.data.target.epoch) == attestation.data.target.root`
|
||||
- _[IGNORE]_ The current `finalized_checkpoint` is an ancestor of the `block` defined by `attestation.data.beacon_block_root` -- i.e.
|
||||
`get_ancestor(store, attestation.data.beacon_block_root, compute_start_slot_at_epoch(store.finalized_checkpoint.epoch))
|
||||
`get_checkpoint_block(store, attestation.data.beacon_block_root, store.finalized_checkpoint.epoch)
|
||||
== store.finalized_checkpoint.root`
|
||||
|
||||
|
||||
|
@ -26,6 +26,7 @@ from eth2spec.test.helpers.fork_transition import (
|
||||
from eth2spec.test.helpers.forks import (
|
||||
is_post_capella, is_post_deneb,
|
||||
is_post_fork,
|
||||
is_post_eip6110,
|
||||
)
|
||||
from eth2spec.test.helpers.light_client import (
|
||||
get_sync_aggregate,
|
||||
@ -57,6 +58,10 @@ def needs_upgrade_to_deneb(d_spec, s_spec):
|
||||
return is_post_deneb(s_spec) and not is_post_deneb(d_spec)
|
||||
|
||||
|
||||
def needs_upgrade_to_eip6110(d_spec, s_spec):
|
||||
return is_post_eip6110(s_spec) and not is_post_eip6110(d_spec)
|
||||
|
||||
|
||||
def check_lc_header_equal(d_spec, s_spec, data, upgraded):
|
||||
assert upgraded.beacon.slot == data.beacon.slot
|
||||
assert upgraded.beacon.hash_tree_root() == data.beacon.hash_tree_root()
|
||||
@ -84,6 +89,10 @@ def upgrade_lc_bootstrap_to_store(d_spec, s_spec, data):
|
||||
upgraded = s_spec.upgrade_lc_bootstrap_to_deneb(upgraded)
|
||||
check_lc_bootstrap_equal(d_spec, s_spec, data, upgraded)
|
||||
|
||||
if needs_upgrade_to_eip6110(d_spec, s_spec):
|
||||
upgraded = s_spec.upgrade_lc_bootstrap_to_eip6110(upgraded)
|
||||
check_lc_bootstrap_equal(d_spec, s_spec, data, upgraded)
|
||||
|
||||
return upgraded
|
||||
|
||||
|
||||
@ -145,6 +154,8 @@ class LightClientSyncTest(object):
|
||||
|
||||
|
||||
def get_store_fork_version(s_spec):
|
||||
if is_post_eip6110(s_spec):
|
||||
return s_spec.config.EIP6110_FORK_VERSION
|
||||
if is_post_deneb(s_spec):
|
||||
return s_spec.config.DENEB_FORK_VERSION
|
||||
if is_post_capella(s_spec):
|
||||
|
@ -8,11 +8,13 @@ from eth2spec.altair import mainnet as spec_altair_mainnet, minimal as spec_alta
|
||||
from eth2spec.bellatrix import mainnet as spec_bellatrix_mainnet, minimal as spec_bellatrix_minimal
|
||||
from eth2spec.capella import mainnet as spec_capella_mainnet, minimal as spec_capella_minimal
|
||||
from eth2spec.deneb import mainnet as spec_deneb_mainnet, minimal as spec_deneb_minimal
|
||||
from eth2spec.eip6110 import mainnet as spec_eip6110_mainnet, minimal as spec_eip6110_minimal
|
||||
from eth2spec.utils import bls
|
||||
|
||||
from .exceptions import SkippedTest
|
||||
from .helpers.constants import (
|
||||
PHASE0, ALTAIR, BELLATRIX, CAPELLA, DENEB,
|
||||
EIP6110,
|
||||
MINIMAL, MAINNET,
|
||||
ALL_PHASES,
|
||||
ALL_FORK_UPGRADES,
|
||||
@ -79,13 +81,15 @@ spec_targets: Dict[PresetBaseName, Dict[SpecForkName, Spec]] = {
|
||||
BELLATRIX: spec_bellatrix_minimal,
|
||||
CAPELLA: spec_capella_minimal,
|
||||
DENEB: spec_deneb_minimal,
|
||||
EIP6110: spec_eip6110_minimal,
|
||||
},
|
||||
MAINNET: {
|
||||
PHASE0: spec_phase0_mainnet,
|
||||
ALTAIR: spec_altair_mainnet,
|
||||
BELLATRIX: spec_bellatrix_mainnet,
|
||||
CAPELLA: spec_capella_mainnet,
|
||||
DENEB: spec_deneb_mainnet
|
||||
DENEB: spec_deneb_mainnet,
|
||||
EIP6110: spec_eip6110_mainnet,
|
||||
},
|
||||
}
|
||||
|
||||
@ -428,6 +432,7 @@ with_altair_and_later = with_all_phases_from(ALTAIR)
|
||||
with_bellatrix_and_later = with_all_phases_from(BELLATRIX)
|
||||
with_capella_and_later = with_all_phases_from(CAPELLA)
|
||||
with_deneb_and_later = with_all_phases_from(DENEB)
|
||||
with_eip6110_and_later = with_all_phases_from(EIP6110)
|
||||
|
||||
|
||||
def _get_preset_targets(kw):
|
||||
|
@ -4,7 +4,8 @@ from eth2spec.test.context import (
|
||||
spec_test,
|
||||
single_phase,
|
||||
with_deneb_and_later,
|
||||
expect_assertion_error
|
||||
expect_assertion_error,
|
||||
always_bls
|
||||
)
|
||||
from eth2spec.test.helpers.sharding import (
|
||||
get_sample_blob,
|
||||
@ -263,6 +264,7 @@ def test_validate_kzg_g1_neutral_element(spec):
|
||||
@with_deneb_and_later
|
||||
@spec_test
|
||||
@single_phase
|
||||
@always_bls
|
||||
def test_validate_kzg_g1_not_in_g1(spec):
|
||||
"""
|
||||
Verify that `validate_kzg_g1` fails on point not in G1
|
||||
@ -274,6 +276,7 @@ def test_validate_kzg_g1_not_in_g1(spec):
|
||||
@with_deneb_and_later
|
||||
@spec_test
|
||||
@single_phase
|
||||
@always_bls
|
||||
def test_validate_kzg_g1_not_on_curve(spec):
|
||||
"""
|
||||
Verify that `validate_kzg_g1` fails on point not in G1
|
||||
|
0
tests/core/pyspec/eth2spec/test/eip6110/__init__.py
Normal file
0
tests/core/pyspec/eth2spec/test/eip6110/__init__.py
Normal file
@ -0,0 +1,282 @@
|
||||
from eth2spec.test.context import spec_state_test, always_bls, with_eip6110_and_later
|
||||
from eth2spec.test.helpers.deposits import (
|
||||
prepare_deposit_receipt,
|
||||
run_deposit_receipt_processing,
|
||||
run_deposit_receipt_processing_with_specific_fork_version
|
||||
)
|
||||
from eth2spec.test.helpers.state import next_epoch_via_block
|
||||
from eth2spec.test.helpers.withdrawals import set_validator_fully_withdrawable
|
||||
|
||||
|
||||
@with_eip6110_and_later
|
||||
@spec_state_test
|
||||
def test_new_deposit_under_max(spec, state):
|
||||
# fresh deposit = next validator index = validator appended to registry
|
||||
validator_index = len(state.validators)
|
||||
# effective balance will be 1 EFFECTIVE_BALANCE_INCREMENT smaller because of this small decrement.
|
||||
amount = spec.MAX_EFFECTIVE_BALANCE - 1
|
||||
deposit_receipt = prepare_deposit_receipt(spec, validator_index, amount, signed=True)
|
||||
|
||||
yield from run_deposit_receipt_processing(spec, state, deposit_receipt, validator_index)
|
||||
|
||||
|
||||
@with_eip6110_and_later
|
||||
@spec_state_test
|
||||
def test_new_deposit_max(spec, state):
|
||||
# fresh deposit = next validator index = validator appended to registry
|
||||
validator_index = len(state.validators)
|
||||
# effective balance will be exactly the same as balance.
|
||||
amount = spec.MAX_EFFECTIVE_BALANCE
|
||||
deposit_receipt = prepare_deposit_receipt(spec, validator_index, amount, signed=True)
|
||||
|
||||
yield from run_deposit_receipt_processing(spec, state, deposit_receipt, validator_index)
|
||||
|
||||
|
||||
@with_eip6110_and_later
|
||||
@spec_state_test
|
||||
def test_new_deposit_over_max(spec, state):
|
||||
# fresh deposit = next validator index = validator appended to registry
|
||||
validator_index = len(state.validators)
|
||||
# just 1 over the limit, effective balance should be set MAX_EFFECTIVE_BALANCE during processing
|
||||
amount = spec.MAX_EFFECTIVE_BALANCE + 1
|
||||
deposit_receipt = prepare_deposit_receipt(spec, validator_index, amount, signed=True)
|
||||
|
||||
yield from run_deposit_receipt_processing(spec, state, deposit_receipt, validator_index)
|
||||
|
||||
|
||||
@with_eip6110_and_later
|
||||
@spec_state_test
|
||||
def test_new_deposit_eth1_withdrawal_credentials(spec, state):
|
||||
# fresh deposit = next validator index = validator appended to registry
|
||||
validator_index = len(state.validators)
|
||||
withdrawal_credentials = (
|
||||
spec.ETH1_ADDRESS_WITHDRAWAL_PREFIX
|
||||
+ b'\x00' * 11 # specified 0s
|
||||
+ b'\x59' * 20 # a 20-byte eth1 address
|
||||
)
|
||||
amount = spec.MAX_EFFECTIVE_BALANCE
|
||||
deposit_receipt = prepare_deposit_receipt(
|
||||
spec,
|
||||
validator_index,
|
||||
amount,
|
||||
withdrawal_credentials=withdrawal_credentials,
|
||||
signed=True,
|
||||
)
|
||||
|
||||
yield from run_deposit_receipt_processing(spec, state, deposit_receipt, validator_index)
|
||||
|
||||
|
||||
@with_eip6110_and_later
|
||||
@spec_state_test
|
||||
def test_new_deposit_non_versioned_withdrawal_credentials(spec, state):
|
||||
# fresh deposit = next validator index = validator appended to registry
|
||||
validator_index = len(state.validators)
|
||||
withdrawal_credentials = (
|
||||
b'\xFF' # Non specified withdrawal credentials version
|
||||
+ b'\x02' * 31 # Garabage bytes
|
||||
)
|
||||
amount = spec.MAX_EFFECTIVE_BALANCE
|
||||
deposit_receipt = prepare_deposit_receipt(
|
||||
spec,
|
||||
validator_index,
|
||||
amount,
|
||||
withdrawal_credentials=withdrawal_credentials,
|
||||
signed=True,
|
||||
)
|
||||
|
||||
yield from run_deposit_receipt_processing(spec, state, deposit_receipt, validator_index)
|
||||
|
||||
|
||||
@with_eip6110_and_later
|
||||
@spec_state_test
|
||||
@always_bls
|
||||
def test_correct_sig_but_forked_state(spec, state):
|
||||
validator_index = len(state.validators)
|
||||
amount = spec.MAX_EFFECTIVE_BALANCE
|
||||
# deposits will always be valid, regardless of the current fork
|
||||
state.fork.current_version = spec.Version('0x1234abcd')
|
||||
deposit_receipt = prepare_deposit_receipt(spec, validator_index, amount, signed=True)
|
||||
yield from run_deposit_receipt_processing(spec, state, deposit_receipt, validator_index)
|
||||
|
||||
|
||||
@with_eip6110_and_later
|
||||
@spec_state_test
|
||||
@always_bls
|
||||
def test_incorrect_sig_new_deposit(spec, state):
|
||||
# fresh deposit = next validator index = validator appended to registry
|
||||
validator_index = len(state.validators)
|
||||
amount = spec.MAX_EFFECTIVE_BALANCE
|
||||
deposit_receipt = prepare_deposit_receipt(spec, validator_index, amount)
|
||||
yield from run_deposit_receipt_processing(spec, state, deposit_receipt, validator_index, effective=False)
|
||||
|
||||
|
||||
@with_eip6110_and_later
|
||||
@spec_state_test
|
||||
def test_top_up__max_effective_balance(spec, state):
|
||||
validator_index = 0
|
||||
amount = spec.MAX_EFFECTIVE_BALANCE // 4
|
||||
deposit_receipt = prepare_deposit_receipt(spec, validator_index, amount, signed=True)
|
||||
|
||||
state.balances[validator_index] = spec.MAX_EFFECTIVE_BALANCE
|
||||
state.validators[validator_index].effective_balance = spec.MAX_EFFECTIVE_BALANCE
|
||||
|
||||
yield from run_deposit_receipt_processing(spec, state, deposit_receipt, validator_index)
|
||||
|
||||
assert state.balances[validator_index] == spec.MAX_EFFECTIVE_BALANCE + amount
|
||||
assert state.validators[validator_index].effective_balance == spec.MAX_EFFECTIVE_BALANCE
|
||||
|
||||
|
||||
@with_eip6110_and_later
|
||||
@spec_state_test
|
||||
def test_top_up__less_effective_balance(spec, state):
|
||||
validator_index = 0
|
||||
amount = spec.MAX_EFFECTIVE_BALANCE // 4
|
||||
deposit_receipt = prepare_deposit_receipt(spec, validator_index, amount, signed=True)
|
||||
|
||||
initial_balance = spec.MAX_EFFECTIVE_BALANCE - 1000
|
||||
initial_effective_balance = spec.MAX_EFFECTIVE_BALANCE - spec.EFFECTIVE_BALANCE_INCREMENT
|
||||
state.balances[validator_index] = initial_balance
|
||||
state.validators[validator_index].effective_balance = initial_effective_balance
|
||||
|
||||
yield from run_deposit_receipt_processing(spec, state, deposit_receipt, validator_index)
|
||||
|
||||
assert state.balances[validator_index] == initial_balance + amount
|
||||
# unchanged effective balance
|
||||
assert state.validators[validator_index].effective_balance == initial_effective_balance
|
||||
|
||||
|
||||
@with_eip6110_and_later
|
||||
@spec_state_test
|
||||
def test_top_up__zero_balance(spec, state):
|
||||
validator_index = 0
|
||||
amount = spec.MAX_EFFECTIVE_BALANCE // 4
|
||||
deposit_receipt = prepare_deposit_receipt(spec, validator_index, amount, signed=True)
|
||||
|
||||
initial_balance = 0
|
||||
initial_effective_balance = 0
|
||||
state.balances[validator_index] = initial_balance
|
||||
state.validators[validator_index].effective_balance = initial_effective_balance
|
||||
|
||||
yield from run_deposit_receipt_processing(spec, state, deposit_receipt, validator_index)
|
||||
|
||||
assert state.balances[validator_index] == initial_balance + amount
|
||||
# unchanged effective balance
|
||||
assert state.validators[validator_index].effective_balance == initial_effective_balance
|
||||
|
||||
|
||||
@with_eip6110_and_later
|
||||
@spec_state_test
|
||||
@always_bls
|
||||
def test_incorrect_sig_top_up(spec, state):
|
||||
validator_index = 0
|
||||
amount = spec.MAX_EFFECTIVE_BALANCE // 4
|
||||
deposit_receipt = prepare_deposit_receipt(spec, validator_index, amount)
|
||||
|
||||
# invalid signatures, in top-ups, are allowed!
|
||||
yield from run_deposit_receipt_processing(spec, state, deposit_receipt, validator_index)
|
||||
|
||||
|
||||
@with_eip6110_and_later
|
||||
@spec_state_test
|
||||
def test_incorrect_withdrawal_credentials_top_up(spec, state):
|
||||
validator_index = 0
|
||||
amount = spec.MAX_EFFECTIVE_BALANCE // 4
|
||||
withdrawal_credentials = spec.BLS_WITHDRAWAL_PREFIX + spec.hash(b"junk")[1:]
|
||||
deposit_receipt = prepare_deposit_receipt(
|
||||
spec,
|
||||
validator_index,
|
||||
amount,
|
||||
withdrawal_credentials=withdrawal_credentials
|
||||
)
|
||||
|
||||
# inconsistent withdrawal credentials, in top-ups, are allowed!
|
||||
yield from run_deposit_receipt_processing(spec, state, deposit_receipt, validator_index)
|
||||
|
||||
|
||||
@with_eip6110_and_later
|
||||
@spec_state_test
|
||||
def test_key_validate_invalid_subgroup(spec, state):
|
||||
validator_index = len(state.validators)
|
||||
amount = spec.MAX_EFFECTIVE_BALANCE
|
||||
|
||||
# All-zero pubkey would not pass `bls.KeyValidate`, but `process_deposit` would not throw exception.
|
||||
pubkey = b'\x00' * 48
|
||||
|
||||
deposit_receipt = prepare_deposit_receipt(spec, validator_index, amount, pubkey=pubkey, signed=True)
|
||||
|
||||
yield from run_deposit_receipt_processing(spec, state, deposit_receipt, validator_index)
|
||||
|
||||
|
||||
@with_eip6110_and_later
|
||||
@spec_state_test
|
||||
def test_key_validate_invalid_decompression(spec, state):
|
||||
validator_index = len(state.validators)
|
||||
amount = spec.MAX_EFFECTIVE_BALANCE
|
||||
|
||||
# `deserialization_fails_infinity_with_true_b_flag` BLS G1 deserialization test case.
|
||||
# This pubkey would not pass `bls.KeyValidate`, but `process_deposit` would not throw exception.
|
||||
pubkey_hex = 'c01000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000'
|
||||
pubkey = bytes.fromhex(pubkey_hex)
|
||||
|
||||
deposit_receipt = prepare_deposit_receipt(spec, validator_index, amount, pubkey=pubkey, signed=True)
|
||||
|
||||
yield from run_deposit_receipt_processing(spec, state, deposit_receipt, validator_index)
|
||||
|
||||
|
||||
@with_eip6110_and_later
|
||||
@spec_state_test
|
||||
@always_bls
|
||||
def test_ineffective_deposit_with_previous_fork_version(spec, state):
|
||||
# Since deposits are valid across forks, the domain is always set with `GENESIS_FORK_VERSION`.
|
||||
# It's an ineffective deposit because it fails at BLS sig verification.
|
||||
# NOTE: it was effective in Altair.
|
||||
assert state.fork.previous_version != state.fork.current_version
|
||||
|
||||
yield from run_deposit_receipt_processing_with_specific_fork_version(
|
||||
spec,
|
||||
state,
|
||||
fork_version=state.fork.previous_version,
|
||||
effective=False,
|
||||
)
|
||||
|
||||
|
||||
@with_eip6110_and_later
|
||||
@spec_state_test
|
||||
@always_bls
|
||||
def test_effective_deposit_with_genesis_fork_version(spec, state):
|
||||
assert spec.config.GENESIS_FORK_VERSION not in (state.fork.previous_version, state.fork.current_version)
|
||||
|
||||
yield from run_deposit_receipt_processing_with_specific_fork_version(
|
||||
spec,
|
||||
state,
|
||||
fork_version=spec.config.GENESIS_FORK_VERSION,
|
||||
)
|
||||
|
||||
|
||||
@with_eip6110_and_later
|
||||
@spec_state_test
|
||||
def test_success_top_up_to_withdrawn_validator(spec, state):
|
||||
validator_index = 0
|
||||
|
||||
# Fully withdraw validator
|
||||
set_validator_fully_withdrawable(spec, state, validator_index)
|
||||
assert state.balances[validator_index] > 0
|
||||
next_epoch_via_block(spec, state)
|
||||
assert state.balances[validator_index] == 0
|
||||
assert state.validators[validator_index].effective_balance > 0
|
||||
next_epoch_via_block(spec, state)
|
||||
assert state.validators[validator_index].effective_balance == 0
|
||||
|
||||
# Make a top-up balance to validator
|
||||
amount = spec.MAX_EFFECTIVE_BALANCE // 4
|
||||
deposit_receipt = prepare_deposit_receipt(spec, validator_index, amount, len(state.validators), signed=True)
|
||||
|
||||
yield from run_deposit_receipt_processing(spec, state, deposit_receipt, validator_index)
|
||||
|
||||
assert state.balances[validator_index] == amount
|
||||
assert state.validators[validator_index].effective_balance == 0
|
||||
|
||||
validator = state.validators[validator_index]
|
||||
balance = state.balances[validator_index]
|
||||
current_epoch = spec.get_current_epoch(state)
|
||||
assert spec.is_fully_withdrawable_validator(validator, balance, current_epoch)
|
@ -0,0 +1 @@
|
||||
from .test_deposit_transition import * # noqa: F401 F403
|
@ -0,0 +1,229 @@
|
||||
from eth2spec.test.helpers.block import (
|
||||
build_empty_block_for_next_slot,
|
||||
)
|
||||
from eth2spec.test.context import (
|
||||
spec_state_test,
|
||||
with_phases,
|
||||
EIP6110,
|
||||
)
|
||||
from eth2spec.test.helpers.deposits import (
|
||||
build_deposit_data,
|
||||
deposit_from_context,
|
||||
prepare_deposit_receipt,
|
||||
)
|
||||
from eth2spec.test.helpers.execution_payload import (
|
||||
compute_el_block_hash,
|
||||
)
|
||||
from eth2spec.test.helpers.keys import privkeys, pubkeys
|
||||
from eth2spec.test.helpers.state import (
|
||||
state_transition_and_sign_block
|
||||
)
|
||||
|
||||
|
||||
def run_deposit_transition_block(spec, state, block, top_up_keys=[], valid=True):
|
||||
"""
|
||||
Run ``process_block``, yielding:
|
||||
- pre-state ('pre')
|
||||
- block ('block')
|
||||
- post-state ('post').
|
||||
If ``valid == False``, run expecting ``AssertionError``
|
||||
"""
|
||||
yield 'pre', state
|
||||
|
||||
signed_block = state_transition_and_sign_block(spec, state, block, not valid)
|
||||
|
||||
yield 'blocks', [signed_block]
|
||||
yield 'post', state if valid else None
|
||||
|
||||
# Check that deposits are applied
|
||||
if valid:
|
||||
expected_pubkeys = [d.data.pubkey for d in block.body.deposits]
|
||||
deposit_receipts = block.body.execution_payload.deposit_receipts
|
||||
expected_pubkeys = expected_pubkeys + [d.pubkey for d in deposit_receipts if (d.pubkey not in top_up_keys)]
|
||||
actual_pubkeys = [v.pubkey for v in state.validators[len(state.validators) - len(expected_pubkeys):]]
|
||||
|
||||
assert actual_pubkeys == expected_pubkeys
|
||||
|
||||
|
||||
def prepare_state_and_block(spec,
|
||||
state,
|
||||
deposit_cnt,
|
||||
deposit_receipt_cnt,
|
||||
first_deposit_receipt_index=0,
|
||||
deposit_receipts_start_index=None,
|
||||
eth1_data_deposit_count=None):
|
||||
deposits = []
|
||||
deposit_receipts = []
|
||||
keypair_index = len(state.validators)
|
||||
|
||||
# Prepare deposits
|
||||
deposit_data_list = []
|
||||
for index in range(deposit_cnt):
|
||||
deposit_data = build_deposit_data(spec,
|
||||
pubkeys[keypair_index],
|
||||
privkeys[keypair_index],
|
||||
# use max effective balance
|
||||
spec.MAX_EFFECTIVE_BALANCE,
|
||||
# insecurely use pubkey as withdrawal key
|
||||
spec.BLS_WITHDRAWAL_PREFIX + spec.hash(pubkeys[keypair_index])[1:],
|
||||
signed=True)
|
||||
deposit_data_list.append(deposit_data)
|
||||
keypair_index += 1
|
||||
|
||||
deposit_root = None
|
||||
for index in range(deposit_cnt):
|
||||
deposit, deposit_root, _ = deposit_from_context(spec, deposit_data_list, index)
|
||||
deposits.append(deposit)
|
||||
|
||||
if deposit_root:
|
||||
state.eth1_deposit_index = 0
|
||||
if not eth1_data_deposit_count:
|
||||
eth1_data_deposit_count = deposit_cnt
|
||||
state.eth1_data = spec.Eth1Data(deposit_root=deposit_root,
|
||||
deposit_count=eth1_data_deposit_count,
|
||||
block_hash=state.eth1_data.block_hash)
|
||||
|
||||
# Prepare deposit receipts
|
||||
for offset in range(deposit_receipt_cnt):
|
||||
deposit_receipt = prepare_deposit_receipt(spec,
|
||||
keypair_index,
|
||||
# use max effective balance
|
||||
spec.MAX_EFFECTIVE_BALANCE,
|
||||
first_deposit_receipt_index + offset,
|
||||
signed=True)
|
||||
deposit_receipts.append(deposit_receipt)
|
||||
keypair_index += 1
|
||||
|
||||
# Set start index if defined
|
||||
if deposit_receipts_start_index:
|
||||
state.deposit_receipts_start_index = deposit_receipts_start_index
|
||||
|
||||
block = build_empty_block_for_next_slot(spec, state)
|
||||
|
||||
# Assign deposits and deposit receipts
|
||||
block.body.deposits = deposits
|
||||
block.body.execution_payload.deposit_receipts = deposit_receipts
|
||||
block.body.execution_payload.block_hash = compute_el_block_hash(spec, block.body.execution_payload)
|
||||
|
||||
return state, block
|
||||
|
||||
|
||||
@with_phases([EIP6110])
|
||||
@spec_state_test
|
||||
def test_deposit_transition__start_index_is_set(spec, state):
|
||||
# 0 deposits, 2 deposit receipts, unset deposit_receipts_start_index
|
||||
state, block = prepare_state_and_block(spec, state,
|
||||
deposit_cnt=0,
|
||||
deposit_receipt_cnt=2,
|
||||
first_deposit_receipt_index=state.eth1_data.deposit_count + 11)
|
||||
|
||||
yield from run_deposit_transition_block(spec, state, block)
|
||||
|
||||
# deposit_receipts_start_index must be set to the index of the first receipt
|
||||
assert state.deposit_receipts_start_index == block.body.execution_payload.deposit_receipts[0].index
|
||||
|
||||
|
||||
@with_phases([EIP6110])
|
||||
@spec_state_test
|
||||
def test_deposit_transition__process_eth1_deposits(spec, state):
|
||||
# 3 deposits, 1 deposit receipt, state.eth1_data.deposit_count < state.deposit_receipts_start_index
|
||||
state, block = prepare_state_and_block(spec, state,
|
||||
deposit_cnt=3,
|
||||
deposit_receipt_cnt=1,
|
||||
first_deposit_receipt_index=11,
|
||||
deposit_receipts_start_index=7)
|
||||
|
||||
yield from run_deposit_transition_block(spec, state, block)
|
||||
|
||||
|
||||
@with_phases([EIP6110])
|
||||
@spec_state_test
|
||||
def test_deposit_transition__process_max_eth1_deposits(spec, state):
|
||||
# spec.MAX_DEPOSITS deposits, 1 deposit receipt, state.eth1_data.deposit_count > state.deposit_receipts_start_index
|
||||
# state.deposit_receipts_start_index == spec.MAX_DEPOSITS
|
||||
state, block = prepare_state_and_block(spec, state,
|
||||
deposit_cnt=spec.MAX_DEPOSITS,
|
||||
deposit_receipt_cnt=1,
|
||||
first_deposit_receipt_index=spec.MAX_DEPOSITS + 1,
|
||||
deposit_receipts_start_index=spec.MAX_DEPOSITS,
|
||||
eth1_data_deposit_count=23)
|
||||
|
||||
yield from run_deposit_transition_block(spec, state, block)
|
||||
|
||||
|
||||
@with_phases([EIP6110])
|
||||
@spec_state_test
|
||||
def test_deposit_transition__process_eth1_deposits_up_to_start_index(spec, state):
|
||||
# 3 deposits, 1 deposit receipt, state.eth1_data.deposit_count == state.deposit_receipts_start_index
|
||||
state, block = prepare_state_and_block(spec, state,
|
||||
deposit_cnt=3,
|
||||
deposit_receipt_cnt=1,
|
||||
first_deposit_receipt_index=7,
|
||||
deposit_receipts_start_index=3)
|
||||
|
||||
yield from run_deposit_transition_block(spec, state, block)
|
||||
|
||||
|
||||
@with_phases([EIP6110])
|
||||
@spec_state_test
|
||||
def test_deposit_transition__invalid_not_enough_eth1_deposits(spec, state):
|
||||
# 3 deposits, 1 deposit receipt, state.eth1_data.deposit_count < state.deposit_receipts_start_index
|
||||
state, block = prepare_state_and_block(spec, state,
|
||||
deposit_cnt=3,
|
||||
deposit_receipt_cnt=1,
|
||||
first_deposit_receipt_index=29,
|
||||
deposit_receipts_start_index=23,
|
||||
eth1_data_deposit_count=17)
|
||||
|
||||
yield from run_deposit_transition_block(spec, state, block, valid=False)
|
||||
|
||||
|
||||
@with_phases([EIP6110])
|
||||
@spec_state_test
|
||||
def test_deposit_transition__invalid_too_many_eth1_deposits(spec, state):
|
||||
# 3 deposits, 1 deposit receipt, state.eth1_data.deposit_count < state.eth1_data_index
|
||||
state, block = prepare_state_and_block(spec, state,
|
||||
deposit_cnt=3,
|
||||
deposit_receipt_cnt=1,
|
||||
first_deposit_receipt_index=11,
|
||||
deposit_receipts_start_index=7,
|
||||
eth1_data_deposit_count=2)
|
||||
|
||||
yield from run_deposit_transition_block(spec, state, block, valid=False)
|
||||
|
||||
|
||||
@with_phases([EIP6110])
|
||||
@spec_state_test
|
||||
def test_deposit_transition__invalid_eth1_deposits_overlap_in_protocol_deposits(spec, state):
|
||||
# spec.MAX_DEPOSITS deposits, 1 deposit receipt, state.eth1_data.deposit_count > state.deposit_receipts_start_index
|
||||
# state.deposit_receipts_start_index == spec.MAX_DEPOSITS - 1
|
||||
state, block = prepare_state_and_block(spec, state,
|
||||
deposit_cnt=spec.MAX_DEPOSITS,
|
||||
deposit_receipt_cnt=1,
|
||||
first_deposit_receipt_index=spec.MAX_DEPOSITS,
|
||||
deposit_receipts_start_index=spec.MAX_DEPOSITS - 1,
|
||||
eth1_data_deposit_count=23)
|
||||
|
||||
yield from run_deposit_transition_block(spec, state, block, valid=False)
|
||||
|
||||
|
||||
@with_phases([EIP6110])
|
||||
@spec_state_test
|
||||
def test_deposit_transition__deposit_and_top_up_same_block(spec, state):
|
||||
# 1 deposit, 1 deposit receipt that top ups deposited validator
|
||||
state, block = prepare_state_and_block(spec, state,
|
||||
deposit_cnt=1,
|
||||
deposit_receipt_cnt=1,
|
||||
first_deposit_receipt_index=11,
|
||||
deposit_receipts_start_index=7)
|
||||
|
||||
# Artificially assign deposit's pubkey to a deposit receipt of the same block
|
||||
top_up_keys = [block.body.deposits[0].data.pubkey]
|
||||
block.body.execution_payload.deposit_receipts[0].pubkey = top_up_keys[0]
|
||||
block.body.execution_payload.block_hash = compute_el_block_hash(spec, block.body.execution_payload)
|
||||
|
||||
yield from run_deposit_transition_block(spec, state, block, top_up_keys=top_up_keys)
|
||||
|
||||
# Check the top up
|
||||
expected_balance = block.body.deposits[0].data.amount + block.body.execution_payload.deposit_receipts[0].amount
|
||||
assert state.balances[len(state.balances) - 1] == expected_balance
|
@ -9,30 +9,31 @@ PHASE0 = SpecForkName('phase0')
|
||||
ALTAIR = SpecForkName('altair')
|
||||
BELLATRIX = SpecForkName('bellatrix')
|
||||
CAPELLA = SpecForkName('capella')
|
||||
DENEB = SpecForkName('deneb')
|
||||
|
||||
# Experimental phases (not included in default "ALL_PHASES"):
|
||||
SHARDING = SpecForkName('sharding')
|
||||
CUSTODY_GAME = SpecForkName('custody_game')
|
||||
DAS = SpecForkName('das')
|
||||
DENEB = SpecForkName('deneb')
|
||||
EIP6110 = SpecForkName('eip6110')
|
||||
|
||||
# The forks that pytest can run with.
|
||||
ALL_PHASES = (
|
||||
# Formal forks
|
||||
PHASE0, ALTAIR, BELLATRIX, CAPELLA,
|
||||
PHASE0, ALTAIR, BELLATRIX, CAPELLA, DENEB,
|
||||
# Experimental patches
|
||||
DENEB,
|
||||
EIP6110,
|
||||
)
|
||||
# The forks that output to the test vectors.
|
||||
TESTGEN_FORKS = (PHASE0, ALTAIR, BELLATRIX, CAPELLA, DENEB)
|
||||
TESTGEN_FORKS = (PHASE0, ALTAIR, BELLATRIX, CAPELLA, DENEB, EIP6110)
|
||||
|
||||
# TODO: no DENEB fork tests now. Should add when we figure out the content of Capella.
|
||||
ALL_FORK_UPGRADES = {
|
||||
# pre_fork_name: post_fork_name
|
||||
PHASE0: ALTAIR,
|
||||
ALTAIR: BELLATRIX,
|
||||
BELLATRIX: CAPELLA,
|
||||
CAPELLA: DENEB,
|
||||
DENEB: EIP6110,
|
||||
}
|
||||
ALL_PRE_POST_FORKS = ALL_FORK_UPGRADES.items()
|
||||
AFTER_BELLATRIX_UPGRADES = {key: value for key, value in ALL_FORK_UPGRADES.items() if key != PHASE0}
|
||||
|
@ -171,6 +171,54 @@ def prepare_state_and_deposit(spec, state, validator_index, amount,
|
||||
return deposit
|
||||
|
||||
|
||||
def build_deposit_receipt(spec,
|
||||
index,
|
||||
pubkey,
|
||||
privkey,
|
||||
amount,
|
||||
withdrawal_credentials,
|
||||
signed):
|
||||
deposit_data = build_deposit_data(spec, pubkey, privkey, amount, withdrawal_credentials, signed=signed)
|
||||
return spec.DepositReceipt(
|
||||
pubkey=deposit_data.pubkey,
|
||||
withdrawal_credentials=deposit_data.withdrawal_credentials,
|
||||
amount=deposit_data.amount,
|
||||
signature=deposit_data.signature,
|
||||
index=index)
|
||||
|
||||
|
||||
def prepare_deposit_receipt(spec, validator_index, amount,
|
||||
index=None,
|
||||
pubkey=None,
|
||||
privkey=None,
|
||||
withdrawal_credentials=None,
|
||||
signed=False):
|
||||
"""
|
||||
Create a deposit receipt for the given validator, depositing the given amount.
|
||||
"""
|
||||
if index is None:
|
||||
index = validator_index
|
||||
|
||||
if pubkey is None:
|
||||
pubkey = pubkeys[validator_index]
|
||||
|
||||
if privkey is None:
|
||||
privkey = privkeys[validator_index]
|
||||
|
||||
# insecurely use pubkey as withdrawal key if no credentials provided
|
||||
if withdrawal_credentials is None:
|
||||
withdrawal_credentials = spec.BLS_WITHDRAWAL_PREFIX + spec.hash(pubkey)[1:]
|
||||
|
||||
return build_deposit_receipt(
|
||||
spec,
|
||||
index,
|
||||
pubkey,
|
||||
privkey,
|
||||
amount,
|
||||
withdrawal_credentials,
|
||||
signed,
|
||||
)
|
||||
|
||||
#
|
||||
# Run processing
|
||||
#
|
||||
@ -255,3 +303,90 @@ def run_deposit_processing_with_specific_fork_version(
|
||||
state.eth1_data.deposit_count = 1
|
||||
|
||||
yield from run_deposit_processing(spec, state, deposit, validator_index, valid=valid, effective=effective)
|
||||
|
||||
|
||||
def run_deposit_receipt_processing(spec, state, deposit_receipt, validator_index, valid=True, effective=True):
|
||||
"""
|
||||
Run ``process_deposit_receipt``, yielding:
|
||||
- pre-state ('pre')
|
||||
- deposit_receipt ('deposit_receipt')
|
||||
- post-state ('post').
|
||||
If ``valid == False``, run expecting ``AssertionError``
|
||||
"""
|
||||
pre_validator_count = len(state.validators)
|
||||
pre_balance = 0
|
||||
is_top_up = False
|
||||
# is a top-up
|
||||
if validator_index < pre_validator_count:
|
||||
is_top_up = True
|
||||
pre_balance = get_balance(state, validator_index)
|
||||
pre_effective_balance = state.validators[validator_index].effective_balance
|
||||
|
||||
yield 'pre', state
|
||||
yield 'deposit_receipt', deposit_receipt
|
||||
|
||||
if not valid:
|
||||
expect_assertion_error(lambda: spec.process_deposit_receipt(state, deposit_receipt))
|
||||
yield 'post', None
|
||||
return
|
||||
|
||||
spec.process_deposit_receipt(state, deposit_receipt)
|
||||
|
||||
yield 'post', state
|
||||
|
||||
if not effective or not bls.KeyValidate(deposit_receipt.pubkey):
|
||||
assert len(state.validators) == pre_validator_count
|
||||
assert len(state.balances) == pre_validator_count
|
||||
if is_top_up:
|
||||
assert get_balance(state, validator_index) == pre_balance
|
||||
else:
|
||||
if is_top_up:
|
||||
# Top-ups do not change effective balance
|
||||
assert state.validators[validator_index].effective_balance == pre_effective_balance
|
||||
assert len(state.validators) == pre_validator_count
|
||||
assert len(state.balances) == pre_validator_count
|
||||
else:
|
||||
# new validator
|
||||
assert len(state.validators) == pre_validator_count + 1
|
||||
assert len(state.balances) == pre_validator_count + 1
|
||||
effective_balance = min(spec.MAX_EFFECTIVE_BALANCE, deposit_receipt.amount)
|
||||
effective_balance -= effective_balance % spec.EFFECTIVE_BALANCE_INCREMENT
|
||||
assert state.validators[validator_index].effective_balance == effective_balance
|
||||
|
||||
assert get_balance(state, validator_index) == pre_balance + deposit_receipt.amount
|
||||
|
||||
|
||||
def run_deposit_receipt_processing_with_specific_fork_version(
|
||||
spec,
|
||||
state,
|
||||
fork_version,
|
||||
valid=True,
|
||||
effective=True):
|
||||
validator_index = len(state.validators)
|
||||
amount = spec.MAX_EFFECTIVE_BALANCE
|
||||
|
||||
pubkey = pubkeys[validator_index]
|
||||
privkey = privkeys[validator_index]
|
||||
withdrawal_credentials = spec.BLS_WITHDRAWAL_PREFIX + spec.hash(pubkey)[1:]
|
||||
|
||||
deposit_message = spec.DepositMessage(pubkey=pubkey, withdrawal_credentials=withdrawal_credentials, amount=amount)
|
||||
domain = spec.compute_domain(domain_type=spec.DOMAIN_DEPOSIT, fork_version=fork_version)
|
||||
deposit_data = spec.DepositData(
|
||||
pubkey=pubkey, withdrawal_credentials=withdrawal_credentials, amount=amount,
|
||||
signature=bls.Sign(privkey, spec.compute_signing_root(deposit_message, domain))
|
||||
)
|
||||
deposit_receipt = spec.DepositReceipt(
|
||||
pubkey=deposit_data.pubkey,
|
||||
withdrawal_credentials=deposit_data.withdrawal_credentials,
|
||||
amount=deposit_data.amount,
|
||||
signature=deposit_data.signature,
|
||||
index=validator_index)
|
||||
|
||||
yield from run_deposit_receipt_processing(
|
||||
spec,
|
||||
state,
|
||||
deposit_receipt,
|
||||
validator_index,
|
||||
valid=valid,
|
||||
effective=effective
|
||||
)
|
||||
|
@ -4,7 +4,11 @@ from rlp import encode
|
||||
from rlp.sedes import big_endian_int, Binary, List
|
||||
|
||||
from eth2spec.debug.random_value import get_random_bytes_list
|
||||
from eth2spec.test.helpers.forks import is_post_capella, is_post_deneb
|
||||
from eth2spec.test.helpers.forks import (
|
||||
is_post_capella,
|
||||
is_post_deneb,
|
||||
is_post_eip6110,
|
||||
)
|
||||
|
||||
|
||||
def get_execution_payload_header(spec, execution_payload):
|
||||
@ -28,6 +32,8 @@ def get_execution_payload_header(spec, execution_payload):
|
||||
payload_header.withdrawals_root = spec.hash_tree_root(execution_payload.withdrawals)
|
||||
if is_post_deneb(spec):
|
||||
payload_header.excess_data_gas = execution_payload.excess_data_gas
|
||||
if is_post_eip6110(spec):
|
||||
payload_header.deposit_receipts_root = spec.hash_tree_root(execution_payload.deposit_receipts)
|
||||
return payload_header
|
||||
|
||||
|
||||
@ -48,7 +54,8 @@ def compute_trie_root_from_indexed_data(data):
|
||||
def compute_el_header_block_hash(spec,
|
||||
payload_header,
|
||||
transactions_trie_root,
|
||||
withdrawals_trie_root=None):
|
||||
withdrawals_trie_root=None,
|
||||
deposit_receipts_trie_root=None):
|
||||
"""
|
||||
Computes the RLP execution block hash described by an `ExecutionPayloadHeader`.
|
||||
"""
|
||||
@ -92,6 +99,10 @@ def compute_el_header_block_hash(spec,
|
||||
if is_post_deneb(spec):
|
||||
# excess_data_gas
|
||||
execution_payload_header_rlp.append((big_endian_int, payload_header.excess_data_gas))
|
||||
if is_post_eip6110(spec):
|
||||
# deposit_receipts_root
|
||||
assert deposit_receipts_trie_root is not None
|
||||
execution_payload_header_rlp.append((Binary(32, 32), deposit_receipts_trie_root))
|
||||
|
||||
sedes = List([schema for schema, _ in execution_payload_header_rlp])
|
||||
values = [value for _, value in execution_payload_header_rlp]
|
||||
@ -118,14 +129,37 @@ def get_withdrawal_rlp(spec, withdrawal):
|
||||
return encode(values, sedes)
|
||||
|
||||
|
||||
def get_deposit_receipt_rlp(spec, deposit_receipt):
|
||||
deposit_receipt_rlp = [
|
||||
# pubkey
|
||||
(Binary(48, 48), deposit_receipt.pubkey),
|
||||
# withdrawal_credentials
|
||||
(Binary(32, 32), deposit_receipt.withdrawal_credentials),
|
||||
# amount
|
||||
(big_endian_int, deposit_receipt.amount),
|
||||
# pubkey
|
||||
(Binary(96, 96), deposit_receipt.signature),
|
||||
# index
|
||||
(big_endian_int, deposit_receipt.index),
|
||||
]
|
||||
|
||||
sedes = List([schema for schema, _ in deposit_receipt_rlp])
|
||||
values = [value for _, value in deposit_receipt_rlp]
|
||||
return encode(values, sedes)
|
||||
|
||||
|
||||
def compute_el_block_hash(spec, payload):
|
||||
transactions_trie_root = compute_trie_root_from_indexed_data(payload.transactions)
|
||||
|
||||
withdrawals_trie_root = None
|
||||
deposit_receipts_trie_root = None
|
||||
|
||||
if is_post_capella(spec):
|
||||
withdrawals_encoded = [get_withdrawal_rlp(spec, withdrawal) for withdrawal in payload.withdrawals]
|
||||
withdrawals_trie_root = compute_trie_root_from_indexed_data(withdrawals_encoded)
|
||||
else:
|
||||
withdrawals_trie_root = None
|
||||
if is_post_eip6110(spec):
|
||||
deposit_receipts_encoded = [get_deposit_receipt_rlp(spec, receipt) for receipt in payload.deposit_receipts]
|
||||
deposit_receipts_trie_root = compute_trie_root_from_indexed_data(deposit_receipts_encoded)
|
||||
|
||||
payload_header = get_execution_payload_header(spec, payload)
|
||||
|
||||
@ -134,6 +168,7 @@ def compute_el_block_hash(spec, payload):
|
||||
payload_header,
|
||||
transactions_trie_root,
|
||||
withdrawals_trie_root,
|
||||
deposit_receipts_trie_root,
|
||||
)
|
||||
|
||||
|
||||
@ -167,6 +202,9 @@ def build_empty_execution_payload(spec, state, randao_mix=None):
|
||||
payload.withdrawals = spec.get_expected_withdrawals(state)
|
||||
if is_post_deneb(spec):
|
||||
payload.excess_data_gas = 0
|
||||
if is_post_eip6110(spec):
|
||||
# just to be clear
|
||||
payload.deposit_receipts = []
|
||||
|
||||
payload.block_hash = compute_el_block_hash(spec, payload)
|
||||
|
||||
|
@ -15,6 +15,7 @@ from eth2spec.test.helpers.constants import (
|
||||
BELLATRIX,
|
||||
CAPELLA,
|
||||
DENEB,
|
||||
EIP6110,
|
||||
)
|
||||
from eth2spec.test.helpers.deposits import (
|
||||
prepare_state_and_deposit,
|
||||
@ -158,6 +159,8 @@ def do_fork(state, spec, post_spec, fork_epoch, with_block=True, sync_aggregate=
|
||||
state = post_spec.upgrade_to_capella(state)
|
||||
elif post_spec.fork == DENEB:
|
||||
state = post_spec.upgrade_to_deneb(state)
|
||||
elif post_spec.fork == EIP6110:
|
||||
state = post_spec.upgrade_to_eip6110(state)
|
||||
|
||||
assert state.fork.epoch == fork_epoch
|
||||
|
||||
@ -173,6 +176,9 @@ def do_fork(state, spec, post_spec, fork_epoch, with_block=True, sync_aggregate=
|
||||
elif post_spec.fork == DENEB:
|
||||
assert state.fork.previous_version == post_spec.config.CAPELLA_FORK_VERSION
|
||||
assert state.fork.current_version == post_spec.config.DENEB_FORK_VERSION
|
||||
elif post_spec.fork == EIP6110:
|
||||
assert state.fork.previous_version == post_spec.config.DENEB_FORK_VERSION
|
||||
assert state.fork.current_version == post_spec.config.EIP6110_FORK_VERSION
|
||||
|
||||
if with_block:
|
||||
return state, _state_transition_and_sign_block_at_slot(
|
||||
|
@ -1,9 +1,12 @@
|
||||
from .constants import (
|
||||
PHASE0, ALTAIR, BELLATRIX, CAPELLA, DENEB,
|
||||
EIP6110,
|
||||
)
|
||||
|
||||
|
||||
def is_post_fork(a, b):
|
||||
if a == EIP6110:
|
||||
return b in [PHASE0, ALTAIR, BELLATRIX, CAPELLA, DENEB, EIP6110]
|
||||
if a == DENEB:
|
||||
return b in [PHASE0, ALTAIR, BELLATRIX, CAPELLA, DENEB]
|
||||
if a == CAPELLA:
|
||||
@ -31,3 +34,7 @@ def is_post_capella(spec):
|
||||
|
||||
def is_post_deneb(spec):
|
||||
return is_post_fork(spec.fork, DENEB)
|
||||
|
||||
|
||||
def is_post_eip6110(spec):
|
||||
return is_post_fork(spec.fork, EIP6110)
|
||||
|
@ -1,11 +1,11 @@
|
||||
from eth2spec.test.helpers.constants import (
|
||||
ALTAIR, BELLATRIX, CAPELLA, DENEB,
|
||||
ALTAIR, BELLATRIX, CAPELLA, DENEB, EIP6110,
|
||||
)
|
||||
from eth2spec.test.helpers.execution_payload import (
|
||||
compute_el_header_block_hash,
|
||||
)
|
||||
from eth2spec.test.helpers.forks import (
|
||||
is_post_altair, is_post_bellatrix, is_post_capella,
|
||||
is_post_altair, is_post_bellatrix, is_post_capella, is_post_eip6110,
|
||||
)
|
||||
from eth2spec.test.helpers.keys import pubkeys
|
||||
|
||||
@ -47,17 +47,20 @@ def get_sample_genesis_execution_payload_header(spec,
|
||||
)
|
||||
|
||||
transactions_trie_root = bytes.fromhex("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421")
|
||||
withdrawals_trie_root = None
|
||||
deposit_receipts_trie_root = None
|
||||
|
||||
if is_post_capella(spec):
|
||||
withdrawals_trie_root = bytes.fromhex("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421")
|
||||
else:
|
||||
withdrawals_trie_root = None
|
||||
if is_post_eip6110(spec):
|
||||
deposit_receipts_trie_root = bytes.fromhex("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421")
|
||||
|
||||
payload_header.block_hash = compute_el_header_block_hash(
|
||||
spec,
|
||||
payload_header,
|
||||
transactions_trie_root,
|
||||
withdrawals_trie_root,
|
||||
deposit_receipts_trie_root,
|
||||
)
|
||||
return payload_header
|
||||
|
||||
@ -80,6 +83,9 @@ def create_genesis_state(spec, validator_balances, activation_threshold):
|
||||
elif spec.fork == DENEB:
|
||||
previous_version = spec.config.CAPELLA_FORK_VERSION
|
||||
current_version = spec.config.DENEB_FORK_VERSION
|
||||
elif spec.fork == EIP6110:
|
||||
previous_version = spec.config.DENEB_FORK_VERSION
|
||||
current_version = spec.config.EIP6110_FORK_VERSION
|
||||
|
||||
state = spec.BeaconState(
|
||||
genesis_time=0,
|
||||
@ -129,4 +135,7 @@ def create_genesis_state(spec, validator_balances, activation_threshold):
|
||||
eth1_block_hash=eth1_block_hash,
|
||||
)
|
||||
|
||||
if is_post_eip6110(spec):
|
||||
state.deposit_receipts_start_index = spec.UNSET_DEPOSIT_RECEIPTS_START_INDEX
|
||||
|
||||
return state
|
||||
|
@ -479,7 +479,7 @@ def test_voting_source_within_two_epoch(spec, state):
|
||||
- store.voting_source[block_root].epoch != store.justified_checkpoint.epoch, and
|
||||
- store.unrealized_justifications[block_root].epoch >= store.justified_checkpoint.epoch, and
|
||||
- store.voting_source[block_root].epoch + 2 >= current_epoch, and
|
||||
- store.finalized_checkpoint.root == get_ancestor(store, block_root, finalized_slot)
|
||||
- store.finalized_checkpoint.root == get_checkpoint_block(store, block_root, store.finalized_checkpoint.epoch)
|
||||
"""
|
||||
test_steps = []
|
||||
# Initialization
|
||||
@ -536,8 +536,11 @@ def test_voting_source_within_two_epoch(spec, state):
|
||||
assert store.unrealized_justifications[last_fork_block_root].epoch >= store.justified_checkpoint.epoch
|
||||
# assert store.voting_source[last_fork_block_root].epoch + 2 >= \
|
||||
# spec.compute_epoch_at_slot(spec.get_current_slot(store))
|
||||
finalized_slot = spec.compute_start_slot_at_epoch(store.finalized_checkpoint.epoch)
|
||||
assert store.finalized_checkpoint.root == spec.get_ancestor(store, last_fork_block_root, finalized_slot)
|
||||
assert store.finalized_checkpoint.root == spec.get_checkpoint_block(
|
||||
store,
|
||||
last_fork_block_root,
|
||||
store.finalized_checkpoint.epoch
|
||||
)
|
||||
assert spec.get_head(store) == last_fork_block_root
|
||||
|
||||
yield 'steps', test_steps
|
||||
@ -552,7 +555,7 @@ def test_voting_source_beyond_two_epoch(spec, state):
|
||||
- store.voting_source[block_root].epoch != store.justified_checkpoint.epoch, and
|
||||
- store.unrealized_justifications[block_root].epoch >= store.justified_checkpoint.epoch, and
|
||||
- store.voting_source[block_root].epoch + 2 < current_epoch, and
|
||||
- store.finalized_checkpoint.root == get_ancestor(store, block_root, finalized_slot)
|
||||
- store.finalized_checkpoint.root == get_checkpoint_block(store, block_root, store.finalized_checkpoint.epoch)
|
||||
"""
|
||||
test_steps = []
|
||||
# Initialization
|
||||
@ -617,8 +620,11 @@ def test_voting_source_beyond_two_epoch(spec, state):
|
||||
assert store.unrealized_justifications[last_fork_block_root].epoch >= store.justified_checkpoint.epoch
|
||||
# assert store.voting_source[last_fork_block_root].epoch + 2 < \
|
||||
# spec.compute_epoch_at_slot(spec.get_current_slot(store))
|
||||
finalized_slot = spec.compute_start_slot_at_epoch(store.finalized_checkpoint.epoch)
|
||||
assert store.finalized_checkpoint.root == spec.get_ancestor(store, last_fork_block_root, finalized_slot)
|
||||
assert store.finalized_checkpoint.root == spec.get_checkpoint_block(
|
||||
store,
|
||||
last_fork_block_root,
|
||||
store.finalized_checkpoint.epoch
|
||||
)
|
||||
assert spec.get_head(store) == correct_head
|
||||
|
||||
yield 'steps', test_steps
|
||||
@ -641,7 +647,7 @@ def test_incorrect_finalized(spec, state):
|
||||
# Check that the store doesn't allow for a head block that has:
|
||||
# - store.voting_source[block_root].epoch == store.justified_checkpoint.epoch, and
|
||||
# - store.finalized_checkpoint.epoch != GENESIS_EPOCH, and
|
||||
# - store.finalized_checkpoint.root != get_ancestor(store, block_root, finalized_slot)
|
||||
# - store.finalized_checkpoint.root != get_checkpoint_block(store, block_root, store.finalized_checkpoint.epoch)
|
||||
test_steps = []
|
||||
# Initialization
|
||||
store, anchor_block = get_genesis_forkchoice_store_and_block(spec, state)
|
||||
@ -718,7 +724,11 @@ def test_incorrect_finalized(spec, state):
|
||||
assert store.voting_source[last_fork_block_root].epoch == store.justified_checkpoint.epoch
|
||||
assert store.finalized_checkpoint.epoch != spec.GENESIS_EPOCH
|
||||
finalized_slot = spec.compute_start_slot_at_epoch(store.finalized_checkpoint.epoch)
|
||||
assert store.finalized_checkpoint.root != spec.get_ancestor(store, last_fork_block_root, finalized_slot)
|
||||
assert store.finalized_checkpoint.root != spec.get_checkpoint_block(
|
||||
store,
|
||||
block_root,
|
||||
store.finalized_checkpoint.epoch
|
||||
)
|
||||
assert spec.get_head(store) != last_fork_block_root
|
||||
assert spec.get_head(store) == head_root
|
||||
|
||||
|
@ -352,8 +352,11 @@ def test_new_finalized_slot_is_not_justified_checkpoint_ancestor(spec, state):
|
||||
# NOTE: Do not call `on_tick` here
|
||||
yield from add_block(spec, store, block, test_steps)
|
||||
|
||||
finalized_slot = spec.compute_start_slot_at_epoch(store.finalized_checkpoint.epoch)
|
||||
ancestor_at_finalized_slot = spec.get_ancestor(store, pre_store_justified_checkpoint_root, finalized_slot)
|
||||
ancestor_at_finalized_slot = spec.get_checkpoint_block(
|
||||
store,
|
||||
pre_store_justified_checkpoint_root,
|
||||
store.finalized_checkpoint.epoch
|
||||
)
|
||||
assert ancestor_at_finalized_slot != store.finalized_checkpoint.root
|
||||
|
||||
assert store.finalized_checkpoint == another_state.finalized_checkpoint
|
||||
@ -428,8 +431,11 @@ def test_new_finalized_slot_is_justified_checkpoint_ancestor(spec, state):
|
||||
for block in all_blocks:
|
||||
yield from tick_and_add_block(spec, store, block, test_steps)
|
||||
|
||||
finalized_slot = spec.compute_start_slot_at_epoch(store.finalized_checkpoint.epoch)
|
||||
ancestor_at_finalized_slot = spec.get_ancestor(store, pre_store_justified_checkpoint_root, finalized_slot)
|
||||
ancestor_at_finalized_slot = spec.get_checkpoint_block(
|
||||
store,
|
||||
pre_store_justified_checkpoint_root,
|
||||
store.finalized_checkpoint.epoch
|
||||
)
|
||||
assert ancestor_at_finalized_slot == store.finalized_checkpoint.root
|
||||
|
||||
assert store.finalized_checkpoint == another_state.finalized_checkpoint
|
||||
@ -857,10 +863,18 @@ def test_incompatible_justification_update_start_of_epoch(spec, state):
|
||||
# Now add the blocks & check that justification update was triggered
|
||||
for signed_block in signed_blocks:
|
||||
yield from tick_and_add_block(spec, store, signed_block, test_steps)
|
||||
finalized_slot = spec.compute_start_slot_at_epoch(state.finalized_checkpoint.epoch)
|
||||
assert spec.get_ancestor(store, last_block_root, finalized_slot) == state.finalized_checkpoint.root
|
||||
justified_slot = spec.compute_start_slot_at_epoch(state.current_justified_checkpoint.epoch)
|
||||
assert spec.get_ancestor(store, last_block_root, justified_slot) != state.current_justified_checkpoint.root
|
||||
finalized_checkpoint_block = spec.get_checkpoint_block(
|
||||
store,
|
||||
last_block_root,
|
||||
state.finalized_checkpoint.epoch,
|
||||
)
|
||||
assert finalized_checkpoint_block == state.finalized_checkpoint.root
|
||||
justified_checkpoint_block = spec.get_checkpoint_block(
|
||||
store,
|
||||
last_block_root,
|
||||
state.current_justified_checkpoint.epoch,
|
||||
)
|
||||
assert justified_checkpoint_block != state.current_justified_checkpoint.root
|
||||
assert store.finalized_checkpoint.epoch == 4
|
||||
assert store.justified_checkpoint.epoch == 6
|
||||
|
||||
@ -934,10 +948,18 @@ def test_incompatible_justification_update_end_of_epoch(spec, state):
|
||||
# Now add the blocks & check that justification update was triggered
|
||||
for signed_block in signed_blocks:
|
||||
yield from tick_and_add_block(spec, store, signed_block, test_steps)
|
||||
finalized_slot = spec.compute_start_slot_at_epoch(state.finalized_checkpoint.epoch)
|
||||
assert spec.get_ancestor(store, last_block_root, finalized_slot) == state.finalized_checkpoint.root
|
||||
justified_slot = spec.compute_start_slot_at_epoch(state.current_justified_checkpoint.epoch)
|
||||
assert spec.get_ancestor(store, last_block_root, justified_slot) != state.current_justified_checkpoint.root
|
||||
finalized_checkpoint_block = spec.get_checkpoint_block(
|
||||
store,
|
||||
last_block_root,
|
||||
state.finalized_checkpoint.epoch,
|
||||
)
|
||||
assert finalized_checkpoint_block == state.finalized_checkpoint.root
|
||||
justified_checkpoint_block = spec.get_checkpoint_block(
|
||||
store,
|
||||
last_block_root,
|
||||
state.current_justified_checkpoint.epoch,
|
||||
)
|
||||
assert justified_checkpoint_block != state.current_justified_checkpoint.root
|
||||
assert store.finalized_checkpoint.epoch == 4
|
||||
assert store.justified_checkpoint.epoch == 6
|
||||
|
||||
|
@ -45,6 +45,7 @@ Operations:
|
||||
| `execution_payload` | `ExecutionPayload` | `execution_payload` | `process_execution_payload(state, execution_payload)` (new in Bellatrix) |
|
||||
| `withdrawals` | `ExecutionPayload` | `execution_payload` | `process_withdrawals(state, execution_payload)` (new in Capella) |
|
||||
| `bls_to_execution_change` | `SignedBLSToExecutionChange` | `address_change` | `process_bls_to_execution_change(state, address_change)` (new in Capella) |
|
||||
| `deposit_receipt` | `DepositReceipt` | `deposit_receipt` | `process_deposit_receipt(state, deposit_receipt)` (new in EIP6110) |
|
||||
|
||||
Note that `block_header` is not strictly an operation (and is a full `Block`), but processed in the same manner, and hence included here.
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
from eth2spec.gen_helpers.gen_from_tests.gen import run_state_test_generators, combine_mods
|
||||
from eth2spec.test.helpers.constants import PHASE0, ALTAIR, BELLATRIX, CAPELLA, DENEB
|
||||
from eth2spec.test.helpers.constants import PHASE0, ALTAIR, BELLATRIX, CAPELLA, DENEB, EIP6110
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
@ -34,6 +34,8 @@ if __name__ == "__main__":
|
||||
|
||||
deneb_mods = capella_mods
|
||||
|
||||
eip6110_mods = deneb_mods
|
||||
|
||||
# TODO Custody Game testgen is disabled for now
|
||||
# custody_game_mods = {**{key: 'eth2spec.test.custody_game.epoch_processing.test_process_' + key for key in [
|
||||
# 'reveal_deadlines',
|
||||
@ -47,6 +49,7 @@ if __name__ == "__main__":
|
||||
BELLATRIX: bellatrix_mods,
|
||||
CAPELLA: capella_mods,
|
||||
DENEB: deneb_mods,
|
||||
EIP6110: eip6110_mods,
|
||||
}
|
||||
|
||||
run_state_test_generators(runner_name="epoch_processing", all_mods=all_mods)
|
||||
|
@ -1,5 +1,5 @@
|
||||
from eth2spec.gen_helpers.gen_from_tests.gen import run_state_test_generators
|
||||
from eth2spec.test.helpers.constants import PHASE0, ALTAIR, BELLATRIX, CAPELLA, DENEB
|
||||
from eth2spec.test.helpers.constants import PHASE0, ALTAIR, BELLATRIX, CAPELLA, DENEB, EIP6110
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
@ -8,6 +8,7 @@ if __name__ == "__main__":
|
||||
bellatrix_mods = altair_mods # No additional Bellatrix specific finality tests
|
||||
capella_mods = bellatrix_mods # No additional Capella specific finality tests
|
||||
deneb_mods = capella_mods # No additional Deneb specific finality tests
|
||||
eip6110_mods = deneb_mods # No additional EIP6110 specific finality tests
|
||||
|
||||
all_mods = {
|
||||
PHASE0: phase_0_mods,
|
||||
@ -15,6 +16,7 @@ if __name__ == "__main__":
|
||||
BELLATRIX: bellatrix_mods,
|
||||
CAPELLA: capella_mods,
|
||||
DENEB: deneb_mods,
|
||||
EIP6110: eip6110_mods,
|
||||
}
|
||||
|
||||
run_state_test_generators(runner_name="finality", all_mods=all_mods)
|
||||
|
@ -1,5 +1,5 @@
|
||||
from eth2spec.gen_helpers.gen_from_tests.gen import run_state_test_generators, combine_mods
|
||||
from eth2spec.test.helpers.constants import ALTAIR, BELLATRIX, CAPELLA, DENEB
|
||||
from eth2spec.test.helpers.constants import ALTAIR, BELLATRIX, CAPELLA, DENEB, EIP6110
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
@ -19,13 +19,15 @@ if __name__ == "__main__":
|
||||
]}
|
||||
bellatrix_mods = combine_mods(_new_bellatrix_mods, altair_mods)
|
||||
capella_mods = bellatrix_mods # No additional Capella specific fork choice tests
|
||||
deneb_mods = capella_mods # No additional Capella specific fork choice tests
|
||||
deneb_mods = capella_mods # No additional Deneb specific fork choice tests
|
||||
eip6110_mods = deneb_mods # No additional EIP6110 specific fork choice tests
|
||||
|
||||
all_mods = {
|
||||
ALTAIR: altair_mods,
|
||||
BELLATRIX: bellatrix_mods,
|
||||
CAPELLA: capella_mods,
|
||||
DENEB: deneb_mods,
|
||||
EIP6110: eip6110_mods,
|
||||
}
|
||||
|
||||
run_state_test_generators(runner_name="fork_choice", all_mods=all_mods)
|
||||
|
@ -1,5 +1,5 @@
|
||||
from eth2spec.gen_helpers.gen_from_tests.gen import run_state_test_generators, combine_mods
|
||||
from eth2spec.test.helpers.constants import PHASE0, ALTAIR, BELLATRIX, CAPELLA, DENEB
|
||||
from eth2spec.test.helpers.constants import PHASE0, ALTAIR, BELLATRIX, CAPELLA, DENEB, EIP6110
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
@ -17,12 +17,14 @@ if __name__ == "__main__":
|
||||
bellatrix_mods = combine_mods(_new_bellatrix_mods, altair_mods)
|
||||
capella_mods = bellatrix_mods # No additional Capella specific genesis tests
|
||||
deneb_mods = capella_mods # No additional Deneb specific genesis tests
|
||||
eip6110_mods = deneb_mods # No additional EIP6110 specific genesis tests
|
||||
all_mods = {
|
||||
PHASE0: phase_0_mods,
|
||||
ALTAIR: altair_mods,
|
||||
BELLATRIX: bellatrix_mods,
|
||||
CAPELLA: capella_mods,
|
||||
DENEB: deneb_mods,
|
||||
EIP6110: eip6110_mods,
|
||||
}
|
||||
|
||||
run_state_test_generators(runner_name="genesis", all_mods=all_mods)
|
||||
|
@ -1,4 +1,4 @@
|
||||
from eth2spec.test.helpers.constants import ALTAIR, BELLATRIX, CAPELLA, DENEB
|
||||
from eth2spec.test.helpers.constants import ALTAIR, BELLATRIX, CAPELLA, DENEB, EIP6110
|
||||
from eth2spec.gen_helpers.gen_from_tests.gen import combine_mods, run_state_test_generators
|
||||
|
||||
|
||||
@ -15,12 +15,14 @@ if __name__ == "__main__":
|
||||
]}
|
||||
capella_mods = combine_mods(_new_capella_mods, bellatrix_mods)
|
||||
deneb_mods = capella_mods
|
||||
eip6110_mods = deneb_mods
|
||||
|
||||
all_mods = {
|
||||
ALTAIR: altair_mods,
|
||||
BELLATRIX: bellatrix_mods,
|
||||
CAPELLA: capella_mods,
|
||||
DENEB: deneb_mods,
|
||||
EIP6110: eip6110_mods,
|
||||
}
|
||||
|
||||
run_state_test_generators(runner_name="light_client", all_mods=all_mods)
|
||||
|
@ -1,5 +1,5 @@
|
||||
from eth2spec.gen_helpers.gen_from_tests.gen import run_state_test_generators, combine_mods
|
||||
from eth2spec.test.helpers.constants import PHASE0, ALTAIR, BELLATRIX, CAPELLA, DENEB
|
||||
from eth2spec.test.helpers.constants import PHASE0, ALTAIR, BELLATRIX, CAPELLA, DENEB, EIP6110
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
@ -38,6 +38,11 @@ if __name__ == "__main__":
|
||||
|
||||
deneb_mods = capella_mods
|
||||
|
||||
_new_eip6110_mods = {key: 'eth2spec.test.eip6110.block_processing.test_process_' + key for key in [
|
||||
'deposit_receipt',
|
||||
]}
|
||||
eip6110_mods = combine_mods(_new_eip6110_mods, deneb_mods)
|
||||
|
||||
# TODO Custody Game testgen is disabled for now
|
||||
# _new_custody_game_mods = {key: 'eth2spec.test.custody_game.block_processing.test_process_' + key for key in [
|
||||
# 'attestation',
|
||||
@ -54,6 +59,7 @@ if __name__ == "__main__":
|
||||
BELLATRIX: bellatrix_mods,
|
||||
CAPELLA: capella_mods,
|
||||
DENEB: deneb_mods,
|
||||
EIP6110: eip6110_mods,
|
||||
}
|
||||
|
||||
run_state_test_generators(runner_name="operations", all_mods=all_mods)
|
||||
|
@ -1,5 +1,5 @@
|
||||
from eth2spec.gen_helpers.gen_from_tests.gen import run_state_test_generators
|
||||
from eth2spec.test.helpers.constants import PHASE0, ALTAIR, BELLATRIX, CAPELLA, DENEB
|
||||
from eth2spec.test.helpers.constants import PHASE0, ALTAIR, BELLATRIX, CAPELLA, DENEB, EIP6110
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
@ -17,6 +17,7 @@ if __name__ == "__main__":
|
||||
bellatrix_mods = altair_mods
|
||||
capella_mods = bellatrix_mods
|
||||
deneb_mods = capella_mods
|
||||
eip6110_mods = deneb_mods
|
||||
|
||||
all_mods = {
|
||||
PHASE0: phase_0_mods,
|
||||
@ -24,6 +25,7 @@ if __name__ == "__main__":
|
||||
BELLATRIX: bellatrix_mods,
|
||||
CAPELLA: capella_mods,
|
||||
DENEB: deneb_mods,
|
||||
EIP6110: eip6110_mods,
|
||||
}
|
||||
|
||||
run_state_test_generators(runner_name="rewards", all_mods=all_mods)
|
||||
|
@ -1,4 +1,4 @@
|
||||
from eth2spec.test.helpers.constants import PHASE0, ALTAIR, BELLATRIX, CAPELLA, DENEB
|
||||
from eth2spec.test.helpers.constants import PHASE0, ALTAIR, BELLATRIX, CAPELLA, DENEB, EIP6110
|
||||
from eth2spec.gen_helpers.gen_from_tests.gen import run_state_test_generators, combine_mods
|
||||
|
||||
|
||||
@ -28,12 +28,18 @@ if __name__ == "__main__":
|
||||
]}
|
||||
deneb_mods = combine_mods(_new_deneb_mods, capella_mods)
|
||||
|
||||
_new_eip6110_mods = {key: 'eth2spec.test.eip6110.sanity.' + key for key in [
|
||||
'blocks',
|
||||
]}
|
||||
eip6110_mods = combine_mods(_new_eip6110_mods, deneb_mods)
|
||||
|
||||
all_mods = {
|
||||
PHASE0: phase_0_mods,
|
||||
ALTAIR: altair_mods,
|
||||
BELLATRIX: bellatrix_mods,
|
||||
CAPELLA: capella_mods,
|
||||
DENEB: deneb_mods,
|
||||
EIP6110: eip6110_mods,
|
||||
}
|
||||
|
||||
run_state_test_generators(runner_name="sanity", all_mods=all_mods)
|
||||
|
@ -1,5 +1,5 @@
|
||||
from eth2spec.gen_helpers.gen_from_tests.gen import run_state_test_generators
|
||||
from eth2spec.test.helpers.constants import BELLATRIX, CAPELLA, DENEB
|
||||
from eth2spec.test.helpers.constants import BELLATRIX, CAPELLA, DENEB, EIP6110
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
@ -8,11 +8,13 @@ if __name__ == "__main__":
|
||||
]}
|
||||
capella_mods = bellatrix_mods
|
||||
deneb_mods = capella_mods
|
||||
eip6110_mods = deneb_mods
|
||||
|
||||
all_mods = {
|
||||
BELLATRIX: bellatrix_mods,
|
||||
CAPELLA: capella_mods,
|
||||
DENEB: deneb_mods,
|
||||
EIP6110: eip6110_mods,
|
||||
}
|
||||
|
||||
run_state_test_generators(runner_name="sync", all_mods=all_mods)
|
||||
|
Loading…
x
Reference in New Issue
Block a user