-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Add max epoch activation churn limit (EIP-7514) to Deneb #3499
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 12 commits
e6f7c99
fd37ffc
cc3ced5
298a630
417b95c
8878a31
28286e7
19bf51d
a56c4d0
f165d39
0efd778
e5e50e3
26d3fa3
e804174
264dfad
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -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) | ||
|
|
||
| <!-- END doctoc generated TOC please keep comment here to allow auto update --> | ||
|
|
@@ -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) | | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. just a nit: since this new param is only applied from There might be confusion in testnets with a
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hmm, but it would break the current code conventions for the new constants/presets/configurations. 🤔
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🤔 ... It actually should be
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I see your point, but we do have |
||
|
|
||
| ## 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. | ||
hwwhww marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| ```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 | ||
hwwhww marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| # [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. | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,90 @@ | ||
| from eth2spec.test.helpers.keys import pubkeys | ||
| from eth2spec.test.helpers.constants import MINIMAL | ||
| from eth2spec.test.context import ( | ||
| with_deneb_and_later, | ||
| spec_test, | ||
| spec_state_test, | ||
| single_phase, | ||
| with_custom_state, | ||
| with_presets, | ||
| 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 | ||
|
|
||
|
|
||
| def run_process_registry_updates(spec, state): | ||
| yield from run_epoch_processing_with(spec, state, 'process_registry_updates') | ||
|
|
||
|
|
||
| def run_test_activation_churn_limit(spec, state): | ||
| mock_activations = spec.get_validator_activation_churn_limit(state) * 2 | ||
|
|
||
| validator_count_0 = len(state.validators) | ||
|
|
||
| for i in range(mock_activations): | ||
| index = validator_count_0 + 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): | ||
| 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[index].activation_epoch == spec.FAR_FUTURE_EPOCH | ||
|
|
||
|
|
||
| @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_activation_churn_limit, | ||
| threshold_fn=lambda spec: spec.config.EJECTION_BALANCE) | ||
| @single_phase | ||
| def test_activation_churn_limit__greater_than_inbound_limit(spec, state): | ||
hwwhww marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| 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) | ||
|
|
||
|
|
||
| @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_activation_churn_limit, | ||
| threshold_fn=lambda spec: spec.config.EJECTION_BALANCE) | ||
| @single_phase | ||
| 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_activation_churn_limit(spec, state) | ||
|
|
||
|
|
||
| @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_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_activation_churn_limit(spec, state) | ||
Uh oh!
There was an error while loading. Please reload this page.