From 4c29b0ba197f53b220ffd05d52d9e52b3f358a05 Mon Sep 17 00:00:00 2001 From: Alex Stokes Date: Wed, 12 Jun 2024 09:56:08 -0600 Subject: [PATCH 01/23] specify the max blobs per block when building a payload --- specs/electra/fork-choice.md | 37 ++++++++++++++++++++++++++++++++++++ specs/electra/validator.md | 1 + 2 files changed, 38 insertions(+) create mode 100644 specs/electra/fork-choice.md diff --git a/specs/electra/fork-choice.md b/specs/electra/fork-choice.md new file mode 100644 index 0000000000..a143d43b80 --- /dev/null +++ b/specs/electra/fork-choice.md @@ -0,0 +1,37 @@ +# Electra -- Fork Choice + +## Table of contents + + + + +- [Introduction](#introduction) +- [Containers](#containers) +- [Helpers](#helpers) + - [Extended `PayloadAttributes`](#extended-payloadattributes) + + + + +## Introduction + +This is the modification of the fork choice accompanying the Electra upgrade. + +## Containers + +## Helpers + +### Extended `PayloadAttributes` + +`PayloadAttributes` is extended with the maximum number of blobs per block. + +```python +@dataclass +class PayloadAttributes(object): + timestamp: uint64 + prev_randao: Bytes32 + suggested_fee_recipient: ExecutionAddress + withdrawals: Sequence[Withdrawal] + parent_beacon_block_root: Root + max_blobs_per_block: uint64 # [New in Electra] +``` diff --git a/specs/electra/validator.md b/specs/electra/validator.md index f589e963c5..3bae8250ea 100644 --- a/specs/electra/validator.md +++ b/specs/electra/validator.md @@ -139,6 +139,7 @@ def prepare_execution_payload(state: BeaconState, suggested_fee_recipient=suggested_fee_recipient, withdrawals=withdrawals, parent_beacon_block_root=hash_tree_root(state.latest_block_header), + max_blobs_per_block=MAX_BLOBS_PER_BLOCK, # [New in Electra] ) return execution_engine.notify_forkchoice_updated( head_block_hash=parent_hash, From 71f2912e41cf1f7e1d4ccb3d07cd1743b57b4d78 Mon Sep 17 00:00:00 2001 From: Alex Stokes Date: Wed, 12 Jun 2024 14:34:52 -0600 Subject: [PATCH 02/23] specify the maximum number of blobs for each payload --- specs/electra/beacon-chain.md | 53 +++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/specs/electra/beacon-chain.md b/specs/electra/beacon-chain.md index d9e9d1f27b..62a8a2292d 100644 --- a/specs/electra/beacon-chain.md +++ b/specs/electra/beacon-chain.md @@ -67,6 +67,11 @@ - [New `compute_consolidation_epoch_and_update_churn`](#new-compute_consolidation_epoch_and_update_churn) - [Updated `slash_validator`](#updated-slash_validator) - [Beacon chain state transition function](#beacon-chain-state-transition-function) + - [Execution engine](#execution-engine) + - [Request data](#request-data) + - [Engine APIs](#engine-apis) + - [Modified `notify_new_payload`](#modified-notify_new_payload) + - [Modified `verify_and_notify_new_payload`](#modified-verify_and_notify_new_payload) - [Epoch processing](#epoch-processing) - [Updated `process_epoch`](#updated-process_epoch) - [Updated `process_registry_updates`](#updated--process_registry_updates) @@ -758,6 +763,54 @@ def slash_validator(state: BeaconState, ## Beacon chain state transition function +### Execution engine + +#### Request data + +#### Engine APIs + +##### Modified `notify_new_payload` + +*Note*: The function `notify_new_payload` is modified to include the maximum number of blobs +allowed per block. + +```python +def notify_new_payload(self: ExecutionEngine, + execution_payload: ExecutionPayload, + parent_beacon_block_root: Root, + max_blobs_per_block: uint64) -> bool: + """ + Return ``True`` if and only if ``execution_payload`` is valid with respect to ``self.execution_state``. + """ + ... +``` + +##### Modified `verify_and_notify_new_payload` + +```python +def verify_and_notify_new_payload(self: ExecutionEngine, + new_payload_request: NewPayloadRequest) -> bool: + """ + Return ``True`` if and only if ``new_payload_request`` is valid with respect to ``self.execution_state``. + """ + execution_payload = new_payload_request.execution_payload + parent_beacon_block_root = new_payload_request.parent_beacon_block_root + + if not self.is_valid_block_hash(execution_payload, parent_beacon_block_root): + return False + + if not self.is_valid_versioned_hashes(new_payload_request): + return False + + # [Modified in Electra] + if not self.notify_new_payload(execution_payload, + parent_beacon_block_root, + MAX_BLOBS_PER_BLOCK): + return False + + return True +``` + ### Epoch processing #### Updated `process_epoch` From 1aa74885f7d59920b4d4da994b9be2292210c5da Mon Sep 17 00:00:00 2001 From: Alex Stokes Date: Wed, 12 Jun 2024 14:46:38 -0600 Subject: [PATCH 03/23] update spec builder for electra execution engine --- pysetup/spec_builders/electra.py | 49 ++++++++++++++++++++++++++++---- 1 file changed, 43 insertions(+), 6 deletions(-) diff --git a/pysetup/spec_builders/electra.py b/pysetup/spec_builders/electra.py index 1f968a817d..dd79811063 100644 --- a/pysetup/spec_builders/electra.py +++ b/pysetup/spec_builders/electra.py @@ -8,16 +8,53 @@ class ElectraSpecBuilder(BaseSpecBuilder): @classmethod def imports(cls, preset_name: str): - return f''' + return f""" from eth2spec.deneb import {preset_name} as deneb -''' +""" -## TODO: deal with changed gindices + @classmethod + def execution_engine_cls(cls) -> str: + return """ +class NoopExecutionEngine(ExecutionEngine): + + def notify_new_payload(self: ExecutionEngine, + execution_payload: ExecutionPayload, + parent_beacon_block_root: Root, + max_blobs_per_block: uint64) -> bool: + return True + + def notify_forkchoice_updated(self: ExecutionEngine, + head_block_hash: Hash32, + safe_block_hash: Hash32, + finalized_block_hash: Hash32, + payload_attributes: Optional[PayloadAttributes]) -> Optional[PayloadId]: + pass + + def get_payload(self: ExecutionEngine, payload_id: PayloadId) -> GetPayloadResponse: + # pylint: disable=unused-argument + raise NotImplementedError("no default block production") + + def is_valid_block_hash(self: ExecutionEngine, + execution_payload: ExecutionPayload, + parent_beacon_block_root: Root) -> bool: + return True + + def is_valid_versioned_hashes(self: ExecutionEngine, new_payload_request: NewPayloadRequest) -> bool: + return True + + def verify_and_notify_new_payload(self: ExecutionEngine, + new_payload_request: NewPayloadRequest) -> bool: + return True + + +EXECUTION_ENGINE = NoopExecutionEngine()""" + + ## TODO: deal with changed gindices @classmethod def hardcoded_ssz_dep_constants(cls) -> Dict[str, str]: return { - 'FINALIZED_ROOT_GINDEX': 'GeneralizedIndex(169)', - 'CURRENT_SYNC_COMMITTEE_GINDEX': 'GeneralizedIndex(86)', - 'NEXT_SYNC_COMMITTEE_GINDEX': 'GeneralizedIndex(87)', + "FINALIZED_ROOT_GINDEX": "GeneralizedIndex(169)", + "CURRENT_SYNC_COMMITTEE_GINDEX": "GeneralizedIndex(86)", + "NEXT_SYNC_COMMITTEE_GINDEX": "GeneralizedIndex(87)", } From d658c86ca2dbff3b3fe64f44c27b0a967eca97bd Mon Sep 17 00:00:00 2001 From: Etan Kissling Date: Thu, 16 May 2024 10:59:51 +0300 Subject: [PATCH 04/23] EIP-7549: Append new `committee_bits` field to end of `Attestation` Introducing new fields in the middle of an existing `Container` pointlessly breaks merkleization of all subsequent fields. In the case of `committee_bits`, it is also misleading, as `signature` only covers `data` inside `Attestation`. --- specs/electra/beacon-chain.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/specs/electra/beacon-chain.md b/specs/electra/beacon-chain.md index 62a8a2292d..cae73f07c8 100644 --- a/specs/electra/beacon-chain.md +++ b/specs/electra/beacon-chain.md @@ -282,8 +282,8 @@ class AttesterSlashing(Container): class Attestation(Container): aggregation_bits: Bitlist[MAX_VALIDATORS_PER_COMMITTEE * MAX_COMMITTEES_PER_SLOT] # [Modified in Electra:EIP7549] data: AttestationData - committee_bits: Bitvector[MAX_COMMITTEES_PER_SLOT] # [New in Electra:EIP7549] signature: BLSSignature + committee_bits: Bitvector[MAX_COMMITTEES_PER_SLOT] # [New in Electra:EIP7549] ``` #### `IndexedAttestation` From 97dfba2cc5cd0186d425ed9afa5ccd491a98c016 Mon Sep 17 00:00:00 2001 From: Benedikt Wagner <113296072+b-wagn@users.noreply.github.com> Date: Thu, 13 Jun 2024 16:30:05 +0200 Subject: [PATCH 05/23] Update polynomial-commitments-sampling.md - Fix dead link --- specs/_features/eip7594/polynomial-commitments-sampling.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/specs/_features/eip7594/polynomial-commitments-sampling.md b/specs/_features/eip7594/polynomial-commitments-sampling.md index 8d97a12575..c2f8eb93cb 100644 --- a/specs/_features/eip7594/polynomial-commitments-sampling.md +++ b/specs/_features/eip7594/polynomial-commitments-sampling.md @@ -52,7 +52,7 @@ ## Introduction -This document extends [polynomial-commitments.md](polynomial-commitments.md) with the functions required for data availability sampling (DAS). It is not part of the core Deneb spec but an extension that can be optionally implemented to allow nodes to reduce their load using DAS. +This document extends [polynomial-commitments.md](https://github.com/ethereum/consensus-specs/blob/dev/specs/deneb/polynomial-commitments.md) with the functions required for data availability sampling (DAS). It is not part of the core Deneb spec but an extension that can be optionally implemented to allow nodes to reduce their load using DAS. ## Public Methods From 29c82757ca824e7101babf27b16f2ca9683979a2 Mon Sep 17 00:00:00 2001 From: Benedikt Wagner <113296072+b-wagn@users.noreply.github.com> Date: Thu, 13 Jun 2024 17:20:04 +0200 Subject: [PATCH 06/23] Update specs/_features/eip7594/polynomial-commitments-sampling.md Co-authored-by: Hsiao-Wei Wang --- specs/_features/eip7594/polynomial-commitments-sampling.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/specs/_features/eip7594/polynomial-commitments-sampling.md b/specs/_features/eip7594/polynomial-commitments-sampling.md index c2f8eb93cb..9337a912e0 100644 --- a/specs/_features/eip7594/polynomial-commitments-sampling.md +++ b/specs/_features/eip7594/polynomial-commitments-sampling.md @@ -52,7 +52,7 @@ ## Introduction -This document extends [polynomial-commitments.md](https://github.com/ethereum/consensus-specs/blob/dev/specs/deneb/polynomial-commitments.md) with the functions required for data availability sampling (DAS). It is not part of the core Deneb spec but an extension that can be optionally implemented to allow nodes to reduce their load using DAS. +This document extends [polynomial-commitments.md](../../deneb/polynomial-commitments.md) with the functions required for data availability sampling (DAS). It is not part of the core Deneb spec but an extension that can be optionally implemented to allow nodes to reduce their load using DAS. ## Public Methods From 5a7f74c3e67d6487d7fd7a99758aed67c79959e8 Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Thu, 13 Jun 2024 23:42:36 +0800 Subject: [PATCH 07/23] bump version to `1.5.0-alpha.3` --- 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 ead8dd9dd9..86f9d092d6 100644 --- a/tests/core/pyspec/eth2spec/VERSION.txt +++ b/tests/core/pyspec/eth2spec/VERSION.txt @@ -1 +1 @@ -1.5.0-alpha.2 +1.5.0-alpha.3 From 053103d46904ae1dd449dd5c8479cf2eb19b9c19 Mon Sep 17 00:00:00 2001 From: Mikhail Kalinin Date: Fri, 31 May 2024 15:57:51 +0600 Subject: [PATCH 08/23] Switch spec to MAX_EFFECTIVE_BALANCE_ELECTRA --- specs/electra/beacon-chain.md | 37 +++++++++++++++++++++++++++++++++-- 1 file changed, 35 insertions(+), 2 deletions(-) diff --git a/specs/electra/beacon-chain.md b/specs/electra/beacon-chain.md index cae73f07c8..48e0dd51a4 100644 --- a/specs/electra/beacon-chain.md +++ b/specs/electra/beacon-chain.md @@ -58,6 +58,7 @@ - [New `get_active_balance`](#new-get_active_balance) - [New `get_pending_balance_to_withdraw`](#new-get_pending_balance_to_withdraw) - [Modified `get_attesting_indices`](#modified-get_attesting_indices) + - [Modified `get_next_sync_committee_indices`](#modified-get_next_sync_committee_indices) - [Beacon state mutators](#beacon-state-mutators) - [Updated `initiate_validator_exit`](#updated--initiate_validator_exit) - [New `switch_to_compounding_validator`](#new-switch_to_compounding_validator) @@ -437,6 +438,8 @@ class BeaconState(Container): #### Updated `compute_proposer_index` +*Note*: The function is modified to use `MAX_EFFECTIVE_BALANCE_ELECTRA` preset. + ```python def compute_proposer_index(state: BeaconState, indices: Sequence[ValidatorIndex], seed: Bytes32) -> ValidatorIndex: """ @@ -620,6 +623,36 @@ def get_attesting_indices(state: BeaconState, attestation: Attestation) -> Set[V return output ``` +#### Modified `get_next_sync_committee_indices` + +*Note*: The function is modified to use `MAX_EFFECTIVE_BALANCE_ELECTRA` preset. + +```python +def get_next_sync_committee_indices(state: BeaconState) -> Sequence[ValidatorIndex]: + """ + Return the sync committee indices, with possible duplicates, for the next sync committee. + """ + epoch = Epoch(get_current_epoch(state) + 1) + + MAX_RANDOM_BYTE = 2**8 - 1 + active_validator_indices = get_active_validator_indices(state, epoch) + active_validator_count = uint64(len(active_validator_indices)) + seed = get_seed(state, epoch, DOMAIN_SYNC_COMMITTEE) + i = 0 + sync_committee_indices: List[ValidatorIndex] = [] + while len(sync_committee_indices) < SYNC_COMMITTEE_SIZE: + shuffled_index = compute_shuffled_index(uint64(i % active_validator_count), active_validator_count, seed) + candidate_index = active_validator_indices[shuffled_index] + random_byte = hash(seed + uint_to_bytes(uint64(i // 32)))[i % 32] + effective_balance = state.validators[candidate_index].effective_balance + # [Modified in Electra:EIP7251] + if effective_balance * MAX_RANDOM_BYTE >= MAX_EFFECTIVE_BALANCE_ELECTRA * random_byte: + sync_committee_indices.append(candidate_index) + i += 1 + return sync_committee_indices +``` + + ### Beacon state mutators #### Updated `initiate_validator_exit` @@ -1491,8 +1524,8 @@ def initialize_beacon_state_from_eth1(eth1_block_hash: Hash32, # 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.effective_balance = min(balance - balance % EFFECTIVE_BALANCE_INCREMENT, MAX_EFFECTIVE_BALANCE_ELECTRA) + if validator.effective_balance >= MIN_ACTIVATION_BALANCE: validator.activation_eligibility_epoch = GENESIS_EPOCH validator.activation_epoch = GENESIS_EPOCH From 3e09a343d299ec336b0121494f4f41fc576f4efd Mon Sep 17 00:00:00 2001 From: Mikhail Kalinin Date: Fri, 31 May 2024 22:02:22 +0600 Subject: [PATCH 09/23] Update tests --- .../test_process_sync_aggregate.py | 9 ++++- .../test_process_sync_aggregate_random.py | 23 +++++++++---- tests/core/pyspec/eth2spec/test/context.py | 34 +++++++++++++++++-- .../pyspec/eth2spec/test/helpers/genesis.py | 21 ++++++++++-- .../phase0/genesis/test_initialization.py | 10 ++++-- 5 files changed, 83 insertions(+), 14 deletions(-) diff --git a/tests/core/pyspec/eth2spec/test/altair/block_processing/sync_aggregate/test_process_sync_aggregate.py b/tests/core/pyspec/eth2spec/test/altair/block_processing/sync_aggregate/test_process_sync_aggregate.py index 37e4439eea..f1a270092c 100644 --- a/tests/core/pyspec/eth2spec/test/altair/block_processing/sync_aggregate/test_process_sync_aggregate.py +++ b/tests/core/pyspec/eth2spec/test/altair/block_processing/sync_aggregate/test_process_sync_aggregate.py @@ -24,6 +24,11 @@ with_presets, spec_state_test, always_bls, + single_phase, + with_custom_state, + spec_test, + default_balances_electra, + default_activation_threshold, ) @@ -143,7 +148,9 @@ def is_duplicate_sync_committee(committee_indices): @with_altair_and_later @with_presets([MINIMAL], reason="to create nonduplicate committee") -@spec_state_test +@spec_test +@with_custom_state(balances_fn=default_balances_electra, threshold_fn=default_activation_threshold) +@single_phase def test_sync_committee_rewards_nonduplicate_committee(spec, state): committee_indices = compute_committee_indices(state) diff --git a/tests/core/pyspec/eth2spec/test/altair/block_processing/sync_aggregate/test_process_sync_aggregate_random.py b/tests/core/pyspec/eth2spec/test/altair/block_processing/sync_aggregate/test_process_sync_aggregate_random.py index a402e3d540..792bcb0e33 100644 --- a/tests/core/pyspec/eth2spec/test/altair/block_processing/sync_aggregate/test_process_sync_aggregate_random.py +++ b/tests/core/pyspec/eth2spec/test/altair/block_processing/sync_aggregate/test_process_sync_aggregate_random.py @@ -24,6 +24,8 @@ with_custom_state, with_presets, spec_test, + default_balances_electra, + misc_balances_electra, ) @@ -132,7 +134,9 @@ def test_random_with_exits_with_duplicates(spec, state): @with_altair_and_later @with_presets([MINIMAL], reason="to create nonduplicate committee") -@spec_state_test +@spec_test +@with_custom_state(balances_fn=default_balances_electra, threshold_fn=default_activation_threshold) +@single_phase def test_random_only_one_participant_without_duplicates(spec, state): rng = random.Random(501) yield from _test_harness_for_randomized_test_case( @@ -144,7 +148,9 @@ def test_random_only_one_participant_without_duplicates(spec, state): @with_altair_and_later @with_presets([MINIMAL], reason="to create nonduplicate committee") -@spec_state_test +@spec_test +@with_custom_state(balances_fn=default_balances_electra, threshold_fn=default_activation_threshold) +@single_phase def test_random_low_participation_without_duplicates(spec, state): rng = random.Random(601) yield from _test_harness_for_randomized_test_case( @@ -156,7 +162,9 @@ def test_random_low_participation_without_duplicates(spec, state): @with_altair_and_later @with_presets([MINIMAL], reason="to create nonduplicate committee") -@spec_state_test +@spec_test +@with_custom_state(balances_fn=default_balances_electra, threshold_fn=default_activation_threshold) +@single_phase def test_random_high_participation_without_duplicates(spec, state): rng = random.Random(701) yield from _test_harness_for_randomized_test_case( @@ -168,7 +176,9 @@ def test_random_high_participation_without_duplicates(spec, state): @with_altair_and_later @with_presets([MINIMAL], reason="to create nonduplicate committee") -@spec_state_test +@spec_test +@with_custom_state(balances_fn=default_balances_electra, threshold_fn=default_activation_threshold) +@single_phase def test_random_all_but_one_participating_without_duplicates(spec, state): rng = random.Random(801) yield from _test_harness_for_randomized_test_case( @@ -181,7 +191,7 @@ def test_random_all_but_one_participating_without_duplicates(spec, state): @with_altair_and_later @with_presets([MINIMAL], reason="to create nonduplicate committee") @spec_test -@with_custom_state(balances_fn=misc_balances, threshold_fn=default_activation_threshold) +@with_custom_state(balances_fn=misc_balances_electra, threshold_fn=default_activation_threshold) @single_phase def test_random_misc_balances_and_half_participation_without_duplicates(spec, state): rng = random.Random(1501) @@ -194,7 +204,8 @@ def test_random_misc_balances_and_half_participation_without_duplicates(spec, st @with_altair_and_later @with_presets([MINIMAL], reason="to create nonduplicate committee") -@spec_state_test +@spec_test +@with_custom_state(balances_fn=default_balances_electra, threshold_fn=default_activation_threshold) @single_phase def test_random_with_exits_without_duplicates(spec, state): rng = random.Random(1502) diff --git a/tests/core/pyspec/eth2spec/test/context.py b/tests/core/pyspec/eth2spec/test/context.py index ff2ab80b5c..e805e1c120 100644 --- a/tests/core/pyspec/eth2spec/test/context.py +++ b/tests/core/pyspec/eth2spec/test/context.py @@ -16,7 +16,7 @@ ALLOWED_TEST_RUNNER_FORKS, LIGHT_CLIENT_TESTING_FORKS, ) -from .helpers.forks import is_post_fork +from .helpers.forks import is_post_fork, is_post_electra from .helpers.genesis import create_genesis_state from .helpers.typing import ( Spec, @@ -86,7 +86,10 @@ def default_activation_threshold(spec: Spec): Helper method to use the default balance activation threshold for state creation for tests. Usage: `@with_custom_state(threshold_fn=default_activation_threshold, ...)` """ - return spec.MAX_EFFECTIVE_BALANCE + if is_post_electra(spec): + return spec.MIN_ACTIVATION_BALANCE + else: + return spec.MAX_EFFECTIVE_BALANCE def zero_activation_threshold(spec: Spec): @@ -106,6 +109,18 @@ def default_balances(spec: Spec): return [spec.MAX_EFFECTIVE_BALANCE] * num_validators +def default_balances_electra(spec: Spec): + """ + Helper method to create a series of default balances for Electra. + Usage: `@with_custom_state(balances_fn=default_balances_electra, ...)` + """ + if not is_post_electra(spec): + return default_balances(spec) + + num_validators = spec.SLOTS_PER_EPOCH * 8 + return [spec.MAX_EFFECTIVE_BALANCE_ELECTRA] * num_validators + + def scaled_churn_balances_min_churn_limit(spec: Spec): """ Helper method to create enough validators to scale the churn limit. @@ -175,6 +190,21 @@ def misc_balances(spec: Spec): return balances +def misc_balances_electra(spec: Spec): + """ + Helper method to create a series of balances that includes some misc. balances for Electra. + Usage: `@with_custom_state(balances_fn=misc_balances, ...)` + """ + if not is_post_electra(spec): + return misc_balances(spec) + + num_validators = spec.SLOTS_PER_EPOCH * 8 + balances = [spec.MAX_EFFECTIVE_BALANCE_ELECTRA * 2 * i // num_validators for i in range(num_validators)] + rng = Random(1234) + rng.shuffle(balances) + return balances + + def misc_balances_in_default_range_with_many_validators(spec: Spec): """ Helper method to create a series of balances that includes some misc. balances but diff --git a/tests/core/pyspec/eth2spec/test/helpers/genesis.py b/tests/core/pyspec/eth2spec/test/helpers/genesis.py index 307491ac76..4013b67bf2 100644 --- a/tests/core/pyspec/eth2spec/test/helpers/genesis.py +++ b/tests/core/pyspec/eth2spec/test/helpers/genesis.py @@ -15,8 +15,23 @@ def build_mock_validator(spec, i: int, balance: int): active_pubkey = pubkeys[i] withdrawal_pubkey = pubkeys[-1 - i] - # insecurely use pubkey as withdrawal key as well - withdrawal_credentials = spec.BLS_WITHDRAWAL_PREFIX + spec.hash(withdrawal_pubkey)[1:] + if is_post_electra(spec): + if balance > spec.MIN_ACTIVATION_BALANCE: + # use compounding withdrawal credentials if the balance is higher than MIN_ACTIVATION_BALANCE + withdrawal_credentials = ( + spec.COMPOUNDING_WITHDRAWAL_PREFIX + + b'\x00' * 11 + + spec.hash(withdrawal_pubkey)[12:] + ) + else: + # insecurely use pubkey as withdrawal key as well + withdrawal_credentials = spec.BLS_WITHDRAWAL_PREFIX + spec.hash(withdrawal_pubkey)[1:] + max_effective_balace = spec.MAX_EFFECTIVE_BALANCE_ELECTRA + else: + # insecurely use pubkey as withdrawal key as well + withdrawal_credentials = spec.BLS_WITHDRAWAL_PREFIX + spec.hash(withdrawal_pubkey)[1:] + max_effective_balace = spec.MAX_EFFECTIVE_BALANCE + validator = spec.Validator( pubkey=active_pubkey, withdrawal_credentials=withdrawal_credentials, @@ -24,7 +39,7 @@ def build_mock_validator(spec, i: int, balance: int): activation_epoch=spec.FAR_FUTURE_EPOCH, exit_epoch=spec.FAR_FUTURE_EPOCH, withdrawable_epoch=spec.FAR_FUTURE_EPOCH, - effective_balance=min(balance - balance % spec.EFFECTIVE_BALANCE_INCREMENT, spec.MAX_EFFECTIVE_BALANCE) + effective_balance=min(balance - balance % spec.EFFECTIVE_BALANCE_INCREMENT, max_effective_balace) ) return validator diff --git a/tests/core/pyspec/eth2spec/test/phase0/genesis/test_initialization.py b/tests/core/pyspec/eth2spec/test/phase0/genesis/test_initialization.py index 4c7c5f28c0..f1c3064723 100644 --- a/tests/core/pyspec/eth2spec/test/phase0/genesis/test_initialization.py +++ b/tests/core/pyspec/eth2spec/test/phase0/genesis/test_initialization.py @@ -11,6 +11,7 @@ ) from eth2spec.test.helpers.forks import ( is_post_altair, + is_post_electra, ) @@ -69,9 +70,14 @@ def test_initialize_beacon_state_some_small_balances(spec): if is_post_altair(spec): yield 'description', 'meta', get_post_altair_description(spec) + if is_post_electra(spec): + max_effective_balance = spec.MAX_EFFECTIVE_BALANCE_ELECTRA + else: + max_effective_balance = spec.MAX_EFFECTIVE_BALANCE + main_deposit_count = spec.config.MIN_GENESIS_ACTIVE_VALIDATOR_COUNT main_deposits, _, deposit_data_list = prepare_full_genesis_deposits( - spec, spec.MAX_EFFECTIVE_BALANCE, + spec, max_effective_balance, deposit_count=main_deposit_count, signed=True, ) # For deposits above, and for another deposit_count, add a balance of EFFECTIVE_BALANCE_INCREMENT @@ -99,7 +105,7 @@ def test_initialize_beacon_state_some_small_balances(spec): assert state.eth1_data.deposit_count == len(deposits) assert state.eth1_data.block_hash == eth1_block_hash # only main deposits participate to the active balance - assert spec.get_total_active_balance(state) == main_deposit_count * spec.MAX_EFFECTIVE_BALANCE + assert spec.get_total_active_balance(state) == main_deposit_count * max_effective_balance # yield state yield 'state', state From 43d208987ee34cc3d40edc6ddfcfd7028fdf9011 Mon Sep 17 00:00:00 2001 From: Mikhail Kalinin Date: Fri, 31 May 2024 22:16:18 +0600 Subject: [PATCH 10/23] Fix lint --- specs/electra/beacon-chain.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/specs/electra/beacon-chain.md b/specs/electra/beacon-chain.md index 48e0dd51a4..5b86890442 100644 --- a/specs/electra/beacon-chain.md +++ b/specs/electra/beacon-chain.md @@ -1524,7 +1524,8 @@ def initialize_beacon_state_from_eth1(eth1_block_hash: Hash32, # 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_ELECTRA) + validator.effective_balance = min( + balance - balance % EFFECTIVE_BALANCE_INCREMENT, MAX_EFFECTIVE_BALANCE_ELECTRA) if validator.effective_balance >= MIN_ACTIVATION_BALANCE: validator.activation_eligibility_epoch = GENESIS_EPOCH validator.activation_epoch = GENESIS_EPOCH From 3960883d5b798880a43b6ddd6c7a2b4869cc51f3 Mon Sep 17 00:00:00 2001 From: Mikhail Kalinin Date: Mon, 3 Jun 2024 14:56:39 +0600 Subject: [PATCH 11/23] Applied suggestions by @hwwhww Co-authored-by: Hsiao-Wei Wang --- specs/electra/beacon-chain.md | 1 + 1 file changed, 1 insertion(+) diff --git a/specs/electra/beacon-chain.md b/specs/electra/beacon-chain.md index 5b86890442..df037cce2c 100644 --- a/specs/electra/beacon-chain.md +++ b/specs/electra/beacon-chain.md @@ -1524,6 +1524,7 @@ def initialize_beacon_state_from_eth1(eth1_block_hash: Hash32, # Process activations for index, validator in enumerate(state.validators): balance = state.balances[index] + # [Modified in Electra:EIP7251] validator.effective_balance = min( balance - balance % EFFECTIVE_BALANCE_INCREMENT, MAX_EFFECTIVE_BALANCE_ELECTRA) if validator.effective_balance >= MIN_ACTIVATION_BALANCE: From 4b1c429686c0fbedaef3d6af15771baaefbce2d5 Mon Sep 17 00:00:00 2001 From: Mikhail Kalinin Date: Fri, 14 Jun 2024 13:26:47 +0700 Subject: [PATCH 12/23] Apply suggestion from @hwwhww Co-authored-by: Hsiao-Wei Wang --- specs/electra/beacon-chain.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/specs/electra/beacon-chain.md b/specs/electra/beacon-chain.md index df037cce2c..f16339fc35 100644 --- a/specs/electra/beacon-chain.md +++ b/specs/electra/beacon-chain.md @@ -1526,7 +1526,7 @@ def initialize_beacon_state_from_eth1(eth1_block_hash: Hash32, balance = state.balances[index] # [Modified in Electra:EIP7251] validator.effective_balance = min( - balance - balance % EFFECTIVE_BALANCE_INCREMENT, MAX_EFFECTIVE_BALANCE_ELECTRA) + balance - balance % EFFECTIVE_BALANCE_INCREMENT, get_validator_max_effective_balance(validator)) if validator.effective_balance >= MIN_ACTIVATION_BALANCE: validator.activation_eligibility_epoch = GENESIS_EPOCH validator.activation_epoch = GENESIS_EPOCH From b3328ac630bf69b23218efc204cc741695d5c54e Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Fri, 14 Jun 2024 15:43:28 +0800 Subject: [PATCH 13/23] Fix tests and remove duplicate `_WITHDRAWAL_PREFIX` definition --- specs/electra/beacon-chain.md | 2 -- .../eth2spec/test/phase0/genesis/test_initialization.py | 4 +++- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/specs/electra/beacon-chain.md b/specs/electra/beacon-chain.md index f16339fc35..a2718c542e 100644 --- a/specs/electra/beacon-chain.md +++ b/specs/electra/beacon-chain.md @@ -132,8 +132,6 @@ The following values are (non-configurable) constants used throughout the specif | Name | Value | | - | - | -| `BLS_WITHDRAWAL_PREFIX` | `Bytes1('0x00')` | -| `ETH1_ADDRESS_WITHDRAWAL_PREFIX` | `Bytes1('0x01')` | | `COMPOUNDING_WITHDRAWAL_PREFIX` | `Bytes1('0x02')` | ### Domains diff --git a/tests/core/pyspec/eth2spec/test/phase0/genesis/test_initialization.py b/tests/core/pyspec/eth2spec/test/phase0/genesis/test_initialization.py index f1c3064723..ed584ed612 100644 --- a/tests/core/pyspec/eth2spec/test/phase0/genesis/test_initialization.py +++ b/tests/core/pyspec/eth2spec/test/phase0/genesis/test_initialization.py @@ -105,7 +105,9 @@ def test_initialize_beacon_state_some_small_balances(spec): assert state.eth1_data.deposit_count == len(deposits) assert state.eth1_data.block_hash == eth1_block_hash # only main deposits participate to the active balance - assert spec.get_total_active_balance(state) == main_deposit_count * max_effective_balance + # NOTE: they are pre-ELECTRA deposits with BLS_WITHDRAWAL_PREFIX, + # so `MAX_EFFECTIVE_BALANCE` is used + assert spec.get_total_active_balance(state) == main_deposit_count * spec.MAX_EFFECTIVE_BALANCE # yield state yield 'state', state From 2eda0a99fbb2da895895870fff75c7e95a8b379d Mon Sep 17 00:00:00 2001 From: b-wagn Date: Fri, 14 Jun 2024 14:23:53 +0200 Subject: [PATCH 14/23] extend test for eip7594 --- .../test_polynomial_commitments.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/tests/core/pyspec/eth2spec/test/eip7594/unittests/polynomial_commitments/test_polynomial_commitments.py b/tests/core/pyspec/eth2spec/test/eip7594/unittests/polynomial_commitments/test_polynomial_commitments.py index 7741398749..a051f14a11 100644 --- a/tests/core/pyspec/eth2spec/test/eip7594/unittests/polynomial_commitments/test_polynomial_commitments.py +++ b/tests/core/pyspec/eth2spec/test/eip7594/unittests/polynomial_commitments/test_polynomial_commitments.py @@ -15,18 +15,35 @@ @spec_test @single_phase def test_fft(spec): + + # in this test we sample a random polynomial in coefficient form + # then we apply an FFT to get evaluations over the roots of unity + # we then apply an inverse FFT to the evaluations to get coefficients + + # we check two things: + # 1) the original coefficients and the resulting coefficients match + # 2) the evaluations that we got are the same as if we would have evaluated individually + rng = random.Random(5566) roots_of_unity = spec.compute_roots_of_unity(spec.FIELD_ELEMENTS_PER_BLOB) + # sample a random polynomial poly_coeff = [rng.randint(0, BLS_MODULUS - 1) for _ in range(spec.FIELD_ELEMENTS_PER_BLOB)] + # do an FFT and then an inverse FFT poly_eval = spec.fft_field(poly_coeff, roots_of_unity) poly_coeff_inversed = spec.fft_field(poly_eval, roots_of_unity, inv=True) + # first check: inverse FFT after FFT results in original coefficients assert len(poly_eval) == len(poly_coeff) == len(poly_coeff_inversed) assert poly_coeff_inversed == poly_coeff + # second check: result of FFT are really the evaluations + for i, w in enumerate(roots_of_unity): + individual_evaluation = spec.evaluate_polynomialcoeff(poly_coeff, w) + assert individual_evaluation == poly_eval[i] + @with_eip7594_and_later @spec_test From 91e23dac412020eb3913bf6c64a21e0b7eb6a3e7 Mon Sep 17 00:00:00 2001 From: b-wagn Date: Fri, 14 Jun 2024 14:59:22 +0200 Subject: [PATCH 15/23] extend test for coset_fft --- .../test_polynomial_commitments.py | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/tests/core/pyspec/eth2spec/test/eip7594/unittests/polynomial_commitments/test_polynomial_commitments.py b/tests/core/pyspec/eth2spec/test/eip7594/unittests/polynomial_commitments/test_polynomial_commitments.py index a051f14a11..b1b6c2d248 100644 --- a/tests/core/pyspec/eth2spec/test/eip7594/unittests/polynomial_commitments/test_polynomial_commitments.py +++ b/tests/core/pyspec/eth2spec/test/eip7594/unittests/polynomial_commitments/test_polynomial_commitments.py @@ -49,18 +49,40 @@ def test_fft(spec): @spec_test @single_phase def test_coset_fft(spec): + + # in this test we sample a random polynomial in coefficient form + # then we apply a Coset FFT to get evaluations over the coset of the roots of unity + # we then apply an inverse Coset FFT to the evaluations to get coefficients + + # we check two things: + # 1) the original coefficients and the resulting coefficients match + # 2) the evaluations that we got are the same as if we would have evaluated individually + rng = random.Random(5566) roots_of_unity = spec.compute_roots_of_unity(spec.FIELD_ELEMENTS_PER_BLOB) + # this is the shift that generates the coset + coset_shift = spec.PRIMITIVE_ROOT_OF_UNITY + + # sample a random polynomial poly_coeff = [rng.randint(0, BLS_MODULUS - 1) for _ in range(spec.FIELD_ELEMENTS_PER_BLOB)] + # do a coset FFT and then an inverse coset FFT poly_eval = spec.coset_fft_field(poly_coeff, roots_of_unity) poly_coeff_inversed = spec.coset_fft_field(poly_eval, roots_of_unity, inv=True) + # first check: inverse coset FFT after coset FFT results in original coefficients assert len(poly_eval) == len(poly_coeff) == len(poly_coeff_inversed) assert poly_coeff_inversed == poly_coeff + # second check: result of FFT are really the evaluations over the coset + for i, w in enumerate(roots_of_unity): + # the element of the coset is coset_shift * w + shifted_w = spec.BLSFieldElement((coset_shift * int(w)) % BLS_MODULUS) + individual_evaluation = spec.evaluate_polynomialcoeff(poly_coeff, shifted_w) + assert individual_evaluation == poly_eval[i] + @with_eip7594_and_later @spec_test From 172e27fe9f614b601e60ab9e0f317f86e0f431ce Mon Sep 17 00:00:00 2001 From: b-wagn Date: Fri, 14 Jun 2024 15:18:00 +0200 Subject: [PATCH 16/23] remove trailing whitespaces --- .../test_polynomial_commitments.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/core/pyspec/eth2spec/test/eip7594/unittests/polynomial_commitments/test_polynomial_commitments.py b/tests/core/pyspec/eth2spec/test/eip7594/unittests/polynomial_commitments/test_polynomial_commitments.py index b1b6c2d248..5bc3a4330a 100644 --- a/tests/core/pyspec/eth2spec/test/eip7594/unittests/polynomial_commitments/test_polynomial_commitments.py +++ b/tests/core/pyspec/eth2spec/test/eip7594/unittests/polynomial_commitments/test_polynomial_commitments.py @@ -20,7 +20,7 @@ def test_fft(spec): # then we apply an FFT to get evaluations over the roots of unity # we then apply an inverse FFT to the evaluations to get coefficients - # we check two things: + # we check two things: # 1) the original coefficients and the resulting coefficients match # 2) the evaluations that we got are the same as if we would have evaluated individually @@ -42,19 +42,19 @@ def test_fft(spec): # second check: result of FFT are really the evaluations for i, w in enumerate(roots_of_unity): individual_evaluation = spec.evaluate_polynomialcoeff(poly_coeff, w) - assert individual_evaluation == poly_eval[i] + assert individual_evaluation == poly_eval[i] @with_eip7594_and_later @spec_test @single_phase def test_coset_fft(spec): - + # in this test we sample a random polynomial in coefficient form # then we apply a Coset FFT to get evaluations over the coset of the roots of unity # we then apply an inverse Coset FFT to the evaluations to get coefficients - # we check two things: + # we check two things: # 1) the original coefficients and the resulting coefficients match # 2) the evaluations that we got are the same as if we would have evaluated individually @@ -81,7 +81,7 @@ def test_coset_fft(spec): # the element of the coset is coset_shift * w shifted_w = spec.BLSFieldElement((coset_shift * int(w)) % BLS_MODULUS) individual_evaluation = spec.evaluate_polynomialcoeff(poly_coeff, shifted_w) - assert individual_evaluation == poly_eval[i] + assert individual_evaluation == poly_eval[i] @with_eip7594_and_later From 4fd2be81196aa7140fb3ab90703b6863f1d3998f Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Fri, 14 Jun 2024 23:05:41 +0800 Subject: [PATCH 17/23] fix typo --- tests/generators/operations/main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/generators/operations/main.py b/tests/generators/operations/main.py index 204f5023a4..51cd507066 100644 --- a/tests/generators/operations/main.py +++ b/tests/generators/operations/main.py @@ -47,7 +47,7 @@ 'attestation', 'consolidation_request', 'deposit_request', - 'voluntary_exit' + 'voluntary_exit', 'withdrawal_request', ]} electra_mods = combine_mods(_new_electra_mods, deneb_mods) From 63813eb9cdc417134416247fbd397272975f7746 Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Fri, 14 Jun 2024 23:57:21 +0800 Subject: [PATCH 18/23] Remove `assert len(missing_cell_indices) != 0` check --- specs/_features/eip7594/polynomial-commitments-sampling.md | 3 --- 1 file changed, 3 deletions(-) diff --git a/specs/_features/eip7594/polynomial-commitments-sampling.md b/specs/_features/eip7594/polynomial-commitments-sampling.md index 9337a912e0..7be1a4a059 100644 --- a/specs/_features/eip7594/polynomial-commitments-sampling.md +++ b/specs/_features/eip7594/polynomial-commitments-sampling.md @@ -565,9 +565,6 @@ def construct_vanishing_polynomial(missing_cell_indices: Sequence[CellIndex]) -> We never encounter this case however because this method is used solely for recovery and recovery only works if at least half of the cells are available. """ - - assert len(missing_cell_indices) != 0 - # Get the small domain roots_of_unity_reduced = compute_roots_of_unity(CELLS_PER_EXT_BLOB) From b0ac4cbcc031e7628c09a78cd86ee8fbff1fc32b Mon Sep 17 00:00:00 2001 From: Etan Kissling Date: Sun, 16 Jun 2024 10:04:41 +0200 Subject: [PATCH 19/23] Bump remerkleable to `v0.1.28` - https://github.com/protolambda/remerkleable/releases/tag/v0.1.28 --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index e5c348ada5..539db215b7 100644 --- a/setup.py +++ b/setup.py @@ -552,7 +552,7 @@ def run(self): "pycryptodome==3.15.0", "py_ecc==6.0.0", "milagro_bls_binding==1.9.0", - "remerkleable==0.1.27", + "remerkleable==0.1.28", "trie==2.0.2", RUAMEL_YAML_VERSION, "lru-dict==1.2.0", From c2b9858264c35b8783392f724928acfb9a7fc947 Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Mon, 13 May 2024 14:35:28 +0300 Subject: [PATCH 20/23] Add Electra merkle proof test vectors --- tests/generators/merkle_proof/main.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/generators/merkle_proof/main.py b/tests/generators/merkle_proof/main.py index b7d30fe9e4..69500137ab 100644 --- a/tests/generators/merkle_proof/main.py +++ b/tests/generators/merkle_proof/main.py @@ -1,4 +1,4 @@ -from eth2spec.test.helpers.constants import DENEB, EIP7594 +from eth2spec.test.helpers.constants import DENEB, ELECTRA, EIP7594 from eth2spec.gen_helpers.gen_from_tests.gen import run_state_test_generators, combine_mods @@ -9,10 +9,12 @@ _new_eip7594_mods = {key: 'eth2spec.test.eip7594.merkle_proof.test_' + key for key in [ 'single_merkle_proof', ]} + electra_mods = deneb_mods eip_7594_mods = combine_mods(_new_eip7594_mods, deneb_mods) all_mods = { DENEB: deneb_mods, + ELECTRA: electra_mods, EIP7594: eip_7594_mods, } From 3c93ea20adca140532ba2d9a00ed66c7eff8582c Mon Sep 17 00:00:00 2001 From: Dankrad Feist Date: Mon, 24 Jun 2024 11:42:57 +0200 Subject: [PATCH 21/23] Blob base fee computation in CL --- specs/electra/beacon-chain.md | 61 +++++++++++++++++++++++++++++++---- specs/electra/fork-choice.md | 2 +- specs/electra/validator.md | 2 +- 3 files changed, 57 insertions(+), 8 deletions(-) diff --git a/specs/electra/beacon-chain.md b/specs/electra/beacon-chain.md index a2718c542e..c598d3616d 100644 --- a/specs/electra/beacon-chain.md +++ b/specs/electra/beacon-chain.md @@ -185,6 +185,13 @@ The following values are (non-configurable) constants used throughout the specif | - | - | - | | `MAX_PENDING_PARTIALS_PER_WITHDRAWALS_SWEEP` | `uint64(2**3)` (= 8)| *[New in Electra:EIP7002]* Maximum number of pending partial withdrawals to process per payload | +### Blobs + +| Name | Value | Description | +| - | - | - | +| `TARGET_BLOBS_PER_BLOCK` | `uint64(3)` | *[New in Electra]* Target number of blobs per block | + + ## Configuration ### Validator cycle @@ -337,7 +344,7 @@ class ExecutionPayload(Container): transactions: List[Transaction, MAX_TRANSACTIONS_PER_PAYLOAD] withdrawals: List[Withdrawal, MAX_WITHDRAWALS_PER_PAYLOAD] blob_gas_used: uint64 - excess_blob_gas: uint64 + excess_blob_gas: uint64 # [Deprecated in Electra: compute blob gas in CL] deposit_requests: List[DepositRequest, MAX_DEPOSIT_REQUESTS_PER_PAYLOAD] # [New in Electra:EIP6110] # [New in Electra:EIP7002:EIP7251] withdrawal_requests: List[WithdrawalRequest, MAX_WITHDRAWAL_REQUESTS_PER_PAYLOAD] @@ -367,7 +374,7 @@ class ExecutionPayloadHeader(Container): transactions_root: Root withdrawals_root: Root blob_gas_used: uint64 - excess_blob_gas: uint64 + excess_blob_gas: uint64 # [Deprecated in Electra: compute blob gas in CL] deposit_requests_root: Root # [New in Electra:EIP6110] withdrawal_requests_root: Root # [New in Electra:EIP7002:EIP7251] consolidation_requests_root: Root # [New in Electra:EIP7251] @@ -428,10 +435,50 @@ class BeaconState(Container): # [New in Electra:EIP7251] pending_partial_withdrawals: List[PendingPartialWithdrawal, PENDING_PARTIAL_WITHDRAWALS_LIMIT] pending_consolidations: List[PendingConsolidation, PENDING_CONSOLIDATIONS_LIMIT] # [New in Electra:EIP7251] + # [New in Electra: compute blob gas in CL] + excess_blob_gas: uint64 + base_fee_per_blob_gas: uint64 ``` ## Helper functions +### Blob gas fee computation + +#### `fake_exponential` + +```python +def fake_exponential(factor: int, numerator: int, denominator: int) -> int: + i = 1 + output = 0 + numerator_accum = factor * denominator + while numerator_accum > 0: + output += numerator_accum + numerator_accum = (numerator_accum * numerator) // (denominator * i) + i += 1 + return output // denominator +``` + +#### `fake_exponential` + +```python +def get_blob_base_fee_update_fraction(max_blobs: int, target_blobs:int)) -> int: + max_excess_per_block = (max_blobs - target_blobs) * BLOB_GAS_PER_BLOB + # 1 / ln(9 / 8) ~= 8.49 = 849 / 1000 + return max_excess_per_block * 849 // 1000 +``` + + +#### `get_base_fee_per_blob_gas` + +```python +def get_base_fee_per_blob_gas(state: BeaconState) -> int: + return fake_exponential( + MIN_BASE_FEE_PER_BLOB_GAS, + state.excess_blob_gas, + get_blob_base_fee_update_fraction(MAX_BLOBS, TARGET_BLOBS_PER_BLOCK) + ) +``` + ### Predicates #### Updated `compute_proposer_index` @@ -802,14 +849,13 @@ def slash_validator(state: BeaconState, ##### Modified `notify_new_payload` -*Note*: The function `notify_new_payload` is modified to include the maximum number of blobs -allowed per block. +*Note*: The function `notify_new_payload` is modified to include the blob gas fee. ```python def notify_new_payload(self: ExecutionEngine, execution_payload: ExecutionPayload, parent_beacon_block_root: Root, - max_blobs_per_block: uint64) -> bool: + base_fee_per_blob_gas: uint64) -> bool: """ Return ``True`` if and only if ``execution_payload`` is valid with respect to ``self.execution_state``. """ @@ -820,6 +866,7 @@ def notify_new_payload(self: ExecutionEngine, ```python def verify_and_notify_new_payload(self: ExecutionEngine, + state: BeaconState, new_payload_request: NewPayloadRequest) -> bool: """ Return ``True`` if and only if ``new_payload_request`` is valid with respect to ``self.execution_state``. @@ -836,8 +883,10 @@ def verify_and_notify_new_payload(self: ExecutionEngine, # [Modified in Electra] if not self.notify_new_payload(execution_payload, parent_beacon_block_root, - MAX_BLOBS_PER_BLOCK): + get_base_fee_per_blob_gas(state)): return False + + state.excess_blob_gas += execution_payload.blob_gas_used return True ``` diff --git a/specs/electra/fork-choice.md b/specs/electra/fork-choice.md index a143d43b80..b1a438dfa7 100644 --- a/specs/electra/fork-choice.md +++ b/specs/electra/fork-choice.md @@ -33,5 +33,5 @@ class PayloadAttributes(object): suggested_fee_recipient: ExecutionAddress withdrawals: Sequence[Withdrawal] parent_beacon_block_root: Root - max_blobs_per_block: uint64 # [New in Electra] + base_fee_per_blob_gas: uint64 # [New in Electra] ``` diff --git a/specs/electra/validator.md b/specs/electra/validator.md index 3bae8250ea..6488e5d39f 100644 --- a/specs/electra/validator.md +++ b/specs/electra/validator.md @@ -139,7 +139,7 @@ def prepare_execution_payload(state: BeaconState, suggested_fee_recipient=suggested_fee_recipient, withdrawals=withdrawals, parent_beacon_block_root=hash_tree_root(state.latest_block_header), - max_blobs_per_block=MAX_BLOBS_PER_BLOCK, # [New in Electra] + base_fee_per_blob_gas=state.base_fee_per_blob_gas, # [New in Electra] ) return execution_engine.notify_forkchoice_updated( head_block_hash=parent_hash, From c499d3a6ed2843d798a0b9b387a90b23f2215edc Mon Sep 17 00:00:00 2001 From: dankrad Date: Tue, 25 Jun 2024 12:03:17 +0200 Subject: [PATCH 22/23] Update specs/electra/beacon-chain.md Co-authored-by: Potuz --- specs/electra/beacon-chain.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/specs/electra/beacon-chain.md b/specs/electra/beacon-chain.md index c598d3616d..cd2cd9afda 100644 --- a/specs/electra/beacon-chain.md +++ b/specs/electra/beacon-chain.md @@ -458,7 +458,7 @@ def fake_exponential(factor: int, numerator: int, denominator: int) -> int: return output // denominator ``` -#### `fake_exponential` +#### `get_blob_base_fee_update_fraction` ```python def get_blob_base_fee_update_fraction(max_blobs: int, target_blobs:int)) -> int: From 35fd6c606094479ff49c8ef6b9dab5be7a29ef91 Mon Sep 17 00:00:00 2001 From: Dankrad Feist Date: Tue, 25 Jun 2024 13:43:22 +0200 Subject: [PATCH 23/23] Fix 8.49 computation --- specs/electra/beacon-chain.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/specs/electra/beacon-chain.md b/specs/electra/beacon-chain.md index cd2cd9afda..ed6c1017b2 100644 --- a/specs/electra/beacon-chain.md +++ b/specs/electra/beacon-chain.md @@ -463,8 +463,8 @@ def fake_exponential(factor: int, numerator: int, denominator: int) -> int: ```python def get_blob_base_fee_update_fraction(max_blobs: int, target_blobs:int)) -> int: max_excess_per_block = (max_blobs - target_blobs) * BLOB_GAS_PER_BLOB - # 1 / ln(9 / 8) ~= 8.49 = 849 / 1000 - return max_excess_per_block * 849 // 1000 + # 1 / ln(9 / 8) ~= 8.49 = 849 / 100 + return max_excess_per_block * 849 // 100 ```