From 1c35eb1c3303fe1e0b101323106d766d8f848cd6 Mon Sep 17 00:00:00 2001 From: dapplion <35266934+dapplion@users.noreply.github.com> Date: Fri, 10 Mar 2023 14:37:18 +0800 Subject: [PATCH 01/44] Lock voluntary_exit domain on capella --- specs/phase0/beacon-chain.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/specs/phase0/beacon-chain.md b/specs/phase0/beacon-chain.md index 7e14fa951a..e5eb12006d 100644 --- a/specs/phase0/beacon-chain.md +++ b/specs/phase0/beacon-chain.md @@ -1903,7 +1903,7 @@ def process_voluntary_exit(state: BeaconState, signed_voluntary_exit: SignedVolu # Verify the validator has been active long enough assert get_current_epoch(state) >= validator.activation_epoch + SHARD_COMMITTEE_PERIOD # Verify signature - domain = get_domain(state, DOMAIN_VOLUNTARY_EXIT, voluntary_exit.epoch) + domain = get_domain(state, DOMAIN_VOLUNTARY_EXIT, min(voluntary_exit.epoch, CAPELLA_FORK_EPOCH)) signing_root = compute_signing_root(voluntary_exit, domain) assert bls.Verify(validator.pubkey, signing_root, signed_voluntary_exit.signature) # Initiate exit From 47f078fc1fdbcc6274d42ee891718ed73bc731d9 Mon Sep 17 00:00:00 2001 From: dapplion <35266934+dapplion@users.noreply.github.com> Date: Sat, 11 Mar 2023 20:28:49 +0800 Subject: [PATCH 02/44] Move change to deneb --- specs/deneb/beacon-chain.md | 44 +++++++++++++++++++++++++++++++++++- specs/phase0/beacon-chain.md | 2 +- 2 files changed, 44 insertions(+), 2 deletions(-) diff --git a/specs/deneb/beacon-chain.md b/specs/deneb/beacon-chain.md index a0ac783b7f..672d0a6332 100644 --- a/specs/deneb/beacon-chain.md +++ b/specs/deneb/beacon-chain.md @@ -203,7 +203,7 @@ def process_block(state: BeaconState, block: BeaconBlock) -> None: process_execution_payload(state, block.body.execution_payload, EXECUTION_ENGINE) # [Modified in Deneb] process_randao(state, block.body) process_eth1_data(state, block.body) - process_operations(state, block.body) + process_operations(state, block.body) # [Modified in Deneb] process_sync_aggregate(state, block.body.sync_aggregate) process_blob_kzg_commitments(state, block.body) # [New in Deneb] ``` @@ -245,6 +245,48 @@ def process_execution_payload(state: BeaconState, payload: ExecutionPayload, exe ) ``` +#### Modified `process_operations` + +```python +def process_operations(state: BeaconState, body: BeaconBlockBody) -> None: + # Verify that outstanding deposits are processed up to the maximum number of deposits + assert len(body.deposits) == min(MAX_DEPOSITS, state.eth1_data.deposit_count - state.eth1_deposit_index) + + def for_ops(operations: Sequence[Any], fn: Callable[[BeaconState, Any], None]) -> None: + for operation in operations: + fn(state, operation) + + for_ops(body.proposer_slashings, process_proposer_slashing) + for_ops(body.attester_slashings, process_attester_slashing) + for_ops(body.attestations, process_attestation) + for_ops(body.deposits, process_deposit) + for_ops(body.voluntary_exits, process_voluntary_exit) # [Modified in Deneb] + for_ops(body.bls_to_execution_changes, process_bls_to_execution_change) +``` + +##### Modified `process_voluntary_exit` + +```python +def process_voluntary_exit(state: BeaconState, signed_voluntary_exit: SignedVoluntaryExit) -> None: + voluntary_exit = signed_voluntary_exit.message + validator = state.validators[voluntary_exit.validator_index] + # Verify the validator is active + assert is_active_validator(validator, get_current_epoch(state)) + # Verify exit has not been initiated + assert validator.exit_epoch == FAR_FUTURE_EPOCH + # Exits must specify an epoch when they become valid; they are not valid before then + assert get_current_epoch(state) >= voluntary_exit.epoch + # Verify the validator has been active long enough + assert get_current_epoch(state) >= validator.activation_epoch + SHARD_COMMITTEE_PERIOD + # Verify signature + domain = get_domain(state, DOMAIN_VOLUNTARY_EXIT, min(voluntary_exit.epoch, CAPELLA_FORK_EPOCH)) # [Modified in Deneb] + signing_root = compute_signing_root(voluntary_exit, domain) + assert bls.Verify(validator.pubkey, signing_root, signed_voluntary_exit.signature) + # Initiate exit + initiate_validator_exit(state, voluntary_exit.validator_index) +``` + + #### Blob KZG commitments ```python diff --git a/specs/phase0/beacon-chain.md b/specs/phase0/beacon-chain.md index e5eb12006d..7e14fa951a 100644 --- a/specs/phase0/beacon-chain.md +++ b/specs/phase0/beacon-chain.md @@ -1903,7 +1903,7 @@ def process_voluntary_exit(state: BeaconState, signed_voluntary_exit: SignedVolu # Verify the validator has been active long enough assert get_current_epoch(state) >= validator.activation_epoch + SHARD_COMMITTEE_PERIOD # Verify signature - domain = get_domain(state, DOMAIN_VOLUNTARY_EXIT, min(voluntary_exit.epoch, CAPELLA_FORK_EPOCH)) + domain = get_domain(state, DOMAIN_VOLUNTARY_EXIT, voluntary_exit.epoch) signing_root = compute_signing_root(voluntary_exit, domain) assert bls.Verify(validator.pubkey, signing_root, signed_voluntary_exit.signature) # Initiate exit From df4ba47e633dff7707d7a531136cfa785a65f5b0 Mon Sep 17 00:00:00 2001 From: Lion - dapplion <35266934+dapplion@users.noreply.github.com> Date: Mon, 13 Mar 2023 08:51:02 +0800 Subject: [PATCH 03/44] Update beacon-chain.md --- specs/deneb/beacon-chain.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/specs/deneb/beacon-chain.md b/specs/deneb/beacon-chain.md index 672d0a6332..fd983f29ed 100644 --- a/specs/deneb/beacon-chain.md +++ b/specs/deneb/beacon-chain.md @@ -279,7 +279,7 @@ def process_voluntary_exit(state: BeaconState, signed_voluntary_exit: SignedVolu # Verify the validator has been active long enough assert get_current_epoch(state) >= validator.activation_epoch + SHARD_COMMITTEE_PERIOD # Verify signature - domain = get_domain(state, DOMAIN_VOLUNTARY_EXIT, min(voluntary_exit.epoch, CAPELLA_FORK_EPOCH)) # [Modified in Deneb] + domain = compute_domain(DOMAIN_VOLUNTARY_EXIT, CAPELLA_FORK_VERSION, state.genesis_validators_root) # [Modified in Deneb] signing_root = compute_signing_root(voluntary_exit, domain) assert bls.Verify(validator.pubkey, signing_root, signed_voluntary_exit.signature) # Initiate exit From 680b026d59a6fc0b4e73817464fb478e7eb1d9bc Mon Sep 17 00:00:00 2001 From: dapplion <35266934+dapplion@users.noreply.github.com> Date: Thu, 30 Mar 2023 09:23:10 +0900 Subject: [PATCH 04/44] Add add_validator_to_registry fn --- specs/altair/beacon-chain.md | 47 ++++++++++++------------------------ specs/phase0/beacon-chain.md | 17 ++++++++----- 2 files changed, 26 insertions(+), 38 deletions(-) diff --git a/specs/altair/beacon-chain.md b/specs/altair/beacon-chain.md index 8c3a8877e8..1de39d6fc7 100644 --- a/specs/altair/beacon-chain.md +++ b/specs/altair/beacon-chain.md @@ -45,7 +45,7 @@ - [Modified `slash_validator`](#modified-slash_validator) - [Block processing](#block-processing) - [Modified `process_attestation`](#modified-process_attestation) - - [Modified `apply_deposit`](#modified-apply_deposit) + - [Modified `add_validator_to_registry`](#modified-add_validator_to_registry) - [Sync aggregate processing](#sync-aggregate-processing) - [Epoch processing](#epoch-processing) - [Justification and finalization](#justification-and-finalization) @@ -508,40 +508,23 @@ def process_attestation(state: BeaconState, attestation: Attestation) -> None: increase_balance(state, get_beacon_proposer_index(state), proposer_reward) ``` -#### Modified `apply_deposit` +#### Modified `add_validator_to_registry` -*Note*: The function `apply_deposit` is modified to initialize `inactivity_scores`, `previous_epoch_participation`, and `current_epoch_participation`. +*Note*: The function `add_validator_to_registry` is modified to initialize `inactivity_scores`, `previous_epoch_participation`, and `current_epoch_participation`. ```python -def apply_deposit(state: BeaconState, - pubkey: BLSPubkey, - withdrawal_credentials: Bytes32, - amount: uint64, - signature: BLSSignature) -> None: - validator_pubkeys = [validator.pubkey for validator in state.validators] - if pubkey not in validator_pubkeys: - # Verify the deposit signature (proof of possession) which is not checked by the deposit contract - deposit_message = DepositMessage( - pubkey=pubkey, - withdrawal_credentials=withdrawal_credentials, - amount=amount, - ) - domain = compute_domain(DOMAIN_DEPOSIT) # Fork-agnostic domain since deposits are valid across forks - signing_root = compute_signing_root(deposit_message, domain) - # Initialize validator if the deposit signature is valid - if bls.Verify(pubkey, signing_root, signature): - index = get_index_for_new_validator(state) - validator = get_validator_from_deposit(pubkey, withdrawal_credentials, amount) - set_or_append_list(state.validators, index, validator) - set_or_append_list(state.balances, index, amount) - # [New in Altair] - set_or_append_list(state.previous_epoch_participation, index, ParticipationFlags(0b0000_0000)) - set_or_append_list(state.current_epoch_participation, index, ParticipationFlags(0b0000_0000)) - set_or_append_list(state.inactivity_scores, index, uint64(0)) - else: - # Increase balance by deposit amount - index = ValidatorIndex(validator_pubkeys.index(pubkey)) - increase_balance(state, index, amount) +def add_validator_to_registry(state: BeaconState, + pubkey: BLSPubkey, + withdrawal_credentials: Bytes32, + amount: uint64) -> None: + index = get_index_for_new_validator(state) + validator = get_validator_from_deposit(pubkey, withdrawal_credentials, amount) + set_or_append_list(state.validators, index, validator) + set_or_append_list(state.balances, index, amount) + # [New in Altair] + set_or_append_list(state.previous_epoch_participation, index, ParticipationFlags(0b0000_0000)) + set_or_append_list(state.current_epoch_participation, index, ParticipationFlags(0b0000_0000)) + set_or_append_list(state.inactivity_scores, index, uint64(0)) ``` #### Sync aggregate processing diff --git a/specs/phase0/beacon-chain.md b/specs/phase0/beacon-chain.md index b77e017ab7..214c0b77e2 100644 --- a/specs/phase0/beacon-chain.md +++ b/specs/phase0/beacon-chain.md @@ -1849,6 +1849,15 @@ def get_validator_from_deposit(pubkey: BLSPubkey, withdrawal_credentials: Bytes3 ) ``` +```python +def add_validator_to_registry(state: BeaconState, + pubkey: BLSPubkey, + withdrawal_credentials: Bytes32, + amount: uint64) -> None: + state.validators.append(get_validator_from_deposit(pubkey, withdrawal_credentials, amount)) + state.balances.append(amount) +``` + ```python def apply_deposit(state: BeaconState, pubkey: BLSPubkey, @@ -1865,12 +1874,8 @@ def apply_deposit(state: BeaconState, ) domain = compute_domain(DOMAIN_DEPOSIT) # Fork-agnostic domain since deposits are valid across forks signing_root = compute_signing_root(deposit_message, domain) - if not bls.Verify(pubkey, signing_root, signature): - return - - # Add validator and balance entries - state.validators.append(get_validator_from_deposit(pubkey, withdrawal_credentials, amount)) - state.balances.append(amount) + if bls.Verify(pubkey, signing_root, signature): + add_validator_to_registry(state, pubkey, withdrawal_credentials, amount) else: # Increase balance by deposit amount index = ValidatorIndex(validator_pubkeys.index(pubkey)) From bce45c56719a7f107d62bde1b9ddedb5256c913c Mon Sep 17 00:00:00 2001 From: djrtwo Date: Mon, 15 May 2023 11:21:11 -0600 Subject: [PATCH 05/44] working through att slot range fix --- .circleci/config.yml | 14 ++ .gitignore | 1 + Makefile | 2 +- configs/mainnet.yaml | 3 + configs/minimal.yaml | 5 + setup.py | 37 ++++-- specs/_features/attslotrange/beacon-chain.md | 74 +++++++++++ specs/_features/attslotrange/fork.md | 123 ++++++++++++++++++ tests/core/pyspec/eth2spec/test/context.py | 6 +- .../pyspec/eth2spec/test/helpers/constants.py | 3 +- .../eth2spec/test/helpers/fork_transition.py | 6 + .../pyspec/eth2spec/test/helpers/forks.py | 8 +- .../pyspec/eth2spec/test/helpers/genesis.py | 5 +- 13 files changed, 273 insertions(+), 14 deletions(-) create mode 100644 specs/_features/attslotrange/beacon-chain.md create mode 100644 specs/_features/attslotrange/fork.md diff --git a/.circleci/config.yml b/.circleci/config.yml index 5958a2fc69..b41699f712 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -168,6 +168,20 @@ jobs: command: make citest fork=eip6110 - store_test_results: path: tests/core/pyspec/test-reports + test-attslotrange: + docker: + - image: circleci/python:3.8 + working_directory: ~/specs-repo + steps: + - restore_cache: + key: v3-specs-repo-{{ .Branch }}-{{ .Revision }} + - restore_pyspec_cached_venv + - run: + name: Run py-tests + command: make citest fork=attslotrange + - store_test_results: + path: tests/core/pyspec/test-reports + table_of_contents: docker: - image: circleci/node:10.16.3 diff --git a/.gitignore b/.gitignore index 82026c27bd..b64dbde432 100644 --- a/.gitignore +++ b/.gitignore @@ -21,6 +21,7 @@ tests/core/pyspec/eth2spec/bellatrix/ tests/core/pyspec/eth2spec/capella/ tests/core/pyspec/eth2spec/deneb/ tests/core/pyspec/eth2spec/eip6110/ +tests/core/pyspec/eth2spec/attslotrange/ # coverage reports .htmlcov diff --git a/Makefile b/Makefile index ab5521663a..b0990bd51c 100644 --- a/Makefile +++ b/Makefile @@ -34,7 +34,7 @@ MARKDOWN_FILES = $(wildcard $(SPEC_DIR)/*/*.md) \ $(wildcard $(SPEC_DIR)/_features/*/*/*.md) \ $(wildcard $(SSZ_DIR)/*.md) -ALL_EXECUTABLE_SPECS = phase0 altair bellatrix capella deneb eip6110 +ALL_EXECUTABLE_SPECS = phase0 altair bellatrix capella deneb eip6110 attslotrange # The parameters for commands. Use `foreach` to avoid listing specs again. COVERAGE_SCOPE := $(foreach S,$(ALL_EXECUTABLE_SPECS), --cov=eth2spec.$S.$(TEST_PRESET_TYPE)) PYLINT_SCOPE := $(foreach S,$(ALL_EXECUTABLE_SPECS), ./eth2spec/$S) diff --git a/configs/mainnet.yaml b/configs/mainnet.yaml index 5ad394c082..1fee9abf66 100644 --- a/configs/mainnet.yaml +++ b/configs/mainnet.yaml @@ -53,6 +53,9 @@ DENEB_FORK_EPOCH: 18446744073709551615 # EIP6110 EIP6110_FORK_VERSION: 0x05000000 # temporary stub EIP6110_FORK_EPOCH: 18446744073709551615 +# AttSlotRange +ATTSLOTRANGE_FORK_VERSION: 0x05000000 # temporary stub +ATTSLOTRANGE_FORK_EPOCH: 18446744073709551615 # Time parameters diff --git a/configs/minimal.yaml b/configs/minimal.yaml index 5895cfc707..acc6854804 100644 --- a/configs/minimal.yaml +++ b/configs/minimal.yaml @@ -52,6 +52,11 @@ DENEB_FORK_EPOCH: 18446744073709551615 # EIP6110 EIP6110_FORK_VERSION: 0x05000001 EIP6110_FORK_EPOCH: 18446744073709551615 +# AttSlotRange +ATTSLOTRANGE_FORK_VERSION: 0x05000001 +ATTSLOTRANGE_FORK_EPOCH: 18446744073709551615 + + # Time parameters diff --git a/setup.py b/setup.py index b2316ed958..23c4ac19c1 100644 --- a/setup.py +++ b/setup.py @@ -48,6 +48,7 @@ def installPackage(package: str): CAPELLA = 'capella' DENEB = 'deneb' EIP6110 = 'eip6110' +ATTSLOTRANGE= 'attslotrange' # The helper functions that are used when defining constants @@ -680,11 +681,23 @@ def imports(cls, preset_name: str): from eth2spec.deneb import {preset_name} as deneb ''' +# +# AttSlotRangeSpecBuilder +# +class AttSlotRangeSpecBuilder(DenebSpecBuilder): + fork: str = ATTSLOTRANGE -spec_builders = { - builder.fork: builder - for builder in (Phase0SpecBuilder, AltairSpecBuilder, BellatrixSpecBuilder, CapellaSpecBuilder, DenebSpecBuilder, EIP6110SpecBuilder) -} + @classmethod + def imports(cls, preset_name: str): + return super().imports(preset_name) + f''' +from eth2spec.deneb import {preset_name} as deneb +''' + +all_builders = ( + Phase0SpecBuilder, AltairSpecBuilder, BellatrixSpecBuilder, CapellaSpecBuilder, DenebSpecBuilder, + EIP6110SpecBuilder, AttSlotRangeSpecBuilder, +) +spec_builders = {builder.fork: builder for builder in all_builders} def is_byte_vector(value: str) -> bool: @@ -982,14 +995,14 @@ def finalize_options(self): if len(self.md_doc_paths) == 0: print("no paths were specified, using default markdown file paths for pyspec" " build (spec fork: %s)" % self.spec_fork) - if self.spec_fork in (PHASE0, ALTAIR, BELLATRIX, CAPELLA, DENEB, EIP6110): + if self.spec_fork in (PHASE0, ALTAIR, BELLATRIX, CAPELLA, DENEB, EIP6110, ATTSLOTRANGE): self.md_doc_paths = """ specs/phase0/beacon-chain.md specs/phase0/fork-choice.md specs/phase0/validator.md specs/phase0/weak-subjectivity.md """ - if self.spec_fork in (ALTAIR, BELLATRIX, CAPELLA, DENEB, EIP6110): + if self.spec_fork in (ALTAIR, BELLATRIX, CAPELLA, DENEB, EIP6110, ATTSLOTRANGE): self.md_doc_paths += """ specs/altair/light-client/full-node.md specs/altair/light-client/light-client.md @@ -1001,7 +1014,7 @@ def finalize_options(self): specs/altair/validator.md specs/altair/p2p-interface.md """ - if self.spec_fork in (BELLATRIX, CAPELLA, DENEB, EIP6110): + if self.spec_fork in (BELLATRIX, CAPELLA, DENEB, EIP6110, ATTSLOTRANGE): self.md_doc_paths += """ specs/bellatrix/beacon-chain.md specs/bellatrix/fork.md @@ -1010,7 +1023,7 @@ def finalize_options(self): specs/bellatrix/p2p-interface.md sync/optimistic.md """ - if self.spec_fork in (CAPELLA, DENEB, EIP6110): + if self.spec_fork in (CAPELLA, DENEB, EIP6110, ATTSLOTRANGE): self.md_doc_paths += """ specs/capella/light-client/fork.md specs/capella/light-client/full-node.md @@ -1022,7 +1035,7 @@ def finalize_options(self): specs/capella/validator.md specs/capella/p2p-interface.md """ - if self.spec_fork in (DENEB, EIP6110): + if self.spec_fork in (DENEB, EIP6110, ATTSLOTRANGE): self.md_doc_paths += """ specs/deneb/light-client/fork.md specs/deneb/light-client/full-node.md @@ -1044,6 +1057,12 @@ def finalize_options(self): specs/_features/eip6110/beacon-chain.md specs/_features/eip6110/fork.md """ + if self.spec_fork == ATTSLOTRANGE: + self.md_doc_paths += """ + specs/_features/attslotrange/beacon-chain.md + specs/_features/attslotrange/fork.md + """ + if len(self.md_doc_paths) == 0: raise Exception('no markdown files specified, and spec fork "%s" is unknown', self.spec_fork) diff --git a/specs/_features/attslotrange/beacon-chain.md b/specs/_features/attslotrange/beacon-chain.md new file mode 100644 index 0000000000..cc0acc61e4 --- /dev/null +++ b/specs/_features/attslotrange/beacon-chain.md @@ -0,0 +1,74 @@ +# Deneb -- The Beacon Chain + +**Notice**: This document is a work-in-progress for researchers and implementers. + +## Table of contents + + + + + +- [Introduction](#introduction) +- [Preset](#preset) +- [Configuration](#configuration) +- [Containers](#containers) +- [Beacon chain state transition function](#beacon-chain-state-transition-function) + - [Block processing](#block-processing) + - [Modified `process_attestation`](#modified-process_attestation) + + + + +## Introduction + +This feature allows for inclusion of attestations created during epoch `N` to be included in slots from epoch `N` as well as all slots in epoch `N+1` rather than the current `SLOTS_PER_EPOCH` slot restricted range. This is an extension of the Deneb upgrade. + +## Preset + +## Configuration + +## Containers + +## Beacon chain state transition function + +### Block processing + +#### Modified `process_attestation` + +*Note*: The function `process_attestation` is modified to expand valid slots for inclusion tothose in the `target.epoch` epoch as well as those in the `target.epoch + 1` epoch. + +```python +def process_attestation(state: BeaconState, attestation: Attestation) -> None: + data = attestation.data + assert data.target.epoch in (get_previous_epoch(state), get_current_epoch(state)) + assert data.target.epoch == compute_epoch_at_slot(data.slot) + assert data.slot + MIN_ATTESTATION_INCLUSION_DELAY <= state.slot # [Modified in AttSlotRange] + assert data.index < get_committee_count_per_slot(state, data.target.epoch) + + committee = get_beacon_committee(state, data.slot, data.index) + assert len(attestation.aggregation_bits) == len(committee) + + # Participation flag indices + participation_flag_indices = get_attestation_participation_flag_indices(state, data, state.slot - data.slot) + + # Verify signature + assert is_valid_indexed_attestation(state, get_indexed_attestation(state, attestation)) + + # Update epoch participation flags + if data.target.epoch == get_current_epoch(state): + epoch_participation = state.current_epoch_participation + else: + epoch_participation = state.previous_epoch_participation + + proposer_reward_numerator = 0 + for index in get_attesting_indices(state, data, attestation.aggregation_bits): + for flag_index, weight in enumerate(PARTICIPATION_FLAG_WEIGHTS): + if flag_index in participation_flag_indices and not has_flag(epoch_participation[index], flag_index): + epoch_participation[index] = add_flag(epoch_participation[index], flag_index) + proposer_reward_numerator += get_base_reward(state, index) * weight + + # Reward proposer + proposer_reward_denominator = (WEIGHT_DENOMINATOR - PROPOSER_WEIGHT) * WEIGHT_DENOMINATOR // PROPOSER_WEIGHT + proposer_reward = Gwei(proposer_reward_numerator // proposer_reward_denominator) + increase_balance(state, get_beacon_proposer_index(state), proposer_reward) +``` diff --git a/specs/_features/attslotrange/fork.md b/specs/_features/attslotrange/fork.md new file mode 100644 index 0000000000..3d8454c2a3 --- /dev/null +++ b/specs/_features/attslotrange/fork.md @@ -0,0 +1,123 @@ +# Att-Slot-Range -- 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 AttSlotRange](#fork-to-attslotrange) + - [Fork trigger](#fork-trigger) + - [Upgrading the state](#upgrading-the-state) + + + +## Introduction + +This document describes the process of Att-Slot-Range upgrade. + +## Configuration + +Warning: this configuration is not definitive. + +| Name | Value | +| - | - | +| `ATTSLOTRANGE_FORK_VERSION` | `Version('0x05000000')` | +| `ATTSLOTRANGE_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 >= ATTSLOTRANGE_FORK_EPOCH: + return ATTSLOTRANGE_FORK_VERSION + if epoch >= DENEB_FORK_EPOCH: + return DENEB_FORK_VERSION + if epoch >= CAPELLA_FORK_EPOCH: + return CAPELLA_FORK_VERSION + if epoch >= BELLATRIX_FORK_EPOCH: + return BELLATRIX_FORK_VERSION + if epoch >= ALTAIR_FORK_EPOCH: + return ALTAIR_FORK_VERSION + return GENESIS_FORK_VERSION +``` + +## Fork to AttSlotRange + +### 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 `ATTSLOTRANGE_FORK_EPOCH`. + +Note that for the pure AttSlotRange networks, we don't apply `upgrade_to_attslotrange` since it starts with AttSlotRange version logic. + +### Upgrading the state + +If `state.slot % SLOTS_PER_EPOCH == 0` and `compute_epoch_at_slot(state.slot) == ATTSLOTRANGE_FORK_EPOCH, +an irregular state change is made to upgrade to AttSlotRange. + +```python +def upgrade_to_attslotrange(pre: deneb.BeaconState) -> BeaconState: + 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=ATTSLOTRANGE_FORK_VERSION, # [Modified in Att-Slot-Range] + epoch=deneb.get_current_epoch(pre), + ), + # 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=pre.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/tests/core/pyspec/eth2spec/test/context.py b/tests/core/pyspec/eth2spec/test/context.py index 901fd273a8..4ffae34af9 100644 --- a/tests/core/pyspec/eth2spec/test/context.py +++ b/tests/core/pyspec/eth2spec/test/context.py @@ -9,12 +9,13 @@ from eth2spec.capella import mainnet as spec_capella_mainnet, minimal as spec_capella_minimal from eth2spec.deneb import mainnet as spec_deneb_mainnet, minimal as spec_deneb_minimal from eth2spec.eip6110 import mainnet as spec_eip6110_mainnet, minimal as spec_eip6110_minimal +from eth2spec.attslotrange import mainnet as spec_attslotrange_mainnet, minimal as spec_attslotrange_minimal from eth2spec.utils import bls from .exceptions import SkippedTest from .helpers.constants import ( PHASE0, ALTAIR, BELLATRIX, CAPELLA, DENEB, - EIP6110, + EIP6110, ATTSLOTRANGE, MINIMAL, MAINNET, ALL_PHASES, ALL_FORK_UPGRADES, @@ -82,6 +83,7 @@ class ForkMeta: CAPELLA: spec_capella_minimal, DENEB: spec_deneb_minimal, EIP6110: spec_eip6110_minimal, + ATTSLOTRANGE: spec_attslotrange_minimal, }, MAINNET: { PHASE0: spec_phase0_mainnet, @@ -90,6 +92,7 @@ class ForkMeta: CAPELLA: spec_capella_mainnet, DENEB: spec_deneb_mainnet, EIP6110: spec_eip6110_mainnet, + ATTSLOTRANGE: spec_attslotrange_mainnet, }, } @@ -433,6 +436,7 @@ def decorator(fn): with_capella_and_later = with_all_phases_from(CAPELLA) with_deneb_and_later = with_all_phases_from(DENEB) with_eip6110_and_later = with_all_phases_from(EIP6110) +with_attslotrange_and_later = with_all_phases_from(ATTSLOTRANGE) def _get_preset_targets(kw): diff --git a/tests/core/pyspec/eth2spec/test/helpers/constants.py b/tests/core/pyspec/eth2spec/test/helpers/constants.py index 2140c96e45..a3339305ea 100644 --- a/tests/core/pyspec/eth2spec/test/helpers/constants.py +++ b/tests/core/pyspec/eth2spec/test/helpers/constants.py @@ -16,13 +16,14 @@ CUSTODY_GAME = SpecForkName('custody_game') DAS = SpecForkName('das') EIP6110 = SpecForkName('eip6110') +ATTSLOTRANGE = SpecForkName('attslotrange') # The forks that pytest can run with. ALL_PHASES = ( # Formal forks PHASE0, ALTAIR, BELLATRIX, CAPELLA, DENEB, # Experimental patches - EIP6110, + EIP6110, ATTSLOTRANGE, ) # The forks that output to the test vectors. TESTGEN_FORKS = (PHASE0, ALTAIR, BELLATRIX, CAPELLA, DENEB, EIP6110) diff --git a/tests/core/pyspec/eth2spec/test/helpers/fork_transition.py b/tests/core/pyspec/eth2spec/test/helpers/fork_transition.py index 68444c4726..76b3327283 100644 --- a/tests/core/pyspec/eth2spec/test/helpers/fork_transition.py +++ b/tests/core/pyspec/eth2spec/test/helpers/fork_transition.py @@ -16,6 +16,7 @@ CAPELLA, DENEB, EIP6110, + ATTSLOTRANGE, ) from eth2spec.test.helpers.deposits import ( prepare_state_and_deposit, @@ -161,6 +162,8 @@ def do_fork(state, spec, post_spec, fork_epoch, with_block=True, sync_aggregate= state = post_spec.upgrade_to_deneb(state) elif post_spec.fork == EIP6110: state = post_spec.upgrade_to_eip6110(state) + elif post_spec.fork == ATTSLOTRANGE: + state = post_spec.upgrade_to_attslotrange(state) assert state.fork.epoch == fork_epoch @@ -179,6 +182,9 @@ def do_fork(state, spec, post_spec, fork_epoch, with_block=True, sync_aggregate= elif post_spec.fork == EIP6110: assert state.fork.previous_version == post_spec.config.DENEB_FORK_VERSION assert state.fork.current_version == post_spec.config.EIP6110_FORK_VERSION + elif post_spec.fork == ATTSLOTRANGE: + assert state.fork.previous_version == post_spec.config.DENEB_FORK_VERSION + assert state.fork.current_version == post_spec.config.ATTSLOTRANGE_FORK_VERSION if with_block: return state, _state_transition_and_sign_block_at_slot( diff --git a/tests/core/pyspec/eth2spec/test/helpers/forks.py b/tests/core/pyspec/eth2spec/test/helpers/forks.py index 5e97522dbb..35c265ebb7 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, + EIP6110, ATTSLOTRANGE, ) def is_post_fork(a, b): + if a == ATTSLOTRANGE: + return b in [PHASE0, ALTAIR, BELLATRIX, CAPELLA, DENEB, ATTSLOTRANGE] if a == EIP6110: return b in [PHASE0, ALTAIR, BELLATRIX, CAPELLA, DENEB, EIP6110] if a == DENEB: @@ -38,3 +40,7 @@ def is_post_deneb(spec): def is_post_eip6110(spec): return is_post_fork(spec.fork, EIP6110) + + +def is_post_attslotrange(spec): + return is_post_fork(spec.fork, ATTSLOTRANGE) diff --git a/tests/core/pyspec/eth2spec/test/helpers/genesis.py b/tests/core/pyspec/eth2spec/test/helpers/genesis.py index fea259013b..e3649b8e9d 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, + ALTAIR, BELLATRIX, CAPELLA, DENEB, EIP6110, ATTSLOTRANGE, ) from eth2spec.test.helpers.execution_payload import ( compute_el_header_block_hash, @@ -86,6 +86,9 @@ def create_genesis_state(spec, validator_balances, activation_threshold): elif spec.fork == EIP6110: previous_version = spec.config.DENEB_FORK_VERSION current_version = spec.config.EIP6110_FORK_VERSION + elif spec.fork == ATTSLOTRANGE: + previous_version = spec.config.DENEB_FORK_VERSION + current_version = spec.config.ATTSLOTRANGE_FORK_VERSION state = spec.BeaconState( genesis_time=0, From 3e2d9a755acdf4caef1acc29540809a0bbf49a24 Mon Sep 17 00:00:00 2001 From: djrtwo Date: Mon, 15 May 2023 11:57:13 -0600 Subject: [PATCH 06/44] disable some attestation tests for attslotrange --- .gitignore | 1 + tests/core/pyspec/eth2spec/test/context.py | 2 ++ .../block_processing/test_process_attestation.py | 15 +++++++++------ 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/.gitignore b/.gitignore index b64dbde432..c8cd7a15a2 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,7 @@ venv .venvs .venv /.pytest_cache +*.swp build/ output/ diff --git a/tests/core/pyspec/eth2spec/test/context.py b/tests/core/pyspec/eth2spec/test/context.py index 4ffae34af9..37a6e6eab9 100644 --- a/tests/core/pyspec/eth2spec/test/context.py +++ b/tests/core/pyspec/eth2spec/test/context.py @@ -438,6 +438,8 @@ def decorator(fn): with_eip6110_and_later = with_all_phases_from(EIP6110) with_attslotrange_and_later = with_all_phases_from(ATTSLOTRANGE) +with_all_phases_except_attslotrange = with_all_phases_except(ATTSLOTRANGE) + def _get_preset_targets(kw): preset_name = DEFAULT_TEST_PRESET diff --git a/tests/core/pyspec/eth2spec/test/phase0/block_processing/test_process_attestation.py b/tests/core/pyspec/eth2spec/test/phase0/block_processing/test_process_attestation.py index 7595ce9cbe..938d874eda 100644 --- a/tests/core/pyspec/eth2spec/test/phase0/block_processing/test_process_attestation.py +++ b/tests/core/pyspec/eth2spec/test/phase0/block_processing/test_process_attestation.py @@ -2,6 +2,9 @@ spec_state_test, always_bls, never_bls, with_all_phases, + # Note, if attslotrange gets included, this will need to be + # 'with all phases up until attslotrange' + with_all_phases_except_attslotrange, spec_test, low_balances, with_custom_state, @@ -93,7 +96,7 @@ def test_invalid_before_inclusion_delay(spec, state): yield from run_attestation_processing(spec, state, attestation, valid=False) -@with_all_phases +@with_all_phases_except_attslotrange @spec_state_test def test_invalid_after_epoch_slots(spec, state): attestation = get_valid_attestation(spec, state, signed=True) @@ -391,7 +394,7 @@ def test_correct_attestation_included_at_one_epoch_delay(spec, state): yield from run_attestation_processing(spec, state, attestation) -@with_all_phases +@with_all_phases_except_attslotrange @spec_state_test def test_invalid_correct_attestation_included_after_epoch_delay(spec, state): attestation = get_valid_attestation(spec, state, signed=True) @@ -430,7 +433,7 @@ def test_incorrect_head_included_at_sqrt_epoch_delay(spec, state): yield from run_attestation_processing(spec, state, attestation) -@with_all_phases +@with_all_phases_except_attslotrange @spec_state_test def test_incorrect_head_included_at_epoch_delay(spec, state): attestation = get_valid_attestation(spec, state, signed=False) @@ -442,7 +445,7 @@ def test_incorrect_head_included_at_epoch_delay(spec, state): yield from run_attestation_processing(spec, state, attestation) -@with_all_phases +@with_all_phases_except_attslotrange @spec_state_test def test_invalid_incorrect_head_included_after_epoch_delay(spec, state): attestation = get_valid_attestation(spec, state, signed=False) @@ -499,7 +502,7 @@ def test_incorrect_head_and_target_included_at_epoch_delay(spec, state): yield from run_attestation_processing(spec, state, attestation) -@with_all_phases +@with_all_phases_except_attslotrange @spec_state_test def test_invalid_incorrect_head_and_target_included_after_epoch_delay(spec, state): attestation = get_valid_attestation(spec, state, signed=False) @@ -553,7 +556,7 @@ def test_incorrect_target_included_at_epoch_delay(spec, state): yield from run_attestation_processing(spec, state, attestation) -@with_all_phases +@with_all_phases_except_attslotrange @spec_state_test def test_invalid_incorrect_target_included_after_epoch_delay(spec, state): attestation = get_valid_attestation(spec, state, signed=False) From ad09a73b965e0d8f1bd2dd64f939f031aefc1832 Mon Sep 17 00:00:00 2001 From: djrtwo Date: Mon, 15 May 2023 12:03:30 -0600 Subject: [PATCH 07/44] add attslotrange to circleci workflows --- .circleci/config.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.circleci/config.yml b/.circleci/config.yml index b41699f712..c3d6540ad3 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -305,6 +305,9 @@ workflows: - test-eip6110: requires: - install_pyspec_test + - test-attslotrange: + requires: + - install_pyspec_test - table_of_contents - codespell - lint: From 5889668403ba6f5ec8ec39d2e090241dd85a23e5 Mon Sep 17 00:00:00 2001 From: djrtwo Date: Mon, 15 May 2023 12:13:20 -0600 Subject: [PATCH 08/44] lint --- .../test/phase0/block_processing/test_process_attestation.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/core/pyspec/eth2spec/test/phase0/block_processing/test_process_attestation.py b/tests/core/pyspec/eth2spec/test/phase0/block_processing/test_process_attestation.py index 938d874eda..3ace6323fc 100644 --- a/tests/core/pyspec/eth2spec/test/phase0/block_processing/test_process_attestation.py +++ b/tests/core/pyspec/eth2spec/test/phase0/block_processing/test_process_attestation.py @@ -2,7 +2,7 @@ spec_state_test, always_bls, never_bls, with_all_phases, - # Note, if attslotrange gets included, this will need to be + # Note, if attslotrange gets included, this will need to be # 'with all phases up until attslotrange' with_all_phases_except_attslotrange, spec_test, From 78403ccf8aa3b28b6e36aab6243c643aea3f0c81 Mon Sep 17 00:00:00 2001 From: djrtwo Date: Tue, 16 May 2023 09:48:23 -0600 Subject: [PATCH 09/44] add p2p for attslotrange --- specs/_features/attslotrange/p2p-interface.md | 72 +++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100644 specs/_features/attslotrange/p2p-interface.md diff --git a/specs/_features/attslotrange/p2p-interface.md b/specs/_features/attslotrange/p2p-interface.md new file mode 100644 index 0000000000..c21da01ffc --- /dev/null +++ b/specs/_features/attslotrange/p2p-interface.md @@ -0,0 +1,72 @@ +# AttSlotRange -- Networking + +This document contains the consensus-layer networking specification for AttSlotRange. + +The specification of these changes continues in the same format as the network specifications of previous upgrades, and assumes them as pre-requisite. + +## Table of contents + + + + + +- [Modifications in AttSlotRange](#modifications-in-attslotrange) + - [The gossip domain: gossipsub](#the-gossip-domain-gossipsub) + - [Topics and messages](#topics-and-messages) + - [Global topics](#global-topics) + - [`beacon_aggregate_and_proof`](#beacon_aggregate_and_proof) + - [Attestation subnets](#attestation-subnets) + - [`beacon_attestation_{subnet_id}](#beacon_attestation_subnet_id) + + + + +## Modifications in AttSlotRange + +### The gossip domain: gossipsub + +#### Topics and messages + +Topics follow the same specification as in prior upgrades. + +The `beacon_aggregate_and_proof` and `beacon_attestation_{subnet_id}` topics are modified to support the gossip of attestations created in epoch `N` to be gossiped through the entire range of slots in epoch `N+1` rather than only through one epoch of slots. + +Otherwise, the specification around the creation, validation, and dissemination of messages has not changed from the Deneb document unless explicitly noted here. + +The derivation of the `message-id` remains stable. + +##### Global topics + +Deneb introduces new global topics for blob sidecars. + +###### `beacon_aggregate_and_proof` + +The following validation is removed: +* _[IGNORE]_ `aggregate.data.slot` is within the last `ATTESTATION_PROPAGATION_SLOT_RANGE` slots (with a `MAXIMUM_GOSSIP_CLOCK_DISPARITY` allowance) -- + i.e. `aggregate.data.slot + ATTESTATION_PROPAGATION_SLOT_RANGE >= current_slot >= aggregate.data.slot` + (a client MAY queue future aggregates for processing at the appropriate slot). + +The following validations are added in its place: +* _[IGNORE]_ `aggregate.data.slot` is equal to or earlier than the `current_slot` (with a `MAXIMUM_GOSSIP_CLOCK_DISPARITY` allowance) -- + i.e. `aggregate.data.slot <= current_slot` + (a client MAY queue future aggregates for processing at the appropriate slot). +* _[IGNORE]_ the epoch of `aggregate.data.slot` is either the current or previous epoch + (with a `MAXIMUM_GOSSIP_CLOCK_DISPARITY` allowance) -- + i.e. `compute_epoch_at_slot(aggregate.data.slot) in (get_previous_epoch(state), get_current_epoch(state))` + +#### Attestation subnets + +##### `beacon_attestation_{subnet_id} + +The following validation is removed: +* _[IGNORE]_ `attestation.data.slot` is within the last `ATTESTATION_PROPAGATION_SLOT_RANGE` slots (with a `MAXIMUM_GOSSIP_CLOCK_DISPARITY` allowance) -- + i.e. `attestation.data.slot + ATTESTATION_PROPAGATION_SLOT_RANGE >= current_slot >= attestation.data.slot` + (a client MAY queue future attestations for processing at the appropriate slot). + +The following validations are added in its place: +* _[IGNORE]_ `attestation.data.slot` is equal to or earlier than the `current_slot` (with a `MAXIMUM_GOSSIP_CLOCK_DISPARITY` allowance) -- + i.e. `attestation.data.slot <= current_slot` + (a client MAY queue future attestation for processing at the appropriate slot). +* _[IGNORE]_ the epoch of `attestation.data.slot` is either the current or previous epoch + (with a `MAXIMUM_GOSSIP_CLOCK_DISPARITY` allowance) -- + i.e. `compute_epoch_at_slot(attestation.data.slot) in (get_previous_epoch(state), get_current_epoch(state))` From 558be7a9a32878868ec221be6c291b52172a1861 Mon Sep 17 00:00:00 2001 From: djrtwo Date: Tue, 16 May 2023 12:20:09 -0600 Subject: [PATCH 10/44] add initialize beacon state from eth1 for AttSlotRAnge --- specs/_features/attslotrange/beacon-chain.md | 55 ++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/specs/_features/attslotrange/beacon-chain.md b/specs/_features/attslotrange/beacon-chain.md index cc0acc61e4..6d65ef8216 100644 --- a/specs/_features/attslotrange/beacon-chain.md +++ b/specs/_features/attslotrange/beacon-chain.md @@ -72,3 +72,58 @@ def process_attestation(state: BeaconState, attestation: Attestation) -> None: proposer_reward = Gwei(proposer_reward_numerator // proposer_reward_denominator) increase_balance(state, get_beacon_proposer_index(state), proposer_reward) ``` + +## Testing + +*Note*: The function `initialize_beacon_state_from_eth1` is modified for pure AttSlotRange testing only. +Modifications include: +1. Use `ATTSLOTRANGE_FORK_VERSION` as the previous and current fork version. + +```python +def initialize_beacon_state_from_eth1(eth1_block_hash: Hash32, + eth1_timestamp: uint64, + deposits: Sequence[Deposit], + execution_payload_header: ExecutionPayloadHeader=ExecutionPayloadHeader() + ) -> BeaconState: + fork = Fork( + previous_version=ATTSLOTRANGE_FORK_VERSION, # [Modified in AttSlotRange] for testing only + current_version=EIP7002_FORK_VERSION, # [Modified in AttSlotRange] + epoch=GENESIS_EPOCH, + ) + state = BeaconState( + genesis_time=eth1_timestamp + GENESIS_DELAY, + fork=fork, + eth1_data=Eth1Data(block_hash=eth1_block_hash, deposit_count=uint64(len(deposits))), + latest_block_header=BeaconBlockHeader(body_root=hash_tree_root(BeaconBlockBody())), + randao_mixes=[eth1_block_hash] * EPOCHS_PER_HISTORICAL_VECTOR, # Seed RANDAO with Eth1 entropy + ) + + # Process deposits + leaves = list(map(lambda deposit: deposit.data, deposits)) + for index, deposit in enumerate(deposits): + deposit_data_list = List[DepositData, 2**DEPOSIT_CONTRACT_TREE_DEPTH](*leaves[:index + 1]) + state.eth1_data.deposit_root = hash_tree_root(deposit_data_list) + process_deposit(state, deposit) + + # Process activations + for index, validator in enumerate(state.validators): + balance = state.balances[index] + validator.effective_balance = min(balance - balance % EFFECTIVE_BALANCE_INCREMENT, MAX_EFFECTIVE_BALANCE) + if validator.effective_balance == MAX_EFFECTIVE_BALANCE: + validator.activation_eligibility_epoch = GENESIS_EPOCH + validator.activation_epoch = GENESIS_EPOCH + + # Set genesis validators root for domain separation and chain versioning + state.genesis_validators_root = hash_tree_root(state.validators) + + # Fill in sync committees + # Note: A duplicate committee is assigned for the current and next committee at genesis + state.current_sync_committee = get_next_sync_committee(state) + state.next_sync_committee = get_next_sync_committee(state) + + # Initialize the execution payload header + state.latest_execution_payload_header = execution_payload_header + + return state +``` + From 235582f4f48d3ff9ea9bc0df8cd09db0025ab67e Mon Sep 17 00:00:00 2001 From: Danny Ryan Date: Wed, 17 May 2023 09:35:32 -0600 Subject: [PATCH 11/44] Update specs/_features/attslotrange/beacon-chain.md Co-authored-by: Potuz --- specs/_features/attslotrange/beacon-chain.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/specs/_features/attslotrange/beacon-chain.md b/specs/_features/attslotrange/beacon-chain.md index 6d65ef8216..aeac1ccc4e 100644 --- a/specs/_features/attslotrange/beacon-chain.md +++ b/specs/_features/attslotrange/beacon-chain.md @@ -35,7 +35,7 @@ This feature allows for inclusion of attestations created during epoch `N` to be #### Modified `process_attestation` -*Note*: The function `process_attestation` is modified to expand valid slots for inclusion tothose in the `target.epoch` epoch as well as those in the `target.epoch + 1` epoch. +*Note*: The function `process_attestation` is modified to expand valid slots for inclusion to those in the `target.epoch` epoch as well as those in the `target.epoch + 1` epoch. ```python def process_attestation(state: BeaconState, attestation: Attestation) -> None: From df1b105b05ef850b4dfb41ca627fb4426018de23 Mon Sep 17 00:00:00 2001 From: djrtwo Date: Wed, 17 May 2023 11:05:09 -0600 Subject: [PATCH 12/44] change rewards flag tracking to allow for any inclusion delay for target reward flag --- specs/_features/attslotrange/beacon-chain.md | 40 +++++++++++++++++++- 1 file changed, 38 insertions(+), 2 deletions(-) diff --git a/specs/_features/attslotrange/beacon-chain.md b/specs/_features/attslotrange/beacon-chain.md index aeac1ccc4e..25ee38f48b 100644 --- a/specs/_features/attslotrange/beacon-chain.md +++ b/specs/_features/attslotrange/beacon-chain.md @@ -15,6 +15,7 @@ - [Beacon chain state transition function](#beacon-chain-state-transition-function) - [Block processing](#block-processing) - [Modified `process_attestation`](#modified-process_attestation) +- [Testing](#testing) @@ -29,13 +30,48 @@ This feature allows for inclusion of attestations created during epoch `N` to be ## Containers +## Helpers + +### Modified `get_attestation_participation_flag_indicies` + +*Note:* The function `get_attestation_participation_flag_indicies` is modified to set the `TIMELY_TARGET_FLAG` for any correct target attestation, regardless of `inclusion_delay` as a baseline reward for any speed of inclusion of an attestation that contributes to justification of the contained chain. + +```python +def get_attestation_participation_flag_indices(state: BeaconState, + data: AttestationData, + inclusion_delay: uint64) -> Sequence[int]: + """ + Return the flag indices that are satisfied by an attestation. + """ + if data.target.epoch == get_current_epoch(state): + justified_checkpoint = state.current_justified_checkpoint + else: + justified_checkpoint = state.previous_justified_checkpoint + + # Matching roots + is_matching_source = data.source == justified_checkpoint + is_matching_target = is_matching_source and data.target.root == get_block_root(state, data.target.epoch) + is_matching_head = is_matching_target and data.beacon_block_root == get_block_root_at_slot(state, data.slot) + assert is_matching_source + + participation_flag_indices = [] + if is_matching_source and inclusion_delay <= integer_squareroot(SLOTS_PER_EPOCH): + participation_flag_indices.append(TIMELY_SOURCE_FLAG_INDEX) + if is_matching_target: + participation_flag_indices.append(TIMELY_TARGET_FLAG_INDEX) + if is_matching_head and inclusion_delay == MIN_ATTESTATION_INCLUSION_DELAY: + participation_flag_indices.append(TIMELY_HEAD_FLAG_INDEX) + + return participation_flag_indices +``` + ## Beacon chain state transition function ### Block processing #### Modified `process_attestation` -*Note*: The function `process_attestation` is modified to expand valid slots for inclusion to those in the `target.epoch` epoch as well as those in the `target.epoch + 1` epoch. +*Note*: The function `process_attestation` is modified to expand valid slots for inclusion to those in both `target.epoch` epoch and `target.epoch + 1` epoch. Additionally, it utilizes an updated version of `get_attestation_participation_flag_indices` to ensure rewards are available for the extended attestation inclusion range. ```python def process_attestation(state: BeaconState, attestation: Attestation) -> None: @@ -87,7 +123,7 @@ def initialize_beacon_state_from_eth1(eth1_block_hash: Hash32, ) -> BeaconState: fork = Fork( previous_version=ATTSLOTRANGE_FORK_VERSION, # [Modified in AttSlotRange] for testing only - current_version=EIP7002_FORK_VERSION, # [Modified in AttSlotRange] + current_version=ATTSLOTRANGE_FORK_VERSION, # [Modified in AttSlotRange] epoch=GENESIS_EPOCH, ) state = BeaconState( From a08cc48e9ed767ab1936f37643b4350eb555cd4a Mon Sep 17 00:00:00 2001 From: djrtwo Date: Wed, 17 May 2023 11:15:24 -0600 Subject: [PATCH 13/44] toc --- specs/_features/attslotrange/beacon-chain.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/specs/_features/attslotrange/beacon-chain.md b/specs/_features/attslotrange/beacon-chain.md index 25ee38f48b..944e928430 100644 --- a/specs/_features/attslotrange/beacon-chain.md +++ b/specs/_features/attslotrange/beacon-chain.md @@ -12,6 +12,8 @@ - [Preset](#preset) - [Configuration](#configuration) - [Containers](#containers) +- [Helpers](#helpers) + - [Modified `get_attestation_participation_flag_indicies`](#modified-get_attestation_participation_flag_indicies) - [Beacon chain state transition function](#beacon-chain-state-transition-function) - [Block processing](#block-processing) - [Modified `process_attestation`](#modified-process_attestation) From ee32e2a31f4892f0f3fa18ea8cced37c3a85b07c Mon Sep 17 00:00:00 2001 From: djrtwo Date: Wed, 17 May 2023 11:53:25 -0600 Subject: [PATCH 14/44] make tests generic across forks --- .../eth2spec/test/helpers/attestations.py | 10 ++- .../test_process_attestation.py | 62 ++++++++++++------- 2 files changed, 49 insertions(+), 23 deletions(-) diff --git a/tests/core/pyspec/eth2spec/test/helpers/attestations.py b/tests/core/pyspec/eth2spec/test/helpers/attestations.py index 360e194f59..ffa0c6c6c8 100644 --- a/tests/core/pyspec/eth2spec/test/helpers/attestations.py +++ b/tests/core/pyspec/eth2spec/test/helpers/attestations.py @@ -5,7 +5,7 @@ from eth2spec.test.context import expect_assertion_error from eth2spec.test.helpers.state import state_transition_and_sign_block, next_epoch, next_slot from eth2spec.test.helpers.block import build_empty_block_for_next_slot -from eth2spec.test.helpers.forks import is_post_altair +from eth2spec.test.helpers.forks import is_post_altair, is_post_attslotrange from eth2spec.test.helpers.keys import privkeys from eth2spec.utils import bls from eth2spec.utils.ssz.ssz_typing import Bitlist @@ -158,6 +158,14 @@ def get_attestation_signature(spec, state, attestation_data, privkey): return bls.Sign(privkey, signing_root) +def compute_max_inclusion_slot(spec, attestation): + if is_post_attslotrange(spec): + next_epoch = spec.compute_epoch_at_slot(attestation.data.slot) + 1 + end_of_next_epoch = spec.compute_start_slot_at_epoch(next_epoch + 1) - 1 + return end_of_next_epoch + return attestation.data.slot + spec.SLOTS_PER_EPOCH + + def fill_aggregate_attestation(spec, state, attestation, signed=False, filter_participant_set=None): """ `signed`: Signing is optional. diff --git a/tests/core/pyspec/eth2spec/test/phase0/block_processing/test_process_attestation.py b/tests/core/pyspec/eth2spec/test/phase0/block_processing/test_process_attestation.py index 3ace6323fc..94a5481fab 100644 --- a/tests/core/pyspec/eth2spec/test/phase0/block_processing/test_process_attestation.py +++ b/tests/core/pyspec/eth2spec/test/phase0/block_processing/test_process_attestation.py @@ -2,9 +2,6 @@ spec_state_test, always_bls, never_bls, with_all_phases, - # Note, if attslotrange gets included, this will need to be - # 'with all phases up until attslotrange' - with_all_phases_except_attslotrange, spec_test, low_balances, with_custom_state, @@ -15,6 +12,7 @@ get_valid_attestation, sign_aggregate_attestation, sign_attestation, + compute_max_inclusion_slot, ) from eth2spec.test.helpers.state import ( next_slots, @@ -96,13 +94,24 @@ def test_invalid_before_inclusion_delay(spec, state): yield from run_attestation_processing(spec, state, attestation, valid=False) -@with_all_phases_except_attslotrange +@with_all_phases +@spec_state_test +def test_at_max_inclusion_slot(spec, state): + attestation = get_valid_attestation(spec, state, signed=True) + + # increment past latest inclusion slot + transition_to_slot_via_block(spec, state, compute_max_inclusion_slot(spec, attestation)) + + yield from run_attestation_processing(spec, state, attestation) + + +@with_all_phases @spec_state_test -def test_invalid_after_epoch_slots(spec, state): +def test_invalid_after_max_inclusion_slot(spec, state): attestation = get_valid_attestation(spec, state, signed=True) # increment past latest inclusion slot - transition_to_slot_via_block(spec, state, state.slot + spec.SLOTS_PER_EPOCH + 1) + transition_to_slot_via_block(spec, state, compute_max_inclusion_slot(spec, attestation) + 1) yield from run_attestation_processing(spec, state, attestation, valid=False) @@ -364,7 +373,7 @@ def test_invalid_too_few_aggregation_bits(spec, state): # -# Full correct atttestation contents at different slot inclusions +# Full correct attestation contents at different slot inclusions # @with_all_phases @@ -394,13 +403,22 @@ def test_correct_attestation_included_at_one_epoch_delay(spec, state): yield from run_attestation_processing(spec, state, attestation) -@with_all_phases_except_attslotrange +@with_all_phases @spec_state_test -def test_invalid_correct_attestation_included_after_epoch_delay(spec, state): +def test_correct_attestation_included_at_max_inclusion_slot(spec, state): + attestation = get_valid_attestation(spec, state, signed=True) + next_slots(spec, state, compute_max_inclusion_slot(spec, attestation)) + + yield from run_attestation_processing(spec, state, attestation) + + +@with_all_phases +@spec_state_test +def test_invalid_correct_attestation_included_after_max_inclusion_slot(spec, state): attestation = get_valid_attestation(spec, state, signed=True) # increment past latest inclusion slot - next_slots(spec, state, spec.SLOTS_PER_EPOCH + 1) + next_slots(spec, state, compute_max_inclusion_slot(spec, attestation) + 1) yield from run_attestation_processing(spec, state, attestation, valid=False) @@ -433,11 +451,11 @@ def test_incorrect_head_included_at_sqrt_epoch_delay(spec, state): yield from run_attestation_processing(spec, state, attestation) -@with_all_phases_except_attslotrange +@with_all_phases @spec_state_test -def test_incorrect_head_included_at_epoch_delay(spec, state): +def test_incorrect_head_included_at_max_inclusion_slot(spec, state): attestation = get_valid_attestation(spec, state, signed=False) - next_slots(spec, state, spec.SLOTS_PER_EPOCH) + next_slots(spec, state, compute_max_inclusion_slot(spec, attestation)) attestation.data.beacon_block_root = b'\x42' * 32 sign_attestation(spec, state, attestation) @@ -445,13 +463,13 @@ def test_incorrect_head_included_at_epoch_delay(spec, state): yield from run_attestation_processing(spec, state, attestation) -@with_all_phases_except_attslotrange +@with_all_phases @spec_state_test -def test_invalid_incorrect_head_included_after_epoch_delay(spec, state): +def test_invalid_incorrect_head_included_after_max_inclusion_slot(spec, state): attestation = get_valid_attestation(spec, state, signed=False) # increment past latest inclusion slot - next_slots(spec, state, spec.SLOTS_PER_EPOCH + 1) + next_slots(spec, state, compute_max_inclusion_slot(spec, attestation) + 1) attestation.data.beacon_block_root = b'\x42' * 32 sign_attestation(spec, state, attestation) @@ -502,12 +520,12 @@ def test_incorrect_head_and_target_included_at_epoch_delay(spec, state): yield from run_attestation_processing(spec, state, attestation) -@with_all_phases_except_attslotrange +@with_all_phases @spec_state_test -def test_invalid_incorrect_head_and_target_included_after_epoch_delay(spec, state): +def test_invalid_incorrect_head_and_target_included_after_max_inclusion_slot(spec, state): attestation = get_valid_attestation(spec, state, signed=False) # increment past latest inclusion slot - next_slots(spec, state, spec.SLOTS_PER_EPOCH + 1) + next_slots(spec, state, compute_max_inclusion_slot(spec, attestation) + 1) attestation.data.beacon_block_root = b'\x42' * 32 attestation.data.target.root = b'\x42' * 32 @@ -556,12 +574,12 @@ def test_incorrect_target_included_at_epoch_delay(spec, state): yield from run_attestation_processing(spec, state, attestation) -@with_all_phases_except_attslotrange +@with_all_phases @spec_state_test -def test_invalid_incorrect_target_included_after_epoch_delay(spec, state): +def test_invalid_incorrect_target_included_after_max_inclusion_slot(spec, state): attestation = get_valid_attestation(spec, state, signed=False) # increment past latest inclusion slot - next_slots(spec, state, spec.SLOTS_PER_EPOCH + 1) + next_slots(spec, state, compute_max_inclusion_slot(spec, attestation) + 1) attestation.data.target.root = b'\x42' * 32 sign_attestation(spec, state, attestation) From f967567ec7481c944b7b4ede21c09feeccb9c24e Mon Sep 17 00:00:00 2001 From: djrtwo Date: Wed, 17 May 2023 11:58:05 -0600 Subject: [PATCH 15/44] add a comment annotation for fork update --- specs/_features/attslotrange/beacon-chain.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/specs/_features/attslotrange/beacon-chain.md b/specs/_features/attslotrange/beacon-chain.md index 944e928430..7ab6475ff6 100644 --- a/specs/_features/attslotrange/beacon-chain.md +++ b/specs/_features/attslotrange/beacon-chain.md @@ -59,7 +59,7 @@ def get_attestation_participation_flag_indices(state: BeaconState, participation_flag_indices = [] if is_matching_source and inclusion_delay <= integer_squareroot(SLOTS_PER_EPOCH): participation_flag_indices.append(TIMELY_SOURCE_FLAG_INDEX) - if is_matching_target: + if is_matching_target: # [Modified in AttSlotRange] participation_flag_indices.append(TIMELY_TARGET_FLAG_INDEX) if is_matching_head and inclusion_delay == MIN_ATTESTATION_INCLUSION_DELAY: participation_flag_indices.append(TIMELY_HEAD_FLAG_INDEX) From 6679b8a1ae65a1afbdfc600ab0b4356c381e572b Mon Sep 17 00:00:00 2001 From: djrtwo Date: Thu, 18 May 2023 10:49:57 -0600 Subject: [PATCH 16/44] attslotrange -> eip-7045 --- .circleci/config.yml | 6 ++--- .gitignore | 2 +- Makefile | 2 +- configs/mainnet.yaml | 6 ++--- configs/minimal.yaml | 6 ++--- setup.py | 26 +++++++++---------- .../{attslotrange => eip7045}/beacon-chain.md | 12 ++++----- .../{attslotrange => eip7045}/fork.md | 24 ++++++++--------- .../p2p-interface.md | 8 +++--- tests/core/pyspec/eth2spec/test/context.py | 12 ++++----- .../eth2spec/test/helpers/attestations.py | 4 +-- .../pyspec/eth2spec/test/helpers/constants.py | 4 +-- .../eth2spec/test/helpers/fork_transition.py | 10 +++---- .../pyspec/eth2spec/test/helpers/forks.py | 10 +++---- .../pyspec/eth2spec/test/helpers/genesis.py | 6 ++--- 15 files changed, 69 insertions(+), 69 deletions(-) rename specs/_features/{attslotrange => eip7045}/beacon-chain.md (94%) rename specs/_features/{attslotrange => eip7045}/fork.md (81%) rename specs/_features/{attslotrange => eip7045}/p2p-interface.md (95%) diff --git a/.circleci/config.yml b/.circleci/config.yml index c3d6540ad3..89a7487c8b 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -168,7 +168,7 @@ jobs: command: make citest fork=eip6110 - store_test_results: path: tests/core/pyspec/test-reports - test-attslotrange: + test-eip7045: docker: - image: circleci/python:3.8 working_directory: ~/specs-repo @@ -178,7 +178,7 @@ jobs: - restore_pyspec_cached_venv - run: name: Run py-tests - command: make citest fork=attslotrange + command: make citest fork=eip7045 - store_test_results: path: tests/core/pyspec/test-reports @@ -305,7 +305,7 @@ workflows: - test-eip6110: requires: - install_pyspec_test - - test-attslotrange: + - test-eip7045: requires: - install_pyspec_test - table_of_contents diff --git a/.gitignore b/.gitignore index c8cd7a15a2..55bf1d1762 100644 --- a/.gitignore +++ b/.gitignore @@ -22,7 +22,7 @@ tests/core/pyspec/eth2spec/bellatrix/ tests/core/pyspec/eth2spec/capella/ tests/core/pyspec/eth2spec/deneb/ tests/core/pyspec/eth2spec/eip6110/ -tests/core/pyspec/eth2spec/attslotrange/ +tests/core/pyspec/eth2spec/eip7045/ # coverage reports .htmlcov diff --git a/Makefile b/Makefile index b0990bd51c..55f77ed4a8 100644 --- a/Makefile +++ b/Makefile @@ -34,7 +34,7 @@ MARKDOWN_FILES = $(wildcard $(SPEC_DIR)/*/*.md) \ $(wildcard $(SPEC_DIR)/_features/*/*/*.md) \ $(wildcard $(SSZ_DIR)/*.md) -ALL_EXECUTABLE_SPECS = phase0 altair bellatrix capella deneb eip6110 attslotrange +ALL_EXECUTABLE_SPECS = phase0 altair bellatrix capella deneb eip6110 eip7045 # The parameters for commands. Use `foreach` to avoid listing specs again. COVERAGE_SCOPE := $(foreach S,$(ALL_EXECUTABLE_SPECS), --cov=eth2spec.$S.$(TEST_PRESET_TYPE)) PYLINT_SCOPE := $(foreach S,$(ALL_EXECUTABLE_SPECS), ./eth2spec/$S) diff --git a/configs/mainnet.yaml b/configs/mainnet.yaml index 1fee9abf66..05cd2c0354 100644 --- a/configs/mainnet.yaml +++ b/configs/mainnet.yaml @@ -53,9 +53,9 @@ DENEB_FORK_EPOCH: 18446744073709551615 # EIP6110 EIP6110_FORK_VERSION: 0x05000000 # temporary stub EIP6110_FORK_EPOCH: 18446744073709551615 -# AttSlotRange -ATTSLOTRANGE_FORK_VERSION: 0x05000000 # temporary stub -ATTSLOTRANGE_FORK_EPOCH: 18446744073709551615 +# EIP7045 +EIP7045_FORK_VERSION: 0x05000000 # temporary stub +EIP7045_FORK_EPOCH: 18446744073709551615 # Time parameters diff --git a/configs/minimal.yaml b/configs/minimal.yaml index acc6854804..0c3df50c53 100644 --- a/configs/minimal.yaml +++ b/configs/minimal.yaml @@ -52,9 +52,9 @@ DENEB_FORK_EPOCH: 18446744073709551615 # EIP6110 EIP6110_FORK_VERSION: 0x05000001 EIP6110_FORK_EPOCH: 18446744073709551615 -# AttSlotRange -ATTSLOTRANGE_FORK_VERSION: 0x05000001 -ATTSLOTRANGE_FORK_EPOCH: 18446744073709551615 +# EIP7045 +EIP7045_FORK_VERSION: 0x05000001 +EIP7045_FORK_EPOCH: 18446744073709551615 diff --git a/setup.py b/setup.py index 23c4ac19c1..5492c7c474 100644 --- a/setup.py +++ b/setup.py @@ -48,7 +48,7 @@ def installPackage(package: str): CAPELLA = 'capella' DENEB = 'deneb' EIP6110 = 'eip6110' -ATTSLOTRANGE= 'attslotrange' +EIP7045= 'eip7045' # The helper functions that are used when defining constants @@ -682,10 +682,10 @@ def imports(cls, preset_name: str): ''' # -# AttSlotRangeSpecBuilder +# EIP7045SpecBuilder # -class AttSlotRangeSpecBuilder(DenebSpecBuilder): - fork: str = ATTSLOTRANGE +class EIP7045SpecBuilder(DenebSpecBuilder): + fork: str = EIP7045 @classmethod def imports(cls, preset_name: str): @@ -695,7 +695,7 @@ def imports(cls, preset_name: str): all_builders = ( Phase0SpecBuilder, AltairSpecBuilder, BellatrixSpecBuilder, CapellaSpecBuilder, DenebSpecBuilder, - EIP6110SpecBuilder, AttSlotRangeSpecBuilder, + EIP6110SpecBuilder, EIP7045SpecBuilder, ) spec_builders = {builder.fork: builder for builder in all_builders} @@ -995,14 +995,14 @@ def finalize_options(self): if len(self.md_doc_paths) == 0: print("no paths were specified, using default markdown file paths for pyspec" " build (spec fork: %s)" % self.spec_fork) - if self.spec_fork in (PHASE0, ALTAIR, BELLATRIX, CAPELLA, DENEB, EIP6110, ATTSLOTRANGE): + if self.spec_fork in (PHASE0, ALTAIR, BELLATRIX, CAPELLA, DENEB, EIP6110, EIP7045): self.md_doc_paths = """ specs/phase0/beacon-chain.md specs/phase0/fork-choice.md specs/phase0/validator.md specs/phase0/weak-subjectivity.md """ - if self.spec_fork in (ALTAIR, BELLATRIX, CAPELLA, DENEB, EIP6110, ATTSLOTRANGE): + if self.spec_fork in (ALTAIR, BELLATRIX, CAPELLA, DENEB, EIP6110, EIP7045): self.md_doc_paths += """ specs/altair/light-client/full-node.md specs/altair/light-client/light-client.md @@ -1014,7 +1014,7 @@ def finalize_options(self): specs/altair/validator.md specs/altair/p2p-interface.md """ - if self.spec_fork in (BELLATRIX, CAPELLA, DENEB, EIP6110, ATTSLOTRANGE): + if self.spec_fork in (BELLATRIX, CAPELLA, DENEB, EIP6110, EIP7045): self.md_doc_paths += """ specs/bellatrix/beacon-chain.md specs/bellatrix/fork.md @@ -1023,7 +1023,7 @@ def finalize_options(self): specs/bellatrix/p2p-interface.md sync/optimistic.md """ - if self.spec_fork in (CAPELLA, DENEB, EIP6110, ATTSLOTRANGE): + if self.spec_fork in (CAPELLA, DENEB, EIP6110, EIP7045): self.md_doc_paths += """ specs/capella/light-client/fork.md specs/capella/light-client/full-node.md @@ -1035,7 +1035,7 @@ def finalize_options(self): specs/capella/validator.md specs/capella/p2p-interface.md """ - if self.spec_fork in (DENEB, EIP6110, ATTSLOTRANGE): + if self.spec_fork in (DENEB, EIP6110, EIP7045): self.md_doc_paths += """ specs/deneb/light-client/fork.md specs/deneb/light-client/full-node.md @@ -1057,10 +1057,10 @@ def finalize_options(self): specs/_features/eip6110/beacon-chain.md specs/_features/eip6110/fork.md """ - if self.spec_fork == ATTSLOTRANGE: + if self.spec_fork == EIP7045: self.md_doc_paths += """ - specs/_features/attslotrange/beacon-chain.md - specs/_features/attslotrange/fork.md + specs/_features/eip7045/beacon-chain.md + specs/_features/eip7045/fork.md """ if len(self.md_doc_paths) == 0: diff --git a/specs/_features/attslotrange/beacon-chain.md b/specs/_features/eip7045/beacon-chain.md similarity index 94% rename from specs/_features/attslotrange/beacon-chain.md rename to specs/_features/eip7045/beacon-chain.md index 7ab6475ff6..9429b102e8 100644 --- a/specs/_features/attslotrange/beacon-chain.md +++ b/specs/_features/eip7045/beacon-chain.md @@ -59,7 +59,7 @@ def get_attestation_participation_flag_indices(state: BeaconState, participation_flag_indices = [] if is_matching_source and inclusion_delay <= integer_squareroot(SLOTS_PER_EPOCH): participation_flag_indices.append(TIMELY_SOURCE_FLAG_INDEX) - if is_matching_target: # [Modified in AttSlotRange] + if is_matching_target: # [Modified in EIP7045] participation_flag_indices.append(TIMELY_TARGET_FLAG_INDEX) if is_matching_head and inclusion_delay == MIN_ATTESTATION_INCLUSION_DELAY: participation_flag_indices.append(TIMELY_HEAD_FLAG_INDEX) @@ -80,7 +80,7 @@ def process_attestation(state: BeaconState, attestation: Attestation) -> None: data = attestation.data assert data.target.epoch in (get_previous_epoch(state), get_current_epoch(state)) assert data.target.epoch == compute_epoch_at_slot(data.slot) - assert data.slot + MIN_ATTESTATION_INCLUSION_DELAY <= state.slot # [Modified in AttSlotRange] + assert data.slot + MIN_ATTESTATION_INCLUSION_DELAY <= state.slot # [Modified in EIP7045] assert data.index < get_committee_count_per_slot(state, data.target.epoch) committee = get_beacon_committee(state, data.slot, data.index) @@ -113,9 +113,9 @@ def process_attestation(state: BeaconState, attestation: Attestation) -> None: ## Testing -*Note*: The function `initialize_beacon_state_from_eth1` is modified for pure AttSlotRange testing only. +*Note*: The function `initialize_beacon_state_from_eth1` is modified for pure EIP7045 testing only. Modifications include: -1. Use `ATTSLOTRANGE_FORK_VERSION` as the previous and current fork version. +1. Use `EIP7045_FORK_VERSION` as the previous and current fork version. ```python def initialize_beacon_state_from_eth1(eth1_block_hash: Hash32, @@ -124,8 +124,8 @@ def initialize_beacon_state_from_eth1(eth1_block_hash: Hash32, execution_payload_header: ExecutionPayloadHeader=ExecutionPayloadHeader() ) -> BeaconState: fork = Fork( - previous_version=ATTSLOTRANGE_FORK_VERSION, # [Modified in AttSlotRange] for testing only - current_version=ATTSLOTRANGE_FORK_VERSION, # [Modified in AttSlotRange] + previous_version=EIP7045_FORK_VERSION, # [Modified in EIP7045] for testing only + current_version=EIP7045_FORK_VERSION, # [Modified in EIP7045] epoch=GENESIS_EPOCH, ) state = BeaconState( diff --git a/specs/_features/attslotrange/fork.md b/specs/_features/eip7045/fork.md similarity index 81% rename from specs/_features/attslotrange/fork.md rename to specs/_features/eip7045/fork.md index 3d8454c2a3..42b14b1704 100644 --- a/specs/_features/attslotrange/fork.md +++ b/specs/_features/eip7045/fork.md @@ -12,7 +12,7 @@ - [Helper functions](#helper-functions) - [Misc](#misc) - [Modified `compute_fork_version`](#modified-compute_fork_version) -- [Fork to AttSlotRange](#fork-to-attslotrange) +- [Fork to EIP7045](#fork-to-eip7045) - [Fork trigger](#fork-trigger) - [Upgrading the state](#upgrading-the-state) @@ -28,8 +28,8 @@ Warning: this configuration is not definitive. | Name | Value | | - | - | -| `ATTSLOTRANGE_FORK_VERSION` | `Version('0x05000000')` | -| `ATTSLOTRANGE_FORK_EPOCH` | `Epoch(18446744073709551615)` **TBD** | +| `EIP7045_FORK_VERSION` | `Version('0x05000000')` | +| `EIP7045_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 >= ATTSLOTRANGE_FORK_EPOCH: - return ATTSLOTRANGE_FORK_VERSION + if epoch >= EIP7045_FORK_EPOCH: + return EIP7045_FORK_VERSION if epoch >= DENEB_FORK_EPOCH: return DENEB_FORK_VERSION if epoch >= CAPELLA_FORK_EPOCH: @@ -55,22 +55,22 @@ def compute_fork_version(epoch: Epoch) -> Version: return GENESIS_FORK_VERSION ``` -## Fork to AttSlotRange +## Fork to EIP7045 ### 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 `ATTSLOTRANGE_FORK_EPOCH`. +For now, we assume the condition will be triggered at epoch `EIP7045_FORK_EPOCH`. -Note that for the pure AttSlotRange networks, we don't apply `upgrade_to_attslotrange` since it starts with AttSlotRange version logic. +Note that for the pure EIP7045 networks, we don't apply `upgrade_to_eip7045` since it starts with EIP7045 version logic. ### Upgrading the state -If `state.slot % SLOTS_PER_EPOCH == 0` and `compute_epoch_at_slot(state.slot) == ATTSLOTRANGE_FORK_EPOCH, -an irregular state change is made to upgrade to AttSlotRange. +If `state.slot % SLOTS_PER_EPOCH == 0` and `compute_epoch_at_slot(state.slot) == EIP7045_FORK_EPOCH, +an irregular state change is made to upgrade to EIP7045. ```python -def upgrade_to_attslotrange(pre: deneb.BeaconState) -> BeaconState: +def upgrade_to_eip7045(pre: deneb.BeaconState) -> BeaconState: post = BeaconState( # Versioning genesis_time=pre.genesis_time, @@ -78,7 +78,7 @@ def upgrade_to_attslotrange(pre: deneb.BeaconState) -> BeaconState: slot=pre.slot, fork=Fork( previous_version=pre.fork.current_version, - current_version=ATTSLOTRANGE_FORK_VERSION, # [Modified in Att-Slot-Range] + current_version=EIP7045_FORK_VERSION, # [Modified in Att-Slot-Range] epoch=deneb.get_current_epoch(pre), ), # History diff --git a/specs/_features/attslotrange/p2p-interface.md b/specs/_features/eip7045/p2p-interface.md similarity index 95% rename from specs/_features/attslotrange/p2p-interface.md rename to specs/_features/eip7045/p2p-interface.md index c21da01ffc..8e263bcee6 100644 --- a/specs/_features/attslotrange/p2p-interface.md +++ b/specs/_features/eip7045/p2p-interface.md @@ -1,6 +1,6 @@ -# AttSlotRange -- Networking +# EIP7045 -- Networking -This document contains the consensus-layer networking specification for AttSlotRange. +This document contains the consensus-layer networking specification for EIP7045. The specification of these changes continues in the same format as the network specifications of previous upgrades, and assumes them as pre-requisite. @@ -10,7 +10,7 @@ The specification of these changes continues in the same format as the network s -- [Modifications in AttSlotRange](#modifications-in-attslotrange) +- [Modifications in EIP7045](#modifications-in-eip7045) - [The gossip domain: gossipsub](#the-gossip-domain-gossipsub) - [Topics and messages](#topics-and-messages) - [Global topics](#global-topics) @@ -21,7 +21,7 @@ The specification of these changes continues in the same format as the network s -## Modifications in AttSlotRange +## Modifications in EIP7045 ### The gossip domain: gossipsub diff --git a/tests/core/pyspec/eth2spec/test/context.py b/tests/core/pyspec/eth2spec/test/context.py index 37a6e6eab9..f3241fd567 100644 --- a/tests/core/pyspec/eth2spec/test/context.py +++ b/tests/core/pyspec/eth2spec/test/context.py @@ -9,13 +9,13 @@ from eth2spec.capella import mainnet as spec_capella_mainnet, minimal as spec_capella_minimal from eth2spec.deneb import mainnet as spec_deneb_mainnet, minimal as spec_deneb_minimal from eth2spec.eip6110 import mainnet as spec_eip6110_mainnet, minimal as spec_eip6110_minimal -from eth2spec.attslotrange import mainnet as spec_attslotrange_mainnet, minimal as spec_attslotrange_minimal +from eth2spec.eip7045 import mainnet as spec_eip7045_mainnet, minimal as spec_eip7045_minimal from eth2spec.utils import bls from .exceptions import SkippedTest from .helpers.constants import ( PHASE0, ALTAIR, BELLATRIX, CAPELLA, DENEB, - EIP6110, ATTSLOTRANGE, + EIP6110, EIP7045, MINIMAL, MAINNET, ALL_PHASES, ALL_FORK_UPGRADES, @@ -83,7 +83,7 @@ class ForkMeta: CAPELLA: spec_capella_minimal, DENEB: spec_deneb_minimal, EIP6110: spec_eip6110_minimal, - ATTSLOTRANGE: spec_attslotrange_minimal, + EIP7045: spec_eip7045_minimal, }, MAINNET: { PHASE0: spec_phase0_mainnet, @@ -92,7 +92,7 @@ class ForkMeta: CAPELLA: spec_capella_mainnet, DENEB: spec_deneb_mainnet, EIP6110: spec_eip6110_mainnet, - ATTSLOTRANGE: spec_attslotrange_mainnet, + EIP7045: spec_eip7045_mainnet, }, } @@ -436,9 +436,9 @@ def decorator(fn): with_capella_and_later = with_all_phases_from(CAPELLA) with_deneb_and_later = with_all_phases_from(DENEB) with_eip6110_and_later = with_all_phases_from(EIP6110) -with_attslotrange_and_later = with_all_phases_from(ATTSLOTRANGE) +with_eip7045_and_later = with_all_phases_from(EIP7045) -with_all_phases_except_attslotrange = with_all_phases_except(ATTSLOTRANGE) +with_all_phases_except_eip7045 = with_all_phases_except(EIP7045) def _get_preset_targets(kw): diff --git a/tests/core/pyspec/eth2spec/test/helpers/attestations.py b/tests/core/pyspec/eth2spec/test/helpers/attestations.py index ffa0c6c6c8..b1f60feb4b 100644 --- a/tests/core/pyspec/eth2spec/test/helpers/attestations.py +++ b/tests/core/pyspec/eth2spec/test/helpers/attestations.py @@ -5,7 +5,7 @@ from eth2spec.test.context import expect_assertion_error from eth2spec.test.helpers.state import state_transition_and_sign_block, next_epoch, next_slot from eth2spec.test.helpers.block import build_empty_block_for_next_slot -from eth2spec.test.helpers.forks import is_post_altair, is_post_attslotrange +from eth2spec.test.helpers.forks import is_post_altair, is_post_eip7045 from eth2spec.test.helpers.keys import privkeys from eth2spec.utils import bls from eth2spec.utils.ssz.ssz_typing import Bitlist @@ -159,7 +159,7 @@ def get_attestation_signature(spec, state, attestation_data, privkey): def compute_max_inclusion_slot(spec, attestation): - if is_post_attslotrange(spec): + if is_post_eip7045(spec): next_epoch = spec.compute_epoch_at_slot(attestation.data.slot) + 1 end_of_next_epoch = spec.compute_start_slot_at_epoch(next_epoch + 1) - 1 return end_of_next_epoch diff --git a/tests/core/pyspec/eth2spec/test/helpers/constants.py b/tests/core/pyspec/eth2spec/test/helpers/constants.py index a3339305ea..7882a15ebb 100644 --- a/tests/core/pyspec/eth2spec/test/helpers/constants.py +++ b/tests/core/pyspec/eth2spec/test/helpers/constants.py @@ -16,14 +16,14 @@ CUSTODY_GAME = SpecForkName('custody_game') DAS = SpecForkName('das') EIP6110 = SpecForkName('eip6110') -ATTSLOTRANGE = SpecForkName('attslotrange') +EIP7045 = SpecForkName('eip7045') # The forks that pytest can run with. ALL_PHASES = ( # Formal forks PHASE0, ALTAIR, BELLATRIX, CAPELLA, DENEB, # Experimental patches - EIP6110, ATTSLOTRANGE, + EIP6110, EIP7045, ) # The forks that output to the test vectors. TESTGEN_FORKS = (PHASE0, ALTAIR, BELLATRIX, CAPELLA, DENEB, EIP6110) diff --git a/tests/core/pyspec/eth2spec/test/helpers/fork_transition.py b/tests/core/pyspec/eth2spec/test/helpers/fork_transition.py index 76b3327283..cf7aeb93a4 100644 --- a/tests/core/pyspec/eth2spec/test/helpers/fork_transition.py +++ b/tests/core/pyspec/eth2spec/test/helpers/fork_transition.py @@ -16,7 +16,7 @@ CAPELLA, DENEB, EIP6110, - ATTSLOTRANGE, + EIP7045, ) from eth2spec.test.helpers.deposits import ( prepare_state_and_deposit, @@ -162,8 +162,8 @@ def do_fork(state, spec, post_spec, fork_epoch, with_block=True, sync_aggregate= state = post_spec.upgrade_to_deneb(state) elif post_spec.fork == EIP6110: state = post_spec.upgrade_to_eip6110(state) - elif post_spec.fork == ATTSLOTRANGE: - state = post_spec.upgrade_to_attslotrange(state) + elif post_spec.fork == EIP7045: + state = post_spec.upgrade_to_eip7045(state) assert state.fork.epoch == fork_epoch @@ -182,9 +182,9 @@ def do_fork(state, spec, post_spec, fork_epoch, with_block=True, sync_aggregate= elif post_spec.fork == EIP6110: assert state.fork.previous_version == post_spec.config.DENEB_FORK_VERSION assert state.fork.current_version == post_spec.config.EIP6110_FORK_VERSION - elif post_spec.fork == ATTSLOTRANGE: + elif post_spec.fork == EIP7045: assert state.fork.previous_version == post_spec.config.DENEB_FORK_VERSION - assert state.fork.current_version == post_spec.config.ATTSLOTRANGE_FORK_VERSION + assert state.fork.current_version == post_spec.config.EIP7045_FORK_VERSION if with_block: return state, _state_transition_and_sign_block_at_slot( diff --git a/tests/core/pyspec/eth2spec/test/helpers/forks.py b/tests/core/pyspec/eth2spec/test/helpers/forks.py index 35c265ebb7..ddd3b795ba 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, ATTSLOTRANGE, + EIP6110, EIP7045, ) def is_post_fork(a, b): - if a == ATTSLOTRANGE: - return b in [PHASE0, ALTAIR, BELLATRIX, CAPELLA, DENEB, ATTSLOTRANGE] + if a == EIP7045: + return b in [PHASE0, ALTAIR, BELLATRIX, CAPELLA, DENEB, EIP7045] if a == EIP6110: return b in [PHASE0, ALTAIR, BELLATRIX, CAPELLA, DENEB, EIP6110] if a == DENEB: @@ -42,5 +42,5 @@ def is_post_eip6110(spec): return is_post_fork(spec.fork, EIP6110) -def is_post_attslotrange(spec): - return is_post_fork(spec.fork, ATTSLOTRANGE) +def is_post_eip7045(spec): + return is_post_fork(spec.fork, EIP7045) diff --git a/tests/core/pyspec/eth2spec/test/helpers/genesis.py b/tests/core/pyspec/eth2spec/test/helpers/genesis.py index e3649b8e9d..eab4abec8d 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, ATTSLOTRANGE, + ALTAIR, BELLATRIX, CAPELLA, DENEB, EIP6110, EIP7045, ) from eth2spec.test.helpers.execution_payload import ( compute_el_header_block_hash, @@ -86,9 +86,9 @@ def create_genesis_state(spec, validator_balances, activation_threshold): elif spec.fork == EIP6110: previous_version = spec.config.DENEB_FORK_VERSION current_version = spec.config.EIP6110_FORK_VERSION - elif spec.fork == ATTSLOTRANGE: + elif spec.fork == EIP7045: previous_version = spec.config.DENEB_FORK_VERSION - current_version = spec.config.ATTSLOTRANGE_FORK_VERSION + current_version = spec.config.EIP7045_FORK_VERSION state = spec.BeaconState( genesis_time=0, From 32036d84a3542ce5b9bd4a2f4e288edfb6267a25 Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Fri, 19 May 2023 23:32:49 +0800 Subject: [PATCH 17/44] Fix tests --- specs/deneb/beacon-chain.md | 5 ++- .../test_process_voluntary_exit.py | 28 +++++++----- .../test/deneb/block_processing/__init__.py | 0 .../test_process_voluntary_exit.py | 45 +++++++++++++++++++ .../test_process_voluntary_exit.py | 44 ++++++++++++++++++ .../eth2spec/test/helpers/voluntary_exits.py | 20 +++++---- tests/generators/operations/main.py | 6 ++- 7 files changed, 127 insertions(+), 21 deletions(-) create mode 100644 tests/core/pyspec/eth2spec/test/deneb/block_processing/__init__.py create mode 100644 tests/core/pyspec/eth2spec/test/deneb/block_processing/test_process_voluntary_exit.py create mode 100644 tests/core/pyspec/eth2spec/test/eip6110/block_processing/test_process_voluntary_exit.py diff --git a/specs/deneb/beacon-chain.md b/specs/deneb/beacon-chain.md index f1fe48e824..7d2f9bdc7d 100644 --- a/specs/deneb/beacon-chain.md +++ b/specs/deneb/beacon-chain.md @@ -30,6 +30,8 @@ - [Block processing](#block-processing) - [Execution payload](#execution-payload) - [`process_execution_payload`](#process_execution_payload) + - [Modified `process_operations`](#modified-process_operations) + - [Modified `process_voluntary_exit`](#modified-process_voluntary_exit) - [Blob KZG commitments](#blob-kzg-commitments) - [Testing](#testing) @@ -281,7 +283,8 @@ def process_voluntary_exit(state: BeaconState, signed_voluntary_exit: SignedVolu # Verify the validator has been active long enough assert get_current_epoch(state) >= validator.activation_epoch + SHARD_COMMITTEE_PERIOD # Verify signature - domain = compute_domain(DOMAIN_VOLUNTARY_EXIT, CAPELLA_FORK_VERSION, state.genesis_validators_root) # [Modified in Deneb] + # [Modified in Deneb] + domain = compute_domain(DOMAIN_VOLUNTARY_EXIT, CAPELLA_FORK_VERSION, state.genesis_validators_root) signing_root = compute_signing_root(voluntary_exit, domain) assert bls.Verify(validator.pubkey, signing_root, signed_voluntary_exit.signature) # Initiate exit diff --git a/tests/core/pyspec/eth2spec/test/bellatrix/block_processing/test_process_voluntary_exit.py b/tests/core/pyspec/eth2spec/test/bellatrix/block_processing/test_process_voluntary_exit.py index f4fcaac689..12b554da5b 100644 --- a/tests/core/pyspec/eth2spec/test/bellatrix/block_processing/test_process_voluntary_exit.py +++ b/tests/core/pyspec/eth2spec/test/bellatrix/block_processing/test_process_voluntary_exit.py @@ -2,6 +2,12 @@ spec_state_test, always_bls, with_bellatrix_and_later, + with_phases, +) +from eth2spec.test.helpers.constants import ( + BELLATRIX, + CAPELLA, + DENEB, ) from eth2spec.test.helpers.keys import pubkey_to_privkey from eth2spec.test.helpers.state import ( @@ -12,8 +18,10 @@ sign_voluntary_exit, ) +BELLATRIX_AND_CAPELLA = [BELLATRIX, CAPELLA] + -def _run_voluntary_exit_processing_test( +def run_voluntary_exit_processing_test( spec, state, fork_version, @@ -51,7 +59,7 @@ def _run_voluntary_exit_processing_test( @spec_state_test @always_bls def test_invalid_voluntary_exit_with_current_fork_version_is_before_fork_epoch(spec, state): - yield from _run_voluntary_exit_processing_test( + yield from run_voluntary_exit_processing_test( spec, state, fork_version=state.fork.current_version, @@ -60,11 +68,11 @@ def test_invalid_voluntary_exit_with_current_fork_version_is_before_fork_epoch(s ) -@with_bellatrix_and_later +@with_phases(BELLATRIX_AND_CAPELLA) @spec_state_test @always_bls def test_voluntary_exit_with_current_fork_version_not_is_before_fork_epoch(spec, state): - yield from _run_voluntary_exit_processing_test( + yield from run_voluntary_exit_processing_test( spec, state, fork_version=state.fork.current_version, @@ -72,13 +80,13 @@ def test_voluntary_exit_with_current_fork_version_not_is_before_fork_epoch(spec, ) -@with_bellatrix_and_later +@with_phases([BELLATRIX, CAPELLA, DENEB]) @spec_state_test @always_bls def test_voluntary_exit_with_previous_fork_version_is_before_fork_epoch(spec, state): assert state.fork.previous_version != state.fork.current_version - yield from _run_voluntary_exit_processing_test( + yield from run_voluntary_exit_processing_test( spec, state, fork_version=state.fork.previous_version, @@ -86,13 +94,13 @@ def test_voluntary_exit_with_previous_fork_version_is_before_fork_epoch(spec, st ) -@with_bellatrix_and_later +@with_phases(BELLATRIX_AND_CAPELLA) @spec_state_test @always_bls def test_invalid_voluntary_exit_with_previous_fork_version_not_is_before_fork_epoch(spec, state): assert state.fork.previous_version != state.fork.current_version - yield from _run_voluntary_exit_processing_test( + yield from run_voluntary_exit_processing_test( spec, state, fork_version=state.fork.previous_version, @@ -107,7 +115,7 @@ def test_invalid_voluntary_exit_with_previous_fork_version_not_is_before_fork_ep def test_invalid_voluntary_exit_with_genesis_fork_version_is_before_fork_epoch(spec, state): assert spec.config.GENESIS_FORK_VERSION not in (state.fork.previous_version, state.fork.current_version) - yield from _run_voluntary_exit_processing_test( + yield from run_voluntary_exit_processing_test( spec, state, fork_version=spec.config.GENESIS_FORK_VERSION, @@ -122,7 +130,7 @@ def test_invalid_voluntary_exit_with_genesis_fork_version_is_before_fork_epoch(s def test_invalid_voluntary_exit_with_genesis_fork_version_not_is_before_fork_epoch(spec, state): assert spec.config.GENESIS_FORK_VERSION not in (state.fork.previous_version, state.fork.current_version) - yield from _run_voluntary_exit_processing_test( + yield from run_voluntary_exit_processing_test( spec, state, fork_version=spec.config.GENESIS_FORK_VERSION, diff --git a/tests/core/pyspec/eth2spec/test/deneb/block_processing/__init__.py b/tests/core/pyspec/eth2spec/test/deneb/block_processing/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/core/pyspec/eth2spec/test/deneb/block_processing/test_process_voluntary_exit.py b/tests/core/pyspec/eth2spec/test/deneb/block_processing/test_process_voluntary_exit.py new file mode 100644 index 0000000000..371fcfed42 --- /dev/null +++ b/tests/core/pyspec/eth2spec/test/deneb/block_processing/test_process_voluntary_exit.py @@ -0,0 +1,45 @@ +from eth2spec.test.context import ( + always_bls, + spec_state_test, + with_phases, + with_deneb_and_later, +) +from eth2spec.test.helpers.constants import ( + DENEB, +) +from eth2spec.test.bellatrix.block_processing.test_process_voluntary_exit import ( + run_voluntary_exit_processing_test, +) + + +@with_deneb_and_later +@spec_state_test +@always_bls +def test_invalid_voluntary_exit_with_current_fork_version_not_is_before_fork_epoch(spec, state): + """ + Since Deneb, the VoluntaryExit domain is fixed to `CAPELLA_FORK_VERSION` + """ + yield from run_voluntary_exit_processing_test( + spec, + state, + fork_version=state.fork.current_version, + is_before_fork_epoch=False, + valid=False, + ) + + +@with_phases([DENEB]) +@spec_state_test +@always_bls +def test_voluntary_exit_with_previous_fork_version_not_is_before_fork_epoch(spec, state): + """ + Since Deneb, the VoluntaryExit domain is fixed to `CAPELLA_FORK_VERSION` + """ + assert state.fork.previous_version != state.fork.current_version + + yield from run_voluntary_exit_processing_test( + spec, + state, + fork_version=state.fork.previous_version, + is_before_fork_epoch=False, + ) diff --git a/tests/core/pyspec/eth2spec/test/eip6110/block_processing/test_process_voluntary_exit.py b/tests/core/pyspec/eth2spec/test/eip6110/block_processing/test_process_voluntary_exit.py new file mode 100644 index 0000000000..4128a11817 --- /dev/null +++ b/tests/core/pyspec/eth2spec/test/eip6110/block_processing/test_process_voluntary_exit.py @@ -0,0 +1,44 @@ +from eth2spec.test.context import ( + always_bls, + spec_state_test, + with_eip6110_and_later, +) +from eth2spec.test.bellatrix.block_processing.test_process_voluntary_exit import ( + run_voluntary_exit_processing_test, +) + + +@with_eip6110_and_later +@spec_state_test +@always_bls +def test_invalid_voluntary_exit_with_previous_fork_version_not_is_before_fork_epoch(spec, state): + """ + Since Deneb, the VoluntaryExit domain is fixed to `CAPELLA_FORK_VERSION` + """ + assert state.fork.previous_version != state.fork.current_version + + yield from run_voluntary_exit_processing_test( + spec, + state, + fork_version=state.fork.previous_version, + is_before_fork_epoch=False, + valid=False, + ) + + +@with_eip6110_and_later +@spec_state_test +@always_bls +def test_invalid_voluntary_exit_with_previous_fork_version_is_before_fork_epoch(spec, state): + """ + Since Deneb, the VoluntaryExit domain is fixed to `CAPELLA_FORK_VERSION` + """ + assert state.fork.previous_version != state.fork.current_version + + yield from run_voluntary_exit_processing_test( + spec, + state, + fork_version=state.fork.previous_version, + is_before_fork_epoch=True, + valid=False, + ) diff --git a/tests/core/pyspec/eth2spec/test/helpers/voluntary_exits.py b/tests/core/pyspec/eth2spec/test/helpers/voluntary_exits.py index cac101dff1..2e8139db64 100644 --- a/tests/core/pyspec/eth2spec/test/helpers/voluntary_exits.py +++ b/tests/core/pyspec/eth2spec/test/helpers/voluntary_exits.py @@ -1,29 +1,31 @@ from random import Random from eth2spec.utils import bls from eth2spec.test.context import expect_assertion_error +from eth2spec.test.helpers.forks import is_post_deneb from eth2spec.test.helpers.keys import privkeys def prepare_signed_exits(spec, state, indices, fork_version=None): - if fork_version is None: - domain = spec.get_domain(state, spec.DOMAIN_VOLUNTARY_EXIT) - else: - domain = spec.compute_domain(spec.DOMAIN_VOLUNTARY_EXIT, fork_version, state.genesis_validators_root) - def create_signed_exit(index): - exit = spec.VoluntaryExit( + voluntary_exit = spec.VoluntaryExit( epoch=spec.get_current_epoch(state), validator_index=index, ) - signing_root = spec.compute_signing_root(exit, domain) - return spec.SignedVoluntaryExit(message=exit, signature=bls.Sign(privkeys[index], signing_root)) + return sign_voluntary_exit(spec, state, voluntary_exit, privkeys[index], fork_version=fork_version) return [create_signed_exit(index) for index in indices] def sign_voluntary_exit(spec, state, voluntary_exit, privkey, fork_version=None): if fork_version is None: - domain = spec.get_domain(state, spec.DOMAIN_VOLUNTARY_EXIT, voluntary_exit.epoch) + if is_post_deneb(spec): + domain = spec.compute_domain( + spec.DOMAIN_VOLUNTARY_EXIT, + spec.config.CAPELLA_FORK_VERSION, + state.genesis_validators_root, + ) + else: + domain = spec.get_domain(state, spec.DOMAIN_VOLUNTARY_EXIT, voluntary_exit.epoch) else: domain = spec.compute_domain(spec.DOMAIN_VOLUNTARY_EXIT, fork_version, state.genesis_validators_root) diff --git a/tests/generators/operations/main.py b/tests/generators/operations/main.py index fc22179176..2cff8bdf66 100644 --- a/tests/generators/operations/main.py +++ b/tests/generators/operations/main.py @@ -36,10 +36,14 @@ ]} capella_mods = combine_mods(_new_capella_mods, bellatrix_mods) - deneb_mods = capella_mods + _new_deneb_mods = {key: 'eth2spec.test.deneb.block_processing.test_process_' + key for key in [ + 'voluntary_exit', + ]} + deneb_mods = combine_mods(_new_deneb_mods, capella_mods) _new_eip6110_mods = {key: 'eth2spec.test.eip6110.block_processing.test_process_' + key for key in [ 'deposit_receipt', + 'voluntary_exit', ]} eip6110_mods = combine_mods(_new_eip6110_mods, deneb_mods) From fa4a10371237ad39e167961cb2bb4a3747a539fb Mon Sep 17 00:00:00 2001 From: Danny Ryan Date: Mon, 22 May 2023 08:07:43 -0600 Subject: [PATCH 18/44] Apply suggestions from code review Co-authored-by: Hsiao-Wei Wang --- specs/_features/eip7045/fork.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/specs/_features/eip7045/fork.md b/specs/_features/eip7045/fork.md index 42b14b1704..152d09f62a 100644 --- a/specs/_features/eip7045/fork.md +++ b/specs/_features/eip7045/fork.md @@ -66,7 +66,7 @@ Note that for the pure EIP7045 networks, we don't apply `upgrade_to_eip7045` sin ### Upgrading the state -If `state.slot % SLOTS_PER_EPOCH == 0` and `compute_epoch_at_slot(state.slot) == EIP7045_FORK_EPOCH, +If `state.slot % SLOTS_PER_EPOCH == 0` and `compute_epoch_at_slot(state.slot) == EIP7045_FORK_EPOCH`, an irregular state change is made to upgrade to EIP7045. ```python From 653e03e70223335d270940cc81640ff875080c7d Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Tue, 30 May 2023 21:12:47 +0800 Subject: [PATCH 19/44] Fix ToC --- specs/deneb/beacon-chain.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/specs/deneb/beacon-chain.md b/specs/deneb/beacon-chain.md index a929db8598..335723626c 100644 --- a/specs/deneb/beacon-chain.md +++ b/specs/deneb/beacon-chain.md @@ -33,8 +33,8 @@ - [Modified `verify_and_notify_new_payload`](#modified-verify_and_notify_new_payload) - [Block processing](#block-processing) - [Execution payload](#execution-payload) - - [`process_execution_payload`](#process_execution_payload) - - [Modified `process_voluntary_exit`](#modified-process_voluntary_exit) + - [Modified `process_execution_payload`](#modified-process_execution_payload) + - [Modified `process_voluntary_exit`](#modified-process_voluntary_exit) - [Testing](#testing) @@ -218,7 +218,7 @@ def verify_and_notify_new_payload(self: ExecutionEngine, #### Execution payload -##### `process_execution_payload` +##### Modified `process_execution_payload` ```python def process_execution_payload(state: BeaconState, body: BeaconBlockBody, execution_engine: ExecutionEngine) -> None: @@ -262,7 +262,7 @@ def process_execution_payload(state: BeaconState, body: BeaconBlockBody, executi ) ``` -##### Modified `process_voluntary_exit` +#### Modified `process_voluntary_exit` ```python def process_voluntary_exit(state: BeaconState, signed_voluntary_exit: SignedVoluntaryExit) -> None: From bab93e8d44b27ccf41a0ddc4993eaae95b144939 Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Wed, 7 Jun 2023 18:40:02 +0800 Subject: [PATCH 20/44] specially mark EIP7044 changes --- specs/deneb/beacon-chain.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/specs/deneb/beacon-chain.md b/specs/deneb/beacon-chain.md index ccf0d6933e..7ce8bb1e7e 100644 --- a/specs/deneb/beacon-chain.md +++ b/specs/deneb/beacon-chain.md @@ -282,7 +282,7 @@ def process_voluntary_exit(state: BeaconState, signed_voluntary_exit: SignedVolu # Verify the validator has been active long enough assert get_current_epoch(state) >= validator.activation_epoch + SHARD_COMMITTEE_PERIOD # Verify signature - # [Modified in Deneb] + # [Modified in Deneb:EIP7044] domain = compute_domain(DOMAIN_VOLUNTARY_EXIT, CAPELLA_FORK_VERSION, state.genesis_validators_root) signing_root = compute_signing_root(voluntary_exit, domain) assert bls.Verify(validator.pubkey, signing_root, signed_voluntary_exit.signature) From 99f294cdd8a2d4461576eacaabbf4dc7ad60169c Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Mon, 12 Jun 2023 16:02:28 +0800 Subject: [PATCH 21/44] Add link to EIP PR7044. Need to change it to eips.ethereum.org path once the EIP is merged --- specs/deneb/beacon-chain.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/specs/deneb/beacon-chain.md b/specs/deneb/beacon-chain.md index e257512320..929ac39f6f 100644 --- a/specs/deneb/beacon-chain.md +++ b/specs/deneb/beacon-chain.md @@ -43,7 +43,8 @@ ## Introduction 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-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 ## Custom types From 530924020f84198675268830f54a879c21784d24 Mon Sep 17 00:00:00 2001 From: dapplion <35266934+dapplion@users.noreply.github.com> Date: Wed, 14 Jun 2023 15:29:59 +0300 Subject: [PATCH 22/44] Lock doctoc version --- .circleci/config.yml | 2 +- .github/workflows/run-tests.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index fcdf483d50..157c56ca5f 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -176,7 +176,7 @@ jobs: - checkout - run: name: Check table of contents - command: sudo npm install -g doctoc@2 && make check_toc + command: sudo npm install -g doctoc@2.2.0 && make check_toc codespell: docker: - image: circleci/python:3.9 diff --git a/.github/workflows/run-tests.yml b/.github/workflows/run-tests.yml index 41a80ab925..b27c907654 100644 --- a/.github/workflows/run-tests.yml +++ b/.github/workflows/run-tests.yml @@ -50,7 +50,7 @@ jobs: with: ref: ${{ github.event.inputs.commitRef || env.DEFAULT_BRANCH }} - name: Check table of contents - run: sudo npm install -g doctoc@2 && make check_toc + run: sudo npm install -g doctoc@2.2.0 && make check_toc codespell: runs-on: self-hosted From 12fabf5854622cec2b01cf652a9277534ea6c59a Mon Sep 17 00:00:00 2001 From: Lion - dapplion <35266934+dapplion@users.noreply.github.com> Date: Wed, 14 Jun 2023 16:47:17 +0300 Subject: [PATCH 23/44] Update specs/deneb/beacon-chain.md Co-authored-by: Danny Ryan --- specs/deneb/beacon-chain.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/specs/deneb/beacon-chain.md b/specs/deneb/beacon-chain.md index 929ac39f6f..0d71e4ae72 100644 --- a/specs/deneb/beacon-chain.md +++ b/specs/deneb/beacon-chain.md @@ -270,6 +270,8 @@ def process_execution_payload(state: BeaconState, body: BeaconBlockBody, executi #### Modified `process_voluntary_exit` +Note: The function `process_voluntary_exit` is modified to use the a fixed fork version -- `CAPELLA_FORK_VERSION` -- for EIP-7044 + ```python def process_voluntary_exit(state: BeaconState, signed_voluntary_exit: SignedVoluntaryExit) -> None: voluntary_exit = signed_voluntary_exit.message From 420f8baf6777cbf35e63ffe4ceb9029b168f65ad Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Wed, 14 Jun 2023 23:04:46 +0800 Subject: [PATCH 24/44] Rework tests. Move all `process_voluntary_exit` tests to Deneb --- specs/deneb/beacon-chain.md | 2 +- .../test_process_voluntary_exit.py | 3 +- .../test_process_voluntary_exit.py | 54 ++++++++++++++++--- .../test_process_voluntary_exit.py | 44 --------------- tests/generators/operations/main.py | 1 - 5 files changed, 49 insertions(+), 55 deletions(-) delete mode 100644 tests/core/pyspec/eth2spec/test/eip6110/block_processing/test_process_voluntary_exit.py diff --git a/specs/deneb/beacon-chain.md b/specs/deneb/beacon-chain.md index 0d71e4ae72..3189ee1906 100644 --- a/specs/deneb/beacon-chain.md +++ b/specs/deneb/beacon-chain.md @@ -270,7 +270,7 @@ def process_execution_payload(state: BeaconState, body: BeaconBlockBody, executi #### Modified `process_voluntary_exit` -Note: The function `process_voluntary_exit` is modified to use the a fixed fork version -- `CAPELLA_FORK_VERSION` -- for EIP-7044 +*Note*: The function `process_voluntary_exit` is modified to use the a fixed fork version -- `CAPELLA_FORK_VERSION` -- for EIP-7044 ```python def process_voluntary_exit(state: BeaconState, signed_voluntary_exit: SignedVoluntaryExit) -> None: diff --git a/tests/core/pyspec/eth2spec/test/bellatrix/block_processing/test_process_voluntary_exit.py b/tests/core/pyspec/eth2spec/test/bellatrix/block_processing/test_process_voluntary_exit.py index 12b554da5b..ea3b57a97a 100644 --- a/tests/core/pyspec/eth2spec/test/bellatrix/block_processing/test_process_voluntary_exit.py +++ b/tests/core/pyspec/eth2spec/test/bellatrix/block_processing/test_process_voluntary_exit.py @@ -7,7 +7,6 @@ from eth2spec.test.helpers.constants import ( BELLATRIX, CAPELLA, - DENEB, ) from eth2spec.test.helpers.keys import pubkey_to_privkey from eth2spec.test.helpers.state import ( @@ -80,7 +79,7 @@ def test_voluntary_exit_with_current_fork_version_not_is_before_fork_epoch(spec, ) -@with_phases([BELLATRIX, CAPELLA, DENEB]) +@with_phases([BELLATRIX, CAPELLA]) @spec_state_test @always_bls def test_voluntary_exit_with_previous_fork_version_is_before_fork_epoch(spec, state): diff --git a/tests/core/pyspec/eth2spec/test/deneb/block_processing/test_process_voluntary_exit.py b/tests/core/pyspec/eth2spec/test/deneb/block_processing/test_process_voluntary_exit.py index 371fcfed42..06a111c86a 100644 --- a/tests/core/pyspec/eth2spec/test/deneb/block_processing/test_process_voluntary_exit.py +++ b/tests/core/pyspec/eth2spec/test/deneb/block_processing/test_process_voluntary_exit.py @@ -19,6 +19,7 @@ def test_invalid_voluntary_exit_with_current_fork_version_not_is_before_fork_epo """ Since Deneb, the VoluntaryExit domain is fixed to `CAPELLA_FORK_VERSION` """ + assert state.fork.current_version != spec.config.CAPELLA_FORK_VERSION yield from run_voluntary_exit_processing_test( spec, state, @@ -28,7 +29,7 @@ def test_invalid_voluntary_exit_with_current_fork_version_not_is_before_fork_epo ) -@with_phases([DENEB]) +@with_deneb_and_later @spec_state_test @always_bls def test_voluntary_exit_with_previous_fork_version_not_is_before_fork_epoch(spec, state): @@ -37,9 +38,48 @@ def test_voluntary_exit_with_previous_fork_version_not_is_before_fork_epoch(spec """ assert state.fork.previous_version != state.fork.current_version - yield from run_voluntary_exit_processing_test( - spec, - state, - fork_version=state.fork.previous_version, - is_before_fork_epoch=False, - ) + if spec.fork == DENEB: + assert state.fork.previous_version == spec.config.CAPELLA_FORK_VERSION + yield from run_voluntary_exit_processing_test( + spec, + state, + fork_version=state.fork.previous_version, + is_before_fork_epoch=False, + ) + else: + assert state.fork.previous_version != spec.config.CAPELLA_FORK_VERSION + yield from run_voluntary_exit_processing_test( + spec, + state, + fork_version=state.fork.previous_version, + is_before_fork_epoch=False, + valid=False, + ) + + +@with_deneb_and_later +@spec_state_test +@always_bls +def test_voluntary_exit_with_previous_fork_version_is_before_fork_epoch(spec, state): + """ + Since Deneb, the VoluntaryExit domain is fixed to `CAPELLA_FORK_VERSION` + """ + assert state.fork.previous_version != state.fork.current_version + + if spec.fork == DENEB: + assert state.fork.previous_version == spec.config.CAPELLA_FORK_VERSION + yield from run_voluntary_exit_processing_test( + spec, + state, + fork_version=state.fork.previous_version, + is_before_fork_epoch=True, + ) + else: + assert state.fork.previous_version != spec.config.CAPELLA_FORK_VERSION + yield from run_voluntary_exit_processing_test( + spec, + state, + fork_version=state.fork.previous_version, + is_before_fork_epoch=True, + valid=False, + ) diff --git a/tests/core/pyspec/eth2spec/test/eip6110/block_processing/test_process_voluntary_exit.py b/tests/core/pyspec/eth2spec/test/eip6110/block_processing/test_process_voluntary_exit.py deleted file mode 100644 index 4128a11817..0000000000 --- a/tests/core/pyspec/eth2spec/test/eip6110/block_processing/test_process_voluntary_exit.py +++ /dev/null @@ -1,44 +0,0 @@ -from eth2spec.test.context import ( - always_bls, - spec_state_test, - with_eip6110_and_later, -) -from eth2spec.test.bellatrix.block_processing.test_process_voluntary_exit import ( - run_voluntary_exit_processing_test, -) - - -@with_eip6110_and_later -@spec_state_test -@always_bls -def test_invalid_voluntary_exit_with_previous_fork_version_not_is_before_fork_epoch(spec, state): - """ - Since Deneb, the VoluntaryExit domain is fixed to `CAPELLA_FORK_VERSION` - """ - assert state.fork.previous_version != state.fork.current_version - - yield from run_voluntary_exit_processing_test( - spec, - state, - fork_version=state.fork.previous_version, - is_before_fork_epoch=False, - valid=False, - ) - - -@with_eip6110_and_later -@spec_state_test -@always_bls -def test_invalid_voluntary_exit_with_previous_fork_version_is_before_fork_epoch(spec, state): - """ - Since Deneb, the VoluntaryExit domain is fixed to `CAPELLA_FORK_VERSION` - """ - assert state.fork.previous_version != state.fork.current_version - - yield from run_voluntary_exit_processing_test( - spec, - state, - fork_version=state.fork.previous_version, - is_before_fork_epoch=True, - valid=False, - ) diff --git a/tests/generators/operations/main.py b/tests/generators/operations/main.py index 3b4e5d1f75..053236c8d7 100644 --- a/tests/generators/operations/main.py +++ b/tests/generators/operations/main.py @@ -45,7 +45,6 @@ _new_eip6110_mods = {key: 'eth2spec.test.eip6110.block_processing.test_process_' + key for key in [ 'deposit_receipt', - 'voluntary_exit', ]} eip6110_mods = combine_mods(_new_eip6110_mods, deneb_mods) From 11ab19c90a6228a696dea3df27b8834674fef348 Mon Sep 17 00:00:00 2001 From: Danny Ryan Date: Wed, 14 Jun 2023 09:25:54 -0600 Subject: [PATCH 25/44] Apply suggestions from code review --- .../deneb/block_processing/test_process_voluntary_exit.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/core/pyspec/eth2spec/test/deneb/block_processing/test_process_voluntary_exit.py b/tests/core/pyspec/eth2spec/test/deneb/block_processing/test_process_voluntary_exit.py index 06a111c86a..711d27eb92 100644 --- a/tests/core/pyspec/eth2spec/test/deneb/block_processing/test_process_voluntary_exit.py +++ b/tests/core/pyspec/eth2spec/test/deneb/block_processing/test_process_voluntary_exit.py @@ -35,6 +35,8 @@ def test_invalid_voluntary_exit_with_current_fork_version_not_is_before_fork_epo def test_voluntary_exit_with_previous_fork_version_not_is_before_fork_epoch(spec, state): """ Since Deneb, the VoluntaryExit domain is fixed to `CAPELLA_FORK_VERSION` + + Note: This test is valid for ``spec.fork == DENEB`` and invalid for subsequent forks """ assert state.fork.previous_version != state.fork.current_version @@ -63,6 +65,8 @@ def test_voluntary_exit_with_previous_fork_version_not_is_before_fork_epoch(spec def test_voluntary_exit_with_previous_fork_version_is_before_fork_epoch(spec, state): """ Since Deneb, the VoluntaryExit domain is fixed to `CAPELLA_FORK_VERSION` + + Note: This test is valid for ``spec.fork == DENEB`` and invalid for subsequent forks """ assert state.fork.previous_version != state.fork.current_version From 7b132c20d1d4347df9bb262753be81407c410279 Mon Sep 17 00:00:00 2001 From: Lion - dapplion <35266934+dapplion@users.noreply.github.com> Date: Wed, 14 Jun 2023 18:52:22 +0300 Subject: [PATCH 26/44] Fix typos in get_shuffle_indices (#3426) --- specs/_features/whisk/beacon-chain.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/specs/_features/whisk/beacon-chain.md b/specs/_features/whisk/beacon-chain.md index bad8188378..6c8db4cec4 100644 --- a/specs/_features/whisk/beacon-chain.md +++ b/specs/_features/whisk/beacon-chain.md @@ -306,9 +306,10 @@ def get_shuffle_indices(randao_reveal: BLSSignature) -> Sequence[uint64]: Given a `randao_reveal` return the list of indices that got shuffled from the entire candidate set """ indices = [] - for i in WHISK_VALIDATORS_PER_SHUFFLE: + for i in range(0, WHISK_VALIDATORS_PER_SHUFFLE): # XXX ensure we are not suffering from modulo bias - shuffle_index = uint256(hash(randao_reveal + uint_to_bytes(i))) % WHISK_CANDIDATE_TRACKERS_COUNT + pre_image = randao_reveal + uint_to_bytes(uint64(i)) + shuffle_index = bytes_to_uint64(hash(pre_image)[0:8]) % WHISK_CANDIDATE_TRACKERS_COUNT indices.append(shuffle_index) return indices From 0ab160bc2801be1ecb5ca2f65a2202f632b75bf5 Mon Sep 17 00:00:00 2001 From: Lion - dapplion <35266934+dapplion@users.noreply.github.com> Date: Wed, 14 Jun 2023 18:55:07 +0300 Subject: [PATCH 27/44] Add initialize_beacon_state_from_eth1 (#3428) --- configs/mainnet.yaml | 3 +++ configs/minimal.yaml | 3 +++ specs/_features/whisk/beacon-chain.md | 23 +++++++++++++++++++++++ 3 files changed, 29 insertions(+) diff --git a/configs/mainnet.yaml b/configs/mainnet.yaml index 365bc11367..9206ab77da 100644 --- a/configs/mainnet.yaml +++ b/configs/mainnet.yaml @@ -53,6 +53,9 @@ DENEB_FORK_EPOCH: 18446744073709551615 # EIP6110 EIP6110_FORK_VERSION: 0x05000000 # temporary stub EIP6110_FORK_EPOCH: 18446744073709551615 +# WHISK +WHISK_FORK_VERSION: 0x06000000 # temporary stub +WHISK_FORK_EPOCH: 18446744073709551615 # Time parameters diff --git a/configs/minimal.yaml b/configs/minimal.yaml index b22a7165e1..256a39d1c1 100644 --- a/configs/minimal.yaml +++ b/configs/minimal.yaml @@ -52,6 +52,9 @@ DENEB_FORK_EPOCH: 18446744073709551615 # EIP6110 EIP6110_FORK_VERSION: 0x05000001 EIP6110_FORK_EPOCH: 18446744073709551615 +# WHISK +WHISK_FORK_VERSION: 0x06000001 +WHISK_FORK_EPOCH: 18446744073709551615 # Time parameters diff --git a/specs/_features/whisk/beacon-chain.md b/specs/_features/whisk/beacon-chain.md index 6c8db4cec4..c8adf945da 100644 --- a/specs/_features/whisk/beacon-chain.md +++ b/specs/_features/whisk/beacon-chain.md @@ -23,6 +23,7 @@ - [`BeaconBlockBody`](#beaconblockbody) - [Deposits](#deposits) - [`get_beacon_proposer_index`](#get_beacon_proposer_index) +- [Testing](#testing) @@ -470,3 +471,25 @@ def get_beacon_proposer_index(state: BeaconState) -> ValidatorIndex: assert state.latest_block_header.slot == state.slot # sanity check `process_block_header` has been called return state.latest_block_header.proposer_index ``` + +## Testing + +*Note*: The function `initialize_beacon_state_from_eth1` is modified for pure Whisk testing only. + +```python +def initialize_beacon_state_from_eth1(eth1_block_hash: Hash32, + eth1_timestamp: uint64, + deposits: Sequence[Deposit], + execution_payload_header: ExecutionPayloadHeader=ExecutionPayloadHeader() + ) -> BeaconState: + state_capella = capella.initialize_beacon_state_from_eth1( + eth1_block_hash, + eth1_timestamp, + deposits, + execution_payload_header, + ) + state = upgrade_to_whisk(state_capella) + state.fork.previous_version = WHISK_FORK_VERSION + state.fork.current_version = WHISK_FORK_VERSION + return state +``` From 65a28b6d69a85135a8b9907b53d40f2f0182cb32 Mon Sep 17 00:00:00 2001 From: Lion - dapplion <35266934+dapplion@users.noreply.github.com> Date: Wed, 14 Jun 2023 18:58:57 +0300 Subject: [PATCH 28/44] Whisk: Move validator whisk trackers and commitments to state (#3407) * Move validator whisk trackers and commitments to state * Move comment --- specs/_features/whisk/beacon-chain.md | 77 ++++++++------------------- specs/_features/whisk/fork.md | 35 ++++++------ 2 files changed, 39 insertions(+), 73 deletions(-) diff --git a/specs/_features/whisk/beacon-chain.md b/specs/_features/whisk/beacon-chain.md index c8adf945da..34e79c1e44 100644 --- a/specs/_features/whisk/beacon-chain.md +++ b/specs/_features/whisk/beacon-chain.md @@ -15,7 +15,6 @@ - [Curdleproofs and opening proofs](#curdleproofs-and-opening-proofs) - [Epoch processing](#epoch-processing) - [`WhiskTracker`](#whisktracker) - - [`Validator`](#validator) - [`BeaconState`](#beaconstate) - [Block processing](#block-processing) - [Block header](#block-header) @@ -125,23 +124,6 @@ class WhiskTracker(Container): k_r_G: BLSG1Point # k * r * G ``` -### `Validator` - -```python -class Validator(Container): - pubkey: BLSPubkey - withdrawal_credentials: Bytes32 # Commitment to pubkey for withdrawals - effective_balance: Gwei # Balance at stake - slashed: boolean - # Status epochs - activation_eligibility_epoch: Epoch # When criteria for activation were met - activation_epoch: Epoch - exit_epoch: Epoch - withdrawable_epoch: Epoch # When validator can withdraw funds - whisk_tracker: WhiskTracker # Whisk tracker (r * G, k * r * G) [New in Whisk] - whisk_k_commitment: BLSG1Point # Whisk k commitment k * BLS_G1_GENERATOR [New in Whisk] -``` - ### `BeaconState` ```python @@ -187,8 +169,11 @@ class BeaconState(Container): next_withdrawal_validator_index: ValidatorIndex # Deep history valid from Capella onwards historical_summaries: List[HistoricalSummary, HISTORICAL_ROOTS_LIMIT] + # Whisk whisk_candidate_trackers: Vector[WhiskTracker, WHISK_CANDIDATE_TRACKERS_COUNT] # [New in Whisk] whisk_proposer_trackers: Vector[WhiskTracker, WHISK_PROPOSER_TRACKERS_COUNT] # [New in Whisk] + whisk_trackers: List[WhiskTracker, VALIDATOR_REGISTRY_LIMIT] # [New in Whisk] + whisk_k_commitments: List[BLSG1Point, VALIDATOR_REGISTRY_LIMIT] # [New in Whisk] ``` ```python @@ -204,7 +189,7 @@ def select_whisk_trackers(state: BeaconState, epoch: Epoch) -> None: for i in range(WHISK_CANDIDATE_TRACKERS_COUNT): seed = hash(get_seed(state, epoch, DOMAIN_WHISK_CANDIDATE_SELECTION) + uint_to_bytes(i)) candidate_index = compute_proposer_index(state, active_validator_indices, seed) # sample by effective balance - state.whisk_candidate_trackers[i] = state.validators[candidate_index].whisk_tracker + state.whisk_candidate_trackers[i] = state.whisk_trackers[candidate_index] ``` ```python @@ -238,7 +223,7 @@ def process_epoch(state: BeaconState) -> None: ```python def process_whisk_opening_proof(state: BeaconState, block: BeaconBlock) -> None: tracker = state.whisk_proposer_trackers[state.slot % WHISK_PROPOSER_TRACKERS_COUNT] - k_commitment = state.validators[block.proposer_index].whisk_k_commitment + k_commitment = state.whisk_k_commitments[block.proposer_index] assert IsValidWhiskOpeningProof(tracker, k_commitment, block.body.whisk_opening_proof) ``` @@ -298,7 +283,7 @@ class BeaconBlockBody(capella.BeaconBlockBody): whisk_shuffle_proof_M_commitment: BLSG1Point # [New in Whisk] whisk_registration_proof: WhiskTrackerProof # [New in Whisk] whisk_tracker: WhiskTracker # [New in Whisk] - whisk_k_commitment: BLSG1Point # [New in Whisk] + whisk_k_commitment: BLSG1Point # k * BLS_G1_GENERATOR [New in Whisk] ``` ```python @@ -343,7 +328,7 @@ def process_shuffled_trackers(state: BeaconState, body: BeaconBlockBody) -> None ```python def is_k_commitment_unique(state: BeaconState, k_commitment: BLSG1Point) -> bool: - return all([validator.whisk_k_commitment != k_commitment for validator in state.validators]) + return all([whisk_k_commitment != k_commitment for whisk_k_commitment in state.whisk_k_commitments]) ``` ```python @@ -384,49 +369,30 @@ def process_block(state: BeaconState, block: BeaconBlock) -> None: ### Deposits +```python +def get_initial_whisk_k(validator_index: ValidatorIndex, counter: int) -> BLSFieldElement: + # hash `validator_index || counter` + return BLSFieldElement(bytes_to_bls_field(hash(uint_to_bytes(validator_index) + uint_to_bytes(uint64(counter))))) +``` + ```python def get_unique_whisk_k(state: BeaconState, validator_index: ValidatorIndex) -> BLSFieldElement: counter = 0 while True: - # hash `validator_index || counter` - k = BLSFieldElement(bytes_to_bls_field(hash(uint_to_bytes(validator_index) + uint_to_bytes(uint64(counter))))) + k = get_initial_whisk_k(validator_index, counter) if is_k_commitment_unique(state, BLSG1ScalarMultiply(k, BLS_G1_GENERATOR)): return k # unique by trial and error counter += 1 ``` ```python -def get_initial_commitments(k: BLSFieldElement) -> Tuple[BLSG1Point, WhiskTracker]: - return ( - BLSG1ScalarMultiply(k, BLS_G1_GENERATOR), - WhiskTracker(r_G=BLS_G1_GENERATOR, k_r_G=BLSG1ScalarMultiply(k, BLS_G1_GENERATOR)) - ) +def get_k_commitment(k: BLSFieldElement) -> BLSG1Point: + return BLSG1ScalarMultiply(k, BLS_G1_GENERATOR) ``` ```python -def get_validator_from_deposit_whisk( - state: BeaconState, - pubkey: BLSPubkey, - withdrawal_credentials: Bytes32, - amount: uint64 -) -> Validator: - effective_balance = min(amount - amount % EFFECTIVE_BALANCE_INCREMENT, MAX_EFFECTIVE_BALANCE) - k = get_unique_whisk_k(state, ValidatorIndex(len(state.validators))) - whisk_k_commitment, whisk_tracker = get_initial_commitments(k) - - validator = Validator( - pubkey=pubkey, - withdrawal_credentials=withdrawal_credentials, - activation_eligibility_epoch=FAR_FUTURE_EPOCH, - activation_epoch=FAR_FUTURE_EPOCH, - exit_epoch=FAR_FUTURE_EPOCH, - withdrawable_epoch=FAR_FUTURE_EPOCH, - effective_balance=effective_balance, - # Whisk fields - whisk_tracker=whisk_tracker, - whisk_k_commitment=whisk_k_commitment, - ) - return validator +def get_initial_tracker(k: BLSFieldElement) -> WhiskTracker: + return WhiskTracker(r_G=BLS_G1_GENERATOR, k_r_G=BLSG1ScalarMultiply(k, BLS_G1_GENERATOR)) ``` ```python @@ -448,13 +414,16 @@ def apply_deposit(state: BeaconState, # Initialize validator if the deposit signature is valid if bls.Verify(pubkey, signing_root, signature): index = get_index_for_new_validator(state) - validator = get_validator_from_deposit_whisk(state, pubkey, withdrawal_credentials, amount) + validator = get_validator_from_deposit(pubkey, withdrawal_credentials, amount) set_or_append_list(state.validators, index, validator) set_or_append_list(state.balances, index, amount) - # [New in Altair] set_or_append_list(state.previous_epoch_participation, index, ParticipationFlags(0b0000_0000)) set_or_append_list(state.current_epoch_participation, index, ParticipationFlags(0b0000_0000)) set_or_append_list(state.inactivity_scores, index, uint64(0)) + # [New in Whisk] + k = get_unique_whisk_k(state, ValidatorIndex(len(state.validators) - 1)) + state.whisk_trackers.append(get_initial_tracker(k)) + state.whisk_k_commitments.append(get_k_commitment(k)) else: # Increase balance by deposit amount index = ValidatorIndex(validator_pubkeys.index(pubkey)) diff --git a/specs/_features/whisk/fork.md b/specs/_features/whisk/fork.md index 189d8c5b32..f66026037f 100644 --- a/specs/_features/whisk/fork.md +++ b/specs/_features/whisk/fork.md @@ -68,6 +68,11 @@ def whisk_proposer_selection(state: BeaconState, epoch: Epoch) -> None: ```python def upgrade_to_whisk(pre: bellatrix.BeaconState) -> BeaconState: + # Compute initial unsafe trackers for all validators + ks = [get_initial_whisk_k(ValidatorIndex(validator_index), 0) for validator_index in range(len(pre.validators))] + whisk_k_commitments = [get_k_commitment(k) for k in ks] + whisk_trackers = [get_initial_tracker(k) for k in ks] + epoch = bellatrix.get_current_epoch(pre) post = BeaconState( # Versioning @@ -104,27 +109,19 @@ def upgrade_to_whisk(pre: bellatrix.BeaconState) -> BeaconState: current_justified_checkpoint=pre.current_justified_checkpoint, finalized_checkpoint=pre.finalized_checkpoint, # Inactivity - inactivity_scores=pre.inactivity_Scores, + 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=pre.latest_execution_payload_header, + # Whisk + whisk_proposer_trackers=[WhiskTracker() for _ in range(WHISK_PROPOSER_TRACKERS_COUNT)], # [New in Whisk] + whisk_candidate_trackers=[WhiskTracker() for _ in range(WHISK_CANDIDATE_TRACKERS_COUNT)], # [New in Whisk] + whisk_trackers=whisk_trackers, # [New in Whisk] + whisk_k_commitments=whisk_k_commitments, # [New in Whisk] ) - # Initialize all validators with predictable commitments - for val_index, pre_validator in enumerate(pre.validators): - whisk_commitment, whisk_tracker = get_initial_commitments(get_unique_whisk_k(post, ValidatorIndex(val_index))) - - post_validator = Validator( - pubkey=pre_validator.pubkey, - withdrawal_credentials=pre_validator.withdrawal_credentials, - effective_balance=pre_validator.effective_balance, - slashed=pre_validator.slashed, - activation_eligibility_epoch=pre_validator.activation_eligibility_epoch, - activation_epoch=pre_validator.activation_epoch, - exit_epoch=pre_validator.exit_epoch, - withdrawable_epoch=pre_validator.withdrawable_epoch, - whisk_commitment=whisk_commitment, - whisk_tracker=whisk_tracker, - ) - post.validators.append(post_validator) - # Do a candidate selection followed by a proposer selection so that we have proposers for the upcoming day # Use an old epoch when selecting candidates so that we don't get the same seed as in the next candidate selection whisk_candidate_selection(post, epoch - WHISK_PROPOSER_SELECTION_GAP - 1) From 9e50c74a372c0d8349764ef411b22cfa71f2a656 Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Thu, 15 Jun 2023 00:45:43 +0800 Subject: [PATCH 29/44] Fix linter (#3430) --- .../test/deneb/block_processing/test_process_voluntary_exit.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/core/pyspec/eth2spec/test/deneb/block_processing/test_process_voluntary_exit.py b/tests/core/pyspec/eth2spec/test/deneb/block_processing/test_process_voluntary_exit.py index 711d27eb92..b01eaab0e1 100644 --- a/tests/core/pyspec/eth2spec/test/deneb/block_processing/test_process_voluntary_exit.py +++ b/tests/core/pyspec/eth2spec/test/deneb/block_processing/test_process_voluntary_exit.py @@ -1,7 +1,6 @@ from eth2spec.test.context import ( always_bls, spec_state_test, - with_phases, with_deneb_and_later, ) from eth2spec.test.helpers.constants import ( From ec4bdae2d449b3ac5769be24a4be4ad26bbe3fea Mon Sep 17 00:00:00 2001 From: djrtwo Date: Wed, 14 Jun 2023 10:51:10 -0600 Subject: [PATCH 30/44] build EIP 7045 into Deneb fork --- .circleci/config.yml | 17 -- Makefile | 2 +- configs/mainnet.yaml | 3 - configs/minimal.yaml | 5 - setup.py | 16 +- specs/_features/eip7045/beacon-chain.md | 167 ------------------ specs/_features/eip7045/fork.md | 123 ------------- specs/_features/eip7045/p2p-interface.md | 72 -------- specs/deneb/beacon-chain.md | 81 ++++++++- specs/deneb/fork.md | 2 +- specs/deneb/p2p-interface.md | 48 ++++- specs/phase0/p2p-interface.md | 2 +- tests/core/pyspec/eth2spec/test/context.py | 8 +- .../test_process_voluntary_exit.py | 1 - .../eth2spec/test/helpers/attestations.py | 4 +- .../pyspec/eth2spec/test/helpers/constants.py | 3 +- .../eth2spec/test/helpers/fork_transition.py | 6 - .../pyspec/eth2spec/test/helpers/forks.py | 8 +- .../pyspec/eth2spec/test/helpers/genesis.py | 5 +- 19 files changed, 136 insertions(+), 437 deletions(-) delete mode 100644 specs/_features/eip7045/beacon-chain.md delete mode 100644 specs/_features/eip7045/fork.md delete mode 100644 specs/_features/eip7045/p2p-interface.md diff --git a/.circleci/config.yml b/.circleci/config.yml index 966eec4c3d..157c56ca5f 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -168,20 +168,6 @@ jobs: command: make citest fork=eip6110 - store_test_results: path: tests/core/pyspec/test-reports - test-eip7045: - docker: - - image: circleci/python:3.8 - working_directory: ~/specs-repo - steps: - - restore_cache: - key: v3-specs-repo-{{ .Branch }}-{{ .Revision }} - - restore_pyspec_cached_venv - - run: - name: Run py-tests - command: make citest fork=eip7045 - - store_test_results: - path: tests/core/pyspec/test-reports - table_of_contents: docker: - image: circleci/node:10.16.3 @@ -305,9 +291,6 @@ workflows: - test-eip6110: requires: - install_pyspec_test - - test-eip7045: - requires: - - install_pyspec_test - table_of_contents - codespell - lint: diff --git a/Makefile b/Makefile index 0dd091e32c..6c852a1e94 100644 --- a/Makefile +++ b/Makefile @@ -34,7 +34,7 @@ MARKDOWN_FILES = $(wildcard $(SPEC_DIR)/*/*.md) \ $(wildcard $(SPEC_DIR)/_features/*/*/*.md) \ $(wildcard $(SSZ_DIR)/*.md) -ALL_EXECUTABLE_SPECS = phase0 altair bellatrix capella deneb eip6110 eip7045 whisk +ALL_EXECUTABLE_SPECS = phase0 altair bellatrix capella deneb eip6110 whisk # The parameters for commands. Use `foreach` to avoid listing specs again. COVERAGE_SCOPE := $(foreach S,$(ALL_EXECUTABLE_SPECS), --cov=eth2spec.$S.$(TEST_PRESET_TYPE)) PYLINT_SCOPE := $(foreach S,$(ALL_EXECUTABLE_SPECS), ./eth2spec/$S) diff --git a/configs/mainnet.yaml b/configs/mainnet.yaml index 12f32d6994..365bc11367 100644 --- a/configs/mainnet.yaml +++ b/configs/mainnet.yaml @@ -53,9 +53,6 @@ DENEB_FORK_EPOCH: 18446744073709551615 # EIP6110 EIP6110_FORK_VERSION: 0x05000000 # temporary stub EIP6110_FORK_EPOCH: 18446744073709551615 -# EIP7045 -EIP7045_FORK_VERSION: 0x05000000 # temporary stub -EIP7045_FORK_EPOCH: 18446744073709551615 # Time parameters diff --git a/configs/minimal.yaml b/configs/minimal.yaml index 870bc5438f..b22a7165e1 100644 --- a/configs/minimal.yaml +++ b/configs/minimal.yaml @@ -52,11 +52,6 @@ DENEB_FORK_EPOCH: 18446744073709551615 # EIP6110 EIP6110_FORK_VERSION: 0x05000001 EIP6110_FORK_EPOCH: 18446744073709551615 -# EIP7045 -EIP7045_FORK_VERSION: 0x05000001 -EIP7045_FORK_EPOCH: 18446744073709551615 - - # Time parameters diff --git a/setup.py b/setup.py index c2b06d8aa5..90ac744e64 100644 --- a/setup.py +++ b/setup.py @@ -48,7 +48,6 @@ def installPackage(package: str): CAPELLA = 'capella' DENEB = 'deneb' EIP6110 = 'eip6110' -EIP7045= 'eip7045' WHISK = 'whisk' PREVIOUS_FORK_OF = { @@ -58,7 +57,6 @@ def installPackage(package: str): CAPELLA: BELLATRIX, DENEB: CAPELLA, EIP6110: DENEB, - EIP7045: DENEB, WHISK: CAPELLA, } @@ -778,18 +776,6 @@ def imports(cls, preset_name: str): from eth2spec.deneb import {preset_name} as deneb ''' -# -# EIP7045SpecBuilder -# -class EIP7045SpecBuilder(DenebSpecBuilder): - fork: str = EIP7045 - - @classmethod - def imports(cls, preset_name: str): - return super().imports(preset_name) + f''' -from eth2spec.deneb import {preset_name} as deneb -''' - # # WhiskSpecBuilder # @@ -816,7 +802,7 @@ def hardcoded_custom_type_dep_constants(cls, spec_object) -> str: builder.fork: builder for builder in ( Phase0SpecBuilder, AltairSpecBuilder, BellatrixSpecBuilder, CapellaSpecBuilder, DenebSpecBuilder, - EIP6110SpecBuilder, EIP7045SpecBuilder, WhiskSpecBuilder, + EIP6110SpecBuilder, WhiskSpecBuilder, ) } diff --git a/specs/_features/eip7045/beacon-chain.md b/specs/_features/eip7045/beacon-chain.md deleted file mode 100644 index 9429b102e8..0000000000 --- a/specs/_features/eip7045/beacon-chain.md +++ /dev/null @@ -1,167 +0,0 @@ -# Deneb -- The Beacon Chain - -**Notice**: This document is a work-in-progress for researchers and implementers. - -## Table of contents - - - - - -- [Introduction](#introduction) -- [Preset](#preset) -- [Configuration](#configuration) -- [Containers](#containers) -- [Helpers](#helpers) - - [Modified `get_attestation_participation_flag_indicies`](#modified-get_attestation_participation_flag_indicies) -- [Beacon chain state transition function](#beacon-chain-state-transition-function) - - [Block processing](#block-processing) - - [Modified `process_attestation`](#modified-process_attestation) -- [Testing](#testing) - - - - -## Introduction - -This feature allows for inclusion of attestations created during epoch `N` to be included in slots from epoch `N` as well as all slots in epoch `N+1` rather than the current `SLOTS_PER_EPOCH` slot restricted range. This is an extension of the Deneb upgrade. - -## Preset - -## Configuration - -## Containers - -## Helpers - -### Modified `get_attestation_participation_flag_indicies` - -*Note:* The function `get_attestation_participation_flag_indicies` is modified to set the `TIMELY_TARGET_FLAG` for any correct target attestation, regardless of `inclusion_delay` as a baseline reward for any speed of inclusion of an attestation that contributes to justification of the contained chain. - -```python -def get_attestation_participation_flag_indices(state: BeaconState, - data: AttestationData, - inclusion_delay: uint64) -> Sequence[int]: - """ - Return the flag indices that are satisfied by an attestation. - """ - if data.target.epoch == get_current_epoch(state): - justified_checkpoint = state.current_justified_checkpoint - else: - justified_checkpoint = state.previous_justified_checkpoint - - # Matching roots - is_matching_source = data.source == justified_checkpoint - is_matching_target = is_matching_source and data.target.root == get_block_root(state, data.target.epoch) - is_matching_head = is_matching_target and data.beacon_block_root == get_block_root_at_slot(state, data.slot) - assert is_matching_source - - participation_flag_indices = [] - if is_matching_source and inclusion_delay <= integer_squareroot(SLOTS_PER_EPOCH): - participation_flag_indices.append(TIMELY_SOURCE_FLAG_INDEX) - if is_matching_target: # [Modified in EIP7045] - participation_flag_indices.append(TIMELY_TARGET_FLAG_INDEX) - if is_matching_head and inclusion_delay == MIN_ATTESTATION_INCLUSION_DELAY: - participation_flag_indices.append(TIMELY_HEAD_FLAG_INDEX) - - return participation_flag_indices -``` - -## Beacon chain state transition function - -### Block processing - -#### Modified `process_attestation` - -*Note*: The function `process_attestation` is modified to expand valid slots for inclusion to those in both `target.epoch` epoch and `target.epoch + 1` epoch. Additionally, it utilizes an updated version of `get_attestation_participation_flag_indices` to ensure rewards are available for the extended attestation inclusion range. - -```python -def process_attestation(state: BeaconState, attestation: Attestation) -> None: - data = attestation.data - assert data.target.epoch in (get_previous_epoch(state), get_current_epoch(state)) - assert data.target.epoch == compute_epoch_at_slot(data.slot) - assert data.slot + MIN_ATTESTATION_INCLUSION_DELAY <= state.slot # [Modified in EIP7045] - assert data.index < get_committee_count_per_slot(state, data.target.epoch) - - committee = get_beacon_committee(state, data.slot, data.index) - assert len(attestation.aggregation_bits) == len(committee) - - # Participation flag indices - participation_flag_indices = get_attestation_participation_flag_indices(state, data, state.slot - data.slot) - - # Verify signature - assert is_valid_indexed_attestation(state, get_indexed_attestation(state, attestation)) - - # Update epoch participation flags - if data.target.epoch == get_current_epoch(state): - epoch_participation = state.current_epoch_participation - else: - epoch_participation = state.previous_epoch_participation - - proposer_reward_numerator = 0 - for index in get_attesting_indices(state, data, attestation.aggregation_bits): - for flag_index, weight in enumerate(PARTICIPATION_FLAG_WEIGHTS): - if flag_index in participation_flag_indices and not has_flag(epoch_participation[index], flag_index): - epoch_participation[index] = add_flag(epoch_participation[index], flag_index) - proposer_reward_numerator += get_base_reward(state, index) * weight - - # Reward proposer - proposer_reward_denominator = (WEIGHT_DENOMINATOR - PROPOSER_WEIGHT) * WEIGHT_DENOMINATOR // PROPOSER_WEIGHT - proposer_reward = Gwei(proposer_reward_numerator // proposer_reward_denominator) - increase_balance(state, get_beacon_proposer_index(state), proposer_reward) -``` - -## Testing - -*Note*: The function `initialize_beacon_state_from_eth1` is modified for pure EIP7045 testing only. -Modifications include: -1. Use `EIP7045_FORK_VERSION` as the previous and current fork version. - -```python -def initialize_beacon_state_from_eth1(eth1_block_hash: Hash32, - eth1_timestamp: uint64, - deposits: Sequence[Deposit], - execution_payload_header: ExecutionPayloadHeader=ExecutionPayloadHeader() - ) -> BeaconState: - fork = Fork( - previous_version=EIP7045_FORK_VERSION, # [Modified in EIP7045] for testing only - current_version=EIP7045_FORK_VERSION, # [Modified in EIP7045] - epoch=GENESIS_EPOCH, - ) - state = BeaconState( - genesis_time=eth1_timestamp + GENESIS_DELAY, - fork=fork, - eth1_data=Eth1Data(block_hash=eth1_block_hash, deposit_count=uint64(len(deposits))), - latest_block_header=BeaconBlockHeader(body_root=hash_tree_root(BeaconBlockBody())), - randao_mixes=[eth1_block_hash] * EPOCHS_PER_HISTORICAL_VECTOR, # Seed RANDAO with Eth1 entropy - ) - - # Process deposits - leaves = list(map(lambda deposit: deposit.data, deposits)) - for index, deposit in enumerate(deposits): - deposit_data_list = List[DepositData, 2**DEPOSIT_CONTRACT_TREE_DEPTH](*leaves[:index + 1]) - state.eth1_data.deposit_root = hash_tree_root(deposit_data_list) - process_deposit(state, deposit) - - # Process activations - for index, validator in enumerate(state.validators): - balance = state.balances[index] - validator.effective_balance = min(balance - balance % EFFECTIVE_BALANCE_INCREMENT, MAX_EFFECTIVE_BALANCE) - if validator.effective_balance == MAX_EFFECTIVE_BALANCE: - validator.activation_eligibility_epoch = GENESIS_EPOCH - validator.activation_epoch = GENESIS_EPOCH - - # Set genesis validators root for domain separation and chain versioning - state.genesis_validators_root = hash_tree_root(state.validators) - - # Fill in sync committees - # Note: A duplicate committee is assigned for the current and next committee at genesis - state.current_sync_committee = get_next_sync_committee(state) - state.next_sync_committee = get_next_sync_committee(state) - - # Initialize the execution payload header - state.latest_execution_payload_header = execution_payload_header - - return state -``` - diff --git a/specs/_features/eip7045/fork.md b/specs/_features/eip7045/fork.md deleted file mode 100644 index 152d09f62a..0000000000 --- a/specs/_features/eip7045/fork.md +++ /dev/null @@ -1,123 +0,0 @@ -# Att-Slot-Range -- 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 EIP7045](#fork-to-eip7045) - - [Fork trigger](#fork-trigger) - - [Upgrading the state](#upgrading-the-state) - - - -## Introduction - -This document describes the process of Att-Slot-Range upgrade. - -## Configuration - -Warning: this configuration is not definitive. - -| Name | Value | -| - | - | -| `EIP7045_FORK_VERSION` | `Version('0x05000000')` | -| `EIP7045_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 >= EIP7045_FORK_EPOCH: - return EIP7045_FORK_VERSION - if epoch >= DENEB_FORK_EPOCH: - return DENEB_FORK_VERSION - if epoch >= CAPELLA_FORK_EPOCH: - return CAPELLA_FORK_VERSION - if epoch >= BELLATRIX_FORK_EPOCH: - return BELLATRIX_FORK_VERSION - if epoch >= ALTAIR_FORK_EPOCH: - return ALTAIR_FORK_VERSION - return GENESIS_FORK_VERSION -``` - -## Fork to EIP7045 - -### 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 `EIP7045_FORK_EPOCH`. - -Note that for the pure EIP7045 networks, we don't apply `upgrade_to_eip7045` since it starts with EIP7045 version logic. - -### Upgrading the state - -If `state.slot % SLOTS_PER_EPOCH == 0` and `compute_epoch_at_slot(state.slot) == EIP7045_FORK_EPOCH`, -an irregular state change is made to upgrade to EIP7045. - -```python -def upgrade_to_eip7045(pre: deneb.BeaconState) -> BeaconState: - 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=EIP7045_FORK_VERSION, # [Modified in Att-Slot-Range] - epoch=deneb.get_current_epoch(pre), - ), - # 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=pre.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/_features/eip7045/p2p-interface.md b/specs/_features/eip7045/p2p-interface.md deleted file mode 100644 index 8e263bcee6..0000000000 --- a/specs/_features/eip7045/p2p-interface.md +++ /dev/null @@ -1,72 +0,0 @@ -# EIP7045 -- Networking - -This document contains the consensus-layer networking specification for EIP7045. - -The specification of these changes continues in the same format as the network specifications of previous upgrades, and assumes them as pre-requisite. - -## Table of contents - - - - - -- [Modifications in EIP7045](#modifications-in-eip7045) - - [The gossip domain: gossipsub](#the-gossip-domain-gossipsub) - - [Topics and messages](#topics-and-messages) - - [Global topics](#global-topics) - - [`beacon_aggregate_and_proof`](#beacon_aggregate_and_proof) - - [Attestation subnets](#attestation-subnets) - - [`beacon_attestation_{subnet_id}](#beacon_attestation_subnet_id) - - - - -## Modifications in EIP7045 - -### The gossip domain: gossipsub - -#### Topics and messages - -Topics follow the same specification as in prior upgrades. - -The `beacon_aggregate_and_proof` and `beacon_attestation_{subnet_id}` topics are modified to support the gossip of attestations created in epoch `N` to be gossiped through the entire range of slots in epoch `N+1` rather than only through one epoch of slots. - -Otherwise, the specification around the creation, validation, and dissemination of messages has not changed from the Deneb document unless explicitly noted here. - -The derivation of the `message-id` remains stable. - -##### Global topics - -Deneb introduces new global topics for blob sidecars. - -###### `beacon_aggregate_and_proof` - -The following validation is removed: -* _[IGNORE]_ `aggregate.data.slot` is within the last `ATTESTATION_PROPAGATION_SLOT_RANGE` slots (with a `MAXIMUM_GOSSIP_CLOCK_DISPARITY` allowance) -- - i.e. `aggregate.data.slot + ATTESTATION_PROPAGATION_SLOT_RANGE >= current_slot >= aggregate.data.slot` - (a client MAY queue future aggregates for processing at the appropriate slot). - -The following validations are added in its place: -* _[IGNORE]_ `aggregate.data.slot` is equal to or earlier than the `current_slot` (with a `MAXIMUM_GOSSIP_CLOCK_DISPARITY` allowance) -- - i.e. `aggregate.data.slot <= current_slot` - (a client MAY queue future aggregates for processing at the appropriate slot). -* _[IGNORE]_ the epoch of `aggregate.data.slot` is either the current or previous epoch - (with a `MAXIMUM_GOSSIP_CLOCK_DISPARITY` allowance) -- - i.e. `compute_epoch_at_slot(aggregate.data.slot) in (get_previous_epoch(state), get_current_epoch(state))` - -#### Attestation subnets - -##### `beacon_attestation_{subnet_id} - -The following validation is removed: -* _[IGNORE]_ `attestation.data.slot` is within the last `ATTESTATION_PROPAGATION_SLOT_RANGE` slots (with a `MAXIMUM_GOSSIP_CLOCK_DISPARITY` allowance) -- - i.e. `attestation.data.slot + ATTESTATION_PROPAGATION_SLOT_RANGE >= current_slot >= attestation.data.slot` - (a client MAY queue future attestations for processing at the appropriate slot). - -The following validations are added in its place: -* _[IGNORE]_ `attestation.data.slot` is equal to or earlier than the `current_slot` (with a `MAXIMUM_GOSSIP_CLOCK_DISPARITY` allowance) -- - i.e. `attestation.data.slot <= current_slot` - (a client MAY queue future attestation for processing at the appropriate slot). -* _[IGNORE]_ the epoch of `attestation.data.slot` is either the current or previous epoch - (with a `MAXIMUM_GOSSIP_CLOCK_DISPARITY` allowance) -- - i.e. `compute_epoch_at_slot(attestation.data.slot) in (get_previous_epoch(state), get_current_epoch(state))` diff --git a/specs/deneb/beacon-chain.md b/specs/deneb/beacon-chain.md index 3189ee1906..8901b35f6e 100644 --- a/specs/deneb/beacon-chain.md +++ b/specs/deneb/beacon-chain.md @@ -24,6 +24,7 @@ - [Helper functions](#helper-functions) - [Misc](#misc) - [`kzg_commitment_to_versioned_hash`](#kzg_commitment_to_versioned_hash) + - [Modified `get_attestation_participation_flag_indicies`](#modified-get_attestation_participation_flag_indicies) - [Beacon chain state transition function](#beacon-chain-state-transition-function) - [Execution engine](#execution-engine) - [Request data](#request-data) @@ -32,6 +33,7 @@ - [`is_valid_versioned_hashes`](#is_valid_versioned_hashes) - [Modified `verify_and_notify_new_payload`](#modified-verify_and_notify_new_payload) - [Block processing](#block-processing) + - [Modified `process_attestation`](#modified-process_attestation) - [Execution payload](#execution-payload) - [Modified `process_execution_payload`](#modified-process_execution_payload) - [Modified `process_voluntary_exit`](#modified-process_voluntary_exit) @@ -45,6 +47,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 ## Custom types @@ -170,6 +173,40 @@ def kzg_commitment_to_versioned_hash(kzg_commitment: KZGCommitment) -> Versioned return VERSIONED_HASH_VERSION_KZG + hash(kzg_commitment)[1:] ``` +### Modified `get_attestation_participation_flag_indicies` + +*Note:* The function `get_attestation_participation_flag_indicies` is modified to set the `TIMELY_TARGET_FLAG` for any correct target attestation, regardless of `inclusion_delay` as a baseline reward for any speed of inclusion of an attestation that contributes to justification of the contained chain for EIP-7045. + +```python +def get_attestation_participation_flag_indices(state: BeaconState, + data: AttestationData, + inclusion_delay: uint64) -> Sequence[int]: + """ + Return the flag indices that are satisfied by an attestation. + """ + if data.target.epoch == get_current_epoch(state): + justified_checkpoint = state.current_justified_checkpoint + else: + justified_checkpoint = state.previous_justified_checkpoint + + # Matching roots + is_matching_source = data.source == justified_checkpoint + is_matching_target = is_matching_source and data.target.root == get_block_root(state, data.target.epoch) + is_matching_head = is_matching_target and data.beacon_block_root == get_block_root_at_slot(state, data.slot) + assert is_matching_source + + participation_flag_indices = [] + if is_matching_source and inclusion_delay <= integer_squareroot(SLOTS_PER_EPOCH): + participation_flag_indices.append(TIMELY_SOURCE_FLAG_INDEX) + if is_matching_target: # [Modified in Deneb:EIP7045] + participation_flag_indices.append(TIMELY_TARGET_FLAG_INDEX) + if is_matching_head and inclusion_delay == MIN_ATTESTATION_INCLUSION_DELAY: + participation_flag_indices.append(TIMELY_HEAD_FLAG_INDEX) + + return participation_flag_indices +``` + + ## Beacon chain state transition function ### Execution engine @@ -221,10 +258,52 @@ def verify_and_notify_new_payload(self: ExecutionEngine, ### Block processing +#### Modified `process_attestation` + +*Note*: The function `process_attestation` is modified to expand valid slots for inclusion to those in both `target.epoch` epoch and `target.epoch + 1` epoch for EIP-7045. Additionally, it utilizes an updated version of `get_attestation_participation_flag_indices` to ensure rewards are available for the extended attestation inclusion range for EIP-7045. + +```python +def process_attestation(state: BeaconState, attestation: Attestation) -> None: + data = attestation.data + assert data.target.epoch in (get_previous_epoch(state), get_current_epoch(state)) + assert data.target.epoch == compute_epoch_at_slot(data.slot) + assert data.slot + MIN_ATTESTATION_INCLUSION_DELAY <= state.slot # [Modified in Deneb:EIP7045] + assert data.index < get_committee_count_per_slot(state, data.target.epoch) + + committee = get_beacon_committee(state, data.slot, data.index) + assert len(attestation.aggregation_bits) == len(committee) + + # Participation flag indices + participation_flag_indices = get_attestation_participation_flag_indices(state, data, state.slot - data.slot) + + # Verify signature + assert is_valid_indexed_attestation(state, get_indexed_attestation(state, attestation)) + + # Update epoch participation flags + if data.target.epoch == get_current_epoch(state): + epoch_participation = state.current_epoch_participation + else: + epoch_participation = state.previous_epoch_participation + + proposer_reward_numerator = 0 + for index in get_attesting_indices(state, data, attestation.aggregation_bits): + for flag_index, weight in enumerate(PARTICIPATION_FLAG_WEIGHTS): + if flag_index in participation_flag_indices and not has_flag(epoch_participation[index], flag_index): + epoch_participation[index] = add_flag(epoch_participation[index], flag_index) + proposer_reward_numerator += get_base_reward(state, index) * weight + + # Reward proposer + proposer_reward_denominator = (WEIGHT_DENOMINATOR - PROPOSER_WEIGHT) * WEIGHT_DENOMINATOR // PROPOSER_WEIGHT + proposer_reward = Gwei(proposer_reward_numerator // proposer_reward_denominator) + increase_balance(state, get_beacon_proposer_index(state), proposer_reward) +``` + #### Execution payload ##### Modified `process_execution_payload` +*Note*: The function `process_execution_payload` is modified to pass `versioned_hashes` into `execution_engine.verify_and_notify_new_payload` and to assign the new fields in `ExecutionPayloadHeader` for EIP-4844. + ```python def process_execution_payload(state: BeaconState, body: BeaconBlockBody, execution_engine: ExecutionEngine) -> None: payload = body.execution_payload @@ -270,7 +349,7 @@ def process_execution_payload(state: BeaconState, body: BeaconBlockBody, executi #### Modified `process_voluntary_exit` -*Note*: The function `process_voluntary_exit` is modified to use the a fixed fork version -- `CAPELLA_FORK_VERSION` -- for EIP-7044 +*Note*: The function `process_voluntary_exit` is modified to use the a fixed fork version -- `CAPELLA_FORK_VERSION` -- for EIP-7044. ```python def process_voluntary_exit(state: BeaconState, signed_voluntary_exit: SignedVoluntaryExit) -> None: diff --git a/specs/deneb/fork.md b/specs/deneb/fork.md index ffced6a59a..08af2fd351 100644 --- a/specs/deneb/fork.md +++ b/specs/deneb/fork.md @@ -57,7 +57,7 @@ def compute_fork_version(epoch: Epoch) -> Version: ### Fork trigger -TBD. This fork is defined for testing purposes, the EIP may be combined with other consensus-layer upgrade. +TBD. This fork is defined for testing purposes. For now, we assume the condition will be triggered at epoch `DENEB_FORK_EPOCH`. Note that for the pure Deneb networks, we don't apply `upgrade_to_deneb` since it starts with Deneb version logic. diff --git a/specs/deneb/p2p-interface.md b/specs/deneb/p2p-interface.md index 809e405a66..f073b50f5c 100644 --- a/specs/deneb/p2p-interface.md +++ b/specs/deneb/p2p-interface.md @@ -23,6 +23,9 @@ The specification of these changes continues in the same format as the network s - [Global topics](#global-topics) - [`beacon_block`](#beacon_block) - [`blob_sidecar_{subnet_id}`](#blob_sidecar_subnet_id) + - [`beacon_aggregate_and_proof`](#beacon_aggregate_and_proof) + - [Attestation subnets](#attestation-subnets) + - [`beacon_attestation_{subnet_id}](#beacon_attestation_subnet_id) - [Transitioning the gossip](#transitioning-the-gossip) - [The Req/Resp domain](#the-reqresp-domain) - [Messages](#messages) @@ -106,7 +109,11 @@ Some gossip meshes are upgraded in the fork of Deneb to support upgraded types. Topics follow the same specification as in prior upgrades. -The `beacon_block` topic is modified to also support deneb blocks and new topics are added per table below. All other topics remain stable. +The `beacon_block` topic is modified to also support Deneb blocks and new topics are added per table below. + +The `voluntary_exit` topic is implicitly modified due to the lock-in use of `CAPELLA_FORK_VERSION` for this message signature validation for EIP-7044. + +The `beacon_aggregate_and_proof` and `beacon_attestation_{subnet_id}` topics are modified to support the gossip of attestations created in epoch `N` to be gossiped through the entire range of slots in epoch `N+1` rather than only through one epoch of slots for EIP-7045. The specification around the creation, validation, and dissemination of messages has not changed from the Capella document unless explicitly noted here. @@ -124,7 +131,9 @@ Deneb introduces new global topics for blob sidecars. ###### `beacon_block` -The *type* of the payload of this topic changes to the (modified) `SignedBeaconBlock` found in deneb. +The *type* of the payload of this topic changes to the (modified) `SignedBeaconBlock` found in Deneb. + +*[Modified in Deneb:EIP4844]* New validation: @@ -150,6 +159,41 @@ The following validations MUST pass before forwarding the `signed_blob_sidecar` - _[REJECT]_ The sidecar is proposed by the expected `proposer_index` for the block's slot in the context of the current shuffling (defined by `block_parent_root`/`slot`). If the `proposer_index` cannot immediately be verified against the expected shuffling, the sidecar MAY be queued for later processing while proposers for the block's branch are calculated -- in such a case _do not_ `REJECT`, instead `IGNORE` this message. +###### `beacon_aggregate_and_proof` + +*[Modified in Deneb:EIP7045]* + +The following validation is removed: +* _[IGNORE]_ `aggregate.data.slot` is within the last `ATTESTATION_PROPAGATION_SLOT_RANGE` slots (with a `MAXIMUM_GOSSIP_CLOCK_DISPARITY` allowance) -- + i.e. `aggregate.data.slot + ATTESTATION_PROPAGATION_SLOT_RANGE >= current_slot >= aggregate.data.slot` + (a client MAY queue future aggregates for processing at the appropriate slot). + +The following validations are added in its place: +* _[IGNORE]_ `aggregate.data.slot` is equal to or earlier than the `current_slot` (with a `MAXIMUM_GOSSIP_CLOCK_DISPARITY` allowance) -- + i.e. `aggregate.data.slot <= current_slot` + (a client MAY queue future aggregates for processing at the appropriate slot). +* _[IGNORE]_ the epoch of `aggregate.data.slot` is either the current or previous epoch + (with a `MAXIMUM_GOSSIP_CLOCK_DISPARITY` allowance) -- + i.e. `compute_epoch_at_slot(aggregate.data.slot) in (get_previous_epoch(state), get_current_epoch(state))` + +##### Attestation subnets + +###### `beacon_attestation_{subnet_id} + +*[Modified in Deneb:EIP7045]* + +The following validation is removed: +* _[IGNORE]_ `attestation.data.slot` is within the last `ATTESTATION_PROPAGATION_SLOT_RANGE` slots (with a `MAXIMUM_GOSSIP_CLOCK_DISPARITY` allowance) -- + i.e. `attestation.data.slot + ATTESTATION_PROPAGATION_SLOT_RANGE >= current_slot >= attestation.data.slot` + (a client MAY queue future attestations for processing at the appropriate slot). + +The following validations are added in its place: +* _[IGNORE]_ `attestation.data.slot` is equal to or earlier than the `current_slot` (with a `MAXIMUM_GOSSIP_CLOCK_DISPARITY` allowance) -- + i.e. `attestation.data.slot <= current_slot` + (a client MAY queue future attestation for processing at the appropriate slot). +* _[IGNORE]_ the epoch of `attestation.data.slot` is either the current or previous epoch + (with a `MAXIMUM_GOSSIP_CLOCK_DISPARITY` allowance) -- + i.e. `compute_epoch_at_slot(attestation.data.slot) in (get_previous_epoch(state), get_current_epoch(state))` #### Transitioning the gossip diff --git a/specs/phase0/p2p-interface.md b/specs/phase0/p2p-interface.md index c0d18b08f3..14427c79ce 100644 --- a/specs/phase0/p2p-interface.md +++ b/specs/phase0/p2p-interface.md @@ -1002,7 +1002,7 @@ Clients MAY connect to peers with the same `fork_digest` but a different `next_f Unless `ENRForkID` is manually updated to matching prior to the earlier `next_fork_epoch` of the two clients, these connecting clients will be unable to successfully interact starting at the earlier `next_fork_epoch`. -### Attestation subnet subcription +### Attestation subnet subscription Because Phase 0 does not have shards and thus does not have Shard Committees, there is no stable backbone to the attestation subnets (`beacon_attestation_{subnet_id}`). To provide this stability, each beacon node should: diff --git a/tests/core/pyspec/eth2spec/test/context.py b/tests/core/pyspec/eth2spec/test/context.py index 88b2526497..48f6857f64 100644 --- a/tests/core/pyspec/eth2spec/test/context.py +++ b/tests/core/pyspec/eth2spec/test/context.py @@ -9,13 +9,12 @@ from eth2spec.capella import mainnet as spec_capella_mainnet, minimal as spec_capella_minimal from eth2spec.deneb import mainnet as spec_deneb_mainnet, minimal as spec_deneb_minimal from eth2spec.eip6110 import mainnet as spec_eip6110_mainnet, minimal as spec_eip6110_minimal -from eth2spec.eip7045 import mainnet as spec_eip7045_mainnet, minimal as spec_eip7045_minimal from eth2spec.utils import bls from .exceptions import SkippedTest from .helpers.constants import ( PHASE0, ALTAIR, BELLATRIX, CAPELLA, DENEB, - EIP6110, EIP7045, + EIP6110, MINIMAL, MAINNET, ALL_PHASES, ALL_FORK_UPGRADES, @@ -84,7 +83,6 @@ class ForkMeta: CAPELLA: spec_capella_minimal, DENEB: spec_deneb_minimal, EIP6110: spec_eip6110_minimal, - EIP7045: spec_eip7045_minimal, }, MAINNET: { PHASE0: spec_phase0_mainnet, @@ -93,7 +91,6 @@ class ForkMeta: CAPELLA: spec_capella_mainnet, DENEB: spec_deneb_mainnet, EIP6110: spec_eip6110_mainnet, - EIP7045: spec_eip7045_mainnet, }, } @@ -544,9 +541,6 @@ def wrapper(*args, spec: Spec, **kw): with_capella_and_later = with_all_phases_from(CAPELLA) with_deneb_and_later = with_all_phases_from(DENEB) with_eip6110_and_later = with_all_phases_from(EIP6110) -with_eip7045_and_later = with_all_phases_from(EIP7045) - -with_all_phases_except_eip7045 = with_all_phases_except(EIP7045) class quoted_str(str): diff --git a/tests/core/pyspec/eth2spec/test/deneb/block_processing/test_process_voluntary_exit.py b/tests/core/pyspec/eth2spec/test/deneb/block_processing/test_process_voluntary_exit.py index 711d27eb92..b01eaab0e1 100644 --- a/tests/core/pyspec/eth2spec/test/deneb/block_processing/test_process_voluntary_exit.py +++ b/tests/core/pyspec/eth2spec/test/deneb/block_processing/test_process_voluntary_exit.py @@ -1,7 +1,6 @@ from eth2spec.test.context import ( always_bls, spec_state_test, - with_phases, with_deneb_and_later, ) from eth2spec.test.helpers.constants import ( diff --git a/tests/core/pyspec/eth2spec/test/helpers/attestations.py b/tests/core/pyspec/eth2spec/test/helpers/attestations.py index b1f60feb4b..4899e62243 100644 --- a/tests/core/pyspec/eth2spec/test/helpers/attestations.py +++ b/tests/core/pyspec/eth2spec/test/helpers/attestations.py @@ -5,7 +5,7 @@ from eth2spec.test.context import expect_assertion_error from eth2spec.test.helpers.state import state_transition_and_sign_block, next_epoch, next_slot from eth2spec.test.helpers.block import build_empty_block_for_next_slot -from eth2spec.test.helpers.forks import is_post_altair, is_post_eip7045 +from eth2spec.test.helpers.forks import is_post_altair, is_post_deneb from eth2spec.test.helpers.keys import privkeys from eth2spec.utils import bls from eth2spec.utils.ssz.ssz_typing import Bitlist @@ -159,7 +159,7 @@ def get_attestation_signature(spec, state, attestation_data, privkey): def compute_max_inclusion_slot(spec, attestation): - if is_post_eip7045(spec): + if is_post_deneb(spec): next_epoch = spec.compute_epoch_at_slot(attestation.data.slot) + 1 end_of_next_epoch = spec.compute_start_slot_at_epoch(next_epoch + 1) - 1 return end_of_next_epoch diff --git a/tests/core/pyspec/eth2spec/test/helpers/constants.py b/tests/core/pyspec/eth2spec/test/helpers/constants.py index 0f1aeb5617..049c354caf 100644 --- a/tests/core/pyspec/eth2spec/test/helpers/constants.py +++ b/tests/core/pyspec/eth2spec/test/helpers/constants.py @@ -17,7 +17,6 @@ CUSTODY_GAME = SpecForkName('custody_game') DAS = SpecForkName('das') EIP6110 = SpecForkName('eip6110') -EIP7045 = SpecForkName('eip7045') # # SpecFork settings @@ -32,7 +31,7 @@ *MAINNET_FORKS, DENEB, # Experimental patches - EIP6110, EIP7045, + EIP6110, ) # 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/fork_transition.py b/tests/core/pyspec/eth2spec/test/helpers/fork_transition.py index cf7aeb93a4..68444c4726 100644 --- a/tests/core/pyspec/eth2spec/test/helpers/fork_transition.py +++ b/tests/core/pyspec/eth2spec/test/helpers/fork_transition.py @@ -16,7 +16,6 @@ CAPELLA, DENEB, EIP6110, - EIP7045, ) from eth2spec.test.helpers.deposits import ( prepare_state_and_deposit, @@ -162,8 +161,6 @@ def do_fork(state, spec, post_spec, fork_epoch, with_block=True, sync_aggregate= state = post_spec.upgrade_to_deneb(state) elif post_spec.fork == EIP6110: state = post_spec.upgrade_to_eip6110(state) - elif post_spec.fork == EIP7045: - state = post_spec.upgrade_to_eip7045(state) assert state.fork.epoch == fork_epoch @@ -182,9 +179,6 @@ def do_fork(state, spec, post_spec, fork_epoch, with_block=True, sync_aggregate= elif post_spec.fork == EIP6110: assert state.fork.previous_version == post_spec.config.DENEB_FORK_VERSION assert state.fork.current_version == post_spec.config.EIP6110_FORK_VERSION - elif post_spec.fork == EIP7045: - assert state.fork.previous_version == post_spec.config.DENEB_FORK_VERSION - assert state.fork.current_version == post_spec.config.EIP7045_FORK_VERSION if with_block: return state, _state_transition_and_sign_block_at_slot( diff --git a/tests/core/pyspec/eth2spec/test/helpers/forks.py b/tests/core/pyspec/eth2spec/test/helpers/forks.py index ddd3b795ba..5e97522dbb 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, EIP7045, + EIP6110, ) def is_post_fork(a, b): - if a == EIP7045: - return b in [PHASE0, ALTAIR, BELLATRIX, CAPELLA, DENEB, EIP7045] if a == EIP6110: return b in [PHASE0, ALTAIR, BELLATRIX, CAPELLA, DENEB, EIP6110] if a == DENEB: @@ -40,7 +38,3 @@ def is_post_deneb(spec): def is_post_eip6110(spec): return is_post_fork(spec.fork, EIP6110) - - -def is_post_eip7045(spec): - return is_post_fork(spec.fork, EIP7045) diff --git a/tests/core/pyspec/eth2spec/test/helpers/genesis.py b/tests/core/pyspec/eth2spec/test/helpers/genesis.py index eab4abec8d..fea259013b 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, EIP7045, + ALTAIR, BELLATRIX, CAPELLA, DENEB, EIP6110, ) from eth2spec.test.helpers.execution_payload import ( compute_el_header_block_hash, @@ -86,9 +86,6 @@ def create_genesis_state(spec, validator_balances, activation_threshold): elif spec.fork == EIP6110: previous_version = spec.config.DENEB_FORK_VERSION current_version = spec.config.EIP6110_FORK_VERSION - elif spec.fork == EIP7045: - previous_version = spec.config.DENEB_FORK_VERSION - current_version = spec.config.EIP7045_FORK_VERSION state = spec.BeaconState( genesis_time=0, From 834f6f70e7b864dde91641191f20e0dd1c3b0331 Mon Sep 17 00:00:00 2001 From: Lion - dapplion <35266934+dapplion@users.noreply.github.com> Date: Thu, 15 Jun 2023 14:33:28 +0300 Subject: [PATCH 31/44] Whisk: assert zeroed values during selection gap (#3425) * Assert zeroed values during selection gap * Update comment --- specs/_features/whisk/beacon-chain.md | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/specs/_features/whisk/beacon-chain.md b/specs/_features/whisk/beacon-chain.md index 34e79c1e44..b10611a8d8 100644 --- a/specs/_features/whisk/beacon-chain.md +++ b/specs/_features/whisk/beacon-chain.md @@ -306,20 +306,23 @@ def process_shuffled_trackers(state: BeaconState, body: BeaconBlockBody) -> None # Check the shuffle proof shuffle_indices = get_shuffle_indices(body.randao_reveal) pre_shuffle_trackers = [state.whisk_candidate_trackers[i] for i in shuffle_indices] - post_shuffle_trackers = body.whisk_post_shuffle_trackers shuffle_epoch = get_current_epoch(state) % WHISK_EPOCHS_PER_SHUFFLING_PHASE if shuffle_epoch + WHISK_PROPOSER_SELECTION_GAP + 1 >= WHISK_EPOCHS_PER_SHUFFLING_PHASE: - # Require unchanged trackers during cooldown - assert pre_shuffle_trackers == post_shuffle_trackers + # Require trackers set to zero during cooldown + assert body.whisk_post_shuffle_trackers == Vector[WhiskTracker, WHISK_VALIDATORS_PER_SHUFFLE]() + assert body.whisk_shuffle_proof_M_commitment == BLSG1Point() + assert body.whisk_shuffle_proof == WhiskShuffleProof() + post_shuffle_trackers = pre_shuffle_trackers else: # Require shuffled trackers during shuffle assert IsValidWhiskShuffleProof( pre_shuffle_trackers, - post_shuffle_trackers, + body.whisk_post_shuffle_trackers, body.whisk_shuffle_proof_M_commitment, body.whisk_shuffle_proof, ) + post_shuffle_trackers = body.whisk_post_shuffle_trackers # Shuffle candidate trackers for i, shuffle_index in enumerate(shuffle_indices): From 781cd83f095e4805e7c24b430607ae7f2fcdbdff Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Fri, 16 Jun 2023 17:21:34 +0800 Subject: [PATCH 32/44] fix typo --- specs/phase0/p2p-interface.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/specs/phase0/p2p-interface.md b/specs/phase0/p2p-interface.md index c0d18b08f3..bbb4c4d427 100644 --- a/specs/phase0/p2p-interface.md +++ b/specs/phase0/p2p-interface.md @@ -55,7 +55,7 @@ It consists of four main sections: - [ENR structure](#enr-structure) - [Attestation subnet bitfield](#attestation-subnet-bitfield) - [`eth2` field](#eth2-field) - - [Attestation subnet subcription](#attestation-subnet-subcription) + - [Attestation subnet subscription](#attestation-subnet-subscription) - [Design decision rationale](#design-decision-rationale) - [Transport](#transport-1) - [Why are we defining specific transports?](#why-are-we-defining-specific-transports) @@ -1002,7 +1002,7 @@ Clients MAY connect to peers with the same `fork_digest` but a different `next_f Unless `ENRForkID` is manually updated to matching prior to the earlier `next_fork_epoch` of the two clients, these connecting clients will be unable to successfully interact starting at the earlier `next_fork_epoch`. -### Attestation subnet subcription +### Attestation subnet subscription Because Phase 0 does not have shards and thus does not have Shard Committees, there is no stable backbone to the attestation subnets (`beacon_attestation_{subnet_id}`). To provide this stability, each beacon node should: From cc4c810b8f12a18f3ecfb8f1f969d91b3440eb24 Mon Sep 17 00:00:00 2001 From: Lion - dapplion <35266934+dapplion@users.noreply.github.com> Date: Mon, 19 Jun 2023 17:08:51 +0300 Subject: [PATCH 33/44] Whisk: complete TODO items in fork logic (#3427) * Complete TODO items in fork logic * Simpler underflow protection * Add saturating_sub --- specs/_features/whisk/beacon-chain.md | 16 +++++++++++---- specs/_features/whisk/fork.md | 29 +++++++++------------------ specs/phase0/beacon-chain.md | 11 ++++++++++ 3 files changed, 33 insertions(+), 23 deletions(-) diff --git a/specs/_features/whisk/beacon-chain.md b/specs/_features/whisk/beacon-chain.md index b10611a8d8..5b82c9ebd1 100644 --- a/specs/_features/whisk/beacon-chain.md +++ b/specs/_features/whisk/beacon-chain.md @@ -177,17 +177,24 @@ class BeaconState(Container): ``` ```python -def select_whisk_trackers(state: BeaconState, epoch: Epoch) -> None: +def select_whisk_proposer_trackers(state: BeaconState, epoch: Epoch) -> None: # Select proposer trackers from candidate trackers - proposer_seed = get_seed(state, epoch - WHISK_PROPOSER_SELECTION_GAP, DOMAIN_WHISK_PROPOSER_SELECTION) + proposer_seed = get_seed( + state, + Epoch(saturating_sub(epoch, WHISK_PROPOSER_SELECTION_GAP)), + DOMAIN_WHISK_PROPOSER_SELECTION + ) for i in range(WHISK_PROPOSER_TRACKERS_COUNT): index = compute_shuffled_index(uint64(i), uint64(len(state.whisk_candidate_trackers)), proposer_seed) state.whisk_proposer_trackers[i] = state.whisk_candidate_trackers[index] +``` +```python +def select_whisk_candidate_trackers(state: BeaconState, epoch: Epoch) -> None: # Select candidate trackers from active validator trackers active_validator_indices = get_active_validator_indices(state, epoch) for i in range(WHISK_CANDIDATE_TRACKERS_COUNT): - seed = hash(get_seed(state, epoch, DOMAIN_WHISK_CANDIDATE_SELECTION) + uint_to_bytes(i)) + seed = hash(get_seed(state, epoch, DOMAIN_WHISK_CANDIDATE_SELECTION) + uint_to_bytes(uint64(i))) candidate_index = compute_proposer_index(state, active_validator_indices, seed) # sample by effective balance state.whisk_candidate_trackers[i] = state.whisk_trackers[candidate_index] ``` @@ -196,7 +203,8 @@ def select_whisk_trackers(state: BeaconState, epoch: Epoch) -> None: def process_whisk_updates(state: BeaconState) -> None: next_epoch = Epoch(get_current_epoch(state) + 1) if next_epoch % WHISK_EPOCHS_PER_SHUFFLING_PHASE == 0: # select trackers at the start of shuffling phases - select_whisk_trackers(state, next_epoch) + select_whisk_proposer_trackers(state, next_epoch) + select_whisk_candidate_trackers(state, next_epoch) ``` ```python diff --git a/specs/_features/whisk/fork.md b/specs/_features/whisk/fork.md index f66026037f..ef3eb08469 100644 --- a/specs/_features/whisk/fork.md +++ b/specs/_features/whisk/fork.md @@ -53,27 +53,13 @@ The upgrade occurs after the completion of the inner loop of `process_slots` tha This ensures that we drop right into the beginning of the shuffling phase but without `process_whisk_epoch()` triggering for this Whisk run. Hence we handle all the setup ourselves in `upgrade_to_whisk()` below. ```python -def whisk_candidate_selection(state: BeaconState, epoch: Epoch) -> None: - # TODO - # pylint: disable=unused-argument - pass -``` - -```python -def whisk_proposer_selection(state: BeaconState, epoch: Epoch) -> None: - # TODO - # pylint: disable=unused-argument - pass -``` - -```python -def upgrade_to_whisk(pre: bellatrix.BeaconState) -> BeaconState: +def upgrade_to_whisk(pre: capella.BeaconState) -> BeaconState: # Compute initial unsafe trackers for all validators ks = [get_initial_whisk_k(ValidatorIndex(validator_index), 0) for validator_index in range(len(pre.validators))] whisk_k_commitments = [get_k_commitment(k) for k in ks] whisk_trackers = [get_initial_tracker(k) for k in ks] - epoch = bellatrix.get_current_epoch(pre) + epoch = get_current_epoch(pre) post = BeaconState( # Versioning genesis_time=pre.genesis_time, @@ -115,6 +101,11 @@ def upgrade_to_whisk(pre: bellatrix.BeaconState) -> BeaconState: next_sync_committee=pre.next_sync_committee, # Execution-layer latest_execution_payload_header=pre.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, # Whisk whisk_proposer_trackers=[WhiskTracker() for _ in range(WHISK_PROPOSER_TRACKERS_COUNT)], # [New in Whisk] whisk_candidate_trackers=[WhiskTracker() for _ in range(WHISK_CANDIDATE_TRACKERS_COUNT)], # [New in Whisk] @@ -124,12 +115,12 @@ def upgrade_to_whisk(pre: bellatrix.BeaconState) -> BeaconState: # Do a candidate selection followed by a proposer selection so that we have proposers for the upcoming day # Use an old epoch when selecting candidates so that we don't get the same seed as in the next candidate selection - whisk_candidate_selection(post, epoch - WHISK_PROPOSER_SELECTION_GAP - 1) - whisk_proposer_selection(post, epoch) + select_whisk_candidate_trackers(post, Epoch(saturating_sub(epoch, WHISK_PROPOSER_SELECTION_GAP + 1))) + select_whisk_proposer_trackers(post, epoch) # Do a final round of candidate selection. # We need it so that we have something to shuffle over the upcoming shuffling phase. - whisk_candidate_selection(post, epoch) + select_whisk_candidate_trackers(post, epoch) return post ``` diff --git a/specs/phase0/beacon-chain.md b/specs/phase0/beacon-chain.md index 214c0b77e2..bdfb078380 100644 --- a/specs/phase0/beacon-chain.md +++ b/specs/phase0/beacon-chain.md @@ -59,6 +59,7 @@ - [`xor`](#xor) - [`uint_to_bytes`](#uint_to_bytes) - [`bytes_to_uint64`](#bytes_to_uint64) + - [`saturating_sub`](#saturating_sub) - [Crypto](#crypto) - [`hash`](#hash) - [`hash_tree_root`](#hash_tree_root) @@ -630,6 +631,16 @@ def bytes_to_uint64(data: bytes) -> uint64: return uint64(int.from_bytes(data, ENDIANNESS)) ``` +#### `saturating_sub` + +```python +def saturating_sub(a: int, b: int) -> int: + """ + Computes a - b, saturating at numeric bounds. + """ + return a - b if a > b else 0 +``` + ### Crypto #### `hash` From c90d724392c619c0fd3dbd471567d2bba9921bef Mon Sep 17 00:00:00 2001 From: Lion - dapplion <35266934+dapplion@users.noreply.github.com> Date: Mon, 19 Jun 2023 17:10:15 +0300 Subject: [PATCH 34/44] Whisk: add preset files (#3424) * Add Whisk preset files * Use N=8 for minimal preset * Update spec_object var location --- presets/mainnet/whisk.yaml | 20 ++++++++++++++++++++ presets/minimal/whisk.yaml | 20 ++++++++++++++++++++ setup.py | 4 ++-- specs/_features/whisk/beacon-chain.md | 21 ++++++++++++++------- 4 files changed, 56 insertions(+), 9 deletions(-) create mode 100644 presets/mainnet/whisk.yaml create mode 100644 presets/minimal/whisk.yaml diff --git a/presets/mainnet/whisk.yaml b/presets/mainnet/whisk.yaml new file mode 100644 index 0000000000..3086ff29de --- /dev/null +++ b/presets/mainnet/whisk.yaml @@ -0,0 +1,20 @@ +# Mainnet preset - Whisk + +# Misc +# --------------------------------------------------------------- +# `uint64(4)` +CURDLEPROOFS_N_BLINDERS: 4 +# `uint64(2**14)` +WHISK_CANDIDATE_TRACKERS_COUNT: 16384 +# `uint64(2**13)` must be < WHISK_CANDIDATE_TRACKERS_COUNT +WHISK_PROPOSER_TRACKERS_COUNT: 8192 +# `Epoch(2**8)` +WHISK_EPOCHS_PER_SHUFFLING_PHASE: 256 +# `uint64(2**7 - CURDLEPROOFS_N_BLINDERS)` +WHISK_VALIDATORS_PER_SHUFFLE: 124 +# `Epoch(2)` +WHISK_PROPOSER_SELECTION_GAP: 2 +# `uint64(2**15)` TODO: will be replaced by a fix format once there's a serialized format +WHISK_MAX_SHUFFLE_PROOF_SIZE: 32768 +# `uint64(2**10)` TODO: will be replaced by a fix format once there's a serialized format +WHISK_MAX_OPENING_PROOF_SIZE: 1024 diff --git a/presets/minimal/whisk.yaml b/presets/minimal/whisk.yaml new file mode 100644 index 0000000000..1a726f79c2 --- /dev/null +++ b/presets/minimal/whisk.yaml @@ -0,0 +1,20 @@ +# Minimal preset - Whisk + +# Misc +# --------------------------------------------------------------- +# [customized] +CURDLEPROOFS_N_BLINDERS: 4 +# [customized] +WHISK_CANDIDATE_TRACKERS_COUNT: 32 +# [customized] +WHISK_PROPOSER_TRACKERS_COUNT: 16 +# [customized] +WHISK_EPOCHS_PER_SHUFFLING_PHASE: 4 +# [customized] +WHISK_VALIDATORS_PER_SHUFFLE: 4 +# [customized] +WHISK_PROPOSER_SELECTION_GAP: 1 +# `uint64(2**15)` TODO: will be replaced by a fix format once there's a serialized format +WHISK_MAX_SHUFFLE_PROOF_SIZE: 32768 +# `uint64(2**10)` TODO: will be replaced by a fix format once there's a serialized format +WHISK_MAX_OPENING_PROOF_SIZE: 1024 diff --git a/setup.py b/setup.py index f12800a621..cc1fcca098 100644 --- a/setup.py +++ b/setup.py @@ -793,8 +793,8 @@ def imports(cls, preset_name: str): def hardcoded_custom_type_dep_constants(cls, spec_object) -> str: # Necessary for custom types `WhiskShuffleProof` and `WhiskTrackerProof` constants = { - 'WHISK_MAX_SHUFFLE_PROOF_SIZE': spec_object.constant_vars['WHISK_MAX_SHUFFLE_PROOF_SIZE'].value, - 'WHISK_MAX_OPENING_PROOF_SIZE': spec_object.constant_vars['WHISK_MAX_OPENING_PROOF_SIZE'].value, + 'WHISK_MAX_SHUFFLE_PROOF_SIZE': spec_object.preset_vars['WHISK_MAX_SHUFFLE_PROOF_SIZE'].value, + 'WHISK_MAX_OPENING_PROOF_SIZE': spec_object.preset_vars['WHISK_MAX_OPENING_PROOF_SIZE'].value, } return {**super().hardcoded_custom_type_dep_constants(spec_object), **constants} diff --git a/specs/_features/whisk/beacon-chain.md b/specs/_features/whisk/beacon-chain.md index 5b82c9ebd1..f2a51e6223 100644 --- a/specs/_features/whisk/beacon-chain.md +++ b/specs/_features/whisk/beacon-chain.md @@ -10,6 +10,8 @@ - [Introduction](#introduction) - [Constants](#constants) + - [Domain types](#domain-types) +- [Preset](#preset) - [Cryptography](#cryptography) - [BLS](#bls) - [Curdleproofs and opening proofs](#curdleproofs-and-opening-proofs) @@ -35,22 +37,27 @@ This document details the beacon chain additions and changes of to support the W ## Constants +### Domain types + +| Name | Value | +| ---------------------------------- | -------------------------- | +| `DOMAIN_WHISK_CANDIDATE_SELECTION` | `DomainType('0x07000000')` | +| `DOMAIN_WHISK_SHUFFLE` | `DomainType('0x07100000')` | +| `DOMAIN_WHISK_PROPOSER_SELECTION` | `DomainType('0x07200000')` | + +## Preset + | Name | Value | Description | | ---------------------------------- | -------------------------- | ----------------------------------------------------------- | +| `CURDLEPROOFS_N_BLINDERS` | `uint64(4)` | number of blinders for curdleproofs | | `WHISK_CANDIDATE_TRACKERS_COUNT` | `uint64(2**14)` (= 16,384) | number of candidate trackers | | `WHISK_PROPOSER_TRACKERS_COUNT` | `uint64(2**13)` (= 8,192) | number of proposer trackers | | `WHISK_EPOCHS_PER_SHUFFLING_PHASE` | `Epoch(2**8)` (= 256) | epochs per shuffling phase | -| `WHISK_VALIDATORS_PER_SHUFFLE` | `uint64(2**7)` (= 128) | number of validators shuffled per shuffle step | +| `WHISK_VALIDATORS_PER_SHUFFLE` | `uint64(2**7 - 4)` (= 124) | number of validators shuffled per shuffle step | | `WHISK_PROPOSER_SELECTION_GAP` | `Epoch(2)` | gap between proposer selection and the block proposal phase | | `WHISK_MAX_SHUFFLE_PROOF_SIZE` | `uint64(2**15)` | max size of a shuffle proof | | `WHISK_MAX_OPENING_PROOF_SIZE` | `uint64(2**10)` | max size of a opening proof | -| Name | Value | -| ---------------------------------- | -------------------------- | -| `DOMAIN_WHISK_CANDIDATE_SELECTION` | `DomainType('0x07000000')` | -| `DOMAIN_WHISK_SHUFFLE` | `DomainType('0x07100000')` | -| `DOMAIN_WHISK_PROPOSER_SELECTION` | `DomainType('0x07200000')` | - ## Cryptography ### BLS From 919052081bf8860e45240114e6943f255ea7f352 Mon Sep 17 00:00:00 2001 From: djrtwo Date: Mon, 19 Jun 2023 08:33:05 -0600 Subject: [PATCH 35/44] toc --- specs/deneb/beacon-chain.md | 8 +++++--- specs/phase0/p2p-interface.md | 2 +- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/specs/deneb/beacon-chain.md b/specs/deneb/beacon-chain.md index 8901b35f6e..69aa16ecd0 100644 --- a/specs/deneb/beacon-chain.md +++ b/specs/deneb/beacon-chain.md @@ -24,7 +24,8 @@ - [Helper functions](#helper-functions) - [Misc](#misc) - [`kzg_commitment_to_versioned_hash`](#kzg_commitment_to_versioned_hash) - - [Modified `get_attestation_participation_flag_indicies`](#modified-get_attestation_participation_flag_indicies) + - [Beacon state accessors](#beacon-state-accessors) + - [Modified `get_attestation_participation_flag_indices`](#modified-get_attestation_participation_flag_indices) - [Beacon chain state transition function](#beacon-chain-state-transition-function) - [Execution engine](#execution-engine) - [Request data](#request-data) @@ -173,7 +174,9 @@ def kzg_commitment_to_versioned_hash(kzg_commitment: KZGCommitment) -> Versioned return VERSIONED_HASH_VERSION_KZG + hash(kzg_commitment)[1:] ``` -### Modified `get_attestation_participation_flag_indicies` +### Beacon state accessors + +#### Modified `get_attestation_participation_flag_indices` *Note:* The function `get_attestation_participation_flag_indicies` is modified to set the `TIMELY_TARGET_FLAG` for any correct target attestation, regardless of `inclusion_delay` as a baseline reward for any speed of inclusion of an attestation that contributes to justification of the contained chain for EIP-7045. @@ -206,7 +209,6 @@ def get_attestation_participation_flag_indices(state: BeaconState, return participation_flag_indices ``` - ## Beacon chain state transition function ### Execution engine diff --git a/specs/phase0/p2p-interface.md b/specs/phase0/p2p-interface.md index 14427c79ce..bbb4c4d427 100644 --- a/specs/phase0/p2p-interface.md +++ b/specs/phase0/p2p-interface.md @@ -55,7 +55,7 @@ It consists of four main sections: - [ENR structure](#enr-structure) - [Attestation subnet bitfield](#attestation-subnet-bitfield) - [`eth2` field](#eth2-field) - - [Attestation subnet subcription](#attestation-subnet-subcription) + - [Attestation subnet subscription](#attestation-subnet-subscription) - [Design decision rationale](#design-decision-rationale) - [Transport](#transport-1) - [Why are we defining specific transports?](#why-are-we-defining-specific-transports) From fd9a72e74a17ee15a4c4556b80d28d187a778df4 Mon Sep 17 00:00:00 2001 From: djrtwo Date: Mon, 19 Jun 2023 08:40:31 -0600 Subject: [PATCH 36/44] add 7045 fork boundary test --- .../eth2spec/test/deneb/sanity/test_blocks.py | 44 ++++++++++++++++++- 1 file changed, 42 insertions(+), 2 deletions(-) diff --git a/tests/core/pyspec/eth2spec/test/deneb/sanity/test_blocks.py b/tests/core/pyspec/eth2spec/test/deneb/sanity/test_blocks.py index 2af330efba..3b2a767f06 100644 --- a/tests/core/pyspec/eth2spec/test/deneb/sanity/test_blocks.py +++ b/tests/core/pyspec/eth2spec/test/deneb/sanity/test_blocks.py @@ -1,16 +1,24 @@ from eth2spec.test.helpers.state import ( - state_transition_and_sign_block + state_transition_and_sign_block, + next_epoch_via_block, + transition_to, ) from eth2spec.test.helpers.block import ( - build_empty_block_for_next_slot + build_empty_block_for_next_slot, ) from eth2spec.test.context import ( + DENEB, spec_state_test, + spec_configured_state_test, with_deneb_and_later, + with_phases, ) from eth2spec.test.helpers.execution_payload import ( compute_el_block_hash, ) +from eth2spec.test.helpers.attestations import ( + get_valid_attestation, +) from eth2spec.test.helpers.sharding import ( get_sample_opaque_tx, ) @@ -58,3 +66,35 @@ def test_max_blobs_per_block(spec, state): @spec_state_test def test_invalid_exceed_max_blobs_per_block(spec, state): yield from run_block_with_blobs(spec, state, blob_count=spec.MAX_BLOBS_PER_BLOCK + 1, valid=False) + + +@with_phases([DENEB]) +@spec_configured_state_test({ + 'DENEB_FORK_EPOCH': 2, +}) +def test_include_attestation_from_previous_fork_with_new_range(spec, state): + # Transition to the epoch prior to the fork epoch + next_epoch_via_block(spec, state) + + # Generate an attestation for slot 0 of this epoch + attestation = get_valid_attestation(spec, state, signed=True) + + # Transition to second to last slot in `DENEB_FORK_EPOCH + next_epoch_via_block(spec, state) + current_epoch = spec.get_current_epoch(state) + assert current_epoch == spec.config.DENEB_FORK_EPOCH + penultimate_slot = spec.compute_start_slot_at_epoch(current_epoch + 1) - 2 + transition_to(spec, state, penultimate_slot) + + # Ensure the new state is in the increased EIP-7045 slot inclusion range + assert penultimate_slot - attestation.data.slot > spec.SLOTS_PER_EPOCH + + block = build_empty_block_for_next_slot(spec, state) + block.body.attestations.append(attestation) + + yield 'pre', state + + signed_block = state_transition_and_sign_block(spec, state, block) + + yield 'blocks', [signed_block] + yield 'post', state From 668568ea22195c18ddfd6053e7c27c3f25f58621 Mon Sep 17 00:00:00 2001 From: djrtwo Date: Mon, 19 Jun 2023 12:05:49 -0600 Subject: [PATCH 37/44] spelling --- specs/deneb/beacon-chain.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/specs/deneb/beacon-chain.md b/specs/deneb/beacon-chain.md index 69aa16ecd0..2726d1648f 100644 --- a/specs/deneb/beacon-chain.md +++ b/specs/deneb/beacon-chain.md @@ -178,7 +178,7 @@ def kzg_commitment_to_versioned_hash(kzg_commitment: KZGCommitment) -> Versioned #### Modified `get_attestation_participation_flag_indices` -*Note:* The function `get_attestation_participation_flag_indicies` is modified to set the `TIMELY_TARGET_FLAG` for any correct target attestation, regardless of `inclusion_delay` as a baseline reward for any speed of inclusion of an attestation that contributes to justification of the contained chain for EIP-7045. +*Note:* The function `get_attestation_participation_flag_indices` is modified to set the `TIMELY_TARGET_FLAG` for any correct target attestation, regardless of `inclusion_delay` as a baseline reward for any speed of inclusion of an attestation that contributes to justification of the contained chain for EIP-7045. ```python def get_attestation_participation_flag_indices(state: BeaconState, From ecefe2d14791675ec9c1e0b62ed16cbf2251a585 Mon Sep 17 00:00:00 2001 From: djrtwo Date: Tue, 20 Jun 2023 15:50:20 -0600 Subject: [PATCH 38/44] pr review --- .gitignore | 1 - specs/deneb/p2p-interface.md | 4 ++-- tests/core/pyspec/eth2spec/test/deneb/sanity/test_blocks.py | 2 +- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/.gitignore b/.gitignore index bee57e2c6e..2ff10cf099 100644 --- a/.gitignore +++ b/.gitignore @@ -22,7 +22,6 @@ tests/core/pyspec/eth2spec/bellatrix/ tests/core/pyspec/eth2spec/capella/ tests/core/pyspec/eth2spec/deneb/ tests/core/pyspec/eth2spec/eip6110/ -tests/core/pyspec/eth2spec/eip7045/ tests/core/pyspec/eth2spec/whisk/ # coverage reports diff --git a/specs/deneb/p2p-interface.md b/specs/deneb/p2p-interface.md index f073b50f5c..f857ffdf13 100644 --- a/specs/deneb/p2p-interface.md +++ b/specs/deneb/p2p-interface.md @@ -25,7 +25,7 @@ The specification of these changes continues in the same format as the network s - [`blob_sidecar_{subnet_id}`](#blob_sidecar_subnet_id) - [`beacon_aggregate_and_proof`](#beacon_aggregate_and_proof) - [Attestation subnets](#attestation-subnets) - - [`beacon_attestation_{subnet_id}](#beacon_attestation_subnet_id) + - [`beacon_attestation_{subnet_id}`](#beacon_attestation_subnet_id) - [Transitioning the gossip](#transitioning-the-gossip) - [The Req/Resp domain](#the-reqresp-domain) - [Messages](#messages) @@ -178,7 +178,7 @@ The following validations are added in its place: ##### Attestation subnets -###### `beacon_attestation_{subnet_id} +###### `beacon_attestation_{subnet_id}` *[Modified in Deneb:EIP7045]* diff --git a/tests/core/pyspec/eth2spec/test/deneb/sanity/test_blocks.py b/tests/core/pyspec/eth2spec/test/deneb/sanity/test_blocks.py index 3b2a767f06..c64efe747b 100644 --- a/tests/core/pyspec/eth2spec/test/deneb/sanity/test_blocks.py +++ b/tests/core/pyspec/eth2spec/test/deneb/sanity/test_blocks.py @@ -79,7 +79,7 @@ def test_include_attestation_from_previous_fork_with_new_range(spec, state): # Generate an attestation for slot 0 of this epoch attestation = get_valid_attestation(spec, state, signed=True) - # Transition to second to last slot in `DENEB_FORK_EPOCH + # Transition to second to last slot in `DENEB_FORK_EPOCH` next_epoch_via_block(spec, state) current_epoch = spec.get_current_epoch(state) assert current_epoch == spec.config.DENEB_FORK_EPOCH From 57a75d033f6df4c27f20e7905410a038c4610b75 Mon Sep 17 00:00:00 2001 From: Alex Stokes Date: Mon, 12 Jun 2023 12:27:33 -0600 Subject: [PATCH 39/44] formatting --- specs/deneb/beacon-chain.md | 1 - 1 file changed, 1 deletion(-) diff --git a/specs/deneb/beacon-chain.md b/specs/deneb/beacon-chain.md index 2726d1648f..b2bbf76160 100644 --- a/specs/deneb/beacon-chain.md +++ b/specs/deneb/beacon-chain.md @@ -86,7 +86,6 @@ and are limited by `MAX_DATA_GAS_PER_BLOCK // DATA_GAS_PER_BLOB`. However the CL ## Configuration - ## Containers ### Extended containers From 2660af05390aa61f06142e1c6311a3a3c633f720 Mon Sep 17 00:00:00 2001 From: Alex Stokes Date: Mon, 12 Jun 2023 12:29:07 -0600 Subject: [PATCH 40/44] move 4788 feature to deneb specs --- setup.py | 8 ++- specs/_features/eip4788/beacon-chain.md | 72 -------------------- specs/_features/eip4788/validator.md | 88 ------------------------- specs/_features/eip6110/beacon-chain.md | 8 ++- specs/deneb/beacon-chain.md | 46 +++++++++++-- specs/deneb/fork-choice.md | 19 +++++- specs/deneb/validator.md | 38 ++++++++++- 7 files changed, 108 insertions(+), 171 deletions(-) delete mode 100644 specs/_features/eip4788/beacon-chain.md delete mode 100644 specs/_features/eip4788/validator.md diff --git a/setup.py b/setup.py index b1ab11c38a..5dfe29c2ae 100644 --- a/setup.py +++ b/setup.py @@ -726,7 +726,9 @@ def execution_engine_cls(cls) -> str: return "\n\n" + """ class NoopExecutionEngine(ExecutionEngine): - def notify_new_payload(self: ExecutionEngine, execution_payload: ExecutionPayload) -> bool: + def notify_new_payload(self: ExecutionEngine, + execution_payload: ExecutionPayload, + parent_beacon_block_root: Root) -> bool: return True def notify_forkchoice_updated(self: ExecutionEngine, @@ -740,7 +742,9 @@ def get_payload(self: ExecutionEngine, payload_id: PayloadId) -> GetPayloadRespo # pylint: disable=unused-argument raise NotImplementedError("no default block production") - def is_valid_block_hash(self: ExecutionEngine, execution_payload: ExecutionPayload) -> bool: + def is_valid_block_hash(self: ExecutionEngine, + execution_payload: ExecutionPayload, + parent_beacon_block_root: Root) -> bool: return True def is_valid_versioned_hashes(self: ExecutionEngine, new_payload_request: NewPayloadRequest) -> bool: diff --git a/specs/_features/eip4788/beacon-chain.md b/specs/_features/eip4788/beacon-chain.md deleted file mode 100644 index 6cd876de99..0000000000 --- a/specs/_features/eip4788/beacon-chain.md +++ /dev/null @@ -1,72 +0,0 @@ -# EIP-4788 -- The Beacon Chain - -## Table of contents - - - - - -- [Introduction](#introduction) -- [Containers](#containers) - - [Extended Containers](#extended-containers) - - [`ExecutionPayload`](#executionpayload) - - [`ExecutionPayloadHeader`](#executionpayloadheader) - - - - -## Introduction - -TODO - -## Containers - -### Extended Containers - -#### `ExecutionPayload` - -```python -class ExecutionPayload(Container): - # Execution block header fields - parent_hash: Hash32 - fee_recipient: ExecutionAddress # 'beneficiary' in the yellow paper - state_root: Bytes32 - receipts_root: Bytes32 - logs_bloom: ByteVector[BYTES_PER_LOGS_BLOOM] - prev_randao: Bytes32 # 'difficulty' in the yellow paper - block_number: uint64 # 'number' in the yellow paper - gas_limit: uint64 - gas_used: uint64 - timestamp: uint64 - extra_data: ByteList[MAX_EXTRA_DATA_BYTES] - base_fee_per_gas: uint256 - # Extra payload fields - block_hash: Hash32 # Hash of execution block - transactions: List[Transaction, MAX_TRANSACTIONS_PER_PAYLOAD] - withdrawals: List[Withdrawal, MAX_WITHDRAWALS_PER_PAYLOAD] - parent_beacon_block_root: Root # [New in EIP-4788] -``` - -#### `ExecutionPayloadHeader` - -```python -class ExecutionPayloadHeader(Container): - # Execution block header fields - parent_hash: Hash32 - fee_recipient: ExecutionAddress - state_root: Bytes32 - receipts_root: Bytes32 - logs_bloom: ByteVector[BYTES_PER_LOGS_BLOOM] - prev_randao: Bytes32 - block_number: uint64 - gas_limit: uint64 - gas_used: uint64 - timestamp: uint64 - extra_data: ByteList[MAX_EXTRA_DATA_BYTES] - base_fee_per_gas: uint256 - # Extra payload fields - block_hash: Hash32 # Hash of execution block - transactions_root: Root - withdrawals_root: Root - parent_beacon_block_root: Root # [New in EIP-4788] -``` diff --git a/specs/_features/eip4788/validator.md b/specs/_features/eip4788/validator.md deleted file mode 100644 index 11462bda1d..0000000000 --- a/specs/_features/eip4788/validator.md +++ /dev/null @@ -1,88 +0,0 @@ -# EIP-4788 -- Honest Validator - -**Notice**: This document is a work-in-progress for researchers and implementers. - -## Table of contents - - - - - -- [Introduction](#introduction) -- [Prerequisites](#prerequisites) -- [Helpers](#helpers) -- [Protocols](#protocols) - - [`ExecutionEngine`](#executionengine) - - [Modified `get_payload`](#modified-get_payload) -- [Beacon chain responsibilities](#beacon-chain-responsibilities) - - [Block proposal](#block-proposal) - - [Constructing the `BeaconBlockBody`](#constructing-the-beaconblockbody) - - [ExecutionPayload](#executionpayload) - - - - -## Introduction - -This document represents the changes to be made in the code of an "honest validator" to implement the EIP-4788 feature. - -## Prerequisites - -This document is an extension of the [Capella -- Honest Validator](../capella/validator.md) guide. -All behaviors and definitions defined in this document, and documents it extends, carry over unless explicitly noted or overridden. - -All terminology, constants, functions, and protocol mechanics defined in the updated Beacon Chain doc of [Capella](../capella/beacon-chain.md) are requisite for this document and used throughout. -Please see related Beacon Chain doc before continuing and use them as a reference throughout. - -## Helpers - -## Protocols - -### `ExecutionEngine` - -#### Modified `get_payload` - -`get_payload` returns the upgraded EIP-4788 `ExecutionPayload` type. - -## Beacon chain responsibilities - -All validator responsibilities remain unchanged other than those noted below. - -### Block proposal - -#### Constructing the `BeaconBlockBody` - -##### ExecutionPayload - -`ExecutionPayload`s are constructed as they were in Capella, except that the parent beacon block root is also supplied. - -*Note*: In this section, `state` is the state of the slot for the block proposal _without_ the block yet applied. -That is, `state` is the `previous_state` processed through any empty slots up to the assigned slot using `process_slots(previous_state, slot)`. - -*Note*: The only change made to `prepare_execution_payload` is to add the parent beacon block root as an additional -parameter to the `PayloadAttributes`. - -```python -def prepare_execution_payload(state: BeaconState, - safe_block_hash: Hash32, - finalized_block_hash: Hash32, - suggested_fee_recipient: ExecutionAddress, - execution_engine: ExecutionEngine) -> Optional[PayloadId]: - # Verify consistency of the parent hash with respect to the previous execution payload header - parent_hash = state.latest_execution_payload_header.block_hash - - # Set the forkchoice head and initiate the payload build process - payload_attributes = PayloadAttributes( - timestamp=compute_timestamp_at_slot(state, state.slot), - prev_randao=get_randao_mix(state, get_current_epoch(state)), - suggested_fee_recipient=suggested_fee_recipient, - withdrawals=get_expected_withdrawals(state), - parent_beacon_block_root=hash_tree_root(state.latest_block_header), # [New in EIP-4788] - ) - return execution_engine.notify_forkchoice_updated( - head_block_hash=parent_hash, - safe_block_hash=safe_block_hash, - finalized_block_hash=finalized_block_hash, - payload_attributes=payload_attributes, - ) -``` diff --git a/specs/_features/eip6110/beacon-chain.md b/specs/_features/eip6110/beacon-chain.md index 1bfa29138a..44980685c4 100644 --- a/specs/_features/eip6110/beacon-chain.md +++ b/specs/_features/eip6110/beacon-chain.md @@ -224,7 +224,7 @@ def process_deposit_receipt(state: BeaconState, deposit_receipt: DepositReceipt) state.deposit_receipts_start_index = deposit_receipt.index apply_deposit( - state=state, + state=state, pubkey=deposit_receipt.pubkey, withdrawal_credentials=deposit_receipt.withdrawal_credentials, amount=deposit_receipt.amount, @@ -251,7 +251,11 @@ def process_execution_payload(state: BeaconState, body: BeaconBlockBody, executi # Verify the execution payload is valid versioned_hashes = [kzg_commitment_to_versioned_hash(commitment) for commitment in body.blob_kzg_commitments] assert execution_engine.verify_and_notify_new_payload( - NewPayloadRequest(execution_payload=payload, versioned_hashes=versioned_hashes) + NewPayloadRequest( + execution_payload=payload, + versioned_hashes=versioned_hashes, + parent_beacon_block_root=state.latest_block_header.parent_root, + ) ) # Cache execution payload header state.latest_execution_payload_header = ExecutionPayloadHeader( diff --git a/specs/deneb/beacon-chain.md b/specs/deneb/beacon-chain.md index b2bbf76160..9228a7d8f3 100644 --- a/specs/deneb/beacon-chain.md +++ b/specs/deneb/beacon-chain.md @@ -31,7 +31,9 @@ - [Request data](#request-data) - [Modified `NewPayloadRequest`](#modified-newpayloadrequest) - [Engine APIs](#engine-apis) + - [`is_valid_block_hash`](#is_valid_block_hash) - [`is_valid_versioned_hashes`](#is_valid_versioned_hashes) + - [Modified `notify_new_payload`](#modified-notify_new_payload) - [Modified `verify_and_notify_new_payload`](#modified-verify_and_notify_new_payload) - [Block processing](#block-processing) - [Modified `process_attestation`](#modified-process_attestation) @@ -46,6 +48,7 @@ ## Introduction Deneb is a consensus-layer upgrade containing a number of features. Including: +* [EIP-4788](https://eips.ethereum.org/EIPS/eip-4788): Beacon block root in the EVM * [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 @@ -221,10 +224,23 @@ def get_attestation_participation_flag_indices(state: BeaconState, class NewPayloadRequest(object): execution_payload: ExecutionPayload versioned_hashes: Sequence[VersionedHash] + parent_beacon_block_root: Root ``` #### Engine APIs +##### `is_valid_block_hash` + +```python +def is_valid_block_hash(self: ExecutionEngine, + execution_payload: ExecutionPayload, + parent_beacon_block_root: Root) -> bool: + """ + Return ``True`` if and only if ``execution_payload.block_hash`` is computed correctly. + """ + ... +``` + ##### `is_valid_versioned_hashes` ```python @@ -236,6 +252,18 @@ def is_valid_versioned_hashes(self: ExecutionEngine, new_payload_request: NewPay ... ``` +##### Modified `notify_new_payload` + +```python +def notify_new_payload(self: ExecutionEngine, + execution_payload: ExecutionPayload, + parent_beacon_block_root: Root) -> bool: + """ + Return ``True`` if and only if ``execution_payload`` is valid with respect to ``self.execution_state``. + """ + ... +``` + ##### Modified `verify_and_notify_new_payload` ```python @@ -244,14 +272,19 @@ def verify_and_notify_new_payload(self: ExecutionEngine, """ Return ``True`` if and only if ``new_payload_request`` is valid with respect to ``self.execution_state``. """ - if not self.is_valid_block_hash(new_payload_request.execution_payload): + execution_payload = new_payload_request.execution_payload + parent_beacon_block_root = new_payload_request.parent_beacon_block_root + + # [New in Deneb:EIP4788] + if not self.is_valid_block_hash(execution_payload, parent_beacon_block_root): return False # [New in Deneb:EIP4844] if not self.is_valid_versioned_hashes(new_payload_request): return False - if not self.notify_new_payload(new_payload_request.execution_payload): + # [New in Deneb:EIP4788] + if not self.notify_new_payload(execution_payload, parent_beacon_block_root): return False return True @@ -303,7 +336,7 @@ def process_attestation(state: BeaconState, attestation: Attestation) -> None: ##### Modified `process_execution_payload` -*Note*: The function `process_execution_payload` is modified to pass `versioned_hashes` into `execution_engine.verify_and_notify_new_payload` and to assign the new fields in `ExecutionPayloadHeader` for EIP-4844. +*Note*: The function `process_execution_payload` is modified to pass `versioned_hashes` into `execution_engine.verify_and_notify_new_payload` and to assign the new fields in `ExecutionPayloadHeader` for EIP-4844. It is also modified to pass in the parent beacon block root to support EIP-4788. ```python def process_execution_payload(state: BeaconState, body: BeaconBlockBody, execution_engine: ExecutionEngine) -> None: @@ -321,9 +354,14 @@ def process_execution_payload(state: BeaconState, body: BeaconBlockBody, executi # Verify the execution payload is valid # [Modified in Deneb:EIP4844] Pass `versioned_hashes` to Execution Engine + # [Modified in Deneb:EIP4788] Pass parent beacon block root to Execution Engine versioned_hashes = [kzg_commitment_to_versioned_hash(commitment) for commitment in body.blob_kzg_commitments] assert execution_engine.verify_and_notify_new_payload( - NewPayloadRequest(execution_payload=payload, versioned_hashes=versioned_hashes) + NewPayloadRequest( + execution_payload=payload, + versioned_hashes=versioned_hashes, + parent_beacon_block_root=state.latest_block_header.parent_root, + ) ) # Cache execution payload header diff --git a/specs/deneb/fork-choice.md b/specs/deneb/fork-choice.md index bbc7fa0f89..d7d2eaa2fc 100644 --- a/specs/deneb/fork-choice.md +++ b/specs/deneb/fork-choice.md @@ -8,7 +8,8 @@ - [Introduction](#introduction) - [Containers](#containers) - [Helpers](#helpers) - - [`is_data_available`](#is_data_available) + - [Extended `PayloadAttributes`](#extended-payloadattributes) + - [`is_data_available`](#is_data_available) - [Updated fork-choice handlers](#updated-fork-choice-handlers) - [`on_block`](#on_block) @@ -23,7 +24,21 @@ This is the modification of the fork choice accompanying the Deneb upgrade. ## Helpers -#### `is_data_available` +### Extended `PayloadAttributes` + +`PayloadAttributes` is extended with the parent beacon block root. + +```python +@dataclass +class PayloadAttributes(object): + timestamp: uint64 + prev_randao: Bytes32 + suggested_fee_recipient: ExecutionAddress + withdrawals: Sequence[Withdrawal] + parent_beacon_block_root: Root # [New in Deneb:EIP4788] +``` + +### `is_data_available` *[New in Deneb:EIP4844]* diff --git a/specs/deneb/validator.md b/specs/deneb/validator.md index 3157ccf218..7b8a81b19a 100644 --- a/specs/deneb/validator.md +++ b/specs/deneb/validator.md @@ -19,6 +19,7 @@ - [Beacon chain responsibilities](#beacon-chain-responsibilities) - [Block and sidecar proposal](#block-and-sidecar-proposal) - [Constructing the `BeaconBlockBody`](#constructing-the-beaconblockbody) + - [ExecutionPayload](#executionpayload) - [Blob KZG commitments](#blob-kzg-commitments) - [Constructing the `SignedBlobSidecar`s](#constructing-the-signedblobsidecars) - [Sidecar](#sidecar) @@ -88,11 +89,46 @@ All validator responsibilities remain unchanged other than those noted below. #### Constructing the `BeaconBlockBody` +##### ExecutionPayload + +`prepare_execution_payload` is updated from the Capella specs to provide the parent beacon block root. + +*Note*: In this section, `state` is the state of the slot for the block proposal _without_ the block yet applied. +That is, `state` is the `previous_state` processed through any empty slots up to the assigned slot using `process_slots(previous_state, slot)`. + +*Note*: The only change made to `prepare_execution_payload` is to add the parent beacon block root as an additional +parameter to the `PayloadAttributes`. + +```python +def prepare_execution_payload(state: BeaconState, + safe_block_hash: Hash32, + finalized_block_hash: Hash32, + suggested_fee_recipient: ExecutionAddress, + execution_engine: ExecutionEngine) -> Optional[PayloadId]: + # Verify consistency of the parent hash with respect to the previous execution payload header + parent_hash = state.latest_execution_payload_header.block_hash + + # Set the forkchoice head and initiate the payload build process + payload_attributes = PayloadAttributes( + timestamp=compute_timestamp_at_slot(state, state.slot), + prev_randao=get_randao_mix(state, get_current_epoch(state)), + suggested_fee_recipient=suggested_fee_recipient, + withdrawals=get_expected_withdrawals(state), + parent_beacon_block_root=hash_tree_root(state.latest_block_header), # [New in Deneb:EIP4788] + ) + return execution_engine.notify_forkchoice_updated( + head_block_hash=parent_hash, + safe_block_hash=safe_block_hash, + finalized_block_hash=finalized_block_hash, + payload_attributes=payload_attributes, + ) +``` + ##### Blob KZG commitments *[New in Deneb:EIP4844]* -1. After retrieving the execution payload from the execution engine as specified in Capella, +1. After retrieving the execution payload from the execution engine as specified above, use the `payload_id` to retrieve `blobs`, `blob_kzg_commitments`, and `blob_kzg_proofs` via `get_payload(payload_id).blobs_bundle`. 2. Set `block.body.blob_kzg_commitments = blob_kzg_commitments`. From 67df56641135a6dfcdd014729852f39337637e05 Mon Sep 17 00:00:00 2001 From: parithosh Date: Thu, 22 Jun 2023 17:19:36 +0200 Subject: [PATCH 41/44] removing manual workflow branch input --- .github/workflows/run-tests.yml | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) diff --git a/.github/workflows/run-tests.yml b/.github/workflows/run-tests.yml index b27c907654..6b24ef5eb1 100644 --- a/.github/workflows/run-tests.yml +++ b/.github/workflows/run-tests.yml @@ -6,10 +6,8 @@ defaults: env: TEST_PRESET_TYPE: "minimal" - DEFAULT_BRANCH: "dev" -# Run tests on workflow_Dispatch -on: +on: push: branches: - dev @@ -22,10 +20,6 @@ on: description: Type of test to run, either mainnet or minimal type: string required: true - commitRef: - description: The branch, tag or SHA to checkout and build from - default: dev - required: true schedule: - cron: '0 0 * * *' @@ -47,8 +41,6 @@ jobs: steps: - name: Checkout this repo uses: actions/checkout@v3.2.0 - with: - ref: ${{ github.event.inputs.commitRef || env.DEFAULT_BRANCH }} - name: Check table of contents run: sudo npm install -g doctoc@2.2.0 && make check_toc @@ -58,8 +50,6 @@ jobs: steps: - name: Checkout this repo uses: actions/checkout@v3.2.0 - with: - ref: ${{ github.event.inputs.commitRef || env.DEFAULT_BRANCH }} - name: Check codespell run: pip install 'codespell<3.0.0,>=2.0.0' --user && make codespell @@ -69,8 +59,6 @@ jobs: steps: - name: Checkout this repo uses: actions/checkout@v3.2.0 - with: - ref: ${{ github.event.inputs.commitRef || env.DEFAULT_BRANCH }} - name: Install pyspec requirements run: make install_test - name: Run linter for pyspec @@ -87,8 +75,6 @@ jobs: steps: - name: Checkout this repo uses: actions/checkout@v3.2.0 - with: - ref: ${{ github.event.inputs.commitRef || env.DEFAULT_BRANCH }} - name: set TEST_PRESET_TYPE if: github.event.inputs.test_preset_type != '' run: | From ad4f1def322f12e1ca36ddf49d7c4111551f2552 Mon Sep 17 00:00:00 2001 From: Danny Ryan Date: Thu, 22 Jun 2023 10:01:49 -0600 Subject: [PATCH 42/44] Apply suggestions from code review --- specs/deneb/beacon-chain.md | 8 +++++--- specs/deneb/fork-choice.md | 2 +- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/specs/deneb/beacon-chain.md b/specs/deneb/beacon-chain.md index 9228a7d8f3..abc1403d53 100644 --- a/specs/deneb/beacon-chain.md +++ b/specs/deneb/beacon-chain.md @@ -231,6 +231,8 @@ class NewPayloadRequest(object): ##### `is_valid_block_hash` +*Note*: The function `is_valid_block_hash` is modified to include the additional `parent_beacon_block_root` parameter for EIP-4788. + ```python def is_valid_block_hash(self: ExecutionEngine, execution_payload: ExecutionPayload, @@ -275,7 +277,7 @@ def verify_and_notify_new_payload(self: ExecutionEngine, execution_payload = new_payload_request.execution_payload parent_beacon_block_root = new_payload_request.parent_beacon_block_root - # [New in Deneb:EIP4788] + # [Modified in Deneb:EIP4788] if not self.is_valid_block_hash(execution_payload, parent_beacon_block_root): return False @@ -283,7 +285,7 @@ def verify_and_notify_new_payload(self: ExecutionEngine, if not self.is_valid_versioned_hashes(new_payload_request): return False - # [New in Deneb:EIP4788] + # [Modified in Deneb:EIP4788] if not self.notify_new_payload(execution_payload, parent_beacon_block_root): return False @@ -354,7 +356,7 @@ def process_execution_payload(state: BeaconState, body: BeaconBlockBody, executi # Verify the execution payload is valid # [Modified in Deneb:EIP4844] Pass `versioned_hashes` to Execution Engine - # [Modified in Deneb:EIP4788] Pass parent beacon block root to Execution Engine + # [Modified in Deneb:EIP4788] Pass `parent_beacon_block_root` to Execution Engine versioned_hashes = [kzg_commitment_to_versioned_hash(commitment) for commitment in body.blob_kzg_commitments] assert execution_engine.verify_and_notify_new_payload( NewPayloadRequest( diff --git a/specs/deneb/fork-choice.md b/specs/deneb/fork-choice.md index d7d2eaa2fc..23eef436c1 100644 --- a/specs/deneb/fork-choice.md +++ b/specs/deneb/fork-choice.md @@ -26,7 +26,7 @@ This is the modification of the fork choice accompanying the Deneb upgrade. ### Extended `PayloadAttributes` -`PayloadAttributes` is extended with the parent beacon block root. +`PayloadAttributes` is extended with the parent beacon block root for EIP-4788. ```python @dataclass From fa649e543092657d56ff732877bd053215f99719 Mon Sep 17 00:00:00 2001 From: Danny Ryan Date: Thu, 22 Jun 2023 10:02:23 -0600 Subject: [PATCH 43/44] Update specs/deneb/beacon-chain.md --- specs/deneb/beacon-chain.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/specs/deneb/beacon-chain.md b/specs/deneb/beacon-chain.md index abc1403d53..321dfb25e3 100644 --- a/specs/deneb/beacon-chain.md +++ b/specs/deneb/beacon-chain.md @@ -256,6 +256,8 @@ def is_valid_versioned_hashes(self: ExecutionEngine, new_payload_request: NewPay ##### Modified `notify_new_payload` +*Note*: The function `notify_new_payload` is modified to include the additional `parent_beacon_block_root` parameter for EIP-4788. + ```python def notify_new_payload(self: ExecutionEngine, execution_payload: ExecutionPayload, From 981611baea73296be6f6c483b127a73d73d5b4b9 Mon Sep 17 00:00:00 2001 From: djrtwo Date: Thu, 22 Jun 2023 15:14:11 -0600 Subject: [PATCH 44/44] bump version to 1.4.0-beta.0 --- tests/core/pyspec/eth2spec/VERSION.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/core/pyspec/eth2spec/VERSION.txt b/tests/core/pyspec/eth2spec/VERSION.txt index 45eafc27d4..c431216bf2 100644 --- a/tests/core/pyspec/eth2spec/VERSION.txt +++ b/tests/core/pyspec/eth2spec/VERSION.txt @@ -1 +1 @@ -1.4.0-alpha.3 +1.4.0-beta.0