From e6f7c99b77a6918eff0b21c7fc534a802adc6352 Mon Sep 17 00:00:00 2001 From: dapplion <35266934+dapplion@users.noreply.github.com> Date: Tue, 12 Sep 2023 10:33:36 +0200 Subject: [PATCH 01/14] Add limit inbound churn --- specs/_features/limit_churn/beacon_chain.md | 88 +++++++++++++++++++++ 1 file changed, 88 insertions(+) create mode 100644 specs/_features/limit_churn/beacon_chain.md diff --git a/specs/_features/limit_churn/beacon_chain.md b/specs/_features/limit_churn/beacon_chain.md new file mode 100644 index 0000000000..7a7a98bf05 --- /dev/null +++ b/specs/_features/limit_churn/beacon_chain.md @@ -0,0 +1,88 @@ +Limit churn -- The Beacon Chain + +## Table of contents + + + + + +- [Introduction](#introduction) +- [Configuration](#configuration) + - [Validator cycle](#validator-cycle) +- [Helper functions](#helper-functions) + - [Beacon state accessors](#beacon-state-accessors) + - [New `get_validator_inbound_churn_limit`](#new-get_validator_inbound_churn_limit) +- [Beacon chain state transition function](#beacon-chain-state-transition-function) + - [Epoch processing](#epoch-processing) + - [Registry updates](#registry-updates) + + + + +## Introduction + +This is the beacon chain specification to limit the max inbound churn value, motivated to limit the validator active set growth rate. + +*Note:* This specification is built upon [Capella](../../capella/beacon_chain.md) and is under active development. + +## Configuration + +### Validator cycle + +| Name | Value | +| - | - | +| `MAX_PER_EPOCH_INBOUND_CHURN_LIMIT` | `uint64(12)` (= 12) | + +## Helper functions + +### Beacon state accessors + +#### New `get_validator_inbound_churn_limit` + +```python +def get_validator_inbound_churn_limit(state: BeaconState) -> uint64: + """ + Return the validator inbound churn limit for the current epoch. + """ + active_validator_indices = get_active_validator_indices(state, get_current_epoch(state)) + return min( + MAX_PER_EPOCH_INBOUND_CHURN_LIMIT, + max( + MIN_PER_EPOCH_CHURN_LIMIT, + uint64(len(active_validator_indices)) // CHURN_LIMIT_QUOTIENT + ) + ) +``` + +## Beacon chain state transition function + +### Epoch processing + +#### Registry updates + +```python +def process_registry_updates(state: BeaconState) -> None: + # Process activation eligibility and ejections + for index, validator in enumerate(state.validators): + if is_eligible_for_activation_queue(validator): + validator.activation_eligibility_epoch = get_current_epoch(state) + 1 + + if ( + is_active_validator(validator, get_current_epoch(state)) + and validator.effective_balance <= EJECTION_BALANCE + ): + initiate_validator_exit(state, ValidatorIndex(index)) + + # Queue validators eligible for activation and not yet dequeued for activation + activation_queue = sorted([ + index for index, validator in enumerate(state.validators) + if is_eligible_for_activation(state, validator) + # Order by the sequence of activation_eligibility_epoch setting and then index + ], key=lambda index: (state.validators[index].activation_eligibility_epoch, index)) + # Dequeued validators for activation up to churn limit + # [Modified in limit churn] + for index in activation_queue[:get_validator_inbound_churn_limit(state)]: + validator = state.validators[index] + validator.activation_epoch = compute_activation_exit_epoch(get_current_epoch(state)) +``` + From fd37ffcb61325753edbd8ff56a4cd2e45b5f244f Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Tue, 12 Sep 2023 21:35:46 +0800 Subject: [PATCH 02/14] Add _features/eip7668 and make linter happy --- .gitignore | 1 + pysetup/constants.py | 1 + pysetup/md_doc_paths.py | 2 + pysetup/spec_builders/__init__.py | 3 +- pysetup/spec_builders/eip7668.py | 12 ++ .../{limit_churn => eip7668}/beacon_chain.md | 10 +- specs/_features/eip7668/fork.md | 139 ++++++++++++++++++ 7 files changed, 162 insertions(+), 6 deletions(-) create mode 100644 pysetup/spec_builders/eip7668.py rename specs/_features/{limit_churn => eip7668}/beacon_chain.md (94%) create mode 100644 specs/_features/eip7668/fork.md diff --git a/.gitignore b/.gitignore index cdfddfb0c3..7eacf101cf 100644 --- a/.gitignore +++ b/.gitignore @@ -23,6 +23,7 @@ tests/core/pyspec/eth2spec/capella/ tests/core/pyspec/eth2spec/deneb/ tests/core/pyspec/eth2spec/eip6110/ tests/core/pyspec/eth2spec/eip7002/ +tests/core/pyspec/eth2spec/eip7668/ tests/core/pyspec/eth2spec/whisk/ # coverage reports diff --git a/pysetup/constants.py b/pysetup/constants.py index 8d53455634..f6f8ed8e43 100644 --- a/pysetup/constants.py +++ b/pysetup/constants.py @@ -6,6 +6,7 @@ DENEB = 'deneb' EIP6110 = 'eip6110' EIP7002 = 'eip7002' +EIP7668 = 'eip7668' WHISK = 'whisk' diff --git a/pysetup/md_doc_paths.py b/pysetup/md_doc_paths.py index 781ae41db3..8031b09361 100644 --- a/pysetup/md_doc_paths.py +++ b/pysetup/md_doc_paths.py @@ -9,6 +9,7 @@ EIP6110, WHISK, EIP7002, + EIP7668, ) @@ -21,6 +22,7 @@ EIP6110: DENEB, WHISK: CAPELLA, EIP7002: CAPELLA, + EIP7668: CAPELLA, } ALL_FORKS = list(PREVIOUS_FORK_OF.keys()) diff --git a/pysetup/spec_builders/__init__.py b/pysetup/spec_builders/__init__.py index 794ae50d29..6f0f1d2032 100644 --- a/pysetup/spec_builders/__init__.py +++ b/pysetup/spec_builders/__init__.py @@ -5,6 +5,7 @@ from .deneb import DenebSpecBuilder from .eip6110 import EIP6110SpecBuilder from .eip7002 import EIP7002SpecBuilder +from .eip7668 import EIP7668SpecBuilder from .whisk import WhiskSpecBuilder @@ -12,6 +13,6 @@ builder.fork: builder for builder in ( Phase0SpecBuilder, AltairSpecBuilder, BellatrixSpecBuilder, CapellaSpecBuilder, DenebSpecBuilder, - EIP6110SpecBuilder, EIP7002SpecBuilder, WhiskSpecBuilder, + EIP6110SpecBuilder, EIP7002SpecBuilder, EIP7668SpecBuilder, WhiskSpecBuilder, ) } diff --git a/pysetup/spec_builders/eip7668.py b/pysetup/spec_builders/eip7668.py new file mode 100644 index 0000000000..55332dd9ee --- /dev/null +++ b/pysetup/spec_builders/eip7668.py @@ -0,0 +1,12 @@ +from .base import BaseSpecBuilder +from ..constants import EIP7668 + + +class EIP7668SpecBuilder(BaseSpecBuilder): + fork: str = EIP7668 + + @classmethod + def imports(cls, preset_name: str): + return super().imports(preset_name) + f''' +from eth2spec.capella import {preset_name} as capella +''' diff --git a/specs/_features/limit_churn/beacon_chain.md b/specs/_features/eip7668/beacon_chain.md similarity index 94% rename from specs/_features/limit_churn/beacon_chain.md rename to specs/_features/eip7668/beacon_chain.md index 7a7a98bf05..aeba214ebf 100644 --- a/specs/_features/limit_churn/beacon_chain.md +++ b/specs/_features/eip7668/beacon_chain.md @@ -46,11 +46,11 @@ def get_validator_inbound_churn_limit(state: BeaconState) -> uint64: """ active_validator_indices = get_active_validator_indices(state, get_current_epoch(state)) return min( - MAX_PER_EPOCH_INBOUND_CHURN_LIMIT, - max( - MIN_PER_EPOCH_CHURN_LIMIT, - uint64(len(active_validator_indices)) // CHURN_LIMIT_QUOTIENT - ) + MAX_PER_EPOCH_INBOUND_CHURN_LIMIT, + max( + MIN_PER_EPOCH_CHURN_LIMIT, + uint64(len(active_validator_indices)) // CHURN_LIMIT_QUOTIENT, + ), ) ``` diff --git a/specs/_features/eip7668/fork.md b/specs/_features/eip7668/fork.md new file mode 100644 index 0000000000..93d2a7d521 --- /dev/null +++ b/specs/_features/eip7668/fork.md @@ -0,0 +1,139 @@ +# EIP-7668 -- Fork Logic + +**Notice**: This document is a work-in-progress for researchers and implementers. + +## Table of contents + + + + +- [Introduction](#introduction) +- [Configuration](#configuration) +- [Helper functions](#helper-functions) + - [Misc](#misc) + - [Modified `compute_fork_version`](#modified-compute_fork_version) +- [Fork to EIP-7668](#fork-to-eip-7668) + - [Fork trigger](#fork-trigger) + - [Upgrading the state](#upgrading-the-state) + + + +## Introduction + +This document describes the process of EIP-7668 upgrade. + +## Configuration + +Warning: this configuration is not definitive. + +| Name | Value | +| - | - | +| `EIP7668_FORK_VERSION` | `Version('0x05000000')` | +| `EIP7668_FORK_EPOCH` | `Epoch(18446744073709551615)` **TBD** | + +## Helper functions + +### Misc + +#### Modified `compute_fork_version` + +```python +def compute_fork_version(epoch: Epoch) -> Version: + """ + Return the fork version at the given ``epoch``. + """ + if epoch >= EIP7668_FORK_EPOCH: + return EIP7668_FORK_VERSION + if epoch >= CAPELLA_FORK_EPOCH: + return CAPELLA_FORK_VERSION + if epoch >= BELLATRIX_FORK_EPOCH: + return BELLATRIX_FORK_VERSION + if epoch >= ALTAIR_FORK_EPOCH: + return ALTAIR_FORK_VERSION + return GENESIS_FORK_VERSION +``` + +## Fork to EIP-7668 + +### Fork trigger + +TBD. This fork is defined for testing purposes, the EIP may be combined with other consensus-layer upgrade. +For now, we assume the condition will be triggered at epoch `EIP7668_FORK_EPOCH`. + +Note that for the pure EIP-7668 networks, we don't apply `upgrade_to_eip7668` since it starts with EIP-7668 version logic. + +### Upgrading the state + +If `state.slot % SLOTS_PER_EPOCH == 0` and `compute_epoch_at_slot(state.slot) == EIP7668_FORK_EPOCH`, +an irregular state change is made to upgrade to EIP-7668. + +```python +def upgrade_to_eip7668(pre: capella.BeaconState) -> BeaconState: + epoch = capella.get_current_epoch(pre) + latest_execution_payload_header = ExecutionPayloadHeader( + parent_hash=pre.latest_execution_payload_header.parent_hash, + fee_recipient=pre.latest_execution_payload_header.fee_recipient, + state_root=pre.latest_execution_payload_header.state_root, + receipts_root=pre.latest_execution_payload_header.receipts_root, + logs_bloom=pre.latest_execution_payload_header.logs_bloom, + prev_randao=pre.latest_execution_payload_header.prev_randao, + block_number=pre.latest_execution_payload_header.block_number, + gas_limit=pre.latest_execution_payload_header.gas_limit, + gas_used=pre.latest_execution_payload_header.gas_used, + timestamp=pre.latest_execution_payload_header.timestamp, + extra_data=pre.latest_execution_payload_header.extra_data, + base_fee_per_gas=pre.latest_execution_payload_header.base_fee_per_gas, + block_hash=pre.latest_execution_payload_header.block_hash, + transactions_root=pre.latest_execution_payload_header.transactions_root, + withdrawals_root=pre.latest_execution_payload_header.withdrawals_root, + ) + post = BeaconState( + # Versioning + genesis_time=pre.genesis_time, + genesis_validators_root=pre.genesis_validators_root, + slot=pre.slot, + fork=Fork( + previous_version=pre.fork.current_version, + current_version=EIP7668_FORK_VERSION, # [Modified in EIP-7668] + epoch=epoch, + ), + # History + latest_block_header=pre.latest_block_header, + block_roots=pre.block_roots, + state_roots=pre.state_roots, + historical_roots=pre.historical_roots, + # Eth1 + eth1_data=pre.eth1_data, + eth1_data_votes=pre.eth1_data_votes, + eth1_deposit_index=pre.eth1_deposit_index, + # Registry + validators=pre.validators, + balances=pre.balances, + # Randomness + randao_mixes=pre.randao_mixes, + # Slashings + slashings=pre.slashings, + # Participation + previous_epoch_participation=pre.previous_epoch_participation, + current_epoch_participation=pre.current_epoch_participation, + # Finality + justification_bits=pre.justification_bits, + previous_justified_checkpoint=pre.previous_justified_checkpoint, + current_justified_checkpoint=pre.current_justified_checkpoint, + finalized_checkpoint=pre.finalized_checkpoint, + # Inactivity + inactivity_scores=pre.inactivity_scores, + # Sync + current_sync_committee=pre.current_sync_committee, + next_sync_committee=pre.next_sync_committee, + # Execution-layer + latest_execution_payload_header=latest_execution_payload_header, + # Withdrawals + next_withdrawal_index=pre.next_withdrawal_index, + next_withdrawal_validator_index=pre.next_withdrawal_validator_index, + # Deep history valid from Capella onwards + historical_summaries=pre.historical_summaries, + ) + + return post +``` From cc3ced59653c39fb05a46ff33735144623ccdb1e Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Tue, 12 Sep 2023 21:48:35 +0800 Subject: [PATCH 03/14] Enable eip7668 pytest --- configs/mainnet.yaml | 6 ++++++ configs/minimal.yaml | 6 ++++++ tests/core/pyspec/eth2spec/test/context.py | 5 ++++- tests/core/pyspec/eth2spec/test/helpers/constants.py | 2 ++ tests/core/pyspec/eth2spec/test/helpers/forks.py | 4 +++- tests/core/pyspec/eth2spec/test/helpers/genesis.py | 5 ++++- 6 files changed, 25 insertions(+), 3 deletions(-) diff --git a/configs/mainnet.yaml b/configs/mainnet.yaml index bcd18e5cdc..87757d12ea 100644 --- a/configs/mainnet.yaml +++ b/configs/mainnet.yaml @@ -56,6 +56,9 @@ EIP6110_FORK_EPOCH: 18446744073709551615 # EIP7002 EIP7002_FORK_VERSION: 0x05000000 # temporary stub EIP7002_FORK_EPOCH: 18446744073709551615 +# EIP7668 +EIP7668_FORK_VERSION: 0x05000000 # temporary stub +EIP7668_FORK_EPOCH: 18446744073709551615 # WHISK WHISK_FORK_VERSION: 0x06000000 # temporary stub WHISK_FORK_EPOCH: 18446744073709551615 @@ -146,3 +149,6 @@ BLOB_SIDECAR_SUBNET_COUNT: 6 WHISK_EPOCHS_PER_SHUFFLING_PHASE: 256 # `Epoch(2)` WHISK_PROPOSER_SELECTION_GAP: 2 + +# EIP7668 +MAX_PER_EPOCH_INBOUND_CHURN_LIMIT: 12 diff --git a/configs/minimal.yaml b/configs/minimal.yaml index d23ca7adb2..642603bdda 100644 --- a/configs/minimal.yaml +++ b/configs/minimal.yaml @@ -55,6 +55,9 @@ EIP6110_FORK_EPOCH: 18446744073709551615 # EIP7002 EIP7002_FORK_VERSION: 0x05000001 EIP7002_FORK_EPOCH: 18446744073709551615 +# EIP7668 +EIP7668_FORK_VERSION: 0x05000001 # temporary stub +EIP7668_FORK_EPOCH: 18446744073709551615 # WHISK WHISK_FORK_VERSION: 0x06000001 WHISK_FORK_EPOCH: 18446744073709551615 @@ -145,3 +148,6 @@ BLOB_SIDECAR_SUBNET_COUNT: 6 # Whisk WHISK_EPOCHS_PER_SHUFFLING_PHASE: 4 WHISK_PROPOSER_SELECTION_GAP: 1 + +# EIP7668 +MAX_PER_EPOCH_INBOUND_CHURN_LIMIT: 12 diff --git a/tests/core/pyspec/eth2spec/test/context.py b/tests/core/pyspec/eth2spec/test/context.py index 0c9d4a1ec5..1da2947214 100644 --- a/tests/core/pyspec/eth2spec/test/context.py +++ b/tests/core/pyspec/eth2spec/test/context.py @@ -10,12 +10,13 @@ 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.eip7002 import mainnet as spec_eip7002_mainnet, minimal as spec_eip7002_minimal +from eth2spec.eip7668 import mainnet as spec_eip7668_mainnet, minimal as spec_eip7668_minimal from eth2spec.utils import bls from .exceptions import SkippedTest from .helpers.constants import ( PHASE0, ALTAIR, BELLATRIX, CAPELLA, DENEB, - EIP6110, EIP7002, + EIP6110, EIP7002, EIP7668, MINIMAL, MAINNET, ALL_PHASES, ALL_FORK_UPGRADES, @@ -85,6 +86,7 @@ class ForkMeta: DENEB: spec_deneb_minimal, EIP6110: spec_eip6110_minimal, EIP7002: spec_eip7002_minimal, + EIP7668: spec_eip7668_minimal, }, MAINNET: { PHASE0: spec_phase0_mainnet, @@ -94,6 +96,7 @@ class ForkMeta: DENEB: spec_deneb_mainnet, EIP6110: spec_eip6110_mainnet, EIP7002: spec_eip7002_mainnet, + EIP7668: spec_eip7668_mainnet, }, } diff --git a/tests/core/pyspec/eth2spec/test/helpers/constants.py b/tests/core/pyspec/eth2spec/test/helpers/constants.py index 82e4f9d0a5..a90edb2ec7 100644 --- a/tests/core/pyspec/eth2spec/test/helpers/constants.py +++ b/tests/core/pyspec/eth2spec/test/helpers/constants.py @@ -18,6 +18,7 @@ DAS = SpecForkName('das') EIP6110 = SpecForkName('eip6110') EIP7002 = SpecForkName('eip7002') +EIP7668 = SpecForkName('eip7668') # # SpecFork settings @@ -34,6 +35,7 @@ # Experimental patches EIP6110, EIP7002, + EIP7668, ) # The forks that have light client specs LIGHT_CLIENT_TESTING_FORKS = (*[item for item in MAINNET_FORKS if item != PHASE0], DENEB) diff --git a/tests/core/pyspec/eth2spec/test/helpers/forks.py b/tests/core/pyspec/eth2spec/test/helpers/forks.py index 492af47fe3..2e247dfc3a 100644 --- a/tests/core/pyspec/eth2spec/test/helpers/forks.py +++ b/tests/core/pyspec/eth2spec/test/helpers/forks.py @@ -1,10 +1,12 @@ from .constants import ( PHASE0, ALTAIR, BELLATRIX, CAPELLA, DENEB, - EIP6110, EIP7002, + EIP6110, EIP7002, EIP7668, ) def is_post_fork(a, b): + if a == EIP7668: + return b in [PHASE0, ALTAIR, BELLATRIX, CAPELLA, EIP7668] if a == EIP7002: return b in [PHASE0, ALTAIR, BELLATRIX, CAPELLA, EIP7002] if a == EIP6110: diff --git a/tests/core/pyspec/eth2spec/test/helpers/genesis.py b/tests/core/pyspec/eth2spec/test/helpers/genesis.py index e55bdef5ce..4f2f0721f2 100644 --- a/tests/core/pyspec/eth2spec/test/helpers/genesis.py +++ b/tests/core/pyspec/eth2spec/test/helpers/genesis.py @@ -1,5 +1,5 @@ from eth2spec.test.helpers.constants import ( - ALTAIR, BELLATRIX, CAPELLA, DENEB, EIP6110, EIP7002, + ALTAIR, BELLATRIX, CAPELLA, DENEB, EIP6110, EIP7002, EIP7668, ) from eth2spec.test.helpers.execution_payload import ( compute_el_header_block_hash, @@ -93,6 +93,9 @@ def create_genesis_state(spec, validator_balances, activation_threshold): elif spec.fork == EIP7002: previous_version = spec.config.CAPELLA_FORK_VERSION current_version = spec.config.EIP7002_FORK_VERSION + elif spec.fork == EIP7668: + previous_version = spec.config.CAPELLA_FORK_VERSION + current_version = spec.config.EIP7668_FORK_VERSION state = spec.BeaconState( genesis_time=0, From 298a6304de2e46c70a26f1e9a34948dfa8a0b762 Mon Sep 17 00:00:00 2001 From: dapplion <35266934+dapplion@users.noreply.github.com> Date: Wed, 13 Sep 2023 10:57:52 +0200 Subject: [PATCH 04/14] review PR --- specs/_features/eip7668/beacon_chain.md | 27 ++++++++++--------------- 1 file changed, 11 insertions(+), 16 deletions(-) diff --git a/specs/_features/eip7668/beacon_chain.md b/specs/_features/eip7668/beacon_chain.md index aeba214ebf..c14fca32e1 100644 --- a/specs/_features/eip7668/beacon_chain.md +++ b/specs/_features/eip7668/beacon_chain.md @@ -1,4 +1,4 @@ -Limit churn -- The Beacon Chain +EIP-7668 -- The Beacon Chain ## Table of contents @@ -11,7 +11,7 @@ Limit churn -- The Beacon Chain - [Validator cycle](#validator-cycle) - [Helper functions](#helper-functions) - [Beacon state accessors](#beacon-state-accessors) - - [New `get_validator_inbound_churn_limit`](#new-get_validator_inbound_churn_limit) + - [New `get_validator_activation_churn_limit`](#new-get_validator_activation_churn_limit) - [Beacon chain state transition function](#beacon-chain-state-transition-function) - [Epoch processing](#epoch-processing) - [Registry updates](#registry-updates) @@ -31,27 +31,20 @@ This is the beacon chain specification to limit the max inbound churn value, mot | Name | Value | | - | - | -| `MAX_PER_EPOCH_INBOUND_CHURN_LIMIT` | `uint64(12)` (= 12) | +| `MAX_PER_EPOCH_ACTIVATION_CHURN_LIMIT` | `uint64(12)` (= 12) | ## Helper functions ### Beacon state accessors -#### New `get_validator_inbound_churn_limit` +#### New `get_validator_activation_churn_limit` ```python -def get_validator_inbound_churn_limit(state: BeaconState) -> uint64: +def get_validator_activation_churn_limit(state: BeaconState) -> uint64: """ - Return the validator inbound churn limit for the current epoch. + Return the validator activation churn limit for the current epoch. """ - active_validator_indices = get_active_validator_indices(state, get_current_epoch(state)) - return min( - MAX_PER_EPOCH_INBOUND_CHURN_LIMIT, - max( - MIN_PER_EPOCH_CHURN_LIMIT, - uint64(len(active_validator_indices)) // CHURN_LIMIT_QUOTIENT, - ), - ) + return min(MAX_PER_EPOCH_INBOUND_CHURN_LIMIT, get_validator_churn_limit(state)) ``` ## Beacon chain state transition function @@ -60,6 +53,8 @@ def get_validator_inbound_churn_limit(state: BeaconState) -> uint64: #### Registry updates +Note: The function `process_registry_updates` is modified to utilize `get_validator_inbound_churn_limit()` the rate limit the activation queue for EIP-7668. + ```python def process_registry_updates(state: BeaconState) -> None: # Process activation eligibility and ejections @@ -80,8 +75,8 @@ def process_registry_updates(state: BeaconState) -> None: # Order by the sequence of activation_eligibility_epoch setting and then index ], key=lambda index: (state.validators[index].activation_eligibility_epoch, index)) # Dequeued validators for activation up to churn limit - # [Modified in limit churn] - for index in activation_queue[:get_validator_inbound_churn_limit(state)]: + # [Modified in EIP7668] + for index in activation_queue[:get_validator_activation_churn_limit(state)]: validator = state.validators[index] validator.activation_epoch = compute_activation_exit_epoch(get_current_epoch(state)) ``` From 417b95c3e6376d61c397b29e103f8f7e60bc1a62 Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Wed, 13 Sep 2023 17:04:39 +0800 Subject: [PATCH 05/14] Add basic activation churn limit tests --- configs/mainnet.yaml | 2 +- configs/minimal.yaml | 7 +- specs/_features/eip7668/beacon_chain.md | 2 +- tests/core/pyspec/eth2spec/test/context.py | 27 +++++- .../pyspec/eth2spec/test/eip7668/__init__.py | 0 .../test/eip7668/epoch_processing/__init__.py | 0 .../test_process_registry_updates.py | 86 +++++++++++++++++++ .../pyspec/eth2spec/test/helpers/forks.py | 4 + .../test_process_registry_updates.py | 14 +-- 9 files changed, 129 insertions(+), 13 deletions(-) create mode 100644 tests/core/pyspec/eth2spec/test/eip7668/__init__.py create mode 100644 tests/core/pyspec/eth2spec/test/eip7668/epoch_processing/__init__.py create mode 100644 tests/core/pyspec/eth2spec/test/eip7668/epoch_processing/test_process_registry_updates.py diff --git a/configs/mainnet.yaml b/configs/mainnet.yaml index 87757d12ea..1b38591aae 100644 --- a/configs/mainnet.yaml +++ b/configs/mainnet.yaml @@ -151,4 +151,4 @@ WHISK_EPOCHS_PER_SHUFFLING_PHASE: 256 WHISK_PROPOSER_SELECTION_GAP: 2 # EIP7668 -MAX_PER_EPOCH_INBOUND_CHURN_LIMIT: 12 +MAX_PER_EPOCH_ACTIVATION_CHURN_LIMIT: 12 diff --git a/configs/minimal.yaml b/configs/minimal.yaml index 642603bdda..edfb0f7e84 100644 --- a/configs/minimal.yaml +++ b/configs/minimal.yaml @@ -85,8 +85,8 @@ INACTIVITY_SCORE_BIAS: 4 INACTIVITY_SCORE_RECOVERY_RATE: 16 # 2**4 * 10**9 (= 16,000,000,000) Gwei EJECTION_BALANCE: 16000000000 -# 2**2 (= 4) -MIN_PER_EPOCH_CHURN_LIMIT: 4 +# [customized] +MIN_PER_EPOCH_CHURN_LIMIT: 2 # [customized] scale queue churn at much lower validator counts for testing CHURN_LIMIT_QUOTIENT: 32 @@ -150,4 +150,5 @@ WHISK_EPOCHS_PER_SHUFFLING_PHASE: 4 WHISK_PROPOSER_SELECTION_GAP: 1 # EIP7668 -MAX_PER_EPOCH_INBOUND_CHURN_LIMIT: 12 +# [customized] +MAX_PER_EPOCH_ACTIVATION_CHURN_LIMIT: 4 diff --git a/specs/_features/eip7668/beacon_chain.md b/specs/_features/eip7668/beacon_chain.md index c14fca32e1..a8952b93af 100644 --- a/specs/_features/eip7668/beacon_chain.md +++ b/specs/_features/eip7668/beacon_chain.md @@ -44,7 +44,7 @@ def get_validator_activation_churn_limit(state: BeaconState) -> uint64: """ Return the validator activation churn limit for the current epoch. """ - return min(MAX_PER_EPOCH_INBOUND_CHURN_LIMIT, get_validator_churn_limit(state)) + return min(MAX_PER_EPOCH_ACTIVATION_CHURN_LIMIT, get_validator_churn_limit(state)) ``` ## Beacon chain state transition function diff --git a/tests/core/pyspec/eth2spec/test/context.py b/tests/core/pyspec/eth2spec/test/context.py index 1da2947214..f1a1a70349 100644 --- a/tests/core/pyspec/eth2spec/test/context.py +++ b/tests/core/pyspec/eth2spec/test/context.py @@ -165,14 +165,34 @@ def default_balances(spec: Spec): return [spec.MAX_EFFECTIVE_BALANCE] * num_validators -def scaled_churn_balances(spec: Spec): +def scaled_churn_balances_min_churn_limit(spec: Spec): """ Helper method to create enough validators to scale the churn limit. (This is *firmly* over the churn limit -- thus the +2 instead of just +1) See the second argument of ``max`` in ``get_validator_churn_limit``. - Usage: `@with_custom_state(balances_fn=scaled_churn_balances, ...)` + Usage: `@with_custom_state(balances_fn=scaled_churn_balances_min_churn_limit, ...)` """ - num_validators = spec.config.CHURN_LIMIT_QUOTIENT * (2 + spec.config.MIN_PER_EPOCH_CHURN_LIMIT) + num_validators = spec.config.CHURN_LIMIT_QUOTIENT * (spec.config.MIN_PER_EPOCH_CHURN_LIMIT + 2) + return [spec.MAX_EFFECTIVE_BALANCE] * num_validators + + +def scaled_churn_balances_equal_inbound_churn_limit(spec: Spec): + """ + Helper method to create enough validators to scale the churn limit. + (This is *firmly* over the churn limit -- thus the +2 instead of just +1) + Usage: `@with_custom_state(balances_fn=scaled_churn_balances_exceed_inbound_churn_limit, ...)` + """ + num_validators = spec.config.CHURN_LIMIT_QUOTIENT * (spec.config.MAX_PER_EPOCH_ACTIVATION_CHURN_LIMIT) + return [spec.MAX_EFFECTIVE_BALANCE] * num_validators + + +def scaled_churn_balances_exceed_inbound_churn_limit(spec: Spec): + """ + Helper method to create enough validators to scale the churn limit. + (This is *firmly* over the churn limit -- thus the +2 instead of just +1) + Usage: `@with_custom_state(balances_fn=scaled_churn_balances_exceed_inbound_churn_limit, ...)` + """ + num_validators = spec.config.CHURN_LIMIT_QUOTIENT * (spec.config.MAX_PER_EPOCH_ACTIVATION_CHURN_LIMIT + 2) return [spec.MAX_EFFECTIVE_BALANCE] * num_validators @@ -548,6 +568,7 @@ def wrapper(*args, spec: Spec, **kw): with_deneb_and_later = with_all_phases_from(DENEB) with_eip6110_and_later = with_all_phases_from(EIP6110) with_eip7002_and_later = with_all_phases_from(EIP7002) +with_eip7668_and_later = with_all_phases_from(EIP7668) class quoted_str(str): diff --git a/tests/core/pyspec/eth2spec/test/eip7668/__init__.py b/tests/core/pyspec/eth2spec/test/eip7668/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/core/pyspec/eth2spec/test/eip7668/epoch_processing/__init__.py b/tests/core/pyspec/eth2spec/test/eip7668/epoch_processing/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/core/pyspec/eth2spec/test/eip7668/epoch_processing/test_process_registry_updates.py b/tests/core/pyspec/eth2spec/test/eip7668/epoch_processing/test_process_registry_updates.py new file mode 100644 index 0000000000..fb0fa2ef01 --- /dev/null +++ b/tests/core/pyspec/eth2spec/test/eip7668/epoch_processing/test_process_registry_updates.py @@ -0,0 +1,86 @@ +from eth2spec.test.helpers.keys import pubkeys +from eth2spec.test.helpers.constants import MINIMAL +from eth2spec.test.context import ( + with_eip7668_and_later, + spec_test, + spec_state_test, + single_phase, + with_custom_state, + with_presets, + scaled_churn_balances_exceed_inbound_churn_limit, + scaled_churn_balances_equal_inbound_churn_limit, +) +from eth2spec.test.helpers.epoch_processing import run_epoch_processing_with + + +def run_process_registry_updates(spec, state): + yield from run_epoch_processing_with(spec, state, 'process_registry_updates') + + +def run_test_inbound_churn_limit(spec, state): + mock_activations = 1 + + for i in range(mock_activations): + index = len(state.validators) + i + validator = spec.Validator( + pubkey=pubkeys[index], + withdrawal_credentials=spec.ETH1_ADDRESS_WITHDRAWAL_PREFIX + b'\x00' * 11 + b'\x56' * 20, + activation_eligibility_epoch=0, + activation_epoch=spec.FAR_FUTURE_EPOCH, + exit_epoch=spec.FAR_FUTURE_EPOCH, + withdrawable_epoch=spec.FAR_FUTURE_EPOCH, + effective_balance=spec.MAX_EFFECTIVE_BALANCE, + ) + state.validators.append(validator) + state.balances.append(spec.MAX_EFFECTIVE_BALANCE) + state.previous_epoch_participation.append(spec.ParticipationFlags(0b0000_0000)) + state.current_epoch_participation.append(spec.ParticipationFlags(0b0000_0000)) + state.inactivity_scores.append(0) + state.validators[index].activation_epoch = spec.FAR_FUTURE_EPOCH + + churn_limit_0 = spec.get_validator_activation_churn_limit(state) + + yield from run_process_registry_updates(spec, state) + + # Half should churn in first run of registry update + for i in range(mock_activations): + if i < churn_limit_0: + assert state.validators[i].activation_epoch < spec.FAR_FUTURE_EPOCH + else: + assert state.validators[i].activation_epoch == spec.FAR_FUTURE_EPOCH + + +@with_eip7668_and_later +@with_presets([MINIMAL], + reason="mainnet config leads to larger validator set than limit of public/private keys pre-generated") +@spec_test +@with_custom_state(balances_fn=scaled_churn_balances_exceed_inbound_churn_limit, + threshold_fn=lambda spec: spec.config.EJECTION_BALANCE) +@single_phase +def test_inbound_churn_limit__greater_than_inbound_limit(spec, state): + assert spec.get_validator_activation_churn_limit(state) == spec.config.MAX_PER_EPOCH_ACTIVATION_CHURN_LIMIT + assert spec.get_validator_churn_limit(state) > spec.config.MAX_PER_EPOCH_ACTIVATION_CHURN_LIMIT + yield from run_test_inbound_churn_limit(spec, state) + + +@with_eip7668_and_later +@with_presets([MINIMAL], + reason="mainnet config leads to larger validator set than limit of public/private keys pre-generated") +@spec_test +@with_custom_state(balances_fn=scaled_churn_balances_equal_inbound_churn_limit, + threshold_fn=lambda spec: spec.config.EJECTION_BALANCE) +@single_phase +def test_inbound_churn_limit__equal_to_inbound_limit(spec, state): + assert spec.get_validator_activation_churn_limit(state) == spec.config.MAX_PER_EPOCH_ACTIVATION_CHURN_LIMIT + assert spec.get_validator_churn_limit(state) == spec.config.MAX_PER_EPOCH_ACTIVATION_CHURN_LIMIT + yield from run_test_inbound_churn_limit(spec, state) + + +@with_eip7668_and_later +@with_presets([MINIMAL], + reason="mainnet config leads to larger validator set than limit of public/private keys pre-generated") +@spec_state_test +def test_inbound_churn_limit__less_than_inbound_limit(spec, state): + assert spec.get_validator_activation_churn_limit(state) < spec.config.MAX_PER_EPOCH_ACTIVATION_CHURN_LIMIT + assert spec.get_validator_churn_limit(state) < spec.config.MAX_PER_EPOCH_ACTIVATION_CHURN_LIMIT + yield from run_test_inbound_churn_limit(spec, state) diff --git a/tests/core/pyspec/eth2spec/test/helpers/forks.py b/tests/core/pyspec/eth2spec/test/helpers/forks.py index 2e247dfc3a..91434c0caf 100644 --- a/tests/core/pyspec/eth2spec/test/helpers/forks.py +++ b/tests/core/pyspec/eth2spec/test/helpers/forks.py @@ -46,3 +46,7 @@ def is_post_eip6110(spec): def is_post_eip7002(spec): return is_post_fork(spec.fork, EIP7002) + + +def is_post_eip7668(spec): + return is_post_fork(spec.fork, EIP7668) diff --git a/tests/core/pyspec/eth2spec/test/phase0/epoch_processing/test_process_registry_updates.py b/tests/core/pyspec/eth2spec/test/phase0/epoch_processing/test_process_registry_updates.py index b4c5f81a0d..b7a7be76ab 100644 --- a/tests/core/pyspec/eth2spec/test/phase0/epoch_processing/test_process_registry_updates.py +++ b/tests/core/pyspec/eth2spec/test/phase0/epoch_processing/test_process_registry_updates.py @@ -5,7 +5,7 @@ spec_test, spec_state_test, with_all_phases, single_phase, with_custom_state, with_presets, - scaled_churn_balances, + scaled_churn_balances_min_churn_limit, ) from eth2spec.test.helpers.epoch_processing import run_epoch_processing_with @@ -164,7 +164,8 @@ def test_activation_queue_efficiency_min(spec, state): @with_presets([MINIMAL], reason="mainnet config leads to larger validator set than limit of public/private keys pre-generated") @spec_test -@with_custom_state(balances_fn=scaled_churn_balances, threshold_fn=lambda spec: spec.config.EJECTION_BALANCE) +@with_custom_state(balances_fn=scaled_churn_balances_min_churn_limit, + threshold_fn=lambda spec: spec.config.EJECTION_BALANCE) @single_phase def test_activation_queue_efficiency_scaled(spec, state): assert spec.get_validator_churn_limit(state) > spec.config.MIN_PER_EPOCH_CHURN_LIMIT @@ -227,7 +228,8 @@ def test_ejection_past_churn_limit_min(spec, state): @with_presets([MINIMAL], reason="mainnet config leads to larger validator set than limit of public/private keys pre-generated") @spec_test -@with_custom_state(balances_fn=scaled_churn_balances, threshold_fn=lambda spec: spec.config.EJECTION_BALANCE) +@with_custom_state(balances_fn=scaled_churn_balances_min_churn_limit, + threshold_fn=lambda spec: spec.config.EJECTION_BALANCE) @single_phase def test_ejection_past_churn_limit_scaled(spec, state): assert spec.get_validator_churn_limit(state) > spec.config.MIN_PER_EPOCH_CHURN_LIMIT @@ -324,7 +326,8 @@ def test_activation_queue_activation_and_ejection__exceed_churn_limit(spec, stat @with_presets([MINIMAL], reason="mainnet config leads to larger validator set than limit of public/private keys pre-generated") @spec_test -@with_custom_state(balances_fn=scaled_churn_balances, threshold_fn=lambda spec: spec.config.EJECTION_BALANCE) +@with_custom_state(balances_fn=scaled_churn_balances_min_churn_limit, + threshold_fn=lambda spec: spec.config.EJECTION_BALANCE) @single_phase def test_activation_queue_activation_and_ejection__scaled_churn_limit(spec, state): churn_limit = spec.get_validator_churn_limit(state) @@ -336,7 +339,8 @@ def test_activation_queue_activation_and_ejection__scaled_churn_limit(spec, stat @with_presets([MINIMAL], reason="mainnet config leads to larger validator set than limit of public/private keys pre-generated") @spec_test -@with_custom_state(balances_fn=scaled_churn_balances, threshold_fn=lambda spec: spec.config.EJECTION_BALANCE) +@with_custom_state(balances_fn=scaled_churn_balances_min_churn_limit, + threshold_fn=lambda spec: spec.config.EJECTION_BALANCE) @single_phase def test_activation_queue_activation_and_ejection__exceed_scaled_churn_limit(spec, state): churn_limit = spec.get_validator_churn_limit(state) From 8878a316c443d240735d84fd3eb13bb8ca1f762c Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Wed, 13 Sep 2023 19:05:01 +0800 Subject: [PATCH 06/14] Fix test_process_voluntary_exit.py --- .../phase0/block_processing/test_process_voluntary_exit.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/core/pyspec/eth2spec/test/phase0/block_processing/test_process_voluntary_exit.py b/tests/core/pyspec/eth2spec/test/phase0/block_processing/test_process_voluntary_exit.py index 4a7286d523..97208dfcdd 100644 --- a/tests/core/pyspec/eth2spec/test/phase0/block_processing/test_process_voluntary_exit.py +++ b/tests/core/pyspec/eth2spec/test/phase0/block_processing/test_process_voluntary_exit.py @@ -3,7 +3,8 @@ spec_state_test, always_bls, with_all_phases, with_presets, spec_test, single_phase, - with_custom_state, scaled_churn_balances, + with_custom_state, + scaled_churn_balances_min_churn_limit, ) from eth2spec.test.helpers.keys import pubkey_to_privkey from eth2spec.test.helpers.voluntary_exits import ( @@ -102,7 +103,8 @@ def test_success_exit_queue__min_churn(spec, state): @with_presets([MINIMAL], reason="mainnet config leads to larger validator set than limit of public/private keys pre-generated") @spec_test -@with_custom_state(balances_fn=scaled_churn_balances, threshold_fn=lambda spec: spec.config.EJECTION_BALANCE) +@with_custom_state(balances_fn=scaled_churn_balances_min_churn_limit, + threshold_fn=lambda spec: spec.config.EJECTION_BALANCE) @single_phase def test_success_exit_queue__scaled_churn(spec, state): churn_limit = spec.get_validator_churn_limit(state) From 28286e7e5fc5a006cc9f2ca9051887d8551cf7c9 Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Thu, 14 Sep 2023 19:05:31 +0800 Subject: [PATCH 07/14] Fix tests --- .../test_process_registry_updates.py | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/tests/core/pyspec/eth2spec/test/eip7668/epoch_processing/test_process_registry_updates.py b/tests/core/pyspec/eth2spec/test/eip7668/epoch_processing/test_process_registry_updates.py index fb0fa2ef01..d68a659ef0 100644 --- a/tests/core/pyspec/eth2spec/test/eip7668/epoch_processing/test_process_registry_updates.py +++ b/tests/core/pyspec/eth2spec/test/eip7668/epoch_processing/test_process_registry_updates.py @@ -18,10 +18,12 @@ def run_process_registry_updates(spec, state): def run_test_inbound_churn_limit(spec, state): - mock_activations = 1 + mock_activations = spec.get_validator_activation_churn_limit(state) * 2 + + validator_count_0 = len(state.validators) for i in range(mock_activations): - index = len(state.validators) + i + index = validator_count_0 + i validator = spec.Validator( pubkey=pubkeys[index], withdrawal_credentials=spec.ETH1_ADDRESS_WITHDRAWAL_PREFIX + b'\x00' * 11 + b'\x56' * 20, @@ -44,10 +46,12 @@ def run_test_inbound_churn_limit(spec, state): # Half should churn in first run of registry update for i in range(mock_activations): - if i < churn_limit_0: - assert state.validators[i].activation_epoch < spec.FAR_FUTURE_EPOCH + index = validator_count_0 + i + if index < validator_count_0 + churn_limit_0: + # The eligible validators within the activation churn limit should have been activated + assert state.validators[index].activation_epoch < spec.FAR_FUTURE_EPOCH else: - assert state.validators[i].activation_epoch == spec.FAR_FUTURE_EPOCH + assert state.validators[index].activation_epoch == spec.FAR_FUTURE_EPOCH @with_eip7668_and_later From 19bf51dd93cf8f8a05457f72afa966068ef9aef7 Mon Sep 17 00:00:00 2001 From: dapplion <35266934+dapplion@users.noreply.github.com> Date: Thu, 14 Sep 2023 13:44:32 +0200 Subject: [PATCH 08/14] Rename eip7668 to eip7514 --- configs/mainnet.yaml | 8 +++--- configs/minimal.yaml | 8 +++--- pysetup/constants.py | 2 +- pysetup/md_doc_paths.py | 4 +-- pysetup/spec_builders/__init__.py | 4 +-- pysetup/spec_builders/{eip7668.py => eip7514} | 6 ++-- .../{eip7668 => eip7514}/beacon_chain.md | 6 ++-- specs/_features/{eip7668 => eip7514}/fork.md | 28 +++++++++---------- tests/core/pyspec/eth2spec/test/context.py | 10 +++---- .../test/{eip7668 => eip7514}/__init__.py | 0 .../epoch_processing/__init__.py | 0 .../test_process_registry_updates.py | 8 +++--- .../pyspec/eth2spec/test/helpers/constants.py | 4 +-- .../pyspec/eth2spec/test/helpers/forks.py | 10 +++---- .../pyspec/eth2spec/test/helpers/genesis.py | 6 ++-- 15 files changed, 52 insertions(+), 52 deletions(-) rename pysetup/spec_builders/{eip7668.py => eip7514} (67%) rename specs/_features/{eip7668 => eip7514}/beacon_chain.md (97%) rename specs/_features/{eip7668 => eip7514}/fork.md (86%) rename tests/core/pyspec/eth2spec/test/{eip7668 => eip7514}/__init__.py (100%) rename tests/core/pyspec/eth2spec/test/{eip7668 => eip7514}/epoch_processing/__init__.py (100%) rename tests/core/pyspec/eth2spec/test/{eip7668 => eip7514}/epoch_processing/test_process_registry_updates.py (97%) diff --git a/configs/mainnet.yaml b/configs/mainnet.yaml index 1b38591aae..75a34bd8aa 100644 --- a/configs/mainnet.yaml +++ b/configs/mainnet.yaml @@ -56,9 +56,9 @@ EIP6110_FORK_EPOCH: 18446744073709551615 # EIP7002 EIP7002_FORK_VERSION: 0x05000000 # temporary stub EIP7002_FORK_EPOCH: 18446744073709551615 -# EIP7668 -EIP7668_FORK_VERSION: 0x05000000 # temporary stub -EIP7668_FORK_EPOCH: 18446744073709551615 +# EIP7514 +EIP7514_FORK_VERSION: 0x05000000 # temporary stub +EIP7514_FORK_EPOCH: 18446744073709551615 # WHISK WHISK_FORK_VERSION: 0x06000000 # temporary stub WHISK_FORK_EPOCH: 18446744073709551615 @@ -150,5 +150,5 @@ WHISK_EPOCHS_PER_SHUFFLING_PHASE: 256 # `Epoch(2)` WHISK_PROPOSER_SELECTION_GAP: 2 -# EIP7668 +# EIP7514 MAX_PER_EPOCH_ACTIVATION_CHURN_LIMIT: 12 diff --git a/configs/minimal.yaml b/configs/minimal.yaml index edfb0f7e84..368e71c17c 100644 --- a/configs/minimal.yaml +++ b/configs/minimal.yaml @@ -55,9 +55,9 @@ EIP6110_FORK_EPOCH: 18446744073709551615 # EIP7002 EIP7002_FORK_VERSION: 0x05000001 EIP7002_FORK_EPOCH: 18446744073709551615 -# EIP7668 -EIP7668_FORK_VERSION: 0x05000001 # temporary stub -EIP7668_FORK_EPOCH: 18446744073709551615 +# EIP7514 +EIP7514_FORK_VERSION: 0x05000001 # temporary stub +EIP7514_FORK_EPOCH: 18446744073709551615 # WHISK WHISK_FORK_VERSION: 0x06000001 WHISK_FORK_EPOCH: 18446744073709551615 @@ -149,6 +149,6 @@ BLOB_SIDECAR_SUBNET_COUNT: 6 WHISK_EPOCHS_PER_SHUFFLING_PHASE: 4 WHISK_PROPOSER_SELECTION_GAP: 1 -# EIP7668 +# EIP7514 # [customized] MAX_PER_EPOCH_ACTIVATION_CHURN_LIMIT: 4 diff --git a/pysetup/constants.py b/pysetup/constants.py index f6f8ed8e43..765429e589 100644 --- a/pysetup/constants.py +++ b/pysetup/constants.py @@ -6,7 +6,7 @@ DENEB = 'deneb' EIP6110 = 'eip6110' EIP7002 = 'eip7002' -EIP7668 = 'eip7668' +EIP7514 = 'eip7514' WHISK = 'whisk' diff --git a/pysetup/md_doc_paths.py b/pysetup/md_doc_paths.py index 8031b09361..51dbfae253 100644 --- a/pysetup/md_doc_paths.py +++ b/pysetup/md_doc_paths.py @@ -9,7 +9,7 @@ EIP6110, WHISK, EIP7002, - EIP7668, + EIP7514, ) @@ -22,7 +22,7 @@ EIP6110: DENEB, WHISK: CAPELLA, EIP7002: CAPELLA, - EIP7668: CAPELLA, + EIP7514: CAPELLA, } ALL_FORKS = list(PREVIOUS_FORK_OF.keys()) diff --git a/pysetup/spec_builders/__init__.py b/pysetup/spec_builders/__init__.py index 6f0f1d2032..aa26b431fe 100644 --- a/pysetup/spec_builders/__init__.py +++ b/pysetup/spec_builders/__init__.py @@ -5,7 +5,7 @@ from .deneb import DenebSpecBuilder from .eip6110 import EIP6110SpecBuilder from .eip7002 import EIP7002SpecBuilder -from .eip7668 import EIP7668SpecBuilder +from .eip7514 import EIP7514SpecBuilder from .whisk import WhiskSpecBuilder @@ -13,6 +13,6 @@ builder.fork: builder for builder in ( Phase0SpecBuilder, AltairSpecBuilder, BellatrixSpecBuilder, CapellaSpecBuilder, DenebSpecBuilder, - EIP6110SpecBuilder, EIP7002SpecBuilder, EIP7668SpecBuilder, WhiskSpecBuilder, + EIP6110SpecBuilder, EIP7002SpecBuilder, EIP7514SpecBuilder, WhiskSpecBuilder, ) } diff --git a/pysetup/spec_builders/eip7668.py b/pysetup/spec_builders/eip7514 similarity index 67% rename from pysetup/spec_builders/eip7668.py rename to pysetup/spec_builders/eip7514 index 55332dd9ee..280cd11996 100644 --- a/pysetup/spec_builders/eip7668.py +++ b/pysetup/spec_builders/eip7514 @@ -1,9 +1,9 @@ from .base import BaseSpecBuilder -from ..constants import EIP7668 +from ..constants import EIP7514 -class EIP7668SpecBuilder(BaseSpecBuilder): - fork: str = EIP7668 +class EIP7514SpecBuilder(BaseSpecBuilder): + fork: str = EIP7514 @classmethod def imports(cls, preset_name: str): diff --git a/specs/_features/eip7668/beacon_chain.md b/specs/_features/eip7514/beacon_chain.md similarity index 97% rename from specs/_features/eip7668/beacon_chain.md rename to specs/_features/eip7514/beacon_chain.md index a8952b93af..321596debb 100644 --- a/specs/_features/eip7668/beacon_chain.md +++ b/specs/_features/eip7514/beacon_chain.md @@ -1,4 +1,4 @@ -EIP-7668 -- The Beacon Chain +EIP-7514 -- The Beacon Chain ## Table of contents @@ -53,7 +53,7 @@ def get_validator_activation_churn_limit(state: BeaconState) -> uint64: #### Registry updates -Note: The function `process_registry_updates` is modified to utilize `get_validator_inbound_churn_limit()` the rate limit the activation queue for EIP-7668. +Note: The function `process_registry_updates` is modified to utilize `get_validator_inbound_churn_limit()` the rate limit the activation queue for EIP-7514. ```python def process_registry_updates(state: BeaconState) -> None: @@ -75,7 +75,7 @@ def process_registry_updates(state: BeaconState) -> None: # Order by the sequence of activation_eligibility_epoch setting and then index ], key=lambda index: (state.validators[index].activation_eligibility_epoch, index)) # Dequeued validators for activation up to churn limit - # [Modified in EIP7668] + # [Modified in EIP7514] for index in activation_queue[:get_validator_activation_churn_limit(state)]: validator = state.validators[index] validator.activation_epoch = compute_activation_exit_epoch(get_current_epoch(state)) diff --git a/specs/_features/eip7668/fork.md b/specs/_features/eip7514/fork.md similarity index 86% rename from specs/_features/eip7668/fork.md rename to specs/_features/eip7514/fork.md index 93d2a7d521..05924874b2 100644 --- a/specs/_features/eip7668/fork.md +++ b/specs/_features/eip7514/fork.md @@ -1,4 +1,4 @@ -# EIP-7668 -- Fork Logic +# EIP-7514 -- Fork Logic **Notice**: This document is a work-in-progress for researchers and implementers. @@ -12,7 +12,7 @@ - [Helper functions](#helper-functions) - [Misc](#misc) - [Modified `compute_fork_version`](#modified-compute_fork_version) -- [Fork to EIP-7668](#fork-to-eip-7668) +- [Fork to EIP-7514](#fork-to-eip-7514) - [Fork trigger](#fork-trigger) - [Upgrading the state](#upgrading-the-state) @@ -20,7 +20,7 @@ ## Introduction -This document describes the process of EIP-7668 upgrade. +This document describes the process of EIP-7514 upgrade. ## Configuration @@ -28,8 +28,8 @@ Warning: this configuration is not definitive. | Name | Value | | - | - | -| `EIP7668_FORK_VERSION` | `Version('0x05000000')` | -| `EIP7668_FORK_EPOCH` | `Epoch(18446744073709551615)` **TBD** | +| `EIP7514_FORK_VERSION` | `Version('0x05000000')` | +| `EIP7514_FORK_EPOCH` | `Epoch(18446744073709551615)` **TBD** | ## Helper functions @@ -42,8 +42,8 @@ def compute_fork_version(epoch: Epoch) -> Version: """ Return the fork version at the given ``epoch``. """ - if epoch >= EIP7668_FORK_EPOCH: - return EIP7668_FORK_VERSION + if epoch >= EIP7514_FORK_EPOCH: + return EIP7514_FORK_VERSION if epoch >= CAPELLA_FORK_EPOCH: return CAPELLA_FORK_VERSION if epoch >= BELLATRIX_FORK_EPOCH: @@ -53,22 +53,22 @@ def compute_fork_version(epoch: Epoch) -> Version: return GENESIS_FORK_VERSION ``` -## Fork to EIP-7668 +## Fork to EIP-7514 ### Fork trigger TBD. This fork is defined for testing purposes, the EIP may be combined with other consensus-layer upgrade. -For now, we assume the condition will be triggered at epoch `EIP7668_FORK_EPOCH`. +For now, we assume the condition will be triggered at epoch `EIP7514_FORK_EPOCH`. -Note that for the pure EIP-7668 networks, we don't apply `upgrade_to_eip7668` since it starts with EIP-7668 version logic. +Note that for the pure EIP-7514 networks, we don't apply `upgrade_to_eip7514` since it starts with EIP-7514 version logic. ### Upgrading the state -If `state.slot % SLOTS_PER_EPOCH == 0` and `compute_epoch_at_slot(state.slot) == EIP7668_FORK_EPOCH`, -an irregular state change is made to upgrade to EIP-7668. +If `state.slot % SLOTS_PER_EPOCH == 0` and `compute_epoch_at_slot(state.slot) == EIP7514_FORK_EPOCH`, +an irregular state change is made to upgrade to EIP-7514. ```python -def upgrade_to_eip7668(pre: capella.BeaconState) -> BeaconState: +def upgrade_to_eip7514(pre: capella.BeaconState) -> BeaconState: epoch = capella.get_current_epoch(pre) latest_execution_payload_header = ExecutionPayloadHeader( parent_hash=pre.latest_execution_payload_header.parent_hash, @@ -94,7 +94,7 @@ def upgrade_to_eip7668(pre: capella.BeaconState) -> BeaconState: slot=pre.slot, fork=Fork( previous_version=pre.fork.current_version, - current_version=EIP7668_FORK_VERSION, # [Modified in EIP-7668] + current_version=EIP7514_FORK_VERSION, # [Modified in EIP-7514] epoch=epoch, ), # History diff --git a/tests/core/pyspec/eth2spec/test/context.py b/tests/core/pyspec/eth2spec/test/context.py index f1a1a70349..d646f08b95 100644 --- a/tests/core/pyspec/eth2spec/test/context.py +++ b/tests/core/pyspec/eth2spec/test/context.py @@ -10,13 +10,13 @@ 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.eip7002 import mainnet as spec_eip7002_mainnet, minimal as spec_eip7002_minimal -from eth2spec.eip7668 import mainnet as spec_eip7668_mainnet, minimal as spec_eip7668_minimal +from eth2spec.eip7514 import mainnet as spec_eip7514_mainnet, minimal as spec_eip7514_minimal from eth2spec.utils import bls from .exceptions import SkippedTest from .helpers.constants import ( PHASE0, ALTAIR, BELLATRIX, CAPELLA, DENEB, - EIP6110, EIP7002, EIP7668, + EIP6110, EIP7002, EIP7514, MINIMAL, MAINNET, ALL_PHASES, ALL_FORK_UPGRADES, @@ -86,7 +86,7 @@ class ForkMeta: DENEB: spec_deneb_minimal, EIP6110: spec_eip6110_minimal, EIP7002: spec_eip7002_minimal, - EIP7668: spec_eip7668_minimal, + EIP7514: spec_eip7514_minimal, }, MAINNET: { PHASE0: spec_phase0_mainnet, @@ -96,7 +96,7 @@ class ForkMeta: DENEB: spec_deneb_mainnet, EIP6110: spec_eip6110_mainnet, EIP7002: spec_eip7002_mainnet, - EIP7668: spec_eip7668_mainnet, + EIP7514: spec_eip7514_mainnet, }, } @@ -568,7 +568,7 @@ def wrapper(*args, spec: Spec, **kw): with_deneb_and_later = with_all_phases_from(DENEB) with_eip6110_and_later = with_all_phases_from(EIP6110) with_eip7002_and_later = with_all_phases_from(EIP7002) -with_eip7668_and_later = with_all_phases_from(EIP7668) +with_eip7514_and_later = with_all_phases_from(EIP7514) class quoted_str(str): diff --git a/tests/core/pyspec/eth2spec/test/eip7668/__init__.py b/tests/core/pyspec/eth2spec/test/eip7514/__init__.py similarity index 100% rename from tests/core/pyspec/eth2spec/test/eip7668/__init__.py rename to tests/core/pyspec/eth2spec/test/eip7514/__init__.py diff --git a/tests/core/pyspec/eth2spec/test/eip7668/epoch_processing/__init__.py b/tests/core/pyspec/eth2spec/test/eip7514/epoch_processing/__init__.py similarity index 100% rename from tests/core/pyspec/eth2spec/test/eip7668/epoch_processing/__init__.py rename to tests/core/pyspec/eth2spec/test/eip7514/epoch_processing/__init__.py diff --git a/tests/core/pyspec/eth2spec/test/eip7668/epoch_processing/test_process_registry_updates.py b/tests/core/pyspec/eth2spec/test/eip7514/epoch_processing/test_process_registry_updates.py similarity index 97% rename from tests/core/pyspec/eth2spec/test/eip7668/epoch_processing/test_process_registry_updates.py rename to tests/core/pyspec/eth2spec/test/eip7514/epoch_processing/test_process_registry_updates.py index d68a659ef0..aa8e2c41b8 100644 --- a/tests/core/pyspec/eth2spec/test/eip7668/epoch_processing/test_process_registry_updates.py +++ b/tests/core/pyspec/eth2spec/test/eip7514/epoch_processing/test_process_registry_updates.py @@ -1,7 +1,7 @@ from eth2spec.test.helpers.keys import pubkeys from eth2spec.test.helpers.constants import MINIMAL from eth2spec.test.context import ( - with_eip7668_and_later, + with_eip7514_and_later, spec_test, spec_state_test, single_phase, @@ -54,7 +54,7 @@ def run_test_inbound_churn_limit(spec, state): assert state.validators[index].activation_epoch == spec.FAR_FUTURE_EPOCH -@with_eip7668_and_later +@with_eip7514_and_later @with_presets([MINIMAL], reason="mainnet config leads to larger validator set than limit of public/private keys pre-generated") @spec_test @@ -67,7 +67,7 @@ def test_inbound_churn_limit__greater_than_inbound_limit(spec, state): yield from run_test_inbound_churn_limit(spec, state) -@with_eip7668_and_later +@with_eip7514_and_later @with_presets([MINIMAL], reason="mainnet config leads to larger validator set than limit of public/private keys pre-generated") @spec_test @@ -80,7 +80,7 @@ def test_inbound_churn_limit__equal_to_inbound_limit(spec, state): yield from run_test_inbound_churn_limit(spec, state) -@with_eip7668_and_later +@with_eip7514_and_later @with_presets([MINIMAL], reason="mainnet config leads to larger validator set than limit of public/private keys pre-generated") @spec_state_test diff --git a/tests/core/pyspec/eth2spec/test/helpers/constants.py b/tests/core/pyspec/eth2spec/test/helpers/constants.py index a90edb2ec7..dff1ede20d 100644 --- a/tests/core/pyspec/eth2spec/test/helpers/constants.py +++ b/tests/core/pyspec/eth2spec/test/helpers/constants.py @@ -18,7 +18,7 @@ DAS = SpecForkName('das') EIP6110 = SpecForkName('eip6110') EIP7002 = SpecForkName('eip7002') -EIP7668 = SpecForkName('eip7668') +EIP7514 = SpecForkName('eip7514') # # SpecFork settings @@ -35,7 +35,7 @@ # Experimental patches EIP6110, EIP7002, - EIP7668, + EIP7514, ) # The forks that have light client specs LIGHT_CLIENT_TESTING_FORKS = (*[item for item in MAINNET_FORKS if item != PHASE0], DENEB) diff --git a/tests/core/pyspec/eth2spec/test/helpers/forks.py b/tests/core/pyspec/eth2spec/test/helpers/forks.py index 91434c0caf..4322e220aa 100644 --- a/tests/core/pyspec/eth2spec/test/helpers/forks.py +++ b/tests/core/pyspec/eth2spec/test/helpers/forks.py @@ -1,12 +1,12 @@ from .constants import ( PHASE0, ALTAIR, BELLATRIX, CAPELLA, DENEB, - EIP6110, EIP7002, EIP7668, + EIP6110, EIP7002, EIP7514, ) def is_post_fork(a, b): - if a == EIP7668: - return b in [PHASE0, ALTAIR, BELLATRIX, CAPELLA, EIP7668] + if a == EIP7514: + return b in [PHASE0, ALTAIR, BELLATRIX, CAPELLA, EIP7514] if a == EIP7002: return b in [PHASE0, ALTAIR, BELLATRIX, CAPELLA, EIP7002] if a == EIP6110: @@ -48,5 +48,5 @@ def is_post_eip7002(spec): return is_post_fork(spec.fork, EIP7002) -def is_post_eip7668(spec): - return is_post_fork(spec.fork, EIP7668) +def is_post_eip7514(spec): + return is_post_fork(spec.fork, EIP7514) diff --git a/tests/core/pyspec/eth2spec/test/helpers/genesis.py b/tests/core/pyspec/eth2spec/test/helpers/genesis.py index 4f2f0721f2..8e01643bb2 100644 --- a/tests/core/pyspec/eth2spec/test/helpers/genesis.py +++ b/tests/core/pyspec/eth2spec/test/helpers/genesis.py @@ -1,5 +1,5 @@ from eth2spec.test.helpers.constants import ( - ALTAIR, BELLATRIX, CAPELLA, DENEB, EIP6110, EIP7002, EIP7668, + ALTAIR, BELLATRIX, CAPELLA, DENEB, EIP6110, EIP7002, EIP7514, ) from eth2spec.test.helpers.execution_payload import ( compute_el_header_block_hash, @@ -93,9 +93,9 @@ def create_genesis_state(spec, validator_balances, activation_threshold): elif spec.fork == EIP7002: previous_version = spec.config.CAPELLA_FORK_VERSION current_version = spec.config.EIP7002_FORK_VERSION - elif spec.fork == EIP7668: + elif spec.fork == EIP7514: previous_version = spec.config.CAPELLA_FORK_VERSION - current_version = spec.config.EIP7668_FORK_VERSION + current_version = spec.config.EIP7514_FORK_VERSION state = spec.BeaconState( genesis_time=0, From a56c4d026ff4fd39cbd77b7b8545eae719613018 Mon Sep 17 00:00:00 2001 From: dapplion <35266934+dapplion@users.noreply.github.com> Date: Thu, 14 Sep 2023 13:47:11 +0200 Subject: [PATCH 09/14] add extension --- pysetup/spec_builders/{eip7514 => eip7514.py} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename pysetup/spec_builders/{eip7514 => eip7514.py} (100%) diff --git a/pysetup/spec_builders/eip7514 b/pysetup/spec_builders/eip7514.py similarity index 100% rename from pysetup/spec_builders/eip7514 rename to pysetup/spec_builders/eip7514.py From f165d39472b1c7f8a39247ffedd453608ac37982 Mon Sep 17 00:00:00 2001 From: Lion - dapplion <35266934+dapplion@users.noreply.github.com> Date: Thu, 14 Sep 2023 16:31:12 +0200 Subject: [PATCH 10/14] Update mainnet.yaml --- configs/mainnet.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configs/mainnet.yaml b/configs/mainnet.yaml index 75a34bd8aa..0bd46649e3 100644 --- a/configs/mainnet.yaml +++ b/configs/mainnet.yaml @@ -151,4 +151,4 @@ WHISK_EPOCHS_PER_SHUFFLING_PHASE: 256 WHISK_PROPOSER_SELECTION_GAP: 2 # EIP7514 -MAX_PER_EPOCH_ACTIVATION_CHURN_LIMIT: 12 +MAX_PER_EPOCH_ACTIVATION_CHURN_LIMIT: 8 From 0efd7785940ec5bbb015aec5e97d2c64d1f51d95 Mon Sep 17 00:00:00 2001 From: Lion - dapplion <35266934+dapplion@users.noreply.github.com> Date: Thu, 14 Sep 2023 16:31:42 +0200 Subject: [PATCH 11/14] Update beacon_chain.md --- specs/_features/eip7514/beacon_chain.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/specs/_features/eip7514/beacon_chain.md b/specs/_features/eip7514/beacon_chain.md index 321596debb..993beee5db 100644 --- a/specs/_features/eip7514/beacon_chain.md +++ b/specs/_features/eip7514/beacon_chain.md @@ -31,7 +31,7 @@ This is the beacon chain specification to limit the max inbound churn value, mot | Name | Value | | - | - | -| `MAX_PER_EPOCH_ACTIVATION_CHURN_LIMIT` | `uint64(12)` (= 12) | +| `MAX_PER_EPOCH_ACTIVATION_CHURN_LIMIT` | `uint64(8)` (= 8) | ## Helper functions From e5e50e3e407c062702be0bc395acf8e1a8030b6e Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Fri, 15 Sep 2023 10:25:47 +0800 Subject: [PATCH 12/14] Add EIP-7514 into Deneb --- .gitignore | 1 - configs/mainnet.yaml | 9 +- configs/minimal.yaml | 9 +- pysetup/constants.py | 1 - pysetup/md_doc_paths.py | 2 - pysetup/spec_builders/__init__.py | 3 +- pysetup/spec_builders/eip7514.py | 12 -- specs/_features/eip7514/beacon_chain.md | 83 ----------- specs/_features/eip7514/fork.md | 139 ------------------ specs/deneb/beacon-chain.md | 53 +++++++ tests/core/pyspec/eth2spec/test/context.py | 14 +- .../epoch_processing}/__init__.py | 0 .../test_process_registry_updates.py | 30 ++-- .../test/eip7514/epoch_processing/__init__.py | 0 .../pyspec/eth2spec/test/helpers/constants.py | 2 - .../pyspec/eth2spec/test/helpers/forks.py | 8 +- .../pyspec/eth2spec/test/helpers/genesis.py | 5 +- tests/generators/epoch_processing/main.py | 5 +- 18 files changed, 84 insertions(+), 292 deletions(-) delete mode 100644 pysetup/spec_builders/eip7514.py delete mode 100644 specs/_features/eip7514/beacon_chain.md delete mode 100644 specs/_features/eip7514/fork.md rename tests/core/pyspec/eth2spec/test/{eip7514 => deneb/epoch_processing}/__init__.py (100%) rename tests/core/pyspec/eth2spec/test/{eip7514 => deneb}/epoch_processing/test_process_registry_updates.py (80%) delete mode 100644 tests/core/pyspec/eth2spec/test/eip7514/epoch_processing/__init__.py diff --git a/.gitignore b/.gitignore index 7eacf101cf..cdfddfb0c3 100644 --- a/.gitignore +++ b/.gitignore @@ -23,7 +23,6 @@ tests/core/pyspec/eth2spec/capella/ tests/core/pyspec/eth2spec/deneb/ tests/core/pyspec/eth2spec/eip6110/ tests/core/pyspec/eth2spec/eip7002/ -tests/core/pyspec/eth2spec/eip7668/ tests/core/pyspec/eth2spec/whisk/ # coverage reports diff --git a/configs/mainnet.yaml b/configs/mainnet.yaml index 0bd46649e3..1b1a0ffa6d 100644 --- a/configs/mainnet.yaml +++ b/configs/mainnet.yaml @@ -56,9 +56,6 @@ EIP6110_FORK_EPOCH: 18446744073709551615 # EIP7002 EIP7002_FORK_VERSION: 0x05000000 # temporary stub EIP7002_FORK_EPOCH: 18446744073709551615 -# EIP7514 -EIP7514_FORK_VERSION: 0x05000000 # temporary stub -EIP7514_FORK_EPOCH: 18446744073709551615 # WHISK WHISK_FORK_VERSION: 0x06000000 # temporary stub WHISK_FORK_EPOCH: 18446744073709551615 @@ -90,7 +87,8 @@ EJECTION_BALANCE: 16000000000 MIN_PER_EPOCH_CHURN_LIMIT: 4 # 2**16 (= 65,536) CHURN_LIMIT_QUOTIENT: 65536 - +# [New in Deneb:EIP7514] 2**3 (=8) +MAX_PER_EPOCH_ACTIVATION_CHURN_LIMIT: 8 # Fork choice # --------------------------------------------------------------- @@ -149,6 +147,3 @@ BLOB_SIDECAR_SUBNET_COUNT: 6 WHISK_EPOCHS_PER_SHUFFLING_PHASE: 256 # `Epoch(2)` WHISK_PROPOSER_SELECTION_GAP: 2 - -# EIP7514 -MAX_PER_EPOCH_ACTIVATION_CHURN_LIMIT: 8 diff --git a/configs/minimal.yaml b/configs/minimal.yaml index 368e71c17c..da3c015766 100644 --- a/configs/minimal.yaml +++ b/configs/minimal.yaml @@ -55,9 +55,6 @@ EIP6110_FORK_EPOCH: 18446744073709551615 # EIP7002 EIP7002_FORK_VERSION: 0x05000001 EIP7002_FORK_EPOCH: 18446744073709551615 -# EIP7514 -EIP7514_FORK_VERSION: 0x05000001 # temporary stub -EIP7514_FORK_EPOCH: 18446744073709551615 # WHISK WHISK_FORK_VERSION: 0x06000001 WHISK_FORK_EPOCH: 18446744073709551615 @@ -89,6 +86,8 @@ EJECTION_BALANCE: 16000000000 MIN_PER_EPOCH_CHURN_LIMIT: 2 # [customized] scale queue churn at much lower validator counts for testing CHURN_LIMIT_QUOTIENT: 32 +# [New in Deneb:EIP7514] [customized] +MAX_PER_EPOCH_ACTIVATION_CHURN_LIMIT: 4 # Fork choice @@ -148,7 +147,3 @@ BLOB_SIDECAR_SUBNET_COUNT: 6 # Whisk WHISK_EPOCHS_PER_SHUFFLING_PHASE: 4 WHISK_PROPOSER_SELECTION_GAP: 1 - -# EIP7514 -# [customized] -MAX_PER_EPOCH_ACTIVATION_CHURN_LIMIT: 4 diff --git a/pysetup/constants.py b/pysetup/constants.py index 765429e589..8d53455634 100644 --- a/pysetup/constants.py +++ b/pysetup/constants.py @@ -6,7 +6,6 @@ DENEB = 'deneb' EIP6110 = 'eip6110' EIP7002 = 'eip7002' -EIP7514 = 'eip7514' WHISK = 'whisk' diff --git a/pysetup/md_doc_paths.py b/pysetup/md_doc_paths.py index 51dbfae253..781ae41db3 100644 --- a/pysetup/md_doc_paths.py +++ b/pysetup/md_doc_paths.py @@ -9,7 +9,6 @@ EIP6110, WHISK, EIP7002, - EIP7514, ) @@ -22,7 +21,6 @@ EIP6110: DENEB, WHISK: CAPELLA, EIP7002: CAPELLA, - EIP7514: CAPELLA, } ALL_FORKS = list(PREVIOUS_FORK_OF.keys()) diff --git a/pysetup/spec_builders/__init__.py b/pysetup/spec_builders/__init__.py index aa26b431fe..794ae50d29 100644 --- a/pysetup/spec_builders/__init__.py +++ b/pysetup/spec_builders/__init__.py @@ -5,7 +5,6 @@ from .deneb import DenebSpecBuilder from .eip6110 import EIP6110SpecBuilder from .eip7002 import EIP7002SpecBuilder -from .eip7514 import EIP7514SpecBuilder from .whisk import WhiskSpecBuilder @@ -13,6 +12,6 @@ builder.fork: builder for builder in ( Phase0SpecBuilder, AltairSpecBuilder, BellatrixSpecBuilder, CapellaSpecBuilder, DenebSpecBuilder, - EIP6110SpecBuilder, EIP7002SpecBuilder, EIP7514SpecBuilder, WhiskSpecBuilder, + EIP6110SpecBuilder, EIP7002SpecBuilder, WhiskSpecBuilder, ) } diff --git a/pysetup/spec_builders/eip7514.py b/pysetup/spec_builders/eip7514.py deleted file mode 100644 index 280cd11996..0000000000 --- a/pysetup/spec_builders/eip7514.py +++ /dev/null @@ -1,12 +0,0 @@ -from .base import BaseSpecBuilder -from ..constants import EIP7514 - - -class EIP7514SpecBuilder(BaseSpecBuilder): - fork: str = EIP7514 - - @classmethod - def imports(cls, preset_name: str): - return super().imports(preset_name) + f''' -from eth2spec.capella import {preset_name} as capella -''' diff --git a/specs/_features/eip7514/beacon_chain.md b/specs/_features/eip7514/beacon_chain.md deleted file mode 100644 index 993beee5db..0000000000 --- a/specs/_features/eip7514/beacon_chain.md +++ /dev/null @@ -1,83 +0,0 @@ -EIP-7514 -- The Beacon Chain - -## Table of contents - - - - - -- [Introduction](#introduction) -- [Configuration](#configuration) - - [Validator cycle](#validator-cycle) -- [Helper functions](#helper-functions) - - [Beacon state accessors](#beacon-state-accessors) - - [New `get_validator_activation_churn_limit`](#new-get_validator_activation_churn_limit) -- [Beacon chain state transition function](#beacon-chain-state-transition-function) - - [Epoch processing](#epoch-processing) - - [Registry updates](#registry-updates) - - - - -## Introduction - -This is the beacon chain specification to limit the max inbound churn value, motivated to limit the validator active set growth rate. - -*Note:* This specification is built upon [Capella](../../capella/beacon_chain.md) and is under active development. - -## Configuration - -### Validator cycle - -| Name | Value | -| - | - | -| `MAX_PER_EPOCH_ACTIVATION_CHURN_LIMIT` | `uint64(8)` (= 8) | - -## Helper functions - -### Beacon state accessors - -#### New `get_validator_activation_churn_limit` - -```python -def get_validator_activation_churn_limit(state: BeaconState) -> uint64: - """ - Return the validator activation churn limit for the current epoch. - """ - return min(MAX_PER_EPOCH_ACTIVATION_CHURN_LIMIT, get_validator_churn_limit(state)) -``` - -## Beacon chain state transition function - -### Epoch processing - -#### Registry updates - -Note: The function `process_registry_updates` is modified to utilize `get_validator_inbound_churn_limit()` the rate limit the activation queue for EIP-7514. - -```python -def process_registry_updates(state: BeaconState) -> None: - # Process activation eligibility and ejections - for index, validator in enumerate(state.validators): - if is_eligible_for_activation_queue(validator): - validator.activation_eligibility_epoch = get_current_epoch(state) + 1 - - if ( - is_active_validator(validator, get_current_epoch(state)) - and validator.effective_balance <= EJECTION_BALANCE - ): - initiate_validator_exit(state, ValidatorIndex(index)) - - # Queue validators eligible for activation and not yet dequeued for activation - activation_queue = sorted([ - index for index, validator in enumerate(state.validators) - if is_eligible_for_activation(state, validator) - # Order by the sequence of activation_eligibility_epoch setting and then index - ], key=lambda index: (state.validators[index].activation_eligibility_epoch, index)) - # Dequeued validators for activation up to churn limit - # [Modified in EIP7514] - for index in activation_queue[:get_validator_activation_churn_limit(state)]: - validator = state.validators[index] - validator.activation_epoch = compute_activation_exit_epoch(get_current_epoch(state)) -``` - diff --git a/specs/_features/eip7514/fork.md b/specs/_features/eip7514/fork.md deleted file mode 100644 index 05924874b2..0000000000 --- a/specs/_features/eip7514/fork.md +++ /dev/null @@ -1,139 +0,0 @@ -# EIP-7514 -- Fork Logic - -**Notice**: This document is a work-in-progress for researchers and implementers. - -## Table of contents - - - - -- [Introduction](#introduction) -- [Configuration](#configuration) -- [Helper functions](#helper-functions) - - [Misc](#misc) - - [Modified `compute_fork_version`](#modified-compute_fork_version) -- [Fork to EIP-7514](#fork-to-eip-7514) - - [Fork trigger](#fork-trigger) - - [Upgrading the state](#upgrading-the-state) - - - -## Introduction - -This document describes the process of EIP-7514 upgrade. - -## Configuration - -Warning: this configuration is not definitive. - -| Name | Value | -| - | - | -| `EIP7514_FORK_VERSION` | `Version('0x05000000')` | -| `EIP7514_FORK_EPOCH` | `Epoch(18446744073709551615)` **TBD** | - -## Helper functions - -### Misc - -#### Modified `compute_fork_version` - -```python -def compute_fork_version(epoch: Epoch) -> Version: - """ - Return the fork version at the given ``epoch``. - """ - if epoch >= EIP7514_FORK_EPOCH: - return EIP7514_FORK_VERSION - if epoch >= CAPELLA_FORK_EPOCH: - return CAPELLA_FORK_VERSION - if epoch >= BELLATRIX_FORK_EPOCH: - return BELLATRIX_FORK_VERSION - if epoch >= ALTAIR_FORK_EPOCH: - return ALTAIR_FORK_VERSION - return GENESIS_FORK_VERSION -``` - -## Fork to EIP-7514 - -### Fork trigger - -TBD. This fork is defined for testing purposes, the EIP may be combined with other consensus-layer upgrade. -For now, we assume the condition will be triggered at epoch `EIP7514_FORK_EPOCH`. - -Note that for the pure EIP-7514 networks, we don't apply `upgrade_to_eip7514` since it starts with EIP-7514 version logic. - -### Upgrading the state - -If `state.slot % SLOTS_PER_EPOCH == 0` and `compute_epoch_at_slot(state.slot) == EIP7514_FORK_EPOCH`, -an irregular state change is made to upgrade to EIP-7514. - -```python -def upgrade_to_eip7514(pre: capella.BeaconState) -> BeaconState: - epoch = capella.get_current_epoch(pre) - latest_execution_payload_header = ExecutionPayloadHeader( - parent_hash=pre.latest_execution_payload_header.parent_hash, - fee_recipient=pre.latest_execution_payload_header.fee_recipient, - state_root=pre.latest_execution_payload_header.state_root, - receipts_root=pre.latest_execution_payload_header.receipts_root, - logs_bloom=pre.latest_execution_payload_header.logs_bloom, - prev_randao=pre.latest_execution_payload_header.prev_randao, - block_number=pre.latest_execution_payload_header.block_number, - gas_limit=pre.latest_execution_payload_header.gas_limit, - gas_used=pre.latest_execution_payload_header.gas_used, - timestamp=pre.latest_execution_payload_header.timestamp, - extra_data=pre.latest_execution_payload_header.extra_data, - base_fee_per_gas=pre.latest_execution_payload_header.base_fee_per_gas, - block_hash=pre.latest_execution_payload_header.block_hash, - transactions_root=pre.latest_execution_payload_header.transactions_root, - withdrawals_root=pre.latest_execution_payload_header.withdrawals_root, - ) - post = BeaconState( - # Versioning - genesis_time=pre.genesis_time, - genesis_validators_root=pre.genesis_validators_root, - slot=pre.slot, - fork=Fork( - previous_version=pre.fork.current_version, - current_version=EIP7514_FORK_VERSION, # [Modified in EIP-7514] - epoch=epoch, - ), - # History - latest_block_header=pre.latest_block_header, - block_roots=pre.block_roots, - state_roots=pre.state_roots, - historical_roots=pre.historical_roots, - # Eth1 - eth1_data=pre.eth1_data, - eth1_data_votes=pre.eth1_data_votes, - eth1_deposit_index=pre.eth1_deposit_index, - # Registry - validators=pre.validators, - balances=pre.balances, - # Randomness - randao_mixes=pre.randao_mixes, - # Slashings - slashings=pre.slashings, - # Participation - previous_epoch_participation=pre.previous_epoch_participation, - current_epoch_participation=pre.current_epoch_participation, - # Finality - justification_bits=pre.justification_bits, - previous_justified_checkpoint=pre.previous_justified_checkpoint, - current_justified_checkpoint=pre.current_justified_checkpoint, - finalized_checkpoint=pre.finalized_checkpoint, - # Inactivity - inactivity_scores=pre.inactivity_scores, - # Sync - current_sync_committee=pre.current_sync_committee, - next_sync_committee=pre.next_sync_committee, - # Execution-layer - latest_execution_payload_header=latest_execution_payload_header, - # Withdrawals - next_withdrawal_index=pre.next_withdrawal_index, - next_withdrawal_validator_index=pre.next_withdrawal_validator_index, - # Deep history valid from Capella onwards - historical_summaries=pre.historical_summaries, - ) - - return post -``` diff --git a/specs/deneb/beacon-chain.md b/specs/deneb/beacon-chain.md index 2328b20e03..f1a8e18e0d 100644 --- a/specs/deneb/beacon-chain.md +++ b/specs/deneb/beacon-chain.md @@ -16,6 +16,7 @@ - [Preset](#preset) - [Execution](#execution) - [Configuration](#configuration) + - [Validator cycle](#validator-cycle) - [Containers](#containers) - [Extended containers](#extended-containers) - [`BeaconBlockBody`](#beaconblockbody) @@ -26,6 +27,7 @@ - [`kzg_commitment_to_versioned_hash`](#kzg_commitment_to_versioned_hash) - [Beacon state accessors](#beacon-state-accessors) - [Modified `get_attestation_participation_flag_indices`](#modified-get_attestation_participation_flag_indices) + - [New `get_validator_activation_churn_limit`](#new-get_validator_activation_churn_limit) - [Beacon chain state transition function](#beacon-chain-state-transition-function) - [Execution engine](#execution-engine) - [Request data](#request-data) @@ -40,6 +42,8 @@ - [Execution payload](#execution-payload) - [Modified `process_execution_payload`](#modified-process_execution_payload) - [Modified `process_voluntary_exit`](#modified-process_voluntary_exit) + - [Epoch processing](#epoch-processing) + - [Registry updates](#registry-updates) - [Testing](#testing) @@ -52,6 +56,7 @@ Deneb is a consensus-layer upgrade containing a number of features. Including: * [EIP-4844](https://eips.ethereum.org/EIPS/eip-4844): Shard Blob Transactions scale data-availability of Ethereum in a simple, forwards-compatible manner * [EIP-7044](https://github.com/ethereum/EIPs/pull/7044): Perpetually Valid Signed Voluntary Exits * [EIP-7045](https://eips.ethereum.org/EIPS/eip-7045): Increase Max Attestation Inclusion Slot +* [EIP-7514](https://eips.ethereum.org/EIPS/eip-7514): Add Max Epoch Churn Limit ## Custom types @@ -89,6 +94,12 @@ and are limited by `MAX_BLOB_GAS_PER_BLOCK // GAS_PER_BLOB`. However the CL limi ## Configuration +### Validator cycle + +| Name | Value | +| - | - | +| `MAX_PER_EPOCH_ACTIVATION_CHURN_LIMIT` | `uint64(2**3)` (= 8) | + ## Containers ### Extended containers @@ -211,6 +222,16 @@ def get_attestation_participation_flag_indices(state: BeaconState, return participation_flag_indices ``` +#### New `get_validator_activation_churn_limit` + +```python +def get_validator_activation_churn_limit(state: BeaconState) -> uint64: + """ + Return the validator activation churn limit for the current epoch. + """ + return min(MAX_PER_EPOCH_ACTIVATION_CHURN_LIMIT, get_validator_churn_limit(state)) +``` + ## Beacon chain state transition function ### Execution engine @@ -415,6 +436,38 @@ def process_voluntary_exit(state: BeaconState, signed_voluntary_exit: SignedVolu initiate_validator_exit(state, voluntary_exit.validator_index) ``` +### Epoch processing + +#### Registry updates + +*Note*: The function `process_registry_updates` is modified to utilize `get_validator_activation_churn_limit()` the rate limit the activation queue for EIP-7514. + +```python +def process_registry_updates(state: BeaconState) -> None: + # Process activation eligibility and ejections + for index, validator in enumerate(state.validators): + if is_eligible_for_activation_queue(validator): + validator.activation_eligibility_epoch = get_current_epoch(state) + 1 + + if ( + is_active_validator(validator, get_current_epoch(state)) + and validator.effective_balance <= EJECTION_BALANCE + ): + initiate_validator_exit(state, ValidatorIndex(index)) + + # Queue validators eligible for activation and not yet dequeued for activation + activation_queue = sorted([ + index for index, validator in enumerate(state.validators) + if is_eligible_for_activation(state, validator) + # Order by the sequence of activation_eligibility_epoch setting and then index + ], key=lambda index: (state.validators[index].activation_eligibility_epoch, index)) + # Dequeued validators for activation up to churn limit + # [Modified in Deneb:EIP7514] + for index in activation_queue[:get_validator_activation_churn_limit(state)]: + validator = state.validators[index] + validator.activation_epoch = compute_activation_exit_epoch(get_current_epoch(state)) +``` + ## Testing *Note*: The function `initialize_beacon_state_from_eth1` is modified for pure Deneb testing only. diff --git a/tests/core/pyspec/eth2spec/test/context.py b/tests/core/pyspec/eth2spec/test/context.py index d646f08b95..7289fdf0fa 100644 --- a/tests/core/pyspec/eth2spec/test/context.py +++ b/tests/core/pyspec/eth2spec/test/context.py @@ -10,13 +10,12 @@ 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.eip7002 import mainnet as spec_eip7002_mainnet, minimal as spec_eip7002_minimal -from eth2spec.eip7514 import mainnet as spec_eip7514_mainnet, minimal as spec_eip7514_minimal from eth2spec.utils import bls from .exceptions import SkippedTest from .helpers.constants import ( PHASE0, ALTAIR, BELLATRIX, CAPELLA, DENEB, - EIP6110, EIP7002, EIP7514, + EIP6110, EIP7002, MINIMAL, MAINNET, ALL_PHASES, ALL_FORK_UPGRADES, @@ -86,7 +85,6 @@ class ForkMeta: DENEB: spec_deneb_minimal, EIP6110: spec_eip6110_minimal, EIP7002: spec_eip7002_minimal, - EIP7514: spec_eip7514_minimal, }, MAINNET: { PHASE0: spec_phase0_mainnet, @@ -96,7 +94,6 @@ class ForkMeta: DENEB: spec_deneb_mainnet, EIP6110: spec_eip6110_mainnet, EIP7002: spec_eip7002_mainnet, - EIP7514: spec_eip7514_mainnet, }, } @@ -176,21 +173,21 @@ def scaled_churn_balances_min_churn_limit(spec: Spec): return [spec.MAX_EFFECTIVE_BALANCE] * num_validators -def scaled_churn_balances_equal_inbound_churn_limit(spec: Spec): +def scaled_churn_balances_equal_activation_churn_limit(spec: Spec): """ Helper method to create enough validators to scale the churn limit. (This is *firmly* over the churn limit -- thus the +2 instead of just +1) - Usage: `@with_custom_state(balances_fn=scaled_churn_balances_exceed_inbound_churn_limit, ...)` + Usage: `@with_custom_state(balances_fn=scaled_churn_balances_exceed_activation_churn_limit, ...)` """ num_validators = spec.config.CHURN_LIMIT_QUOTIENT * (spec.config.MAX_PER_EPOCH_ACTIVATION_CHURN_LIMIT) return [spec.MAX_EFFECTIVE_BALANCE] * num_validators -def scaled_churn_balances_exceed_inbound_churn_limit(spec: Spec): +def scaled_churn_balances_exceed_activation_churn_limit(spec: Spec): """ Helper method to create enough validators to scale the churn limit. (This is *firmly* over the churn limit -- thus the +2 instead of just +1) - Usage: `@with_custom_state(balances_fn=scaled_churn_balances_exceed_inbound_churn_limit, ...)` + Usage: `@with_custom_state(balances_fn=scaled_churn_balances_exceed_activation_churn_limit, ...)` """ num_validators = spec.config.CHURN_LIMIT_QUOTIENT * (spec.config.MAX_PER_EPOCH_ACTIVATION_CHURN_LIMIT + 2) return [spec.MAX_EFFECTIVE_BALANCE] * num_validators @@ -568,7 +565,6 @@ def wrapper(*args, spec: Spec, **kw): with_deneb_and_later = with_all_phases_from(DENEB) with_eip6110_and_later = with_all_phases_from(EIP6110) with_eip7002_and_later = with_all_phases_from(EIP7002) -with_eip7514_and_later = with_all_phases_from(EIP7514) class quoted_str(str): diff --git a/tests/core/pyspec/eth2spec/test/eip7514/__init__.py b/tests/core/pyspec/eth2spec/test/deneb/epoch_processing/__init__.py similarity index 100% rename from tests/core/pyspec/eth2spec/test/eip7514/__init__.py rename to tests/core/pyspec/eth2spec/test/deneb/epoch_processing/__init__.py diff --git a/tests/core/pyspec/eth2spec/test/eip7514/epoch_processing/test_process_registry_updates.py b/tests/core/pyspec/eth2spec/test/deneb/epoch_processing/test_process_registry_updates.py similarity index 80% rename from tests/core/pyspec/eth2spec/test/eip7514/epoch_processing/test_process_registry_updates.py rename to tests/core/pyspec/eth2spec/test/deneb/epoch_processing/test_process_registry_updates.py index aa8e2c41b8..d0b7638c6d 100644 --- a/tests/core/pyspec/eth2spec/test/eip7514/epoch_processing/test_process_registry_updates.py +++ b/tests/core/pyspec/eth2spec/test/deneb/epoch_processing/test_process_registry_updates.py @@ -1,14 +1,14 @@ from eth2spec.test.helpers.keys import pubkeys from eth2spec.test.helpers.constants import MINIMAL from eth2spec.test.context import ( - with_eip7514_and_later, + with_deneb_and_later, spec_test, spec_state_test, single_phase, with_custom_state, with_presets, - scaled_churn_balances_exceed_inbound_churn_limit, - scaled_churn_balances_equal_inbound_churn_limit, + scaled_churn_balances_exceed_activation_churn_limit, + scaled_churn_balances_equal_activation_churn_limit, ) from eth2spec.test.helpers.epoch_processing import run_epoch_processing_with @@ -17,7 +17,7 @@ def run_process_registry_updates(spec, state): yield from run_epoch_processing_with(spec, state, 'process_registry_updates') -def run_test_inbound_churn_limit(spec, state): +def run_test_activation_churn_limit(spec, state): mock_activations = spec.get_validator_activation_churn_limit(state) * 2 validator_count_0 = len(state.validators) @@ -54,37 +54,37 @@ def run_test_inbound_churn_limit(spec, state): assert state.validators[index].activation_epoch == spec.FAR_FUTURE_EPOCH -@with_eip7514_and_later +@with_deneb_and_later @with_presets([MINIMAL], reason="mainnet config leads to larger validator set than limit of public/private keys pre-generated") @spec_test -@with_custom_state(balances_fn=scaled_churn_balances_exceed_inbound_churn_limit, +@with_custom_state(balances_fn=scaled_churn_balances_exceed_activation_churn_limit, threshold_fn=lambda spec: spec.config.EJECTION_BALANCE) @single_phase -def test_inbound_churn_limit__greater_than_inbound_limit(spec, state): +def test_activation_churn_limit__greater_than_inbound_limit(spec, state): assert spec.get_validator_activation_churn_limit(state) == spec.config.MAX_PER_EPOCH_ACTIVATION_CHURN_LIMIT assert spec.get_validator_churn_limit(state) > spec.config.MAX_PER_EPOCH_ACTIVATION_CHURN_LIMIT - yield from run_test_inbound_churn_limit(spec, state) + yield from run_test_activation_churn_limit(spec, state) -@with_eip7514_and_later +@with_deneb_and_later @with_presets([MINIMAL], reason="mainnet config leads to larger validator set than limit of public/private keys pre-generated") @spec_test -@with_custom_state(balances_fn=scaled_churn_balances_equal_inbound_churn_limit, +@with_custom_state(balances_fn=scaled_churn_balances_equal_activation_churn_limit, threshold_fn=lambda spec: spec.config.EJECTION_BALANCE) @single_phase -def test_inbound_churn_limit__equal_to_inbound_limit(spec, state): +def test_activation_churn_limit__equal_to_inbound_limit(spec, state): assert spec.get_validator_activation_churn_limit(state) == spec.config.MAX_PER_EPOCH_ACTIVATION_CHURN_LIMIT assert spec.get_validator_churn_limit(state) == spec.config.MAX_PER_EPOCH_ACTIVATION_CHURN_LIMIT - yield from run_test_inbound_churn_limit(spec, state) + yield from run_test_activation_churn_limit(spec, state) -@with_eip7514_and_later +@with_deneb_and_later @with_presets([MINIMAL], reason="mainnet config leads to larger validator set than limit of public/private keys pre-generated") @spec_state_test -def test_inbound_churn_limit__less_than_inbound_limit(spec, state): +def test_activation_churn_limit__less_than_inbound_limit(spec, state): assert spec.get_validator_activation_churn_limit(state) < spec.config.MAX_PER_EPOCH_ACTIVATION_CHURN_LIMIT assert spec.get_validator_churn_limit(state) < spec.config.MAX_PER_EPOCH_ACTIVATION_CHURN_LIMIT - yield from run_test_inbound_churn_limit(spec, state) + yield from run_test_activation_churn_limit(spec, state) diff --git a/tests/core/pyspec/eth2spec/test/eip7514/epoch_processing/__init__.py b/tests/core/pyspec/eth2spec/test/eip7514/epoch_processing/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/tests/core/pyspec/eth2spec/test/helpers/constants.py b/tests/core/pyspec/eth2spec/test/helpers/constants.py index dff1ede20d..82e4f9d0a5 100644 --- a/tests/core/pyspec/eth2spec/test/helpers/constants.py +++ b/tests/core/pyspec/eth2spec/test/helpers/constants.py @@ -18,7 +18,6 @@ DAS = SpecForkName('das') EIP6110 = SpecForkName('eip6110') EIP7002 = SpecForkName('eip7002') -EIP7514 = SpecForkName('eip7514') # # SpecFork settings @@ -35,7 +34,6 @@ # Experimental patches EIP6110, EIP7002, - EIP7514, ) # The forks that have light client specs LIGHT_CLIENT_TESTING_FORKS = (*[item for item in MAINNET_FORKS if item != PHASE0], DENEB) diff --git a/tests/core/pyspec/eth2spec/test/helpers/forks.py b/tests/core/pyspec/eth2spec/test/helpers/forks.py index 4322e220aa..492af47fe3 100644 --- a/tests/core/pyspec/eth2spec/test/helpers/forks.py +++ b/tests/core/pyspec/eth2spec/test/helpers/forks.py @@ -1,12 +1,10 @@ from .constants import ( PHASE0, ALTAIR, BELLATRIX, CAPELLA, DENEB, - EIP6110, EIP7002, EIP7514, + EIP6110, EIP7002, ) def is_post_fork(a, b): - if a == EIP7514: - return b in [PHASE0, ALTAIR, BELLATRIX, CAPELLA, EIP7514] if a == EIP7002: return b in [PHASE0, ALTAIR, BELLATRIX, CAPELLA, EIP7002] if a == EIP6110: @@ -46,7 +44,3 @@ def is_post_eip6110(spec): def is_post_eip7002(spec): return is_post_fork(spec.fork, EIP7002) - - -def is_post_eip7514(spec): - return is_post_fork(spec.fork, EIP7514) diff --git a/tests/core/pyspec/eth2spec/test/helpers/genesis.py b/tests/core/pyspec/eth2spec/test/helpers/genesis.py index 8e01643bb2..e55bdef5ce 100644 --- a/tests/core/pyspec/eth2spec/test/helpers/genesis.py +++ b/tests/core/pyspec/eth2spec/test/helpers/genesis.py @@ -1,5 +1,5 @@ from eth2spec.test.helpers.constants import ( - ALTAIR, BELLATRIX, CAPELLA, DENEB, EIP6110, EIP7002, EIP7514, + ALTAIR, BELLATRIX, CAPELLA, DENEB, EIP6110, EIP7002, ) from eth2spec.test.helpers.execution_payload import ( compute_el_header_block_hash, @@ -93,9 +93,6 @@ def create_genesis_state(spec, validator_balances, activation_threshold): elif spec.fork == EIP7002: previous_version = spec.config.CAPELLA_FORK_VERSION current_version = spec.config.EIP7002_FORK_VERSION - elif spec.fork == EIP7514: - previous_version = spec.config.CAPELLA_FORK_VERSION - current_version = spec.config.EIP7514_FORK_VERSION state = spec.BeaconState( genesis_time=0, diff --git a/tests/generators/epoch_processing/main.py b/tests/generators/epoch_processing/main.py index 645c84cb6b..63c2a548fd 100644 --- a/tests/generators/epoch_processing/main.py +++ b/tests/generators/epoch_processing/main.py @@ -32,7 +32,10 @@ ]} capella_mods = combine_mods(_new_capella_mods, bellatrix_mods) - deneb_mods = capella_mods + _new_deneb_mods = {key: 'eth2spec.test.deneb.epoch_processing.test_process_' + key for key in [ + 'registry_updates', + ]} + deneb_mods = combine_mods(_new_deneb_mods, capella_mods) eip6110_mods = deneb_mods From 26d3fa3efd42ba7968edcfd9899908b8eda24ddc Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Fri, 15 Sep 2023 22:02:34 +0800 Subject: [PATCH 13/14] Apply suggestions from code review Co-authored-by: danny --- configs/mainnet.yaml | 2 +- configs/minimal.yaml | 2 +- specs/deneb/beacon-chain.md | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/configs/mainnet.yaml b/configs/mainnet.yaml index 1b1a0ffa6d..252f82dbe1 100644 --- a/configs/mainnet.yaml +++ b/configs/mainnet.yaml @@ -87,7 +87,7 @@ EJECTION_BALANCE: 16000000000 MIN_PER_EPOCH_CHURN_LIMIT: 4 # 2**16 (= 65,536) CHURN_LIMIT_QUOTIENT: 65536 -# [New in Deneb:EIP7514] 2**3 (=8) +# [New in Deneb:EIP7514] 2**3 (= 8) MAX_PER_EPOCH_ACTIVATION_CHURN_LIMIT: 8 # Fork choice diff --git a/configs/minimal.yaml b/configs/minimal.yaml index da3c015766..a3b1a8d5ad 100644 --- a/configs/minimal.yaml +++ b/configs/minimal.yaml @@ -82,7 +82,7 @@ INACTIVITY_SCORE_BIAS: 4 INACTIVITY_SCORE_RECOVERY_RATE: 16 # 2**4 * 10**9 (= 16,000,000,000) Gwei EJECTION_BALANCE: 16000000000 -# [customized] +# [customized] more easily demonstrate the difference between this value and the activation churn limit MIN_PER_EPOCH_CHURN_LIMIT: 2 # [customized] scale queue churn at much lower validator counts for testing CHURN_LIMIT_QUOTIENT: 32 diff --git a/specs/deneb/beacon-chain.md b/specs/deneb/beacon-chain.md index f1a8e18e0d..5902f4091a 100644 --- a/specs/deneb/beacon-chain.md +++ b/specs/deneb/beacon-chain.md @@ -440,7 +440,7 @@ def process_voluntary_exit(state: BeaconState, signed_voluntary_exit: SignedVolu #### Registry updates -*Note*: The function `process_registry_updates` is modified to utilize `get_validator_activation_churn_limit()` the rate limit the activation queue for EIP-7514. +*Note*: The function `process_registry_updates` is modified to utilize `get_validator_activation_churn_limit()` to rate limit the activation queue for EIP-7514. ```python def process_registry_updates(state: BeaconState) -> None: @@ -461,7 +461,7 @@ def process_registry_updates(state: BeaconState) -> None: if is_eligible_for_activation(state, validator) # Order by the sequence of activation_eligibility_epoch setting and then index ], key=lambda index: (state.validators[index].activation_eligibility_epoch, index)) - # Dequeued validators for activation up to churn limit + # Dequeued validators for activation up to activation churn limit # [Modified in Deneb:EIP7514] for index in activation_queue[:get_validator_activation_churn_limit(state)]: validator = state.validators[index] From e8041749a2252121f08c13d8b2ae5c52b57e6bb2 Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Fri, 15 Sep 2023 22:05:26 +0800 Subject: [PATCH 14/14] Apply PR feedback. Rename `inbound_limit` to `activation_limit` --- .../deneb/epoch_processing/test_process_registry_updates.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/core/pyspec/eth2spec/test/deneb/epoch_processing/test_process_registry_updates.py b/tests/core/pyspec/eth2spec/test/deneb/epoch_processing/test_process_registry_updates.py index d0b7638c6d..4cbcc1ed5c 100644 --- a/tests/core/pyspec/eth2spec/test/deneb/epoch_processing/test_process_registry_updates.py +++ b/tests/core/pyspec/eth2spec/test/deneb/epoch_processing/test_process_registry_updates.py @@ -61,7 +61,7 @@ def run_test_activation_churn_limit(spec, state): @with_custom_state(balances_fn=scaled_churn_balances_exceed_activation_churn_limit, threshold_fn=lambda spec: spec.config.EJECTION_BALANCE) @single_phase -def test_activation_churn_limit__greater_than_inbound_limit(spec, state): +def test_activation_churn_limit__greater_than_activation_limit(spec, state): assert spec.get_validator_activation_churn_limit(state) == spec.config.MAX_PER_EPOCH_ACTIVATION_CHURN_LIMIT assert spec.get_validator_churn_limit(state) > spec.config.MAX_PER_EPOCH_ACTIVATION_CHURN_LIMIT yield from run_test_activation_churn_limit(spec, state) @@ -74,7 +74,7 @@ def test_activation_churn_limit__greater_than_inbound_limit(spec, state): @with_custom_state(balances_fn=scaled_churn_balances_equal_activation_churn_limit, threshold_fn=lambda spec: spec.config.EJECTION_BALANCE) @single_phase -def test_activation_churn_limit__equal_to_inbound_limit(spec, state): +def test_activation_churn_limit__equal_to_activation_limit(spec, state): assert spec.get_validator_activation_churn_limit(state) == spec.config.MAX_PER_EPOCH_ACTIVATION_CHURN_LIMIT assert spec.get_validator_churn_limit(state) == spec.config.MAX_PER_EPOCH_ACTIVATION_CHURN_LIMIT yield from run_test_activation_churn_limit(spec, state) @@ -84,7 +84,7 @@ def test_activation_churn_limit__equal_to_inbound_limit(spec, state): @with_presets([MINIMAL], reason="mainnet config leads to larger validator set than limit of public/private keys pre-generated") @spec_state_test -def test_activation_churn_limit__less_than_inbound_limit(spec, state): +def test_activation_churn_limit__less_than_activation_limit(spec, state): assert spec.get_validator_activation_churn_limit(state) < spec.config.MAX_PER_EPOCH_ACTIVATION_CHURN_LIMIT assert spec.get_validator_churn_limit(state) < spec.config.MAX_PER_EPOCH_ACTIVATION_CHURN_LIMIT yield from run_test_activation_churn_limit(spec, state)