From 1c8d57eeb721b6f5d5ba35dea2c31cd0f3c7cf8b Mon Sep 17 00:00:00 2001 From: Jacek Sieka Date: Thu, 27 Oct 2022 10:33:38 +0200 Subject: [PATCH 001/158] Historical batches This PR, a continuation of replaces `historical_roots` with `historical_block_roots`. By keeping an accumulator of historical block roots in the state, it becomes possible to validate the entire block history that led up to that particular state without executing the transitions, and without checking them one by one in backwards order using a parent chain. This is interesting for archival purposes as well as when implementing sync protocols that can verify chunks of blocks quickly, meaning they can be downloaded in any order. It's also useful as it provides a canonical hash by which such chunks of blocks can be named, with a direct reference in the state. In this PR, `historical_roots` is frozen at its current value and `historical_batches` are computed from the merge epoch onwards. After this PR, `block_batch_root` in the state can be used to verify an era of blocks against the state with a simple root check. The `historical_roots` values on the other hand can be used to verify that a constant distributed with clients is valid for a particular state, and therefore extends the block validation all the way back to genesis without backfilling `block_batch_root` and without introducing any new security assumptions in the client. As far as naming goes, it's convenient to talk about an "era" being 8192 slots ~= 1.14 days. The 8192 number comes from the SLOTS_PER_HISTORICAL_ROOT constant. With multiple easily verifable blocks in a file, it becomes trivial to offload block history to out-of-protocol transfer methods (bittorrent / ftp / whatever) - including execution payloads, paving the way for a future in which clients purge block history in p2p. This PR can be applied along with the merge which simplifies payload distribution from the get-go. Both execution and consensus clients benefit because from the merge onwards, they both need to be able to supply ranges of blocks in the sync protocol from what effectively is "cold storage". Another possibility is to include it in a future cleanup PR - this complicates the "cold storage" mode above by not covering exection payloads from start. --- specs/capella/beacon-chain.md | 34 ++++++++++++++++++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-) diff --git a/specs/capella/beacon-chain.md b/specs/capella/beacon-chain.md index 3b6dc4453..d80b70610 100644 --- a/specs/capella/beacon-chain.md +++ b/specs/capella/beacon-chain.md @@ -21,6 +21,7 @@ - [`Withdrawal`](#withdrawal) - [`BLSToExecutionChange`](#blstoexecutionchange) - [`SignedBLSToExecutionChange`](#signedblstoexecutionchange) + - [`HistoricalBatchSummary`](#historicalbatchsummary) - [Extended Containers](#extended-containers) - [`ExecutionPayload`](#executionpayload) - [`ExecutionPayloadHeader`](#executionpayloadheader) @@ -37,6 +38,7 @@ - [Epoch processing](#epoch-processing) - [Full withdrawals](#full-withdrawals) - [Partial withdrawals](#partial-withdrawals) + - [Historical batches updates](#historical-batches-updates) - [Block processing](#block-processing) - [New `process_withdrawals`](#new-process_withdrawals) - [Modified `process_execution_payload`](#modified-process_execution_payload) @@ -132,6 +134,18 @@ class SignedBLSToExecutionChange(Container): signature: BLSSignature ``` +#### `HistoricalBatchSummary` + +```python +class HistoricalBatchSummary(Container): + """ + `HistoricalBatchSummary` matches the components of the phase0 HistoricalBatch + making the two hash_tree_root-compatible. + """ + block_batch_root: Root + state_batch_root: Root +``` + ### Extended Containers #### `ExecutionPayload` @@ -213,7 +227,8 @@ class BeaconState(Container): latest_block_header: BeaconBlockHeader block_roots: Vector[Root, SLOTS_PER_HISTORICAL_ROOT] state_roots: Vector[Root, SLOTS_PER_HISTORICAL_ROOT] - historical_roots: List[Root, HISTORICAL_ROOTS_LIMIT] + historical_roots: List[Root, HISTORICAL_ROOTS_LIMIT] # Frozen in Merge, replaced by historical_batches + historical_batches: List[HistoricalBatchSummary, HISTORICAL_ROOTS_LIMIT] # Valid from Merge onwards # Eth1 eth1_data: Eth1Data eth1_data_votes: List[Eth1Data, EPOCHS_PER_ETH1_VOTING_PERIOD * SLOTS_PER_EPOCH] @@ -320,7 +335,7 @@ def process_epoch(state: BeaconState) -> None: process_effective_balance_updates(state) process_slashings_reset(state) process_randao_mixes_reset(state) - process_historical_roots_update(state) + process_historical_batches_update(state) process_participation_flag_updates(state) process_sync_committee_updates(state) process_full_withdrawals(state) # [New in Capella] @@ -367,6 +382,21 @@ def process_partial_withdrawals(state: BeaconState) -> None: state.next_partial_withdrawal_validator_index = validator_index ``` +#### Historical batches updates + +*Note*: The function `process_historical_batches_update` replaces `process_historical_roots_update` in phase0. + +```python +def process_historical_batches_update(state: BeaconState) -> None: + # Set historical block root accumulator + next_epoch = Epoch(get_current_epoch(state) + 1) + if next_epoch % (SLOTS_PER_HISTORICAL_ROOT // SLOTS_PER_EPOCH) == 0: + historical_batch = HistoricalBatchSummary( + block_batch_root=hash_tree_root(state.block_roots), + state_batch_root=hash_tree_root(state.state_roots)) + state.historical_batches.append(historical_batch) +``` + ### Block processing ```python From 4d1b487b21082cea70c1a0664c1ad0304300f6cc Mon Sep 17 00:00:00 2001 From: Jacek Sieka Date: Thu, 27 Oct 2022 10:38:09 +0200 Subject: [PATCH 002/158] move field last avoids changing "header" fields in state --- specs/capella/beacon-chain.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/specs/capella/beacon-chain.md b/specs/capella/beacon-chain.md index d80b70610..433ccba57 100644 --- a/specs/capella/beacon-chain.md +++ b/specs/capella/beacon-chain.md @@ -228,7 +228,6 @@ class BeaconState(Container): block_roots: Vector[Root, SLOTS_PER_HISTORICAL_ROOT] state_roots: Vector[Root, SLOTS_PER_HISTORICAL_ROOT] historical_roots: List[Root, HISTORICAL_ROOTS_LIMIT] # Frozen in Merge, replaced by historical_batches - historical_batches: List[HistoricalBatchSummary, HISTORICAL_ROOTS_LIMIT] # Valid from Merge onwards # Eth1 eth1_data: Eth1Data eth1_data_votes: List[Eth1Data, EPOCHS_PER_ETH1_VOTING_PERIOD * SLOTS_PER_EPOCH] @@ -259,6 +258,8 @@ class BeaconState(Container): withdrawal_queue: List[Withdrawal, WITHDRAWAL_QUEUE_LIMIT] # [New in Capella] next_withdrawal_index: WithdrawalIndex # [New in Capella] next_partial_withdrawal_validator_index: ValidatorIndex # [New in Capella] + # Deep history + historical_batches: List[HistoricalBatchSummary, HISTORICAL_ROOTS_LIMIT] # Valid from Merge onwards ``` ## Helpers From f42da8d00b803c00a8f275322723e68cc0280ec2 Mon Sep 17 00:00:00 2001 From: Etan Kissling Date: Sat, 19 Nov 2022 12:57:13 +0100 Subject: [PATCH 003/158] Apply `with_config_overrides` to all phases When defining a fork transition test, additional spec forks are made available through `@with_phases(..., other_phases=...)`. The `with_config_overrides` decorator only applies to the primary phase so far, which can be unexpected. `with_config_overrides` is adjusted to override config in subsequent `other_phases` as well. --- .../altair/unittests/test_config_override.py | 14 +++++- tests/core/pyspec/eth2spec/test/context.py | 50 ++++++++++++------- 2 files changed, 44 insertions(+), 20 deletions(-) diff --git a/tests/core/pyspec/eth2spec/test/altair/unittests/test_config_override.py b/tests/core/pyspec/eth2spec/test/altair/unittests/test_config_override.py index 5448781ec..cd186e62f 100644 --- a/tests/core/pyspec/eth2spec/test/altair/unittests/test_config_override.py +++ b/tests/core/pyspec/eth2spec/test/altair/unittests/test_config_override.py @@ -1,10 +1,13 @@ from eth2spec.test.context import ( spec_configured_state_test, spec_state_test_with_matching_config, + spec_test, with_all_phases, + with_matching_spec_config, with_phases, + with_state, ) -from eth2spec.test.helpers.constants import ALTAIR +from eth2spec.test.helpers.constants import ALTAIR, BELLATRIX from eth2spec.test.helpers.forks import ( is_post_capella, is_post_eip4844, ) @@ -56,3 +59,12 @@ def test_override_config_fork_epoch(spec, state): return assert False # Fork is missing + + +@with_phases(phases=[ALTAIR], other_phases=[BELLATRIX]) +@spec_test +@with_state +@with_matching_spec_config +def test_capella_store_with_legacy_data(spec, phases, state): + assert state.fork.current_version == spec.config.ALTAIR_FORK_VERSION + assert phases[BELLATRIX].ALTAIR_FORK_EPOCH == spec.config.ALTAIR_FORK_EPOCH diff --git a/tests/core/pyspec/eth2spec/test/context.py b/tests/core/pyspec/eth2spec/test/context.py index 94910fa47..be8f04ae1 100644 --- a/tests/core/pyspec/eth2spec/test/context.py +++ b/tests/core/pyspec/eth2spec/test/context.py @@ -318,14 +318,16 @@ def config_fork_epoch_overrides(spec, state): return overrides +def with_matching_spec_config(fn): + def decorator(*args, spec: Spec, **kw): + conf = config_fork_epoch_overrides(spec, kw['state']) + overrides = with_config_overrides(conf) + return overrides(fn)(*args, spec=spec, **kw) + return decorator + + def spec_state_test_with_matching_config(fn): - def decorator(fn): - def wrapper(*args, spec: Spec, **kw): - conf = config_fork_epoch_overrides(spec, kw['state']) - overrides = with_config_overrides(conf) - return overrides(fn)(*args, spec=spec, **kw) - return wrapper - return spec_test(with_state(decorator(single_phase(fn)))) + return spec_test(with_state(with_matching_spec_config(single_phase(fn)))) def expect_assertion_error(fn): @@ -569,6 +571,22 @@ def _get_copy_of_spec(spec): return module +def spec_with_config_overrides(spec, config_overrides): + # apply our overrides to a copy of it, and apply it to the spec + config = spec.config._asdict() + config.update(config_overrides) + config_types = spec.Configuration.__annotations__ + modified_config = {k: config_types[k](v) for k, v in config.items()} + + spec.config = spec.Configuration(**modified_config) + + # To output the changed config in a format compatible with yaml test vectors, + # the dict SSZ objects have to be converted into Python built-in types. + output_config = _get_basic_dict(modified_config) + + return spec, output_config + + def with_config_overrides(config_overrides): """ WARNING: the spec_test decorator must wrap this, to ensure the decorated test actually runs. @@ -579,20 +597,14 @@ def with_config_overrides(config_overrides): """ def decorator(fn): def wrapper(*args, spec: Spec, **kw): - spec = _get_copy_of_spec(spec) - - # apply our overrides to a copy of it, and apply it to the spec - config = spec.config._asdict() - config.update(config_overrides) - config_types = spec.Configuration.__annotations__ - modified_config = {k: config_types[k](v) for k, v in config.items()} - - # To output the changed config to could be serialized with yaml test vectors, - # the dict SSZ objects have to be converted into Python built-in types. - output_config = _get_basic_dict(modified_config) + spec, output_config = spec_with_config_overrides(_get_copy_of_spec(spec), config_overrides) yield 'config', 'cfg', output_config - spec.config = spec.Configuration(**modified_config) + if 'phases' in kw: + for fork in kw['phases']: + if is_post_fork(fork, spec.fork): + kw['phases'][fork], _ = \ + spec_with_config_overrides(_get_copy_of_spec(kw['phases'][fork]), config_overrides) # Run the function out = fn(*args, spec=spec, **kw) From db796f70ad597ae8d7b188534259911b889a33d9 Mon Sep 17 00:00:00 2001 From: Etan Kissling Date: Sun, 20 Nov 2022 14:25:50 +0100 Subject: [PATCH 004/158] Add missing `.config` --- .../eth2spec/test/altair/unittests/test_config_override.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/core/pyspec/eth2spec/test/altair/unittests/test_config_override.py b/tests/core/pyspec/eth2spec/test/altair/unittests/test_config_override.py index cd186e62f..6748fac76 100644 --- a/tests/core/pyspec/eth2spec/test/altair/unittests/test_config_override.py +++ b/tests/core/pyspec/eth2spec/test/altair/unittests/test_config_override.py @@ -67,4 +67,4 @@ def test_override_config_fork_epoch(spec, state): @with_matching_spec_config def test_capella_store_with_legacy_data(spec, phases, state): assert state.fork.current_version == spec.config.ALTAIR_FORK_VERSION - assert phases[BELLATRIX].ALTAIR_FORK_EPOCH == spec.config.ALTAIR_FORK_EPOCH + assert phases[BELLATRIX].config.ALTAIR_FORK_EPOCH == spec.config.ALTAIR_FORK_EPOCH From 8bf801ecc64aaa3e1b5ba24b80855bb5e7fa1112 Mon Sep 17 00:00:00 2001 From: Etan Kissling Date: Tue, 6 Dec 2022 17:44:41 +0100 Subject: [PATCH 005/158] Add `block_to_light_client_header` helper Introduce `block_to_light_client_header` helper function to enable future forks to override it with additional info (e.g., execution), without having to change the general light client logic. Likewise, update existing light client data creation flow to use `block_to_light_client_header` and default-initialize empty fields. Furthermore, generalize `create_update` helper to streamline test code using `block_to_light_client_header`. Note: In Altair spec, LC header is the same as `BeaconBlockHeader`. however; future forks will extend it with more information. --- specs/altair/light-client/full-node.md | 64 ++++---- .../light_client/test_update_ranking.py | 154 ++++++++---------- .../light_client/test_sync_protocol.py | 135 +++++++-------- .../eth2spec/test/helpers/light_client.py | 52 +++--- 4 files changed, 181 insertions(+), 224 deletions(-) diff --git a/specs/altair/light-client/full-node.md b/specs/altair/light-client/full-node.md index 53ba4dc82..2dd2ded6c 100644 --- a/specs/altair/light-client/full-node.md +++ b/specs/altair/light-client/full-node.md @@ -11,6 +11,7 @@ - [Introduction](#introduction) - [Helper functions](#helper-functions) - [`compute_merkle_proof_for_state`](#compute_merkle_proof_for_state) + - [`block_to_light_client_header`](#block_to_light_client_header) - [Deriving light client data](#deriving-light-client-data) - [`create_light_client_bootstrap`](#create_light_client_bootstrap) - [`create_light_client_update`](#create_light_client_update) @@ -34,6 +35,19 @@ def compute_merkle_proof_for_state(state: BeaconState, ... ``` +### `block_to_light_client_header` + +```python +def block_to_light_client_header(block: SignedBeaconBlock) -> BeaconBlockHeader: + return BeaconBlockHeader( + slot=block.message.slot, + proposer_index=block.message.proposer_index, + parent_root=block.message.parent_root, + state_root=block.message.state_root, + body_root=hash_tree_root(block.message.body), + ) +``` + ## Deriving light client data Full nodes are expected to derive light client data from historic blocks and states and provide it to other clients. @@ -55,13 +69,7 @@ def create_light_client_bootstrap(state: BeaconState, assert hash_tree_root(header) == hash_tree_root(block.message) return LightClientBootstrap( - header=BeaconBlockHeader( - slot=state.latest_block_header.slot, - proposer_index=state.latest_block_header.proposer_index, - parent_root=state.latest_block_header.parent_root, - state_root=hash_tree_root(state), - body_root=state.latest_block_header.body_root, - ), + header=block_to_light_client_header(block), current_sync_committee=state.current_sync_committee, current_sync_committee_branch=compute_merkle_proof_for_state(state, CURRENT_SYNC_COMMITTEE_INDEX), ) @@ -103,42 +111,30 @@ def create_light_client_update(state: BeaconState, assert hash_tree_root(attested_header) == hash_tree_root(attested_block.message) == block.message.parent_root update_attested_period = compute_sync_committee_period_at_slot(attested_block.message.slot) + update = LightClientUpdate() + + update.attested_header = block_to_light_client_header(attested_block) + # `next_sync_committee` is only useful if the message is signed by the current sync committee if update_attested_period == update_signature_period: - next_sync_committee = attested_state.next_sync_committee - next_sync_committee_branch = compute_merkle_proof_for_state(attested_state, NEXT_SYNC_COMMITTEE_INDEX) - else: - next_sync_committee = SyncCommittee() - next_sync_committee_branch = [Bytes32() for _ in range(floorlog2(NEXT_SYNC_COMMITTEE_INDEX))] + update.next_sync_committee = attested_state.next_sync_committee + update.next_sync_committee_branch = \ + compute_merkle_proof_for_state(attested_state, NEXT_SYNC_COMMITTEE_INDEX) # Indicate finality whenever possible if finalized_block is not None: if finalized_block.message.slot != GENESIS_SLOT: - finalized_header = BeaconBlockHeader( - slot=finalized_block.message.slot, - proposer_index=finalized_block.message.proposer_index, - parent_root=finalized_block.message.parent_root, - state_root=finalized_block.message.state_root, - body_root=hash_tree_root(finalized_block.message.body), - ) - assert hash_tree_root(finalized_header) == attested_state.finalized_checkpoint.root + update.finalized_header = block_to_light_client_header(finalized_block) + assert hash_tree_root(update.finalized_header) == attested_state.finalized_checkpoint.root else: assert attested_state.finalized_checkpoint.root == Bytes32() - finalized_header = BeaconBlockHeader() - finality_branch = compute_merkle_proof_for_state(attested_state, FINALIZED_ROOT_INDEX) - else: - finalized_header = BeaconBlockHeader() - finality_branch = [Bytes32() for _ in range(floorlog2(FINALIZED_ROOT_INDEX))] + update.finality_branch = \ + compute_merkle_proof_for_state(attested_state, FINALIZED_ROOT_INDEX) - return LightClientUpdate( - attested_header=attested_header, - next_sync_committee=next_sync_committee, - next_sync_committee_branch=next_sync_committee_branch, - finalized_header=finalized_header, - finality_branch=finality_branch, - sync_aggregate=block.message.body.sync_aggregate, - signature_slot=block.message.slot, - ) + update.sync_aggregate = block.message.body.sync_aggregate + update.signature_slot = block.message.slot + + return update ``` Full nodes SHOULD provide the best derivable `LightClientUpdate` (according to `is_better_update`) for each sync committee period covering any epochs in range `[max(ALTAIR_FORK_EPOCH, current_epoch - MIN_EPOCHS_FOR_BLOCK_REQUESTS), current_epoch]` where `current_epoch` is defined by the current wall-clock time. Full nodes MAY also provide `LightClientUpdate` for other sync committee periods. diff --git a/tests/core/pyspec/eth2spec/test/altair/light_client/test_update_ranking.py b/tests/core/pyspec/eth2spec/test/altair/light_client/test_update_ranking.py index 23ad79584..bde70a940 100644 --- a/tests/core/pyspec/eth2spec/test/altair/light_client/test_update_ranking.py +++ b/tests/core/pyspec/eth2spec/test/altair/light_client/test_update_ranking.py @@ -9,45 +9,23 @@ from eth2spec.test.helpers.attestations import ( ) from eth2spec.test.helpers.constants import MINIMAL from eth2spec.test.helpers.light_client import ( - get_sync_aggregate, - signed_block_to_header, + create_update, ) from eth2spec.test.helpers.state import ( next_slots, ) -from math import floor -def create_update(spec, test, with_next, with_finality, participation_rate): +def create_test_update(spec, test, with_next, with_finality, participation_rate): attested_state, attested_block, finalized_block = test - num_participants = floor(spec.SYNC_COMMITTEE_SIZE * participation_rate) - - attested_header = signed_block_to_header(spec, attested_block) - - if with_next: - next_sync_committee = attested_state.next_sync_committee - next_sync_committee_branch = spec.compute_merkle_proof_for_state(attested_state, spec.NEXT_SYNC_COMMITTEE_INDEX) - else: - next_sync_committee = spec.SyncCommittee() - next_sync_committee_branch = [spec.Bytes32() for _ in range(spec.floorlog2(spec.NEXT_SYNC_COMMITTEE_INDEX))] - - if with_finality: - finalized_header = signed_block_to_header(spec, finalized_block) - finality_branch = spec.compute_merkle_proof_for_state(attested_state, spec.FINALIZED_ROOT_INDEX) - else: - finalized_header = spec.BeaconBlockHeader() - finality_branch = [spec.Bytes32() for _ in range(spec.floorlog2(spec.FINALIZED_ROOT_INDEX))] - - sync_aggregate, signature_slot = get_sync_aggregate(spec, attested_state, num_participants) - - return spec.LightClientUpdate( - attested_header=attested_header, - next_sync_committee=next_sync_committee, - next_sync_committee_branch=next_sync_committee_branch, - finalized_header=finalized_header, - finality_branch=finality_branch, - sync_aggregate=sync_aggregate, - signature_slot=signature_slot, + return create_update( + spec, + attested_state, + attested_block, + finalized_block, + with_next, + with_finality, + participation_rate, ) @@ -84,76 +62,76 @@ def test_update_ranking(spec, state): # Create updates (in descending order of quality) updates = [ # Updates with sync committee finality - create_update(spec, fin, with_next=1, with_finality=1, participation_rate=1.0), - create_update(spec, lat, with_next=1, with_finality=1, participation_rate=1.0), - create_update(spec, fin, with_next=1, with_finality=1, participation_rate=0.8), - create_update(spec, lat, with_next=1, with_finality=1, participation_rate=0.8), + create_test_update(spec, fin, with_next=1, with_finality=1, participation_rate=1.0), + create_test_update(spec, lat, with_next=1, with_finality=1, participation_rate=1.0), + create_test_update(spec, fin, with_next=1, with_finality=1, participation_rate=0.8), + create_test_update(spec, lat, with_next=1, with_finality=1, participation_rate=0.8), # Updates without sync committee finality - create_update(spec, att, with_next=1, with_finality=1, participation_rate=1.0), - create_update(spec, att, with_next=1, with_finality=1, participation_rate=0.8), + create_test_update(spec, att, with_next=1, with_finality=1, participation_rate=1.0), + create_test_update(spec, att, with_next=1, with_finality=1, participation_rate=0.8), # Updates without indication of any finality - create_update(spec, att, with_next=1, with_finality=0, participation_rate=1.0), - create_update(spec, fin, with_next=1, with_finality=0, participation_rate=1.0), - create_update(spec, lat, with_next=1, with_finality=0, participation_rate=1.0), - create_update(spec, att, with_next=1, with_finality=0, participation_rate=0.8), - create_update(spec, fin, with_next=1, with_finality=0, participation_rate=0.8), - create_update(spec, lat, with_next=1, with_finality=0, participation_rate=0.8), + create_test_update(spec, att, with_next=1, with_finality=0, participation_rate=1.0), + create_test_update(spec, fin, with_next=1, with_finality=0, participation_rate=1.0), + create_test_update(spec, lat, with_next=1, with_finality=0, participation_rate=1.0), + create_test_update(spec, att, with_next=1, with_finality=0, participation_rate=0.8), + create_test_update(spec, fin, with_next=1, with_finality=0, participation_rate=0.8), + create_test_update(spec, lat, with_next=1, with_finality=0, participation_rate=0.8), # Updates with sync committee finality but no `next_sync_committee` - create_update(spec, sig, with_next=0, with_finality=1, participation_rate=1.0), - create_update(spec, fin, with_next=0, with_finality=1, participation_rate=1.0), - create_update(spec, lat, with_next=0, with_finality=1, participation_rate=1.0), - create_update(spec, sig, with_next=0, with_finality=1, participation_rate=0.8), - create_update(spec, fin, with_next=0, with_finality=1, participation_rate=0.8), - create_update(spec, lat, with_next=0, with_finality=1, participation_rate=0.8), + create_test_update(spec, sig, with_next=0, with_finality=1, participation_rate=1.0), + create_test_update(spec, fin, with_next=0, with_finality=1, participation_rate=1.0), + create_test_update(spec, lat, with_next=0, with_finality=1, participation_rate=1.0), + create_test_update(spec, sig, with_next=0, with_finality=1, participation_rate=0.8), + create_test_update(spec, fin, with_next=0, with_finality=1, participation_rate=0.8), + create_test_update(spec, lat, with_next=0, with_finality=1, participation_rate=0.8), # Updates without sync committee finality and also no `next_sync_committee` - create_update(spec, att, with_next=0, with_finality=1, participation_rate=1.0), - create_update(spec, att, with_next=0, with_finality=1, participation_rate=0.8), + create_test_update(spec, att, with_next=0, with_finality=1, participation_rate=1.0), + create_test_update(spec, att, with_next=0, with_finality=1, participation_rate=0.8), # Updates without indication of any finality nor `next_sync_committee` - create_update(spec, sig, with_next=0, with_finality=0, participation_rate=1.0), - create_update(spec, att, with_next=0, with_finality=0, participation_rate=1.0), - create_update(spec, fin, with_next=0, with_finality=0, participation_rate=1.0), - create_update(spec, lat, with_next=0, with_finality=0, participation_rate=1.0), - create_update(spec, sig, with_next=0, with_finality=0, participation_rate=0.8), - create_update(spec, att, with_next=0, with_finality=0, participation_rate=0.8), - create_update(spec, fin, with_next=0, with_finality=0, participation_rate=0.8), - create_update(spec, lat, with_next=0, with_finality=0, participation_rate=0.8), + create_test_update(spec, sig, with_next=0, with_finality=0, participation_rate=1.0), + create_test_update(spec, att, with_next=0, with_finality=0, participation_rate=1.0), + create_test_update(spec, fin, with_next=0, with_finality=0, participation_rate=1.0), + create_test_update(spec, lat, with_next=0, with_finality=0, participation_rate=1.0), + create_test_update(spec, sig, with_next=0, with_finality=0, participation_rate=0.8), + create_test_update(spec, att, with_next=0, with_finality=0, participation_rate=0.8), + create_test_update(spec, fin, with_next=0, with_finality=0, participation_rate=0.8), + create_test_update(spec, lat, with_next=0, with_finality=0, participation_rate=0.8), # Updates with low sync committee participation - create_update(spec, fin, with_next=1, with_finality=1, participation_rate=0.4), - create_update(spec, lat, with_next=1, with_finality=1, participation_rate=0.4), - create_update(spec, att, with_next=1, with_finality=1, participation_rate=0.4), - create_update(spec, att, with_next=1, with_finality=0, participation_rate=0.4), - create_update(spec, fin, with_next=1, with_finality=0, participation_rate=0.4), - create_update(spec, lat, with_next=1, with_finality=0, participation_rate=0.4), - create_update(spec, sig, with_next=0, with_finality=1, participation_rate=0.4), - create_update(spec, fin, with_next=0, with_finality=1, participation_rate=0.4), - create_update(spec, lat, with_next=0, with_finality=1, participation_rate=0.4), - create_update(spec, att, with_next=0, with_finality=1, participation_rate=0.4), - create_update(spec, sig, with_next=0, with_finality=0, participation_rate=0.4), - create_update(spec, att, with_next=0, with_finality=0, participation_rate=0.4), - create_update(spec, fin, with_next=0, with_finality=0, participation_rate=0.4), - create_update(spec, lat, with_next=0, with_finality=0, participation_rate=0.4), + create_test_update(spec, fin, with_next=1, with_finality=1, participation_rate=0.4), + create_test_update(spec, lat, with_next=1, with_finality=1, participation_rate=0.4), + create_test_update(spec, att, with_next=1, with_finality=1, participation_rate=0.4), + create_test_update(spec, att, with_next=1, with_finality=0, participation_rate=0.4), + create_test_update(spec, fin, with_next=1, with_finality=0, participation_rate=0.4), + create_test_update(spec, lat, with_next=1, with_finality=0, participation_rate=0.4), + create_test_update(spec, sig, with_next=0, with_finality=1, participation_rate=0.4), + create_test_update(spec, fin, with_next=0, with_finality=1, participation_rate=0.4), + create_test_update(spec, lat, with_next=0, with_finality=1, participation_rate=0.4), + create_test_update(spec, att, with_next=0, with_finality=1, participation_rate=0.4), + create_test_update(spec, sig, with_next=0, with_finality=0, participation_rate=0.4), + create_test_update(spec, att, with_next=0, with_finality=0, participation_rate=0.4), + create_test_update(spec, fin, with_next=0, with_finality=0, participation_rate=0.4), + create_test_update(spec, lat, with_next=0, with_finality=0, participation_rate=0.4), # Updates with very low sync committee participation - create_update(spec, fin, with_next=1, with_finality=1, participation_rate=0.2), - create_update(spec, lat, with_next=1, with_finality=1, participation_rate=0.2), - create_update(spec, att, with_next=1, with_finality=1, participation_rate=0.2), - create_update(spec, att, with_next=1, with_finality=0, participation_rate=0.2), - create_update(spec, fin, with_next=1, with_finality=0, participation_rate=0.2), - create_update(spec, lat, with_next=1, with_finality=0, participation_rate=0.2), - create_update(spec, sig, with_next=0, with_finality=1, participation_rate=0.2), - create_update(spec, fin, with_next=0, with_finality=1, participation_rate=0.2), - create_update(spec, lat, with_next=0, with_finality=1, participation_rate=0.2), - create_update(spec, att, with_next=0, with_finality=1, participation_rate=0.2), - create_update(spec, sig, with_next=0, with_finality=0, participation_rate=0.2), - create_update(spec, att, with_next=0, with_finality=0, participation_rate=0.2), - create_update(spec, fin, with_next=0, with_finality=0, participation_rate=0.2), - create_update(spec, lat, with_next=0, with_finality=0, participation_rate=0.2), + create_test_update(spec, fin, with_next=1, with_finality=1, participation_rate=0.2), + create_test_update(spec, lat, with_next=1, with_finality=1, participation_rate=0.2), + create_test_update(spec, att, with_next=1, with_finality=1, participation_rate=0.2), + create_test_update(spec, att, with_next=1, with_finality=0, participation_rate=0.2), + create_test_update(spec, fin, with_next=1, with_finality=0, participation_rate=0.2), + create_test_update(spec, lat, with_next=1, with_finality=0, participation_rate=0.2), + create_test_update(spec, sig, with_next=0, with_finality=1, participation_rate=0.2), + create_test_update(spec, fin, with_next=0, with_finality=1, participation_rate=0.2), + create_test_update(spec, lat, with_next=0, with_finality=1, participation_rate=0.2), + create_test_update(spec, att, with_next=0, with_finality=1, participation_rate=0.2), + create_test_update(spec, sig, with_next=0, with_finality=0, participation_rate=0.2), + create_test_update(spec, att, with_next=0, with_finality=0, participation_rate=0.2), + create_test_update(spec, fin, with_next=0, with_finality=0, participation_rate=0.2), + create_test_update(spec, lat, with_next=0, with_finality=0, participation_rate=0.2), ] yield "updates", updates diff --git a/tests/core/pyspec/eth2spec/test/altair/unittests/light_client/test_sync_protocol.py b/tests/core/pyspec/eth2spec/test/altair/unittests/light_client/test_sync_protocol.py index bf09cc30e..a72f1980b 100644 --- a/tests/core/pyspec/eth2spec/test/altair/unittests/light_client/test_sync_protocol.py +++ b/tests/core/pyspec/eth2spec/test/altair/unittests/light_client/test_sync_protocol.py @@ -11,43 +11,44 @@ from eth2spec.test.helpers.attestations import ( ) from eth2spec.test.helpers.constants import MINIMAL from eth2spec.test.helpers.light_client import ( - get_sync_aggregate, - initialize_light_client_store, - signed_block_to_header, + create_update, ) from eth2spec.test.helpers.state import ( next_slots, ) +def setup_test(spec, state): + trusted_block = spec.SignedBeaconBlock() + trusted_block.message.state_root = state.hash_tree_root() + trusted_block_root = trusted_block.message.hash_tree_root() + bootstrap = spec.create_light_client_bootstrap(state, trusted_block) + store = spec.initialize_light_client_store(trusted_block_root, bootstrap) + store.next_sync_committee = state.next_sync_committee + + return (trusted_block, store) + + @with_altair_and_later @spec_state_test_with_matching_config def test_process_light_client_update_not_timeout(spec, state): - store = initialize_light_client_store(spec, state) + genesis_block, store = setup_test(spec, state) # Block at slot 1 doesn't increase sync committee period, so it won't force update store.finalized_header attested_block = state_transition_with_full_block(spec, state, False, False) - attested_header = signed_block_to_header(spec, attested_block) - - # Sync committee signing the attested_header - sync_aggregate, signature_slot = get_sync_aggregate(spec, state) - next_sync_committee = spec.SyncCommittee() - next_sync_committee_branch = [spec.Bytes32() for _ in range(spec.floorlog2(spec.NEXT_SYNC_COMMITTEE_INDEX))] + signature_slot = state.slot + 1 # Ensure that finality checkpoint is genesis assert state.finalized_checkpoint.epoch == 0 - # Finality is unchanged - finalized_header = spec.BeaconBlockHeader() - finality_branch = [spec.Bytes32() for _ in range(spec.floorlog2(spec.FINALIZED_ROOT_INDEX))] - update = spec.LightClientUpdate( - attested_header=attested_header, - next_sync_committee=next_sync_committee, - next_sync_committee_branch=next_sync_committee_branch, - finalized_header=finalized_header, - finality_branch=finality_branch, - sync_aggregate=sync_aggregate, - signature_slot=signature_slot, + update = create_update( + spec, + attested_state=state, + attested_block=attested_block, + finalized_block=genesis_block, + with_next=False, + with_finality=False, + participation_rate=1.0, ) pre_store = deepcopy(store) @@ -64,7 +65,7 @@ def test_process_light_client_update_not_timeout(spec, state): @spec_state_test_with_matching_config @with_presets([MINIMAL], reason="too slow") def test_process_light_client_update_at_period_boundary(spec, state): - store = initialize_light_client_store(spec, state) + genesis_block, store = setup_test(spec, state) # Forward to slot before next sync committee period so that next block is final one in period next_slots(spec, state, spec.UPDATE_TIMEOUT - 2) @@ -73,25 +74,16 @@ def test_process_light_client_update_at_period_boundary(spec, state): assert store_period == update_period attested_block = state_transition_with_full_block(spec, state, False, False) - attested_header = signed_block_to_header(spec, attested_block) + signature_slot = state.slot + 1 - # Sync committee signing the attested_header - sync_aggregate, signature_slot = get_sync_aggregate(spec, state) - next_sync_committee = spec.SyncCommittee() - next_sync_committee_branch = [spec.Bytes32() for _ in range(spec.floorlog2(spec.NEXT_SYNC_COMMITTEE_INDEX))] - - # Finality is unchanged - finalized_header = spec.BeaconBlockHeader() - finality_branch = [spec.Bytes32() for _ in range(spec.floorlog2(spec.FINALIZED_ROOT_INDEX))] - - update = spec.LightClientUpdate( - attested_header=attested_header, - next_sync_committee=next_sync_committee, - next_sync_committee_branch=next_sync_committee_branch, - finalized_header=finalized_header, - finality_branch=finality_branch, - sync_aggregate=sync_aggregate, - signature_slot=signature_slot, + update = create_update( + spec, + attested_state=state, + attested_block=attested_block, + finalized_block=genesis_block, + with_next=False, + with_finality=False, + participation_rate=1.0, ) pre_store = deepcopy(store) @@ -108,7 +100,7 @@ def test_process_light_client_update_at_period_boundary(spec, state): @spec_state_test_with_matching_config @with_presets([MINIMAL], reason="too slow") def test_process_light_client_update_timeout(spec, state): - store = initialize_light_client_store(spec, state) + genesis_block, store = setup_test(spec, state) # Forward to next sync committee period next_slots(spec, state, spec.UPDATE_TIMEOUT) @@ -117,26 +109,16 @@ def test_process_light_client_update_timeout(spec, state): assert store_period + 1 == update_period attested_block = state_transition_with_full_block(spec, state, False, False) - attested_header = signed_block_to_header(spec, attested_block) + signature_slot = state.slot + 1 - # Sync committee signing the attested_header - sync_aggregate, signature_slot = get_sync_aggregate(spec, state) - - # Sync committee is updated - next_sync_committee = state.next_sync_committee - next_sync_committee_branch = spec.compute_merkle_proof_for_state(state, spec.NEXT_SYNC_COMMITTEE_INDEX) - # Finality is unchanged - finalized_header = spec.BeaconBlockHeader() - finality_branch = [spec.Bytes32() for _ in range(spec.floorlog2(spec.FINALIZED_ROOT_INDEX))] - - update = spec.LightClientUpdate( - attested_header=attested_header, - next_sync_committee=next_sync_committee, - next_sync_committee_branch=next_sync_committee_branch, - finalized_header=finalized_header, - finality_branch=finality_branch, - sync_aggregate=sync_aggregate, - signature_slot=signature_slot, + update = create_update( + spec, + attested_state=state, + attested_block=attested_block, + finalized_block=genesis_block, + with_next=True, + with_finality=False, + participation_rate=1.0, ) pre_store = deepcopy(store) @@ -153,7 +135,7 @@ def test_process_light_client_update_timeout(spec, state): @spec_state_test_with_matching_config @with_presets([MINIMAL], reason="too slow") def test_process_light_client_update_finality_updated(spec, state): - store = initialize_light_client_store(spec, state) + _, store = setup_test(spec, state) # Change finality blocks = [] @@ -169,28 +151,21 @@ def test_process_light_client_update_finality_updated(spec, state): assert store_period == update_period attested_block = blocks[-1] - attested_header = signed_block_to_header(spec, attested_block) + signature_slot = state.slot + 1 - # Sync committee signing the attested_header - sync_aggregate, signature_slot = get_sync_aggregate(spec, state) - - # Updated sync_committee and finality - next_sync_committee = spec.SyncCommittee() - next_sync_committee_branch = [spec.Bytes32() for _ in range(spec.floorlog2(spec.NEXT_SYNC_COMMITTEE_INDEX))] + # Updated finality finalized_block = blocks[spec.SLOTS_PER_EPOCH - 1] - finalized_header = signed_block_to_header(spec, finalized_block) - assert finalized_header.slot == spec.compute_start_slot_at_epoch(state.finalized_checkpoint.epoch) - assert finalized_header.hash_tree_root() == state.finalized_checkpoint.root - finality_branch = spec.compute_merkle_proof_for_state(state, spec.FINALIZED_ROOT_INDEX) + assert finalized_block.message.slot == spec.compute_start_slot_at_epoch(state.finalized_checkpoint.epoch) + assert finalized_block.message.hash_tree_root() == state.finalized_checkpoint.root - update = spec.LightClientUpdate( - attested_header=attested_header, - next_sync_committee=next_sync_committee, - next_sync_committee_branch=next_sync_committee_branch, - finalized_header=finalized_header, - finality_branch=finality_branch, - sync_aggregate=sync_aggregate, - signature_slot=signature_slot, + update = create_update( + spec, + attested_state=state, + attested_block=attested_block, + finalized_block=finalized_block, + with_next=False, + with_finality=True, + participation_rate=1.0, ) spec.process_light_client_update(store, update, signature_slot, state.genesis_validators_root) diff --git a/tests/core/pyspec/eth2spec/test/helpers/light_client.py b/tests/core/pyspec/eth2spec/test/helpers/light_client.py index 8d632b3a1..39175a352 100644 --- a/tests/core/pyspec/eth2spec/test/helpers/light_client.py +++ b/tests/core/pyspec/eth2spec/test/helpers/light_client.py @@ -5,28 +5,7 @@ from eth2spec.test.helpers.sync_committee import ( compute_aggregate_sync_committee_signature, compute_committee_indices, ) - - -def signed_block_to_header(spec, block): - return spec.BeaconBlockHeader( - slot=block.message.slot, - proposer_index=block.message.proposer_index, - parent_root=block.message.parent_root, - state_root=block.message.state_root, - body_root=block.message.body.hash_tree_root(), - ) - - -def initialize_light_client_store(spec, state): - return spec.LightClientStore( - finalized_header=spec.BeaconBlockHeader(), - current_sync_committee=state.current_sync_committee, - next_sync_committee=state.next_sync_committee, - best_valid_update=None, - optimistic_header=spec.BeaconBlockHeader(), - previous_max_active_participants=0, - current_max_active_participants=0, - ) +from math import floor def get_sync_aggregate(spec, state, num_participants=None, signature_slot=None): @@ -60,3 +39,32 @@ def get_sync_aggregate(spec, state, num_participants=None, signature_slot=None): sync_committee_signature=sync_committee_signature, ) return sync_aggregate, signature_slot + + +def create_update(spec, + attested_state, + attested_block, + finalized_block, + with_next, + with_finality, + participation_rate): + num_participants = floor(spec.SYNC_COMMITTEE_SIZE * participation_rate) + + update = spec.LightClientUpdate() + + update.attested_header = spec.block_to_light_client_header(attested_block) + + if with_next: + update.next_sync_committee = attested_state.next_sync_committee + update.next_sync_committee_branch = \ + spec.compute_merkle_proof_for_state(attested_state, spec.NEXT_SYNC_COMMITTEE_INDEX) + + if with_finality: + update.finalized_header = spec.block_to_light_client_header(finalized_block) + update.finality_branch = \ + spec.compute_merkle_proof_for_state(attested_state, spec.FINALIZED_ROOT_INDEX) + + update.sync_aggregate, update.signature_slot = \ + get_sync_aggregate(spec, attested_state, num_participants) + + return update From 0fb0b26742e18ae86c545471e0cc98dab10f716a Mon Sep 17 00:00:00 2001 From: Etan Kissling Date: Tue, 6 Dec 2022 22:05:19 +0100 Subject: [PATCH 006/158] Add accessors for LC header Introduce `get_lc_beacon_slot` and `get_lc_beacon_root` accessors similar to `get_current_slot(state)` to account for future extensions to the light client header structure that may override how those fields are accessed. Idea is to extend with execution accessors in the future. --- specs/altair/light-client/full-node.md | 10 +-- specs/altair/light-client/light-client.md | 2 +- specs/altair/light-client/p2p-interface.md | 20 ++--- specs/altair/light-client/sync-protocol.md | 70 ++++++++++------ .../test/altair/light_client/test_sync.py | 80 +++++++++---------- .../light_client/test_update_ranking.py | 2 +- .../light_client/test_sync_protocol.py | 6 +- tests/formats/light_client/sync.md | 8 +- 8 files changed, 108 insertions(+), 90 deletions(-) diff --git a/specs/altair/light-client/full-node.md b/specs/altair/light-client/full-node.md index 53ba4dc82..0afbe54fb 100644 --- a/specs/altair/light-client/full-node.md +++ b/specs/altair/light-client/full-node.md @@ -121,7 +121,7 @@ def create_light_client_update(state: BeaconState, state_root=finalized_block.message.state_root, body_root=hash_tree_root(finalized_block.message.body), ) - assert hash_tree_root(finalized_header) == attested_state.finalized_checkpoint.root + assert get_lc_beacon_root(update.finalized_header) == attested_state.finalized_checkpoint.root else: assert attested_state.finalized_checkpoint.root == Bytes32() finalized_header = BeaconBlockHeader() @@ -143,8 +143,8 @@ def create_light_client_update(state: BeaconState, Full nodes SHOULD provide the best derivable `LightClientUpdate` (according to `is_better_update`) for each sync committee period covering any epochs in range `[max(ALTAIR_FORK_EPOCH, current_epoch - MIN_EPOCHS_FOR_BLOCK_REQUESTS), current_epoch]` where `current_epoch` is defined by the current wall-clock time. Full nodes MAY also provide `LightClientUpdate` for other sync committee periods. -- `LightClientUpdate` are assigned to sync committee periods based on their `attested_header.slot` -- `LightClientUpdate` are only considered if `compute_sync_committee_period_at_slot(update.attested_header.slot) == compute_sync_committee_period_at_slot(update.signature_slot)` +- `LightClientUpdate` are assigned to sync committee periods based on their `get_lc_beacon_slot(attested_header)` +- `LightClientUpdate` are only considered if `compute_sync_committee_period_at_slot(get_lc_beacon_slot(update.attested_header)) == compute_sync_committee_period_at_slot(update.signature_slot)` - Only `LightClientUpdate` with `next_sync_committee` as selected by fork choice are provided, regardless of ranking by `is_better_update`. To uniquely identify a non-finalized sync committee fork, all of `period`, `current_sync_committee` and `next_sync_committee` need to be incorporated, as sync committees may reappear over time. ### `create_light_client_finality_update` @@ -160,7 +160,7 @@ def create_light_client_finality_update(update: LightClientUpdate) -> LightClien ) ``` -Full nodes SHOULD provide the `LightClientFinalityUpdate` with the highest `attested_header.slot` (if multiple, highest `signature_slot`) as selected by fork choice, and SHOULD support a push mechanism to deliver new `LightClientFinalityUpdate` whenever `finalized_header` changes. +Full nodes SHOULD provide the `LightClientFinalityUpdate` with the highest `get_lc_beacon_slot(attested_header)` (if multiple, highest `signature_slot`) as selected by fork choice, and SHOULD support a push mechanism to deliver new `LightClientFinalityUpdate` whenever `finalized_header` changes. ### `create_light_client_optimistic_update` @@ -173,4 +173,4 @@ def create_light_client_optimistic_update(update: LightClientUpdate) -> LightCli ) ``` -Full nodes SHOULD provide the `LightClientOptimisticUpdate` with the highest `attested_header.slot` (if multiple, highest `signature_slot`) as selected by fork choice, and SHOULD support a push mechanism to deliver new `LightClientOptimisticUpdate` whenever `attested_header` changes. +Full nodes SHOULD provide the `LightClientOptimisticUpdate` with the highest `get_lc_beacon_slot(attested_header)` (if multiple, highest `signature_slot`) as selected by fork choice, and SHOULD support a push mechanism to deliver new `LightClientOptimisticUpdate` whenever `attested_header` changes. diff --git a/specs/altair/light-client/light-client.md b/specs/altair/light-client/light-client.md index 318950437..15ed3112d 100644 --- a/specs/altair/light-client/light-client.md +++ b/specs/altair/light-client/light-client.md @@ -23,7 +23,7 @@ This document explains how light clients MAY obtain light client data to sync wi 1. The light client MUST be configured out-of-band with a spec/preset (including fork schedule), with `genesis_state` (including `genesis_time` and `genesis_validators_root`), and with a trusted block root. The trusted block SHOULD be within the weak subjectivity period, and its root SHOULD be from a finalized `Checkpoint`. 2. The local clock is initialized based on the configured `genesis_time`, and the current fork digest is determined to browse for and connect to relevant light client data providers. 3. The light client fetches a [`LightClientBootstrap`](./sync-protocol.md#lightclientbootstrap) object for the configured trusted block root. The `bootstrap` object is passed to [`initialize_light_client_store`](./sync-protocol.md#initialize_light_client_store) to obtain a local [`LightClientStore`](./sync-protocol.md#lightclientstore). -4. The light client tracks the sync committee periods `finalized_period` from `store.finalized_header.slot`, `optimistic_period` from `store.optimistic_header.slot`, and `current_period` from `current_slot` based on the local clock. +4. The light client tracks the sync committee periods `finalized_period` from `get_lc_beacon_slot(store.finalized_header)`, `optimistic_period` from `get_lc_beacon_slot(store.optimistic_header)`, and `current_period` from `current_slot` based on the local clock. 1. When `finalized_period == optimistic_period` and [`is_next_sync_committee_known`](./sync-protocol.md#is_next_sync_committee_known) indicates `False`, the light client fetches a [`LightClientUpdate`](./sync-protocol.md#lightclientupdate) for `finalized_period`. If `finalized_period == current_period`, this fetch SHOULD be scheduled at a random time before `current_period` advances. 2. When `finalized_period + 1 < current_period`, the light client fetches a `LightClientUpdate` for each sync committee period in range `[finalized_period + 1, current_period)` (current period excluded) 3. When `finalized_period + 1 >= current_period`, the light client keeps observing [`LightClientFinalityUpdate`](./sync-protocol.md#lightclientfinalityupdate) and [`LightClientOptimisticUpdate`](./sync-protocol.md#lightclientoptimisticupdate). Received objects are passed to [`process_light_client_finality_update`](./sync-protocol.md#process_light_client_finality_update) and [`process_light_client_optimistic_update`](./sync-protocol.md#process_light_client_optimistic_update). This ensures that `finalized_header` and `optimistic_header` reflect the latest blocks. diff --git a/specs/altair/light-client/p2p-interface.md b/specs/altair/light-client/p2p-interface.md index 501269ee2..13b8625b1 100644 --- a/specs/altair/light-client/p2p-interface.md +++ b/specs/altair/light-client/p2p-interface.md @@ -67,11 +67,11 @@ For full nodes, the following validations MUST additionally pass before forwardi For light clients, the following validations MUST additionally pass before forwarding the `finality_update` on the network. - _[REJECT]_ The `finality_update` is valid -- i.e. validate that `process_light_client_finality_update` does not indicate errors -- _[IGNORE]_ The `finality_update` advances the `finalized_header` of the local `LightClientStore` -- i.e. validate that processing `finality_update` increases `store.finalized_header.slot` +- _[IGNORE]_ The `finality_update` advances the `finalized_header` of the local `LightClientStore` -- i.e. validate that processing `finality_update` increases `get_lc_beacon_slot(store.finalized_header)` Light clients SHOULD call `process_light_client_finality_update` even if the message is ignored. -The gossip `ForkDigest`-context is determined based on `compute_fork_version(compute_epoch_at_slot(finality_update.attested_header.slot))`. +The gossip `ForkDigest`-context is determined based on `compute_fork_version(compute_epoch_at_slot(get_lc_beacon_slot(finality_update.attested_header)))`. Per `context = compute_fork_digest(fork_version, genesis_validators_root)`: @@ -95,11 +95,11 @@ For full nodes, the following validations MUST additionally pass before forwardi For light clients, the following validations MUST additionally pass before forwarding the `optimistic_update` on the network. - _[REJECT]_ The `optimistic_update` is valid -- i.e. validate that `process_light_client_optimistic_update` does not indicate errors -- _[IGNORE]_ The `optimistic_update` either matches corresponding fields of the most recently forwarded `LightClientFinalityUpdate` (if any), or it advances the `optimistic_header` of the local `LightClientStore` -- i.e. validate that processing `optimistic_update` increases `store.optimistic_header.slot` +- _[IGNORE]_ The `optimistic_update` either matches corresponding fields of the most recently forwarded `LightClientFinalityUpdate` (if any), or it advances the `optimistic_header` of the local `LightClientStore` -- i.e. validate that processing `optimistic_update` increases `get_lc_beacon_slot(store.optimistic_header)` Light clients SHOULD call `process_light_client_optimistic_update` even if the message is ignored. -The gossip `ForkDigest`-context is determined based on `compute_fork_version(compute_epoch_at_slot(optimistic_update.attested_header.slot))`. +The gossip `ForkDigest`-context is determined based on `compute_fork_version(compute_epoch_at_slot(get_lc_beacon_slot(optimistic_update.attested_header)))`. Per `context = compute_fork_digest(fork_version, genesis_validators_root)`: @@ -142,7 +142,7 @@ Peers SHOULD provide results as defined in [`create_light_client_bootstrap`](./f When a `LightClientBootstrap` instance cannot be produced for a given block root, peers SHOULD respond with error code `3: ResourceUnavailable`. -A `ForkDigest`-context based on `compute_fork_version(compute_epoch_at_slot(bootstrap.header.slot))` is used to select the fork namespace of the Response type. +A `ForkDigest`-context based on `compute_fork_version(compute_epoch_at_slot(get_lc_beacon_slot(bootstrap.header)))` is used to select the fork namespace of the Response type. Per `context = compute_fork_digest(fork_version, genesis_validators_root)`: @@ -180,7 +180,7 @@ The response MUST consist of zero or more `response_chunk`. Each _successful_ `r Peers SHOULD provide results as defined in [`create_light_client_update`](./full-node.md#create_light_client_update). They MUST respond with at least the earliest known result within the requested range, and MUST send results in consecutive order (by period). The response MUST NOT contain more than `min(MAX_REQUEST_LIGHT_CLIENT_UPDATES, count)` results. -For each `response_chunk`, a `ForkDigest`-context based on `compute_fork_version(compute_epoch_at_slot(update.attested_header.slot))` is used to select the fork namespace of the Response type. Note that this `fork_version` may be different from the one used to verify the `update.sync_aggregate`, which is based on `update.signature_slot`. +For each `response_chunk`, a `ForkDigest`-context based on `compute_fork_version(compute_epoch_at_slot(get_lc_beacon_slot(update.attested_header)))` is used to select the fork namespace of the Response type. Note that this `fork_version` may be different from the one used to verify the `update.sync_aggregate`, which is based on `update.signature_slot`. Per `context = compute_fork_digest(fork_version, genesis_validators_root)`: @@ -211,7 +211,7 @@ Peers SHOULD provide results as defined in [`create_light_client_finality_update When no `LightClientFinalityUpdate` is available, peers SHOULD respond with error code `3: ResourceUnavailable`. -A `ForkDigest`-context based on `compute_fork_version(compute_epoch_at_slot(finality_update.attested_header.slot))` is used to select the fork namespace of the Response type. Note that this `fork_version` may be different from the one used to verify the `finality_update.sync_aggregate`, which is based on `finality_update.signature_slot`. +A `ForkDigest`-context based on `compute_fork_version(compute_epoch_at_slot(get_lc_beacon_slot(finality_update.attested_header)))` is used to select the fork namespace of the Response type. Note that this `fork_version` may be different from the one used to verify the `finality_update.sync_aggregate`, which is based on `finality_update.signature_slot`. Per `context = compute_fork_digest(fork_version, genesis_validators_root)`: @@ -242,7 +242,7 @@ Peers SHOULD provide results as defined in [`create_light_client_optimistic_upda When no `LightClientOptimisticUpdate` is available, peers SHOULD respond with error code `3: ResourceUnavailable`. -A `ForkDigest`-context based on `compute_fork_version(compute_epoch_at_slot(optimistic_update.attested_header.slot))` is used to select the fork namespace of the Response type. Note that this `fork_version` may be different from the one used to verify the `optimistic_update.sync_aggregate`, which is based on `optimistic_update.signature_slot`. +A `ForkDigest`-context based on `compute_fork_version(compute_epoch_at_slot(get_lc_beacon_slot(optimistic_update.attested_header)))` is used to select the fork namespace of the Response type. Note that this `fork_version` may be different from the one used to verify the `optimistic_update.sync_aggregate`, which is based on `optimistic_update.signature_slot`. Per `context = compute_fork_digest(fork_version, genesis_validators_root)`: @@ -273,7 +273,7 @@ All full nodes SHOULD subscribe to and provide stability on the [`light_client_f Whenever fork choice selects a new head block with a sync aggregate participation `>= MIN_SYNC_COMMITTEE_PARTICIPANTS` and a post-Altair parent block, full nodes with at least one validator assigned to the current sync committee at the block's `slot` SHOULD broadcast derived light client data as follows: -- If `finalized_header.slot` increased, a `LightClientFinalityUpdate` SHOULD be broadcasted to the pubsub topic `light_client_finality_update` if no matching message has not yet been forwarded as part of gossip validation. -- If `attested_header.slot` increased, a `LightClientOptimisticUpdate` SHOULD be broadcasted to the pubsub topic `light_client_optimistic_update` if no matching message has not yet been forwarded as part of gossip validation. +- If `get_lc_beacon_slot(finalized_header)` increased, a `LightClientFinalityUpdate` SHOULD be broadcasted to the pubsub topic `light_client_finality_update` if no matching message has not yet been forwarded as part of gossip validation. +- If `get_lc_beacon_slot(attested_header)` increased, a `LightClientOptimisticUpdate` SHOULD be broadcasted to the pubsub topic `light_client_optimistic_update` if no matching message has not yet been forwarded as part of gossip validation. These messages SHOULD be broadcasted after one-third of `slot` has transpired (`SECONDS_PER_SLOT / INTERVALS_PER_SLOT` seconds after the start of the slot). To ensure that the corresponding block was given enough time to propagate through the network, they SHOULD NOT be sent earlier. Note that this is different from how other messages are handled, e.g., attestations, which may be sent early. diff --git a/specs/altair/light-client/sync-protocol.md b/specs/altair/light-client/sync-protocol.md index 793483bc0..5ee0d66fe 100644 --- a/specs/altair/light-client/sync-protocol.md +++ b/specs/altair/light-client/sync-protocol.md @@ -19,6 +19,8 @@ - [`LightClientOptimisticUpdate`](#lightclientoptimisticupdate) - [`LightClientStore`](#lightclientstore) - [Helper functions](#helper-functions) + - [`get_lc_beacon_slot`](#get_lc_beacon_slot) + - [`get_lc_beacon_root`](#get_lc_beacon_root) - [`is_sync_committee_update`](#is_sync_committee_update) - [`is_finality_update`](#is_finality_update) - [`is_better_update`](#is_better_update) @@ -150,6 +152,20 @@ class LightClientStore(object): ## Helper functions +### `get_lc_beacon_slot` + +```python +def get_lc_beacon_slot(header: BeaconBlockHeader) -> Slot: + return header.slot +``` + +### `get_lc_beacon_root` + +```python +def get_lc_beacon_root(header: BeaconBlockHeader) -> Root: + return hash_tree_root(header) +``` + ### `is_sync_committee_update` ```python @@ -181,11 +197,11 @@ def is_better_update(new_update: LightClientUpdate, old_update: LightClientUpdat # Compare presence of relevant sync committee new_has_relevant_sync_committee = is_sync_committee_update(new_update) and ( - compute_sync_committee_period_at_slot(new_update.attested_header.slot) + compute_sync_committee_period_at_slot(get_lc_beacon_slot(new_update.attested_header)) == compute_sync_committee_period_at_slot(new_update.signature_slot) ) old_has_relevant_sync_committee = is_sync_committee_update(old_update) and ( - compute_sync_committee_period_at_slot(old_update.attested_header.slot) + compute_sync_committee_period_at_slot(get_lc_beacon_slot(old_update.attested_header)) == compute_sync_committee_period_at_slot(old_update.signature_slot) ) if new_has_relevant_sync_committee != old_has_relevant_sync_committee: @@ -200,12 +216,12 @@ def is_better_update(new_update: LightClientUpdate, old_update: LightClientUpdat # Compare sync committee finality if new_has_finality: new_has_sync_committee_finality = ( - compute_sync_committee_period_at_slot(new_update.finalized_header.slot) - == compute_sync_committee_period_at_slot(new_update.attested_header.slot) + compute_sync_committee_period_at_slot(get_lc_beacon_slot(new_update.finalized_header)) + == compute_sync_committee_period_at_slot(get_lc_beacon_slot(new_update.attested_header)) ) old_has_sync_committee_finality = ( - compute_sync_committee_period_at_slot(old_update.finalized_header.slot) - == compute_sync_committee_period_at_slot(old_update.attested_header.slot) + compute_sync_committee_period_at_slot(get_lc_beacon_slot(old_update.finalized_header)) + == compute_sync_committee_period_at_slot(get_lc_beacon_slot(old_update.attested_header)) ) if new_has_sync_committee_finality != old_has_sync_committee_finality: return new_has_sync_committee_finality @@ -215,8 +231,8 @@ def is_better_update(new_update: LightClientUpdate, old_update: LightClientUpdat return new_num_active_participants > old_num_active_participants # Tiebreaker 2: Prefer older data (fewer changes to best) - if new_update.attested_header.slot != old_update.attested_header.slot: - return new_update.attested_header.slot < old_update.attested_header.slot + if get_lc_beacon_slot(new_update.attested_header) != get_lc_beacon_slot(old_update.attested_header): + return get_lc_beacon_slot(new_update.attested_header) < get_lc_beacon_slot(old_update.attested_header) return new_update.signature_slot < old_update.signature_slot ``` @@ -260,7 +276,7 @@ A light client maintains its state in a `store` object of type `LightClientStore ```python def initialize_light_client_store(trusted_block_root: Root, bootstrap: LightClientBootstrap) -> LightClientStore: - assert hash_tree_root(bootstrap.header) == trusted_block_root + assert get_lc_beacon_root(bootstrap.header) == trusted_block_root assert is_valid_merkle_branch( leaf=hash_tree_root(bootstrap.current_sync_committee), @@ -301,8 +317,10 @@ def validate_light_client_update(store: LightClientStore, assert sum(sync_aggregate.sync_committee_bits) >= MIN_SYNC_COMMITTEE_PARTICIPANTS # Verify update does not skip a sync committee period - assert current_slot >= update.signature_slot > update.attested_header.slot >= update.finalized_header.slot - store_period = compute_sync_committee_period_at_slot(store.finalized_header.slot) + update_attested_slot = get_lc_beacon_slot(update.attested_header) + update_finalized_slot = get_lc_beacon_slot(update.finalized_header) + assert current_slot >= update.signature_slot > update_attested_slot >= update_finalized_slot + store_period = compute_sync_committee_period_at_slot(get_lc_beacon_slot(store.finalized_header)) update_signature_period = compute_sync_committee_period_at_slot(update.signature_slot) if is_next_sync_committee_known(store): assert update_signature_period in (store_period, store_period + 1) @@ -310,12 +328,12 @@ def validate_light_client_update(store: LightClientStore, assert update_signature_period == store_period # Verify update is relevant - update_attested_period = compute_sync_committee_period_at_slot(update.attested_header.slot) + update_attested_period = compute_sync_committee_period_at_slot(update_attested_slot) update_has_next_sync_committee = not is_next_sync_committee_known(store) and ( is_sync_committee_update(update) and update_attested_period == store_period ) assert ( - update.attested_header.slot > store.finalized_header.slot + update_attested_slot > get_lc_beacon_slot(store.finalized_header) or update_has_next_sync_committee ) @@ -325,11 +343,11 @@ def validate_light_client_update(store: LightClientStore, if not is_finality_update(update): assert update.finalized_header == BeaconBlockHeader() else: - if update.finalized_header.slot == GENESIS_SLOT: + if update_finalized_slot == GENESIS_SLOT: assert update.finalized_header == BeaconBlockHeader() finalized_root = Bytes32() else: - finalized_root = hash_tree_root(update.finalized_header) + finalized_root = get_lc_beacon_root(update.finalized_header) assert is_valid_merkle_branch( leaf=finalized_root, branch=update.finality_branch, @@ -372,8 +390,8 @@ def validate_light_client_update(store: LightClientStore, ```python def apply_light_client_update(store: LightClientStore, update: LightClientUpdate) -> None: - store_period = compute_sync_committee_period_at_slot(store.finalized_header.slot) - update_finalized_period = compute_sync_committee_period_at_slot(update.finalized_header.slot) + store_period = compute_sync_committee_period_at_slot(get_lc_beacon_slot(store.finalized_header)) + update_finalized_period = compute_sync_committee_period_at_slot(get_lc_beacon_slot(update.finalized_header)) if not is_next_sync_committee_known(store): assert update_finalized_period == store_period store.next_sync_committee = update.next_sync_committee @@ -382,9 +400,9 @@ def apply_light_client_update(store: LightClientStore, update: LightClientUpdate store.next_sync_committee = update.next_sync_committee store.previous_max_active_participants = store.current_max_active_participants store.current_max_active_participants = 0 - if update.finalized_header.slot > store.finalized_header.slot: + if get_lc_beacon_slot(update.finalized_header) > get_lc_beacon_slot(store.finalized_header): store.finalized_header = update.finalized_header - if store.finalized_header.slot > store.optimistic_header.slot: + if get_lc_beacon_slot(store.finalized_header) > get_lc_beacon_slot(store.optimistic_header): store.optimistic_header = store.finalized_header ``` @@ -393,14 +411,14 @@ def apply_light_client_update(store: LightClientStore, update: LightClientUpdate ```python def process_light_client_store_force_update(store: LightClientStore, current_slot: Slot) -> None: if ( - current_slot > store.finalized_header.slot + UPDATE_TIMEOUT + current_slot > get_lc_beacon_slot(store.finalized_header) + UPDATE_TIMEOUT and store.best_valid_update is not None ): # Forced best update when the update timeout has elapsed. - # Because the apply logic waits for `finalized_header.slot` to indicate sync committee finality, + # Because the apply logic waits for `get_lc_beacon_slot(finalized_header)` to indicate sync committee finality, # the `attested_header` may be treated as `finalized_header` in extended periods of non-finality # to guarantee progression into later sync committee periods according to `is_better_update`. - if store.best_valid_update.finalized_header.slot <= store.finalized_header.slot: + if get_lc_beacon_slot(store.best_valid_update.finalized_header) <= get_lc_beacon_slot(store.finalized_header): store.best_valid_update.finalized_header = store.best_valid_update.attested_header apply_light_client_update(store, store.best_valid_update) store.best_valid_update = None @@ -433,7 +451,7 @@ def process_light_client_update(store: LightClientStore, # Update the optimistic header if ( sum(sync_committee_bits) > get_safety_threshold(store) - and update.attested_header.slot > store.optimistic_header.slot + and get_lc_beacon_slot(update.attested_header) > get_lc_beacon_slot(store.optimistic_header) ): store.optimistic_header = update.attested_header @@ -441,14 +459,14 @@ def process_light_client_update(store: LightClientStore, update_has_finalized_next_sync_committee = ( not is_next_sync_committee_known(store) and is_sync_committee_update(update) and is_finality_update(update) and ( - compute_sync_committee_period_at_slot(update.finalized_header.slot) - == compute_sync_committee_period_at_slot(update.attested_header.slot) + compute_sync_committee_period_at_slot(get_lc_beacon_slot(update.finalized_header)) + == compute_sync_committee_period_at_slot(get_lc_beacon_slot(update.attested_header)) ) ) if ( sum(sync_committee_bits) * 3 >= len(sync_committee_bits) * 2 and ( - update.finalized_header.slot > store.finalized_header.slot + get_lc_beacon_slot(update.finalized_header) > get_lc_beacon_slot(store.finalized_header) or update_has_finalized_next_sync_committee ) ): diff --git a/tests/core/pyspec/eth2spec/test/altair/light_client/test_sync.py b/tests/core/pyspec/eth2spec/test/altair/light_client/test_sync.py index 1364c4bf1..cc6a070a3 100644 --- a/tests/core/pyspec/eth2spec/test/altair/light_client/test_sync.py +++ b/tests/core/pyspec/eth2spec/test/altair/light_client/test_sync.py @@ -56,18 +56,18 @@ def get_update_file_name(spec, update): suffix2 = "f" else: suffix2 = "x" - return f"update_{encode_hex(update.attested_header.hash_tree_root())}_{suffix1}{suffix2}" + return f"update_{encode_hex(spec.get_lc_beacon_root(update.attested_header))}_{suffix1}{suffix2}" -def get_checks(store): +def get_checks(spec, store): return { "finalized_header": { - 'slot': int(store.finalized_header.slot), - 'beacon_root': encode_hex(store.finalized_header.hash_tree_root()), + 'slot': int(spec.get_lc_beacon_slot(store.finalized_header)), + 'beacon_root': encode_hex(spec.get_lc_beacon_root(store.finalized_header)), }, "optimistic_header": { - 'slot': int(store.optimistic_header.slot), - 'beacon_root': encode_hex(store.optimistic_header.hash_tree_root()), + 'slot': int(spec.get_lc_beacon_slot(store.optimistic_header)), + 'beacon_root': encode_hex(spec.get_lc_beacon_root(store.optimistic_header)), }, } @@ -80,7 +80,7 @@ def emit_force_update(test, spec, state): test.steps.append({ "force_update": { "current_slot": int(current_slot), - "checks": get_checks(test.store), + "checks": get_checks(spec, test.store), } }) @@ -99,7 +99,7 @@ def emit_update(test, spec, state, block, attested_state, attested_block, finali "process_update": { "update": get_update_file_name(spec, update), "current_slot": int(current_slot), - "checks": get_checks(test.store), + "checks": get_checks(spec, test.store), } }) return update @@ -141,10 +141,10 @@ def test_light_client_sync(spec, state): sync_aggregate, _ = get_sync_aggregate(spec, state) block = state_transition_with_full_block(spec, state, True, True, sync_aggregate=sync_aggregate) yield from emit_update(test, spec, state, block, attested_state, attested_block, finalized_block) - assert test.store.finalized_header.slot == finalized_state.slot + assert spec.get_lc_beacon_slot(test.store.finalized_header) == finalized_state.slot assert test.store.next_sync_committee == finalized_state.next_sync_committee assert test.store.best_valid_update is None - assert test.store.optimistic_header.slot == attested_state.slot + assert spec.get_lc_beacon_slot(test.store.optimistic_header) == attested_state.slot # Advance to next sync committee period # ``` @@ -167,10 +167,10 @@ def test_light_client_sync(spec, state): sync_aggregate, _ = get_sync_aggregate(spec, state) block = state_transition_with_full_block(spec, state, True, True, sync_aggregate=sync_aggregate) yield from emit_update(test, spec, state, block, attested_state, attested_block, finalized_block) - assert test.store.finalized_header.slot == finalized_state.slot + assert spec.get_lc_beacon_slot(test.store.finalized_header) == finalized_state.slot assert test.store.next_sync_committee == finalized_state.next_sync_committee assert test.store.best_valid_update is None - assert test.store.optimistic_header.slot == attested_state.slot + assert spec.get_lc_beacon_slot(test.store.optimistic_header) == attested_state.slot # Edge case: Signature in next period # ``` @@ -193,10 +193,10 @@ def test_light_client_sync(spec, state): sync_aggregate, _ = get_sync_aggregate(spec, state) block = state_transition_with_full_block(spec, state, True, True, sync_aggregate=sync_aggregate) yield from emit_update(test, spec, state, block, attested_state, attested_block, finalized_block) - assert test.store.finalized_header.slot == finalized_state.slot + assert spec.get_lc_beacon_slot(test.store.finalized_header) == finalized_state.slot assert test.store.next_sync_committee == finalized_state.next_sync_committee assert test.store.best_valid_update is None - assert test.store.optimistic_header.slot == attested_state.slot + assert spec.get_lc_beacon_slot(test.store.optimistic_header) == attested_state.slot # Edge case: Finalized header not included # ``` @@ -214,10 +214,10 @@ def test_light_client_sync(spec, state): sync_aggregate, _ = get_sync_aggregate(spec, state) block = state_transition_with_full_block(spec, state, True, True, sync_aggregate=sync_aggregate) update = yield from emit_update(test, spec, state, block, attested_state, attested_block, finalized_block=None) - assert test.store.finalized_header.slot == finalized_state.slot + assert spec.get_lc_beacon_slot(test.store.finalized_header) == finalized_state.slot assert test.store.next_sync_committee == finalized_state.next_sync_committee assert test.store.best_valid_update == update - assert test.store.optimistic_header.slot == attested_state.slot + assert spec.get_lc_beacon_slot(test.store.optimistic_header) == attested_state.slot # Non-finalized case: Attested `next_sync_committee` is not finalized # ``` @@ -236,10 +236,10 @@ def test_light_client_sync(spec, state): sync_aggregate, _ = get_sync_aggregate(spec, state) block = state_transition_with_full_block(spec, state, True, True, sync_aggregate=sync_aggregate) update = yield from emit_update(test, spec, state, block, attested_state, attested_block, finalized_block) - assert test.store.finalized_header.slot == finalized_state.slot + assert spec.get_lc_beacon_slot(test.store.finalized_header) == finalized_state.slot assert test.store.next_sync_committee == finalized_state.next_sync_committee assert test.store.best_valid_update == update - assert test.store.optimistic_header.slot == attested_state.slot + assert spec.get_lc_beacon_slot(test.store.optimistic_header) == attested_state.slot # Force-update using timeout # ``` @@ -256,10 +256,10 @@ def test_light_client_sync(spec, state): attested_state = state.copy() next_slots(spec, state, spec.UPDATE_TIMEOUT - 1) yield from emit_force_update(test, spec, state) - assert test.store.finalized_header.slot == store_state.slot + assert spec.get_lc_beacon_slot(test.store.finalized_header) == store_state.slot assert test.store.next_sync_committee == store_state.next_sync_committee assert test.store.best_valid_update is None - assert test.store.optimistic_header.slot == store_state.slot + assert spec.get_lc_beacon_slot(test.store.optimistic_header) == store_state.slot # Edge case: Finalized header not included, after force-update # ``` @@ -275,10 +275,10 @@ def test_light_client_sync(spec, state): sync_aggregate, _ = get_sync_aggregate(spec, state) block = state_transition_with_full_block(spec, state, True, True, sync_aggregate=sync_aggregate) update = yield from emit_update(test, spec, state, block, attested_state, attested_block, finalized_block=None) - assert test.store.finalized_header.slot == store_state.slot + assert spec.get_lc_beacon_slot(test.store.finalized_header) == store_state.slot assert test.store.next_sync_committee == store_state.next_sync_committee assert test.store.best_valid_update == update - assert test.store.optimistic_header.slot == attested_state.slot + assert spec.get_lc_beacon_slot(test.store.optimistic_header) == attested_state.slot # Edge case: Finalized header older than store # ``` @@ -296,15 +296,15 @@ def test_light_client_sync(spec, state): sync_aggregate, _ = get_sync_aggregate(spec, state) block = state_transition_with_full_block(spec, state, True, True, sync_aggregate=sync_aggregate) update = yield from emit_update(test, spec, state, block, attested_state, attested_block, finalized_block) - assert test.store.finalized_header.slot == store_state.slot + assert spec.get_lc_beacon_slot(test.store.finalized_header) == store_state.slot assert test.store.next_sync_committee == store_state.next_sync_committee assert test.store.best_valid_update == update - assert test.store.optimistic_header.slot == attested_state.slot + assert spec.get_lc_beacon_slot(test.store.optimistic_header) == attested_state.slot yield from emit_force_update(test, spec, state) - assert test.store.finalized_header.slot == attested_state.slot + assert spec.get_lc_beacon_slot(test.store.finalized_header) == attested_state.slot assert test.store.next_sync_committee == attested_state.next_sync_committee assert test.store.best_valid_update is None - assert test.store.optimistic_header.slot == attested_state.slot + assert spec.get_lc_beacon_slot(test.store.optimistic_header) == attested_state.slot # Advance to next sync committee period # ``` @@ -327,10 +327,10 @@ def test_light_client_sync(spec, state): sync_aggregate, _ = get_sync_aggregate(spec, state) block = state_transition_with_full_block(spec, state, True, True, sync_aggregate=sync_aggregate) yield from emit_update(test, spec, state, block, attested_state, attested_block, finalized_block) - assert test.store.finalized_header.slot == finalized_state.slot + assert spec.get_lc_beacon_slot(test.store.finalized_header) == finalized_state.slot assert test.store.next_sync_committee == finalized_state.next_sync_committee assert test.store.best_valid_update is None - assert test.store.optimistic_header.slot == attested_state.slot + assert spec.get_lc_beacon_slot(test.store.optimistic_header) == attested_state.slot # Finish test yield from finish_test(test) @@ -357,10 +357,10 @@ def test_supply_sync_committee_from_past_update(spec, state): # Apply `LightClientUpdate` from the past, populating `store.next_sync_committee` yield from emit_update(test, spec, past_state, block, attested_state, attested_block, finalized_block) - assert test.store.finalized_header.slot == state.slot + assert spec.get_lc_beacon_slot(test.store.finalized_header) == state.slot assert test.store.next_sync_committee == finalized_state.next_sync_committee assert test.store.best_valid_update is None - assert test.store.optimistic_header.slot == state.slot + assert spec.get_lc_beacon_slot(test.store.optimistic_header) == state.slot # Finish test yield from finish_test(test) @@ -383,10 +383,10 @@ def test_advance_finality_without_sync_committee(spec, state): sync_aggregate, _ = get_sync_aggregate(spec, state) block = state_transition_with_full_block(spec, state, True, True, sync_aggregate=sync_aggregate) yield from emit_update(test, spec, state, block, attested_state, attested_block, finalized_block) - assert test.store.finalized_header.slot == finalized_state.slot + assert spec.get_lc_beacon_slot(test.store.finalized_header) == finalized_state.slot assert test.store.next_sync_committee == finalized_state.next_sync_committee assert test.store.best_valid_update is None - assert test.store.optimistic_header.slot == attested_state.slot + assert spec.get_lc_beacon_slot(test.store.optimistic_header) == attested_state.slot # Advance finality into next sync committee period, but omit `next_sync_committee` transition_to(spec, state, compute_start_slot_at_next_sync_committee_period(spec, state)) @@ -402,10 +402,10 @@ def test_advance_finality_without_sync_committee(spec, state): sync_aggregate, _ = get_sync_aggregate(spec, state) block = state_transition_with_full_block(spec, state, True, True, sync_aggregate=sync_aggregate) yield from emit_update(test, spec, state, block, attested_state, attested_block, finalized_block, with_next=False) - assert test.store.finalized_header.slot == finalized_state.slot + assert spec.get_lc_beacon_slot(test.store.finalized_header) == finalized_state.slot assert not spec.is_next_sync_committee_known(test.store) assert test.store.best_valid_update is None - assert test.store.optimistic_header.slot == attested_state.slot + assert spec.get_lc_beacon_slot(test.store.optimistic_header) == attested_state.slot # Advance finality once more, with `next_sync_committee` still unknown past_state = finalized_state @@ -419,24 +419,24 @@ def test_advance_finality_without_sync_committee(spec, state): # Apply `LightClientUpdate` without `finalized_header` nor `next_sync_committee` update = yield from emit_update(test, spec, state, block, attested_state, attested_block, None, with_next=False) - assert test.store.finalized_header.slot == past_state.slot + assert spec.get_lc_beacon_slot(test.store.finalized_header) == past_state.slot assert not spec.is_next_sync_committee_known(test.store) assert test.store.best_valid_update == update - assert test.store.optimistic_header.slot == attested_state.slot + assert spec.get_lc_beacon_slot(test.store.optimistic_header) == attested_state.slot # Apply `LightClientUpdate` with `finalized_header` but no `next_sync_committee` yield from emit_update(test, spec, state, block, attested_state, attested_block, finalized_block, with_next=False) - assert test.store.finalized_header.slot == finalized_state.slot + assert spec.get_lc_beacon_slot(test.store.finalized_header) == finalized_state.slot assert not spec.is_next_sync_committee_known(test.store) assert test.store.best_valid_update is None - assert test.store.optimistic_header.slot == attested_state.slot + assert spec.get_lc_beacon_slot(test.store.optimistic_header) == attested_state.slot # Apply full `LightClientUpdate`, supplying `next_sync_committee` yield from emit_update(test, spec, state, block, attested_state, attested_block, finalized_block) - assert test.store.finalized_header.slot == finalized_state.slot + assert spec.get_lc_beacon_slot(test.store.finalized_header) == finalized_state.slot assert test.store.next_sync_committee == finalized_state.next_sync_committee assert test.store.best_valid_update is None - assert test.store.optimistic_header.slot == attested_state.slot + assert spec.get_lc_beacon_slot(test.store.optimistic_header) == attested_state.slot # Finish test yield from finish_test(test) diff --git a/tests/core/pyspec/eth2spec/test/altair/light_client/test_update_ranking.py b/tests/core/pyspec/eth2spec/test/altair/light_client/test_update_ranking.py index 23ad79584..96c372435 100644 --- a/tests/core/pyspec/eth2spec/test/altair/light_client/test_update_ranking.py +++ b/tests/core/pyspec/eth2spec/test/altair/light_client/test_update_ranking.py @@ -59,7 +59,7 @@ def test_update_ranking(spec, state): # - `sig_finalized` / `sig_attested` --> Only signature in next sync committee period # - `att_finalized` / `att_attested` --> Attested header also in next sync committee period # - `fin_finalized` / `fin_attested` --> Finalized header also in next sync committee period - # - `lat_finalized` / `lat_attested` --> Like `fin`, but at a later `attested_header.slot` + # - `lat_finalized` / `lat_attested` --> Like `fin`, but at a later `get_lc_beacon_slot(attested_header)` next_slots(spec, state, spec.compute_start_slot_at_epoch(spec.EPOCHS_PER_SYNC_COMMITTEE_PERIOD - 3) - 1) sig_finalized_block = state_transition_with_full_block(spec, state, True, True) _, _, state = next_slots_with_attestations(spec, state, spec.SLOTS_PER_EPOCH - 1, True, True) diff --git a/tests/core/pyspec/eth2spec/test/altair/unittests/light_client/test_sync_protocol.py b/tests/core/pyspec/eth2spec/test/altair/unittests/light_client/test_sync_protocol.py index bf09cc30e..860091b32 100644 --- a/tests/core/pyspec/eth2spec/test/altair/unittests/light_client/test_sync_protocol.py +++ b/tests/core/pyspec/eth2spec/test/altair/unittests/light_client/test_sync_protocol.py @@ -68,7 +68,7 @@ def test_process_light_client_update_at_period_boundary(spec, state): # Forward to slot before next sync committee period so that next block is final one in period next_slots(spec, state, spec.UPDATE_TIMEOUT - 2) - store_period = spec.compute_sync_committee_period_at_slot(store.optimistic_header.slot) + store_period = spec.compute_sync_committee_period_at_slot(spec.get_lc_beacon_slot(store.optimistic_header)) update_period = spec.compute_sync_committee_period_at_slot(state.slot) assert store_period == update_period @@ -112,7 +112,7 @@ def test_process_light_client_update_timeout(spec, state): # Forward to next sync committee period next_slots(spec, state, spec.UPDATE_TIMEOUT) - store_period = spec.compute_sync_committee_period_at_slot(store.optimistic_header.slot) + store_period = spec.compute_sync_committee_period_at_slot(spec.get_lc_beacon_slot(store.optimistic_header)) update_period = spec.compute_sync_committee_period_at_slot(state.slot) assert store_period + 1 == update_period @@ -164,7 +164,7 @@ def test_process_light_client_update_finality_updated(spec, state): # Ensure that finality checkpoint has changed assert state.finalized_checkpoint.epoch == 3 # Ensure that it's same period - store_period = spec.compute_sync_committee_period_at_slot(store.optimistic_header.slot) + store_period = spec.compute_sync_committee_period_at_slot(spec.get_lc_beacon_slot(store.optimistic_header)) update_period = spec.compute_sync_committee_period_at_slot(state.slot) assert store_period == update_period diff --git a/tests/formats/light_client/sync.md b/tests/formats/light_client/sync.md index 4d7162c3b..3beeec0dd 100644 --- a/tests/formats/light_client/sync.md +++ b/tests/formats/light_client/sync.md @@ -25,12 +25,12 @@ Each step includes checks to verify the expected impact on the `store` object. ```yaml finalized_header: { - slot: int, -- Integer value from store.finalized_header.slot - beacon_root: string, -- Encoded 32-byte value from store.finalized_header.hash_tree_root() + slot: int, -- Integer value from get_lc_beacon_slot(store.finalized_header) + beacon_root: string, -- Encoded 32-byte value from get_lc_beacon_root(store.finalized_header) } optimistic_header: { - slot: int, -- Integer value from store.optimistic_header.slot - beacon_root: string, -- Encoded 32-byte value from store.optimistic_header.hash_tree_root() + slot: int, -- Integer value from get_lc_beacon_slot(store.optimistic_header) + beacon_root: string, -- Encoded 32-byte value from get_lc_beacon_root(store.optimistic_header) } ``` From 14fd9370467c8bcbd3ed6131ca46739577dd1a7a Mon Sep 17 00:00:00 2001 From: Etan Kissling Date: Tue, 6 Dec 2022 23:21:06 +0100 Subject: [PATCH 007/158] Fix --- specs/altair/light-client/full-node.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/specs/altair/light-client/full-node.md b/specs/altair/light-client/full-node.md index 0afbe54fb..139b3c941 100644 --- a/specs/altair/light-client/full-node.md +++ b/specs/altair/light-client/full-node.md @@ -121,7 +121,7 @@ def create_light_client_update(state: BeaconState, state_root=finalized_block.message.state_root, body_root=hash_tree_root(finalized_block.message.body), ) - assert get_lc_beacon_root(update.finalized_header) == attested_state.finalized_checkpoint.root + assert get_lc_beacon_root(finalized_header) == attested_state.finalized_checkpoint.root else: assert attested_state.finalized_checkpoint.root == Bytes32() finalized_header = BeaconBlockHeader() From 0649e0662c5baf1aa4d954c5375d1880bf7af369 Mon Sep 17 00:00:00 2001 From: Etan Kissling Date: Wed, 7 Dec 2022 21:10:09 +0100 Subject: [PATCH 008/158] Allow selecting phase to emit, and fix combi with overrides --- .../altair/unittests/test_config_override.py | 24 ++++++++++++--- tests/core/pyspec/eth2spec/test/context.py | 30 ++++++++++++------- 2 files changed, 40 insertions(+), 14 deletions(-) diff --git a/tests/core/pyspec/eth2spec/test/altair/unittests/test_config_override.py b/tests/core/pyspec/eth2spec/test/altair/unittests/test_config_override.py index 6748fac76..ed6f63868 100644 --- a/tests/core/pyspec/eth2spec/test/altair/unittests/test_config_override.py +++ b/tests/core/pyspec/eth2spec/test/altair/unittests/test_config_override.py @@ -3,6 +3,7 @@ from eth2spec.test.context import ( spec_state_test_with_matching_config, spec_test, with_all_phases, + with_config_overrides, with_matching_spec_config, with_phases, with_state, @@ -32,7 +33,7 @@ def test_config_override(spec, state): @with_all_phases @spec_state_test_with_matching_config -def test_override_config_fork_epoch(spec, state): +def test_config_override_matching_fork_epochs(spec, state): if state.fork.current_version == spec.config.GENESIS_FORK_VERSION: return @@ -63,8 +64,23 @@ def test_override_config_fork_epoch(spec, state): @with_phases(phases=[ALTAIR], other_phases=[BELLATRIX]) @spec_test +@with_config_overrides({ + 'ALTAIR_FORK_VERSION': '0x11111111', + 'BELLATRIX_FORK_EPOCH': 4, +}, emit=False) @with_state -@with_matching_spec_config -def test_capella_store_with_legacy_data(spec, phases, state): +@with_matching_spec_config(emitted_fork=BELLATRIX) +def test_config_override_across_phases(spec, phases, state): assert state.fork.current_version == spec.config.ALTAIR_FORK_VERSION - assert phases[BELLATRIX].config.ALTAIR_FORK_EPOCH == spec.config.ALTAIR_FORK_EPOCH + + assert spec.config.ALTAIR_FORK_VERSION == spec.Version('0x11111111') + assert spec.config.ALTAIR_FORK_EPOCH == 0 + assert not hasattr(spec.config, 'BELLATRIX_FORK_EPOCH') + + assert phases[ALTAIR].config.ALTAIR_FORK_VERSION == spec.Version('0x11111111') + assert phases[ALTAIR].config.ALTAIR_FORK_EPOCH == 0 + assert not hasattr(phases[ALTAIR].config, 'BELLATRIX_FORK_EPOCH') + + assert phases[ALTAIR].config.ALTAIR_FORK_VERSION == spec.Version('0x11111111') + assert phases[BELLATRIX].config.ALTAIR_FORK_EPOCH == 0 + assert phases[BELLATRIX].config.BELLATRIX_FORK_EPOCH == 4 diff --git a/tests/core/pyspec/eth2spec/test/context.py b/tests/core/pyspec/eth2spec/test/context.py index be8f04ae1..d80d841cc 100644 --- a/tests/core/pyspec/eth2spec/test/context.py +++ b/tests/core/pyspec/eth2spec/test/context.py @@ -1,4 +1,5 @@ import pytest +from copy import deepcopy from dataclasses import dataclass import importlib @@ -318,16 +319,18 @@ def config_fork_epoch_overrides(spec, state): return overrides -def with_matching_spec_config(fn): - def decorator(*args, spec: Spec, **kw): - conf = config_fork_epoch_overrides(spec, kw['state']) - overrides = with_config_overrides(conf) - return overrides(fn)(*args, spec=spec, **kw) +def with_matching_spec_config(emitted_fork=None): + def decorator(fn): + def wrapper(*args, spec: Spec, **kw): + overrides = config_fork_epoch_overrides(spec, kw['state']) + deco = with_config_overrides(overrides, emitted_fork) + return deco(fn)(*args, spec=spec, **kw) + return wrapper return decorator def spec_state_test_with_matching_config(fn): - return spec_test(with_state(with_matching_spec_config(single_phase(fn)))) + return spec_test(with_state(with_matching_spec_config()(single_phase(fn)))) def expect_assertion_error(fn): @@ -568,13 +571,17 @@ def _get_copy_of_spec(spec): module_spec = importlib.util.find_spec(module_path) module = importlib.util.module_from_spec(module_spec) module_spec.loader.exec_module(module) + + # Preserve existing config overrides + module.config = deepcopy(spec.config) + return module def spec_with_config_overrides(spec, config_overrides): # apply our overrides to a copy of it, and apply it to the spec config = spec.config._asdict() - config.update(config_overrides) + config.update((k, config_overrides[k]) for k in config.keys() & config_overrides.keys()) config_types = spec.Configuration.__annotations__ modified_config = {k: config_types[k](v) for k, v in config.items()} @@ -587,7 +594,7 @@ def spec_with_config_overrides(spec, config_overrides): return spec, output_config -def with_config_overrides(config_overrides): +def with_config_overrides(config_overrides, emitted_fork=None, emit=True): """ WARNING: the spec_test decorator must wrap this, to ensure the decorated test actually runs. This decorator forces the test to yield, and pytest doesn't run generator tests, and instead silently passes it. @@ -598,13 +605,16 @@ def with_config_overrides(config_overrides): def decorator(fn): def wrapper(*args, spec: Spec, **kw): spec, output_config = spec_with_config_overrides(_get_copy_of_spec(spec), config_overrides) - yield 'config', 'cfg', output_config + if emit and emitted_fork is None: + yield 'config', 'cfg', output_config if 'phases' in kw: for fork in kw['phases']: if is_post_fork(fork, spec.fork): - kw['phases'][fork], _ = \ + kw['phases'][fork], output_config = \ spec_with_config_overrides(_get_copy_of_spec(kw['phases'][fork]), config_overrides) + if emit and emitted_fork == fork: + yield 'config', 'cfg', output_config # Run the function out = fn(*args, spec=spec, **kw) From 0c3853e95952b61ce64f05a651f0e32b858f15ad Mon Sep 17 00:00:00 2001 From: Etan Kissling Date: Sun, 11 Dec 2022 23:41:08 +0100 Subject: [PATCH 009/158] Avoid modifying caller `phases` (`kw` is shallow copy) --- tests/core/pyspec/eth2spec/test/context.py | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/tests/core/pyspec/eth2spec/test/context.py b/tests/core/pyspec/eth2spec/test/context.py index d80d841cc..b1f608d7b 100644 --- a/tests/core/pyspec/eth2spec/test/context.py +++ b/tests/core/pyspec/eth2spec/test/context.py @@ -604,20 +604,26 @@ def with_config_overrides(config_overrides, emitted_fork=None, emit=True): """ def decorator(fn): def wrapper(*args, spec: Spec, **kw): + # Apply config overrides to spec spec, output_config = spec_with_config_overrides(_get_copy_of_spec(spec), config_overrides) - if emit and emitted_fork is None: - yield 'config', 'cfg', output_config + # Apply config overrides to additional phases, if present if 'phases' in kw: + phases = {} for fork in kw['phases']: - if is_post_fork(fork, spec.fork): - kw['phases'][fork], output_config = \ - spec_with_config_overrides(_get_copy_of_spec(kw['phases'][fork]), config_overrides) - if emit and emitted_fork == fork: - yield 'config', 'cfg', output_config + phases[fork], output = \ + spec_with_config_overrides(_get_copy_of_spec(kw['phases'][fork]), config_overrides) + if emitted_fork == fork: + output_config = output + kw['phases'] = phases # Run the function out = fn(*args, spec=spec, **kw) + + # Emit requested spec (with overrides) + if emit: + yield 'config', 'cfg', output_config + # If it's not returning None like a normal test function, # it's generating things, and we need to complete it before setting back the config. if out is not None: From 2e97af262734c4ae5a619a6991b81100d9ff404e Mon Sep 17 00:00:00 2001 From: Etan Kissling Date: Mon, 12 Dec 2022 00:43:07 +0100 Subject: [PATCH 010/158] Add `ExecutionPayloadHeader` to LC data While the light client sync protocol currently provides access to the latest `BeaconBlockHeader`, obtaining the matching execution data needs workarounds such as downloading the full block. Having ready access to the EL state root simplifies use cases that need a way to cross-check `eth_getProof` responses against LC data. Access to `block_hash` unlocks scenarios where a CL light client drives an EL without `engine_newPayload`. As of Altair, only the CL beacon block root is available, but the EL block hash is needed for engine API. Other fields in the `ExecutionPayloadHeader` such as `logs_bloom` may allow light client applications to monitor blocks for local interest, e.g. for transfers affecting a certain wallet. This enables to download only the few relevant blocks instead of every single one. A new `LightClientStore` is proposed into the Capella spec that may be used to sync LC data that includes execution data. Existing pre-Capella LC data will remain as is, but can be locally upgraded before feeding it into the new `LightClientStore` so that light clients do not need to run a potentially expensive fork transition at a specific time. This enables the `LightClientStore` to be upgraded at a use case dependent timing at any time before Capella hits. Smart contract and embedded deployments benefit from reduced code size and do not need synchronization with the beacon chain clock to perform the Capella fork. --- Makefile | 2 +- README.md | 2 +- setup.py | 20 + specs/capella/light-client/fork.md | 93 +++++ specs/capella/light-client/full-node.md | 72 ++++ specs/capella/light-client/p2p-interface.md | 99 +++++ specs/capella/light-client/sync-protocol.md | 289 +++++++++++++ .../test/altair/light_client/test_sync.py | 390 +++++++++++++++--- .../test/capella/light_client/__init__.py | 0 .../light_client/test_single_merkle_proof.py | 31 ++ tests/formats/light_client/sync.md | 25 +- tests/generators/light_client/main.py | 8 +- 12 files changed, 973 insertions(+), 58 deletions(-) create mode 100644 specs/capella/light-client/fork.md create mode 100644 specs/capella/light-client/full-node.md create mode 100644 specs/capella/light-client/p2p-interface.md create mode 100644 specs/capella/light-client/sync-protocol.md create mode 100644 tests/core/pyspec/eth2spec/test/capella/light_client/__init__.py create mode 100644 tests/core/pyspec/eth2spec/test/capella/light_client/test_single_merkle_proof.py diff --git a/Makefile b/Makefile index 73450562b..728656cb6 100644 --- a/Makefile +++ b/Makefile @@ -26,7 +26,7 @@ GENERATOR_VENVS = $(patsubst $(GENERATOR_DIR)/%, $(GENERATOR_DIR)/%venv, $(GENER MARKDOWN_FILES = $(wildcard $(SPEC_DIR)/phase0/*.md) \ $(wildcard $(SPEC_DIR)/altair/*.md) $(wildcard $(SPEC_DIR)/altair/**/*.md) \ $(wildcard $(SPEC_DIR)/bellatrix/*.md) \ - $(wildcard $(SPEC_DIR)/capella/*.md) \ + $(wildcard $(SPEC_DIR)/capella/*.md) $(wildcard $(SPEC_DIR)/capella/**/*.md) \ $(wildcard $(SPEC_DIR)/custody/*.md) \ $(wildcard $(SPEC_DIR)/das/*.md) \ $(wildcard $(SPEC_DIR)/sharding/*.md) \ diff --git a/README.md b/README.md index 07b78c0d5..766b6eda7 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,7 @@ Features are researched and developed in parallel, and then consolidated into se ### In-development Specifications | Code Name or Topic | Specs | Notes | | - | - | - | -| Capella (tentative) |
  • Core
    • [Beacon chain changes](specs/capella/beacon-chain.md)
    • [Capella fork](specs/capella/fork.md)
  • Additions
    • [Validator additions](specs/capella/validator.md)
    • [P2P networking](specs/capella/p2p-interface.md)
| +| Capella (tentative) |
  • Core
    • [Beacon chain changes](specs/capella/beacon-chain.md)
    • [Capella fork](specs/capella/fork.md)
  • Additions
    • [Light client sync protocol changes](specs/capella/sync-protocol.md) ([fork](specs/capella/light-client/fork.md), [full node](specs/capella/light-client/full-node.md), [networking](specs/altair/light-client/p2p-interface.md))
    • [Validator additions](specs/capella/validator.md)
  • [Validator additions](specs/capella/validator.md)
  • [P2P networking](specs/capella/p2p-interface.md)
| | EIP4844 (tentative) |
  • Core
    • [Beacon Chain changes](specs/eip4844/beacon-chain.md)
    • [EIP-4844 fork](specs/eip4844/fork.md)
    • [Polynomial commitments](specs/eip4844/polynomial-commitments.md)
  • Additions
    • [Honest validator guide changes](specs/eip4844/validator.md)
    • [P2P networking](specs/eip4844/p2p-interface.md)
| | Sharding (outdated) |
  • Core
    • [Beacon Chain changes](specs/sharding/beacon-chain.md)
  • Additions
    • [P2P networking](specs/sharding/p2p-interface.md)
| | Custody Game (outdated) |
  • Core
    • [Beacon Chain changes](specs/custody_game/beacon-chain.md)
  • Additions
    • [Honest validator guide changes](specs/custody_game/validator.md)
| Dependent on sharding | diff --git a/setup.py b/setup.py index 432a41fe4..db0ad0cfc 100644 --- a/setup.py +++ b/setup.py @@ -616,6 +616,21 @@ from eth2spec.bellatrix import {preset_name} as bellatrix ''' + @classmethod + def sundry_functions(cls) -> str: + return super().sundry_functions() + '\n\n' + ''' +def compute_merkle_proof_for_block_body(body: BeaconBlockBody, + index: GeneralizedIndex) -> Sequence[Bytes32]: + return build_proof(body.get_backing(), index)''' + + + @classmethod + def hardcoded_ssz_dep_constants(cls) -> Dict[str, str]: + constants = { + 'EXECUTION_PAYLOAD_INDEX': 'GeneralizedIndex(25)', + } + return {**super().hardcoded_ssz_dep_constants(), **constants} + # # EIP4844SpecBuilder # @@ -718,6 +733,7 @@ def objects_to_spec(preset_name: str, if k in [ "ceillog2", "floorlog2", + "compute_merkle_proof_for_block_body", "compute_merkle_proof_for_state", ]: del spec_object.functions[k] @@ -1010,6 +1026,10 @@ class PySpecCommand(Command): """ if self.spec_fork in (CAPELLA, EIP4844): self.md_doc_paths += """ + specs/capella/light-client/fork.md + specs/capella/light-client/full-node.md + specs/capella/light-client/p2p-interface.md + specs/capella/light-client/sync-protocol.md specs/capella/beacon-chain.md specs/capella/fork.md specs/capella/fork-choice.md diff --git a/specs/capella/light-client/fork.md b/specs/capella/light-client/fork.md new file mode 100644 index 000000000..700f736c2 --- /dev/null +++ b/specs/capella/light-client/fork.md @@ -0,0 +1,93 @@ +# Capella Light Client -- Fork Logic + +## Table of contents + + + + + +- [Introduction](#introduction) + - [Upgrading light client data](#upgrading-light-client-data) + - [Upgrading the store](#upgrading-the-store) + + + + +## Introduction + +This document describes how to upgrade existing light client objects based on the [Altair specification](../../altair/light-client/sync-protocol.md) to Capella. This is necessary when processing pre-Capella data with a post-Capella `LightClientStore`. Note that the data being exchanged over the network protocols uses the original format. + +### Upgrading light client data + +A Capella `LightClientStore` can still process earlier light client data. In order to do so, that pre-Capella data needs to be locally upgraded to Capella before processing. + +```python +def upgrade_lc_header_to_capella(pre: BeaconBlockHeader) -> LightClientHeader: + return LightClientHeader( + beacon=pre, + execution=ExecutionPayloadHeader(), + ) +``` + +```python +def upgrade_lc_bootstrap_to_capella(pre: altair.LightClientBootstrap) -> LightClientBootstrap: + return LightClientBootstrap( + header=upgrade_lc_header_to_capella(pre.header), + current_sync_committee=pre.current_sync_committee, + current_sync_committee_branch=pre.current_sync_committee_branch, + ) +``` + +```python +def upgrade_lc_update_to_capella(pre: altair.LightClientUpdate) -> LightClientUpdate: + return LightClientUpdate( + attested_header=upgrade_lc_header_to_capella(pre.attested_header), + next_sync_committee=pre.next_sync_committee, + next_sync_committee_branch=pre.next_sync_committee_branch, + finalized_header=upgrade_lc_header_to_capella(pre.finalized_header), + finality_branch=pre.finality_branch, + sync_aggregate=pre.sync_aggregate, + signature_slot=pre.signature_slot, + ) +``` + +```python +def upgrade_lc_finality_update_to_capella(pre: altair.LightClientFinalityUpdate) -> LightClientFinalityUpdate: + return LightClientFinalityUpdate( + attested_header=upgrade_lc_header_to_capella(pre.attested_header), + finalized_header=upgrade_lc_header_to_capella(pre.finalized_header), + finality_branch=pre.finality_branch, + sync_aggregate=pre.sync_aggregate, + signature_slot=pre.signature_slot, + ) +``` + +```python +def upgrade_lc_optimistic_update_to_capella(pre: altair.LightClientOptimisticUpdate) -> LightClientOptimisticUpdate: + return LightClientOptimisticUpdate( + attested_header=upgrade_lc_header_to_capella(pre.attested_header), + sync_aggregate=pre.sync_aggregate, + signature_slot=pre.signature_slot, + ) +``` + +### Upgrading the store + +Existing `LightClientStore` objects based on Altair MUST be upgraded to Capella before Capella based light client data can be processed. The `LightClientStore` upgrade MAY be performed before `CAPELLA_FORK_EPOCH`. + +```python +def upgrade_lc_store_to_capella(pre: altair.LightClientStore) -> LightClientStore: + if pre.best_valid_update is None: + best_valid_update = None + else: + best_valid_update = upgrade_lc_update_to_capella(pre.best_valid_update) + return LightClientStore( + finalized_header=upgrade_lc_header_to_capella(pre.finalized_header), + current_sync_committee=pre.current_sync_committee, + next_sync_committee=pre.next_sync_committee, + best_valid_update=best_valid_update, + optimistic_header=upgrade_lc_header_to_capella(pre.optimistic_header), + previous_max_active_participants=pre.previous_max_active_participants, + current_max_active_participants=pre.current_max_active_participants, + ) +``` diff --git a/specs/capella/light-client/full-node.md b/specs/capella/light-client/full-node.md new file mode 100644 index 000000000..104853f8e --- /dev/null +++ b/specs/capella/light-client/full-node.md @@ -0,0 +1,72 @@ +# Capella Light Client -- Full Node + +**Notice**: This document is a work-in-progress for researchers and implementers. + +## Table of contents + + + + + +- [Introduction](#introduction) +- [Helper functions](#helper-functions) + - [`compute_merkle_proof_for_block_body`](#compute_merkle_proof_for_block_body) + - [Modified `block_to_light_client_header`](#modified-block_to_light_client_header) + + + + +## Introduction + +This upgrade adds information about the execution payload to light client data as part of the Capella upgrade. + +## Helper functions + +### `compute_merkle_proof_for_block_body` + +```python +def compute_merkle_proof_for_block_body(body: BeaconBlockBody, + index: GeneralizedIndex) -> Sequence[Bytes32]: + ... +``` + +### Modified `block_to_light_client_header` + +```python +def block_to_light_client_header(block: SignedBeaconBlock) -> LightClientHeader: + if compute_epoch_at_slot(block.message.slot) >= CAPELLA_FORK_EPOCH: + payload = block.message.body.execution_payload + execution_header = ExecutionPayloadHeader( + parent_hash=payload.parent_hash, + fee_recipient=payload.fee_recipient, + state_root=payload.state_root, + receipts_root=payload.receipts_root, + logs_bloom=payload.logs_bloom, + prev_randao=payload.prev_randao, + block_number=payload.block_number, + gas_limit=payload.gas_limit, + gas_used=payload.gas_used, + timestamp=payload.timestamp, + extra_data=payload.extra_data, + base_fee_per_gas=payload.base_fee_per_gas, + block_hash=payload.block_hash, + transactions_root=hash_tree_root(payload.transactions), + withdrawals_root=hash_tree_root(payload.withdrawals), + ) + execution_branch = compute_merkle_proof_for_block_body(block.message.body, EXECUTION_PAYLOAD_INDEX) + else: + execution_header = ExecutionPayloadHeader() + execution_branch = [Bytes32() for _ in range(floorlog2(EXECUTION_PAYLOAD_INDEX))] + + return LightClientHeader( + beacon=BeaconBlockHeader( + slot=block.message.slot, + proposer_index=block.message.proposer_index, + parent_root=block.message.parent_root, + state_root=block.message.state_root, + body_root=hash_tree_root(block.message.body), + ), + execution=execution_header, + execution_branch=execution_branch, + ) +``` diff --git a/specs/capella/light-client/p2p-interface.md b/specs/capella/light-client/p2p-interface.md new file mode 100644 index 000000000..b6c1ec080 --- /dev/null +++ b/specs/capella/light-client/p2p-interface.md @@ -0,0 +1,99 @@ +# Capella Light Client -- Networking + +**Notice**: This document is a work-in-progress for researchers and implementers. + +## Table of contents + + + + + +- [Networking](#networking) + - [The gossip domain: gossipsub](#the-gossip-domain-gossipsub) + - [Topics and messages](#topics-and-messages) + - [Global topics](#global-topics) + - [`light_client_finality_update`](#light_client_finality_update) + - [`light_client_optimistic_update`](#light_client_optimistic_update) + - [The Req/Resp domain](#the-reqresp-domain) + - [Messages](#messages) + - [GetLightClientBootstrap](#getlightclientbootstrap) + - [LightClientUpdatesByRange](#lightclientupdatesbyrange) + - [GetLightClientFinalityUpdate](#getlightclientfinalityupdate) + - [GetLightClientOptimisticUpdate](#getlightclientoptimisticupdate) + + + + +## Networking + +The [Altair light client networking specification](../../altair/light-client/p2p-interface.md) is extended to exchange [Capella light client data](./sync-protocol.md). + +### The gossip domain: gossipsub + +#### Topics and messages + +##### Global topics + +###### `light_client_finality_update` + +[0]: # (eth2spec: skip) + +| `fork_version` | Message SSZ type | +| ------------------------------------------------------ | ------------------------------------- | +| `GENESIS_FORK_VERSION` | n/a | +| `ALTAIR_FORK_VERSION` through `BELLATRIX_FORK_VERSION` | `altair.LightClientFinalityUpdate` | +| `CAPELLA_FORK_VERSION` and later | `capella.LightClientFinalityUpdate` | + +###### `light_client_optimistic_update` + +[0]: # (eth2spec: skip) + +| `fork_version` | Message SSZ type | +| ------------------------------------------------------ | ------------------------------------- | +| `GENESIS_FORK_VERSION` | n/a | +| `ALTAIR_FORK_VERSION` through `BELLATRIX_FORK_VERSION` | `altair.LightClientOptimisticUpdate` | +| `CAPELLA_FORK_VERSION` and later | `capella.LightClientOptimisticUpdate` | + +### The Req/Resp domain + +#### Messages + +##### GetLightClientBootstrap + +[0]: # (eth2spec: skip) + +| `fork_version` | Response SSZ type | +| ------------------------------------------------------ | ------------------------------------- | +| `GENESIS_FORK_VERSION` | n/a | +| `ALTAIR_FORK_VERSION` through `BELLATRIX_FORK_VERSION` | `altair.LightClientBootstrap` | +| `CAPELLA_FORK_VERSION` and later | `capella.LightClientBootstrap` | + +##### LightClientUpdatesByRange + +[0]: # (eth2spec: skip) + +| `fork_version` | Response chunk SSZ type | +| ------------------------------------------------------ | ------------------------------------- | +| `GENESIS_FORK_VERSION` | n/a | +| `ALTAIR_FORK_VERSION` through `BELLATRIX_FORK_VERSION` | `altair.LightClientUpdate` | +| `CAPELLA_FORK_VERSION` and later | `capella.LightClientUpdate` | + +##### GetLightClientFinalityUpdate + +[0]: # (eth2spec: skip) + +| `fork_version` | Response SSZ type | +| ------------------------------------------------------ | ------------------------------------- | +| `GENESIS_FORK_VERSION` | n/a | +| `ALTAIR_FORK_VERSION` through `BELLATRIX_FORK_VERSION` | `altair.LightClientFinalityUpdate` | +| `CAPELLA_FORK_VERSION` and later | `capella.LightClientFinalityUpdate` | + +##### GetLightClientOptimisticUpdate + +[0]: # (eth2spec: skip) + +| `fork_version` | Response SSZ type | +| ------------------------------------------------------ | ------------------------------------- | +| `GENESIS_FORK_VERSION` | n/a | +| `ALTAIR_FORK_VERSION` through `BELLATRIX_FORK_VERSION` | `altair.LightClientOptimisticUpdate` | +| `CAPELLA_FORK_VERSION` and later | `capella.LightClientOptimisticUpdate` | diff --git a/specs/capella/light-client/sync-protocol.md b/specs/capella/light-client/sync-protocol.md new file mode 100644 index 000000000..d8bfe3fd1 --- /dev/null +++ b/specs/capella/light-client/sync-protocol.md @@ -0,0 +1,289 @@ +# Capella Light Client -- Sync Protocol + +**Notice**: This document is a work-in-progress for researchers and implementers. + +## Table of contents + + + + + +- [Introduction](#introduction) +- [Constants](#constants) +- [Containers](#containers) + - [`LightClientHeader`](#lightclientheader) + - [Modified `LightClientBootstrap`](#modified-lightclientbootstrap) + - [Modified `LightClientUpdate`](#modified-lightclientupdate) + - [Modified `LightClientFinalityUpdate`](#modified-lightclientfinalityupdate) + - [Modified `LightClientOptimisticUpdate`](#modified-lightclientoptimisticupdate) + - [Modified `LightClientStore`](#modified-lightclientstore) +- [Helper functions](#helper-functions) + - [Modified `get_lc_beacon_slot`](#modified-get_lc_beacon_slot) + - [Modified `get_lc_beacon_root`](#modified-get_lc_beacon_root) + - [`get_lc_execution_root`](#get_lc_execution_root) + - [`is_valid_light_client_header`](#is_valid_light_client_header) +- [Light client initialization](#light-client-initialization) + - [Modified `initialize_light_client_store`](#modified-initialize_light_client_store) +- [Light client state updates](#light-client-state-updates) + - [Modified `validate_light_client_update`](#modified-validate_light_client_update) + + + + +## Introduction + +This upgrade adds information about the execution payload to light client data as part of the Capella upgrade. It extends the [Altair Light Client specifications](../../altair/light-client/sync-protocol.md). The [fork document](./fork.md) explains how to upgrade existing Altair based deployments to Capella. + +Additional documents describes the impact of the upgrade on certain roles: +- [Full node](./full-node.md) +- [Networking](./p2p-interface.md) + +## Constants + +| Name | Value | +| - | - | +| `EXECUTION_PAYLOAD_INDEX` | `get_generalized_index(BeaconBlockBody, 'execution_payload')` (= 25) | + +## Containers + +### `LightClientHeader` + +```python +class LightClientHeader(Container): + # Beacon block header + beacon: BeaconBlockHeader + # Execution payload header corresponding to `beacon.body_root` (from Capella onward) + execution: ExecutionPayloadHeader + execution_branch: Vector[Bytes32, floorlog2(EXECUTION_PAYLOAD_INDEX)] +``` + +### Modified `LightClientBootstrap` + +```python +class LightClientBootstrap(Container): + # Header matching the requested beacon block root + header: LightClientHeader # [Modified in Capella] + # Current sync committee corresponding to `header.beacon.state_root` + current_sync_committee: SyncCommittee + current_sync_committee_branch: Vector[Bytes32, floorlog2(CURRENT_SYNC_COMMITTEE_INDEX)] +``` + +### Modified `LightClientUpdate` + +```python +class LightClientUpdate(Container): + # Header attested to by the sync committee + attested_header: LightClientHeader # [Modified in Capella] + # Next sync committee corresponding to `attested_header.beacon.state_root` + next_sync_committee: SyncCommittee + next_sync_committee_branch: Vector[Bytes32, floorlog2(NEXT_SYNC_COMMITTEE_INDEX)] + # Finalized header corresponding to `attested_header.beacon.state_root` + finalized_header: LightClientHeader # [Modified in Capella] + finality_branch: Vector[Bytes32, floorlog2(FINALIZED_ROOT_INDEX)] + # Sync committee aggregate signature + sync_aggregate: SyncAggregate + # Slot at which the aggregate signature was created (untrusted) + signature_slot: Slot +``` + +### Modified `LightClientFinalityUpdate` + +```python +class LightClientFinalityUpdate(Container): + # Header attested to by the sync committee + attested_header: LightClientHeader # [Modified in Capella] + # Finalized header corresponding to `attested_header.beacon.state_root` + finalized_header: LightClientHeader # [Modified in Capella] + finality_branch: Vector[Bytes32, floorlog2(FINALIZED_ROOT_INDEX)] + # Sync committee aggregate signature + sync_aggregate: SyncAggregate + # Slot at which the aggregate signature was created (untrusted) + signature_slot: Slot +``` + +### Modified `LightClientOptimisticUpdate` + +```python +class LightClientOptimisticUpdate(Container): + # Header attested to by the sync committee + attested_header: LightClientHeader # [Modified in Capella] + # Sync committee aggregate signature + sync_aggregate: SyncAggregate + # Slot at which the aggregate signature was created (untrusted) + signature_slot: Slot +``` + +### Modified `LightClientStore` + +```python +@dataclass +class LightClientStore(object): + # Header that is finalized + finalized_header: LightClientHeader # [Modified in Capella] + # Sync committees corresponding to the finalized header + current_sync_committee: SyncCommittee + next_sync_committee: SyncCommittee + # Best available header to switch finalized head to if we see nothing else + best_valid_update: Optional[LightClientUpdate] + # Most recent available reasonably-safe header + optimistic_header: LightClientHeader # [Modified in Capella] + # Max number of active participants in a sync committee (used to calculate safety threshold) + previous_max_active_participants: uint64 + current_max_active_participants: uint64 +``` + +## Helper functions + +### Modified `get_lc_beacon_slot` + +```python +def get_lc_beacon_slot(header: LightClientHeader) -> Slot: + return header.beacon.slot +``` + +### Modified `get_lc_beacon_root` + +```python +def get_lc_beacon_root(header: LightClientHeader) -> Root: + return hash_tree_root(header.beacon) +``` + +### `get_lc_execution_root` + +```python +def get_lc_execution_root(header: LightClientHeader) -> Root: + if compute_epoch_at_slot(get_lc_beacon_slot(header)) >= CAPELLA_FORK_EPOCH: + return hash_tree_root(header.execution) + + return Root() +``` + +### `is_valid_light_client_header` + +```python +def is_valid_light_client_header(header: LightClientHeader) -> bool: + if compute_epoch_at_slot(get_lc_beacon_slot(header)) >= CAPELLA_FORK_EPOCH: + return is_valid_merkle_branch( + leaf=get_lc_execution_root(header), + branch=header.execution_branch, + depth=floorlog2(EXECUTION_PAYLOAD_INDEX), + index=get_subtree_index(EXECUTION_PAYLOAD_INDEX), + root=header.beacon.body_root, + ) + + return ( + header.execution == ExecutionPayloadHeader() + and header.execution_branch == [Bytes32() for _ in range(floorlog2(EXECUTION_PAYLOAD_INDEX))] + ) +``` + +## Light client initialization + +### Modified `initialize_light_client_store` + +```python +def initialize_light_client_store(trusted_block_root: Root, + bootstrap: LightClientBootstrap) -> LightClientStore: + assert is_valid_light_client_header(bootstrap.header) # [New in Capella] + assert get_lc_beacon_root(bootstrap.header) == trusted_block_root + + assert is_valid_merkle_branch( + leaf=hash_tree_root(bootstrap.current_sync_committee), + branch=bootstrap.current_sync_committee_branch, + depth=floorlog2(CURRENT_SYNC_COMMITTEE_INDEX), + index=get_subtree_index(CURRENT_SYNC_COMMITTEE_INDEX), + root=bootstrap.header.beacon.state_root, # [Modified in Capella] + ) + + return LightClientStore( + finalized_header=bootstrap.header, + current_sync_committee=bootstrap.current_sync_committee, + next_sync_committee=SyncCommittee(), + best_valid_update=None, + optimistic_header=bootstrap.header, + previous_max_active_participants=0, + current_max_active_participants=0, + ) +``` + +## Light client state updates + +### Modified `validate_light_client_update` + +```python +def validate_light_client_update(store: LightClientStore, + update: LightClientUpdate, + current_slot: Slot, + genesis_validators_root: Root) -> None: + # Verify sync committee has sufficient participants + sync_aggregate = update.sync_aggregate + assert sum(sync_aggregate.sync_committee_bits) >= MIN_SYNC_COMMITTEE_PARTICIPANTS + + # Verify update does not skip a sync committee period + assert is_valid_light_client_header(update.attested_header) # [New in Capella] + update_attested_slot = get_lc_beacon_slot(update.attested_header) + update_finalized_slot = get_lc_beacon_slot(update.finalized_header) + assert current_slot >= update.signature_slot > update_attested_slot >= update_finalized_slot + store_period = compute_sync_committee_period_at_slot(get_lc_beacon_slot(store.finalized_header)) + update_signature_period = compute_sync_committee_period_at_slot(update.signature_slot) + if is_next_sync_committee_known(store): + assert update_signature_period in (store_period, store_period + 1) + else: + assert update_signature_period == store_period + + # Verify update is relevant + update_attested_period = compute_sync_committee_period_at_slot(update_attested_slot) + update_has_next_sync_committee = not is_next_sync_committee_known(store) and ( + is_sync_committee_update(update) and update_attested_period == store_period + ) + assert update_attested_slot > update_finalized_slot or update_has_next_sync_committee + + # Verify that the `finality_branch`, if present, confirms `finalized_header.beacon` + # to match the finalized checkpoint root saved in the state of `attested_header.beacon`. + # Note that the genesis finalized checkpoint root is represented as a zero hash. + if not is_finality_update(update): + assert update.finalized_header == LightClientHeader() # [Modified in Capella] + else: + if update_finalized_slot == GENESIS_SLOT: + assert update.finalized_header == LightClientHeader() # [Modified in Capella] + finalized_root = Bytes32() + else: + assert is_valid_light_client_header(update.finalized_header) # [New in Capella] + finalized_root = get_lc_beacon_root(update.finalized_header) + assert is_valid_merkle_branch( + leaf=finalized_root, + branch=update.finality_branch, + depth=floorlog2(FINALIZED_ROOT_INDEX), + index=get_subtree_index(FINALIZED_ROOT_INDEX), + root=update.attested_header.beacon.state_root, # [Modified in Capella] + ) + + # Verify that the `next_sync_committee`, if present, actually is the next sync committee saved in the + # state of the `attested_header.beacon` + if not is_sync_committee_update(update): + assert update.next_sync_committee == SyncCommittee() + else: + if update_attested_period == store_period and is_next_sync_committee_known(store): + assert update.next_sync_committee == store.next_sync_committee + assert is_valid_merkle_branch( + leaf=hash_tree_root(update.next_sync_committee), + branch=update.next_sync_committee_branch, + depth=floorlog2(NEXT_SYNC_COMMITTEE_INDEX), + index=get_subtree_index(NEXT_SYNC_COMMITTEE_INDEX), + root=update.attested_header.beacon.state_root, # [Modified in Capella] + ) + + # Verify sync committee aggregate signature + if update_signature_period == store_period: + sync_committee = store.current_sync_committee + else: + sync_committee = store.next_sync_committee + participant_pubkeys = [ + pubkey for (bit, pubkey) in zip(sync_aggregate.sync_committee_bits, sync_committee.pubkeys) + if bit + ] + fork_version = compute_fork_version(compute_epoch_at_slot(update.signature_slot)) + domain = compute_domain(DOMAIN_SYNC_COMMITTEE, fork_version, genesis_validators_root) + signing_root = compute_signing_root(update.attested_header.beacon, domain) # [Modified in Capella] + assert bls.FastAggregateVerify(participant_pubkeys, signing_root, sync_aggregate.sync_committee_signature) +``` diff --git a/tests/core/pyspec/eth2spec/test/altair/light_client/test_sync.py b/tests/core/pyspec/eth2spec/test/altair/light_client/test_sync.py index cc6a070a3..53215670a 100644 --- a/tests/core/pyspec/eth2spec/test/altair/light_client/test_sync.py +++ b/tests/core/pyspec/eth2spec/test/altair/light_client/test_sync.py @@ -3,14 +3,30 @@ from typing import (Any, Dict, List) from eth_utils import encode_hex from eth2spec.test.context import ( spec_state_test_with_matching_config, + spec_test, + with_config_overrides, + with_matching_spec_config, + with_phases, with_presets, + with_state, with_altair_and_later, ) from eth2spec.test.helpers.attestations import ( next_slots_with_attestations, state_transition_with_full_block, ) -from eth2spec.test.helpers.constants import MINIMAL +from eth2spec.test.helpers.constants import ( + PHASE0, ALTAIR, BELLATRIX, CAPELLA, + MINIMAL, + ALL_PHASES, +) +from eth2spec.test.helpers.fork_transition import ( + do_fork, +) +from eth2spec.test.helpers.forks import ( + is_post_capella, + is_post_fork, +) from eth2spec.test.helpers.light_client import ( get_sync_aggregate, ) @@ -20,25 +36,117 @@ from eth2spec.test.helpers.state import ( ) -def setup_test(spec, state): - class LightClientSyncTest(object): - steps: List[Dict[str, Any]] - genesis_validators_root: spec.Root - store: spec.LightClientStore +def get_spec_for_fork_version(spec, fork_version, phases): + if phases is None: + return spec + for fork in [fork for fork in ALL_PHASES if is_post_fork(spec.fork, fork)]: + if fork == PHASE0: + fork_version_field = 'GENESIS_FORK_VERSION' + else: + fork_version_field = fork.upper() + '_FORK_VERSION' + if fork_version == getattr(spec.config, fork_version_field): + return phases[fork] + raise ValueError("Unknown fork version %s" % fork_version) + +def needs_upgrade_to_capella(d_spec, s_spec): + return is_post_capella(s_spec) and not is_post_capella(d_spec) + + +def upgrade_lc_bootstrap_to_store(d_spec, s_spec, data): + if not needs_upgrade_to_capella(d_spec, s_spec): + return data + + upgraded = s_spec.upgrade_lc_bootstrap_to_capella(data) + assert s_spec.get_lc_beacon_slot(upgraded.header) == d_spec.get_lc_beacon_slot(data.header) + assert s_spec.get_lc_beacon_root(upgraded.header) == d_spec.get_lc_beacon_root(data.header) + assert s_spec.get_lc_execution_root(upgraded.header) == s_spec.Root() + assert upgraded.current_sync_committee == data.current_sync_committee + assert upgraded.current_sync_committee_branch == data.current_sync_committee_branch + return upgraded + + +def upgrade_lc_update_to_store(d_spec, s_spec, data): + if not needs_upgrade_to_capella(d_spec, s_spec): + return data + + upgraded = s_spec.upgrade_lc_update_to_capella(data) + assert s_spec.get_lc_beacon_slot(upgraded.attested_header) == d_spec.get_lc_beacon_slot(data.attested_header) + assert s_spec.get_lc_beacon_root(upgraded.attested_header) == d_spec.get_lc_beacon_root(data.attested_header) + assert s_spec.get_lc_execution_root(upgraded.attested_header) == s_spec.Root() + assert upgraded.next_sync_committee == data.next_sync_committee + assert upgraded.next_sync_committee_branch == data.next_sync_committee_branch + assert s_spec.get_lc_beacon_slot(upgraded.finalized_header) == d_spec.get_lc_beacon_slot(data.finalized_header) + assert s_spec.get_lc_beacon_root(upgraded.finalized_header) == d_spec.get_lc_beacon_root(data.finalized_header) + assert s_spec.get_lc_execution_root(upgraded.finalized_header) == s_spec.Root() + assert upgraded.sync_aggregate == data.sync_aggregate + assert upgraded.signature_slot == data.signature_slot + return upgraded + + +def upgrade_lc_store_to_new_spec(d_spec, s_spec, data): + if not needs_upgrade_to_capella(d_spec, s_spec): + return data + + upgraded = s_spec.upgrade_lc_store_to_capella(data) + assert s_spec.get_lc_beacon_slot(upgraded.finalized_header) == d_spec.get_lc_beacon_slot(data.finalized_header) + assert s_spec.get_lc_beacon_root(upgraded.finalized_header) == d_spec.get_lc_beacon_root(data.finalized_header) + assert s_spec.get_lc_execution_root(upgraded.finalized_header) == s_spec.Root() + assert upgraded.current_sync_committee == data.current_sync_committee + assert upgraded.next_sync_committee == data.next_sync_committee + if upgraded.best_valid_update is None: + assert data.best_valid_update is None + else: + assert upgraded.best_valid_update == upgrade_lc_update_to_store(d_spec, s_spec, data.best_valid_update) + assert s_spec.get_lc_beacon_slot(upgraded.optimistic_header) == d_spec.get_lc_beacon_slot(data.optimistic_header) + assert s_spec.get_lc_beacon_root(upgraded.optimistic_header) == d_spec.get_lc_beacon_root(data.optimistic_header) + assert s_spec.get_lc_execution_root(upgraded.optimistic_header) == s_spec.Root() + assert upgraded.previous_max_active_participants == data.previous_max_active_participants + assert upgraded.current_max_active_participants == data.current_max_active_participants + return upgraded + + +class LightClientSyncTest(object): + steps: List[Dict[str, Any]] + genesis_validators_root: Any + s_spec: Any + store: Any + + +def get_store_fork_version(s_spec): + if is_post_capella(s_spec): + return s_spec.config.CAPELLA_FORK_VERSION + return s_spec.config.ALTAIR_FORK_VERSION + + +def setup_test(spec, state, s_spec=None, phases=None): test = LightClientSyncTest() test.steps = [] + if s_spec is None: + s_spec = spec + test.s_spec = s_spec + yield "genesis_validators_root", "meta", "0x" + state.genesis_validators_root.hex() test.genesis_validators_root = state.genesis_validators_root next_slots(spec, state, spec.SLOTS_PER_EPOCH * 2 - 1) trusted_block = state_transition_with_full_block(spec, state, True, True) trusted_block_root = trusted_block.message.hash_tree_root() - bootstrap = spec.create_light_client_bootstrap(state, trusted_block) yield "trusted_block_root", "meta", "0x" + trusted_block_root.hex() - yield "bootstrap", bootstrap - test.store = spec.initialize_light_client_store(trusted_block_root, bootstrap) + + data_fork_version = spec.compute_fork_version(spec.compute_epoch_at_slot(trusted_block.message.slot)) + data_fork_digest = spec.compute_fork_digest(data_fork_version, test.genesis_validators_root) + d_spec = get_spec_for_fork_version(spec, data_fork_version, phases) + data = d_spec.create_light_client_bootstrap(state, trusted_block) + yield "bootstrap_fork_digest", "meta", encode_hex(data_fork_digest) + yield "bootstrap", data + + upgraded = upgrade_lc_bootstrap_to_store(d_spec, test.s_spec, data) + test.store = test.s_spec.initialize_light_client_store(trusted_block_root, upgraded) + store_fork_version = get_store_fork_version(test.s_spec) + store_fork_digest = test.s_spec.compute_fork_digest(store_fork_version, test.genesis_validators_root) + yield "store_fork_digest", "meta", encode_hex(store_fork_digest) return test @@ -47,62 +155,97 @@ def finish_test(test): yield "steps", test.steps -def get_update_file_name(spec, update): - if spec.is_sync_committee_update(update): +def get_update_file_name(d_spec, update): + if d_spec.is_sync_committee_update(update): suffix1 = "s" else: suffix1 = "x" - if spec.is_finality_update(update): + if d_spec.is_finality_update(update): suffix2 = "f" else: suffix2 = "x" - return f"update_{encode_hex(spec.get_lc_beacon_root(update.attested_header))}_{suffix1}{suffix2}" + return f"update_{encode_hex(d_spec.get_lc_beacon_root(update.attested_header))}_{suffix1}{suffix2}" -def get_checks(spec, store): +def get_checks(s_spec, store): + if is_post_capella(s_spec): + return { + "finalized_header": { + 'slot': int(s_spec.get_lc_beacon_slot(store.finalized_header)), + 'beacon_root': encode_hex(s_spec.get_lc_beacon_root(store.finalized_header)), + 'execution_root': encode_hex(s_spec.get_lc_execution_root(store.finalized_header)), + }, + "optimistic_header": { + 'slot': int(s_spec.get_lc_beacon_slot(store.optimistic_header)), + 'beacon_root': encode_hex(s_spec.get_lc_beacon_root(store.optimistic_header)), + 'execution_root': encode_hex(s_spec.get_lc_execution_root(store.optimistic_header)), + }, + } + return { "finalized_header": { - 'slot': int(spec.get_lc_beacon_slot(store.finalized_header)), - 'beacon_root': encode_hex(spec.get_lc_beacon_root(store.finalized_header)), + 'slot': int(s_spec.get_lc_beacon_slot(store.finalized_header)), + 'beacon_root': encode_hex(s_spec.get_lc_beacon_root(store.finalized_header)), }, "optimistic_header": { - 'slot': int(spec.get_lc_beacon_slot(store.optimistic_header)), - 'beacon_root': encode_hex(spec.get_lc_beacon_root(store.optimistic_header)), + 'slot': int(s_spec.get_lc_beacon_slot(store.optimistic_header)), + 'beacon_root': encode_hex(s_spec.get_lc_beacon_root(store.optimistic_header)), }, } def emit_force_update(test, spec, state): current_slot = state.slot - spec.process_light_client_store_force_update(test.store, current_slot) + test.s_spec.process_light_client_store_force_update(test.store, current_slot) yield from [] # Consistently enable `yield from` syntax in calling tests test.steps.append({ "force_update": { "current_slot": int(current_slot), - "checks": get_checks(spec, test.store), + "checks": get_checks(test.s_spec, test.store), } }) -def emit_update(test, spec, state, block, attested_state, attested_block, finalized_block, with_next=True): - update = spec.create_light_client_update(state, block, attested_state, attested_block, finalized_block) +def emit_update(test, spec, state, block, attested_state, attested_block, finalized_block, with_next=True, phases=None): + data_fork_version = spec.compute_fork_version(spec.compute_epoch_at_slot(attested_block.message.slot)) + data_fork_digest = spec.compute_fork_digest(data_fork_version, test.genesis_validators_root) + d_spec = get_spec_for_fork_version(spec, data_fork_version, phases) + data = d_spec.create_light_client_update(state, block, attested_state, attested_block, finalized_block) if not with_next: - update.next_sync_committee = spec.SyncCommittee() - update.next_sync_committee_branch = \ + data.next_sync_committee = spec.SyncCommittee() + data.next_sync_committee_branch = \ [spec.Bytes32() for _ in range(spec.floorlog2(spec.NEXT_SYNC_COMMITTEE_INDEX))] current_slot = state.slot - spec.process_light_client_update(test.store, update, current_slot, test.genesis_validators_root) - yield get_update_file_name(spec, update), update + upgraded = upgrade_lc_update_to_store(d_spec, test.s_spec, data) + test.s_spec.process_light_client_update(test.store, upgraded, current_slot, test.genesis_validators_root) + + yield get_update_file_name(d_spec, data), data test.steps.append({ "process_update": { - "update": get_update_file_name(spec, update), + "update_fork_digest": encode_hex(data_fork_digest), + "update": get_update_file_name(d_spec, data), "current_slot": int(current_slot), - "checks": get_checks(spec, test.store), + "checks": get_checks(test.s_spec, test.store), + } + }) + return upgraded + + +def emit_upgrade_store(test, new_s_spec, phases=None): + test.store = upgrade_lc_store_to_new_spec(test.s_spec, new_s_spec, test.store) + test.s_spec = new_s_spec + store_fork_version = get_store_fork_version(test.s_spec) + store_fork_digest = test.s_spec.compute_fork_digest(store_fork_version, test.genesis_validators_root) + + yield from [] # Consistently enable `yield from` syntax in calling tests + test.steps.append({ + "process_upgrade_store": { + "store_fork_digest": encode_hex(store_fork_digest), + "checks": get_checks(test.s_spec, test.store), } }) - return update def compute_start_slot_at_sync_committee_period(spec, sync_committee_period): @@ -141,10 +284,10 @@ def test_light_client_sync(spec, state): sync_aggregate, _ = get_sync_aggregate(spec, state) block = state_transition_with_full_block(spec, state, True, True, sync_aggregate=sync_aggregate) yield from emit_update(test, spec, state, block, attested_state, attested_block, finalized_block) - assert spec.get_lc_beacon_slot(test.store.finalized_header) == finalized_state.slot + assert test.s_spec.get_lc_beacon_slot(test.store.finalized_header) == finalized_state.slot assert test.store.next_sync_committee == finalized_state.next_sync_committee assert test.store.best_valid_update is None - assert spec.get_lc_beacon_slot(test.store.optimistic_header) == attested_state.slot + assert test.s_spec.get_lc_beacon_slot(test.store.optimistic_header) == attested_state.slot # Advance to next sync committee period # ``` @@ -167,10 +310,10 @@ def test_light_client_sync(spec, state): sync_aggregate, _ = get_sync_aggregate(spec, state) block = state_transition_with_full_block(spec, state, True, True, sync_aggregate=sync_aggregate) yield from emit_update(test, spec, state, block, attested_state, attested_block, finalized_block) - assert spec.get_lc_beacon_slot(test.store.finalized_header) == finalized_state.slot + assert test.s_spec.get_lc_beacon_slot(test.store.finalized_header) == finalized_state.slot assert test.store.next_sync_committee == finalized_state.next_sync_committee assert test.store.best_valid_update is None - assert spec.get_lc_beacon_slot(test.store.optimistic_header) == attested_state.slot + assert test.s_spec.get_lc_beacon_slot(test.store.optimistic_header) == attested_state.slot # Edge case: Signature in next period # ``` @@ -193,10 +336,10 @@ def test_light_client_sync(spec, state): sync_aggregate, _ = get_sync_aggregate(spec, state) block = state_transition_with_full_block(spec, state, True, True, sync_aggregate=sync_aggregate) yield from emit_update(test, spec, state, block, attested_state, attested_block, finalized_block) - assert spec.get_lc_beacon_slot(test.store.finalized_header) == finalized_state.slot + assert test.s_spec.get_lc_beacon_slot(test.store.finalized_header) == finalized_state.slot assert test.store.next_sync_committee == finalized_state.next_sync_committee assert test.store.best_valid_update is None - assert spec.get_lc_beacon_slot(test.store.optimistic_header) == attested_state.slot + assert test.s_spec.get_lc_beacon_slot(test.store.optimistic_header) == attested_state.slot # Edge case: Finalized header not included # ``` @@ -214,10 +357,10 @@ def test_light_client_sync(spec, state): sync_aggregate, _ = get_sync_aggregate(spec, state) block = state_transition_with_full_block(spec, state, True, True, sync_aggregate=sync_aggregate) update = yield from emit_update(test, spec, state, block, attested_state, attested_block, finalized_block=None) - assert spec.get_lc_beacon_slot(test.store.finalized_header) == finalized_state.slot + assert test.s_spec.get_lc_beacon_slot(test.store.finalized_header) == finalized_state.slot assert test.store.next_sync_committee == finalized_state.next_sync_committee assert test.store.best_valid_update == update - assert spec.get_lc_beacon_slot(test.store.optimistic_header) == attested_state.slot + assert test.s_spec.get_lc_beacon_slot(test.store.optimistic_header) == attested_state.slot # Non-finalized case: Attested `next_sync_committee` is not finalized # ``` @@ -236,10 +379,10 @@ def test_light_client_sync(spec, state): sync_aggregate, _ = get_sync_aggregate(spec, state) block = state_transition_with_full_block(spec, state, True, True, sync_aggregate=sync_aggregate) update = yield from emit_update(test, spec, state, block, attested_state, attested_block, finalized_block) - assert spec.get_lc_beacon_slot(test.store.finalized_header) == finalized_state.slot + assert test.s_spec.get_lc_beacon_slot(test.store.finalized_header) == finalized_state.slot assert test.store.next_sync_committee == finalized_state.next_sync_committee assert test.store.best_valid_update == update - assert spec.get_lc_beacon_slot(test.store.optimistic_header) == attested_state.slot + assert test.s_spec.get_lc_beacon_slot(test.store.optimistic_header) == attested_state.slot # Force-update using timeout # ``` @@ -278,7 +421,7 @@ def test_light_client_sync(spec, state): assert spec.get_lc_beacon_slot(test.store.finalized_header) == store_state.slot assert test.store.next_sync_committee == store_state.next_sync_committee assert test.store.best_valid_update == update - assert spec.get_lc_beacon_slot(test.store.optimistic_header) == attested_state.slot + assert test.s_spec.get_lc_beacon_slot(test.store.optimistic_header) == attested_state.slot # Edge case: Finalized header older than store # ``` @@ -299,12 +442,12 @@ def test_light_client_sync(spec, state): assert spec.get_lc_beacon_slot(test.store.finalized_header) == store_state.slot assert test.store.next_sync_committee == store_state.next_sync_committee assert test.store.best_valid_update == update - assert spec.get_lc_beacon_slot(test.store.optimistic_header) == attested_state.slot + assert test.s_spec.get_lc_beacon_slot(test.store.optimistic_header) == attested_state.slot yield from emit_force_update(test, spec, state) assert spec.get_lc_beacon_slot(test.store.finalized_header) == attested_state.slot assert test.store.next_sync_committee == attested_state.next_sync_committee assert test.store.best_valid_update is None - assert spec.get_lc_beacon_slot(test.store.optimistic_header) == attested_state.slot + assert test.s_spec.get_lc_beacon_slot(test.store.optimistic_header) == attested_state.slot # Advance to next sync committee period # ``` @@ -327,10 +470,10 @@ def test_light_client_sync(spec, state): sync_aggregate, _ = get_sync_aggregate(spec, state) block = state_transition_with_full_block(spec, state, True, True, sync_aggregate=sync_aggregate) yield from emit_update(test, spec, state, block, attested_state, attested_block, finalized_block) - assert spec.get_lc_beacon_slot(test.store.finalized_header) == finalized_state.slot + assert test.s_spec.get_lc_beacon_slot(test.store.finalized_header) == finalized_state.slot assert test.store.next_sync_committee == finalized_state.next_sync_committee assert test.store.best_valid_update is None - assert spec.get_lc_beacon_slot(test.store.optimistic_header) == attested_state.slot + assert test.s_spec.get_lc_beacon_slot(test.store.optimistic_header) == attested_state.slot # Finish test yield from finish_test(test) @@ -383,10 +526,10 @@ def test_advance_finality_without_sync_committee(spec, state): sync_aggregate, _ = get_sync_aggregate(spec, state) block = state_transition_with_full_block(spec, state, True, True, sync_aggregate=sync_aggregate) yield from emit_update(test, spec, state, block, attested_state, attested_block, finalized_block) - assert spec.get_lc_beacon_slot(test.store.finalized_header) == finalized_state.slot + assert test.s_spec.get_lc_beacon_slot(test.store.finalized_header) == finalized_state.slot assert test.store.next_sync_committee == finalized_state.next_sync_committee assert test.store.best_valid_update is None - assert spec.get_lc_beacon_slot(test.store.optimistic_header) == attested_state.slot + assert test.s_spec.get_lc_beacon_slot(test.store.optimistic_header) == attested_state.slot # Advance finality into next sync committee period, but omit `next_sync_committee` transition_to(spec, state, compute_start_slot_at_next_sync_committee_period(spec, state)) @@ -402,10 +545,10 @@ def test_advance_finality_without_sync_committee(spec, state): sync_aggregate, _ = get_sync_aggregate(spec, state) block = state_transition_with_full_block(spec, state, True, True, sync_aggregate=sync_aggregate) yield from emit_update(test, spec, state, block, attested_state, attested_block, finalized_block, with_next=False) - assert spec.get_lc_beacon_slot(test.store.finalized_header) == finalized_state.slot + assert test.s_spec.get_lc_beacon_slot(test.store.finalized_header) == finalized_state.slot assert not spec.is_next_sync_committee_known(test.store) assert test.store.best_valid_update is None - assert spec.get_lc_beacon_slot(test.store.optimistic_header) == attested_state.slot + assert test.s_spec.get_lc_beacon_slot(test.store.optimistic_header) == attested_state.slot # Advance finality once more, with `next_sync_committee` still unknown past_state = finalized_state @@ -422,21 +565,162 @@ def test_advance_finality_without_sync_committee(spec, state): assert spec.get_lc_beacon_slot(test.store.finalized_header) == past_state.slot assert not spec.is_next_sync_committee_known(test.store) assert test.store.best_valid_update == update - assert spec.get_lc_beacon_slot(test.store.optimistic_header) == attested_state.slot + assert test.s_spec.get_lc_beacon_slot(test.store.optimistic_header) == attested_state.slot # Apply `LightClientUpdate` with `finalized_header` but no `next_sync_committee` yield from emit_update(test, spec, state, block, attested_state, attested_block, finalized_block, with_next=False) - assert spec.get_lc_beacon_slot(test.store.finalized_header) == finalized_state.slot + assert test.s_spec.get_lc_beacon_slot(test.store.finalized_header) == finalized_state.slot assert not spec.is_next_sync_committee_known(test.store) assert test.store.best_valid_update is None - assert spec.get_lc_beacon_slot(test.store.optimistic_header) == attested_state.slot + assert test.s_spec.get_lc_beacon_slot(test.store.optimistic_header) == attested_state.slot # Apply full `LightClientUpdate`, supplying `next_sync_committee` yield from emit_update(test, spec, state, block, attested_state, attested_block, finalized_block) - assert spec.get_lc_beacon_slot(test.store.finalized_header) == finalized_state.slot + assert test.s_spec.get_lc_beacon_slot(test.store.finalized_header) == finalized_state.slot assert test.store.next_sync_committee == finalized_state.next_sync_committee assert test.store.best_valid_update is None - assert spec.get_lc_beacon_slot(test.store.optimistic_header) == attested_state.slot + assert test.s_spec.get_lc_beacon_slot(test.store.optimistic_header) == attested_state.slot + + # Finish test + yield from finish_test(test) + + +@with_phases(phases=[BELLATRIX], other_phases=[CAPELLA]) +@spec_test +@with_config_overrides({ + 'CAPELLA_FORK_EPOCH': 3, # `setup_test` advances to epoch 2 +}, emit=False) +@with_state +@with_matching_spec_config(emitted_fork=CAPELLA) +@with_presets([MINIMAL], reason="too slow") +def test_capella_fork(spec, phases, state): + # Start test + test = yield from setup_test(spec, state, phases=phases) + + # Initial `LightClientUpdate` + finalized_block = spec.SignedBeaconBlock() + finalized_block.message.state_root = state.hash_tree_root() + finalized_state = state.copy() + attested_block = state_transition_with_full_block(spec, state, True, True) + attested_state = state.copy() + sync_aggregate, _ = get_sync_aggregate(spec, state) + block = state_transition_with_full_block(spec, state, True, True, sync_aggregate=sync_aggregate) + yield from emit_update(test, spec, state, block, attested_state, attested_block, finalized_block, phases=phases) + assert test.s_spec.get_lc_beacon_slot(test.store.finalized_header) == finalized_state.slot + assert test.store.next_sync_committee == finalized_state.next_sync_committee + assert test.store.best_valid_update is None + assert test.s_spec.get_lc_beacon_slot(test.store.optimistic_header) == attested_state.slot + + # Jump to two slots before Capella + transition_to(spec, state, spec.compute_start_slot_at_epoch(phases[CAPELLA].config.CAPELLA_FORK_EPOCH) - 4) + attested_block = state_transition_with_full_block(spec, state, True, True) + attested_state = state.copy() + sync_aggregate, _ = get_sync_aggregate(spec, state) + block = state_transition_with_full_block(spec, state, True, True, sync_aggregate=sync_aggregate) + update = \ + yield from emit_update(test, spec, state, block, attested_state, attested_block, finalized_block, phases=phases) + assert test.s_spec.get_lc_beacon_slot(test.store.finalized_header) == finalized_state.slot + assert test.store.next_sync_committee == finalized_state.next_sync_committee + assert test.store.best_valid_update == update + assert test.s_spec.get_lc_beacon_slot(test.store.optimistic_header) == attested_state.slot + + # Perform `LightClientStore` upgrade + yield from emit_upgrade_store(test, phases[CAPELLA], phases=phases) + update = test.store.best_valid_update + + # Final slot before Capella, check that importing the Altair format still works + attested_block = block.copy() + attested_state = state.copy() + sync_aggregate, _ = get_sync_aggregate(spec, state) + block = state_transition_with_full_block(spec, state, True, True, sync_aggregate=sync_aggregate) + yield from emit_update(test, spec, state, block, attested_state, attested_block, finalized_block, phases=phases) + assert test.s_spec.get_lc_beacon_slot(test.store.finalized_header) == finalized_state.slot + assert test.store.next_sync_committee == finalized_state.next_sync_committee + assert test.store.best_valid_update == update + assert test.s_spec.get_lc_beacon_slot(test.store.optimistic_header) == attested_state.slot + + # Upgrade to Capella, attested block is still before the fork + attested_block = block.copy() + attested_state = state.copy() + state, _ = do_fork(state, spec, phases[CAPELLA], phases[CAPELLA].config.CAPELLA_FORK_EPOCH, with_block=False) + spec = phases[CAPELLA] + sync_aggregate, _ = get_sync_aggregate(spec, state) + block = state_transition_with_full_block(spec, state, True, True, sync_aggregate=sync_aggregate) + yield from emit_update(test, spec, state, block, attested_state, attested_block, finalized_block, phases=phases) + assert test.s_spec.get_lc_beacon_slot(test.store.finalized_header) == finalized_state.slot + assert test.store.next_sync_committee == finalized_state.next_sync_committee + assert test.store.best_valid_update == update + assert test.s_spec.get_lc_beacon_slot(test.store.optimistic_header) == attested_state.slot + assert test.s_spec.get_lc_execution_root(test.store.optimistic_header) == test.s_spec.Root() + + # Another block in Capella, this time attested block is after the fork + attested_block = block.copy() + attested_state = state.copy() + sync_aggregate, _ = get_sync_aggregate(spec, state) + block = state_transition_with_full_block(spec, state, True, True, sync_aggregate=sync_aggregate) + yield from emit_update(test, spec, state, block, attested_state, attested_block, finalized_block, phases=phases) + assert test.s_spec.get_lc_beacon_slot(test.store.finalized_header) == finalized_state.slot + assert test.store.next_sync_committee == finalized_state.next_sync_committee + assert test.store.best_valid_update == update + assert test.s_spec.get_lc_beacon_slot(test.store.optimistic_header) == attested_state.slot + assert test.s_spec.get_lc_execution_root(test.store.optimistic_header) != test.s_spec.Root() + + # Jump to next epoch + transition_to(spec, state, spec.compute_start_slot_at_epoch(phases[CAPELLA].config.CAPELLA_FORK_EPOCH + 1) - 2) + attested_block = state_transition_with_full_block(spec, state, True, True) + attested_state = state.copy() + sync_aggregate, _ = get_sync_aggregate(spec, state) + block = state_transition_with_full_block(spec, state, True, True, sync_aggregate=sync_aggregate) + yield from emit_update(test, spec, state, block, attested_state, attested_block, finalized_block, phases=phases) + assert test.s_spec.get_lc_beacon_slot(test.store.finalized_header) == finalized_state.slot + assert test.s_spec.get_lc_execution_root(test.store.finalized_header) == test.s_spec.Root() + assert test.store.next_sync_committee == finalized_state.next_sync_committee + assert test.store.best_valid_update == update + assert test.s_spec.get_lc_beacon_slot(test.store.optimistic_header) == attested_state.slot + assert test.s_spec.get_lc_execution_root(test.store.optimistic_header) != test.s_spec.Root() + + # Finalize it + finalized_block = block.copy() + finalized_state = state.copy() + _, _, state = next_slots_with_attestations(spec, state, 2 * spec.SLOTS_PER_EPOCH - 1, True, True) + attested_block = state_transition_with_full_block(spec, state, True, True) + attested_state = state.copy() + sync_aggregate, _ = get_sync_aggregate(spec, state) + block = state_transition_with_full_block(spec, state, True, True, sync_aggregate=sync_aggregate) + yield from emit_update(test, spec, state, block, attested_state, attested_block, finalized_block, phases=phases) + assert test.s_spec.get_lc_beacon_slot(test.store.finalized_header) == finalized_state.slot + assert test.s_spec.get_lc_execution_root(test.store.finalized_header) != test.s_spec.Root() + assert test.store.next_sync_committee == finalized_state.next_sync_committee + assert test.store.best_valid_update is None + assert test.s_spec.get_lc_beacon_slot(test.store.optimistic_header) == attested_state.slot + assert test.s_spec.get_lc_execution_root(test.store.optimistic_header) != test.s_spec.Root() + + # Finish test + yield from finish_test(test) + + +@with_phases(phases=[ALTAIR, BELLATRIX], other_phases=[CAPELLA]) +@spec_test +@with_state +@with_matching_spec_config(emitted_fork=CAPELLA) +@with_presets([MINIMAL], reason="too slow") +def test_capella_store_with_legacy_data(spec, phases, state): + # Start test (Altair bootstrap but with a Capella store) + test = yield from setup_test(spec, state, s_spec=phases[CAPELLA], phases=phases) + + # Initial `LightClientUpdate` (check that it works with Capella store) + finalized_block = spec.SignedBeaconBlock() + finalized_block.message.state_root = state.hash_tree_root() + finalized_state = state.copy() + attested_block = state_transition_with_full_block(spec, state, True, True) + attested_state = state.copy() + sync_aggregate, _ = get_sync_aggregate(spec, state) + block = state_transition_with_full_block(spec, state, True, True, sync_aggregate=sync_aggregate) + yield from emit_update(test, spec, state, block, attested_state, attested_block, finalized_block, phases=phases) + assert test.s_spec.get_lc_beacon_slot(test.store.finalized_header) == finalized_state.slot + assert test.store.next_sync_committee == finalized_state.next_sync_committee + assert test.store.best_valid_update is None + assert test.s_spec.get_lc_beacon_slot(test.store.optimistic_header) == attested_state.slot # Finish test yield from finish_test(test) diff --git a/tests/core/pyspec/eth2spec/test/capella/light_client/__init__.py b/tests/core/pyspec/eth2spec/test/capella/light_client/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/tests/core/pyspec/eth2spec/test/capella/light_client/test_single_merkle_proof.py b/tests/core/pyspec/eth2spec/test/capella/light_client/test_single_merkle_proof.py new file mode 100644 index 000000000..ca257a5a3 --- /dev/null +++ b/tests/core/pyspec/eth2spec/test/capella/light_client/test_single_merkle_proof.py @@ -0,0 +1,31 @@ +from eth2spec.test.context import ( + spec_state_test, + with_capella_and_later, + with_test_suite_name, +) +from eth2spec.test.helpers.attestations import ( + state_transition_with_full_block, +) + + +@with_test_suite_name("BeaconBlockBody") +@with_capella_and_later +@spec_state_test +def test_execution_merkle_proof(spec, state): + block = state_transition_with_full_block(spec, state, True, False) + + yield "object", block.message.body + execution_branch = \ + spec.compute_merkle_proof_for_block_body(block.message.body, spec.EXECUTION_PAYLOAD_INDEX) + yield "proof", { + "leaf": "0x" + block.message.body.execution_payload.hash_tree_root().hex(), + "leaf_index": spec.EXECUTION_PAYLOAD_INDEX, + "branch": ['0x' + root.hex() for root in execution_branch] + } + assert spec.is_valid_merkle_branch( + leaf=block.message.body.execution_payload.hash_tree_root(), + branch=execution_branch, + depth=spec.floorlog2(spec.EXECUTION_PAYLOAD_INDEX), + index=spec.get_subtree_index(spec.EXECUTION_PAYLOAD_INDEX), + root=block.message.body.hash_tree_root(), + ) diff --git a/tests/formats/light_client/sync.md b/tests/formats/light_client/sync.md index 3beeec0dd..5d6ac2b92 100644 --- a/tests/formats/light_client/sync.md +++ b/tests/formats/light_client/sync.md @@ -9,11 +9,15 @@ This series of tests provides reference test vectors for validating that a light ```yaml genesis_validators_root: Bytes32 -- string, hex encoded, with 0x prefix trusted_block_root: Bytes32 -- string, hex encoded, with 0x prefix +bootstrap_fork_digest: string -- Encoded `ForkDigest`-context of `bootstrap` +store_fork_digest: string -- Encoded `ForkDigest`-context of `store` object being tested ``` ### `bootstrap.ssz_snappy` -An SSZ-snappy encoded `bootstrap` object of type `LightClientBootstrap` to initialize a local `store` object of type `LightClientStore` using `initialize_light_client_store(trusted_block_rooot, bootstrap)`. +An SSZ-snappy encoded `bootstrap` object of type `LightClientBootstrap` to initialize a local `store` object of type `LightClientStore` with `store_fork_digest` using `initialize_light_client_store(trusted_block_rooot, bootstrap)`. The SSZ type can be determined from `bootstrap_fork_digest`. + +If `store_fork_digest` differs from `bootstrap_fork_digest`, the `bootstrap` object may need upgrading before initializing the store. ### `steps.yaml` @@ -27,10 +31,12 @@ Each step includes checks to verify the expected impact on the `store` object. finalized_header: { slot: int, -- Integer value from get_lc_beacon_slot(store.finalized_header) beacon_root: string, -- Encoded 32-byte value from get_lc_beacon_root(store.finalized_header) + execution_root: string, -- From Capella onward; get_lc_execution_root(store.finalized_header) } optimistic_header: { slot: int, -- Integer value from get_lc_beacon_slot(store.optimistic_header) beacon_root: string, -- Encoded 32-byte value from get_lc_beacon_root(store.optimistic_header) + execution_root: string, -- From Capella onward; get_lc_execution_root(store.optimistic_header) } ``` @@ -54,6 +60,7 @@ The function `process_light_client_update(store, update, current_slot, genesis_v ```yaml { + update_fork_digest: string -- Encoded `ForkDigest`-context of `update` update: string -- name of the `*.ssz_snappy` file to load as a `LightClientUpdate` object current_slot: int -- integer, decimal @@ -61,8 +68,24 @@ The function `process_light_client_update(store, update, current_slot, genesis_v } ``` +If `store_fork_digest` differs from `update_fork_digest`, the `update` object may need upgrading before initializing the store. + After this step, the `store` object may have been updated. +#### `process_upgrade_store` + +The `store` should be upgraded to reflect the new `store_fork_digest`: + +```yaml +{ + store_fork_digest: string -- Encoded `ForkDigest`-context of `store` + checks: {: value} -- the assertions. +} +``` + +After this step, the `store` object may have been updated. + + ## Condition A test-runner should initialize a local `LightClientStore` using the provided `bootstrap` object. It should then proceed to execute all the test steps in sequence. After each step, it should verify that the resulting `store` verifies against the provided `checks`. diff --git a/tests/generators/light_client/main.py b/tests/generators/light_client/main.py index 5d45bf39d..54c09fae6 100644 --- a/tests/generators/light_client/main.py +++ b/tests/generators/light_client/main.py @@ -1,5 +1,5 @@ from eth2spec.test.helpers.constants import ALTAIR, BELLATRIX, CAPELLA, EIP4844 -from eth2spec.gen_helpers.gen_from_tests.gen import run_state_test_generators +from eth2spec.gen_helpers.gen_from_tests.gen import combine_mods, run_state_test_generators if __name__ == "__main__": @@ -9,7 +9,11 @@ if __name__ == "__main__": 'update_ranking', ]} bellatrix_mods = altair_mods - capella_mods = bellatrix_mods + + _new_capella_mods = {key: 'eth2spec.test.capella.light_client.test_' + key for key in [ + 'single_merkle_proof', + ]} + capella_mods = combine_mods(_new_capella_mods, bellatrix_mods) eip4844_mods = capella_mods all_mods = { From 82ff974090638cb966771defd6ee36d3e4210065 Mon Sep 17 00:00:00 2001 From: Etan Kissling Date: Mon, 12 Dec 2022 12:15:27 +0100 Subject: [PATCH 011/158] Emit config before calling test to ignore changes --- tests/core/pyspec/eth2spec/test/context.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/core/pyspec/eth2spec/test/context.py b/tests/core/pyspec/eth2spec/test/context.py index b1f608d7b..4bddaba1c 100644 --- a/tests/core/pyspec/eth2spec/test/context.py +++ b/tests/core/pyspec/eth2spec/test/context.py @@ -617,13 +617,13 @@ def with_config_overrides(config_overrides, emitted_fork=None, emit=True): output_config = output kw['phases'] = phases - # Run the function - out = fn(*args, spec=spec, **kw) - # Emit requested spec (with overrides) if emit: yield 'config', 'cfg', output_config + # Run the function + out = fn(*args, spec=spec, **kw) + # If it's not returning None like a normal test function, # it's generating things, and we need to complete it before setting back the config. if out is not None: From 2df8a559b8a20cee0a371d8185909c402fe0fe21 Mon Sep 17 00:00:00 2001 From: Etan Kissling Date: Mon, 12 Dec 2022 12:19:46 +0100 Subject: [PATCH 012/158] Fix LC references in main readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 766b6eda7..7c9713a47 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,7 @@ Features are researched and developed in parallel, and then consolidated into se ### In-development Specifications | Code Name or Topic | Specs | Notes | | - | - | - | -| Capella (tentative) |
  • Core
    • [Beacon chain changes](specs/capella/beacon-chain.md)
    • [Capella fork](specs/capella/fork.md)
  • Additions
    • [Light client sync protocol changes](specs/capella/sync-protocol.md) ([fork](specs/capella/light-client/fork.md), [full node](specs/capella/light-client/full-node.md), [networking](specs/altair/light-client/p2p-interface.md))
    • [Validator additions](specs/capella/validator.md)
  • [Validator additions](specs/capella/validator.md)
  • [P2P networking](specs/capella/p2p-interface.md)
| +| Capella (tentative) |
  • Core
    • [Beacon chain changes](specs/capella/beacon-chain.md)
    • [Capella fork](specs/capella/fork.md)
  • Additions
    • [Light client sync protocol changes](specs/capella/light-client/sync-protocol.md) ([fork](specs/capella/light-client/fork.md), [full node](specs/capella/light-client/full-node.md), [networking](specs/capella/light-client/p2p-interface.md))
    • [Validator additions](specs/capella/validator.md)
  • [Validator additions](specs/capella/validator.md)
  • [P2P networking](specs/capella/p2p-interface.md)
| | EIP4844 (tentative) |
  • Core
    • [Beacon Chain changes](specs/eip4844/beacon-chain.md)
    • [EIP-4844 fork](specs/eip4844/fork.md)
    • [Polynomial commitments](specs/eip4844/polynomial-commitments.md)
  • Additions
    • [Honest validator guide changes](specs/eip4844/validator.md)
    • [P2P networking](specs/eip4844/p2p-interface.md)
| | Sharding (outdated) |
  • Core
    • [Beacon Chain changes](specs/sharding/beacon-chain.md)
  • Additions
    • [P2P networking](specs/sharding/p2p-interface.md)
| | Custody Game (outdated) |
  • Core
    • [Beacon Chain changes](specs/custody_game/beacon-chain.md)
  • Additions
    • [Honest validator guide changes](specs/custody_game/validator.md)
| Dependent on sharding | From 11d2a5994899fc1513f15da98cefaa45700f2400 Mon Sep 17 00:00:00 2001 From: Etan Kissling Date: Mon, 12 Dec 2022 12:33:58 +0100 Subject: [PATCH 013/158] Flip `is_valid_light_client_header` logic for extensibility --- specs/capella/light-client/sync-protocol.md | 23 +++++++++++---------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/specs/capella/light-client/sync-protocol.md b/specs/capella/light-client/sync-protocol.md index d8bfe3fd1..515b53582 100644 --- a/specs/capella/light-client/sync-protocol.md +++ b/specs/capella/light-client/sync-protocol.md @@ -162,18 +162,19 @@ def get_lc_execution_root(header: LightClientHeader) -> Root: ```python def is_valid_light_client_header(header: LightClientHeader) -> bool: - if compute_epoch_at_slot(get_lc_beacon_slot(header)) >= CAPELLA_FORK_EPOCH: - return is_valid_merkle_branch( - leaf=get_lc_execution_root(header), - branch=header.execution_branch, - depth=floorlog2(EXECUTION_PAYLOAD_INDEX), - index=get_subtree_index(EXECUTION_PAYLOAD_INDEX), - root=header.beacon.body_root, - ) + if compute_epoch_at_slot(get_lc_beacon_slot(header)) < CAPELLA_FORK_EPOCH: + if header.execution != ExecutionPayloadHeader(): + return False - return ( - header.execution == ExecutionPayloadHeader() - and header.execution_branch == [Bytes32() for _ in range(floorlog2(EXECUTION_PAYLOAD_INDEX))] + if header.execution_branch != [Bytes32() for _ in range(floorlog2(EXECUTION_PAYLOAD_INDEX))]: + return False + + return is_valid_merkle_branch( + leaf=get_lc_execution_root(header), + branch=header.execution_branch, + depth=floorlog2(EXECUTION_PAYLOAD_INDEX), + index=get_subtree_index(EXECUTION_PAYLOAD_INDEX), + root=header.beacon.body_root, ) ``` From d6da56cc195699babbe325b3f6093487d358aba5 Mon Sep 17 00:00:00 2001 From: Etan Kissling Date: Mon, 12 Dec 2022 12:37:57 +0100 Subject: [PATCH 014/158] Remove double mention of validator changes in readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 7c9713a47..d7b6595d6 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,7 @@ Features are researched and developed in parallel, and then consolidated into se ### In-development Specifications | Code Name or Topic | Specs | Notes | | - | - | - | -| Capella (tentative) |
  • Core
    • [Beacon chain changes](specs/capella/beacon-chain.md)
    • [Capella fork](specs/capella/fork.md)
  • Additions
    • [Light client sync protocol changes](specs/capella/light-client/sync-protocol.md) ([fork](specs/capella/light-client/fork.md), [full node](specs/capella/light-client/full-node.md), [networking](specs/capella/light-client/p2p-interface.md))
    • [Validator additions](specs/capella/validator.md)
  • [Validator additions](specs/capella/validator.md)
  • [P2P networking](specs/capella/p2p-interface.md)
| +| Capella (tentative) |
  • Core
    • [Beacon chain changes](specs/capella/beacon-chain.md)
    • [Capella fork](specs/capella/fork.md)
  • Additions
    • [Light client sync protocol changes](specs/capella/light-client/sync-protocol.md) ([fork](specs/capella/light-client/fork.md), [full node](specs/capella/light-client/full-node.md), [networking](specs/capella/light-client/p2p-interface.md))
    • [Validator additions](specs/capella/validator.md)
    • [P2P networking](specs/capella/p2p-interface.md)
| | EIP4844 (tentative) |
  • Core
    • [Beacon Chain changes](specs/eip4844/beacon-chain.md)
    • [EIP-4844 fork](specs/eip4844/fork.md)
    • [Polynomial commitments](specs/eip4844/polynomial-commitments.md)
  • Additions
    • [Honest validator guide changes](specs/eip4844/validator.md)
    • [P2P networking](specs/eip4844/p2p-interface.md)
| | Sharding (outdated) |
  • Core
    • [Beacon Chain changes](specs/sharding/beacon-chain.md)
  • Additions
    • [P2P networking](specs/sharding/p2p-interface.md)
| | Custody Game (outdated) |
  • Core
    • [Beacon Chain changes](specs/custody_game/beacon-chain.md)
  • Additions
    • [Honest validator guide changes](specs/custody_game/validator.md)
| Dependent on sharding | From 5028a806ad9f07822df2bc6a5be4796943f013ef Mon Sep 17 00:00:00 2001 From: Etan Kissling Date: Mon, 12 Dec 2022 12:45:43 +0100 Subject: [PATCH 015/158] Implicit init during fork transition --- specs/capella/light-client/fork.md | 1 - 1 file changed, 1 deletion(-) diff --git a/specs/capella/light-client/fork.md b/specs/capella/light-client/fork.md index 700f736c2..ee2102b22 100644 --- a/specs/capella/light-client/fork.md +++ b/specs/capella/light-client/fork.md @@ -25,7 +25,6 @@ A Capella `LightClientStore` can still process earlier light client data. In ord def upgrade_lc_header_to_capella(pre: BeaconBlockHeader) -> LightClientHeader: return LightClientHeader( beacon=pre, - execution=ExecutionPayloadHeader(), ) ``` From 4df86632b6c56f10cab8934e444e9fb16fea653b Mon Sep 17 00:00:00 2001 From: Etan Kissling Date: Mon, 12 Dec 2022 12:56:34 +0100 Subject: [PATCH 016/158] Rename `legacy` --> `altair` in test name --- .../core/pyspec/eth2spec/test/altair/light_client/test_sync.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/core/pyspec/eth2spec/test/altair/light_client/test_sync.py b/tests/core/pyspec/eth2spec/test/altair/light_client/test_sync.py index 53215670a..31bee9dd6 100644 --- a/tests/core/pyspec/eth2spec/test/altair/light_client/test_sync.py +++ b/tests/core/pyspec/eth2spec/test/altair/light_client/test_sync.py @@ -704,7 +704,7 @@ def test_capella_fork(spec, phases, state): @with_state @with_matching_spec_config(emitted_fork=CAPELLA) @with_presets([MINIMAL], reason="too slow") -def test_capella_store_with_legacy_data(spec, phases, state): +def test_capella_store_with_altair_data(spec, phases, state): # Start test (Altair bootstrap but with a Capella store) test = yield from setup_test(spec, state, s_spec=phases[CAPELLA], phases=phases) From e67ca3d3098c476139ee4149442f0dc0e6761af9 Mon Sep 17 00:00:00 2001 From: Etan Kissling Date: Mon, 12 Dec 2022 13:09:18 +0100 Subject: [PATCH 017/158] Compute epoch only once for better readability --- specs/capella/light-client/full-node.md | 4 +++- specs/capella/light-client/sync-protocol.md | 8 ++++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/specs/capella/light-client/full-node.md b/specs/capella/light-client/full-node.md index 104853f8e..6a2104a38 100644 --- a/specs/capella/light-client/full-node.md +++ b/specs/capella/light-client/full-node.md @@ -34,7 +34,9 @@ def compute_merkle_proof_for_block_body(body: BeaconBlockBody, ```python def block_to_light_client_header(block: SignedBeaconBlock) -> LightClientHeader: - if compute_epoch_at_slot(block.message.slot) >= CAPELLA_FORK_EPOCH: + epoch = compute_epoch_at_slot(block.message.slot) + + if epoch >= CAPELLA_FORK_EPOCH: payload = block.message.body.execution_payload execution_header = ExecutionPayloadHeader( parent_hash=payload.parent_hash, diff --git a/specs/capella/light-client/sync-protocol.md b/specs/capella/light-client/sync-protocol.md index 515b53582..060dea1b9 100644 --- a/specs/capella/light-client/sync-protocol.md +++ b/specs/capella/light-client/sync-protocol.md @@ -152,7 +152,9 @@ def get_lc_beacon_root(header: LightClientHeader) -> Root: ```python def get_lc_execution_root(header: LightClientHeader) -> Root: - if compute_epoch_at_slot(get_lc_beacon_slot(header)) >= CAPELLA_FORK_EPOCH: + epoch = compute_epoch_at_slot(get_lc_beacon_slot(header)) + + if epoch >= CAPELLA_FORK_EPOCH: return hash_tree_root(header.execution) return Root() @@ -162,7 +164,9 @@ def get_lc_execution_root(header: LightClientHeader) -> Root: ```python def is_valid_light_client_header(header: LightClientHeader) -> bool: - if compute_epoch_at_slot(get_lc_beacon_slot(header)) < CAPELLA_FORK_EPOCH: + epoch = compute_epoch_at_slot(get_lc_beacon_slot(header)) + + if epoch < CAPELLA_FORK_EPOCH: if header.execution != ExecutionPayloadHeader(): return False From 8ad6810a44d86ca57fb37053cc299164d074795b Mon Sep 17 00:00:00 2001 From: Etan Kissling Date: Mon, 12 Dec 2022 13:11:49 +0100 Subject: [PATCH 018/158] EIP4844 support (`excess_data_gas`), fork tests nyi --- Makefile | 2 +- README.md | 2 +- setup.py | 4 + specs/eip4844/light-client/fork.md | 110 ++++++++++++++++++++ specs/eip4844/light-client/full-node.md | 70 +++++++++++++ specs/eip4844/light-client/p2p-interface.md | 105 +++++++++++++++++++ specs/eip4844/light-client/sync-protocol.md | 88 ++++++++++++++++ 7 files changed, 379 insertions(+), 2 deletions(-) create mode 100644 specs/eip4844/light-client/fork.md create mode 100644 specs/eip4844/light-client/full-node.md create mode 100644 specs/eip4844/light-client/p2p-interface.md create mode 100644 specs/eip4844/light-client/sync-protocol.md diff --git a/Makefile b/Makefile index 728656cb6..f99f2ae9b 100644 --- a/Makefile +++ b/Makefile @@ -30,7 +30,7 @@ MARKDOWN_FILES = $(wildcard $(SPEC_DIR)/phase0/*.md) \ $(wildcard $(SPEC_DIR)/custody/*.md) \ $(wildcard $(SPEC_DIR)/das/*.md) \ $(wildcard $(SPEC_DIR)/sharding/*.md) \ - $(wildcard $(SPEC_DIR)/eip4844/*.md) \ + $(wildcard $(SPEC_DIR)/eip4844/*.md) $(wildcard $(SPEC_DIR)/eip4844/**/*.md) \ $(wildcard $(SSZ_DIR)/*.md) COV_HTML_OUT=.htmlcov diff --git a/README.md b/README.md index d7b6595d6..0827e06a4 100644 --- a/README.md +++ b/README.md @@ -25,7 +25,7 @@ Features are researched and developed in parallel, and then consolidated into se | Code Name or Topic | Specs | Notes | | - | - | - | | Capella (tentative) |
  • Core
    • [Beacon chain changes](specs/capella/beacon-chain.md)
    • [Capella fork](specs/capella/fork.md)
  • Additions
    • [Light client sync protocol changes](specs/capella/light-client/sync-protocol.md) ([fork](specs/capella/light-client/fork.md), [full node](specs/capella/light-client/full-node.md), [networking](specs/capella/light-client/p2p-interface.md))
    • [Validator additions](specs/capella/validator.md)
    • [P2P networking](specs/capella/p2p-interface.md)
| -| EIP4844 (tentative) |
  • Core
    • [Beacon Chain changes](specs/eip4844/beacon-chain.md)
    • [EIP-4844 fork](specs/eip4844/fork.md)
    • [Polynomial commitments](specs/eip4844/polynomial-commitments.md)
  • Additions
    • [Honest validator guide changes](specs/eip4844/validator.md)
    • [P2P networking](specs/eip4844/p2p-interface.md)
| +| EIP4844 (tentative) |
  • Core
    • [Beacon Chain changes](specs/eip4844/beacon-chain.md)
    • [EIP-4844 fork](specs/eip4844/fork.md)
    • [Polynomial commitments](specs/eip4844/polynomial-commitments.md)
  • Additions
    • [Light client sync protocol changes](specs/eip4844/light-client/sync-protocol.md) ([fork](specs/eip4844/light-client/fork.md), [full node](specs/eip4844/light-client/full-node.md), [networking](specs/eip4844/light-client/p2p-interface.md))
    • [Honest validator guide changes](specs/eip4844/validator.md)
    • [P2P networking](specs/eip4844/p2p-interface.md)
| | Sharding (outdated) |
  • Core
    • [Beacon Chain changes](specs/sharding/beacon-chain.md)
  • Additions
    • [P2P networking](specs/sharding/p2p-interface.md)
| | Custody Game (outdated) |
  • Core
    • [Beacon Chain changes](specs/custody_game/beacon-chain.md)
  • Additions
    • [Honest validator guide changes](specs/custody_game/validator.md)
| Dependent on sharding | | Data Availability Sampling (outdated) |
  • Core
    • [Core types and functions](specs/das/das-core.md)
    • [Fork choice changes](specs/das/fork-choice.md)
  • Additions
    • [P2P Networking](specs/das/p2p-interface.md)
    • [Sampling process](specs/das/sampling.md)
|
  • Dependent on sharding
  • [Technical explainer](https://hackmd.io/@HWeNw8hNRimMm2m2GH56Cw/B1YJPGkpD)
| diff --git a/setup.py b/setup.py index db0ad0cfc..83a2e71f3 100644 --- a/setup.py +++ b/setup.py @@ -1038,6 +1038,10 @@ class PySpecCommand(Command): """ if self.spec_fork == EIP4844: self.md_doc_paths += """ + specs/eip4844/light-client/fork.md + specs/eip4844/light-client/full-node.md + specs/eip4844/light-client/p2p-interface.md + specs/eip4844/light-client/sync-protocol.md specs/eip4844/beacon-chain.md specs/eip4844/fork.md specs/eip4844/polynomial-commitments.md diff --git a/specs/eip4844/light-client/fork.md b/specs/eip4844/light-client/fork.md new file mode 100644 index 000000000..2d5f74f46 --- /dev/null +++ b/specs/eip4844/light-client/fork.md @@ -0,0 +1,110 @@ +# EIP4844 Light Client -- Fork Logic + +## Table of contents + + + + + +- [Introduction](#introduction) + - [Upgrading light client data](#upgrading-light-client-data) + - [Upgrading the store](#upgrading-the-store) + + + + +## Introduction + +This document describes how to upgrade existing light client objects based on the [Capella specification](../../capella/light-client/sync-protocol.md) to EIP4844. This is necessary when processing pre-EIP4844 data with a post-EIP4844 `LightClientStore`. Note that the data being exchanged over the network protocols uses the original format. + +### Upgrading light client data + +A EIP4844 `LightClientStore` can still process earlier light client data. In order to do so, that pre-EIP4844 data needs to be locally upgraded to EIP4844 before processing. + +```python +def upgrade_lc_header_to_eip4844(pre: capella.LightClientHeader) -> LightClientHeader: + return LightClientHeader( + beacon=pre.beacon, + execution=ExecutionPayloadHeader( + parent_hash=pre.execution.parent_hash, + fee_recipient=pre.execution.fee_recipient, + state_root=pre.execution.state_root, + receipts_root=pre.execution.receipts_root, + logs_bloom=pre.execution.logs_bloom, + prev_randao=pre.execution.prev_randao, + block_number=pre.execution.block_number, + gas_limit=pre.execution.gas_limit, + gas_used=pre.execution.gas_used, + timestamp=pre.execution.timestamp, + extra_data=pre.execution.extra_data, + base_fee_per_gas=pre.execution.base_fee_per_gas, + block_hash=pre.execution.block_hash, + transactions_root=pre.execution.transactions_root, + withdrawals_root=pre.execution.withdrawals_root, + ), + execution_branch=pre.execution_branch, + ) +``` + +```python +def upgrade_lc_bootstrap_to_eip4844(pre: capella.LightClientBootstrap) -> LightClientBootstrap: + return LightClientBootstrap( + header=upgrade_lc_header_to_eip4844(pre.header), + current_sync_committee=pre.current_sync_committee, + current_sync_committee_branch=pre.current_sync_committee_branch, + ) +``` + +```python +def upgrade_lc_update_to_eip4844(pre: capella.LightClientUpdate) -> LightClientUpdate: + return LightClientUpdate( + attested_header=upgrade_lc_header_to_eip4844(pre.attested_header), + next_sync_committee=pre.next_sync_committee, + next_sync_committee_branch=pre.next_sync_committee_branch, + finalized_header=upgrade_lc_header_to_eip4844(pre.finalized_header), + finality_branch=pre.finality_branch, + sync_aggregate=pre.sync_aggregate, + signature_slot=pre.signature_slot, + ) +``` + +```python +def upgrade_lc_finality_update_to_eip4844(pre: capella.LightClientFinalityUpdate) -> LightClientFinalityUpdate: + return LightClientFinalityUpdate( + attested_header=upgrade_lc_header_to_eip4844(pre.attested_header), + finalized_header=upgrade_lc_header_to_eip4844(pre.finalized_header), + finality_branch=pre.finality_branch, + sync_aggregate=pre.sync_aggregate, + signature_slot=pre.signature_slot, + ) +``` + +```python +def upgrade_lc_optimistic_update_to_eip4844(pre: capella.LightClientOptimisticUpdate) -> LightClientOptimisticUpdate: + return LightClientOptimisticUpdate( + attested_header=upgrade_lc_header_to_eip4844(pre.attested_header), + sync_aggregate=pre.sync_aggregate, + signature_slot=pre.signature_slot, + ) +``` + +### Upgrading the store + +Existing `LightClientStore` objects based on Capella MUST be upgraded to EIP4844 before EIP4844 based light client data can be processed. The `LightClientStore` upgrade MAY be performed before `EIP4844_FORK_EPOCH`. + +```python +def upgrade_lc_store_to_eip4844(pre: capella.LightClientStore) -> LightClientStore: + if pre.best_valid_update is None: + best_valid_update = None + else: + best_valid_update = upgrade_lc_update_to_eip4844(pre.best_valid_update) + return LightClientStore( + finalized_header=upgrade_lc_header_to_eip4844(pre.finalized_header), + current_sync_committee=pre.current_sync_committee, + next_sync_committee=pre.next_sync_committee, + best_valid_update=best_valid_update, + optimistic_header=upgrade_lc_header_to_eip4844(pre.optimistic_header), + previous_max_active_participants=pre.previous_max_active_participants, + current_max_active_participants=pre.current_max_active_participants, + ) +``` diff --git a/specs/eip4844/light-client/full-node.md b/specs/eip4844/light-client/full-node.md new file mode 100644 index 000000000..e9d7340f6 --- /dev/null +++ b/specs/eip4844/light-client/full-node.md @@ -0,0 +1,70 @@ +# EIP4844 Light Client -- Full Node + +**Notice**: This document is a work-in-progress for researchers and implementers. + +## Table of contents + + + + + +- [Introduction](#introduction) +- [Helper functions](#helper-functions) + - [Modified `block_to_light_client_header`](#modified-block_to_light_client_header) + + + + +## Introduction + +This upgrade adds information about the execution payload to light client data as part of the EIP4844 upgrade. + +## Helper functions + +### Modified `block_to_light_client_header` + +```python +def block_to_light_client_header(block: SignedBeaconBlock) -> LightClientHeader: + epoch = compute_epoch_at_slot(block.message.slot) + + if epoch >= CAPELLA_FORK_EPOCH: + payload = block.message.body.execution_payload + execution_header = ExecutionPayloadHeader( + parent_hash=payload.parent_hash, + fee_recipient=payload.fee_recipient, + state_root=payload.state_root, + receipts_root=payload.receipts_root, + logs_bloom=payload.logs_bloom, + prev_randao=payload.prev_randao, + block_number=payload.block_number, + gas_limit=payload.gas_limit, + gas_used=payload.gas_used, + timestamp=payload.timestamp, + extra_data=payload.extra_data, + base_fee_per_gas=payload.base_fee_per_gas, + block_hash=payload.block_hash, + transactions_root=hash_tree_root(payload.transactions), + withdrawals_root=hash_tree_root(payload.withdrawals), + ) + + # [New in EIP4844] + if epoch >= EIP4844_FORK_EPOCH: + execution_header.excess_data_gas = payload.excess_data_gas + + execution_branch = compute_merkle_proof_for_block_body(block.message.body, EXECUTION_PAYLOAD_INDEX) + else: + execution_header = ExecutionPayloadHeader() + execution_branch = [Bytes32() for _ in range(floorlog2(EXECUTION_PAYLOAD_INDEX))] + + return LightClientHeader( + beacon=BeaconBlockHeader( + slot=block.message.slot, + proposer_index=block.message.proposer_index, + parent_root=block.message.parent_root, + state_root=block.message.state_root, + body_root=hash_tree_root(block.message.body), + ), + execution=execution_header, + execution_branch=execution_branch, + ) +``` diff --git a/specs/eip4844/light-client/p2p-interface.md b/specs/eip4844/light-client/p2p-interface.md new file mode 100644 index 000000000..f3d89c130 --- /dev/null +++ b/specs/eip4844/light-client/p2p-interface.md @@ -0,0 +1,105 @@ +# EIP4844 Light Client -- Networking + +**Notice**: This document is a work-in-progress for researchers and implementers. + +## Table of contents + + + + + +- [Networking](#networking) + - [The gossip domain: gossipsub](#the-gossip-domain-gossipsub) + - [Topics and messages](#topics-and-messages) + - [Global topics](#global-topics) + - [`light_client_finality_update`](#light_client_finality_update) + - [`light_client_optimistic_update`](#light_client_optimistic_update) + - [The Req/Resp domain](#the-reqresp-domain) + - [Messages](#messages) + - [GetLightClientBootstrap](#getlightclientbootstrap) + - [LightClientUpdatesByRange](#lightclientupdatesbyrange) + - [GetLightClientFinalityUpdate](#getlightclientfinalityupdate) + - [GetLightClientOptimisticUpdate](#getlightclientoptimisticupdate) + + + + +## Networking + +The [Capella light client networking specification](../../capella/light-client/p2p-interface.md) is extended to exchange [EIP4844 light client data](./sync-protocol.md). + +### The gossip domain: gossipsub + +#### Topics and messages + +##### Global topics + +###### `light_client_finality_update` + +[0]: # (eth2spec: skip) + +| `fork_version` | Message SSZ type | +| ------------------------------------------------------ | ------------------------------------- | +| `GENESIS_FORK_VERSION` | n/a | +| `ALTAIR_FORK_VERSION` through `BELLATRIX_FORK_VERSION` | `altair.LightClientFinalityUpdate` | +| `CAPELLA_FORK_VERSION` | `capella.LightClientFinalityUpdate` | +| `EIP4844_FORK_VERSION` and later | `eip4844.LightClientFinalityUpdate` | + +###### `light_client_optimistic_update` + +[0]: # (eth2spec: skip) + +| `fork_version` | Message SSZ type | +| ------------------------------------------------------ | ------------------------------------- | +| `GENESIS_FORK_VERSION` | n/a | +| `ALTAIR_FORK_VERSION` through `BELLATRIX_FORK_VERSION` | `altair.LightClientOptimisticUpdate` | +| `CAPELLA_FORK_VERSION` | `capella.LightClientOptimisticUpdate` | +| `EIP4844_FORK_VERSION` and later | `eip4844.LightClientOptimisticUpdate` | + +### The Req/Resp domain + +#### Messages + +##### GetLightClientBootstrap + +[0]: # (eth2spec: skip) + +| `fork_version` | Response SSZ type | +| ------------------------------------------------------ | ------------------------------------- | +| `GENESIS_FORK_VERSION` | n/a | +| `ALTAIR_FORK_VERSION` through `BELLATRIX_FORK_VERSION` | `altair.LightClientBootstrap` | +| `CAPELLA_FORK_VERSION` | `capella.LightClientBootstrap` | +| `EIP4844_FORK_VERSION` and later | `eip4844.LightClientBootstrap` | + +##### LightClientUpdatesByRange + +[0]: # (eth2spec: skip) + +| `fork_version` | Response chunk SSZ type | +| ------------------------------------------------------ | ------------------------------------- | +| `GENESIS_FORK_VERSION` | n/a | +| `ALTAIR_FORK_VERSION` through `BELLATRIX_FORK_VERSION` | `altair.LightClientUpdate` | +| `CAPELLA_FORK_VERSION` | `capella.LightClientUpdate` | +| `EIP4844_FORK_VERSION` and later | `eip4844.LightClientUpdate` | + +##### GetLightClientFinalityUpdate + +[0]: # (eth2spec: skip) + +| `fork_version` | Response SSZ type | +| ------------------------------------------------------ | ------------------------------------- | +| `GENESIS_FORK_VERSION` | n/a | +| `ALTAIR_FORK_VERSION` through `BELLATRIX_FORK_VERSION` | `altair.LightClientFinalityUpdate` | +| `CAPELLA_FORK_VERSION` | `capella.LightClientFinalityUpdate` | +| `EIP4844_FORK_VERSION` and later | `eip4844.LightClientFinalityUpdate` | + +##### GetLightClientOptimisticUpdate + +[0]: # (eth2spec: skip) + +| `fork_version` | Response SSZ type | +| ------------------------------------------------------ | ------------------------------------- | +| `GENESIS_FORK_VERSION` | n/a | +| `ALTAIR_FORK_VERSION` through `BELLATRIX_FORK_VERSION` | `altair.LightClientOptimisticUpdate` | +| `CAPELLA_FORK_VERSION` | `capella.LightClientOptimisticUpdate` | +| `EIP4844_FORK_VERSION` and later | `eip4844.LightClientOptimisticUpdate` | diff --git a/specs/eip4844/light-client/sync-protocol.md b/specs/eip4844/light-client/sync-protocol.md new file mode 100644 index 000000000..e66b81ea1 --- /dev/null +++ b/specs/eip4844/light-client/sync-protocol.md @@ -0,0 +1,88 @@ +# EIP4844 Light Client -- Sync Protocol + +**Notice**: This document is a work-in-progress for researchers and implementers. + +## Table of contents + + + + + +- [Introduction](#introduction) +- [Helper functions](#helper-functions) + - [Modified `get_lc_execution_root`](#modified-get_lc_execution_root) + - [Modified `is_valid_light_client_header`](#modified-is_valid_light_client_header) + + + + +## Introduction + +This upgrade updates light client data to include the EIP4844 changes to the [`ExecutionPayload`](../beacon-chain.md) structure. It extends the [Capella Light Client specifications](../../capella/light-client/sync-protocol.md). The [fork document](./fork.md) explains how to upgrade existing Capella based deployments to EIP4844. + +Additional documents describes the impact of the upgrade on certain roles: +- [Full node](./full-node.md) +- [Networking](./p2p-interface.md) + +## Helper functions + +### Modified `get_lc_execution_root` + +```python +def get_lc_execution_root(header: LightClientHeader) -> Root: + epoch = compute_epoch_at_slot(get_lc_beacon_slot(header)) + + # [New in EIP4844] + if epoch >= EIP4844_FORK_EPOCH: + return hash_tree_root(header.execution) + + # [Modified in EIP4844] + if epoch >= CAPELLA_FORK_EPOCH: + execution_header = capella.ExecutionPayloadHeader( + parent_hash=header.execution.parent_hash, + fee_recipient=header.execution.fee_recipient, + state_root=header.execution.state_root, + receipts_root=header.execution.receipts_root, + logs_bloom=header.execution.logs_bloom, + prev_randao=header.execution.prev_randao, + block_number=header.execution.block_number, + gas_limit=header.execution.gas_limit, + gas_used=header.execution.gas_used, + timestamp=header.execution.timestamp, + extra_data=header.execution.extra_data, + base_fee_per_gas=header.execution.base_fee_per_gas, + block_hash=header.execution.block_hash, + transactions_root=header.execution.transactions_root, + withdrawals_root=header.execution.withdrawals_root, + ) + return hash_tree_root(execution_header) + + return Root() +``` + +### Modified `is_valid_light_client_header` + +```python +def is_valid_light_client_header(header: LightClientHeader) -> bool: + epoch = compute_epoch_at_slot(get_lc_beacon_slot(header)) + + # [New in EIP4844] + if epoch < EIP4844_FORK_EPOCH: + if header.execution.excess_data_gas != uint256(0): + return False + + if epoch < CAPELLA_FORK_EPOCH: + if header.execution != ExecutionPayloadHeader(): + return False + + if header.execution_branch != [Bytes32() for _ in range(floorlog2(EXECUTION_PAYLOAD_INDEX))]: + return False + + return is_valid_merkle_branch( + leaf=get_lc_execution_root(header), + branch=header.execution_branch, + depth=floorlog2(EXECUTION_PAYLOAD_INDEX), + index=get_subtree_index(EXECUTION_PAYLOAD_INDEX), + root=header.beacon.body_root, + ) +``` From dc05a3f19e34d95f3190f1fffc9edda9dec433e0 Mon Sep 17 00:00:00 2001 From: Etan Kissling Date: Mon, 12 Dec 2022 13:13:25 +0100 Subject: [PATCH 019/158] Rename test back --- .../pyspec/eth2spec/test/altair/light_client/test_sync.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/core/pyspec/eth2spec/test/altair/light_client/test_sync.py b/tests/core/pyspec/eth2spec/test/altair/light_client/test_sync.py index 31bee9dd6..6ac2d250e 100644 --- a/tests/core/pyspec/eth2spec/test/altair/light_client/test_sync.py +++ b/tests/core/pyspec/eth2spec/test/altair/light_client/test_sync.py @@ -704,8 +704,8 @@ def test_capella_fork(spec, phases, state): @with_state @with_matching_spec_config(emitted_fork=CAPELLA) @with_presets([MINIMAL], reason="too slow") -def test_capella_store_with_altair_data(spec, phases, state): - # Start test (Altair bootstrap but with a Capella store) +def test_capella_store_with_legacy_data(spec, phases, state): + # Start test (Legacy bootstrap but with a Capella store) test = yield from setup_test(spec, state, s_spec=phases[CAPELLA], phases=phases) # Initial `LightClientUpdate` (check that it works with Capella store) From 700bef7a45eb479002096383337c7d3c386e8feb Mon Sep 17 00:00:00 2001 From: Etan Kissling Date: Mon, 12 Dec 2022 13:39:14 +0100 Subject: [PATCH 020/158] Fix `is_valid_light_client_header` --- specs/capella/light-client/sync-protocol.md | 9 ++++----- specs/eip4844/light-client/sync-protocol.md | 9 ++++----- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/specs/capella/light-client/sync-protocol.md b/specs/capella/light-client/sync-protocol.md index 060dea1b9..41204331e 100644 --- a/specs/capella/light-client/sync-protocol.md +++ b/specs/capella/light-client/sync-protocol.md @@ -167,11 +167,10 @@ def is_valid_light_client_header(header: LightClientHeader) -> bool: epoch = compute_epoch_at_slot(get_lc_beacon_slot(header)) if epoch < CAPELLA_FORK_EPOCH: - if header.execution != ExecutionPayloadHeader(): - return False - - if header.execution_branch != [Bytes32() for _ in range(floorlog2(EXECUTION_PAYLOAD_INDEX))]: - return False + return ( + header.execution == ExecutionPayloadHeader() + and header.execution_branch == [Bytes32() for _ in range(floorlog2(EXECUTION_PAYLOAD_INDEX))] + ) return is_valid_merkle_branch( leaf=get_lc_execution_root(header), diff --git a/specs/eip4844/light-client/sync-protocol.md b/specs/eip4844/light-client/sync-protocol.md index e66b81ea1..61881bd38 100644 --- a/specs/eip4844/light-client/sync-protocol.md +++ b/specs/eip4844/light-client/sync-protocol.md @@ -72,11 +72,10 @@ def is_valid_light_client_header(header: LightClientHeader) -> bool: return False if epoch < CAPELLA_FORK_EPOCH: - if header.execution != ExecutionPayloadHeader(): - return False - - if header.execution_branch != [Bytes32() for _ in range(floorlog2(EXECUTION_PAYLOAD_INDEX))]: - return False + return ( + header.execution == ExecutionPayloadHeader() + and header.execution_branch == [Bytes32() for _ in range(floorlog2(EXECUTION_PAYLOAD_INDEX))] + ) return is_valid_merkle_branch( leaf=get_lc_execution_root(header), From a8dabc05a8cbd9868b7f4311a6d3979061bf76b8 Mon Sep 17 00:00:00 2001 From: Etan Kissling Date: Mon, 12 Dec 2022 19:08:45 +0100 Subject: [PATCH 021/158] Add `test_eip4844_store_with_legacy_data` (fork test still nyi) --- .../test/altair/light_client/test_sync.py | 132 ++++++++++++------ 1 file changed, 89 insertions(+), 43 deletions(-) diff --git a/tests/core/pyspec/eth2spec/test/altair/light_client/test_sync.py b/tests/core/pyspec/eth2spec/test/altair/light_client/test_sync.py index 6ac2d250e..5f9fc983e 100644 --- a/tests/core/pyspec/eth2spec/test/altair/light_client/test_sync.py +++ b/tests/core/pyspec/eth2spec/test/altair/light_client/test_sync.py @@ -16,7 +16,7 @@ from eth2spec.test.helpers.attestations import ( state_transition_with_full_block, ) from eth2spec.test.helpers.constants import ( - PHASE0, ALTAIR, BELLATRIX, CAPELLA, + PHASE0, ALTAIR, BELLATRIX, CAPELLA, EIP4844, MINIMAL, ALL_PHASES, ) @@ -24,7 +24,7 @@ from eth2spec.test.helpers.fork_transition import ( do_fork, ) from eth2spec.test.helpers.forks import ( - is_post_capella, + is_post_capella, is_post_eip4844, is_post_fork, ) from eth2spec.test.helpers.light_client import ( @@ -53,56 +53,87 @@ def needs_upgrade_to_capella(d_spec, s_spec): return is_post_capella(s_spec) and not is_post_capella(d_spec) -def upgrade_lc_bootstrap_to_store(d_spec, s_spec, data): - if not needs_upgrade_to_capella(d_spec, s_spec): - return data +def needs_upgrade_to_eip4844(d_spec, s_spec): + return is_post_eip4844(s_spec) and not is_post_eip4844(d_spec) - upgraded = s_spec.upgrade_lc_bootstrap_to_capella(data) - assert s_spec.get_lc_beacon_slot(upgraded.header) == d_spec.get_lc_beacon_slot(data.header) - assert s_spec.get_lc_beacon_root(upgraded.header) == d_spec.get_lc_beacon_root(data.header) - assert s_spec.get_lc_execution_root(upgraded.header) == s_spec.Root() + +def check_lc_header_equal(d_spec, s_spec, data, upgraded): + assert s_spec.get_lc_beacon_slot(upgraded) == d_spec.get_lc_beacon_slot(data) + assert s_spec.get_lc_beacon_root(upgraded) == d_spec.get_lc_beacon_root(data) + if is_post_capella(s_spec): + if is_post_capella(d_spec): + assert s_spec.get_lc_execution_root(upgraded) == d_spec.get_lc_execution_root(data) + else: + assert s_spec.get_lc_execution_root(upgraded) == s_spec.Root() + + +def check_lc_bootstrap_equal(d_spec, s_spec, data, upgraded): + check_lc_header_equal(d_spec, s_spec, data.header, upgraded.header) assert upgraded.current_sync_committee == data.current_sync_committee assert upgraded.current_sync_committee_branch == data.current_sync_committee_branch + + +def upgrade_lc_bootstrap_to_store(d_spec, s_spec, data): + upgraded = data + + if needs_upgrade_to_capella(d_spec, s_spec): + upgraded = s_spec.upgrade_lc_bootstrap_to_capella(upgraded) + check_lc_bootstrap_equal(d_spec, s_spec, data, upgraded) + + if needs_upgrade_to_eip4844(d_spec, s_spec): + upgraded = s_spec.upgrade_lc_bootstrap_to_eip4844(upgraded) + check_lc_bootstrap_equal(d_spec, s_spec, data, upgraded) + return upgraded +def check_lc_update_equal(d_spec, s_spec, data, upgraded): + check_lc_header_equal(d_spec, s_spec, data.attested_header, upgraded.attested_header) + assert upgraded.next_sync_committee == data.next_sync_committee + assert upgraded.next_sync_committee_branch == data.next_sync_committee_branch + check_lc_header_equal(d_spec, s_spec, data.finalized_header, upgraded.finalized_header) + assert upgraded.sync_aggregate == data.sync_aggregate + assert upgraded.signature_slot == data.signature_slot + + def upgrade_lc_update_to_store(d_spec, s_spec, data): - if not needs_upgrade_to_capella(d_spec, s_spec): - return data + upgraded = data + + if needs_upgrade_to_capella(d_spec, s_spec): + upgraded = s_spec.upgrade_lc_update_to_capella(upgraded) + check_lc_update_equal(d_spec, s_spec, data, upgraded) + + if needs_upgrade_to_eip4844(d_spec, s_spec): + upgraded = s_spec.upgrade_lc_update_to_eip4844(upgraded) + check_lc_update_equal(d_spec, s_spec, data, upgraded) - upgraded = s_spec.upgrade_lc_update_to_capella(data) - assert s_spec.get_lc_beacon_slot(upgraded.attested_header) == d_spec.get_lc_beacon_slot(data.attested_header) - assert s_spec.get_lc_beacon_root(upgraded.attested_header) == d_spec.get_lc_beacon_root(data.attested_header) - assert s_spec.get_lc_execution_root(upgraded.attested_header) == s_spec.Root() - assert upgraded.next_sync_committee == data.next_sync_committee - assert upgraded.next_sync_committee_branch == data.next_sync_committee_branch - assert s_spec.get_lc_beacon_slot(upgraded.finalized_header) == d_spec.get_lc_beacon_slot(data.finalized_header) - assert s_spec.get_lc_beacon_root(upgraded.finalized_header) == d_spec.get_lc_beacon_root(data.finalized_header) - assert s_spec.get_lc_execution_root(upgraded.finalized_header) == s_spec.Root() - assert upgraded.sync_aggregate == data.sync_aggregate - assert upgraded.signature_slot == data.signature_slot return upgraded -def upgrade_lc_store_to_new_spec(d_spec, s_spec, data): - if not needs_upgrade_to_capella(d_spec, s_spec): - return data - - upgraded = s_spec.upgrade_lc_store_to_capella(data) - assert s_spec.get_lc_beacon_slot(upgraded.finalized_header) == d_spec.get_lc_beacon_slot(data.finalized_header) - assert s_spec.get_lc_beacon_root(upgraded.finalized_header) == d_spec.get_lc_beacon_root(data.finalized_header) - assert s_spec.get_lc_execution_root(upgraded.finalized_header) == s_spec.Root() +def check_lc_store_equal(d_spec, s_spec, data, upgraded): + check_lc_header_equal(d_spec, s_spec, data.finalized_header, upgraded.finalized_header) assert upgraded.current_sync_committee == data.current_sync_committee assert upgraded.next_sync_committee == data.next_sync_committee if upgraded.best_valid_update is None: assert data.best_valid_update is None else: - assert upgraded.best_valid_update == upgrade_lc_update_to_store(d_spec, s_spec, data.best_valid_update) - assert s_spec.get_lc_beacon_slot(upgraded.optimistic_header) == d_spec.get_lc_beacon_slot(data.optimistic_header) - assert s_spec.get_lc_beacon_root(upgraded.optimistic_header) == d_spec.get_lc_beacon_root(data.optimistic_header) - assert s_spec.get_lc_execution_root(upgraded.optimistic_header) == s_spec.Root() + check_lc_update_equal(d_spec, s_spec, data.best_valid_update, upgraded.best_valid_update) + check_lc_header_equal(d_spec, s_spec, data.optimistic_header, upgraded.optimistic_header) assert upgraded.previous_max_active_participants == data.previous_max_active_participants assert upgraded.current_max_active_participants == data.current_max_active_participants + + +def upgrade_lc_store_to_new_spec(d_spec, s_spec, data): + upgraded = data + + if needs_upgrade_to_capella(d_spec, s_spec): + upgraded = s_spec.upgrade_lc_store_to_capella(upgraded) + check_lc_store_equal(d_spec, s_spec, data, upgraded) + + if needs_upgrade_to_eip4844(d_spec, s_spec): + upgraded = s_spec.upgrade_lc_store_to_eip4844(upgraded) + check_lc_store_equal(d_spec, s_spec, data, upgraded) + return upgraded @@ -114,6 +145,8 @@ class LightClientSyncTest(object): def get_store_fork_version(s_spec): + if is_post_eip4844(s_spec): + return s_spec.config.EIP4844_FORK_VERSION if is_post_capella(s_spec): return s_spec.config.CAPELLA_FORK_VERSION return s_spec.config.ALTAIR_FORK_VERSION @@ -699,16 +732,11 @@ def test_capella_fork(spec, phases, state): yield from finish_test(test) -@with_phases(phases=[ALTAIR, BELLATRIX], other_phases=[CAPELLA]) -@spec_test -@with_state -@with_matching_spec_config(emitted_fork=CAPELLA) -@with_presets([MINIMAL], reason="too slow") -def test_capella_store_with_legacy_data(spec, phases, state): - # Start test (Legacy bootstrap but with a Capella store) - test = yield from setup_test(spec, state, s_spec=phases[CAPELLA], phases=phases) +def run_test_upgraded_store_with_legacy_data(spec, state, s_spec, phases): + # Start test (Legacy bootstrap with an upgraded store) + test = yield from setup_test(spec, state, s_spec, phases) - # Initial `LightClientUpdate` (check that it works with Capella store) + # Initial `LightClientUpdate` (check that the upgraded store can process it) finalized_block = spec.SignedBeaconBlock() finalized_block.message.state_root = state.hash_tree_root() finalized_state = state.copy() @@ -724,3 +752,21 @@ def test_capella_store_with_legacy_data(spec, phases, state): # Finish test yield from finish_test(test) + + +@with_phases(phases=[ALTAIR, BELLATRIX], other_phases=[CAPELLA]) +@spec_test +@with_state +@with_matching_spec_config(emitted_fork=CAPELLA) +@with_presets([MINIMAL], reason="too slow") +def test_capella_store_with_legacy_data(spec, phases, state): + yield from run_test_upgraded_store_with_legacy_data(spec, state, phases[CAPELLA], phases) + + +@with_phases(phases=[ALTAIR, BELLATRIX, CAPELLA], other_phases=[EIP4844]) +@spec_test +@with_state +@with_matching_spec_config(emitted_fork=EIP4844) +@with_presets([MINIMAL], reason="too slow") +def test_eip4844_store_with_legacy_data(spec, phases, state): + yield from run_test_upgraded_store_with_legacy_data(spec, state, phases[EIP4844], phases) From ef2a8b319d963bbe00976a366ac7ded2ea3fcb12 Mon Sep 17 00:00:00 2001 From: Etan Kissling Date: Tue, 13 Dec 2022 12:30:14 +0100 Subject: [PATCH 022/158] Avoid line continuation syntax --- specs/altair/light-client/full-node.md | 8 ++++---- .../altair/light_client/test_single_merkle_proof.py | 12 ++++++------ .../pyspec/eth2spec/test/helpers/light_client.py | 12 ++++++------ 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/specs/altair/light-client/full-node.md b/specs/altair/light-client/full-node.md index 2dd2ded6c..7f0b7bc39 100644 --- a/specs/altair/light-client/full-node.md +++ b/specs/altair/light-client/full-node.md @@ -118,8 +118,8 @@ def create_light_client_update(state: BeaconState, # `next_sync_committee` is only useful if the message is signed by the current sync committee if update_attested_period == update_signature_period: update.next_sync_committee = attested_state.next_sync_committee - update.next_sync_committee_branch = \ - compute_merkle_proof_for_state(attested_state, NEXT_SYNC_COMMITTEE_INDEX) + update.next_sync_committee_branch = compute_merkle_proof_for_state( + attested_state, NEXT_SYNC_COMMITTEE_INDEX) # Indicate finality whenever possible if finalized_block is not None: @@ -128,8 +128,8 @@ def create_light_client_update(state: BeaconState, assert hash_tree_root(update.finalized_header) == attested_state.finalized_checkpoint.root else: assert attested_state.finalized_checkpoint.root == Bytes32() - update.finality_branch = \ - compute_merkle_proof_for_state(attested_state, FINALIZED_ROOT_INDEX) + update.finality_branch = compute_merkle_proof_for_state( + attested_state, FINALIZED_ROOT_INDEX) update.sync_aggregate = block.message.body.sync_aggregate update.signature_slot = block.message.slot diff --git a/tests/core/pyspec/eth2spec/test/altair/light_client/test_single_merkle_proof.py b/tests/core/pyspec/eth2spec/test/altair/light_client/test_single_merkle_proof.py index 465fa629f..5d802bbb3 100644 --- a/tests/core/pyspec/eth2spec/test/altair/light_client/test_single_merkle_proof.py +++ b/tests/core/pyspec/eth2spec/test/altair/light_client/test_single_merkle_proof.py @@ -10,8 +10,8 @@ from eth2spec.test.context import ( @spec_state_test def test_current_sync_committee_merkle_proof(spec, state): yield "object", state - current_sync_committee_branch = \ - spec.compute_merkle_proof_for_state(state, spec.CURRENT_SYNC_COMMITTEE_INDEX) + current_sync_committee_branch = spec.compute_merkle_proof_for_state( + state, spec.CURRENT_SYNC_COMMITTEE_INDEX) yield "proof", { "leaf": "0x" + state.current_sync_committee.hash_tree_root().hex(), "leaf_index": spec.CURRENT_SYNC_COMMITTEE_INDEX, @@ -31,8 +31,8 @@ def test_current_sync_committee_merkle_proof(spec, state): @spec_state_test def test_next_sync_committee_merkle_proof(spec, state): yield "object", state - next_sync_committee_branch = \ - spec.compute_merkle_proof_for_state(state, spec.NEXT_SYNC_COMMITTEE_INDEX) + next_sync_committee_branch = spec.compute_merkle_proof_for_state( + state, spec.NEXT_SYNC_COMMITTEE_INDEX) yield "proof", { "leaf": "0x" + state.next_sync_committee.hash_tree_root().hex(), "leaf_index": spec.NEXT_SYNC_COMMITTEE_INDEX, @@ -52,8 +52,8 @@ def test_next_sync_committee_merkle_proof(spec, state): @spec_state_test def test_finality_root_merkle_proof(spec, state): yield "object", state - finality_branch = \ - spec.compute_merkle_proof_for_state(state, spec.FINALIZED_ROOT_INDEX) + finality_branch = spec.compute_merkle_proof_for_state( + state, spec.FINALIZED_ROOT_INDEX) yield "proof", { "leaf": "0x" + state.finalized_checkpoint.root.hex(), "leaf_index": spec.FINALIZED_ROOT_INDEX, diff --git a/tests/core/pyspec/eth2spec/test/helpers/light_client.py b/tests/core/pyspec/eth2spec/test/helpers/light_client.py index 39175a352..215d174fc 100644 --- a/tests/core/pyspec/eth2spec/test/helpers/light_client.py +++ b/tests/core/pyspec/eth2spec/test/helpers/light_client.py @@ -56,15 +56,15 @@ def create_update(spec, if with_next: update.next_sync_committee = attested_state.next_sync_committee - update.next_sync_committee_branch = \ - spec.compute_merkle_proof_for_state(attested_state, spec.NEXT_SYNC_COMMITTEE_INDEX) + update.next_sync_committee_branch = spec.compute_merkle_proof_for_state( + attested_state, spec.NEXT_SYNC_COMMITTEE_INDEX) if with_finality: update.finalized_header = spec.block_to_light_client_header(finalized_block) - update.finality_branch = \ - spec.compute_merkle_proof_for_state(attested_state, spec.FINALIZED_ROOT_INDEX) + update.finality_branch = spec.compute_merkle_proof_for_state( + attested_state, spec.FINALIZED_ROOT_INDEX) - update.sync_aggregate, update.signature_slot = \ - get_sync_aggregate(spec, attested_state, num_participants) + update.sync_aggregate, update.signature_slot = get_sync_aggregate( + spec, attested_state, num_participants) return update From c84862bfaee574f4fa2fa8ad8334ff2c707144aa Mon Sep 17 00:00:00 2001 From: Etan Kissling Date: Tue, 13 Dec 2022 12:34:14 +0100 Subject: [PATCH 023/158] Avoid line continuation syntax --- tests/core/pyspec/eth2spec/test/context.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/core/pyspec/eth2spec/test/context.py b/tests/core/pyspec/eth2spec/test/context.py index 4bddaba1c..39b889901 100644 --- a/tests/core/pyspec/eth2spec/test/context.py +++ b/tests/core/pyspec/eth2spec/test/context.py @@ -611,8 +611,8 @@ def with_config_overrides(config_overrides, emitted_fork=None, emit=True): if 'phases' in kw: phases = {} for fork in kw['phases']: - phases[fork], output = \ - spec_with_config_overrides(_get_copy_of_spec(kw['phases'][fork]), config_overrides) + phases[fork], output = spec_with_config_overrides( + _get_copy_of_spec(kw['phases'][fork]), config_overrides) if emitted_fork == fork: output_config = output kw['phases'] = phases From 84592f101b0113f9c5be339eadb15d56128dd3ca Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Fri, 16 Dec 2022 00:49:14 +0800 Subject: [PATCH 024/158] Add tests for `process_historical_batches_update` --- setup.py | 1 + specs/capella/beacon-chain.md | 42 +++++++++++++++++-- .../test/capella/epoch_processing/__init__.py | 0 .../test_process_historical_batches_update.py | 27 ++++++++++++ .../test/eip4844/epoch_processing/__init__.py | 0 .../test_process_historical_batches_update.py | 23 ++++++++++ .../eth2spec/test/helpers/epoch_processing.py | 10 ++++- .../test_process_historical_roots_update.py | 8 +++- .../test/phase0/sanity/test_blocks.py | 22 ++++++++-- .../eth2spec/test/phase0/sanity/test_slots.py | 33 +++++++++++++++ tests/generators/epoch_processing/main.py | 14 ++++--- 11 files changed, 163 insertions(+), 17 deletions(-) create mode 100644 tests/core/pyspec/eth2spec/test/capella/epoch_processing/__init__.py create mode 100644 tests/core/pyspec/eth2spec/test/capella/epoch_processing/test_process_historical_batches_update.py create mode 100644 tests/core/pyspec/eth2spec/test/eip4844/epoch_processing/__init__.py create mode 100644 tests/core/pyspec/eth2spec/test/eip4844/epoch_processing/test_process_historical_batches_update.py diff --git a/setup.py b/setup.py index be8be6d90..b2f2ac8e3 100644 --- a/setup.py +++ b/setup.py @@ -660,6 +660,7 @@ def get_empty_list_result(fn): # type: ignore process_withdrawals = no_op(process_withdrawals) process_bls_to_execution_change = no_op(process_bls_to_execution_change) get_expected_withdrawals = get_empty_list_result(get_expected_withdrawals) +process_historical_batches_update = no_op(process_historical_batches_update) # diff --git a/specs/capella/beacon-chain.md b/specs/capella/beacon-chain.md index 8dfb96b9f..baa06398d 100644 --- a/specs/capella/beacon-chain.md +++ b/specs/capella/beacon-chain.md @@ -30,6 +30,8 @@ - [`is_fully_withdrawable_validator`](#is_fully_withdrawable_validator) - [`is_partially_withdrawable_validator`](#is_partially_withdrawable_validator) - [Beacon chain state transition function](#beacon-chain-state-transition-function) + - [Epoch processing](#epoch-processing) + - [Historical batches updates](#historical-batches-updates) - [Block processing](#block-processing) - [New `get_expected_withdrawals`](#new-get_expected_withdrawals) - [New `process_withdrawals`](#new-process_withdrawals) @@ -209,7 +211,7 @@ class BeaconState(Container): latest_block_header: BeaconBlockHeader block_roots: Vector[Root, SLOTS_PER_HISTORICAL_ROOT] state_roots: Vector[Root, SLOTS_PER_HISTORICAL_ROOT] - historical_roots: List[Root, HISTORICAL_ROOTS_LIMIT] # Frozen in Merge, replaced by historical_batches + historical_roots: List[Root, HISTORICAL_ROOTS_LIMIT] # Frozen in Merge, replaced by historical_batches # Eth1 eth1_data: Eth1Data eth1_data_votes: List[Eth1Data, EPOCHS_PER_ETH1_VOTING_PERIOD * SLOTS_PER_EPOCH] @@ -239,8 +241,8 @@ class BeaconState(Container): # Withdrawals next_withdrawal_index: WithdrawalIndex # [New in Capella] next_withdrawal_validator_index: ValidatorIndex # [New in Capella] - # Deep history - historical_batches: List[HistoricalBatchSummary, HISTORICAL_ROOTS_LIMIT] # Valid from Merge onwards + # Deep history valid from Capella onwards + historical_batches: List[HistoricalBatchSummary, HISTORICAL_ROOTS_LIMIT] # [New in Capella] ``` ## Helpers @@ -285,6 +287,40 @@ def is_partially_withdrawable_validator(validator: Validator, balance: Gwei) -> ## Beacon chain state transition function +### Epoch processing + +*Note*: The function `process_historical_batches_update` replaces `process_historical_roots_update` in Bellatrix. + +```python +def process_epoch(state: BeaconState) -> None: + process_justification_and_finalization(state) + process_inactivity_updates(state) + process_rewards_and_penalties(state) + process_registry_updates(state) + process_slashings(state) + process_eth1_data_reset(state) + process_effective_balance_updates(state) + process_slashings_reset(state) + process_randao_mixes_reset(state) + process_historical_batches_update(state) # [Modified in Capella] + process_participation_flag_updates(state) + process_sync_committee_updates(state) +``` + +#### Historical batches updates + +```python +def process_historical_batches_update(state: BeaconState) -> None: + # Set historical block root accumulator. + next_epoch = Epoch(get_current_epoch(state) + 1) + if next_epoch % (SLOTS_PER_HISTORICAL_ROOT // SLOTS_PER_EPOCH) == 0: + historical_batch = HistoricalBatchSummary( + block_batch_root=hash_tree_root(state.block_roots), + state_batch_root=hash_tree_root(state.state_roots), + ) + state.historical_batches.append(historical_batch) +``` + ### Block processing ```python diff --git a/tests/core/pyspec/eth2spec/test/capella/epoch_processing/__init__.py b/tests/core/pyspec/eth2spec/test/capella/epoch_processing/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/tests/core/pyspec/eth2spec/test/capella/epoch_processing/test_process_historical_batches_update.py b/tests/core/pyspec/eth2spec/test/capella/epoch_processing/test_process_historical_batches_update.py new file mode 100644 index 000000000..ba049272b --- /dev/null +++ b/tests/core/pyspec/eth2spec/test/capella/epoch_processing/test_process_historical_batches_update.py @@ -0,0 +1,27 @@ +from eth2spec.test.context import ( + CAPELLA, + spec_state_test, + with_phases, +) +from eth2spec.test.helpers.epoch_processing import ( + run_epoch_processing_with +) + + +def run_process_historical_batches_update(spec, state): + yield from run_epoch_processing_with(spec, state, 'process_historical_batches_update') + + +@with_phases([CAPELLA]) +@spec_state_test +def test_historical_batches_accumulator(spec, state): + # skip ahead to near the end of the historical batch period (excl block before epoch processing) + state.slot = spec.SLOTS_PER_HISTORICAL_ROOT - 1 + pre_historical_batches = state.historical_batches.copy() + + yield from run_process_historical_batches_update(spec, state) + + assert len(state.historical_batches) == len(pre_historical_batches) + 1 + summary = state.historical_batches[len(state.historical_batches) - 1] + assert summary.block_batch_root == state.block_roots.hash_tree_root() + assert summary.state_batch_root == state.state_roots.hash_tree_root() diff --git a/tests/core/pyspec/eth2spec/test/eip4844/epoch_processing/__init__.py b/tests/core/pyspec/eth2spec/test/eip4844/epoch_processing/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/tests/core/pyspec/eth2spec/test/eip4844/epoch_processing/test_process_historical_batches_update.py b/tests/core/pyspec/eth2spec/test/eip4844/epoch_processing/test_process_historical_batches_update.py new file mode 100644 index 000000000..f6e6f2ce7 --- /dev/null +++ b/tests/core/pyspec/eth2spec/test/eip4844/epoch_processing/test_process_historical_batches_update.py @@ -0,0 +1,23 @@ +from eth2spec.test.context import ( + spec_state_test, + with_eip4844_and_later, +) +from eth2spec.test.helpers.epoch_processing import ( + run_epoch_processing_with +) + + +def run_process_historical_batches_update(spec, state): + yield from run_epoch_processing_with(spec, state, 'process_historical_batches_update') + + +@with_eip4844_and_later +@spec_state_test +def test_no_op(spec, state): + # skip ahead to near the end of the historical batch period (excl block before epoch processing) + state.slot = spec.SLOTS_PER_HISTORICAL_ROOT - 1 + historical_batches_len = len(state.historical_batches) + + yield from run_process_historical_batches_update(spec, state) + + assert len(state.historical_batches) == historical_batches_len diff --git a/tests/core/pyspec/eth2spec/test/helpers/epoch_processing.py b/tests/core/pyspec/eth2spec/test/helpers/epoch_processing.py index ed61f8bdb..399222841 100644 --- a/tests/core/pyspec/eth2spec/test/helpers/epoch_processing.py +++ b/tests/core/pyspec/eth2spec/test/helpers/epoch_processing.py @@ -1,5 +1,8 @@ -from eth2spec.test.helpers.forks import is_post_altair +from eth2spec.test.helpers.forks import ( + is_post_altair, + is_post_capella, +) def get_process_calls(spec): @@ -22,7 +25,10 @@ def get_process_calls(spec): 'process_effective_balance_updates', 'process_slashings_reset', 'process_randao_mixes_reset', - 'process_historical_roots_update', + # Capella replaced `process_historical_roots_update` with `process_historical_batches_update` + 'process_historical_batches_update' if is_post_capella(spec) else ( + 'process_historical_roots_update' + ), # Altair replaced `process_participation_record_updates` with `process_participation_flag_updates` 'process_participation_flag_updates' if is_post_altair(spec) else ( 'process_participation_record_updates' diff --git a/tests/core/pyspec/eth2spec/test/phase0/epoch_processing/test_process_historical_roots_update.py b/tests/core/pyspec/eth2spec/test/phase0/epoch_processing/test_process_historical_roots_update.py index 02ce7ccba..f03d0bd98 100644 --- a/tests/core/pyspec/eth2spec/test/phase0/epoch_processing/test_process_historical_roots_update.py +++ b/tests/core/pyspec/eth2spec/test/phase0/epoch_processing/test_process_historical_roots_update.py @@ -1,4 +1,8 @@ -from eth2spec.test.context import spec_state_test, with_all_phases +from eth2spec.test.context import ( + PHASE0, ALTAIR, BELLATRIX, + spec_state_test, + with_phases, +) from eth2spec.test.helpers.epoch_processing import ( run_epoch_processing_with ) @@ -8,7 +12,7 @@ def run_process_historical_roots_update(spec, state): yield from run_epoch_processing_with(spec, state, 'process_historical_roots_update') -@with_all_phases +@with_phases([PHASE0, ALTAIR, BELLATRIX]) @spec_state_test def test_historical_root_accumulator(spec, state): # skip ahead to near the end of the historical roots period (excl block before epoch processing) diff --git a/tests/core/pyspec/eth2spec/test/phase0/sanity/test_blocks.py b/tests/core/pyspec/eth2spec/test/phase0/sanity/test_blocks.py index 1e9dd2d48..8b35e814f 100644 --- a/tests/core/pyspec/eth2spec/test/phase0/sanity/test_blocks.py +++ b/tests/core/pyspec/eth2spec/test/phase0/sanity/test_blocks.py @@ -29,8 +29,8 @@ from eth2spec.test.helpers.sync_committee import ( compute_committee_indices, compute_sync_committee_participant_reward_and_penalty, ) -from eth2spec.test.helpers.constants import PHASE0, MINIMAL -from eth2spec.test.helpers.forks import is_post_altair, is_post_bellatrix +from eth2spec.test.helpers.constants import PHASE0, EIP4844, MINIMAL +from eth2spec.test.helpers.forks import is_post_altair, is_post_bellatrix, is_post_capella from eth2spec.test.context import ( spec_test, spec_state_test, dump_skipping_message, with_phases, with_all_phases, single_phase, @@ -1026,7 +1026,10 @@ def test_balance_driven_status_transitions(spec, state): @always_bls def test_historical_batch(spec, state): state.slot += spec.SLOTS_PER_HISTORICAL_ROOT - (state.slot % spec.SLOTS_PER_HISTORICAL_ROOT) - 1 - pre_historical_roots_len = len(state.historical_roots) + pre_historical_roots = state.historical_roots.copy() + + if is_post_capella(spec): + pre_historical_batches = state.historical_batches.copy() yield 'pre', state @@ -1038,7 +1041,18 @@ def test_historical_batch(spec, state): assert state.slot == block.slot assert spec.get_current_epoch(state) % (spec.SLOTS_PER_HISTORICAL_ROOT // spec.SLOTS_PER_EPOCH) == 0 - assert len(state.historical_roots) == pre_historical_roots_len + 1 + + # check history update + if is_post_capella(spec): + # Frozen `historical_roots` + assert state.historical_roots == pre_historical_roots + if spec.fork == EIP4844: + # TODO: no-op for now in EIP4844 testnet + assert state.historical_batches == pre_historical_batches + else: + assert len(state.historical_batches) == len(pre_historical_batches) + 1 + else: + assert len(state.historical_roots) == len(pre_historical_roots) + 1 @with_all_phases diff --git a/tests/core/pyspec/eth2spec/test/phase0/sanity/test_slots.py b/tests/core/pyspec/eth2spec/test/phase0/sanity/test_slots.py index 3fa57f0f1..0010898f8 100644 --- a/tests/core/pyspec/eth2spec/test/phase0/sanity/test_slots.py +++ b/tests/core/pyspec/eth2spec/test/phase0/sanity/test_slots.py @@ -1,3 +1,9 @@ +from eth2spec.test.helpers.constants import ( + EIP4844, +) +from eth2spec.test.helpers.forks import ( + is_post_capella, +) from eth2spec.test.helpers.state import get_state_root from eth2spec.test.context import ( spec_state_test, @@ -61,3 +67,30 @@ def test_over_epoch_boundary(spec, state): yield 'slots', int(slots) spec.process_slots(state, state.slot + slots) yield 'post', state + + +@with_all_phases +@spec_state_test +def test_historical_accumulator(spec, state): + pre_historical_roots = state.historical_roots.copy() + + if is_post_capella(spec): + pre_historical_batches = state.historical_batches.copy() + + yield 'pre', state + slots = spec.SLOTS_PER_HISTORICAL_ROOT + yield 'slots', int(slots) + spec.process_slots(state, state.slot + slots) + yield 'post', state + + # check history update + if is_post_capella(spec): + # Frozen `historical_roots` + assert state.historical_roots == pre_historical_roots + if spec.fork == EIP4844: + # TODO: no-op for now in EIP4844 testnet + assert state.historical_batches == pre_historical_batches + else: + assert len(state.historical_batches) == len(pre_historical_batches) + 1 + else: + assert len(state.historical_roots) == len(pre_historical_roots) + 1 diff --git a/tests/generators/epoch_processing/main.py b/tests/generators/epoch_processing/main.py index 84421e749..f8430bc7e 100644 --- a/tests/generators/epoch_processing/main.py +++ b/tests/generators/epoch_processing/main.py @@ -27,13 +27,15 @@ if __name__ == "__main__": # so no additional tests required. bellatrix_mods = altair_mods - # No epoch-processing changes in Capella and previous testing repeats with new types, - # so no additional tests required. - capella_mods = bellatrix_mods + _new_capella_mods = {key: 'eth2spec.test.capella.epoch_processing.test_process_' + key for key in [ + 'historical_batches_update', + ]} + capella_mods = combine_mods(_new_capella_mods, bellatrix_mods) - # No epoch-processing changes in EIP4844 and previous testing repeats with new types, - # so no additional tests required. - eip4844_mods = capella_mods + _new_eip4844_mods = {key: 'eth2spec.test.eip4844.epoch_processing.test_process_' + key for key in [ + 'historical_batches_update', + ]} + eip4844_mods = combine_mods(_new_eip4844_mods, capella_mods) # TODO Custody Game testgen is disabled for now # custody_game_mods = {**{key: 'eth2spec.test.custody_game.epoch_processing.test_process_' + key for key in [ From b6ac1fa099b074e6566d221775df73d3a39dcd52 Mon Sep 17 00:00:00 2001 From: Jacek Sieka Date: Tue, 20 Dec 2022 07:46:18 +0100 Subject: [PATCH 025/158] Update specs/capella/beacon-chain.md Co-authored-by: Danny Ryan --- specs/capella/beacon-chain.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/specs/capella/beacon-chain.md b/specs/capella/beacon-chain.md index baa06398d..e869d0e5f 100644 --- a/specs/capella/beacon-chain.md +++ b/specs/capella/beacon-chain.md @@ -211,7 +211,7 @@ class BeaconState(Container): latest_block_header: BeaconBlockHeader block_roots: Vector[Root, SLOTS_PER_HISTORICAL_ROOT] state_roots: Vector[Root, SLOTS_PER_HISTORICAL_ROOT] - historical_roots: List[Root, HISTORICAL_ROOTS_LIMIT] # Frozen in Merge, replaced by historical_batches + historical_roots: List[Root, HISTORICAL_ROOTS_LIMIT] # Frozen in Capella, replaced by historical_batches # Eth1 eth1_data: Eth1Data eth1_data_votes: List[Eth1Data, EPOCHS_PER_ETH1_VOTING_PERIOD * SLOTS_PER_EPOCH] From 5a75704e37304f02e611dcc9b9cee3607a76f2a2 Mon Sep 17 00:00:00 2001 From: terence tsao Date: Fri, 23 Dec 2022 14:02:33 +0800 Subject: [PATCH 026/158] Clarify behavior for empty blobs sidecar --- specs/eip4844/p2p-interface.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/specs/eip4844/p2p-interface.md b/specs/eip4844/p2p-interface.md index 420a6da05..2ab39ea09 100644 --- a/specs/eip4844/p2p-interface.md +++ b/specs/eip4844/p2p-interface.md @@ -226,6 +226,8 @@ The request MUST be encoded as an SSZ-container. The response MUST consist of zero or more `response_chunk`. Each _successful_ `response_chunk` MUST contain a single `BlobsSidecar` payload. +In cases where a slot contains empty blob, no `blobs_sidecar` is returned. + Clients MUST keep a record of signed blobs sidecars seen on the epoch range `[max(current_epoch - MIN_EPOCHS_FOR_BLOBS_SIDECARS_REQUESTS, EIP4844_FORK_EPOCH), current_epoch]` where `current_epoch` is defined by the current wall-clock time, @@ -247,6 +249,8 @@ disconnect and/or temporarily ban such an un-synced or semi-synced client. Clients MUST respond with at least the first blobs sidecar that exists in the range, if they have it, and no more than `MAX_REQUEST_BLOBS_SIDECARS` sidecars. +Clients MUST not respond with empty blobs sidecars. + The following blobs sidecars, where they exist, MUST be sent in consecutive order. Clients MAY limit the number of blobs sidecars in the response. From 42121adeb062a5f2bf9118720dc6c74c6caa61f1 Mon Sep 17 00:00:00 2001 From: terence tsao Date: Fri, 23 Dec 2022 14:30:30 +0800 Subject: [PATCH 027/158] Clarify what empty means --- specs/eip4844/p2p-interface.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/specs/eip4844/p2p-interface.md b/specs/eip4844/p2p-interface.md index 2ab39ea09..3acfe6500 100644 --- a/specs/eip4844/p2p-interface.md +++ b/specs/eip4844/p2p-interface.md @@ -226,7 +226,7 @@ The request MUST be encoded as an SSZ-container. The response MUST consist of zero or more `response_chunk`. Each _successful_ `response_chunk` MUST contain a single `BlobsSidecar` payload. -In cases where a slot contains empty blob, no `blobs_sidecar` is returned. +In cases where a slot contains a `BlobSidecar` that does not contain any blobs, but contain non-zero `beacon_block_root` and `beacon_block_slot`, no `blobs_sidecar` is returned. Clients MUST keep a record of signed blobs sidecars seen on the epoch range `[max(current_epoch - MIN_EPOCHS_FOR_BLOBS_SIDECARS_REQUESTS, EIP4844_FORK_EPOCH), current_epoch]` From 518c49bbbabe4ddaa0d4cf1d6cc44bedd3598164 Mon Sep 17 00:00:00 2001 From: terencechain Date: Fri, 23 Dec 2022 20:47:14 +0800 Subject: [PATCH 028/158] Update specs/eip4844/p2p-interface.md Co-authored-by: g11tech --- specs/eip4844/p2p-interface.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/specs/eip4844/p2p-interface.md b/specs/eip4844/p2p-interface.md index 3acfe6500..b01304ec8 100644 --- a/specs/eip4844/p2p-interface.md +++ b/specs/eip4844/p2p-interface.md @@ -226,7 +226,7 @@ The request MUST be encoded as an SSZ-container. The response MUST consist of zero or more `response_chunk`. Each _successful_ `response_chunk` MUST contain a single `BlobsSidecar` payload. -In cases where a slot contains a `BlobSidecar` that does not contain any blobs, but contain non-zero `beacon_block_root` and `beacon_block_slot`, no `blobs_sidecar` is returned. +In cases where a slot contains a `BlobSidecar` that does not contain any blobs, but contain non-zero `beacon_block_root` and `beacon_block_slot`, `blobs_sidecar` **may be** skipped. Clients MUST keep a record of signed blobs sidecars seen on the epoch range `[max(current_epoch - MIN_EPOCHS_FOR_BLOBS_SIDECARS_REQUESTS, EIP4844_FORK_EPOCH), current_epoch]` From 491bb1d20778edd70cdac818f8ce392f5b73fcdf Mon Sep 17 00:00:00 2001 From: terence tsao Date: Fri, 23 Dec 2022 22:21:51 +0800 Subject: [PATCH 029/158] Clean ups --- specs/eip4844/p2p-interface.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/specs/eip4844/p2p-interface.md b/specs/eip4844/p2p-interface.md index 3acfe6500..06a763404 100644 --- a/specs/eip4844/p2p-interface.md +++ b/specs/eip4844/p2p-interface.md @@ -226,7 +226,7 @@ The request MUST be encoded as an SSZ-container. The response MUST consist of zero or more `response_chunk`. Each _successful_ `response_chunk` MUST contain a single `BlobsSidecar` payload. -In cases where a slot contains a `BlobSidecar` that does not contain any blobs, but contain non-zero `beacon_block_root` and `beacon_block_slot`, no `blobs_sidecar` is returned. +In cases where a slot contains a `BlobSidecar` that does not contain any blobs, but contain non-zero `beacon_block_root`, `beacon_block_slot` and a valid `kzg_aggregated_proof`, `blobs_sidecar` MAY be skipped. Clients MUST keep a record of signed blobs sidecars seen on the epoch range `[max(current_epoch - MIN_EPOCHS_FOR_BLOBS_SIDECARS_REQUESTS, EIP4844_FORK_EPOCH), current_epoch]` @@ -249,7 +249,7 @@ disconnect and/or temporarily ban such an un-synced or semi-synced client. Clients MUST respond with at least the first blobs sidecar that exists in the range, if they have it, and no more than `MAX_REQUEST_BLOBS_SIDECARS` sidecars. -Clients MUST not respond with empty blobs sidecars. +Clients MAY skip to respond empty blobs sidecars. The following blobs sidecars, where they exist, MUST be sent in consecutive order. From 45b1eb79799afc1e94a81ee3b1d0a1792410d0dd Mon Sep 17 00:00:00 2001 From: terence tsao Date: Wed, 28 Dec 2022 18:42:24 -0800 Subject: [PATCH 030/158] EIP4844: Enable withdrawal --- specs/eip4844/beacon-chain.md | 8 -------- 1 file changed, 8 deletions(-) diff --git a/specs/eip4844/beacon-chain.md b/specs/eip4844/beacon-chain.md index 19acb57d8..afab3fc44 100644 --- a/specs/eip4844/beacon-chain.md +++ b/specs/eip4844/beacon-chain.md @@ -346,11 +346,3 @@ def initialize_beacon_state_from_eth1(eth1_block_hash: Hash32, return state ``` - -### Disabling Withdrawals - -During testing we avoid Capella-specific updates to the state transition. We do this by replacing the following functions with a no-op implementation: -- `process_withdrawals` -- `process_bls_to_execution_change` - -The `get_expected_withdrawals` function is also modified to return an empty withdrawals list. As such, the `PayloadAttributes` used to update forkchoice does not contain withdrawals. From 2afb02ba302254b8a991dc1575bee045c7f5e86f Mon Sep 17 00:00:00 2001 From: terence tsao Date: Wed, 28 Dec 2022 18:49:02 -0800 Subject: [PATCH 031/158] Fix Toc --- specs/eip4844/beacon-chain.md | 1 - 1 file changed, 1 deletion(-) diff --git a/specs/eip4844/beacon-chain.md b/specs/eip4844/beacon-chain.md index afab3fc44..bc5c41a5c 100644 --- a/specs/eip4844/beacon-chain.md +++ b/specs/eip4844/beacon-chain.md @@ -33,7 +33,6 @@ - [`process_execution_payload`](#process_execution_payload) - [Blob KZG commitments](#blob-kzg-commitments) - [Testing](#testing) - - [Disabling Withdrawals](#disabling-withdrawals) From 4c573ff6b96e693a343370903110e7cb3348407c Mon Sep 17 00:00:00 2001 From: Dankrad Feist Date: Sat, 17 Dec 2022 17:14:48 +0000 Subject: [PATCH 032/158] Add compute_kzg_proof to public methods --- specs/eip4844/polynomial-commitments.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/specs/eip4844/polynomial-commitments.md b/specs/eip4844/polynomial-commitments.md index 6aef9c611..8884457ed 100644 --- a/specs/eip4844/polynomial-commitments.md +++ b/specs/eip4844/polynomial-commitments.md @@ -370,8 +370,9 @@ def verify_kzg_proof_impl(polynomial_kzg: KZGCommitment, ```python def compute_kzg_proof(polynomial: Polynomial, z: BLSFieldElement) -> KZGProof: """ - Compute KZG proof at point `z` with `polynomial` being in evaluation form - Do this by computing the quotient polynomial in evaluation form: q(x) = (p(x) - p(z)) / (x - z) + Compute KZG proof at point `z` with `polynomial` being in evaluation form. + Do this by computing the quotient polynomial in evaluation form: q(x) = (p(x) - p(z)) / (x - z). + Public method. """ y = evaluate_polynomial_in_evaluation_form(polynomial, z) polynomial_shifted = [BLSFieldElement((int(p) - int(y)) % BLS_MODULUS) for p in polynomial] From 1cfabcbe54378284319bc6f38c45484b6cefd3fb Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Mon, 2 Jan 2023 23:07:00 +0800 Subject: [PATCH 033/158] Rename `HistoricalBatchSummary` -> `HistoricalSummary` and `historical_batches` -> `historical_summaries` --- setup.py | 2 +- specs/capella/beacon-chain.md | 26 +++++++++---------- .../test_process_historical_batches_update.py | 14 +++++----- .../test_process_historical_batches_update.py | 10 +++---- .../eth2spec/test/helpers/epoch_processing.py | 4 +-- .../test/phase0/sanity/test_blocks.py | 6 ++--- .../eth2spec/test/phase0/sanity/test_slots.py | 6 ++--- tests/generators/epoch_processing/main.py | 4 +-- 8 files changed, 36 insertions(+), 36 deletions(-) diff --git a/setup.py b/setup.py index b2f2ac8e3..f95f85284 100644 --- a/setup.py +++ b/setup.py @@ -660,7 +660,7 @@ def get_empty_list_result(fn): # type: ignore process_withdrawals = no_op(process_withdrawals) process_bls_to_execution_change = no_op(process_bls_to_execution_change) get_expected_withdrawals = get_empty_list_result(get_expected_withdrawals) -process_historical_batches_update = no_op(process_historical_batches_update) +process_historical_summaries_update = no_op(process_historical_summaries_update) # diff --git a/specs/capella/beacon-chain.md b/specs/capella/beacon-chain.md index e869d0e5f..5d322ca92 100644 --- a/specs/capella/beacon-chain.md +++ b/specs/capella/beacon-chain.md @@ -18,7 +18,7 @@ - [`Withdrawal`](#withdrawal) - [`BLSToExecutionChange`](#blstoexecutionchange) - [`SignedBLSToExecutionChange`](#signedblstoexecutionchange) - - [`HistoricalBatchSummary`](#historicalbatchsummary) + - [`HistoricalSummary`](#historicalsummary) - [Extended Containers](#extended-containers) - [`ExecutionPayload`](#executionpayload) - [`ExecutionPayloadHeader`](#executionpayloadheader) @@ -31,7 +31,7 @@ - [`is_partially_withdrawable_validator`](#is_partially_withdrawable_validator) - [Beacon chain state transition function](#beacon-chain-state-transition-function) - [Epoch processing](#epoch-processing) - - [Historical batches updates](#historical-batches-updates) + - [Historical summaries updates](#historical-summaries-updates) - [Block processing](#block-processing) - [New `get_expected_withdrawals`](#new-get_expected_withdrawals) - [New `process_withdrawals`](#new-process_withdrawals) @@ -118,12 +118,12 @@ class SignedBLSToExecutionChange(Container): signature: BLSSignature ``` -#### `HistoricalBatchSummary` +#### `HistoricalSummary` ```python -class HistoricalBatchSummary(Container): +class HistoricalSummary(Container): """ - `HistoricalBatchSummary` matches the components of the phase0 HistoricalBatch + `HistoricalSummary` matches the components of the phase0 `HistoricalBatch` making the two hash_tree_root-compatible. """ block_batch_root: Root @@ -211,7 +211,7 @@ class BeaconState(Container): latest_block_header: BeaconBlockHeader block_roots: Vector[Root, SLOTS_PER_HISTORICAL_ROOT] state_roots: Vector[Root, SLOTS_PER_HISTORICAL_ROOT] - historical_roots: List[Root, HISTORICAL_ROOTS_LIMIT] # Frozen in Capella, replaced by historical_batches + historical_roots: List[Root, HISTORICAL_ROOTS_LIMIT] # Frozen in Capella, replaced by historical_summaries # Eth1 eth1_data: Eth1Data eth1_data_votes: List[Eth1Data, EPOCHS_PER_ETH1_VOTING_PERIOD * SLOTS_PER_EPOCH] @@ -242,7 +242,7 @@ class BeaconState(Container): next_withdrawal_index: WithdrawalIndex # [New in Capella] next_withdrawal_validator_index: ValidatorIndex # [New in Capella] # Deep history valid from Capella onwards - historical_batches: List[HistoricalBatchSummary, HISTORICAL_ROOTS_LIMIT] # [New in Capella] + historical_summaries: List[HistoricalSummary, HISTORICAL_ROOTS_LIMIT] # [New in Capella] ``` ## Helpers @@ -289,7 +289,7 @@ def is_partially_withdrawable_validator(validator: Validator, balance: Gwei) -> ### Epoch processing -*Note*: The function `process_historical_batches_update` replaces `process_historical_roots_update` in Bellatrix. +*Note*: The function `process_historical_summaries_update` replaces `process_historical_roots_update` in Bellatrix. ```python def process_epoch(state: BeaconState) -> None: @@ -302,23 +302,23 @@ def process_epoch(state: BeaconState) -> None: process_effective_balance_updates(state) process_slashings_reset(state) process_randao_mixes_reset(state) - process_historical_batches_update(state) # [Modified in Capella] + process_historical_summaries_update(state) # [Modified in Capella] process_participation_flag_updates(state) process_sync_committee_updates(state) ``` -#### Historical batches updates +#### Historical summaries updates ```python -def process_historical_batches_update(state: BeaconState) -> None: +def process_historical_summaries_update(state: BeaconState) -> None: # Set historical block root accumulator. next_epoch = Epoch(get_current_epoch(state) + 1) if next_epoch % (SLOTS_PER_HISTORICAL_ROOT // SLOTS_PER_EPOCH) == 0: - historical_batch = HistoricalBatchSummary( + historical_summary = HistoricalSummary( block_batch_root=hash_tree_root(state.block_roots), state_batch_root=hash_tree_root(state.state_roots), ) - state.historical_batches.append(historical_batch) + state.historical_summaries.append(historical_summary) ``` ### Block processing diff --git a/tests/core/pyspec/eth2spec/test/capella/epoch_processing/test_process_historical_batches_update.py b/tests/core/pyspec/eth2spec/test/capella/epoch_processing/test_process_historical_batches_update.py index ba049272b..16620b38d 100644 --- a/tests/core/pyspec/eth2spec/test/capella/epoch_processing/test_process_historical_batches_update.py +++ b/tests/core/pyspec/eth2spec/test/capella/epoch_processing/test_process_historical_batches_update.py @@ -8,20 +8,20 @@ from eth2spec.test.helpers.epoch_processing import ( ) -def run_process_historical_batches_update(spec, state): - yield from run_epoch_processing_with(spec, state, 'process_historical_batches_update') +def run_process_historical_summaries_update(spec, state): + yield from run_epoch_processing_with(spec, state, 'process_historical_summaries_update') @with_phases([CAPELLA]) @spec_state_test -def test_historical_batches_accumulator(spec, state): +def test_historical_summaries_accumulator(spec, state): # skip ahead to near the end of the historical batch period (excl block before epoch processing) state.slot = spec.SLOTS_PER_HISTORICAL_ROOT - 1 - pre_historical_batches = state.historical_batches.copy() + pre_historical_summaries = state.historical_summaries.copy() - yield from run_process_historical_batches_update(spec, state) + yield from run_process_historical_summaries_update(spec, state) - assert len(state.historical_batches) == len(pre_historical_batches) + 1 - summary = state.historical_batches[len(state.historical_batches) - 1] + assert len(state.historical_summaries) == len(pre_historical_summaries) + 1 + summary = state.historical_summaries[len(state.historical_summaries) - 1] assert summary.block_batch_root == state.block_roots.hash_tree_root() assert summary.state_batch_root == state.state_roots.hash_tree_root() diff --git a/tests/core/pyspec/eth2spec/test/eip4844/epoch_processing/test_process_historical_batches_update.py b/tests/core/pyspec/eth2spec/test/eip4844/epoch_processing/test_process_historical_batches_update.py index f6e6f2ce7..21865ae38 100644 --- a/tests/core/pyspec/eth2spec/test/eip4844/epoch_processing/test_process_historical_batches_update.py +++ b/tests/core/pyspec/eth2spec/test/eip4844/epoch_processing/test_process_historical_batches_update.py @@ -7,8 +7,8 @@ from eth2spec.test.helpers.epoch_processing import ( ) -def run_process_historical_batches_update(spec, state): - yield from run_epoch_processing_with(spec, state, 'process_historical_batches_update') +def run_process_historical_summaries_update(spec, state): + yield from run_epoch_processing_with(spec, state, 'process_historical_summaries_update') @with_eip4844_and_later @@ -16,8 +16,8 @@ def run_process_historical_batches_update(spec, state): def test_no_op(spec, state): # skip ahead to near the end of the historical batch period (excl block before epoch processing) state.slot = spec.SLOTS_PER_HISTORICAL_ROOT - 1 - historical_batches_len = len(state.historical_batches) + historical_summaries_len = len(state.historical_summaries) - yield from run_process_historical_batches_update(spec, state) + yield from run_process_historical_summaries_update(spec, state) - assert len(state.historical_batches) == historical_batches_len + assert len(state.historical_summaries) == historical_summaries_len diff --git a/tests/core/pyspec/eth2spec/test/helpers/epoch_processing.py b/tests/core/pyspec/eth2spec/test/helpers/epoch_processing.py index 399222841..44b42aff9 100644 --- a/tests/core/pyspec/eth2spec/test/helpers/epoch_processing.py +++ b/tests/core/pyspec/eth2spec/test/helpers/epoch_processing.py @@ -25,8 +25,8 @@ def get_process_calls(spec): 'process_effective_balance_updates', 'process_slashings_reset', 'process_randao_mixes_reset', - # Capella replaced `process_historical_roots_update` with `process_historical_batches_update` - 'process_historical_batches_update' if is_post_capella(spec) else ( + # Capella replaced `process_historical_roots_update` with `process_historical_summaries_update` + 'process_historical_summaries_update' if is_post_capella(spec) else ( 'process_historical_roots_update' ), # Altair replaced `process_participation_record_updates` with `process_participation_flag_updates` diff --git a/tests/core/pyspec/eth2spec/test/phase0/sanity/test_blocks.py b/tests/core/pyspec/eth2spec/test/phase0/sanity/test_blocks.py index 8b35e814f..71c7798a1 100644 --- a/tests/core/pyspec/eth2spec/test/phase0/sanity/test_blocks.py +++ b/tests/core/pyspec/eth2spec/test/phase0/sanity/test_blocks.py @@ -1029,7 +1029,7 @@ def test_historical_batch(spec, state): pre_historical_roots = state.historical_roots.copy() if is_post_capella(spec): - pre_historical_batches = state.historical_batches.copy() + pre_historical_summaries = state.historical_summaries.copy() yield 'pre', state @@ -1048,9 +1048,9 @@ def test_historical_batch(spec, state): assert state.historical_roots == pre_historical_roots if spec.fork == EIP4844: # TODO: no-op for now in EIP4844 testnet - assert state.historical_batches == pre_historical_batches + assert state.historical_summaries == pre_historical_summaries else: - assert len(state.historical_batches) == len(pre_historical_batches) + 1 + assert len(state.historical_summaries) == len(pre_historical_summaries) + 1 else: assert len(state.historical_roots) == len(pre_historical_roots) + 1 diff --git a/tests/core/pyspec/eth2spec/test/phase0/sanity/test_slots.py b/tests/core/pyspec/eth2spec/test/phase0/sanity/test_slots.py index 0010898f8..7b860159a 100644 --- a/tests/core/pyspec/eth2spec/test/phase0/sanity/test_slots.py +++ b/tests/core/pyspec/eth2spec/test/phase0/sanity/test_slots.py @@ -75,7 +75,7 @@ def test_historical_accumulator(spec, state): pre_historical_roots = state.historical_roots.copy() if is_post_capella(spec): - pre_historical_batches = state.historical_batches.copy() + pre_historical_summaries = state.historical_summaries.copy() yield 'pre', state slots = spec.SLOTS_PER_HISTORICAL_ROOT @@ -89,8 +89,8 @@ def test_historical_accumulator(spec, state): assert state.historical_roots == pre_historical_roots if spec.fork == EIP4844: # TODO: no-op for now in EIP4844 testnet - assert state.historical_batches == pre_historical_batches + assert state.historical_summaries == pre_historical_summaries else: - assert len(state.historical_batches) == len(pre_historical_batches) + 1 + assert len(state.historical_summaries) == len(pre_historical_summaries) + 1 else: assert len(state.historical_roots) == len(pre_historical_roots) + 1 diff --git a/tests/generators/epoch_processing/main.py b/tests/generators/epoch_processing/main.py index f8430bc7e..58beb0fd2 100644 --- a/tests/generators/epoch_processing/main.py +++ b/tests/generators/epoch_processing/main.py @@ -28,12 +28,12 @@ if __name__ == "__main__": bellatrix_mods = altair_mods _new_capella_mods = {key: 'eth2spec.test.capella.epoch_processing.test_process_' + key for key in [ - 'historical_batches_update', + 'historical_summaries_update', ]} capella_mods = combine_mods(_new_capella_mods, bellatrix_mods) _new_eip4844_mods = {key: 'eth2spec.test.eip4844.epoch_processing.test_process_' + key for key in [ - 'historical_batches_update', + 'historical_summaries_update', ]} eip4844_mods = combine_mods(_new_eip4844_mods, capella_mods) From dcacb7164f812d1a7161f956615a5123ed266202 Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Tue, 3 Jan 2023 21:50:06 +0800 Subject: [PATCH 034/158] Rename `block_batch_root` to `block_summary_root` and `state_batch_root` to `state_summary_root` --- specs/capella/beacon-chain.md | 8 ++++---- .../test_process_historical_batches_update.py | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/specs/capella/beacon-chain.md b/specs/capella/beacon-chain.md index 5d322ca92..bd7a2c50c 100644 --- a/specs/capella/beacon-chain.md +++ b/specs/capella/beacon-chain.md @@ -126,8 +126,8 @@ class HistoricalSummary(Container): `HistoricalSummary` matches the components of the phase0 `HistoricalBatch` making the two hash_tree_root-compatible. """ - block_batch_root: Root - state_batch_root: Root + block_summary_root: Root + state_summary_root: Root ``` ### Extended Containers @@ -315,8 +315,8 @@ def process_historical_summaries_update(state: BeaconState) -> None: next_epoch = Epoch(get_current_epoch(state) + 1) if next_epoch % (SLOTS_PER_HISTORICAL_ROOT // SLOTS_PER_EPOCH) == 0: historical_summary = HistoricalSummary( - block_batch_root=hash_tree_root(state.block_roots), - state_batch_root=hash_tree_root(state.state_roots), + block_summary_root=hash_tree_root(state.block_roots), + state_summary_root=hash_tree_root(state.state_roots), ) state.historical_summaries.append(historical_summary) ``` diff --git a/tests/core/pyspec/eth2spec/test/capella/epoch_processing/test_process_historical_batches_update.py b/tests/core/pyspec/eth2spec/test/capella/epoch_processing/test_process_historical_batches_update.py index 16620b38d..f1f8292eb 100644 --- a/tests/core/pyspec/eth2spec/test/capella/epoch_processing/test_process_historical_batches_update.py +++ b/tests/core/pyspec/eth2spec/test/capella/epoch_processing/test_process_historical_batches_update.py @@ -23,5 +23,5 @@ def test_historical_summaries_accumulator(spec, state): assert len(state.historical_summaries) == len(pre_historical_summaries) + 1 summary = state.historical_summaries[len(state.historical_summaries) - 1] - assert summary.block_batch_root == state.block_roots.hash_tree_root() - assert summary.state_batch_root == state.state_roots.hash_tree_root() + assert summary.block_summary_root == state.block_roots.hash_tree_root() + assert summary.state_summary_root == state.state_roots.hash_tree_root() From bd26c96a8c7c8000695fbf615170f3251f092252 Mon Sep 17 00:00:00 2001 From: Parithosh Jayanthi Date: Tue, 3 Jan 2023 16:23:09 +0100 Subject: [PATCH 035/158] Adds Github Actions CI (#3028) * Squash commits * Rename TEST_TYPE to TEST_PRESET_TYPE * Try python3 -m pytest -n 16 * updating actions versions * adding cleanup * reorder * Add eip4844 Co-authored-by: Hsiao-Wei Wang --- .github/workflows/run-tests.yml | 133 ++++++++++++++++++++++++++++++++ Makefile | 18 ++--- 2 files changed, 142 insertions(+), 9 deletions(-) create mode 100644 .github/workflows/run-tests.yml diff --git a/.github/workflows/run-tests.yml b/.github/workflows/run-tests.yml new file mode 100644 index 000000000..3e23d1910 --- /dev/null +++ b/.github/workflows/run-tests.yml @@ -0,0 +1,133 @@ +name: Run spec tests and linter + +defaults: + run: + shell: zsh {0} + +env: + TEST_PRESET_TYPE: "minimal" + DEFAULT_BRANCH: "dev" + +# Run tests on workflow_Dispatch +on: + push: + branches: + - dev + - master + pull_request: + workflow_dispatch: + inputs: + test_preset_type: + default: minimal + 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 * * *' + +jobs: + precleanup: + runs-on: self-hosted + if: always() + steps: + - name: 'Cleanup build folder' + run: | + ls -la ./ + rm -rf ./* || true + rm -rf ./.??* || true + ls -la ./ + setup-env: + runs-on: self-hosted + needs: precleanup + steps: + - name: Checkout this repo + uses: actions/checkout@v3.2.0 + with: + ref: ${{ github.event.inputs.commitRef || env.DEFAULT_BRANCH }} + - uses: actions/cache@v3.2.2 + id: cache-git + with: + path: ./* + key: ${{ github.sha }} + + table_of_contents: + runs-on: self-hosted + needs: setup-env + steps: + - uses: actions/cache@v3.2.2 + id: restore-build + with: + path: ./* + key: ${{ github.sha }} + - name: Check table of contents + run: sudo npm install -g doctoc@2 && make check_toc + + codespell: + runs-on: self-hosted + needs: setup-env + steps: + - name: Check codespell + run: pip install 'codespell<3.0.0,>=2.0.0' --user && make codespell + + lint: + runs-on: self-hosted + needs: setup-env + steps: + - name: Run linter for pyspec + run: make lint + - name: Run linter for test generators + run: make lint_generators + + pyspec-tests: + runs-on: self-hosted + needs: [setup-env,lint,codespell,table_of_contents] + strategy: + matrix: + version: ["phase0", "altair", "bellatrix", "capella", "eip4844"] + steps: + - uses: actions/cache@v3.2.2 + id: restore-build + with: + path: ./* + key: ${{ github.sha }} + - name: set TEST_PRESET_TYPE + if: github.event.inputs.test_preset_type != '' + run: | + echo "spec_test_preset_type=${{ github.event.inputs.test_preset_type || env.TEST_PRESET_TYPE }}" >> $GITHUB_ENV + - name: set TEST_PRESET_TYPE + if: ${{ (github.event_name == 'push' && github.ref_name != 'master') || github.event_name == 'pull_request' }} + run: | + echo "spec_test_preset_type=${{ env.TEST_PRESET_TYPE}}" >> $GITHUB_ENV + - name: set TEST_PRESET_TYPE + if: ${{ github.event_name == 'push' && github.ref_name == 'master' }} + run: | + echo "spec_test_preset_type=mainnet" >> $GITHUB_ENV + - name: set TEST_PRESET_TYPE + if: github.event.schedule=='0 0 * * *' + run: | + echo "spec_test_preset_type=mainnet" >> $GITHUB_ENV + - name: Install pyspec requirements + run: make install_test + - name: test-${{ matrix.version }} + run: make citest fork=${{ matrix.version }} TEST_PRESET_TYPE=${{env.spec_test_preset_type}} + - uses: actions/upload-artifact@v3 + if: always() + with: + name: test-${{ matrix.version }} + path: tests/core/pyspec/test-reports + + cleanup: + runs-on: self-hosted + needs: [setup-env,pyspec-tests,codespell,lint,table_of_contents] + if: always() + steps: + - name: 'Cleanup build folder' + run: | + ls -la ./ + rm -rf ./* || true + rm -rf ./.??* || true + ls -la ./ \ No newline at end of file diff --git a/Makefile b/Makefile index 645ed7006..ac769b200 100644 --- a/Makefile +++ b/Makefile @@ -13,7 +13,7 @@ SOLIDITY_DEPOSIT_CONTRACT_SOURCE = ${SOLIDITY_DEPOSIT_CONTRACT_DIR}/deposit_cont SOLIDITY_FILE_NAME = deposit_contract.json DEPOSIT_CONTRACT_TESTER_DIR = ${SOLIDITY_DEPOSIT_CONTRACT_DIR}/web3_tester CONFIGS_DIR = ./configs - +TEST_PRESET_TYPE ?= minimal # Collect a list of generator names GENERATORS = $(sort $(dir $(wildcard $(GENERATOR_DIR)/*/.))) # Map this list of generator paths to "gen_{generator name}" entries @@ -96,30 +96,30 @@ generate_tests: $(GENERATOR_TARGETS) # "make pyspec" to create the pyspec for all phases. pyspec: - . venv/bin/activate; python3 setup.py pyspecdev + python3 -m venv venv; . venv/bin/activate; python3 setup.py pyspecdev # installs the packages to run pyspec tests install_test: python3 -m venv venv; . venv/bin/activate; python3 -m pip install -e .[lint]; python3 -m pip install -e .[test] -# Testing against `minimal` config by default +# Testing against `minimal` or `mainnet` config by default test: pyspec . venv/bin/activate; cd $(PY_SPEC_DIR); \ - python3 -m pytest -n 4 --disable-bls --cov=eth2spec.phase0.minimal --cov=eth2spec.altair.minimal --cov=eth2spec.bellatrix.minimal --cov=eth2spec.capella.minimal --cov=eth2spec.eip4844.minimal --cov-report="html:$(COV_HTML_OUT)" --cov-branch eth2spec + python3 -m pytest -n 4 --disable-bls --cov=eth2spec.phase0.$(TEST_PRESET_TYPE) --cov=eth2spec.altair.$(TEST_PRESET_TYPE) --cov=eth2spec.bellatrix.$(TEST_PRESET_TYPE) --cov=eth2spec.capella.$(TEST_PRESET_TYPE) --cov=eth2spec.eip4844.$(TEST_PRESET_TYPE) --cov-report="html:$(COV_HTML_OUT)" --cov-branch eth2spec -# Testing against `minimal` config by default +# Testing against `minimal` or `mainnet` config by default find_test: pyspec . venv/bin/activate; cd $(PY_SPEC_DIR); \ - python3 -m pytest -k=$(K) --disable-bls --cov=eth2spec.phase0.minimal --cov=eth2spec.altair.minimal --cov=eth2spec.bellatrix.minimal --cov=eth2spec.capella.minimal --cov=eth2spec.eip4844.minimal --cov-report="html:$(COV_HTML_OUT)" --cov-branch eth2spec + python3 -m pytest -k=$(K) --disable-bls --cov=eth2spec.phase0.$(TEST_PRESET_TYPE) --cov=eth2spec.altair.$(TEST_PRESET_TYPE) --cov=eth2spec.bellatrix.$(TEST_PRESET_TYPE) --cov=eth2spec.capella.$(TEST_PRESET_TYPE) --cov=eth2spec.eip4844.$(TEST_PRESET_TYPE) --cov-report="html:$(COV_HTML_OUT)" --cov-branch eth2spec citest: pyspec mkdir -p $(TEST_REPORT_DIR); ifdef fork . venv/bin/activate; cd $(PY_SPEC_DIR); \ - python3 -m pytest -n 4 --bls-type=milagro --fork=$(fork) --junitxml=test-reports/test_results.xml eth2spec + python3 -m pytest -n 16 --bls-type=milagro --preset=$(TEST_PRESET_TYPE) --fork=$(fork) --junitxml=test-reports/test_results.xml eth2spec else . venv/bin/activate; cd $(PY_SPEC_DIR); \ - python3 -m pytest -n 4 --bls-type=milagro --junitxml=test-reports/test_results.xml eth2spec + python3 -m pytest -n 16 --bls-type=milagro --preset=$(TEST_PRESET_TYPE) --junitxml=test-reports/test_results.xml eth2spec endif @@ -135,7 +135,7 @@ check_toc: $(MARKDOWN_FILES:=.toc) rm $*.tmp codespell: - codespell . --skip ./.git -I .codespell-whitelist + codespell . --skip "./.git,./venv,$(PY_SPEC_DIR)/.mypy_cache" -I .codespell-whitelist # TODO: add future protocol upgrade patch packages to linting. # NOTE: we use `pylint` just for catching unused arguments in spec code From 6b94aab3af875d97e8574cbc23d6919b6540a235 Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Tue, 3 Jan 2023 23:28:37 +0800 Subject: [PATCH 036/158] Move `is_data_available` check to fork-choice `on_block` --- specs/eip4844/beacon-chain.md | 28 --------- specs/eip4844/fork-choice.md | 105 ++++++++++++++++++++++++++++++++++ 2 files changed, 105 insertions(+), 28 deletions(-) create mode 100644 specs/eip4844/fork-choice.md diff --git a/specs/eip4844/beacon-chain.md b/specs/eip4844/beacon-chain.md index 19acb57d8..e62c455d6 100644 --- a/specs/eip4844/beacon-chain.md +++ b/specs/eip4844/beacon-chain.md @@ -23,7 +23,6 @@ - [Helper functions](#helper-functions) - [Misc](#misc) - [`validate_blobs_sidecar`](#validate_blobs_sidecar) - - [`is_data_available`](#is_data_available) - [`kzg_commitment_to_versioned_hash`](#kzg_commitment_to_versioned_hash) - [`tx_peek_blob_versioned_hashes`](#tx_peek_blob_versioned_hashes) - [`verify_kzg_commitments_against_transactions`](#verify_kzg_commitments_against_transactions) @@ -162,30 +161,6 @@ def validate_blobs_sidecar(slot: Slot, assert verify_aggregate_kzg_proof(blobs, expected_kzg_commitments, kzg_aggregated_proof) ``` -#### `is_data_available` - -The implementation of `is_data_available` will become more sophisticated during later sharding upgrades. -Initially, it requires every verifying actor to retrieve the matching `BlobsSidecar`, -and validate the sidecar with `validate_blobs_sidecar`. - -The block MUST NOT be considered valid until a valid `BlobsSidecar` has been downloaded. Blocks that have been previously validated as available SHOULD be considered available even if the associated `BlobsSidecar` has subsequently been pruned. - -```python -def is_data_available(slot: Slot, beacon_block_root: Root, blob_kzg_commitments: Sequence[KZGCommitment]) -> bool: - # `retrieve_blobs_sidecar` is implementation and context dependent, raises an exception if not available. - # Note: the p2p network does not guarantee sidecar retrieval outside of `MIN_EPOCHS_FOR_BLOBS_SIDECARS_REQUESTS` - sidecar = retrieve_blobs_sidecar(slot, beacon_block_root) - - # For testing, `retrieve_blobs_sidecar` returns "TEST". - # TODO: Remove it once we have a way to inject `BlobsSidecar` into tests. - if isinstance(sidecar, str): - return True - - validate_blobs_sidecar(slot, beacon_block_root, blob_kzg_commitments, sidecar) - return True -``` - - #### `kzg_commitment_to_versioned_hash` ```python @@ -241,9 +216,6 @@ def process_block(state: BeaconState, block: BeaconBlock) -> None: process_operations(state, block.body) process_sync_aggregate(state, block.body.sync_aggregate) process_blob_kzg_commitments(state, block.body) # [New in EIP-4844] - - # New in EIP-4844 - assert is_data_available(block.slot, hash_tree_root(block), block.body.blob_kzg_commitments) ``` #### Execution payload diff --git a/specs/eip4844/fork-choice.md b/specs/eip4844/fork-choice.md new file mode 100644 index 000000000..bc25eeae7 --- /dev/null +++ b/specs/eip4844/fork-choice.md @@ -0,0 +1,105 @@ +# EIP-4844 -- Fork Choice + +## Table of contents + + + + +- [Introduction](#introduction) +- [Helpers](#helpers) + - [`is_data_available`](#is_data_available) +- [Updated fork-choice handlers](#updated-fork-choice-handlers) + - [`on_block`](#on_block) + + + + +## Introduction + +This is the modification of the fork choice according to the executable beacon chain proposal. + +## Helpers + +#### `is_data_available` + +The implementation of `is_data_available` will become more sophisticated during later sharding upgrades. +Initially, it requires every verifying actor to retrieve the matching `BlobsSidecar`, +and validate the sidecar with `validate_blobs_sidecar`. + +The block MUST NOT be considered valid until a valid `BlobsSidecar` has been downloaded. Blocks that have been previously validated as available SHOULD be considered available even if the associated `BlobsSidecar` has subsequently been pruned. + +```python +def is_data_available(slot: Slot, beacon_block_root: Root, blob_kzg_commitments: Sequence[KZGCommitment]) -> bool: + # `retrieve_blobs_sidecar` is implementation and context dependent, raises an exception if not available. + # Note: the p2p network does not guarantee sidecar retrieval outside of `MIN_EPOCHS_FOR_BLOBS_SIDECARS_REQUESTS` + sidecar = retrieve_blobs_sidecar(slot, beacon_block_root) + + # For testing, `retrieve_blobs_sidecar` returns "TEST". + # TODO: Remove it once we have a way to inject `BlobsSidecar` into tests. + if isinstance(sidecar, str): + return True + + validate_blobs_sidecar(slot, beacon_block_root, blob_kzg_commitments, sidecar) + return True +``` + +## Updated fork-choice handlers + +### `on_block` + +*Note*: The only modification is the addition of the verification of transition block conditions. + +```python +def on_block(store: Store, signed_block: SignedBeaconBlock) -> None: + """ + Run ``on_block`` upon receiving a new block. + """ + block = signed_block.message + # Parent block must be known + assert block.parent_root in store.block_states + # Make a copy of the state to avoid mutability issues + pre_state = copy(store.block_states[block.parent_root]) + # Blocks cannot be in the future. If they are, their consideration must be delayed until they are in the past. + assert get_current_slot(store) >= block.slot + + # Check that block is later than the finalized epoch slot (optimization to reduce calls to get_ancestor) + finalized_slot = compute_start_slot_at_epoch(store.finalized_checkpoint.epoch) + assert block.slot > finalized_slot + # Check block is a descendant of the finalized block at the checkpoint finalized slot + assert get_ancestor(store, block.parent_root, finalized_slot) == store.finalized_checkpoint.root + + # [New in EIP-4844] + # Check if the block is available + assert is_data_available(block.slot, hash_tree_root(block), block.body.blob_kzg_commitments) + + # Check the block is valid and compute the post-state + state = pre_state.copy() + state_transition(state, signed_block, True) + + # Check the merge transition + if is_merge_transition_block(pre_state, block.body): + validate_merge_block(block) + + # Add new block to the store + store.blocks[hash_tree_root(block)] = block + # Add new state for this block to the store + store.block_states[hash_tree_root(block)] = state + + # Add proposer score boost if the block is timely + time_into_slot = (store.time - store.genesis_time) % SECONDS_PER_SLOT + is_before_attesting_interval = time_into_slot < SECONDS_PER_SLOT // INTERVALS_PER_SLOT + if get_current_slot(store) == block.slot and is_before_attesting_interval: + store.proposer_boost_root = hash_tree_root(block) + + # Update justified checkpoint + if state.current_justified_checkpoint.epoch > store.justified_checkpoint.epoch: + if state.current_justified_checkpoint.epoch > store.best_justified_checkpoint.epoch: + store.best_justified_checkpoint = state.current_justified_checkpoint + if should_update_justified_checkpoint(store, state.current_justified_checkpoint): + store.justified_checkpoint = state.current_justified_checkpoint + + # Update finalized checkpoint + if state.finalized_checkpoint.epoch > store.finalized_checkpoint.epoch: + store.finalized_checkpoint = state.finalized_checkpoint + store.justified_checkpoint = state.current_justified_checkpoint +``` From dba75eece9529ad6bc59c11fcb1382c3eed986b5 Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Wed, 4 Jan 2023 00:45:46 +0800 Subject: [PATCH 037/158] Enable Capella feature in eip4844 fork Fix lint --- setup.py | 29 ----- .../test_process_bls_to_execution_change.py | 23 ++-- .../block_processing/test_process_deposit.py | 5 +- .../test_process_withdrawals.py | 110 +++++++++--------- .../test_process_historical_batches_update.py | 5 +- .../test/capella/sanity/test_blocks.py | 21 ++-- .../test/eip4844/block_processing/__init__.py | 0 .../test_process_bls_to_execution_change.py | 40 ------- .../test_process_withdrawals.py | 41 ------- .../test/eip4844/epoch_processing/__init__.py | 0 .../test_process_historical_batches_update.py | 23 ---- .../test/phase0/sanity/test_blocks.py | 8 +- .../eth2spec/test/phase0/sanity/test_slots.py | 9 +- tests/generators/epoch_processing/main.py | 6 +- tests/generators/operations/main.py | 6 +- 15 files changed, 86 insertions(+), 240 deletions(-) delete mode 100644 tests/core/pyspec/eth2spec/test/eip4844/block_processing/__init__.py delete mode 100644 tests/core/pyspec/eth2spec/test/eip4844/block_processing/test_process_bls_to_execution_change.py delete mode 100644 tests/core/pyspec/eth2spec/test/eip4844/block_processing/test_process_withdrawals.py delete mode 100644 tests/core/pyspec/eth2spec/test/eip4844/epoch_processing/__init__.py delete mode 100644 tests/core/pyspec/eth2spec/test/eip4844/epoch_processing/test_process_historical_batches_update.py diff --git a/setup.py b/setup.py index f95f85284..83c7e857e 100644 --- a/setup.py +++ b/setup.py @@ -638,35 +638,6 @@ T = TypeVar('T') # For generic function @classmethod def sundry_functions(cls) -> str: return super().sundry_functions() + '\n\n' + ''' -# -# Temporarily disable Withdrawals functions for EIP4844 testnets -# - - -def no_op(fn): # type: ignore - # pylint: disable=unused-argument - def wrapper(*args, **kw): # type: ignore - return None - return wrapper - - -def get_empty_list_result(fn): # type: ignore - # pylint: disable=unused-argument - def wrapper(*args, **kw): # type: ignore - return [] - return wrapper - - -process_withdrawals = no_op(process_withdrawals) -process_bls_to_execution_change = no_op(process_bls_to_execution_change) -get_expected_withdrawals = get_empty_list_result(get_expected_withdrawals) -process_historical_summaries_update = no_op(process_historical_summaries_update) - - -# -# End -# - def retrieve_blobs_sidecar(slot: Slot, beacon_block_root: Root) -> PyUnion[BlobsSidecar, str]: # pylint: disable=unused-argument return "TEST"''' diff --git a/tests/core/pyspec/eth2spec/test/capella/block_processing/test_process_bls_to_execution_change.py b/tests/core/pyspec/eth2spec/test/capella/block_processing/test_process_bls_to_execution_change.py index 6a1ba5b36..094de5eeb 100644 --- a/tests/core/pyspec/eth2spec/test/capella/block_processing/test_process_bls_to_execution_change.py +++ b/tests/core/pyspec/eth2spec/test/capella/block_processing/test_process_bls_to_execution_change.py @@ -1,8 +1,7 @@ -from eth2spec.test.helpers.constants import CAPELLA from eth2spec.test.helpers.keys import pubkeys from eth2spec.test.helpers.bls_to_execution_changes import get_signed_address_change -from eth2spec.test.context import spec_state_test, expect_assertion_error, with_phases, always_bls +from eth2spec.test.context import spec_state_test, expect_assertion_error, with_capella_and_later, always_bls def run_bls_to_execution_change_processing(spec, state, signed_address_change, valid=True): @@ -38,14 +37,14 @@ def run_bls_to_execution_change_processing(spec, state, signed_address_change, v yield 'post', state -@with_phases([CAPELLA]) +@with_capella_and_later @spec_state_test def test_success(spec, state): signed_address_change = get_signed_address_change(spec, state) yield from run_bls_to_execution_change_processing(spec, state, signed_address_change) -@with_phases([CAPELLA]) +@with_capella_and_later @spec_state_test def test_success_not_activated(spec, state): validator_index = 3 @@ -63,7 +62,7 @@ def test_success_not_activated(spec, state): assert not spec.is_fully_withdrawable_validator(validator, balance, spec.get_current_epoch(state)) -@with_phases([CAPELLA]) +@with_capella_and_later @spec_state_test def test_success_in_activation_queue(spec, state): validator_index = 3 @@ -81,7 +80,7 @@ def test_success_in_activation_queue(spec, state): assert not spec.is_fully_withdrawable_validator(validator, balance, spec.get_current_epoch(state)) -@with_phases([CAPELLA]) +@with_capella_and_later @spec_state_test def test_success_in_exit_queue(spec, state): validator_index = 3 @@ -94,7 +93,7 @@ def test_success_in_exit_queue(spec, state): yield from run_bls_to_execution_change_processing(spec, state, signed_address_change) -@with_phases([CAPELLA]) +@with_capella_and_later @spec_state_test def test_success_exited(spec, state): validator_index = 4 @@ -111,7 +110,7 @@ def test_success_exited(spec, state): assert not spec.is_fully_withdrawable_validator(validator, balance, spec.get_current_epoch(state)) -@with_phases([CAPELLA]) +@with_capella_and_later @spec_state_test def test_success_withdrawable(spec, state): validator_index = 4 @@ -129,7 +128,7 @@ def test_success_withdrawable(spec, state): assert spec.is_fully_withdrawable_validator(validator, balance, spec.get_current_epoch(state)) -@with_phases([CAPELLA]) +@with_capella_and_later @spec_state_test def test_invalid_val_index_out_of_range(spec, state): # Create for one validator beyond the validator list length @@ -138,7 +137,7 @@ def test_invalid_val_index_out_of_range(spec, state): yield from run_bls_to_execution_change_processing(spec, state, signed_address_change, valid=False) -@with_phases([CAPELLA]) +@with_capella_and_later @spec_state_test def test_invalid_already_0x01(spec, state): # Create for one validator beyond the validator list length @@ -150,7 +149,7 @@ def test_invalid_already_0x01(spec, state): yield from run_bls_to_execution_change_processing(spec, state, signed_address_change, valid=False) -@with_phases([CAPELLA]) +@with_capella_and_later @spec_state_test def test_invalid_incorrect_from_bls_pubkey(spec, state): # Create for one validator beyond the validator list length @@ -164,7 +163,7 @@ def test_invalid_incorrect_from_bls_pubkey(spec, state): yield from run_bls_to_execution_change_processing(spec, state, signed_address_change, valid=False) -@with_phases([CAPELLA]) +@with_capella_and_later @spec_state_test @always_bls def test_invalid_bad_signature(spec, state): diff --git a/tests/core/pyspec/eth2spec/test/capella/block_processing/test_process_deposit.py b/tests/core/pyspec/eth2spec/test/capella/block_processing/test_process_deposit.py index 685d17651..e0603d301 100644 --- a/tests/core/pyspec/eth2spec/test/capella/block_processing/test_process_deposit.py +++ b/tests/core/pyspec/eth2spec/test/capella/block_processing/test_process_deposit.py @@ -1,8 +1,7 @@ from eth2spec.test.context import ( spec_state_test, - with_phases, + with_capella_and_later, ) -from eth2spec.test.helpers.constants import CAPELLA from eth2spec.test.helpers.state import next_epoch_via_block from eth2spec.test.helpers.deposits import ( prepare_state_and_deposit, @@ -11,7 +10,7 @@ from eth2spec.test.helpers.deposits import ( from eth2spec.test.helpers.withdrawals import set_validator_fully_withdrawable -@with_phases([CAPELLA]) +@with_capella_and_later @spec_state_test def test_success_top_up_to_withdrawn_validator(spec, state): validator_index = 0 diff --git a/tests/core/pyspec/eth2spec/test/capella/block_processing/test_process_withdrawals.py b/tests/core/pyspec/eth2spec/test/capella/block_processing/test_process_withdrawals.py index fa3806d2c..674231096 100644 --- a/tests/core/pyspec/eth2spec/test/capella/block_processing/test_process_withdrawals.py +++ b/tests/core/pyspec/eth2spec/test/capella/block_processing/test_process_withdrawals.py @@ -4,9 +4,9 @@ from eth2spec.test.context import ( spec_state_test, expect_assertion_error, with_presets, - with_phases, + with_capella_and_later, ) -from eth2spec.test.helpers.constants import MAINNET, MINIMAL, CAPELLA +from eth2spec.test.helpers.constants import MAINNET, MINIMAL from eth2spec.test.helpers.execution_payload import ( build_empty_execution_payload, compute_el_block_hash, @@ -97,7 +97,7 @@ def run_withdrawals_processing(spec, state, execution_payload, num_expected_with return expected_withdrawals -@with_phases([CAPELLA]) +@with_capella_and_later @spec_state_test def test_success_zero_expected_withdrawals(spec, state): assert len(spec.get_expected_withdrawals(state)) == 0 @@ -108,7 +108,7 @@ def test_success_zero_expected_withdrawals(spec, state): yield from run_withdrawals_processing(spec, state, execution_payload) -@with_phases([CAPELLA]) +@with_capella_and_later @spec_state_test def test_success_one_full_withdrawal(spec, state): fully_withdrawable_indices, partial_withdrawals_indices = prepare_expected_withdrawals( @@ -125,7 +125,7 @@ def test_success_one_full_withdrawal(spec, state): partial_withdrawals_indices=partial_withdrawals_indices) -@with_phases([CAPELLA]) +@with_capella_and_later @spec_state_test def test_success_one_partial_withdrawal(spec, state): fully_withdrawable_indices, partial_withdrawals_indices = prepare_expected_withdrawals( @@ -145,7 +145,7 @@ def test_success_one_partial_withdrawal(spec, state): ) -@with_phases([CAPELLA]) +@with_capella_and_later @spec_state_test def test_success_max_per_slot(spec, state): num_full_withdrawals = spec.MAX_WITHDRAWALS_PER_PAYLOAD // 2 @@ -163,7 +163,7 @@ def test_success_max_per_slot(spec, state): partial_withdrawals_indices=partial_withdrawals_indices) -@with_phases([CAPELLA]) +@with_capella_and_later @with_presets([MAINNET], reason="too few validators with minimal config") @spec_state_test def test_success_all_fully_withdrawable_in_one_sweep(spec, state): @@ -182,7 +182,7 @@ def test_success_all_fully_withdrawable_in_one_sweep(spec, state): partial_withdrawals_indices=partial_withdrawals_indices) -@with_phases([CAPELLA]) +@with_capella_and_later @with_presets([MINIMAL], reason="too many validators with mainnet config") @spec_state_test def test_success_all_fully_withdrawable(spec, state): @@ -201,7 +201,7 @@ def test_success_all_fully_withdrawable(spec, state): partial_withdrawals_indices=partial_withdrawals_indices) -@with_phases([CAPELLA]) +@with_capella_and_later @with_presets([MAINNET], reason="too few validators with minimal config") @spec_state_test def test_success_all_partially_withdrawable_in_one_sweep(spec, state): @@ -220,7 +220,7 @@ def test_success_all_partially_withdrawable_in_one_sweep(spec, state): partial_withdrawals_indices=partial_withdrawals_indices) -@with_phases([CAPELLA]) +@with_capella_and_later @with_presets([MINIMAL], reason="too many validators with mainnet config") @spec_state_test def test_success_all_partially_withdrawable(spec, state): @@ -243,7 +243,7 @@ def test_success_all_partially_withdrawable(spec, state): # Failure cases in which the number of withdrawals in the execution_payload is incorrect # -@with_phases([CAPELLA]) +@with_capella_and_later @spec_state_test def test_invalid_non_withdrawable_non_empty_withdrawals(spec, state): next_slot(spec, state) @@ -260,7 +260,7 @@ def test_invalid_non_withdrawable_non_empty_withdrawals(spec, state): yield from run_withdrawals_processing(spec, state, execution_payload, valid=False) -@with_phases([CAPELLA]) +@with_capella_and_later @spec_state_test def test_invalid_one_expected_full_withdrawal_and_none_in_withdrawals(spec, state): prepare_expected_withdrawals(spec, state, num_full_withdrawals=1) @@ -273,7 +273,7 @@ def test_invalid_one_expected_full_withdrawal_and_none_in_withdrawals(spec, stat yield from run_withdrawals_processing(spec, state, execution_payload, valid=False) -@with_phases([CAPELLA]) +@with_capella_and_later @spec_state_test def test_invalid_one_expected_partial_withdrawal_and_none_in_withdrawals(spec, state): prepare_expected_withdrawals(spec, state, num_partial_withdrawals=1) @@ -286,7 +286,7 @@ def test_invalid_one_expected_partial_withdrawal_and_none_in_withdrawals(spec, s yield from run_withdrawals_processing(spec, state, execution_payload, valid=False) -@with_phases([CAPELLA]) +@with_capella_and_later @spec_state_test def test_invalid_one_expected_full_withdrawal_and_duplicate_in_withdrawals(spec, state): prepare_expected_withdrawals(spec, state, num_full_withdrawals=2) @@ -299,7 +299,7 @@ def test_invalid_one_expected_full_withdrawal_and_duplicate_in_withdrawals(spec, yield from run_withdrawals_processing(spec, state, execution_payload, valid=False) -@with_phases([CAPELLA]) +@with_capella_and_later @spec_state_test def test_invalid_two_expected_partial_withdrawal_and_duplicate_in_withdrawals(spec, state): prepare_expected_withdrawals(spec, state, num_partial_withdrawals=2) @@ -312,7 +312,7 @@ def test_invalid_two_expected_partial_withdrawal_and_duplicate_in_withdrawals(sp yield from run_withdrawals_processing(spec, state, execution_payload, valid=False) -@with_phases([CAPELLA]) +@with_capella_and_later @spec_state_test def test_invalid_max_per_slot_full_withdrawals_and_one_less_in_withdrawals(spec, state): prepare_expected_withdrawals(spec, state, num_full_withdrawals=spec.MAX_WITHDRAWALS_PER_PAYLOAD) @@ -325,7 +325,7 @@ def test_invalid_max_per_slot_full_withdrawals_and_one_less_in_withdrawals(spec, yield from run_withdrawals_processing(spec, state, execution_payload, valid=False) -@with_phases([CAPELLA]) +@with_capella_and_later @spec_state_test def test_invalid_max_per_slot_partial_withdrawals_and_one_less_in_withdrawals(spec, state): prepare_expected_withdrawals(spec, state, num_partial_withdrawals=spec.MAX_WITHDRAWALS_PER_PAYLOAD) @@ -338,7 +338,7 @@ def test_invalid_max_per_slot_partial_withdrawals_and_one_less_in_withdrawals(sp yield from run_withdrawals_processing(spec, state, execution_payload, valid=False) -@with_phases([CAPELLA]) +@with_capella_and_later @spec_state_test def test_invalid_a_lot_fully_withdrawable_too_few_in_withdrawals(spec, state): prepare_expected_withdrawals(spec, state, num_full_withdrawals=spec.MAX_WITHDRAWALS_PER_PAYLOAD * 4) @@ -351,7 +351,7 @@ def test_invalid_a_lot_fully_withdrawable_too_few_in_withdrawals(spec, state): yield from run_withdrawals_processing(spec, state, execution_payload, valid=False) -@with_phases([CAPELLA]) +@with_capella_and_later @spec_state_test def test_invalid_a_lot_partially_withdrawable_too_few_in_withdrawals(spec, state): prepare_expected_withdrawals(spec, state, num_partial_withdrawals=spec.MAX_WITHDRAWALS_PER_PAYLOAD * 4) @@ -364,7 +364,7 @@ def test_invalid_a_lot_partially_withdrawable_too_few_in_withdrawals(spec, state yield from run_withdrawals_processing(spec, state, execution_payload, valid=False) -@with_phases([CAPELLA]) +@with_capella_and_later @spec_state_test def test_invalid_a_lot_mixed_withdrawable_in_queue_too_few_in_withdrawals(spec, state): prepare_expected_withdrawals(spec, state, num_full_withdrawals=spec.MAX_WITHDRAWALS_PER_PAYLOAD, @@ -382,7 +382,7 @@ def test_invalid_a_lot_mixed_withdrawable_in_queue_too_few_in_withdrawals(spec, # Failure cases in which the withdrawals in the execution_payload are incorrect # -@with_phases([CAPELLA]) +@with_capella_and_later @spec_state_test def test_invalid_incorrect_withdrawal_index(spec, state): prepare_expected_withdrawals(spec, state, num_full_withdrawals=1) @@ -395,7 +395,7 @@ def test_invalid_incorrect_withdrawal_index(spec, state): yield from run_withdrawals_processing(spec, state, execution_payload, valid=False) -@with_phases([CAPELLA]) +@with_capella_and_later @spec_state_test def test_invalid_incorrect_address_full(spec, state): prepare_expected_withdrawals(spec, state, num_full_withdrawals=1) @@ -408,7 +408,7 @@ def test_invalid_incorrect_address_full(spec, state): yield from run_withdrawals_processing(spec, state, execution_payload, valid=False) -@with_phases([CAPELLA]) +@with_capella_and_later @spec_state_test def test_invalid_incorrect_address_partial(spec, state): prepare_expected_withdrawals(spec, state, num_partial_withdrawals=1) @@ -421,7 +421,7 @@ def test_invalid_incorrect_address_partial(spec, state): yield from run_withdrawals_processing(spec, state, execution_payload, valid=False) -@with_phases([CAPELLA]) +@with_capella_and_later @spec_state_test def test_invalid_incorrect_amount_full(spec, state): prepare_expected_withdrawals(spec, state, num_full_withdrawals=1) @@ -434,7 +434,7 @@ def test_invalid_incorrect_amount_full(spec, state): yield from run_withdrawals_processing(spec, state, execution_payload, valid=False) -@with_phases([CAPELLA]) +@with_capella_and_later @spec_state_test def test_invalid_incorrect_amount_partial(spec, state): prepare_expected_withdrawals(spec, state, num_full_withdrawals=1) @@ -447,7 +447,7 @@ def test_invalid_incorrect_amount_partial(spec, state): yield from run_withdrawals_processing(spec, state, execution_payload, valid=False) -@with_phases([CAPELLA]) +@with_capella_and_later @spec_state_test def test_invalid_one_of_many_incorrectly_full(spec, state): prepare_expected_withdrawals(spec, state, num_full_withdrawals=spec.MAX_WITHDRAWALS_PER_PAYLOAD * 4) @@ -466,7 +466,7 @@ def test_invalid_one_of_many_incorrectly_full(spec, state): yield from run_withdrawals_processing(spec, state, execution_payload, valid=False) -@with_phases([CAPELLA]) +@with_capella_and_later @spec_state_test def test_invalid_one_of_many_incorrectly_partial(spec, state): prepare_expected_withdrawals(spec, state, num_partial_withdrawals=spec.MAX_WITHDRAWALS_PER_PAYLOAD * 4) @@ -485,7 +485,7 @@ def test_invalid_one_of_many_incorrectly_partial(spec, state): yield from run_withdrawals_processing(spec, state, execution_payload, valid=False) -@with_phases([CAPELLA]) +@with_capella_and_later @spec_state_test def test_invalid_many_incorrectly_full(spec, state): prepare_expected_withdrawals(spec, state, num_full_withdrawals=spec.MAX_WITHDRAWALS_PER_PAYLOAD * 4) @@ -504,7 +504,7 @@ def test_invalid_many_incorrectly_full(spec, state): yield from run_withdrawals_processing(spec, state, execution_payload, valid=False) -@with_phases([CAPELLA]) +@with_capella_and_later @spec_state_test def test_invalid_many_incorrectly_partial(spec, state): prepare_expected_withdrawals(spec, state, num_partial_withdrawals=spec.MAX_WITHDRAWALS_PER_PAYLOAD * 4) @@ -527,7 +527,7 @@ def test_invalid_many_incorrectly_partial(spec, state): # More full withdrawal cases # -@with_phases([CAPELLA]) +@with_capella_and_later @spec_state_test def test_withdrawable_epoch_but_0_balance(spec, state): current_epoch = spec.get_current_epoch(state) @@ -541,7 +541,7 @@ def test_withdrawable_epoch_but_0_balance(spec, state): yield from run_withdrawals_processing(spec, state, execution_payload, num_expected_withdrawals=0) -@with_phases([CAPELLA]) +@with_capella_and_later @spec_state_test def test_withdrawable_epoch_but_0_effective_balance_0_balance(spec, state): current_epoch = spec.get_current_epoch(state) @@ -555,7 +555,7 @@ def test_withdrawable_epoch_but_0_effective_balance_0_balance(spec, state): yield from run_withdrawals_processing(spec, state, execution_payload, num_expected_withdrawals=0) -@with_phases([CAPELLA]) +@with_capella_and_later @spec_state_test def test_withdrawable_epoch_but_0_effective_balance_nonzero_balance(spec, state): current_epoch = spec.get_current_epoch(state) @@ -569,7 +569,7 @@ def test_withdrawable_epoch_but_0_effective_balance_nonzero_balance(spec, state) yield from run_withdrawals_processing(spec, state, execution_payload, num_expected_withdrawals=1) -@with_phases([CAPELLA]) +@with_capella_and_later @spec_state_test def test_no_withdrawals_but_some_next_epoch(spec, state): current_epoch = spec.get_current_epoch(state) @@ -583,7 +583,7 @@ def test_no_withdrawals_but_some_next_epoch(spec, state): yield from run_withdrawals_processing(spec, state, execution_payload, num_expected_withdrawals=0) -@with_phases([CAPELLA]) +@with_capella_and_later @spec_state_test def test_all_withdrawal(spec, state): # Make all validators withdrawable @@ -619,25 +619,25 @@ def run_random_full_withdrawals_test(spec, state, rng): yield from run_withdrawals_processing(spec, state, execution_payload) -@with_phases([CAPELLA]) +@with_capella_and_later @spec_state_test def test_random_full_withdrawals_0(spec, state): yield from run_random_full_withdrawals_test(spec, state, random.Random(444)) -@with_phases([CAPELLA]) +@with_capella_and_later @spec_state_test def test_random_full_withdrawals_1(spec, state): yield from run_random_full_withdrawals_test(spec, state, random.Random(420)) -@with_phases([CAPELLA]) +@with_capella_and_later @spec_state_test def test_random_full_withdrawals_2(spec, state): yield from run_random_full_withdrawals_test(spec, state, random.Random(200)) -@with_phases([CAPELLA]) +@with_capella_and_later @spec_state_test def test_random_full_withdrawals_3(spec, state): yield from run_random_full_withdrawals_test(spec, state, random.Random(2000000)) @@ -647,7 +647,7 @@ def test_random_full_withdrawals_3(spec, state): # More partial withdrawal cases # -@with_phases([CAPELLA]) +@with_capella_and_later @spec_state_test def test_success_no_max_effective_balance(spec, state): validator_index = len(state.validators) // 2 @@ -663,7 +663,7 @@ def test_success_no_max_effective_balance(spec, state): yield from run_withdrawals_processing(spec, state, execution_payload, num_expected_withdrawals=0) -@with_phases([CAPELLA]) +@with_capella_and_later @spec_state_test def test_success_no_excess_balance(spec, state): validator_index = len(state.validators) // 2 @@ -679,7 +679,7 @@ def test_success_no_excess_balance(spec, state): yield from run_withdrawals_processing(spec, state, execution_payload, num_expected_withdrawals=0) -@with_phases([CAPELLA]) +@with_capella_and_later @spec_state_test def test_success_excess_balance_but_no_max_effective_balance(spec, state): validator_index = len(state.validators) // 2 @@ -696,7 +696,7 @@ def test_success_excess_balance_but_no_max_effective_balance(spec, state): yield from run_withdrawals_processing(spec, state, execution_payload, num_expected_withdrawals=0) -@with_phases([CAPELLA]) +@with_capella_and_later @spec_state_test def test_success_one_partial_withdrawable_not_yet_active(spec, state): validator_index = min(len(state.validators) // 2, spec.MAX_VALIDATORS_PER_WITHDRAWALS_SWEEP - 1) @@ -710,7 +710,7 @@ def test_success_one_partial_withdrawable_not_yet_active(spec, state): yield from run_withdrawals_processing(spec, state, execution_payload, num_expected_withdrawals=1) -@with_phases([CAPELLA]) +@with_capella_and_later @spec_state_test def test_success_one_partial_withdrawable_in_exit_queue(spec, state): validator_index = min(len(state.validators) // 2, spec.MAX_VALIDATORS_PER_WITHDRAWALS_SWEEP - 1) @@ -725,7 +725,7 @@ def test_success_one_partial_withdrawable_in_exit_queue(spec, state): yield from run_withdrawals_processing(spec, state, execution_payload, num_expected_withdrawals=1) -@with_phases([CAPELLA]) +@with_capella_and_later @spec_state_test def test_success_one_partial_withdrawable_exited(spec, state): validator_index = min(len(state.validators) // 2, spec.MAX_VALIDATORS_PER_WITHDRAWALS_SWEEP - 1) @@ -739,7 +739,7 @@ def test_success_one_partial_withdrawable_exited(spec, state): yield from run_withdrawals_processing(spec, state, execution_payload, num_expected_withdrawals=1) -@with_phases([CAPELLA]) +@with_capella_and_later @spec_state_test def test_success_one_partial_withdrawable_active_and_slashed(spec, state): validator_index = min(len(state.validators) // 2, spec.MAX_VALIDATORS_PER_WITHDRAWALS_SWEEP - 1) @@ -753,7 +753,7 @@ def test_success_one_partial_withdrawable_active_and_slashed(spec, state): yield from run_withdrawals_processing(spec, state, execution_payload, num_expected_withdrawals=1) -@with_phases([CAPELLA]) +@with_capella_and_later @spec_state_test def test_success_one_partial_withdrawable_exited_and_slashed(spec, state): validator_index = min(len(state.validators) // 2, spec.MAX_VALIDATORS_PER_WITHDRAWALS_SWEEP - 1) @@ -768,7 +768,7 @@ def test_success_one_partial_withdrawable_exited_and_slashed(spec, state): yield from run_withdrawals_processing(spec, state, execution_payload, num_expected_withdrawals=1) -@with_phases([CAPELLA]) +@with_capella_and_later @spec_state_test def test_success_two_partial_withdrawable(spec, state): set_validator_partially_withdrawable(spec, state, 0) @@ -779,7 +779,7 @@ def test_success_two_partial_withdrawable(spec, state): yield from run_withdrawals_processing(spec, state, execution_payload, num_expected_withdrawals=2) -@with_phases([CAPELLA]) +@with_capella_and_later @spec_state_test def test_success_max_partial_withdrawable(spec, state): # Sanity check that this test works for this state @@ -794,7 +794,7 @@ def test_success_max_partial_withdrawable(spec, state): spec, state, execution_payload, num_expected_withdrawals=spec.MAX_WITHDRAWALS_PER_PAYLOAD) -@with_phases([CAPELLA]) +@with_capella_and_later @with_presets([MINIMAL], reason="not enough validators with mainnet config") @spec_state_test def test_success_max_plus_one_withdrawable(spec, state): @@ -833,37 +833,37 @@ def run_random_partial_withdrawals_test(spec, state, rng): yield from run_withdrawals_processing(spec, state, execution_payload) -@with_phases([CAPELLA]) +@with_capella_and_later @spec_state_test def test_random_0(spec, state): yield from run_random_partial_withdrawals_test(spec, state, random.Random(0)) -@with_phases([CAPELLA]) +@with_capella_and_later @spec_state_test def test_random_partial_withdrawals_1(spec, state): yield from run_random_partial_withdrawals_test(spec, state, random.Random(1)) -@with_phases([CAPELLA]) +@with_capella_and_later @spec_state_test def test_random_partial_withdrawals_2(spec, state): yield from run_random_partial_withdrawals_test(spec, state, random.Random(2)) -@with_phases([CAPELLA]) +@with_capella_and_later @spec_state_test def test_random_partial_withdrawals_3(spec, state): yield from run_random_partial_withdrawals_test(spec, state, random.Random(3)) -@with_phases([CAPELLA]) +@with_capella_and_later @spec_state_test def test_random_partial_withdrawals_4(spec, state): yield from run_random_partial_withdrawals_test(spec, state, random.Random(4)) -@with_phases([CAPELLA]) +@with_capella_and_later @spec_state_test def test_random_partial_withdrawals_5(spec, state): yield from run_random_partial_withdrawals_test(spec, state, random.Random(5)) diff --git a/tests/core/pyspec/eth2spec/test/capella/epoch_processing/test_process_historical_batches_update.py b/tests/core/pyspec/eth2spec/test/capella/epoch_processing/test_process_historical_batches_update.py index f1f8292eb..c5465d328 100644 --- a/tests/core/pyspec/eth2spec/test/capella/epoch_processing/test_process_historical_batches_update.py +++ b/tests/core/pyspec/eth2spec/test/capella/epoch_processing/test_process_historical_batches_update.py @@ -1,7 +1,6 @@ from eth2spec.test.context import ( - CAPELLA, spec_state_test, - with_phases, + with_capella_and_later, ) from eth2spec.test.helpers.epoch_processing import ( run_epoch_processing_with @@ -12,7 +11,7 @@ def run_process_historical_summaries_update(spec, state): yield from run_epoch_processing_with(spec, state, 'process_historical_summaries_update') -@with_phases([CAPELLA]) +@with_capella_and_later @spec_state_test def test_historical_summaries_accumulator(spec, state): # skip ahead to near the end of the historical batch period (excl block before epoch processing) diff --git a/tests/core/pyspec/eth2spec/test/capella/sanity/test_blocks.py b/tests/core/pyspec/eth2spec/test/capella/sanity/test_blocks.py index 1df046c9d..1cd1c1317 100644 --- a/tests/core/pyspec/eth2spec/test/capella/sanity/test_blocks.py +++ b/tests/core/pyspec/eth2spec/test/capella/sanity/test_blocks.py @@ -1,7 +1,6 @@ from eth2spec.test.context import ( - with_phases, spec_state_test + with_capella_and_later, spec_state_test ) -from eth2spec.test.helpers.constants import CAPELLA from eth2spec.test.helpers.state import ( state_transition_and_sign_block, ) @@ -25,7 +24,7 @@ from eth2spec.test.helpers.voluntary_exits import prepare_signed_exits # BLSToExecutionChange # -@with_phases([CAPELLA]) +@with_capella_and_later @spec_state_test def test_success_bls_change(spec, state): index = 0 @@ -48,7 +47,7 @@ def test_success_bls_change(spec, state): assert post_credentials[12:] == signed_address_change.message.to_execution_address -@with_phases([CAPELLA]) +@with_capella_and_later @spec_state_test def test_success_exit_and_bls_change(spec, state): # move state forward SHARD_COMMITTEE_PERIOD epochs to allow for exit @@ -77,7 +76,7 @@ def test_success_exit_and_bls_change(spec, state): assert spec.is_fully_withdrawable_validator(validator, balance, validator.withdrawable_epoch) -@with_phases([CAPELLA]) +@with_capella_and_later @spec_state_test def test_invalid_duplicate_bls_changes_same_block(spec, state): index = 0 @@ -96,7 +95,7 @@ def test_invalid_duplicate_bls_changes_same_block(spec, state): yield 'post', None -@with_phases([CAPELLA]) +@with_capella_and_later @spec_state_test def test_invalid_two_bls_changes_of_different_addresses_same_validator_same_block(spec, state): index = 0 @@ -124,7 +123,7 @@ def test_invalid_two_bls_changes_of_different_addresses_same_validator_same_bloc # Withdrawals # -@with_phases([CAPELLA]) +@with_capella_and_later @spec_state_test def test_full_withdrawal_in_epoch_transition(spec, state): index = 0 @@ -145,7 +144,7 @@ def test_full_withdrawal_in_epoch_transition(spec, state): assert len(spec.get_expected_withdrawals(state)) == 0 -@with_phases([CAPELLA]) +@with_capella_and_later @spec_state_test def test_partial_withdrawal_in_epoch_transition(spec, state): index = state.next_withdrawal_index @@ -169,7 +168,7 @@ def test_partial_withdrawal_in_epoch_transition(spec, state): assert len(spec.get_expected_withdrawals(state)) == 0 -@with_phases([CAPELLA]) +@with_capella_and_later @spec_state_test def test_many_partial_withdrawals_in_epoch_transition(spec, state): assert len(state.validators) > spec.MAX_WITHDRAWALS_PER_PAYLOAD @@ -221,7 +220,7 @@ def _perform_valid_withdrawal(spec, state): return pre_state, signed_block_1, pre_next_withdrawal_index -@with_phases([CAPELLA]) +@with_capella_and_later @spec_state_test def test_withdrawal_success_two_blocks(spec, state): pre_state, signed_block_1, pre_next_withdrawal_index = _perform_valid_withdrawal(spec, state) @@ -238,7 +237,7 @@ def test_withdrawal_success_two_blocks(spec, state): yield 'post', state -@with_phases([CAPELLA]) +@with_capella_and_later @spec_state_test def test_invalid_withdrawal_fail_second_block_payload_isnt_compatible(spec, state): _perform_valid_withdrawal(spec, state) diff --git a/tests/core/pyspec/eth2spec/test/eip4844/block_processing/__init__.py b/tests/core/pyspec/eth2spec/test/eip4844/block_processing/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tests/core/pyspec/eth2spec/test/eip4844/block_processing/test_process_bls_to_execution_change.py b/tests/core/pyspec/eth2spec/test/eip4844/block_processing/test_process_bls_to_execution_change.py deleted file mode 100644 index d9b93394f..000000000 --- a/tests/core/pyspec/eth2spec/test/eip4844/block_processing/test_process_bls_to_execution_change.py +++ /dev/null @@ -1,40 +0,0 @@ -from eth2spec.test.helpers.bls_to_execution_changes import get_signed_address_change -from eth2spec.test.context import spec_state_test, expect_assertion_error, with_eip4844_and_later - - -def run_bls_to_execution_change_processing_no_op(spec, state, signed_address_change, valid=True): - """ - Run ``process_bls_to_execution_change``, yielding: - - pre-state ('pre') - - address-change ('address_change') - - post-state ('post'). - If ``valid == False``, run expecting ``AssertionError`` - """ - pre_state = state.copy() - - # yield pre-state - yield 'pre', state - - yield 'address_change', signed_address_change - - # If the address_change is invalid, processing is aborted, and there is no post-state. - if not valid: - expect_assertion_error(lambda: spec.process_bls_to_execution_change(state, signed_address_change)) - yield 'post', None - return - - # process address change - spec.process_bls_to_execution_change(state, signed_address_change) - - # yield post-state - yield 'post', state - - # Make sure state has NOT been changed - assert state == pre_state - - -@with_eip4844_and_later -@spec_state_test -def test_no_op(spec, state): - signed_address_change = get_signed_address_change(spec, state) - yield from run_bls_to_execution_change_processing_no_op(spec, state, signed_address_change) diff --git a/tests/core/pyspec/eth2spec/test/eip4844/block_processing/test_process_withdrawals.py b/tests/core/pyspec/eth2spec/test/eip4844/block_processing/test_process_withdrawals.py deleted file mode 100644 index a7db37e42..000000000 --- a/tests/core/pyspec/eth2spec/test/eip4844/block_processing/test_process_withdrawals.py +++ /dev/null @@ -1,41 +0,0 @@ - -from eth2spec.test.context import spec_state_test, expect_assertion_error, with_eip4844_and_later -from eth2spec.test.helpers.execution_payload import ( - build_empty_execution_payload, -) -from eth2spec.test.helpers.state import next_slot - - -def run_withdrawals_processing(spec, state, execution_payload, valid=True): - """ - Run ``process_execution_payload``, yielding: - - pre-state ('pre') - - execution payload ('execution_payload') - - post-state ('post'). - If ``valid == False``, run expecting ``AssertionError`` - """ - pre_state = state.copy() - - yield 'pre', state - yield 'execution_payload', execution_payload - - if not valid: - expect_assertion_error(lambda: spec.process_withdrawals(state, execution_payload)) - yield 'post', None - return - - spec.process_withdrawals(state, execution_payload) - - yield 'post', state - - # Make sure state has NOT been changed - assert state == pre_state - - -@with_eip4844_and_later -@spec_state_test -def test_no_op(spec, state): - next_slot(spec, state) - execution_payload = build_empty_execution_payload(spec, state) - - yield from run_withdrawals_processing(spec, state, execution_payload) diff --git a/tests/core/pyspec/eth2spec/test/eip4844/epoch_processing/__init__.py b/tests/core/pyspec/eth2spec/test/eip4844/epoch_processing/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tests/core/pyspec/eth2spec/test/eip4844/epoch_processing/test_process_historical_batches_update.py b/tests/core/pyspec/eth2spec/test/eip4844/epoch_processing/test_process_historical_batches_update.py deleted file mode 100644 index 21865ae38..000000000 --- a/tests/core/pyspec/eth2spec/test/eip4844/epoch_processing/test_process_historical_batches_update.py +++ /dev/null @@ -1,23 +0,0 @@ -from eth2spec.test.context import ( - spec_state_test, - with_eip4844_and_later, -) -from eth2spec.test.helpers.epoch_processing import ( - run_epoch_processing_with -) - - -def run_process_historical_summaries_update(spec, state): - yield from run_epoch_processing_with(spec, state, 'process_historical_summaries_update') - - -@with_eip4844_and_later -@spec_state_test -def test_no_op(spec, state): - # skip ahead to near the end of the historical batch period (excl block before epoch processing) - state.slot = spec.SLOTS_PER_HISTORICAL_ROOT - 1 - historical_summaries_len = len(state.historical_summaries) - - yield from run_process_historical_summaries_update(spec, state) - - assert len(state.historical_summaries) == historical_summaries_len diff --git a/tests/core/pyspec/eth2spec/test/phase0/sanity/test_blocks.py b/tests/core/pyspec/eth2spec/test/phase0/sanity/test_blocks.py index 71c7798a1..2e1a2a369 100644 --- a/tests/core/pyspec/eth2spec/test/phase0/sanity/test_blocks.py +++ b/tests/core/pyspec/eth2spec/test/phase0/sanity/test_blocks.py @@ -29,7 +29,7 @@ from eth2spec.test.helpers.sync_committee import ( compute_committee_indices, compute_sync_committee_participant_reward_and_penalty, ) -from eth2spec.test.helpers.constants import PHASE0, EIP4844, MINIMAL +from eth2spec.test.helpers.constants import PHASE0, MINIMAL from eth2spec.test.helpers.forks import is_post_altair, is_post_bellatrix, is_post_capella from eth2spec.test.context import ( spec_test, spec_state_test, dump_skipping_message, @@ -1046,11 +1046,7 @@ def test_historical_batch(spec, state): if is_post_capella(spec): # Frozen `historical_roots` assert state.historical_roots == pre_historical_roots - if spec.fork == EIP4844: - # TODO: no-op for now in EIP4844 testnet - assert state.historical_summaries == pre_historical_summaries - else: - assert len(state.historical_summaries) == len(pre_historical_summaries) + 1 + assert len(state.historical_summaries) == len(pre_historical_summaries) + 1 else: assert len(state.historical_roots) == len(pre_historical_roots) + 1 diff --git a/tests/core/pyspec/eth2spec/test/phase0/sanity/test_slots.py b/tests/core/pyspec/eth2spec/test/phase0/sanity/test_slots.py index 7b860159a..90d332d57 100644 --- a/tests/core/pyspec/eth2spec/test/phase0/sanity/test_slots.py +++ b/tests/core/pyspec/eth2spec/test/phase0/sanity/test_slots.py @@ -1,6 +1,3 @@ -from eth2spec.test.helpers.constants import ( - EIP4844, -) from eth2spec.test.helpers.forks import ( is_post_capella, ) @@ -87,10 +84,6 @@ def test_historical_accumulator(spec, state): if is_post_capella(spec): # Frozen `historical_roots` assert state.historical_roots == pre_historical_roots - if spec.fork == EIP4844: - # TODO: no-op for now in EIP4844 testnet - assert state.historical_summaries == pre_historical_summaries - else: - assert len(state.historical_summaries) == len(pre_historical_summaries) + 1 + assert len(state.historical_summaries) == len(pre_historical_summaries) + 1 else: assert len(state.historical_roots) == len(pre_historical_roots) + 1 diff --git a/tests/generators/epoch_processing/main.py b/tests/generators/epoch_processing/main.py index 58beb0fd2..384d047be 100644 --- a/tests/generators/epoch_processing/main.py +++ b/tests/generators/epoch_processing/main.py @@ -32,10 +32,8 @@ if __name__ == "__main__": ]} capella_mods = combine_mods(_new_capella_mods, bellatrix_mods) - _new_eip4844_mods = {key: 'eth2spec.test.eip4844.epoch_processing.test_process_' + key for key in [ - 'historical_summaries_update', - ]} - eip4844_mods = combine_mods(_new_eip4844_mods, capella_mods) + # TODO: add process_execution_payload tests + eip4844_mods = capella_mods # TODO Custody Game testgen is disabled for now # custody_game_mods = {**{key: 'eth2spec.test.custody_game.epoch_processing.test_process_' + key for key in [ diff --git a/tests/generators/operations/main.py b/tests/generators/operations/main.py index 4c073ebe4..d370a1b85 100644 --- a/tests/generators/operations/main.py +++ b/tests/generators/operations/main.py @@ -36,11 +36,7 @@ if __name__ == "__main__": ]} capella_mods = combine_mods(_new_capella_mods, bellatrix_mods) - _new_eip4844_mods = {key: 'eth2spec.test.eip4844.block_processing.test_process_' + key for key in [ - 'bls_to_execution_change', - 'withdrawals', - ]} - eip4844_mods = combine_mods(_new_eip4844_mods, capella_mods) + eip4844_mods = capella_mods # TODO Custody Game testgen is disabled for now # _new_custody_game_mods = {key: 'eth2spec.test.custody_game.block_processing.test_process_' + key for key in [ From 118daae6d9d62188debcaf34f4f74f21e4705f26 Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Wed, 4 Jan 2023 17:54:59 +0800 Subject: [PATCH 038/158] Add notes for new state historical accumulators --- specs/capella/beacon-chain.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/specs/capella/beacon-chain.md b/specs/capella/beacon-chain.md index bd7a2c50c..5d0df0edd 100644 --- a/specs/capella/beacon-chain.md +++ b/specs/capella/beacon-chain.md @@ -53,6 +53,10 @@ to validator withdrawals. Including: * Operation to change from `BLS_WITHDRAWAL_PREFIX` to `ETH1_ADDRESS_WITHDRAWAL_PREFIX` versioned withdrawal credentials to enable withdrawals for a validator. +Another new feature is the new state/block historical accumulators. It becomes possible to validate +the entire block history that led up to that particular state without executing the transitions +and checking them one by one in backward order using a parent chain. + ## Custom types We define the following Python custom types for type hinting and readability: From 9d14dcd8b0171d7e811a2f322174b2d02219ea0d Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Wed, 4 Jan 2023 18:09:38 +0800 Subject: [PATCH 039/158] Ensure that no duplidate block hashes --- .../pyspec/eth2spec/test/bellatrix/sync/test_optimistic.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tests/core/pyspec/eth2spec/test/bellatrix/sync/test_optimistic.py b/tests/core/pyspec/eth2spec/test/bellatrix/sync/test_optimistic.py index 974719f92..eb56e368a 100644 --- a/tests/core/pyspec/eth2spec/test/bellatrix/sync/test_optimistic.py +++ b/tests/core/pyspec/eth2spec/test/bellatrix/sync/test_optimistic.py @@ -64,6 +64,7 @@ def test_from_syncing_to_invalid(spec, state): block.body.execution_payload.parent_hash = ( block_hashes[f'chain_a_{i - 1}'] if i != 0 else block_hashes['block_0'] ) + block.body.execution_payload.extra_data = spec.hash(bytes(f'chain_a_{i}', 'UTF-8')) block.body.execution_payload.block_hash = compute_el_block_hash(spec, block.body.execution_payload) block_hashes[f'chain_a_{i}'] = block.body.execution_payload.block_hash @@ -80,6 +81,7 @@ def test_from_syncing_to_invalid(spec, state): block.body.execution_payload.parent_hash = ( block_hashes[f'chain_b_{i - 1}'] if i != 0 else block_hashes['block_0'] ) + block.body.execution_payload.extra_data = spec.hash(bytes(f'chain_b_{i}', 'UTF-8')) block.body.execution_payload.block_hash = compute_el_block_hash(spec, block.body.execution_payload) block_hashes[f'chain_b_{i}'] = block.body.execution_payload.block_hash @@ -92,9 +94,13 @@ def test_from_syncing_to_invalid(spec, state): # Now add block 4 to chain `b` with INVALID block = build_empty_block_for_next_slot(spec, state) block.body.execution_payload.parent_hash = signed_blocks_b[-1].message.body.execution_payload.block_hash + block.body.execution_payload.extra_data = spec.hash(bytes(f'chain_b_{i}', 'UTF-8')) block.body.execution_payload.block_hash = compute_el_block_hash(spec, block.body.execution_payload) block_hashes['chain_b_3'] = block.body.execution_payload.block_hash + # Ensure that no duplicate block hashes + assert len(block_hashes) == len(set(block_hashes.values())) + signed_block = state_transition_and_sign_block(spec, state, block) payload_status = PayloadStatusV1( status=PayloadStatusV1Status.INVALID, From 599883644986e85558aac6eaf37e381d92830a02 Mon Sep 17 00:00:00 2001 From: protolambda Date: Wed, 4 Jan 2023 11:20:09 +0100 Subject: [PATCH 040/158] tests/formats: update epoch and operations formats to reflect push-withdrawals (#3184) * tests/formats: update epoch and operations formats to reflect push-withdrawals of PR 3068 * fix typo * Update epoch processing readme Co-authored-by: Hsiao-Wei Wang --- tests/formats/epoch_processing/README.md | 5 ++--- tests/formats/operations/README.md | 23 ++++++++++++----------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/tests/formats/epoch_processing/README.md b/tests/formats/epoch_processing/README.md index 41d2a102a..2951767f2 100644 --- a/tests/formats/epoch_processing/README.md +++ b/tests/formats/epoch_processing/README.md @@ -41,11 +41,10 @@ Sub-transitions: - `effective_balance_updates` - `slashings_reset` - `randao_mixes_reset` -- `historical_roots_update` +- `historical_roots_update` (Phase0, Altair, Bellatrix only) +- `historical_summaries_update` (Capella) - `participation_record_updates` (Phase 0 only) - `participation_flag_updates` (Altair) - `sync_committee_updates` (Altair) -- `full_withdrawals` (Capella) -- `partial_withdrawals` (Capella) The resulting state should match the expected `post` state. diff --git a/tests/formats/operations/README.md b/tests/formats/operations/README.md index ba2c64b3a..810d62578 100644 --- a/tests/formats/operations/README.md +++ b/tests/formats/operations/README.md @@ -33,17 +33,18 @@ This excludes the other parts of the block-transition. Operations: -| *`operation-name`* | *`operation-object`* | *`input name`* | *`processing call`* | -|-------------------------|-----------------------|----------------------|----------------------------------------------------------------------| -| `attestation` | `Attestation` | `attestation` | `process_attestation(state, attestation)` | -| `attester_slashing` | `AttesterSlashing` | `attester_slashing` | `process_attester_slashing(state, attester_slashing)` | -| `block_header` | `BeaconBlock` | **`block`** | `process_block_header(state, block)` | -| `deposit` | `Deposit` | `deposit` | `process_deposit(state, deposit)` | -| `proposer_slashing` | `ProposerSlashing` | `proposer_slashing` | `process_proposer_slashing(state, proposer_slashing)` | -| `voluntary_exit` | `SignedVoluntaryExit` | `voluntary_exit` | `process_voluntary_exit(state, voluntary_exit)` | -| `sync_aggregate` | `SyncAggregate` | `sync_aggregate` | `process_sync_aggregate(state, sync_aggregate)` (new in Altair) | -| `execution_payload` | `ExecutionPayload` | `execution_payload` | `process_execution_payload(state, execution_payload)` (new in Bellatrix) | -| `bls_to_execution_change` | `SignedBLSToExecutionChange` | `signed_address_change` | `process_bls_to_execution_change(state, signed_address_change)` (new in Capella) | +| *`operation-name`* | *`operation-object`* | *`input name`* | *`processing call`* | +|---------------------------|------------------------------|---------------------|----------------------------------------------------------------------------------| +| `attestation` | `Attestation` | `attestation` | `process_attestation(state, attestation)` | +| `attester_slashing` | `AttesterSlashing` | `attester_slashing` | `process_attester_slashing(state, attester_slashing)` | +| `block_header` | `BeaconBlock` | **`block`** | `process_block_header(state, block)` | +| `deposit` | `Deposit` | `deposit` | `process_deposit(state, deposit)` | +| `proposer_slashing` | `ProposerSlashing` | `proposer_slashing` | `process_proposer_slashing(state, proposer_slashing)` | +| `voluntary_exit` | `SignedVoluntaryExit` | `voluntary_exit` | `process_voluntary_exit(state, voluntary_exit)` | +| `sync_aggregate` | `SyncAggregate` | `sync_aggregate` | `process_sync_aggregate(state, sync_aggregate)` (new in Altair) | +| `execution_payload` | `ExecutionPayload` | `execution_payload` | `process_execution_payload(state, execution_payload)` (new in Bellatrix) | +| `withdrawals` | `ExecutionPayload` | `execution_payload` | `process_withdrawals(state, execution_payload)` (new in Capella) | +| `bls_to_execution_change` | `SignedBLSToExecutionChange` | `address_change` | `process_bls_to_execution_change(state, address_change)` (new in Capella) | Note that `block_header` is not strictly an operation (and is a full `Block`), but processed in the same manner, and hence included here. From 5ff877cc26dab8ebdbd83ff08689ca3231a64607 Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Wed, 4 Jan 2023 18:24:13 +0800 Subject: [PATCH 041/158] Add link to docs lookup table --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 07b78c0d5..bb69a452a 100644 --- a/README.md +++ b/README.md @@ -25,7 +25,7 @@ Features are researched and developed in parallel, and then consolidated into se | Code Name or Topic | Specs | Notes | | - | - | - | | Capella (tentative) |
  • Core
    • [Beacon chain changes](specs/capella/beacon-chain.md)
    • [Capella fork](specs/capella/fork.md)
  • Additions
    • [Validator additions](specs/capella/validator.md)
    • [P2P networking](specs/capella/p2p-interface.md)
| -| EIP4844 (tentative) |
  • Core
    • [Beacon Chain changes](specs/eip4844/beacon-chain.md)
    • [EIP-4844 fork](specs/eip4844/fork.md)
    • [Polynomial commitments](specs/eip4844/polynomial-commitments.md)
  • Additions
    • [Honest validator guide changes](specs/eip4844/validator.md)
    • [P2P networking](specs/eip4844/p2p-interface.md)
| +| EIP4844 (tentative) |
  • Core
    • [Beacon Chain changes](specs/eip4844/beacon-chain.md)
    • [EIP-4844 fork](specs/eip4844/fork.md)
    • [Polynomial commitments](specs/eip4844/polynomial-commitments.md)
    • [Fork choice changes](specs/eip4844/fork-choice.md)
  • Additions
    • [Honest validator guide changes](specs/eip4844/validator.md)
    • [P2P networking](specs/eip4844/p2p-interface.md)
| | Sharding (outdated) |
  • Core
    • [Beacon Chain changes](specs/sharding/beacon-chain.md)
  • Additions
    • [P2P networking](specs/sharding/p2p-interface.md)
| | Custody Game (outdated) |
  • Core
    • [Beacon Chain changes](specs/custody_game/beacon-chain.md)
  • Additions
    • [Honest validator guide changes](specs/custody_game/validator.md)
| Dependent on sharding | | Data Availability Sampling (outdated) |
  • Core
    • [Core types and functions](specs/das/das-core.md)
    • [Fork choice changes](specs/das/fork-choice.md)
  • Additions
    • [P2P Networking](specs/das/p2p-interface.md)
    • [Sampling process](specs/das/sampling.md)
|
  • Dependent on sharding
  • [Technical explainer](https://hackmd.io/@HWeNw8hNRimMm2m2GH56Cw/B1YJPGkpD)
| From 9d402dd2d21a55c28fdcd01efeb76fe1d823b066 Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Wed, 4 Jan 2023 18:51:51 +0800 Subject: [PATCH 042/158] minor fix --- tests/generators/epoch_processing/main.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/generators/epoch_processing/main.py b/tests/generators/epoch_processing/main.py index 384d047be..dda4345a8 100644 --- a/tests/generators/epoch_processing/main.py +++ b/tests/generators/epoch_processing/main.py @@ -32,7 +32,6 @@ if __name__ == "__main__": ]} capella_mods = combine_mods(_new_capella_mods, bellatrix_mods) - # TODO: add process_execution_payload tests eip4844_mods = capella_mods # TODO Custody Game testgen is disabled for now From 7d2482a025e29261a7b306301977f22590c7f7c9 Mon Sep 17 00:00:00 2001 From: henridf Date: Wed, 4 Jan 2023 16:29:15 +0100 Subject: [PATCH 043/158] Fix typo in eip4844/BeaconBlocksByRoot docs --- specs/eip4844/p2p-interface.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/specs/eip4844/p2p-interface.md b/specs/eip4844/p2p-interface.md index 420a6da05..1f5fd55cd 100644 --- a/specs/eip4844/p2p-interface.md +++ b/specs/eip4844/p2p-interface.md @@ -141,8 +141,8 @@ Per `context = compute_fork_digest(fork_version, genesis_validators_root)`: **Protocol ID:** `/eth2/beacon_chain/req/beacon_blocks_by_root/2/` -After `EIP4844_FORK_EPOCH`, `BeaconBlocksByRootV2` is replaced by `BeaconBlockAndBlobsSidecarByRootV1` -clients MUST support requesting blocks by root for pre-fork-epoch blocks. +After `EIP4844_FORK_EPOCH`, `BeaconBlocksByRootV2` is replaced by `BeaconBlockAndBlobsSidecarByRootV1`. +Clients MUST support requesting blocks by root for pre-fork-epoch blocks. Per `context = compute_fork_digest(fork_version, genesis_validators_root)`: From e5cda1745fa537d5b19403f2af5cbec0ebb2191a Mon Sep 17 00:00:00 2001 From: Etan Kissling Date: Wed, 4 Jan 2023 18:07:55 +0100 Subject: [PATCH 044/158] Run fork test for EIP4844 --- .../test/altair/light_client/test_sync.py | 69 +++++++++++-------- 1 file changed, 40 insertions(+), 29 deletions(-) diff --git a/tests/core/pyspec/eth2spec/test/altair/light_client/test_sync.py b/tests/core/pyspec/eth2spec/test/altair/light_client/test_sync.py index b3fd4ebe8..9c90b63fa 100644 --- a/tests/core/pyspec/eth2spec/test/altair/light_client/test_sync.py +++ b/tests/core/pyspec/eth2spec/test/altair/light_client/test_sync.py @@ -618,15 +618,7 @@ def test_advance_finality_without_sync_committee(spec, state): yield from finish_test(test) -@with_phases(phases=[BELLATRIX], other_phases=[CAPELLA]) -@spec_test -@with_config_overrides({ - 'CAPELLA_FORK_EPOCH': 3, # `setup_test` advances to epoch 2 -}, emit=False) -@with_state -@with_matching_spec_config(emitted_fork=CAPELLA) -@with_presets([MINIMAL], reason="too slow") -def test_capella_fork(spec, phases, state): +def run_test_single_fork(spec, phases, state, fork): # Start test test = yield from setup_test(spec, state, phases=phases) @@ -644,8 +636,9 @@ def test_capella_fork(spec, phases, state): assert test.store.best_valid_update is None assert test.s_spec.get_lc_beacon_slot(test.store.optimistic_header) == attested_state.slot - # Jump to two slots before Capella - transition_to(spec, state, spec.compute_start_slot_at_epoch(phases[CAPELLA].config.CAPELLA_FORK_EPOCH) - 4) + # Jump to two slots before fork + fork_epoch = getattr(phases[fork].config, fork.upper() + '_FORK_EPOCH') + transition_to(spec, state, spec.compute_start_slot_at_epoch(fork_epoch) - 4) attested_block = state_transition_with_full_block(spec, state, True, True) attested_state = state.copy() sync_aggregate, _ = get_sync_aggregate(spec, state) @@ -658,10 +651,10 @@ def test_capella_fork(spec, phases, state): assert test.s_spec.get_lc_beacon_slot(test.store.optimistic_header) == attested_state.slot # Perform `LightClientStore` upgrade - yield from emit_upgrade_store(test, phases[CAPELLA], phases=phases) + yield from emit_upgrade_store(test, phases[fork], phases=phases) update = test.store.best_valid_update - # Final slot before Capella, check that importing the Altair format still works + # Final slot before fork, check that importing the pre-fork format still works attested_block = block.copy() attested_state = state.copy() sync_aggregate, _ = get_sync_aggregate(spec, state) @@ -672,11 +665,11 @@ def test_capella_fork(spec, phases, state): assert test.store.best_valid_update == update assert test.s_spec.get_lc_beacon_slot(test.store.optimistic_header) == attested_state.slot - # Upgrade to Capella, attested block is still before the fork + # Upgrade to post-fork spec, attested block is still before the fork attested_block = block.copy() attested_state = state.copy() - state, _ = do_fork(state, spec, phases[CAPELLA], phases[CAPELLA].config.CAPELLA_FORK_EPOCH, with_block=False) - spec = phases[CAPELLA] + state, _ = do_fork(state, spec, phases[fork], fork_epoch, with_block=False) + spec = phases[fork] sync_aggregate, _ = get_sync_aggregate(spec, state) block = state_transition_with_full_block(spec, state, True, True, sync_aggregate=sync_aggregate) yield from emit_update(test, spec, state, block, attested_state, attested_block, finalized_block, phases=phases) @@ -684,9 +677,8 @@ def test_capella_fork(spec, phases, state): assert test.store.next_sync_committee == finalized_state.next_sync_committee assert test.store.best_valid_update == update assert test.s_spec.get_lc_beacon_slot(test.store.optimistic_header) == attested_state.slot - assert test.s_spec.get_lc_execution_root(test.store.optimistic_header) == test.s_spec.Root() - # Another block in Capella, this time attested block is after the fork + # Another block after the fork, this time attested block is after the fork attested_block = block.copy() attested_state = state.copy() sync_aggregate, _ = get_sync_aggregate(spec, state) @@ -696,23 +688,20 @@ def test_capella_fork(spec, phases, state): assert test.store.next_sync_committee == finalized_state.next_sync_committee assert test.store.best_valid_update == update assert test.s_spec.get_lc_beacon_slot(test.store.optimistic_header) == attested_state.slot - assert test.s_spec.get_lc_execution_root(test.store.optimistic_header) != test.s_spec.Root() # Jump to next epoch - transition_to(spec, state, spec.compute_start_slot_at_epoch(phases[CAPELLA].config.CAPELLA_FORK_EPOCH + 1) - 2) + transition_to(spec, state, spec.compute_start_slot_at_epoch(fork_epoch + 1) - 2) attested_block = state_transition_with_full_block(spec, state, True, True) attested_state = state.copy() sync_aggregate, _ = get_sync_aggregate(spec, state) block = state_transition_with_full_block(spec, state, True, True, sync_aggregate=sync_aggregate) yield from emit_update(test, spec, state, block, attested_state, attested_block, finalized_block, phases=phases) assert test.s_spec.get_lc_beacon_slot(test.store.finalized_header) == finalized_state.slot - assert test.s_spec.get_lc_execution_root(test.store.finalized_header) == test.s_spec.Root() assert test.store.next_sync_committee == finalized_state.next_sync_committee assert test.store.best_valid_update == update assert test.s_spec.get_lc_beacon_slot(test.store.optimistic_header) == attested_state.slot - assert test.s_spec.get_lc_execution_root(test.store.optimistic_header) != test.s_spec.Root() - # Finalize it + # Finalize the fork finalized_block = block.copy() finalized_state = state.copy() _, _, state = next_slots_with_attestations(spec, state, 2 * spec.SLOTS_PER_EPOCH - 1, True, True) @@ -722,19 +711,41 @@ def test_capella_fork(spec, phases, state): block = state_transition_with_full_block(spec, state, True, True, sync_aggregate=sync_aggregate) yield from emit_update(test, spec, state, block, attested_state, attested_block, finalized_block, phases=phases) assert test.s_spec.get_lc_beacon_slot(test.store.finalized_header) == finalized_state.slot - assert test.s_spec.get_lc_execution_root(test.store.finalized_header) != test.s_spec.Root() assert test.store.next_sync_committee == finalized_state.next_sync_committee assert test.store.best_valid_update is None assert test.s_spec.get_lc_beacon_slot(test.store.optimistic_header) == attested_state.slot - assert test.s_spec.get_lc_execution_root(test.store.optimistic_header) != test.s_spec.Root() # Finish test yield from finish_test(test) -def run_test_upgraded_store_with_legacy_data(spec, state, s_spec, phases): +@with_phases(phases=[BELLATRIX], other_phases=[CAPELLA]) +@spec_test +@with_config_overrides({ + 'CAPELLA_FORK_EPOCH': 3, # `setup_test` advances to epoch 2 +}, emit=False) +@with_state +@with_matching_spec_config(emitted_fork=CAPELLA) +@with_presets([MINIMAL], reason="too slow") +def test_capella_fork(spec, phases, state): + yield from run_test_single_fork(spec, phases, state, CAPELLA) + + +@with_phases(phases=[CAPELLA], other_phases=[EIP4844]) +@spec_test +@with_config_overrides({ + 'EIP4844_FORK_EPOCH': 3, # `setup_test` advances to epoch 2 +}, emit=False) +@with_state +@with_matching_spec_config(emitted_fork=EIP4844) +@with_presets([MINIMAL], reason="too slow") +def test_eip4844_fork(spec, phases, state): + yield from run_test_single_fork(spec, phases, state, EIP4844) + + +def run_test_upgraded_store_with_legacy_data(spec, phases, state, fork): # Start test (Legacy bootstrap with an upgraded store) - test = yield from setup_test(spec, state, s_spec, phases) + test = yield from setup_test(spec, state, phases[fork], phases) # Initial `LightClientUpdate` (check that the upgraded store can process it) finalized_block = spec.SignedBeaconBlock() @@ -760,7 +771,7 @@ def run_test_upgraded_store_with_legacy_data(spec, state, s_spec, phases): @with_matching_spec_config(emitted_fork=CAPELLA) @with_presets([MINIMAL], reason="too slow") def test_capella_store_with_legacy_data(spec, phases, state): - yield from run_test_upgraded_store_with_legacy_data(spec, state, phases[CAPELLA], phases) + yield from run_test_upgraded_store_with_legacy_data(spec, phases, state, CAPELLA) @with_phases(phases=[ALTAIR, BELLATRIX, CAPELLA], other_phases=[EIP4844]) @@ -769,4 +780,4 @@ def test_capella_store_with_legacy_data(spec, phases, state): @with_matching_spec_config(emitted_fork=EIP4844) @with_presets([MINIMAL], reason="too slow") def test_eip4844_store_with_legacy_data(spec, phases, state): - yield from run_test_upgraded_store_with_legacy_data(spec, state, phases[EIP4844], phases) + yield from run_test_upgraded_store_with_legacy_data(spec, phases, state, EIP4844) From ce7fd412cc9b29747690f5b44004e27feae86241 Mon Sep 17 00:00:00 2001 From: Etan Kissling Date: Wed, 4 Jan 2023 19:44:10 +0100 Subject: [PATCH 045/158] Add test for LC data spanning 3 forks --- .../test/altair/light_client/test_sync.py | 49 +++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/tests/core/pyspec/eth2spec/test/altair/light_client/test_sync.py b/tests/core/pyspec/eth2spec/test/altair/light_client/test_sync.py index 9c90b63fa..beb9350e2 100644 --- a/tests/core/pyspec/eth2spec/test/altair/light_client/test_sync.py +++ b/tests/core/pyspec/eth2spec/test/altair/light_client/test_sync.py @@ -743,6 +743,55 @@ def test_eip4844_fork(spec, phases, state): yield from run_test_single_fork(spec, phases, state, EIP4844) +def run_test_multi_fork(spec, phases, state, fork_1, fork_2): + # Start test + test = yield from setup_test(spec, state, phases[fork_2], phases) + + # Set up so that finalized is from `spec`, ... + finalized_block = spec.SignedBeaconBlock() + finalized_block.message.state_root = state.hash_tree_root() + finalized_state = state.copy() + + # ..., attested is from `fork_1`, ... + fork_1_epoch = getattr(phases[fork_1].config, fork_1.upper() + '_FORK_EPOCH') + transition_to(spec, state, spec.compute_start_slot_at_epoch(fork_1_epoch) - 1) + state, _ = do_fork(state, spec, phases[fork_1], fork_1_epoch, with_block=False) + spec = phases[fork_1] + attested_block = state_transition_with_full_block(spec, state, True, True) + attested_state = state.copy() + + # ..., and signature is from `fork_2` + fork_2_epoch = getattr(phases[fork_2].config, fork_2.upper() + '_FORK_EPOCH') + transition_to(spec, state, spec.compute_start_slot_at_epoch(fork_2_epoch) - 1) + state, _ = do_fork(state, spec, phases[fork_2], fork_2_epoch, with_block=False) + spec = phases[fork_2] + sync_aggregate, _ = get_sync_aggregate(spec, state) + block = state_transition_with_full_block(spec, state, True, True, sync_aggregate=sync_aggregate) + + # Check that update applies + yield from emit_update(test, spec, state, block, attested_state, attested_block, finalized_block, phases=phases) + assert test.s_spec.get_lc_beacon_slot(test.store.finalized_header) == finalized_state.slot + assert test.store.next_sync_committee == finalized_state.next_sync_committee + assert test.store.best_valid_update is None + assert test.s_spec.get_lc_beacon_slot(test.store.optimistic_header) == attested_state.slot + + # Finish test + yield from finish_test(test) + + +@with_phases(phases=[BELLATRIX], other_phases=[CAPELLA, EIP4844]) +@spec_test +@with_config_overrides({ + 'CAPELLA_FORK_EPOCH': 3, # `setup_test` advances to epoch 2 + 'EIP4844_FORK_EPOCH': 4, +}, emit=False) +@with_state +@with_matching_spec_config(emitted_fork=EIP4844) +@with_presets([MINIMAL], reason="too slow") +def test_capella_eip4844_fork(spec, phases, state): + yield from run_test_multi_fork(spec, phases, state, CAPELLA, EIP4844) + + def run_test_upgraded_store_with_legacy_data(spec, phases, state, fork): # Start test (Legacy bootstrap with an upgraded store) test = yield from setup_test(spec, state, phases[fork], phases) From 5c64a2047af9315db4ce3bd0eec0d81194311e46 Mon Sep 17 00:00:00 2001 From: Etan Kissling Date: Thu, 5 Jan 2023 13:36:04 +0100 Subject: [PATCH 046/158] Add `LightClientHeader` wrapper In Altair, light client sync protocol exchanges `BeaconBlockHeader` structures for tracking current progress. Wrapping `BeaconBlockHeader` inside a `LightClientHeader` allows future extensions of this header, e.g., to also track `ExecutionPayloadHeader`. Note: This changes the JSON REST format by adding a `beacon` nesting. For SSZ, the serialization format stays same (but overall root changes). --- specs/altair/light-client/full-node.md | 26 ++--- specs/altair/light-client/light-client.md | 2 +- specs/altair/light-client/p2p-interface.md | 24 ++--- specs/altair/light-client/sync-protocol.md | 101 ++++++++++-------- .../test/altair/light_client/test_sync.py | 74 ++++++------- .../light_client/test_update_ranking.py | 2 +- .../light_client/test_sync_protocol.py | 6 +- tests/formats/light_client/sync.md | 8 +- 8 files changed, 128 insertions(+), 115 deletions(-) diff --git a/specs/altair/light-client/full-node.md b/specs/altair/light-client/full-node.md index 7f0b7bc39..7dc25448c 100644 --- a/specs/altair/light-client/full-node.md +++ b/specs/altair/light-client/full-node.md @@ -38,13 +38,15 @@ def compute_merkle_proof_for_state(state: BeaconState, ### `block_to_light_client_header` ```python -def block_to_light_client_header(block: SignedBeaconBlock) -> BeaconBlockHeader: - return BeaconBlockHeader( - slot=block.message.slot, - proposer_index=block.message.proposer_index, - parent_root=block.message.parent_root, - state_root=block.message.state_root, - body_root=hash_tree_root(block.message.body), +def block_to_light_client_header(block: SignedBeaconBlock) -> LightClientHeader: + return LightClientHeader( + beacon=BeaconBlockHeader( + slot=block.message.slot, + proposer_index=block.message.proposer_index, + parent_root=block.message.parent_root, + state_root=block.message.state_root, + body_root=hash_tree_root(block.message.body), + ), ) ``` @@ -125,7 +127,7 @@ def create_light_client_update(state: BeaconState, if finalized_block is not None: if finalized_block.message.slot != GENESIS_SLOT: update.finalized_header = block_to_light_client_header(finalized_block) - assert hash_tree_root(update.finalized_header) == attested_state.finalized_checkpoint.root + assert hash_tree_root(update.finalized_header.beacon) == attested_state.finalized_checkpoint.root else: assert attested_state.finalized_checkpoint.root == Bytes32() update.finality_branch = compute_merkle_proof_for_state( @@ -139,8 +141,8 @@ def create_light_client_update(state: BeaconState, Full nodes SHOULD provide the best derivable `LightClientUpdate` (according to `is_better_update`) for each sync committee period covering any epochs in range `[max(ALTAIR_FORK_EPOCH, current_epoch - MIN_EPOCHS_FOR_BLOCK_REQUESTS), current_epoch]` where `current_epoch` is defined by the current wall-clock time. Full nodes MAY also provide `LightClientUpdate` for other sync committee periods. -- `LightClientUpdate` are assigned to sync committee periods based on their `attested_header.slot` -- `LightClientUpdate` are only considered if `compute_sync_committee_period_at_slot(update.attested_header.slot) == compute_sync_committee_period_at_slot(update.signature_slot)` +- `LightClientUpdate` are assigned to sync committee periods based on their `attested_header.beacon.slot` +- `LightClientUpdate` are only considered if `compute_sync_committee_period_at_slot(update.attested_header.beacon.slot) == compute_sync_committee_period_at_slot(update.signature_slot)` - Only `LightClientUpdate` with `next_sync_committee` as selected by fork choice are provided, regardless of ranking by `is_better_update`. To uniquely identify a non-finalized sync committee fork, all of `period`, `current_sync_committee` and `next_sync_committee` need to be incorporated, as sync committees may reappear over time. ### `create_light_client_finality_update` @@ -156,7 +158,7 @@ def create_light_client_finality_update(update: LightClientUpdate) -> LightClien ) ``` -Full nodes SHOULD provide the `LightClientFinalityUpdate` with the highest `attested_header.slot` (if multiple, highest `signature_slot`) as selected by fork choice, and SHOULD support a push mechanism to deliver new `LightClientFinalityUpdate` whenever `finalized_header` changes. +Full nodes SHOULD provide the `LightClientFinalityUpdate` with the highest `attested_header.beacon.slot` (if multiple, highest `signature_slot`) as selected by fork choice, and SHOULD support a push mechanism to deliver new `LightClientFinalityUpdate` whenever `finalized_header` changes. ### `create_light_client_optimistic_update` @@ -169,4 +171,4 @@ def create_light_client_optimistic_update(update: LightClientUpdate) -> LightCli ) ``` -Full nodes SHOULD provide the `LightClientOptimisticUpdate` with the highest `attested_header.slot` (if multiple, highest `signature_slot`) as selected by fork choice, and SHOULD support a push mechanism to deliver new `LightClientOptimisticUpdate` whenever `attested_header` changes. +Full nodes SHOULD provide the `LightClientOptimisticUpdate` with the highest `attested_header.beacon.slot` (if multiple, highest `signature_slot`) as selected by fork choice, and SHOULD support a push mechanism to deliver new `LightClientOptimisticUpdate` whenever `attested_header` changes. diff --git a/specs/altair/light-client/light-client.md b/specs/altair/light-client/light-client.md index 318950437..545c36a75 100644 --- a/specs/altair/light-client/light-client.md +++ b/specs/altair/light-client/light-client.md @@ -23,7 +23,7 @@ This document explains how light clients MAY obtain light client data to sync wi 1. The light client MUST be configured out-of-band with a spec/preset (including fork schedule), with `genesis_state` (including `genesis_time` and `genesis_validators_root`), and with a trusted block root. The trusted block SHOULD be within the weak subjectivity period, and its root SHOULD be from a finalized `Checkpoint`. 2. The local clock is initialized based on the configured `genesis_time`, and the current fork digest is determined to browse for and connect to relevant light client data providers. 3. The light client fetches a [`LightClientBootstrap`](./sync-protocol.md#lightclientbootstrap) object for the configured trusted block root. The `bootstrap` object is passed to [`initialize_light_client_store`](./sync-protocol.md#initialize_light_client_store) to obtain a local [`LightClientStore`](./sync-protocol.md#lightclientstore). -4. The light client tracks the sync committee periods `finalized_period` from `store.finalized_header.slot`, `optimistic_period` from `store.optimistic_header.slot`, and `current_period` from `current_slot` based on the local clock. +4. The light client tracks the sync committee periods `finalized_period` from `store.finalized_header.beacon.slot`, `optimistic_period` from `store.optimistic_header.beacon.slot`, and `current_period` from `current_slot` based on the local clock. 1. When `finalized_period == optimistic_period` and [`is_next_sync_committee_known`](./sync-protocol.md#is_next_sync_committee_known) indicates `False`, the light client fetches a [`LightClientUpdate`](./sync-protocol.md#lightclientupdate) for `finalized_period`. If `finalized_period == current_period`, this fetch SHOULD be scheduled at a random time before `current_period` advances. 2. When `finalized_period + 1 < current_period`, the light client fetches a `LightClientUpdate` for each sync committee period in range `[finalized_period + 1, current_period)` (current period excluded) 3. When `finalized_period + 1 >= current_period`, the light client keeps observing [`LightClientFinalityUpdate`](./sync-protocol.md#lightclientfinalityupdate) and [`LightClientOptimisticUpdate`](./sync-protocol.md#lightclientoptimisticupdate). Received objects are passed to [`process_light_client_finality_update`](./sync-protocol.md#process_light_client_finality_update) and [`process_light_client_optimistic_update`](./sync-protocol.md#process_light_client_optimistic_update). This ensures that `finalized_header` and `optimistic_header` reflect the latest blocks. diff --git a/specs/altair/light-client/p2p-interface.md b/specs/altair/light-client/p2p-interface.md index 501269ee2..c82fe9a2f 100644 --- a/specs/altair/light-client/p2p-interface.md +++ b/specs/altair/light-client/p2p-interface.md @@ -59,7 +59,7 @@ New global topics are added to provide light clients with the latest updates. This topic is used to propagate the latest `LightClientFinalityUpdate` to light clients, allowing them to keep track of the latest `finalized_header`. The following validations MUST pass before forwarding the `finality_update` on the network. -- _[IGNORE]_ The `finalized_header.slot` is greater than that of all previously forwarded `finality_update`s +- _[IGNORE]_ The `finalized_header.beacon.slot` is greater than that of all previously forwarded `finality_update`s - _[IGNORE]_ The `finality_update` is received after the block at `signature_slot` was given enough time to propagate through the network -- i.e. validate that one-third of `finality_update.signature_slot` has transpired (`SECONDS_PER_SLOT / INTERVALS_PER_SLOT` seconds after the start of the slot, with a `MAXIMUM_GOSSIP_CLOCK_DISPARITY` allowance) For full nodes, the following validations MUST additionally pass before forwarding the `finality_update` on the network. @@ -67,11 +67,11 @@ For full nodes, the following validations MUST additionally pass before forwardi For light clients, the following validations MUST additionally pass before forwarding the `finality_update` on the network. - _[REJECT]_ The `finality_update` is valid -- i.e. validate that `process_light_client_finality_update` does not indicate errors -- _[IGNORE]_ The `finality_update` advances the `finalized_header` of the local `LightClientStore` -- i.e. validate that processing `finality_update` increases `store.finalized_header.slot` +- _[IGNORE]_ The `finality_update` advances the `finalized_header` of the local `LightClientStore` -- i.e. validate that processing `finality_update` increases `store.finalized_header.beacon.slot` Light clients SHOULD call `process_light_client_finality_update` even if the message is ignored. -The gossip `ForkDigest`-context is determined based on `compute_fork_version(compute_epoch_at_slot(finality_update.attested_header.slot))`. +The gossip `ForkDigest`-context is determined based on `compute_fork_version(compute_epoch_at_slot(finality_update.attested_header.beacon.slot))`. Per `context = compute_fork_digest(fork_version, genesis_validators_root)`: @@ -87,7 +87,7 @@ Per `context = compute_fork_digest(fork_version, genesis_validators_root)`: This topic is used to propagate the latest `LightClientOptimisticUpdate` to light clients, allowing them to keep track of the latest `optimistic_header`. The following validations MUST pass before forwarding the `optimistic_update` on the network. -- _[IGNORE]_ The `attested_header.slot` is greater than that of all previously forwarded `optimistic_update`s +- _[IGNORE]_ The `attested_header.beacon.slot` is greater than that of all previously forwarded `optimistic_update`s - _[IGNORE]_ The `optimistic_update` is received after the block at `signature_slot` was given enough time to propagate through the network -- i.e. validate that one-third of `optimistic_update.signature_slot` has transpired (`SECONDS_PER_SLOT / INTERVALS_PER_SLOT` seconds after the start of the slot, with a `MAXIMUM_GOSSIP_CLOCK_DISPARITY` allowance) For full nodes, the following validations MUST additionally pass before forwarding the `optimistic_update` on the network. @@ -95,11 +95,11 @@ For full nodes, the following validations MUST additionally pass before forwardi For light clients, the following validations MUST additionally pass before forwarding the `optimistic_update` on the network. - _[REJECT]_ The `optimistic_update` is valid -- i.e. validate that `process_light_client_optimistic_update` does not indicate errors -- _[IGNORE]_ The `optimistic_update` either matches corresponding fields of the most recently forwarded `LightClientFinalityUpdate` (if any), or it advances the `optimistic_header` of the local `LightClientStore` -- i.e. validate that processing `optimistic_update` increases `store.optimistic_header.slot` +- _[IGNORE]_ The `optimistic_update` either matches corresponding fields of the most recently forwarded `LightClientFinalityUpdate` (if any), or it advances the `optimistic_header` of the local `LightClientStore` -- i.e. validate that processing `optimistic_update` increases `store.optimistic_header.beacon.slot` Light clients SHOULD call `process_light_client_optimistic_update` even if the message is ignored. -The gossip `ForkDigest`-context is determined based on `compute_fork_version(compute_epoch_at_slot(optimistic_update.attested_header.slot))`. +The gossip `ForkDigest`-context is determined based on `compute_fork_version(compute_epoch_at_slot(optimistic_update.attested_header.beacon.slot))`. Per `context = compute_fork_digest(fork_version, genesis_validators_root)`: @@ -142,7 +142,7 @@ Peers SHOULD provide results as defined in [`create_light_client_bootstrap`](./f When a `LightClientBootstrap` instance cannot be produced for a given block root, peers SHOULD respond with error code `3: ResourceUnavailable`. -A `ForkDigest`-context based on `compute_fork_version(compute_epoch_at_slot(bootstrap.header.slot))` is used to select the fork namespace of the Response type. +A `ForkDigest`-context based on `compute_fork_version(compute_epoch_at_slot(bootstrap.header.beacon.slot))` is used to select the fork namespace of the Response type. Per `context = compute_fork_digest(fork_version, genesis_validators_root)`: @@ -180,7 +180,7 @@ The response MUST consist of zero or more `response_chunk`. Each _successful_ `r Peers SHOULD provide results as defined in [`create_light_client_update`](./full-node.md#create_light_client_update). They MUST respond with at least the earliest known result within the requested range, and MUST send results in consecutive order (by period). The response MUST NOT contain more than `min(MAX_REQUEST_LIGHT_CLIENT_UPDATES, count)` results. -For each `response_chunk`, a `ForkDigest`-context based on `compute_fork_version(compute_epoch_at_slot(update.attested_header.slot))` is used to select the fork namespace of the Response type. Note that this `fork_version` may be different from the one used to verify the `update.sync_aggregate`, which is based on `update.signature_slot`. +For each `response_chunk`, a `ForkDigest`-context based on `compute_fork_version(compute_epoch_at_slot(update.attested_header.beacon.slot))` is used to select the fork namespace of the Response type. Note that this `fork_version` may be different from the one used to verify the `update.sync_aggregate`, which is based on `update.signature_slot`. Per `context = compute_fork_digest(fork_version, genesis_validators_root)`: @@ -211,7 +211,7 @@ Peers SHOULD provide results as defined in [`create_light_client_finality_update When no `LightClientFinalityUpdate` is available, peers SHOULD respond with error code `3: ResourceUnavailable`. -A `ForkDigest`-context based on `compute_fork_version(compute_epoch_at_slot(finality_update.attested_header.slot))` is used to select the fork namespace of the Response type. Note that this `fork_version` may be different from the one used to verify the `finality_update.sync_aggregate`, which is based on `finality_update.signature_slot`. +A `ForkDigest`-context based on `compute_fork_version(compute_epoch_at_slot(finality_update.attested_header.beacon.slot))` is used to select the fork namespace of the Response type. Note that this `fork_version` may be different from the one used to verify the `finality_update.sync_aggregate`, which is based on `finality_update.signature_slot`. Per `context = compute_fork_digest(fork_version, genesis_validators_root)`: @@ -242,7 +242,7 @@ Peers SHOULD provide results as defined in [`create_light_client_optimistic_upda When no `LightClientOptimisticUpdate` is available, peers SHOULD respond with error code `3: ResourceUnavailable`. -A `ForkDigest`-context based on `compute_fork_version(compute_epoch_at_slot(optimistic_update.attested_header.slot))` is used to select the fork namespace of the Response type. Note that this `fork_version` may be different from the one used to verify the `optimistic_update.sync_aggregate`, which is based on `optimistic_update.signature_slot`. +A `ForkDigest`-context based on `compute_fork_version(compute_epoch_at_slot(optimistic_update.attested_header.beacon.slot))` is used to select the fork namespace of the Response type. Note that this `fork_version` may be different from the one used to verify the `optimistic_update.sync_aggregate`, which is based on `optimistic_update.signature_slot`. Per `context = compute_fork_digest(fork_version, genesis_validators_root)`: @@ -273,7 +273,7 @@ All full nodes SHOULD subscribe to and provide stability on the [`light_client_f Whenever fork choice selects a new head block with a sync aggregate participation `>= MIN_SYNC_COMMITTEE_PARTICIPANTS` and a post-Altair parent block, full nodes with at least one validator assigned to the current sync committee at the block's `slot` SHOULD broadcast derived light client data as follows: -- If `finalized_header.slot` increased, a `LightClientFinalityUpdate` SHOULD be broadcasted to the pubsub topic `light_client_finality_update` if no matching message has not yet been forwarded as part of gossip validation. -- If `attested_header.slot` increased, a `LightClientOptimisticUpdate` SHOULD be broadcasted to the pubsub topic `light_client_optimistic_update` if no matching message has not yet been forwarded as part of gossip validation. +- If `finalized_header.beacon.slot` increased, a `LightClientFinalityUpdate` SHOULD be broadcasted to the pubsub topic `light_client_finality_update` if no matching message has not yet been forwarded as part of gossip validation. +- If `attested_header.beacon.slot` increased, a `LightClientOptimisticUpdate` SHOULD be broadcasted to the pubsub topic `light_client_optimistic_update` if no matching message has not yet been forwarded as part of gossip validation. These messages SHOULD be broadcasted after one-third of `slot` has transpired (`SECONDS_PER_SLOT / INTERVALS_PER_SLOT` seconds after the start of the slot). To ensure that the corresponding block was given enough time to propagate through the network, they SHOULD NOT be sent earlier. Note that this is different from how other messages are handled, e.g., attestations, which may be sent early. diff --git a/specs/altair/light-client/sync-protocol.md b/specs/altair/light-client/sync-protocol.md index 793483bc0..bbee8680b 100644 --- a/specs/altair/light-client/sync-protocol.md +++ b/specs/altair/light-client/sync-protocol.md @@ -13,6 +13,7 @@ - [Preset](#preset) - [Misc](#misc) - [Containers](#containers) + - [`LightClientHeader`](#lightclientheader) - [`LightClientBootstrap`](#lightclientbootstrap) - [`LightClientUpdate`](#lightclientupdate) - [`LightClientFinalityUpdate`](#lightclientfinalityupdate) @@ -73,13 +74,21 @@ Additional documents describe how the light client sync protocol can be used: ## Containers +### `LightClientHeader` + +```python +class LightClientHeader(Container): + # Beacon block header + beacon: BeaconBlockHeader +``` + ### `LightClientBootstrap` ```python class LightClientBootstrap(Container): # Header matching the requested beacon block root - header: BeaconBlockHeader - # Current sync committee corresponding to `header.state_root` + header: LightClientHeader + # Current sync committee corresponding to `header.beacon.state_root` current_sync_committee: SyncCommittee current_sync_committee_branch: Vector[Bytes32, floorlog2(CURRENT_SYNC_COMMITTEE_INDEX)] ``` @@ -89,12 +98,12 @@ class LightClientBootstrap(Container): ```python class LightClientUpdate(Container): # Header attested to by the sync committee - attested_header: BeaconBlockHeader - # Next sync committee corresponding to `attested_header.state_root` + attested_header: LightClientHeader + # Next sync committee corresponding to `attested_header.beacon.state_root` next_sync_committee: SyncCommittee next_sync_committee_branch: Vector[Bytes32, floorlog2(NEXT_SYNC_COMMITTEE_INDEX)] - # Finalized header corresponding to `attested_header.state_root` - finalized_header: BeaconBlockHeader + # Finalized header corresponding to `attested_header.beacon.state_root` + finalized_header: LightClientHeader finality_branch: Vector[Bytes32, floorlog2(FINALIZED_ROOT_INDEX)] # Sync committee aggregate signature sync_aggregate: SyncAggregate @@ -107,9 +116,9 @@ class LightClientUpdate(Container): ```python class LightClientFinalityUpdate(Container): # Header attested to by the sync committee - attested_header: BeaconBlockHeader - # Finalized header corresponding to `attested_header.state_root` - finalized_header: BeaconBlockHeader + attested_header: LightClientHeader + # Finalized header corresponding to `attested_header.beacon.state_root` + finalized_header: LightClientHeader finality_branch: Vector[Bytes32, floorlog2(FINALIZED_ROOT_INDEX)] # Sync committee aggregate signature sync_aggregate: SyncAggregate @@ -122,7 +131,7 @@ class LightClientFinalityUpdate(Container): ```python class LightClientOptimisticUpdate(Container): # Header attested to by the sync committee - attested_header: BeaconBlockHeader + attested_header: LightClientHeader # Sync committee aggregate signature sync_aggregate: SyncAggregate # Slot at which the aggregate signature was created (untrusted) @@ -135,14 +144,14 @@ class LightClientOptimisticUpdate(Container): @dataclass class LightClientStore(object): # Header that is finalized - finalized_header: BeaconBlockHeader + finalized_header: LightClientHeader # Sync committees corresponding to the finalized header current_sync_committee: SyncCommittee next_sync_committee: SyncCommittee # Best available header to switch finalized head to if we see nothing else best_valid_update: Optional[LightClientUpdate] # Most recent available reasonably-safe header - optimistic_header: BeaconBlockHeader + optimistic_header: LightClientHeader # Max number of active participants in a sync committee (used to calculate safety threshold) previous_max_active_participants: uint64 current_max_active_participants: uint64 @@ -181,11 +190,11 @@ def is_better_update(new_update: LightClientUpdate, old_update: LightClientUpdat # Compare presence of relevant sync committee new_has_relevant_sync_committee = is_sync_committee_update(new_update) and ( - compute_sync_committee_period_at_slot(new_update.attested_header.slot) + compute_sync_committee_period_at_slot(new_update.attested_header.beacon.slot) == compute_sync_committee_period_at_slot(new_update.signature_slot) ) old_has_relevant_sync_committee = is_sync_committee_update(old_update) and ( - compute_sync_committee_period_at_slot(old_update.attested_header.slot) + compute_sync_committee_period_at_slot(old_update.attested_header.beacon.slot) == compute_sync_committee_period_at_slot(old_update.signature_slot) ) if new_has_relevant_sync_committee != old_has_relevant_sync_committee: @@ -200,12 +209,12 @@ def is_better_update(new_update: LightClientUpdate, old_update: LightClientUpdat # Compare sync committee finality if new_has_finality: new_has_sync_committee_finality = ( - compute_sync_committee_period_at_slot(new_update.finalized_header.slot) - == compute_sync_committee_period_at_slot(new_update.attested_header.slot) + compute_sync_committee_period_at_slot(new_update.finalized_header.beacon.slot) + == compute_sync_committee_period_at_slot(new_update.attested_header.beacon.slot) ) old_has_sync_committee_finality = ( - compute_sync_committee_period_at_slot(old_update.finalized_header.slot) - == compute_sync_committee_period_at_slot(old_update.attested_header.slot) + compute_sync_committee_period_at_slot(old_update.finalized_header.beacon.slot) + == compute_sync_committee_period_at_slot(old_update.attested_header.beacon.slot) ) if new_has_sync_committee_finality != old_has_sync_committee_finality: return new_has_sync_committee_finality @@ -215,8 +224,8 @@ def is_better_update(new_update: LightClientUpdate, old_update: LightClientUpdat return new_num_active_participants > old_num_active_participants # Tiebreaker 2: Prefer older data (fewer changes to best) - if new_update.attested_header.slot != old_update.attested_header.slot: - return new_update.attested_header.slot < old_update.attested_header.slot + if new_update.attested_header.beacon.slot != old_update.attested_header.beacon.slot: + return new_update.attested_header.beacon.slot < old_update.attested_header.beacon.slot return new_update.signature_slot < old_update.signature_slot ``` @@ -260,14 +269,14 @@ A light client maintains its state in a `store` object of type `LightClientStore ```python def initialize_light_client_store(trusted_block_root: Root, bootstrap: LightClientBootstrap) -> LightClientStore: - assert hash_tree_root(bootstrap.header) == trusted_block_root + assert hash_tree_root(bootstrap.header.beacon) == trusted_block_root assert is_valid_merkle_branch( leaf=hash_tree_root(bootstrap.current_sync_committee), branch=bootstrap.current_sync_committee_branch, depth=floorlog2(CURRENT_SYNC_COMMITTEE_INDEX), index=get_subtree_index(CURRENT_SYNC_COMMITTEE_INDEX), - root=bootstrap.header.state_root, + root=bootstrap.header.beacon.state_root, ) return LightClientStore( @@ -301,8 +310,10 @@ def validate_light_client_update(store: LightClientStore, assert sum(sync_aggregate.sync_committee_bits) >= MIN_SYNC_COMMITTEE_PARTICIPANTS # Verify update does not skip a sync committee period - assert current_slot >= update.signature_slot > update.attested_header.slot >= update.finalized_header.slot - store_period = compute_sync_committee_period_at_slot(store.finalized_header.slot) + update_attested_slot = update.attested_header.beacon.slot + update_finalized_slot = update.finalized_header.beacon.slot + assert current_slot >= update.signature_slot > update_attested_slot >= update_finalized_slot + store_period = compute_sync_committee_period_at_slot(store.finalized_header.beacon.slot) update_signature_period = compute_sync_committee_period_at_slot(update.signature_slot) if is_next_sync_committee_known(store): assert update_signature_period in (store_period, store_period + 1) @@ -310,12 +321,12 @@ def validate_light_client_update(store: LightClientStore, assert update_signature_period == store_period # Verify update is relevant - update_attested_period = compute_sync_committee_period_at_slot(update.attested_header.slot) + update_attested_period = compute_sync_committee_period_at_slot(update_attested_slot) update_has_next_sync_committee = not is_next_sync_committee_known(store) and ( is_sync_committee_update(update) and update_attested_period == store_period ) assert ( - update.attested_header.slot > store.finalized_header.slot + update_attested_slot > store.finalized_header.beacon.slot or update_has_next_sync_committee ) @@ -323,19 +334,19 @@ def validate_light_client_update(store: LightClientStore, # to match the finalized checkpoint root saved in the state of `attested_header`. # Note that the genesis finalized checkpoint root is represented as a zero hash. if not is_finality_update(update): - assert update.finalized_header == BeaconBlockHeader() + assert update.finalized_header == LightClientHeader() else: - if update.finalized_header.slot == GENESIS_SLOT: - assert update.finalized_header == BeaconBlockHeader() + if update_finalized_slot == GENESIS_SLOT: + assert update.finalized_header == LightClientHeader() finalized_root = Bytes32() else: - finalized_root = hash_tree_root(update.finalized_header) + finalized_root = hash_tree_root(update.finalized_header.beacon) assert is_valid_merkle_branch( leaf=finalized_root, branch=update.finality_branch, depth=floorlog2(FINALIZED_ROOT_INDEX), index=get_subtree_index(FINALIZED_ROOT_INDEX), - root=update.attested_header.state_root, + root=update.attested_header.beacon.state_root, ) # Verify that the `next_sync_committee`, if present, actually is the next sync committee saved in the @@ -350,7 +361,7 @@ def validate_light_client_update(store: LightClientStore, branch=update.next_sync_committee_branch, depth=floorlog2(NEXT_SYNC_COMMITTEE_INDEX), index=get_subtree_index(NEXT_SYNC_COMMITTEE_INDEX), - root=update.attested_header.state_root, + root=update.attested_header.beacon.state_root, ) # Verify sync committee aggregate signature @@ -364,7 +375,7 @@ def validate_light_client_update(store: LightClientStore, ] fork_version = compute_fork_version(compute_epoch_at_slot(update.signature_slot)) domain = compute_domain(DOMAIN_SYNC_COMMITTEE, fork_version, genesis_validators_root) - signing_root = compute_signing_root(update.attested_header, domain) + signing_root = compute_signing_root(update.attested_header.beacon, domain) assert bls.FastAggregateVerify(participant_pubkeys, signing_root, sync_aggregate.sync_committee_signature) ``` @@ -372,8 +383,8 @@ def validate_light_client_update(store: LightClientStore, ```python def apply_light_client_update(store: LightClientStore, update: LightClientUpdate) -> None: - store_period = compute_sync_committee_period_at_slot(store.finalized_header.slot) - update_finalized_period = compute_sync_committee_period_at_slot(update.finalized_header.slot) + store_period = compute_sync_committee_period_at_slot(store.finalized_header.beacon.slot) + update_finalized_period = compute_sync_committee_period_at_slot(update.finalized_header.beacon.slot) if not is_next_sync_committee_known(store): assert update_finalized_period == store_period store.next_sync_committee = update.next_sync_committee @@ -382,9 +393,9 @@ def apply_light_client_update(store: LightClientStore, update: LightClientUpdate store.next_sync_committee = update.next_sync_committee store.previous_max_active_participants = store.current_max_active_participants store.current_max_active_participants = 0 - if update.finalized_header.slot > store.finalized_header.slot: + if update.finalized_header.beacon.slot > store.finalized_header.beacon.slot: store.finalized_header = update.finalized_header - if store.finalized_header.slot > store.optimistic_header.slot: + if store.finalized_header.beacon.slot > store.optimistic_header.beacon.slot: store.optimistic_header = store.finalized_header ``` @@ -393,14 +404,14 @@ def apply_light_client_update(store: LightClientStore, update: LightClientUpdate ```python def process_light_client_store_force_update(store: LightClientStore, current_slot: Slot) -> None: if ( - current_slot > store.finalized_header.slot + UPDATE_TIMEOUT + current_slot > store.finalized_header.beacon.slot + UPDATE_TIMEOUT and store.best_valid_update is not None ): # Forced best update when the update timeout has elapsed. - # Because the apply logic waits for `finalized_header.slot` to indicate sync committee finality, + # Because the apply logic waits for `finalized_header.beacon.slot` to indicate sync committee finality, # the `attested_header` may be treated as `finalized_header` in extended periods of non-finality # to guarantee progression into later sync committee periods according to `is_better_update`. - if store.best_valid_update.finalized_header.slot <= store.finalized_header.slot: + if store.best_valid_update.finalized_header.beacon.slot <= store.finalized_header.beacon.slot: store.best_valid_update.finalized_header = store.best_valid_update.attested_header apply_light_client_update(store, store.best_valid_update) store.best_valid_update = None @@ -433,7 +444,7 @@ def process_light_client_update(store: LightClientStore, # Update the optimistic header if ( sum(sync_committee_bits) > get_safety_threshold(store) - and update.attested_header.slot > store.optimistic_header.slot + and update.attested_header.beacon.slot > store.optimistic_header.beacon.slot ): store.optimistic_header = update.attested_header @@ -441,14 +452,14 @@ def process_light_client_update(store: LightClientStore, update_has_finalized_next_sync_committee = ( not is_next_sync_committee_known(store) and is_sync_committee_update(update) and is_finality_update(update) and ( - compute_sync_committee_period_at_slot(update.finalized_header.slot) - == compute_sync_committee_period_at_slot(update.attested_header.slot) + compute_sync_committee_period_at_slot(update.finalized_header.beacon.slot) + == compute_sync_committee_period_at_slot(update.attested_header.beacon.slot) ) ) if ( sum(sync_committee_bits) * 3 >= len(sync_committee_bits) * 2 and ( - update.finalized_header.slot > store.finalized_header.slot + update.finalized_header.beacon.slot > store.finalized_header.beacon.slot or update_has_finalized_next_sync_committee ) ): @@ -487,7 +498,7 @@ def process_light_client_optimistic_update(store: LightClientStore, attested_header=optimistic_update.attested_header, next_sync_committee=SyncCommittee(), next_sync_committee_branch=[Bytes32() for _ in range(floorlog2(NEXT_SYNC_COMMITTEE_INDEX))], - finalized_header=BeaconBlockHeader(), + finalized_header=LightClientHeader(), finality_branch=[Bytes32() for _ in range(floorlog2(FINALIZED_ROOT_INDEX))], sync_aggregate=optimistic_update.sync_aggregate, signature_slot=optimistic_update.signature_slot, diff --git a/tests/core/pyspec/eth2spec/test/altair/light_client/test_sync.py b/tests/core/pyspec/eth2spec/test/altair/light_client/test_sync.py index 1364c4bf1..c7e6b5dbe 100644 --- a/tests/core/pyspec/eth2spec/test/altair/light_client/test_sync.py +++ b/tests/core/pyspec/eth2spec/test/altair/light_client/test_sync.py @@ -56,18 +56,18 @@ def get_update_file_name(spec, update): suffix2 = "f" else: suffix2 = "x" - return f"update_{encode_hex(update.attested_header.hash_tree_root())}_{suffix1}{suffix2}" + return f"update_{encode_hex(update.attested_header.beacon.hash_tree_root())}_{suffix1}{suffix2}" def get_checks(store): return { "finalized_header": { - 'slot': int(store.finalized_header.slot), - 'beacon_root': encode_hex(store.finalized_header.hash_tree_root()), + 'slot': int(store.finalized_header.beacon.slot), + 'beacon_root': encode_hex(store.finalized_header.beacon.hash_tree_root()), }, "optimistic_header": { - 'slot': int(store.optimistic_header.slot), - 'beacon_root': encode_hex(store.optimistic_header.hash_tree_root()), + 'slot': int(store.optimistic_header.beacon.slot), + 'beacon_root': encode_hex(store.optimistic_header.beacon.hash_tree_root()), }, } @@ -141,10 +141,10 @@ def test_light_client_sync(spec, state): sync_aggregate, _ = get_sync_aggregate(spec, state) block = state_transition_with_full_block(spec, state, True, True, sync_aggregate=sync_aggregate) yield from emit_update(test, spec, state, block, attested_state, attested_block, finalized_block) - assert test.store.finalized_header.slot == finalized_state.slot + assert test.store.finalized_header.beacon.slot == finalized_state.slot assert test.store.next_sync_committee == finalized_state.next_sync_committee assert test.store.best_valid_update is None - assert test.store.optimistic_header.slot == attested_state.slot + assert test.store.optimistic_header.beacon.slot == attested_state.slot # Advance to next sync committee period # ``` @@ -167,10 +167,10 @@ def test_light_client_sync(spec, state): sync_aggregate, _ = get_sync_aggregate(spec, state) block = state_transition_with_full_block(spec, state, True, True, sync_aggregate=sync_aggregate) yield from emit_update(test, spec, state, block, attested_state, attested_block, finalized_block) - assert test.store.finalized_header.slot == finalized_state.slot + assert test.store.finalized_header.beacon.slot == finalized_state.slot assert test.store.next_sync_committee == finalized_state.next_sync_committee assert test.store.best_valid_update is None - assert test.store.optimistic_header.slot == attested_state.slot + assert test.store.optimistic_header.beacon.slot == attested_state.slot # Edge case: Signature in next period # ``` @@ -193,10 +193,10 @@ def test_light_client_sync(spec, state): sync_aggregate, _ = get_sync_aggregate(spec, state) block = state_transition_with_full_block(spec, state, True, True, sync_aggregate=sync_aggregate) yield from emit_update(test, spec, state, block, attested_state, attested_block, finalized_block) - assert test.store.finalized_header.slot == finalized_state.slot + assert test.store.finalized_header.beacon.slot == finalized_state.slot assert test.store.next_sync_committee == finalized_state.next_sync_committee assert test.store.best_valid_update is None - assert test.store.optimistic_header.slot == attested_state.slot + assert test.store.optimistic_header.beacon.slot == attested_state.slot # Edge case: Finalized header not included # ``` @@ -214,10 +214,10 @@ def test_light_client_sync(spec, state): sync_aggregate, _ = get_sync_aggregate(spec, state) block = state_transition_with_full_block(spec, state, True, True, sync_aggregate=sync_aggregate) update = yield from emit_update(test, spec, state, block, attested_state, attested_block, finalized_block=None) - assert test.store.finalized_header.slot == finalized_state.slot + assert test.store.finalized_header.beacon.slot == finalized_state.slot assert test.store.next_sync_committee == finalized_state.next_sync_committee assert test.store.best_valid_update == update - assert test.store.optimistic_header.slot == attested_state.slot + assert test.store.optimistic_header.beacon.slot == attested_state.slot # Non-finalized case: Attested `next_sync_committee` is not finalized # ``` @@ -236,10 +236,10 @@ def test_light_client_sync(spec, state): sync_aggregate, _ = get_sync_aggregate(spec, state) block = state_transition_with_full_block(spec, state, True, True, sync_aggregate=sync_aggregate) update = yield from emit_update(test, spec, state, block, attested_state, attested_block, finalized_block) - assert test.store.finalized_header.slot == finalized_state.slot + assert test.store.finalized_header.beacon.slot == finalized_state.slot assert test.store.next_sync_committee == finalized_state.next_sync_committee assert test.store.best_valid_update == update - assert test.store.optimistic_header.slot == attested_state.slot + assert test.store.optimistic_header.beacon.slot == attested_state.slot # Force-update using timeout # ``` @@ -256,10 +256,10 @@ def test_light_client_sync(spec, state): attested_state = state.copy() next_slots(spec, state, spec.UPDATE_TIMEOUT - 1) yield from emit_force_update(test, spec, state) - assert test.store.finalized_header.slot == store_state.slot + assert test.store.finalized_header.beacon.slot == store_state.slot assert test.store.next_sync_committee == store_state.next_sync_committee assert test.store.best_valid_update is None - assert test.store.optimistic_header.slot == store_state.slot + assert test.store.optimistic_header.beacon.slot == store_state.slot # Edge case: Finalized header not included, after force-update # ``` @@ -275,10 +275,10 @@ def test_light_client_sync(spec, state): sync_aggregate, _ = get_sync_aggregate(spec, state) block = state_transition_with_full_block(spec, state, True, True, sync_aggregate=sync_aggregate) update = yield from emit_update(test, spec, state, block, attested_state, attested_block, finalized_block=None) - assert test.store.finalized_header.slot == store_state.slot + assert test.store.finalized_header.beacon.slot == store_state.slot assert test.store.next_sync_committee == store_state.next_sync_committee assert test.store.best_valid_update == update - assert test.store.optimistic_header.slot == attested_state.slot + assert test.store.optimistic_header.beacon.slot == attested_state.slot # Edge case: Finalized header older than store # ``` @@ -296,15 +296,15 @@ def test_light_client_sync(spec, state): sync_aggregate, _ = get_sync_aggregate(spec, state) block = state_transition_with_full_block(spec, state, True, True, sync_aggregate=sync_aggregate) update = yield from emit_update(test, spec, state, block, attested_state, attested_block, finalized_block) - assert test.store.finalized_header.slot == store_state.slot + assert test.store.finalized_header.beacon.slot == store_state.slot assert test.store.next_sync_committee == store_state.next_sync_committee assert test.store.best_valid_update == update - assert test.store.optimistic_header.slot == attested_state.slot + assert test.store.optimistic_header.beacon.slot == attested_state.slot yield from emit_force_update(test, spec, state) - assert test.store.finalized_header.slot == attested_state.slot + assert test.store.finalized_header.beacon.slot == attested_state.slot assert test.store.next_sync_committee == attested_state.next_sync_committee assert test.store.best_valid_update is None - assert test.store.optimistic_header.slot == attested_state.slot + assert test.store.optimistic_header.beacon.slot == attested_state.slot # Advance to next sync committee period # ``` @@ -327,10 +327,10 @@ def test_light_client_sync(spec, state): sync_aggregate, _ = get_sync_aggregate(spec, state) block = state_transition_with_full_block(spec, state, True, True, sync_aggregate=sync_aggregate) yield from emit_update(test, spec, state, block, attested_state, attested_block, finalized_block) - assert test.store.finalized_header.slot == finalized_state.slot + assert test.store.finalized_header.beacon.slot == finalized_state.slot assert test.store.next_sync_committee == finalized_state.next_sync_committee assert test.store.best_valid_update is None - assert test.store.optimistic_header.slot == attested_state.slot + assert test.store.optimistic_header.beacon.slot == attested_state.slot # Finish test yield from finish_test(test) @@ -357,10 +357,10 @@ def test_supply_sync_committee_from_past_update(spec, state): # Apply `LightClientUpdate` from the past, populating `store.next_sync_committee` yield from emit_update(test, spec, past_state, block, attested_state, attested_block, finalized_block) - assert test.store.finalized_header.slot == state.slot + assert test.store.finalized_header.beacon.slot == state.slot assert test.store.next_sync_committee == finalized_state.next_sync_committee assert test.store.best_valid_update is None - assert test.store.optimistic_header.slot == state.slot + assert test.store.optimistic_header.beacon.slot == state.slot # Finish test yield from finish_test(test) @@ -383,10 +383,10 @@ def test_advance_finality_without_sync_committee(spec, state): sync_aggregate, _ = get_sync_aggregate(spec, state) block = state_transition_with_full_block(spec, state, True, True, sync_aggregate=sync_aggregate) yield from emit_update(test, spec, state, block, attested_state, attested_block, finalized_block) - assert test.store.finalized_header.slot == finalized_state.slot + assert test.store.finalized_header.beacon.slot == finalized_state.slot assert test.store.next_sync_committee == finalized_state.next_sync_committee assert test.store.best_valid_update is None - assert test.store.optimistic_header.slot == attested_state.slot + assert test.store.optimistic_header.beacon.slot == attested_state.slot # Advance finality into next sync committee period, but omit `next_sync_committee` transition_to(spec, state, compute_start_slot_at_next_sync_committee_period(spec, state)) @@ -402,10 +402,10 @@ def test_advance_finality_without_sync_committee(spec, state): sync_aggregate, _ = get_sync_aggregate(spec, state) block = state_transition_with_full_block(spec, state, True, True, sync_aggregate=sync_aggregate) yield from emit_update(test, spec, state, block, attested_state, attested_block, finalized_block, with_next=False) - assert test.store.finalized_header.slot == finalized_state.slot + assert test.store.finalized_header.beacon.slot == finalized_state.slot assert not spec.is_next_sync_committee_known(test.store) assert test.store.best_valid_update is None - assert test.store.optimistic_header.slot == attested_state.slot + assert test.store.optimistic_header.beacon.slot == attested_state.slot # Advance finality once more, with `next_sync_committee` still unknown past_state = finalized_state @@ -419,24 +419,24 @@ def test_advance_finality_without_sync_committee(spec, state): # Apply `LightClientUpdate` without `finalized_header` nor `next_sync_committee` update = yield from emit_update(test, spec, state, block, attested_state, attested_block, None, with_next=False) - assert test.store.finalized_header.slot == past_state.slot + assert test.store.finalized_header.beacon.slot == past_state.slot assert not spec.is_next_sync_committee_known(test.store) assert test.store.best_valid_update == update - assert test.store.optimistic_header.slot == attested_state.slot + assert test.store.optimistic_header.beacon.slot == attested_state.slot # Apply `LightClientUpdate` with `finalized_header` but no `next_sync_committee` yield from emit_update(test, spec, state, block, attested_state, attested_block, finalized_block, with_next=False) - assert test.store.finalized_header.slot == finalized_state.slot + assert test.store.finalized_header.beacon.slot == finalized_state.slot assert not spec.is_next_sync_committee_known(test.store) assert test.store.best_valid_update is None - assert test.store.optimistic_header.slot == attested_state.slot + assert test.store.optimistic_header.beacon.slot == attested_state.slot # Apply full `LightClientUpdate`, supplying `next_sync_committee` yield from emit_update(test, spec, state, block, attested_state, attested_block, finalized_block) - assert test.store.finalized_header.slot == finalized_state.slot + assert test.store.finalized_header.beacon.slot == finalized_state.slot assert test.store.next_sync_committee == finalized_state.next_sync_committee assert test.store.best_valid_update is None - assert test.store.optimistic_header.slot == attested_state.slot + assert test.store.optimistic_header.beacon.slot == attested_state.slot # Finish test yield from finish_test(test) diff --git a/tests/core/pyspec/eth2spec/test/altair/light_client/test_update_ranking.py b/tests/core/pyspec/eth2spec/test/altair/light_client/test_update_ranking.py index bde70a940..75f1a568a 100644 --- a/tests/core/pyspec/eth2spec/test/altair/light_client/test_update_ranking.py +++ b/tests/core/pyspec/eth2spec/test/altair/light_client/test_update_ranking.py @@ -37,7 +37,7 @@ def test_update_ranking(spec, state): # - `sig_finalized` / `sig_attested` --> Only signature in next sync committee period # - `att_finalized` / `att_attested` --> Attested header also in next sync committee period # - `fin_finalized` / `fin_attested` --> Finalized header also in next sync committee period - # - `lat_finalized` / `lat_attested` --> Like `fin`, but at a later `attested_header.slot` + # - `lat_finalized` / `lat_attested` --> Like `fin`, but at a later `attested_header.beacon.slot` next_slots(spec, state, spec.compute_start_slot_at_epoch(spec.EPOCHS_PER_SYNC_COMMITTEE_PERIOD - 3) - 1) sig_finalized_block = state_transition_with_full_block(spec, state, True, True) _, _, state = next_slots_with_attestations(spec, state, spec.SLOTS_PER_EPOCH - 1, True, True) diff --git a/tests/core/pyspec/eth2spec/test/altair/unittests/light_client/test_sync_protocol.py b/tests/core/pyspec/eth2spec/test/altair/unittests/light_client/test_sync_protocol.py index a72f1980b..235f9a8b1 100644 --- a/tests/core/pyspec/eth2spec/test/altair/unittests/light_client/test_sync_protocol.py +++ b/tests/core/pyspec/eth2spec/test/altair/unittests/light_client/test_sync_protocol.py @@ -69,7 +69,7 @@ def test_process_light_client_update_at_period_boundary(spec, state): # Forward to slot before next sync committee period so that next block is final one in period next_slots(spec, state, spec.UPDATE_TIMEOUT - 2) - store_period = spec.compute_sync_committee_period_at_slot(store.optimistic_header.slot) + store_period = spec.compute_sync_committee_period_at_slot(store.optimistic_header.beacon.slot) update_period = spec.compute_sync_committee_period_at_slot(state.slot) assert store_period == update_period @@ -104,7 +104,7 @@ def test_process_light_client_update_timeout(spec, state): # Forward to next sync committee period next_slots(spec, state, spec.UPDATE_TIMEOUT) - store_period = spec.compute_sync_committee_period_at_slot(store.optimistic_header.slot) + store_period = spec.compute_sync_committee_period_at_slot(store.optimistic_header.beacon.slot) update_period = spec.compute_sync_committee_period_at_slot(state.slot) assert store_period + 1 == update_period @@ -146,7 +146,7 @@ def test_process_light_client_update_finality_updated(spec, state): # Ensure that finality checkpoint has changed assert state.finalized_checkpoint.epoch == 3 # Ensure that it's same period - store_period = spec.compute_sync_committee_period_at_slot(store.optimistic_header.slot) + store_period = spec.compute_sync_committee_period_at_slot(store.optimistic_header.beacon.slot) update_period = spec.compute_sync_committee_period_at_slot(state.slot) assert store_period == update_period diff --git a/tests/formats/light_client/sync.md b/tests/formats/light_client/sync.md index 4d7162c3b..41aeec49b 100644 --- a/tests/formats/light_client/sync.md +++ b/tests/formats/light_client/sync.md @@ -25,12 +25,12 @@ Each step includes checks to verify the expected impact on the `store` object. ```yaml finalized_header: { - slot: int, -- Integer value from store.finalized_header.slot - beacon_root: string, -- Encoded 32-byte value from store.finalized_header.hash_tree_root() + slot: int, -- Integer value from store.finalized_header.beacon.slot + beacon_root: string, -- Encoded 32-byte value from store.finalized_header.beacon.hash_tree_root() } optimistic_header: { - slot: int, -- Integer value from store.optimistic_header.slot - beacon_root: string, -- Encoded 32-byte value from store.optimistic_header.hash_tree_root() + slot: int, -- Integer value from store.optimistic_header.beacon.slot + beacon_root: string, -- Encoded 32-byte value from store.optimistic_header.beacon.hash_tree_root() } ``` From 82e9631c5180432b7e3e73570ef100c551ca7d3a Mon Sep 17 00:00:00 2001 From: parithosh Date: Thu, 5 Jan 2023 14:09:18 +0100 Subject: [PATCH 047/158] add cache to linter and codespell --- .github/workflows/run-tests.yml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/.github/workflows/run-tests.yml b/.github/workflows/run-tests.yml index 3e23d1910..21c286eae 100644 --- a/.github/workflows/run-tests.yml +++ b/.github/workflows/run-tests.yml @@ -70,6 +70,11 @@ jobs: runs-on: self-hosted needs: setup-env steps: + - uses: actions/cache@v3.2.2 + id: restore-build + with: + path: ./* + key: ${{ github.sha }} - name: Check codespell run: pip install 'codespell<3.0.0,>=2.0.0' --user && make codespell @@ -77,6 +82,11 @@ jobs: runs-on: self-hosted needs: setup-env steps: + - uses: actions/cache@v3.2.2 + id: restore-build + with: + path: ./* + key: ${{ github.sha }} - name: Run linter for pyspec run: make lint - name: Run linter for test generators From fd05a7c023bcd0847846a01b948a62df61b755bd Mon Sep 17 00:00:00 2001 From: parithosh Date: Thu, 5 Jan 2023 14:14:38 +0100 Subject: [PATCH 048/158] remove cache fully --- .github/workflows/run-tests.yml | 55 ++++++++++++--------------------- 1 file changed, 19 insertions(+), 36 deletions(-) diff --git a/.github/workflows/run-tests.yml b/.github/workflows/run-tests.yml index 21c286eae..3bab00950 100644 --- a/.github/workflows/run-tests.yml +++ b/.github/workflows/run-tests.yml @@ -30,7 +30,7 @@ on: - cron: '0 0 * * *' jobs: - precleanup: + preclear: runs-on: self-hosted if: always() steps: @@ -40,53 +40,37 @@ jobs: rm -rf ./* || true rm -rf ./.??* || true ls -la ./ - setup-env: - runs-on: self-hosted - needs: precleanup - steps: + + table_of_contents: + runs-on: self-hosted + needs: preclear + steps: - name: Checkout this repo uses: actions/checkout@v3.2.0 with: ref: ${{ github.event.inputs.commitRef || env.DEFAULT_BRANCH }} - - uses: actions/cache@v3.2.2 - id: cache-git - with: - path: ./* - key: ${{ github.sha }} - - table_of_contents: - runs-on: self-hosted - needs: setup-env - steps: - - uses: actions/cache@v3.2.2 - id: restore-build - with: - path: ./* - key: ${{ github.sha }} - name: Check table of contents run: sudo npm install -g doctoc@2 && make check_toc codespell: runs-on: self-hosted - needs: setup-env + needs: preclear steps: - - uses: actions/cache@v3.2.2 - id: restore-build + - name: Checkout this repo + uses: actions/checkout@v3.2.0 with: - path: ./* - key: ${{ github.sha }} + ref: ${{ github.event.inputs.commitRef || env.DEFAULT_BRANCH }} - name: Check codespell run: pip install 'codespell<3.0.0,>=2.0.0' --user && make codespell lint: runs-on: self-hosted - needs: setup-env + needs: preclear steps: - - uses: actions/cache@v3.2.2 - id: restore-build + - name: Checkout this repo + uses: actions/checkout@v3.2.0 with: - path: ./* - key: ${{ github.sha }} + ref: ${{ github.event.inputs.commitRef || env.DEFAULT_BRANCH }} - name: Run linter for pyspec run: make lint - name: Run linter for test generators @@ -94,16 +78,15 @@ jobs: pyspec-tests: runs-on: self-hosted - needs: [setup-env,lint,codespell,table_of_contents] + needs: [preclear,lint,codespell,table_of_contents] strategy: matrix: version: ["phase0", "altair", "bellatrix", "capella", "eip4844"] steps: - - uses: actions/cache@v3.2.2 - id: restore-build + - name: Checkout this repo + uses: actions/checkout@v3.2.0 with: - path: ./* - key: ${{ github.sha }} + ref: ${{ github.event.inputs.commitRef || env.DEFAULT_BRANCH }} - name: set TEST_PRESET_TYPE if: github.event.inputs.test_preset_type != '' run: | @@ -132,7 +115,7 @@ jobs: cleanup: runs-on: self-hosted - needs: [setup-env,pyspec-tests,codespell,lint,table_of_contents] + needs: [preclear,pyspec-tests,codespell,lint,table_of_contents] if: always() steps: - name: 'Cleanup build folder' From e937e2abbc48aad805d15df64480168ab993b98d Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Fri, 6 Jan 2023 13:08:32 +0800 Subject: [PATCH 049/158] Apply suggestions from code review Co-authored-by: Danny Ryan --- specs/eip4844/fork-choice.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/specs/eip4844/fork-choice.md b/specs/eip4844/fork-choice.md index bc25eeae7..2613bbb7e 100644 --- a/specs/eip4844/fork-choice.md +++ b/specs/eip4844/fork-choice.md @@ -22,8 +22,8 @@ This is the modification of the fork choice according to the executable beacon c #### `is_data_available` -The implementation of `is_data_available` will become more sophisticated during later sharding upgrades. -Initially, it requires every verifying actor to retrieve the matching `BlobsSidecar`, +The implementation of `is_data_available` will become more sophisticated during later scaling upgrades. +Initially, verification requires every verifying actor to retrieve the matching `BlobsSidecar`, and validate the sidecar with `validate_blobs_sidecar`. The block MUST NOT be considered valid until a valid `BlobsSidecar` has been downloaded. Blocks that have been previously validated as available SHOULD be considered available even if the associated `BlobsSidecar` has subsequently been pruned. @@ -69,7 +69,8 @@ def on_block(store: Store, signed_block: SignedBeaconBlock) -> None: assert get_ancestor(store, block.parent_root, finalized_slot) == store.finalized_checkpoint.root # [New in EIP-4844] - # Check if the block is available + # Check if blob data is available + # If not, this block MAY be queued and subsequently considered when blob data becomes available assert is_data_available(block.slot, hash_tree_root(block), block.body.blob_kzg_commitments) # Check the block is valid and compute the post-state From d679b2e80d4b8c0a9ffa7198df89f0213e67b3ef Mon Sep 17 00:00:00 2001 From: Danny Ryan Date: Fri, 6 Jan 2023 08:06:39 -0700 Subject: [PATCH 050/158] Update specs/capella/beacon-chain.md --- specs/capella/beacon-chain.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/specs/capella/beacon-chain.md b/specs/capella/beacon-chain.md index 5d0df0edd..9a04f2f38 100644 --- a/specs/capella/beacon-chain.md +++ b/specs/capella/beacon-chain.md @@ -53,9 +53,10 @@ to validator withdrawals. Including: * Operation to change from `BLS_WITHDRAWAL_PREFIX` to `ETH1_ADDRESS_WITHDRAWAL_PREFIX` versioned withdrawal credentials to enable withdrawals for a validator. -Another new feature is the new state/block historical accumulators. It becomes possible to validate -the entire block history that led up to that particular state without executing the transitions -and checking them one by one in backward order using a parent chain. +Another new feature is the new independent state and block historical accumulators +that replace the original singular historical roots. With these accumulators, it becomes possible to validate +the entire block history that led up to that particular state without any additional information +beyond the state and the blocks. ## Custom types From 8255618206fdd9507e1405716918cfb82d5f17f5 Mon Sep 17 00:00:00 2001 From: Danny Ryan Date: Fri, 6 Jan 2023 08:16:14 -0700 Subject: [PATCH 051/158] bump VERSION.txt to 1.3.0-rc.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 79c724242..b73f10e65 100644 --- a/tests/core/pyspec/eth2spec/VERSION.txt +++ b/tests/core/pyspec/eth2spec/VERSION.txt @@ -1 +1 @@ -1.3.0-alpha.2 +1.3.0-rc.0 From e154b3414c30131ce970d8319d00d997ede4a162 Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Fri, 6 Jan 2023 23:19:44 +0800 Subject: [PATCH 052/158] Move `validate_blobs_sidecar` to fork-choice and add spec into execution spec scope --- setup.py | 1 + specs/eip4844/beacon-chain.md | 17 ----------------- specs/eip4844/fork-choice.md | 17 +++++++++++++++++ .../{validator => fork_choice}/__init__.py | 0 .../test_validate_blobs_sidecar.py} | 0 5 files changed, 18 insertions(+), 17 deletions(-) rename tests/core/pyspec/eth2spec/test/eip4844/unittests/{validator => fork_choice}/__init__.py (100%) rename tests/core/pyspec/eth2spec/test/eip4844/unittests/{validator/test_validator.py => fork_choice/test_validate_blobs_sidecar.py} (100%) diff --git a/setup.py b/setup.py index be8be6d90..28d55f07e 100644 --- a/setup.py +++ b/setup.py @@ -1020,6 +1020,7 @@ class PySpecCommand(Command): self.md_doc_paths += """ specs/eip4844/beacon-chain.md specs/eip4844/fork.md + specs/eip4844/fork-choice.md specs/eip4844/polynomial-commitments.md specs/eip4844/p2p-interface.md specs/eip4844/validator.md diff --git a/specs/eip4844/beacon-chain.md b/specs/eip4844/beacon-chain.md index e62c455d6..8b0224f86 100644 --- a/specs/eip4844/beacon-chain.md +++ b/specs/eip4844/beacon-chain.md @@ -22,7 +22,6 @@ - [`ExecutionPayloadHeader`](#executionpayloadheader) - [Helper functions](#helper-functions) - [Misc](#misc) - - [`validate_blobs_sidecar`](#validate_blobs_sidecar) - [`kzg_commitment_to_versioned_hash`](#kzg_commitment_to_versioned_hash) - [`tx_peek_blob_versioned_hashes`](#tx_peek_blob_versioned_hashes) - [`verify_kzg_commitments_against_transactions`](#verify_kzg_commitments_against_transactions) @@ -145,22 +144,6 @@ class ExecutionPayloadHeader(Container): ### Misc -#### `validate_blobs_sidecar` - -```python -def validate_blobs_sidecar(slot: Slot, - beacon_block_root: Root, - expected_kzg_commitments: Sequence[KZGCommitment], - blobs_sidecar: BlobsSidecar) -> None: - assert slot == blobs_sidecar.beacon_block_slot - assert beacon_block_root == blobs_sidecar.beacon_block_root - blobs = blobs_sidecar.blobs - kzg_aggregated_proof = blobs_sidecar.kzg_aggregated_proof - assert len(expected_kzg_commitments) == len(blobs) - - assert verify_aggregate_kzg_proof(blobs, expected_kzg_commitments, kzg_aggregated_proof) -``` - #### `kzg_commitment_to_versioned_hash` ```python diff --git a/specs/eip4844/fork-choice.md b/specs/eip4844/fork-choice.md index 2613bbb7e..ead394234 100644 --- a/specs/eip4844/fork-choice.md +++ b/specs/eip4844/fork-choice.md @@ -7,6 +7,7 @@ - [Introduction](#introduction) - [Helpers](#helpers) + - [`validate_blobs_sidecar`](#validate_blobs_sidecar) - [`is_data_available`](#is_data_available) - [Updated fork-choice handlers](#updated-fork-choice-handlers) - [`on_block`](#on_block) @@ -20,6 +21,22 @@ This is the modification of the fork choice according to the executable beacon c ## Helpers +#### `validate_blobs_sidecar` + +```python +def validate_blobs_sidecar(slot: Slot, + beacon_block_root: Root, + expected_kzg_commitments: Sequence[KZGCommitment], + blobs_sidecar: BlobsSidecar) -> None: + assert slot == blobs_sidecar.beacon_block_slot + assert beacon_block_root == blobs_sidecar.beacon_block_root + blobs = blobs_sidecar.blobs + kzg_aggregated_proof = blobs_sidecar.kzg_aggregated_proof + assert len(expected_kzg_commitments) == len(blobs) + + assert verify_aggregate_kzg_proof(blobs, expected_kzg_commitments, kzg_aggregated_proof) +``` + #### `is_data_available` The implementation of `is_data_available` will become more sophisticated during later scaling upgrades. diff --git a/tests/core/pyspec/eth2spec/test/eip4844/unittests/validator/__init__.py b/tests/core/pyspec/eth2spec/test/eip4844/unittests/fork_choice/__init__.py similarity index 100% rename from tests/core/pyspec/eth2spec/test/eip4844/unittests/validator/__init__.py rename to tests/core/pyspec/eth2spec/test/eip4844/unittests/fork_choice/__init__.py diff --git a/tests/core/pyspec/eth2spec/test/eip4844/unittests/validator/test_validator.py b/tests/core/pyspec/eth2spec/test/eip4844/unittests/fork_choice/test_validate_blobs_sidecar.py similarity index 100% rename from tests/core/pyspec/eth2spec/test/eip4844/unittests/validator/test_validator.py rename to tests/core/pyspec/eth2spec/test/eip4844/unittests/fork_choice/test_validate_blobs_sidecar.py From c9f8e4fef845b2b03a7790ede72c10e13f052187 Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Fri, 6 Jan 2023 23:39:04 +0800 Subject: [PATCH 053/158] Move `BlobsSidecar` --- specs/eip4844/fork-choice.md | 14 ++++++++++++++ specs/eip4844/p2p-interface.md | 11 ----------- 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/specs/eip4844/fork-choice.md b/specs/eip4844/fork-choice.md index ead394234..0937b66d7 100644 --- a/specs/eip4844/fork-choice.md +++ b/specs/eip4844/fork-choice.md @@ -6,6 +6,8 @@ - [Introduction](#introduction) +- [Containers](#containers) + - [`BlobsSidecar`](#blobssidecar) - [Helpers](#helpers) - [`validate_blobs_sidecar`](#validate_blobs_sidecar) - [`is_data_available`](#is_data_available) @@ -19,6 +21,18 @@ This is the modification of the fork choice according to the executable beacon chain proposal. +## Containers + +### `BlobsSidecar` + +```python +class BlobsSidecar(Container): + beacon_block_root: Root + beacon_block_slot: Slot + blobs: List[Blob, MAX_BLOBS_PER_BLOCK] + kzg_aggregated_proof: KZGProof +``` + ## Helpers #### `validate_blobs_sidecar` diff --git a/specs/eip4844/p2p-interface.md b/specs/eip4844/p2p-interface.md index 420a6da05..582331203 100644 --- a/specs/eip4844/p2p-interface.md +++ b/specs/eip4844/p2p-interface.md @@ -12,7 +12,6 @@ The specification of these changes continues in the same format as the network s - [Configuration](#configuration) - [Containers](#containers) - - [`BlobsSidecar`](#blobssidecar) - [`SignedBeaconBlockAndBlobsSidecar`](#signedbeaconblockandblobssidecar) - [The gossip domain: gossipsub](#the-gossip-domain-gossipsub) - [Topics and messages](#topics-and-messages) @@ -41,16 +40,6 @@ The specification of these changes continues in the same format as the network s ## Containers -### `BlobsSidecar` - -```python -class BlobsSidecar(Container): - beacon_block_root: Root - beacon_block_slot: Slot - blobs: List[Blob, MAX_BLOBS_PER_BLOCK] - kzg_aggregated_proof: KZGProof -``` - ### `SignedBeaconBlockAndBlobsSidecar` ```python From 4ba2266fd55f5e0bc330ad2a70090443c23871ac Mon Sep 17 00:00:00 2001 From: Danny Ryan Date: Fri, 6 Jan 2023 08:45:20 -0700 Subject: [PATCH 054/158] Update specs/eip4844/fork-choice.md --- specs/eip4844/fork-choice.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/specs/eip4844/fork-choice.md b/specs/eip4844/fork-choice.md index 0937b66d7..8dea28ded 100644 --- a/specs/eip4844/fork-choice.md +++ b/specs/eip4844/fork-choice.md @@ -19,7 +19,7 @@ ## Introduction -This is the modification of the fork choice according to the executable beacon chain proposal. +This is the modification of the fork choice accompanying the EIP-4844 upgrade. ## Containers From 8b14345143b65c45f35805fdff3af25965a0f5f1 Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Sat, 7 Jan 2023 01:49:23 +0800 Subject: [PATCH 055/158] Fix test file name --- ...ches_update.py => test_process_historical_summaries_update.py} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename tests/core/pyspec/eth2spec/test/capella/epoch_processing/{test_process_historical_batches_update.py => test_process_historical_summaries_update.py} (100%) diff --git a/tests/core/pyspec/eth2spec/test/capella/epoch_processing/test_process_historical_batches_update.py b/tests/core/pyspec/eth2spec/test/capella/epoch_processing/test_process_historical_summaries_update.py similarity index 100% rename from tests/core/pyspec/eth2spec/test/capella/epoch_processing/test_process_historical_batches_update.py rename to tests/core/pyspec/eth2spec/test/capella/epoch_processing/test_process_historical_summaries_update.py From 5230c1ba8738645ced8cbf94f3eb46efbbffd623 Mon Sep 17 00:00:00 2001 From: Etan Kissling Date: Fri, 6 Jan 2023 19:58:23 +0100 Subject: [PATCH 056/158] Add `is_valid_light_client_header` and comments --- specs/altair/light-client/sync-protocol.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/specs/altair/light-client/sync-protocol.md b/specs/altair/light-client/sync-protocol.md index bbee8680b..33994a0b8 100644 --- a/specs/altair/light-client/sync-protocol.md +++ b/specs/altair/light-client/sync-protocol.md @@ -22,6 +22,7 @@ - [Helper functions](#helper-functions) - [`is_sync_committee_update`](#is_sync_committee_update) - [`is_finality_update`](#is_finality_update) + - [`is_valid_light_client_header`](#is_valid_light_client_header) - [`is_better_update`](#is_better_update) - [`is_next_sync_committee_known`](#is_next_sync_committee_known) - [`get_safety_threshold`](#get_safety_threshold) @@ -82,6 +83,8 @@ class LightClientHeader(Container): beacon: BeaconBlockHeader ``` +Future upgrades may introduce additional fields to this structure, and validate them by extending [`is_valid_light_client_header`](#is_valid_light_client_header). + ### `LightClientBootstrap` ```python @@ -173,6 +176,14 @@ def is_finality_update(update: LightClientUpdate) -> bool: return update.finality_branch != [Bytes32() for _ in range(floorlog2(FINALIZED_ROOT_INDEX))] ``` +### `is_valid_light_client_header` + +```python +def is_valid_light_client_header(header: LightClientHeader) -> bool: + # pylint: disable=unused-argument + return True +``` + ### `is_better_update` ```python @@ -269,6 +280,7 @@ A light client maintains its state in a `store` object of type `LightClientStore ```python def initialize_light_client_store(trusted_block_root: Root, bootstrap: LightClientBootstrap) -> LightClientStore: + assert is_valid_light_client_header(bootstrap.header) assert hash_tree_root(bootstrap.header.beacon) == trusted_block_root assert is_valid_merkle_branch( @@ -310,6 +322,7 @@ def validate_light_client_update(store: LightClientStore, assert sum(sync_aggregate.sync_committee_bits) >= MIN_SYNC_COMMITTEE_PARTICIPANTS # Verify update does not skip a sync committee period + assert is_valid_light_client_header(update.attested_header) update_attested_slot = update.attested_header.beacon.slot update_finalized_slot = update.finalized_header.beacon.slot assert current_slot >= update.signature_slot > update_attested_slot >= update_finalized_slot @@ -340,6 +353,7 @@ def validate_light_client_update(store: LightClientStore, assert update.finalized_header == LightClientHeader() finalized_root = Bytes32() else: + assert is_valid_light_client_header(update.finalized_header) finalized_root = hash_tree_root(update.finalized_header.beacon) assert is_valid_merkle_branch( leaf=finalized_root, From b951ce077ac96510dbae8ed25451e69858d75a20 Mon Sep 17 00:00:00 2001 From: Etan Kissling Date: Fri, 6 Jan 2023 20:01:02 +0100 Subject: [PATCH 057/158] Move helper --- specs/altair/light-client/sync-protocol.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/specs/altair/light-client/sync-protocol.md b/specs/altair/light-client/sync-protocol.md index 33994a0b8..f1b012e98 100644 --- a/specs/altair/light-client/sync-protocol.md +++ b/specs/altair/light-client/sync-protocol.md @@ -20,9 +20,9 @@ - [`LightClientOptimisticUpdate`](#lightclientoptimisticupdate) - [`LightClientStore`](#lightclientstore) - [Helper functions](#helper-functions) + - [`is_valid_light_client_header`](#is_valid_light_client_header) - [`is_sync_committee_update`](#is_sync_committee_update) - [`is_finality_update`](#is_finality_update) - - [`is_valid_light_client_header`](#is_valid_light_client_header) - [`is_better_update`](#is_better_update) - [`is_next_sync_committee_known`](#is_next_sync_committee_known) - [`get_safety_threshold`](#get_safety_threshold) @@ -162,6 +162,14 @@ class LightClientStore(object): ## Helper functions +### `is_valid_light_client_header` + +```python +def is_valid_light_client_header(header: LightClientHeader) -> bool: + # pylint: disable=unused-argument + return True +``` + ### `is_sync_committee_update` ```python @@ -176,14 +184,6 @@ def is_finality_update(update: LightClientUpdate) -> bool: return update.finality_branch != [Bytes32() for _ in range(floorlog2(FINALIZED_ROOT_INDEX))] ``` -### `is_valid_light_client_header` - -```python -def is_valid_light_client_header(header: LightClientHeader) -> bool: - # pylint: disable=unused-argument - return True -``` - ### `is_better_update` ```python From d23d0147c8ded93f9b51811fa01dc945834f20ce Mon Sep 17 00:00:00 2001 From: GeemoCandama <104614073+GeemoCandama@users.noreply.github.com> Date: Sat, 7 Jan 2023 14:28:12 -0600 Subject: [PATCH 058/158] Update p2p-interface.md fixed typo --- specs/altair/light-client/p2p-interface.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/specs/altair/light-client/p2p-interface.md b/specs/altair/light-client/p2p-interface.md index 501269ee2..2326eed1f 100644 --- a/specs/altair/light-client/p2p-interface.md +++ b/specs/altair/light-client/p2p-interface.md @@ -255,7 +255,7 @@ Per `context = compute_fork_digest(fork_version, genesis_validators_root)`: ## Light clients -Light clients using libp2p to stay in sync with the network SHOULD subscribe to the [`light_client_finality_update`](#light_client_finality_update) and [`light_client_optimistic_update`](#light_client_optimistic_update) pubsub topics and validate all received messages while the [light client sync process](./light-client.md#light-client-sync-process) supports processing `LightClientFinalityUpdate` and `LightClientOptimistic` structures. +Light clients using libp2p to stay in sync with the network SHOULD subscribe to the [`light_client_finality_update`](#light_client_finality_update) and [`light_client_optimistic_update`](#light_client_optimistic_update) pubsub topics and validate all received messages while the [light client sync process](./light-client.md#light-client-sync-process) supports processing `LightClientFinalityUpdate` and `LightClientOptimisticUpdate` structures. Light clients MAY also collect historic light client data and make it available to other peers. If they do, they SHOULD advertise supported message endpoints in [the Req/Resp domain](#the-reqresp-domain), and MAY also update the contents of their [`Status`](../../phase0/p2p-interface.md#status) message to reflect the locally available light client data. From f057f530fe44e1b1df92d95f139e25033050cfc5 Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Tue, 10 Jan 2023 16:45:58 +0800 Subject: [PATCH 059/158] Add `historical_summaries` setup to fork.md --- specs/capella/fork.md | 6 ++++-- specs/eip4844/fork.md | 2 ++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/specs/capella/fork.md b/specs/capella/fork.md index e2493d33b..49bf8744f 100644 --- a/specs/capella/fork.md +++ b/specs/capella/fork.md @@ -129,8 +129,10 @@ def upgrade_to_capella(pre: bellatrix.BeaconState) -> BeaconState: # Execution-layer latest_execution_payload_header=latest_execution_payload_header, # Withdrawals - next_withdrawal_index=WithdrawalIndex(0), - next_withdrawal_validator_index=ValidatorIndex(0), + next_withdrawal_index=WithdrawalIndex(0), # [New in Capella] + next_withdrawal_validator_index=ValidatorIndex(0), # [New in Capella] + # Deep history valid from Capella onwards + historical_summaries=List[HistoricalSummary, HISTORICAL_ROOTS_LIMIT]([]), # [New in Capella] ) return post diff --git a/specs/eip4844/fork.md b/specs/eip4844/fork.md index 60a53f91f..39521879a 100644 --- a/specs/eip4844/fork.md +++ b/specs/eip4844/fork.md @@ -131,6 +131,8 @@ def upgrade_to_eip4844(pre: capella.BeaconState) -> BeaconState: # Withdrawals next_withdrawal_index=pre.next_withdrawal_index, next_withdrawal_validator_index=pre.next_withdrawal_validator_index, + # Deep history valid from Capella onwards + historical_summaries=pre.historical_summaries, ) return post From 025f80f7677cdef27a305fe5a4e4e27a84610545 Mon Sep 17 00:00:00 2001 From: parithosh Date: Tue, 10 Jan 2023 10:23:04 +0100 Subject: [PATCH 060/158] adding install_test --- .github/workflows/run-tests.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/run-tests.yml b/.github/workflows/run-tests.yml index 3bab00950..2c7b9d883 100644 --- a/.github/workflows/run-tests.yml +++ b/.github/workflows/run-tests.yml @@ -71,6 +71,8 @@ jobs: 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 run: make lint - name: Run linter for test generators From 96a553615ab5546296c58952c852daccbda8c013 Mon Sep 17 00:00:00 2001 From: terence tsao Date: Tue, 10 Jan 2023 10:28:19 -0800 Subject: [PATCH 061/158] Add rate limit suggestion --- specs/eip4844/p2p-interface.md | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/specs/eip4844/p2p-interface.md b/specs/eip4844/p2p-interface.md index ead9ba15c..53199b6fd 100644 --- a/specs/eip4844/p2p-interface.md +++ b/specs/eip4844/p2p-interface.md @@ -226,8 +226,6 @@ The request MUST be encoded as an SSZ-container. The response MUST consist of zero or more `response_chunk`. Each _successful_ `response_chunk` MUST contain a single `BlobsSidecar` payload. -In cases where a slot contains a `BlobSidecar` that does not contain any blobs, but contain non-zero `beacon_block_root`, `beacon_block_slot` and a valid `kzg_aggregated_proof`, `blobs_sidecar` may be skipped. - Clients MUST keep a record of signed blobs sidecars seen on the epoch range `[max(current_epoch - MIN_EPOCHS_FOR_BLOBS_SIDECARS_REQUESTS, EIP4844_FORK_EPOCH), current_epoch]` where `current_epoch` is defined by the current wall-clock time, @@ -249,12 +247,12 @@ disconnect and/or temporarily ban such an un-synced or semi-synced client. Clients MUST respond with at least the first blobs sidecar that exists in the range, if they have it, and no more than `MAX_REQUEST_BLOBS_SIDECARS` sidecars. -Clients MAY skip to respond empty blobs sidecars. - The following blobs sidecars, where they exist, MUST be sent in consecutive order. Clients MAY limit the number of blobs sidecars in the response. +Clients MAY not want to rate limit `BlobSidecar` that does not contain any blobs, but contain non-zero `beacon_block_root`, `beacon_block_slot` and a valid `kzg_aggregated_proof`. + The response MUST contain no more than `count` blobs sidecars. Clients MUST respond with blobs sidecars from their view of the current fork choice From a2099dabf7a302b5d5d09e3c1be915aa6b6adac3 Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Thu, 12 Jan 2023 03:23:17 +0800 Subject: [PATCH 062/158] Add `test_invalid_previous_fork_version` --- .../test_process_bls_to_execution_change.py | 22 +++++++++++++++++++ .../test/helpers/bls_to_execution_changes.py | 9 ++++++-- 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/tests/core/pyspec/eth2spec/test/capella/block_processing/test_process_bls_to_execution_change.py b/tests/core/pyspec/eth2spec/test/capella/block_processing/test_process_bls_to_execution_change.py index 094de5eeb..4e8bd7502 100644 --- a/tests/core/pyspec/eth2spec/test/capella/block_processing/test_process_bls_to_execution_change.py +++ b/tests/core/pyspec/eth2spec/test/capella/block_processing/test_process_bls_to_execution_change.py @@ -172,3 +172,25 @@ def test_invalid_bad_signature(spec, state): signed_address_change.signature = spec.BLSSignature(b'\x42' * 96) yield from run_bls_to_execution_change_processing(spec, state, signed_address_change, valid=False) + + +@with_capella_and_later +@spec_state_test +@always_bls +def test_current_fork_version(spec, state): + """ + It should be identical to the `test_success` test case. + It is just for comparing with `test_invalid_previous_fork_version`. + """ + signed_address_change = get_signed_address_change(spec, state, fork_version=state.fork.current_version) + + yield from run_bls_to_execution_change_processing(spec, state, signed_address_change) + + +@with_capella_and_later +@spec_state_test +@always_bls +def test_invalid_previous_fork_version(spec, state): + signed_address_change = get_signed_address_change(spec, state, fork_version=state.fork.previous_version) + + yield from run_bls_to_execution_change_processing(spec, state, signed_address_change, valid=False) diff --git a/tests/core/pyspec/eth2spec/test/helpers/bls_to_execution_changes.py b/tests/core/pyspec/eth2spec/test/helpers/bls_to_execution_changes.py index 446fa9710..ce0211646 100644 --- a/tests/core/pyspec/eth2spec/test/helpers/bls_to_execution_changes.py +++ b/tests/core/pyspec/eth2spec/test/helpers/bls_to_execution_changes.py @@ -2,7 +2,8 @@ from eth2spec.utils import bls from eth2spec.test.helpers.keys import pubkeys, privkeys, pubkey_to_privkey -def get_signed_address_change(spec, state, validator_index=None, withdrawal_pubkey=None, to_execution_address=None): +def get_signed_address_change(spec, state, validator_index=None, withdrawal_pubkey=None, to_execution_address=None, + fork_version=None): if validator_index is None: validator_index = 0 @@ -16,7 +17,11 @@ def get_signed_address_change(spec, state, validator_index=None, withdrawal_pubk if to_execution_address is None: to_execution_address = b'\x42' * 20 - domain = spec.get_domain(state, spec.DOMAIN_BLS_TO_EXECUTION_CHANGE) + if fork_version is None: + domain = spec.get_domain(state, spec.DOMAIN_BLS_TO_EXECUTION_CHANGE) + else: + domain = spec.compute_domain(spec.DOMAIN_BLS_TO_EXECUTION_CHANGE, fork_version, state.genesis_validators_root) + address_change = spec.BLSToExecutionChange( validator_index=validator_index, from_bls_pubkey=withdrawal_pubkey, From 8d841c864b13d3c9be7505662d39e0c258c54a83 Mon Sep 17 00:00:00 2001 From: Danny Ryan Date: Wed, 11 Jan 2023 19:44:39 -0700 Subject: [PATCH 063/158] minor copy edit --- specs/eip4844/p2p-interface.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/specs/eip4844/p2p-interface.md b/specs/eip4844/p2p-interface.md index 53199b6fd..f7c296aa8 100644 --- a/specs/eip4844/p2p-interface.md +++ b/specs/eip4844/p2p-interface.md @@ -251,7 +251,8 @@ The following blobs sidecars, where they exist, MUST be sent in consecutive orde Clients MAY limit the number of blobs sidecars in the response. -Clients MAY not want to rate limit `BlobSidecar` that does not contain any blobs, but contain non-zero `beacon_block_root`, `beacon_block_slot` and a valid `kzg_aggregated_proof`. +An empty `BlobSidecar` is one that does not contain any blobs, but contains non-zero `beacon_block_root`, `beacon_block_slot` and a valid `kzg_aggregated_proof`. +Clients MAY NOT want to consider empty `BlobSidecar`s in rate limiting logic. The response MUST contain no more than `count` blobs sidecars. From 730a7afe49210ce8b326d672ef478c3f48a83e43 Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Thu, 12 Jan 2023 23:10:22 +0800 Subject: [PATCH 064/158] Always use `GENESIS_FORK_VERSION` to sign `BLSToExecutionChange` message --- specs/capella/beacon-chain.md | 3 ++- .../test_process_bls_to_execution_change.py | 17 +++++++++++------ .../test/helpers/bls_to_execution_changes.py | 8 ++++---- 3 files changed, 17 insertions(+), 11 deletions(-) diff --git a/specs/capella/beacon-chain.md b/specs/capella/beacon-chain.md index 9a04f2f38..1be41e7eb 100644 --- a/specs/capella/beacon-chain.md +++ b/specs/capella/beacon-chain.md @@ -472,7 +472,8 @@ def process_bls_to_execution_change(state: BeaconState, assert validator.withdrawal_credentials[:1] == BLS_WITHDRAWAL_PREFIX assert validator.withdrawal_credentials[1:] == hash(address_change.from_bls_pubkey)[1:] - domain = get_domain(state, DOMAIN_BLS_TO_EXECUTION_CHANGE) + # Fork-agnostic domain since address changes are valid across forks + domain = compute_domain(DOMAIN_BLS_TO_EXECUTION_CHANGE, genesis_validators_root=state.genesis_validators_root) signing_root = compute_signing_root(address_change, domain) assert bls.Verify(address_change.from_bls_pubkey, signing_root, signed_address_change.signature) diff --git a/tests/core/pyspec/eth2spec/test/capella/block_processing/test_process_bls_to_execution_change.py b/tests/core/pyspec/eth2spec/test/capella/block_processing/test_process_bls_to_execution_change.py index 4e8bd7502..3c692816d 100644 --- a/tests/core/pyspec/eth2spec/test/capella/block_processing/test_process_bls_to_execution_change.py +++ b/tests/core/pyspec/eth2spec/test/capella/block_processing/test_process_bls_to_execution_change.py @@ -177,16 +177,21 @@ def test_invalid_bad_signature(spec, state): @with_capella_and_later @spec_state_test @always_bls -def test_current_fork_version(spec, state): - """ - It should be identical to the `test_success` test case. - It is just for comparing with `test_invalid_previous_fork_version`. - """ - signed_address_change = get_signed_address_change(spec, state, fork_version=state.fork.current_version) +def test_genesis_fork_version(spec, state): + signed_address_change = get_signed_address_change(spec, state, fork_version=spec.config.GENESIS_FORK_VERSION) yield from run_bls_to_execution_change_processing(spec, state, signed_address_change) +@with_capella_and_later +@spec_state_test +@always_bls +def test_invalid_current_fork_version(spec, state): + signed_address_change = get_signed_address_change(spec, state, fork_version=state.fork.current_version) + + yield from run_bls_to_execution_change_processing(spec, state, signed_address_change, valid=False) + + @with_capella_and_later @spec_state_test @always_bls diff --git a/tests/core/pyspec/eth2spec/test/helpers/bls_to_execution_changes.py b/tests/core/pyspec/eth2spec/test/helpers/bls_to_execution_changes.py index ce0211646..0fd7e1fe8 100644 --- a/tests/core/pyspec/eth2spec/test/helpers/bls_to_execution_changes.py +++ b/tests/core/pyspec/eth2spec/test/helpers/bls_to_execution_changes.py @@ -17,10 +17,10 @@ def get_signed_address_change(spec, state, validator_index=None, withdrawal_pubk if to_execution_address is None: to_execution_address = b'\x42' * 20 - if fork_version is None: - domain = spec.get_domain(state, spec.DOMAIN_BLS_TO_EXECUTION_CHANGE) - else: - domain = spec.compute_domain(spec.DOMAIN_BLS_TO_EXECUTION_CHANGE, fork_version, state.genesis_validators_root) + domain = spec.compute_domain( + spec.DOMAIN_BLS_TO_EXECUTION_CHANGE, + fork_version=fork_version, + genesis_validators_root=state.genesis_validators_root) address_change = spec.BLSToExecutionChange( validator_index=validator_index, From 4af46e7e7841cc71ee7d949291d09d433f370e57 Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Thu, 12 Jan 2023 23:30:09 +0800 Subject: [PATCH 065/158] Ignore `bls_to_execution_change` messages before `CAPELLA_FORK_EPOCH` --- specs/capella/p2p-interface.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/specs/capella/p2p-interface.md b/specs/capella/p2p-interface.md index 4cb23a67e..89655409c 100644 --- a/specs/capella/p2p-interface.md +++ b/specs/capella/p2p-interface.md @@ -59,8 +59,10 @@ See Capella [state transition document](./beacon-chain.md#beaconblockbody) for f This topic is used to propagate signed bls to execution change messages to be included in future blocks. +Let `system_clock_epoch` be an epoch number according to the local system clock of a node. The following validations MUST pass before forwarding the `signed_bls_to_execution_change` on the network: +- _[IGNORE]_ `system_clock_epoch >= CAPELLA_FORK_EPOCH`. - _[IGNORE]_ The `signed_bls_to_execution_change` is the first valid signed bls to execution change received for the validator with index `signed_bls_to_execution_change.message.validator_index`. - _[REJECT]_ All of the conditions within `process_bls_to_execution_change` pass validation. From b7205813fd07c8f0e2038fe51364c2da16bdf94a Mon Sep 17 00:00:00 2001 From: Etan Kissling Date: Thu, 12 Jan 2023 19:01:57 +0100 Subject: [PATCH 066/158] Update sync test documentation --- tests/formats/light_client/sync.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/tests/formats/light_client/sync.md b/tests/formats/light_client/sync.md index c42486c5c..2f17dbe7a 100644 --- a/tests/formats/light_client/sync.md +++ b/tests/formats/light_client/sync.md @@ -17,7 +17,7 @@ store_fork_digest: string -- Encoded `ForkDigest`-context of `store` obj An SSZ-snappy encoded `bootstrap` object of type `LightClientBootstrap` to initialize a local `store` object of type `LightClientStore` with `store_fork_digest` using `initialize_light_client_store(trusted_block_rooot, bootstrap)`. The SSZ type can be determined from `bootstrap_fork_digest`. -If `store_fork_digest` differs from `bootstrap_fork_digest`, the `bootstrap` object may need upgrading before initializing the store. +If `store_fork_digest` differs from `bootstrap_fork_digest`, the `bootstrap` object may need to be upgraded before initializing the store. ### `steps.yaml` @@ -68,7 +68,7 @@ The function `process_light_client_update(store, update, current_slot, genesis_v } ``` -If `store_fork_digest` differs from `update_fork_digest`, the `update` object may need upgrading before initializing the store. +If `store_fork_digest` differs from `update_fork_digest`, the `update` object may need to be upgraded before processing the update. After this step, the `store` object may have been updated. @@ -85,7 +85,6 @@ The `store` should be upgraded to reflect the new `store_fork_digest`: After this step, the `store` object may have been updated. - ## Condition A test-runner should initialize a local `LightClientStore` using the provided `bootstrap` object. It should then proceed to execute all the test steps in sequence. After each step, it should verify that the resulting `store` verifies against the provided `checks`. From 6a19cf568a734418de4e57922bfb3cf934443f28 Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Fri, 13 Jan 2023 16:49:24 +0800 Subject: [PATCH 067/158] PR feedback from @terencechain: re-use `current_epoch` definition --- specs/capella/p2p-interface.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/specs/capella/p2p-interface.md b/specs/capella/p2p-interface.md index 89655409c..834fd44d8 100644 --- a/specs/capella/p2p-interface.md +++ b/specs/capella/p2p-interface.md @@ -59,10 +59,10 @@ See Capella [state transition document](./beacon-chain.md#beaconblockbody) for f This topic is used to propagate signed bls to execution change messages to be included in future blocks. -Let `system_clock_epoch` be an epoch number according to the local system clock of a node. The following validations MUST pass before forwarding the `signed_bls_to_execution_change` on the network: -- _[IGNORE]_ `system_clock_epoch >= CAPELLA_FORK_EPOCH`. +- _[IGNORE]_ `current_epoch >= CAPELLA_FORK_EPOCH`, + where `current_epoch` is defined by the current wall-clock time. - _[IGNORE]_ The `signed_bls_to_execution_change` is the first valid signed bls to execution change received for the validator with index `signed_bls_to_execution_change.message.validator_index`. - _[REJECT]_ All of the conditions within `process_bls_to_execution_change` pass validation. From ca32fe834782cc83e166007101c30beac17344ca Mon Sep 17 00:00:00 2001 From: Etan Kissling Date: Fri, 13 Jan 2023 11:19:53 +0100 Subject: [PATCH 068/158] Add docstrings to explain empty header --- specs/capella/light-client/full-node.md | 4 ++++ specs/eip4844/light-client/full-node.md | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/specs/capella/light-client/full-node.md b/specs/capella/light-client/full-node.md index 6a2104a38..a406cd771 100644 --- a/specs/capella/light-client/full-node.md +++ b/specs/capella/light-client/full-node.md @@ -57,6 +57,10 @@ def block_to_light_client_header(block: SignedBeaconBlock) -> LightClientHeader: ) execution_branch = compute_merkle_proof_for_block_body(block.message.body, EXECUTION_PAYLOAD_INDEX) else: + # Note that during fork transitions, `finalized_header` may still point to earlier forks. + # While Bellatrix blocks also contain an `ExecutionPayload` (minus `withdrawals_root`), + # it was not included in the corresponding light client data. To ensure compatibility + # with legacy data going through `upgrade_lc_header_to_capella`, leave out execution data. execution_header = ExecutionPayloadHeader() execution_branch = [Bytes32() for _ in range(floorlog2(EXECUTION_PAYLOAD_INDEX))] diff --git a/specs/eip4844/light-client/full-node.md b/specs/eip4844/light-client/full-node.md index e9d7340f6..70983e1b3 100644 --- a/specs/eip4844/light-client/full-node.md +++ b/specs/eip4844/light-client/full-node.md @@ -53,6 +53,10 @@ def block_to_light_client_header(block: SignedBeaconBlock) -> LightClientHeader: execution_branch = compute_merkle_proof_for_block_body(block.message.body, EXECUTION_PAYLOAD_INDEX) else: + # Note that during fork transitions, `finalized_header` may still point to earlier forks. + # While Bellatrix blocks also contain an `ExecutionPayload` (minus `withdrawals_root`), + # it was not included in the corresponding light client data. To ensure compatibility + # with legacy data going through `upgrade_lc_header_to_capella`, leave out execution data. execution_header = ExecutionPayloadHeader() execution_branch = [Bytes32() for _ in range(floorlog2(EXECUTION_PAYLOAD_INDEX))] From a580f82c7d7b88d33b8c06b168447d46c3526b8f Mon Sep 17 00:00:00 2001 From: Etan Kissling Date: Fri, 13 Jan 2023 14:59:34 +0100 Subject: [PATCH 069/158] Use `beacon` wrapper in `upgrade_lc_header_to_capella` --- specs/capella/light-client/fork.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/specs/capella/light-client/fork.md b/specs/capella/light-client/fork.md index ee2102b22..d5640e01b 100644 --- a/specs/capella/light-client/fork.md +++ b/specs/capella/light-client/fork.md @@ -22,9 +22,9 @@ This document describes how to upgrade existing light client objects based on th A Capella `LightClientStore` can still process earlier light client data. In order to do so, that pre-Capella data needs to be locally upgraded to Capella before processing. ```python -def upgrade_lc_header_to_capella(pre: BeaconBlockHeader) -> LightClientHeader: +def upgrade_lc_header_to_capella(pre: altair.LightClientHeader) -> LightClientHeader: return LightClientHeader( - beacon=pre, + beacon=pre.beacon, ) ``` From d4eaf4bff4eac9d7a84455f1939b0be87c2e35e3 Mon Sep 17 00:00:00 2001 From: djrtwo Date: Fri, 13 Jan 2023 08:07:21 -0700 Subject: [PATCH 070/158] add invalid test for BLSChange genesis_validators_root --- .../test_process_bls_to_execution_change.py | 9 +++++++++ .../test/helpers/bls_to_execution_changes.py | 14 +++++++++++--- 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/tests/core/pyspec/eth2spec/test/capella/block_processing/test_process_bls_to_execution_change.py b/tests/core/pyspec/eth2spec/test/capella/block_processing/test_process_bls_to_execution_change.py index 3c692816d..ab7e14d56 100644 --- a/tests/core/pyspec/eth2spec/test/capella/block_processing/test_process_bls_to_execution_change.py +++ b/tests/core/pyspec/eth2spec/test/capella/block_processing/test_process_bls_to_execution_change.py @@ -199,3 +199,12 @@ def test_invalid_previous_fork_version(spec, state): signed_address_change = get_signed_address_change(spec, state, fork_version=state.fork.previous_version) yield from run_bls_to_execution_change_processing(spec, state, signed_address_change, valid=False) + + +@with_capella_and_later +@spec_state_test +@always_bls +def test_invalid_genesis_validators_root(spec, state): + signed_address_change = get_signed_address_change(spec, state, genesis_validators_root=b'\x99' * 32) + + yield from run_bls_to_execution_change_processing(spec, state, signed_address_change, valid=False) diff --git a/tests/core/pyspec/eth2spec/test/helpers/bls_to_execution_changes.py b/tests/core/pyspec/eth2spec/test/helpers/bls_to_execution_changes.py index 0fd7e1fe8..a71e5780e 100644 --- a/tests/core/pyspec/eth2spec/test/helpers/bls_to_execution_changes.py +++ b/tests/core/pyspec/eth2spec/test/helpers/bls_to_execution_changes.py @@ -2,8 +2,12 @@ from eth2spec.utils import bls from eth2spec.test.helpers.keys import pubkeys, privkeys, pubkey_to_privkey -def get_signed_address_change(spec, state, validator_index=None, withdrawal_pubkey=None, to_execution_address=None, - fork_version=None): +def get_signed_address_change(spec, state, + validator_index=None, + withdrawal_pubkey=None, + to_execution_address=None, + fork_version=None, + genesis_validators_root=None): if validator_index is None: validator_index = 0 @@ -17,10 +21,14 @@ def get_signed_address_change(spec, state, validator_index=None, withdrawal_pubk if to_execution_address is None: to_execution_address = b'\x42' * 20 + if genesis_validators_root is None: + genesis_validators_root = spec.genesis_validators_root + domain = spec.compute_domain( spec.DOMAIN_BLS_TO_EXECUTION_CHANGE, fork_version=fork_version, - genesis_validators_root=state.genesis_validators_root) + genesis_validators_root=genesis_validators_root, + ) address_change = spec.BLSToExecutionChange( validator_index=validator_index, From e1df31818bd27fc5b1c210ada93ad4d701289595 Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Fri, 13 Jan 2023 23:18:29 +0800 Subject: [PATCH 071/158] fix typo --- .../pyspec/eth2spec/test/helpers/bls_to_execution_changes.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/core/pyspec/eth2spec/test/helpers/bls_to_execution_changes.py b/tests/core/pyspec/eth2spec/test/helpers/bls_to_execution_changes.py index a71e5780e..df8af1616 100644 --- a/tests/core/pyspec/eth2spec/test/helpers/bls_to_execution_changes.py +++ b/tests/core/pyspec/eth2spec/test/helpers/bls_to_execution_changes.py @@ -22,7 +22,7 @@ def get_signed_address_change(spec, state, to_execution_address = b'\x42' * 20 if genesis_validators_root is None: - genesis_validators_root = spec.genesis_validators_root + genesis_validators_root = state.genesis_validators_root domain = spec.compute_domain( spec.DOMAIN_BLS_TO_EXECUTION_CHANGE, From 3dd7e3583f8970dd6733105da5a685bef8a833bd Mon Sep 17 00:00:00 2001 From: Danny Ryan Date: Fri, 13 Jan 2023 08:24:43 -0700 Subject: [PATCH 072/158] bump VERSION.txt to 1.3.0-rc.1 --- 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 b73f10e65..bf16dded0 100644 --- a/tests/core/pyspec/eth2spec/VERSION.txt +++ b/tests/core/pyspec/eth2spec/VERSION.txt @@ -1 +1 @@ -1.3.0-rc.0 +1.3.0-rc.1 From 64f609af180d8096312d2d7cb0c09cf53048b113 Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Wed, 11 Jan 2023 00:23:19 +0800 Subject: [PATCH 073/158] Add a test case from staking-deposit-cli --- .../test_process_bls_to_execution_change.py | 38 ++++++++++++++++++- 1 file changed, 36 insertions(+), 2 deletions(-) diff --git a/tests/core/pyspec/eth2spec/test/capella/block_processing/test_process_bls_to_execution_change.py b/tests/core/pyspec/eth2spec/test/capella/block_processing/test_process_bls_to_execution_change.py index ab7e14d56..996285add 100644 --- a/tests/core/pyspec/eth2spec/test/capella/block_processing/test_process_bls_to_execution_change.py +++ b/tests/core/pyspec/eth2spec/test/capella/block_processing/test_process_bls_to_execution_change.py @@ -1,7 +1,14 @@ from eth2spec.test.helpers.keys import pubkeys from eth2spec.test.helpers.bls_to_execution_changes import get_signed_address_change - -from eth2spec.test.context import spec_state_test, expect_assertion_error, with_capella_and_later, always_bls +from eth2spec.test.helpers.constants import CAPELLA, MAINNET +from eth2spec.test.context import ( + always_bls, + expect_assertion_error, + spec_state_test, + with_capella_and_later, + with_presets, + with_phases, +) def run_bls_to_execution_change_processing(spec, state, signed_address_change, valid=True): @@ -208,3 +215,30 @@ def test_invalid_genesis_validators_root(spec, state): signed_address_change = get_signed_address_change(spec, state, genesis_validators_root=b'\x99' * 32) yield from run_bls_to_execution_change_processing(spec, state, signed_address_change, valid=False) + + +@with_phases([CAPELLA]) +@with_presets([MAINNET], reason="use mainnet fork version") +@spec_state_test +@always_bls +def test_valid_signature_from_staking_deposit_cli(spec, state): + validator_index = 1 + from_bls_pubkey = bytes.fromhex('86248e64705987236ec3c41f6a81d96f98e7b85e842a1d71405b216fa75a9917512f3c94c85779a9729c927ea2aa9ed1') # noqa: E501 + to_execution_address = bytes.fromhex('3434343434343434343434343434343434343434') + signature = bytes.fromhex('b9611626f18632086b6e05e161b1cb1f686ca0e920d12a2d7430e230e336d96b381099d1fda198949b727830088d70eb039e30ea213908a34a1d0d81b0c4c8fd23f38475f36c45ff98dd0906874387183d7583c60ad7bd1744a41ea68b5dfcb2') # noqa: E501 + + # Use mainnet `genesis_validators_root` + state.genesis_validators_root = bytes.fromhex('4b363db94e286120d76eb905340fdd4e54bfe9f06bf33ff6cf5ad27f511bfe95') + state.validators[1].withdrawal_credentials = spec.BLS_WITHDRAWAL_PREFIX + spec.hash(from_bls_pubkey)[1:] + + address_change = spec.BLSToExecutionChange( + validator_index=validator_index, + from_bls_pubkey=from_bls_pubkey, + to_execution_address=to_execution_address, + ) + signed_address_change = spec.SignedBLSToExecutionChange( + message=address_change, + signature=signature, + ) + + yield from run_bls_to_execution_change_processing(spec, state, signed_address_change) From 75def3c88e410c9f062dc8b33200ff81eb06f2b7 Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Thu, 12 Jan 2023 02:51:48 +0800 Subject: [PATCH 074/158] PR feedback from @ralexstokes Co-authored-by: Alex Stokes --- .../block_processing/test_process_bls_to_execution_change.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/core/pyspec/eth2spec/test/capella/block_processing/test_process_bls_to_execution_change.py b/tests/core/pyspec/eth2spec/test/capella/block_processing/test_process_bls_to_execution_change.py index 996285add..afc6469db 100644 --- a/tests/core/pyspec/eth2spec/test/capella/block_processing/test_process_bls_to_execution_change.py +++ b/tests/core/pyspec/eth2spec/test/capella/block_processing/test_process_bls_to_execution_change.py @@ -229,7 +229,7 @@ def test_valid_signature_from_staking_deposit_cli(spec, state): # Use mainnet `genesis_validators_root` state.genesis_validators_root = bytes.fromhex('4b363db94e286120d76eb905340fdd4e54bfe9f06bf33ff6cf5ad27f511bfe95') - state.validators[1].withdrawal_credentials = spec.BLS_WITHDRAWAL_PREFIX + spec.hash(from_bls_pubkey)[1:] + state.validators[validator_index].withdrawal_credentials = spec.BLS_WITHDRAWAL_PREFIX + spec.hash(from_bls_pubkey)[1:] address_change = spec.BLSToExecutionChange( validator_index=validator_index, From 9b3f8881b48a9dde25e025e21055fe0fff5a63e8 Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Thu, 12 Jan 2023 21:57:05 +0800 Subject: [PATCH 075/158] Fix lint --- .../block_processing/test_process_bls_to_execution_change.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/core/pyspec/eth2spec/test/capella/block_processing/test_process_bls_to_execution_change.py b/tests/core/pyspec/eth2spec/test/capella/block_processing/test_process_bls_to_execution_change.py index afc6469db..c96e1f9ac 100644 --- a/tests/core/pyspec/eth2spec/test/capella/block_processing/test_process_bls_to_execution_change.py +++ b/tests/core/pyspec/eth2spec/test/capella/block_processing/test_process_bls_to_execution_change.py @@ -229,7 +229,8 @@ def test_valid_signature_from_staking_deposit_cli(spec, state): # Use mainnet `genesis_validators_root` state.genesis_validators_root = bytes.fromhex('4b363db94e286120d76eb905340fdd4e54bfe9f06bf33ff6cf5ad27f511bfe95') - state.validators[validator_index].withdrawal_credentials = spec.BLS_WITHDRAWAL_PREFIX + spec.hash(from_bls_pubkey)[1:] + validator = state.validators[validator_index] + validator.withdrawal_credentials = spec.BLS_WITHDRAWAL_PREFIX + spec.hash(from_bls_pubkey)[1:] address_change = spec.BLSToExecutionChange( validator_index=validator_index, From a5273905efc76fcfbbece33429bbd6dcb430e976 Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Fri, 13 Jan 2023 23:34:59 +0800 Subject: [PATCH 076/158] Update signature value due to #3206 --- .../block_processing/test_process_bls_to_execution_change.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/core/pyspec/eth2spec/test/capella/block_processing/test_process_bls_to_execution_change.py b/tests/core/pyspec/eth2spec/test/capella/block_processing/test_process_bls_to_execution_change.py index c96e1f9ac..f222744f0 100644 --- a/tests/core/pyspec/eth2spec/test/capella/block_processing/test_process_bls_to_execution_change.py +++ b/tests/core/pyspec/eth2spec/test/capella/block_processing/test_process_bls_to_execution_change.py @@ -225,7 +225,7 @@ def test_valid_signature_from_staking_deposit_cli(spec, state): validator_index = 1 from_bls_pubkey = bytes.fromhex('86248e64705987236ec3c41f6a81d96f98e7b85e842a1d71405b216fa75a9917512f3c94c85779a9729c927ea2aa9ed1') # noqa: E501 to_execution_address = bytes.fromhex('3434343434343434343434343434343434343434') - signature = bytes.fromhex('b9611626f18632086b6e05e161b1cb1f686ca0e920d12a2d7430e230e336d96b381099d1fda198949b727830088d70eb039e30ea213908a34a1d0d81b0c4c8fd23f38475f36c45ff98dd0906874387183d7583c60ad7bd1744a41ea68b5dfcb2') # noqa: E501 + signature = bytes.fromhex('8cf4219884b326a04f6664b680cd9a99ad70b5280745af1147477aa9f8b4a2b2b38b8688c6a74a06f275ad4e14c5c0c70e2ed37a15ece5bf7c0724a376ad4c03c79e14dd9f633a3d54abc1ce4e73bec3524a789ab9a69d4d06686a8a67c9e4dc') # noqa: E501 # Use mainnet `genesis_validators_root` state.genesis_validators_root = bytes.fromhex('4b363db94e286120d76eb905340fdd4e54bfe9f06bf33ff6cf5ad27f511bfe95') From 514d4431caae8ecf158589c3052f64f6de4c37f6 Mon Sep 17 00:00:00 2001 From: Etan Kissling Date: Fri, 13 Jan 2023 20:11:05 +0100 Subject: [PATCH 077/158] Use `bellatrix` in `upgrade_x_to_capella` helpers --- specs/capella/light-client/fork.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/specs/capella/light-client/fork.md b/specs/capella/light-client/fork.md index d5640e01b..6dcc7578c 100644 --- a/specs/capella/light-client/fork.md +++ b/specs/capella/light-client/fork.md @@ -22,14 +22,14 @@ This document describes how to upgrade existing light client objects based on th A Capella `LightClientStore` can still process earlier light client data. In order to do so, that pre-Capella data needs to be locally upgraded to Capella before processing. ```python -def upgrade_lc_header_to_capella(pre: altair.LightClientHeader) -> LightClientHeader: +def upgrade_lc_header_to_capella(pre: bellatrix.LightClientHeader) -> LightClientHeader: return LightClientHeader( beacon=pre.beacon, ) ``` ```python -def upgrade_lc_bootstrap_to_capella(pre: altair.LightClientBootstrap) -> LightClientBootstrap: +def upgrade_lc_bootstrap_to_capella(pre: bellatrix.LightClientBootstrap) -> LightClientBootstrap: return LightClientBootstrap( header=upgrade_lc_header_to_capella(pre.header), current_sync_committee=pre.current_sync_committee, @@ -38,7 +38,7 @@ def upgrade_lc_bootstrap_to_capella(pre: altair.LightClientBootstrap) -> LightCl ``` ```python -def upgrade_lc_update_to_capella(pre: altair.LightClientUpdate) -> LightClientUpdate: +def upgrade_lc_update_to_capella(pre: bellatrix.LightClientUpdate) -> LightClientUpdate: return LightClientUpdate( attested_header=upgrade_lc_header_to_capella(pre.attested_header), next_sync_committee=pre.next_sync_committee, @@ -51,7 +51,7 @@ def upgrade_lc_update_to_capella(pre: altair.LightClientUpdate) -> LightClientUp ``` ```python -def upgrade_lc_finality_update_to_capella(pre: altair.LightClientFinalityUpdate) -> LightClientFinalityUpdate: +def upgrade_lc_finality_update_to_capella(pre: bellatrix.LightClientFinalityUpdate) -> LightClientFinalityUpdate: return LightClientFinalityUpdate( attested_header=upgrade_lc_header_to_capella(pre.attested_header), finalized_header=upgrade_lc_header_to_capella(pre.finalized_header), @@ -62,7 +62,7 @@ def upgrade_lc_finality_update_to_capella(pre: altair.LightClientFinalityUpdate) ``` ```python -def upgrade_lc_optimistic_update_to_capella(pre: altair.LightClientOptimisticUpdate) -> LightClientOptimisticUpdate: +def upgrade_lc_optimistic_update_to_capella(pre: bellatrix.LightClientOptimisticUpdate) -> LightClientOptimisticUpdate: return LightClientOptimisticUpdate( attested_header=upgrade_lc_header_to_capella(pre.attested_header), sync_aggregate=pre.sync_aggregate, @@ -75,7 +75,7 @@ def upgrade_lc_optimistic_update_to_capella(pre: altair.LightClientOptimisticUpd Existing `LightClientStore` objects based on Altair MUST be upgraded to Capella before Capella based light client data can be processed. The `LightClientStore` upgrade MAY be performed before `CAPELLA_FORK_EPOCH`. ```python -def upgrade_lc_store_to_capella(pre: altair.LightClientStore) -> LightClientStore: +def upgrade_lc_store_to_capella(pre: bellatrix.LightClientStore) -> LightClientStore: if pre.best_valid_update is None: best_valid_update = None else: From ffd047c6fa19b331bb9265f8cf22ea616b1fe5c3 Mon Sep 17 00:00:00 2001 From: Etan Kissling Date: Sat, 14 Jan 2023 14:51:59 +0100 Subject: [PATCH 078/158] Consistent test step naming --- .../core/pyspec/eth2spec/test/altair/light_client/test_sync.py | 2 +- tests/formats/light_client/sync.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/core/pyspec/eth2spec/test/altair/light_client/test_sync.py b/tests/core/pyspec/eth2spec/test/altair/light_client/test_sync.py index eb30ecb92..664b4fb44 100644 --- a/tests/core/pyspec/eth2spec/test/altair/light_client/test_sync.py +++ b/tests/core/pyspec/eth2spec/test/altair/light_client/test_sync.py @@ -274,7 +274,7 @@ def emit_upgrade_store(test, new_s_spec, phases=None): yield from [] # Consistently enable `yield from` syntax in calling tests test.steps.append({ - "process_upgrade_store": { + "upgrade_store": { "store_fork_digest": encode_hex(store_fork_digest), "checks": get_checks(test.s_spec, test.store), } diff --git a/tests/formats/light_client/sync.md b/tests/formats/light_client/sync.md index 2f17dbe7a..1706b4c16 100644 --- a/tests/formats/light_client/sync.md +++ b/tests/formats/light_client/sync.md @@ -72,7 +72,7 @@ If `store_fork_digest` differs from `update_fork_digest`, the `update` object ma After this step, the `store` object may have been updated. -#### `process_upgrade_store` +#### `upgrade_store` The `store` should be upgraded to reflect the new `store_fork_digest`: From 52d978b12ed89a7a6020b7d2c29887648ee35d8a Mon Sep 17 00:00:00 2001 From: Etan Kissling Date: Sun, 15 Jan 2023 12:13:35 +0100 Subject: [PATCH 079/158] Use `Gwei` for `Withdrawal` amount in mock-EE Updates the EL block hash computation for pytests to match latest spec. Notably, use `Gwei` for `Withdrawal` amount consistently. Also fix `excess_data_gas` not being correctly accounted for. https://github.com/ethereum/execution-apis/pull/354 https://github.com/ethereum/EIPs/pull/6325 --- tests/core/pyspec/eth2spec/test/helpers/execution_payload.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/core/pyspec/eth2spec/test/helpers/execution_payload.py b/tests/core/pyspec/eth2spec/test/helpers/execution_payload.py index 1f478ccc6..5e0c160b3 100644 --- a/tests/core/pyspec/eth2spec/test/helpers/execution_payload.py +++ b/tests/core/pyspec/eth2spec/test/helpers/execution_payload.py @@ -26,6 +26,8 @@ def get_execution_payload_header(spec, execution_payload): ) if is_post_capella(spec): payload_header.withdrawals_root = spec.hash_tree_root(execution_payload.withdrawals) + if is_post_eip4844(spec): + payload_header.excess_data_gas = execution_payload.excess_data_gas return payload_header @@ -108,7 +110,7 @@ def get_withdrawal_rlp(spec, withdrawal): # address (Binary(20, 20), withdrawal.address), # amount - (big_endian_int, spec.uint256(withdrawal.amount) * (10**9)), + (big_endian_int, withdrawal.amount), ] sedes = List([schema for schema, _ in withdrawal_rlp]) From 296ba921c9c06c7aa2b5daea4c34c4407601f524 Mon Sep 17 00:00:00 2001 From: George Kadianakis Date: Mon, 16 Jan 2023 15:57:35 +0200 Subject: [PATCH 080/158] EIP4844: Handle barycentric evaluations at roots of unity --- specs/eip4844/polynomial-commitments.md | 8 +++-- .../test_polynomial_commitments.py | 34 +++++++++++++++++++ .../pyspec/eth2spec/test/helpers/sharding.py | 32 +++++++++++++++++ 3 files changed, 71 insertions(+), 3 deletions(-) diff --git a/specs/eip4844/polynomial-commitments.md b/specs/eip4844/polynomial-commitments.md index 8884457ed..26ee00487 100644 --- a/specs/eip4844/polynomial-commitments.md +++ b/specs/eip4844/polynomial-commitments.md @@ -302,11 +302,13 @@ def evaluate_polynomial_in_evaluation_form(polynomial: Polynomial, assert width == FIELD_ELEMENTS_PER_BLOB inverse_width = bls_modular_inverse(BLSFieldElement(width)) - # Make sure we won't divide by zero during division - assert z not in ROOTS_OF_UNITY - roots_of_unity_brp = bit_reversal_permutation(ROOTS_OF_UNITY) + # If we are asked to evaluate within the domain, we already know the answer + if z in roots_of_unity_brp: + eval_index = roots_of_unity_brp.index(z) + return BLSFieldElement(polynomial[eval_index]) + result = 0 for i in range(width): a = BLSFieldElement(int(polynomial[i]) * int(roots_of_unity_brp[i]) % BLS_MODULUS) diff --git a/tests/core/pyspec/eth2spec/test/eip4844/unittests/polynomial_commitments/test_polynomial_commitments.py b/tests/core/pyspec/eth2spec/test/eip4844/unittests/polynomial_commitments/test_polynomial_commitments.py index 3e9e2cb63..75a4e822a 100644 --- a/tests/core/pyspec/eth2spec/test/eip4844/unittests/polynomial_commitments/test_polynomial_commitments.py +++ b/tests/core/pyspec/eth2spec/test/eip4844/unittests/polynomial_commitments/test_polynomial_commitments.py @@ -4,6 +4,8 @@ from eth2spec.test.context import ( ) from eth2spec.test.helpers.sharding import ( get_sample_blob, + get_poly_in_both_forms, + eval_poly_in_coeff_form, ) @@ -18,3 +20,35 @@ def test_verify_kzg_proof(spec, state): y = spec.evaluate_polynomial_in_evaluation_form(polynomial, x) assert spec.verify_kzg_proof_impl(commitment, x, y, proof) + + +@with_eip4844_and_later +@spec_state_test +def test_barycentric_within_domain(spec, state): + """ + Test barycentric formula correctness by using it to evaluate a polynomial at all the points of its domain + (the roots of unity). + + Then make sure that we would get the same result if we evaluated it from coefficient form without using the + barycentric formula + """ + poly_coeff, poly_eval = get_poly_in_both_forms(spec) + roots_of_unity_brp = spec.bit_reversal_permutation(spec.ROOTS_OF_UNITY) + + assert len(poly_coeff) == len(poly_eval) == len(roots_of_unity_brp) + n = len(poly_coeff) + + # Iterate over the entire domain + for i in range(n): + # Grab a root of unity and use it as the evaluation point + z = int(roots_of_unity_brp[i]) + + # Get p(z) by evaluating poly in coefficient form + p_z_coeff = eval_poly_in_coeff_form(spec, poly_coeff, z) + + # Get p(z) by evaluating poly in evaluation form + p_z_eval = spec.evaluate_polynomial_in_evaluation_form(poly_eval, z) + + # The two evaluations should be agree and p(z) should also be the i-th "coefficient" of the polynomial in + # evaluation form + assert p_z_coeff == p_z_eval == poly_eval[i] diff --git a/tests/core/pyspec/eth2spec/test/helpers/sharding.py b/tests/core/pyspec/eth2spec/test/helpers/sharding.py index 4523e07f2..2ea8c94bc 100644 --- a/tests/core/pyspec/eth2spec/test/helpers/sharding.py +++ b/tests/core/pyspec/eth2spec/test/helpers/sharding.py @@ -66,6 +66,38 @@ def get_sample_blob(spec, rng=None): return spec.Blob(b) +def eval_poly_in_coeff_form(spec, coeffs, x): + """ + Evaluate a polynomial in coefficient form at 'x' using Horner's rule + """ + total = 0 + for a in reversed(coeffs): + total = (total * x + a) % spec.BLS_MODULUS + return total % spec.BLS_MODULUS + + +def get_poly_in_both_forms(spec, rng=None): + """ + Generate and return a random polynomial in both coefficient form and evaluation form + """ + if rng is None: + rng = random.Random(5566) + + roots_of_unity_brp = spec.bit_reversal_permutation(spec.ROOTS_OF_UNITY) + + coeffs = [ + rng.randint(0, spec.BLS_MODULUS - 1) + for _ in range(spec.FIELD_ELEMENTS_PER_BLOB) + ] + + evals = [ + eval_poly_in_coeff_form(spec, coeffs, int(z)) + for z in roots_of_unity_brp + ] + + return coeffs, evals + + def get_sample_opaque_tx(spec, blob_count=1, rng=None): blobs = [] blob_kzg_commitments = [] From 6e5df21f7d6fa47e0ed911cae567e5acd8589562 Mon Sep 17 00:00:00 2001 From: George Kadianakis Date: Mon, 16 Jan 2023 15:57:48 +0200 Subject: [PATCH 081/158] EIP4844: Also add unittest for barycentric outside the domain --- .../test_polynomial_commitments.py | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/tests/core/pyspec/eth2spec/test/eip4844/unittests/polynomial_commitments/test_polynomial_commitments.py b/tests/core/pyspec/eth2spec/test/eip4844/unittests/polynomial_commitments/test_polynomial_commitments.py index 75a4e822a..b503bba57 100644 --- a/tests/core/pyspec/eth2spec/test/eip4844/unittests/polynomial_commitments/test_polynomial_commitments.py +++ b/tests/core/pyspec/eth2spec/test/eip4844/unittests/polynomial_commitments/test_polynomial_commitments.py @@ -1,3 +1,5 @@ +import random + from eth2spec.test.context import ( spec_state_test, with_eip4844_and_later, @@ -22,6 +24,37 @@ def test_verify_kzg_proof(spec, state): assert spec.verify_kzg_proof_impl(commitment, x, y, proof) +@with_eip4844_and_later +@spec_state_test +def test_barycentric_outside_domain(spec, state): + """ + Test barycentric formula correctness by using it to evaluate a polynomial at a bunch of points outside its domain + (the roots of unity). + + Then make sure that we would get the same result if we evaluated it from coefficient form without using the + barycentric formula + """ + rng = random.Random(5566) + poly_coeff, poly_eval = get_poly_in_both_forms(spec) + roots_of_unity_brp = spec.bit_reversal_permutation(spec.ROOTS_OF_UNITY) + + assert len(poly_coeff) == len(poly_eval) == len(roots_of_unity_brp) + n_samples = 12 + + for i in range(n_samples): + # Get a random evaluation point + z = rng.randint(0, spec.BLS_MODULUS - 1) + + # Get p(z) by evaluating poly in coefficient form + p_z_coeff = eval_poly_in_coeff_form(spec, poly_coeff, z) + + # Get p(z) by evaluating poly in evaluation form + p_z_eval = spec.evaluate_polynomial_in_evaluation_form(poly_eval, z) + + # Both evaluations should agree + assert p_z_coeff == p_z_eval + + @with_eip4844_and_later @spec_state_test def test_barycentric_within_domain(spec, state): From c6453e215d8ee2100ec3bce6da56876c9093bbcc Mon Sep 17 00:00:00 2001 From: George Kadianakis Date: Tue, 17 Jan 2023 16:16:46 +0200 Subject: [PATCH 082/158] EIP4844: Make extra sure we didn't win the jackpot --- .../polynomial_commitments/test_polynomial_commitments.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/core/pyspec/eth2spec/test/eip4844/unittests/polynomial_commitments/test_polynomial_commitments.py b/tests/core/pyspec/eth2spec/test/eip4844/unittests/polynomial_commitments/test_polynomial_commitments.py index b503bba57..6b5e0d38d 100644 --- a/tests/core/pyspec/eth2spec/test/eip4844/unittests/polynomial_commitments/test_polynomial_commitments.py +++ b/tests/core/pyspec/eth2spec/test/eip4844/unittests/polynomial_commitments/test_polynomial_commitments.py @@ -42,8 +42,10 @@ def test_barycentric_outside_domain(spec, state): n_samples = 12 for i in range(n_samples): - # Get a random evaluation point + # Get a random evaluation point and make sure it's not a root of unity z = rng.randint(0, spec.BLS_MODULUS - 1) + while z in roots_of_unity_brp: + z = rng.randint(0, spec.BLS_MODULUS - 1) # Get p(z) by evaluating poly in coefficient form p_z_coeff = eval_poly_in_coeff_form(spec, poly_coeff, z) From 20dc6821abcdfe2bba686ca9a209a1af1300dc38 Mon Sep 17 00:00:00 2001 From: George Kadianakis Date: Tue, 17 Jan 2023 16:18:16 +0200 Subject: [PATCH 083/158] EIP4844: Unused i in for loop Co-authored-by: Hsiao-Wei Wang --- .../polynomial_commitments/test_polynomial_commitments.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/core/pyspec/eth2spec/test/eip4844/unittests/polynomial_commitments/test_polynomial_commitments.py b/tests/core/pyspec/eth2spec/test/eip4844/unittests/polynomial_commitments/test_polynomial_commitments.py index 6b5e0d38d..24b45475e 100644 --- a/tests/core/pyspec/eth2spec/test/eip4844/unittests/polynomial_commitments/test_polynomial_commitments.py +++ b/tests/core/pyspec/eth2spec/test/eip4844/unittests/polynomial_commitments/test_polynomial_commitments.py @@ -41,7 +41,7 @@ def test_barycentric_outside_domain(spec, state): assert len(poly_coeff) == len(poly_eval) == len(roots_of_unity_brp) n_samples = 12 - for i in range(n_samples): + for _ in range(n_samples): # Get a random evaluation point and make sure it's not a root of unity z = rng.randint(0, spec.BLS_MODULUS - 1) while z in roots_of_unity_brp: From f1435d456d26b43e0aea77b95e390e52091e8c9c Mon Sep 17 00:00:00 2001 From: Emilia Hane <58548332+emhane@users.noreply.github.com> Date: Thu, 19 Jan 2023 21:26:21 +0100 Subject: [PATCH 084/158] Update p2p-interface.md --- specs/eip4844/p2p-interface.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/specs/eip4844/p2p-interface.md b/specs/eip4844/p2p-interface.md index 3e0456713..e86e7a219 100644 --- a/specs/eip4844/p2p-interface.md +++ b/specs/eip4844/p2p-interface.md @@ -218,7 +218,7 @@ Each _successful_ `response_chunk` MUST contain a single `BlobsSidecar` payload. Clients MUST keep a record of signed blobs sidecars seen on the epoch range `[max(current_epoch - MIN_EPOCHS_FOR_BLOBS_SIDECARS_REQUESTS, EIP4844_FORK_EPOCH), current_epoch]` where `current_epoch` is defined by the current wall-clock time, -and clients MUST support serving requests of blocks on this range. +and clients MUST support serving requests of blobs on this range. Peers that are unable to reply to blobs sidecars requests within the `MIN_EPOCHS_FOR_BLOBS_SIDECARS_REQUESTS` epoch range SHOULD respond with error code `3: ResourceUnavailable`. From a0791712cd1afda05807b3f79aee1a50a1bc59ed Mon Sep 17 00:00:00 2001 From: Pawan Dhananjay Date: Fri, 20 Jan 2023 21:32:00 +0530 Subject: [PATCH 085/158] Remove kzg point validations in gossip --- specs/eip4844/p2p-interface.md | 5 ----- 1 file changed, 5 deletions(-) diff --git a/specs/eip4844/p2p-interface.md b/specs/eip4844/p2p-interface.md index 3e0456713..01051dc39 100644 --- a/specs/eip4844/p2p-interface.md +++ b/specs/eip4844/p2p-interface.md @@ -85,17 +85,12 @@ This topic is used to propagate new signed and coupled beacon blocks and blobs s In addition to the gossip validations for the `beacon_block` topic from prior specifications, the following validations MUST pass before forwarding the `signed_beacon_block_and_blobs_sidecar` on the network. Alias `signed_beacon_block = signed_beacon_block_and_blobs_sidecar.beacon_block`, `block = signed_beacon_block.message`, `execution_payload = block.body.execution_payload`. -- _[REJECT]_ The KZG commitments of the blobs are all correctly encoded compressed BLS G1 points - -- i.e. `all(bls.KeyValidate(commitment) for commitment in block.body.blob_kzg_commitments)` - _[REJECT]_ The KZG commitments correspond to the versioned hashes in the transactions list -- i.e. `verify_kzg_commitments_against_transactions(block.body.execution_payload.transactions, block.body.blob_kzg_commitments)` Alias `sidecar = signed_beacon_block_and_blobs_sidecar.blobs_sidecar`. - _[IGNORE]_ the `sidecar.beacon_block_slot` is for the current slot (with a `MAXIMUM_GOSSIP_CLOCK_DISPARITY` allowance) -- i.e. `sidecar.beacon_block_slot == block.slot`. -- _[REJECT]_ the `sidecar.blobs` are all well formatted, i.e. the `BLSFieldElement` in valid range (`x < BLS_MODULUS`). -- _[REJECT]_ The KZG proof is a correctly encoded compressed BLS G1 point - -- i.e. `bls.KeyValidate(blobs_sidecar.kzg_aggregated_proof)` - _[REJECT]_ The KZG commitments in the block are valid against the provided blobs sidecar -- i.e. `validate_blobs_sidecar(block.slot, hash_tree_root(block), block.body.blob_kzg_commitments, sidecar)` From 317facbd6405da29d6785f0b4077e04edc99aeb4 Mon Sep 17 00:00:00 2001 From: Paul Harris Date: Mon, 23 Jan 2023 15:08:34 +0100 Subject: [PATCH 086/158] Replaced EIP4844 references with Deneb Fixes #3207 --- .circleci/config.yml | 6 +- .github/workflows/run-tests.yml | 2 +- .gitignore | 2 +- Makefile | 12 +- README.md | 2 +- configs/mainnet.yaml | 6 +- configs/minimal.yaml | 6 +- presets/mainnet/{eip4844.yaml => deneb.yaml} | 0 presets/minimal/{eip4844.yaml => deneb.yaml} | 0 setup.py | 40 +++--- specs/{eip4844 => deneb}/beacon-chain.md | 6 +- specs/{eip4844 => deneb}/fork-choice.md | 0 specs/{eip4844 => deneb}/fork.md | 20 +-- specs/{eip4844 => deneb}/light-client/fork.md | 38 ++--- .../light-client/full-node.md | 8 +- .../light-client/p2p-interface.md | 60 ++++---- .../light-client/sync-protocol.md | 14 +- specs/{eip4844 => deneb}/p2p-interface.md | 8 +- .../polynomial-commitments.md | 0 specs/{eip4844 => deneb}/validator.md | 0 .../test/altair/light_client/test_sync.py | 52 +++---- tests/core/pyspec/eth2spec/test/context.py | 10 +- .../test/{eip4844 => deneb}/__init__.py | 0 .../test/{eip4844 => deneb}/fork/__init__.py | 0 .../fork/test_deneb_fork_basic.py} | 48 +++---- .../test/deneb/fork/test_deneb_fork_random.py | 84 +++++++++++ .../{eip4844 => deneb}/random/__init__.py | 0 .../{eip4844 => deneb}/random/test_random.py | 130 +++++++++--------- .../{eip4844 => deneb}/sanity/__init__.py | 0 .../{eip4844 => deneb}/sanity/test_blocks.py | 6 +- .../{eip4844 => deneb}/unittests/__init__.py | 0 .../unittests/fork_choice/__init__.py | 0 .../test_validate_blobs_sidecar.py | 10 +- .../polynomial_commitments/__init__.py | 0 .../test_polynomial_commitments.py | 8 +- .../{eip4844 => deneb}/unittests/test_kzg.py | 4 +- .../unittests/test_offset.py | 4 +- .../eip4844/fork/test_eip4844_fork_random.py | 84 ----------- .../pyspec/eth2spec/test/helpers/constants.py | 10 +- .../helpers/{eip4844 => deneb}/__init__.py | 0 .../test/helpers/{eip4844 => deneb}/fork.py | 10 +- .../test/helpers/execution_payload.py | 6 +- .../eth2spec/test/helpers/fork_transition.py | 10 +- .../pyspec/eth2spec/test/helpers/forks.py | 10 +- .../pyspec/eth2spec/test/helpers/genesis.py | 6 +- .../test/utils/randomized_block_tests.py | 4 +- tests/generators/epoch_processing/main.py | 6 +- tests/generators/finality/main.py | 6 +- tests/generators/fork_choice/main.py | 6 +- tests/generators/forks/main.py | 8 +- tests/generators/genesis/main.py | 6 +- tests/generators/light_client/main.py | 6 +- tests/generators/operations/main.py | 6 +- tests/generators/random/Makefile | 4 +- tests/generators/random/generate.py | 14 +- tests/generators/random/main.py | 6 +- tests/generators/rewards/main.py | 6 +- tests/generators/sanity/main.py | 8 +- tests/generators/sync/main.py | 6 +- 59 files changed, 407 insertions(+), 407 deletions(-) rename presets/mainnet/{eip4844.yaml => deneb.yaml} (100%) rename presets/minimal/{eip4844.yaml => deneb.yaml} (100%) rename specs/{eip4844 => deneb}/beacon-chain.md (98%) rename specs/{eip4844 => deneb}/fork-choice.md (100%) rename specs/{eip4844 => deneb}/fork.md (86%) rename specs/{eip4844 => deneb}/light-client/fork.md (62%) rename specs/{eip4844 => deneb}/light-client/full-node.md (94%) rename specs/{eip4844 => deneb}/light-client/p2p-interface.md (65%) rename specs/{eip4844 => deneb}/light-client/sync-protocol.md (84%) rename specs/{eip4844 => deneb}/p2p-interface.md (95%) rename specs/{eip4844 => deneb}/polynomial-commitments.md (100%) rename specs/{eip4844 => deneb}/validator.md (100%) rename tests/core/pyspec/eth2spec/test/{eip4844 => deneb}/__init__.py (100%) rename tests/core/pyspec/eth2spec/test/{eip4844 => deneb}/fork/__init__.py (100%) rename tests/core/pyspec/eth2spec/test/{eip4844/fork/test_eip4844_fork_basic.py => deneb/fork/test_deneb_fork_basic.py} (55%) create mode 100644 tests/core/pyspec/eth2spec/test/deneb/fork/test_deneb_fork_random.py rename tests/core/pyspec/eth2spec/test/{eip4844 => deneb}/random/__init__.py (100%) rename tests/core/pyspec/eth2spec/test/{eip4844 => deneb}/random/test_random.py (63%) rename tests/core/pyspec/eth2spec/test/{eip4844 => deneb}/sanity/__init__.py (100%) rename tests/core/pyspec/eth2spec/test/{eip4844 => deneb}/sanity/test_blocks.py (95%) rename tests/core/pyspec/eth2spec/test/{eip4844 => deneb}/unittests/__init__.py (100%) rename tests/core/pyspec/eth2spec/test/{eip4844 => deneb}/unittests/fork_choice/__init__.py (100%) rename tests/core/pyspec/eth2spec/test/{eip4844 => deneb}/unittests/fork_choice/test_validate_blobs_sidecar.py (93%) rename tests/core/pyspec/eth2spec/test/{eip4844 => deneb}/unittests/polynomial_commitments/__init__.py (100%) rename tests/core/pyspec/eth2spec/test/{eip4844 => deneb}/unittests/polynomial_commitments/test_polynomial_commitments.py (96%) rename tests/core/pyspec/eth2spec/test/{eip4844 => deneb}/unittests/test_kzg.py (91%) rename tests/core/pyspec/eth2spec/test/{eip4844 => deneb}/unittests/test_offset.py (94%) delete mode 100644 tests/core/pyspec/eth2spec/test/eip4844/fork/test_eip4844_fork_random.py rename tests/core/pyspec/eth2spec/test/helpers/{eip4844 => deneb}/__init__.py (100%) rename tests/core/pyspec/eth2spec/test/helpers/{eip4844 => deneb}/fork.py (90%) diff --git a/.circleci/config.yml b/.circleci/config.yml index 94065d0bb..665207bdd 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -142,7 +142,7 @@ jobs: command: make citest fork=capella - store_test_results: path: tests/core/pyspec/test-reports - test-eip4844: + test-deneb: docker: - image: circleci/python:3.8 working_directory: ~/specs-repo @@ -152,7 +152,7 @@ jobs: - restore_pyspec_cached_venv - run: name: Run py-tests - command: make citest fork=eip4844 + command: make citest fork=deneb - store_test_results: path: tests/core/pyspec/test-reports table_of_contents: @@ -272,7 +272,7 @@ workflows: - test-capella: requires: - install_pyspec_test - - test-eip4844: + - test-deneb: requires: - install_pyspec_test - table_of_contents diff --git a/.github/workflows/run-tests.yml b/.github/workflows/run-tests.yml index 2c7b9d883..926c3fbbf 100644 --- a/.github/workflows/run-tests.yml +++ b/.github/workflows/run-tests.yml @@ -83,7 +83,7 @@ jobs: needs: [preclear,lint,codespell,table_of_contents] strategy: matrix: - version: ["phase0", "altair", "bellatrix", "capella", "eip4844"] + version: ["phase0", "altair", "bellatrix", "capella", "deneb"] steps: - name: Checkout this repo uses: actions/checkout@v3.2.0 diff --git a/.gitignore b/.gitignore index 219251599..c49e6c006 100644 --- a/.gitignore +++ b/.gitignore @@ -19,7 +19,7 @@ tests/core/pyspec/eth2spec/phase0/ tests/core/pyspec/eth2spec/altair/ tests/core/pyspec/eth2spec/bellatrix/ tests/core/pyspec/eth2spec/capella/ -tests/core/pyspec/eth2spec/eip4844/ +tests/core/pyspec/eth2spec/deneb/ # coverage reports .htmlcov diff --git a/Makefile b/Makefile index 8604fac27..854f42ce3 100644 --- a/Makefile +++ b/Makefile @@ -30,7 +30,7 @@ MARKDOWN_FILES = $(wildcard $(SPEC_DIR)/phase0/*.md) \ $(wildcard $(SPEC_DIR)/custody/*.md) \ $(wildcard $(SPEC_DIR)/das/*.md) \ $(wildcard $(SPEC_DIR)/sharding/*.md) \ - $(wildcard $(SPEC_DIR)/eip4844/*.md) $(wildcard $(SPEC_DIR)/eip4844/**/*.md) \ + $(wildcard $(SPEC_DIR)/deneb/*.md) $(wildcard $(SPEC_DIR)/deneb/**/*.md) \ $(wildcard $(SSZ_DIR)/*.md) COV_HTML_OUT=.htmlcov @@ -67,7 +67,7 @@ partial_clean: rm -rf $(ETH2SPEC_MODULE_DIR)/altair rm -rf $(ETH2SPEC_MODULE_DIR)/bellatrix rm -rf $(ETH2SPEC_MODULE_DIR)/capella - rm -rf $(ETH2SPEC_MODULE_DIR)/eip4844 + rm -rf $(ETH2SPEC_MODULE_DIR)/deneb rm -rf $(COV_HTML_OUT_DIR) rm -rf $(TEST_REPORT_DIR) rm -rf eth2spec.egg-info dist build @@ -105,12 +105,12 @@ install_test: # Testing against `minimal` or `mainnet` config by default test: pyspec . venv/bin/activate; cd $(PY_SPEC_DIR); \ - python3 -m pytest -n 4 --disable-bls --cov=eth2spec.phase0.$(TEST_PRESET_TYPE) --cov=eth2spec.altair.$(TEST_PRESET_TYPE) --cov=eth2spec.bellatrix.$(TEST_PRESET_TYPE) --cov=eth2spec.capella.$(TEST_PRESET_TYPE) --cov=eth2spec.eip4844.$(TEST_PRESET_TYPE) --cov-report="html:$(COV_HTML_OUT)" --cov-branch eth2spec + python3 -m pytest -n 4 --disable-bls --cov=eth2spec.phase0.$(TEST_PRESET_TYPE) --cov=eth2spec.altair.$(TEST_PRESET_TYPE) --cov=eth2spec.bellatrix.$(TEST_PRESET_TYPE) --cov=eth2spec.capella.$(TEST_PRESET_TYPE) --cov=eth2spec.deneb.$(TEST_PRESET_TYPE) --cov-report="html:$(COV_HTML_OUT)" --cov-branch eth2spec # Testing against `minimal` or `mainnet` config by default find_test: pyspec . venv/bin/activate; cd $(PY_SPEC_DIR); \ - python3 -m pytest -k=$(K) --disable-bls --cov=eth2spec.phase0.$(TEST_PRESET_TYPE) --cov=eth2spec.altair.$(TEST_PRESET_TYPE) --cov=eth2spec.bellatrix.$(TEST_PRESET_TYPE) --cov=eth2spec.capella.$(TEST_PRESET_TYPE) --cov=eth2spec.eip4844.$(TEST_PRESET_TYPE) --cov-report="html:$(COV_HTML_OUT)" --cov-branch eth2spec + python3 -m pytest -k=$(K) --disable-bls --cov=eth2spec.phase0.$(TEST_PRESET_TYPE) --cov=eth2spec.altair.$(TEST_PRESET_TYPE) --cov=eth2spec.bellatrix.$(TEST_PRESET_TYPE) --cov=eth2spec.capella.$(TEST_PRESET_TYPE) --cov=eth2spec.deneb.$(TEST_PRESET_TYPE) --cov-report="html:$(COV_HTML_OUT)" --cov-branch eth2spec citest: pyspec mkdir -p $(TEST_REPORT_DIR); @@ -142,8 +142,8 @@ codespell: lint: pyspec . venv/bin/activate; cd $(PY_SPEC_DIR); \ flake8 --config $(LINTER_CONFIG_FILE) ./eth2spec \ - && pylint --rcfile $(LINTER_CONFIG_FILE) ./eth2spec/phase0 ./eth2spec/altair ./eth2spec/bellatrix ./eth2spec/capella ./eth2spec/eip4844 \ - && mypy --config-file $(LINTER_CONFIG_FILE) -p eth2spec.phase0 -p eth2spec.altair -p eth2spec.bellatrix -p eth2spec.capella -p eth2spec.eip4844 + && pylint --rcfile $(LINTER_CONFIG_FILE) ./eth2spec/phase0 ./eth2spec/altair ./eth2spec/bellatrix ./eth2spec/capella ./eth2spec/deneb \ + && mypy --config-file $(LINTER_CONFIG_FILE) -p eth2spec.phase0 -p eth2spec.altair -p eth2spec.bellatrix -p eth2spec.capella -p eth2spec.deneb lint_generators: pyspec . venv/bin/activate; cd $(TEST_GENERATORS_DIR); \ diff --git a/README.md b/README.md index ed8771cb0..466c15193 100644 --- a/README.md +++ b/README.md @@ -25,7 +25,7 @@ Features are researched and developed in parallel, and then consolidated into se | Code Name or Topic | Specs | Notes | | - | - | - | | Capella (tentative) |
  • Core
    • [Beacon chain changes](specs/capella/beacon-chain.md)
    • [Capella fork](specs/capella/fork.md)
  • Additions
    • [Light client sync protocol changes](specs/capella/light-client/sync-protocol.md) ([fork](specs/capella/light-client/fork.md), [full node](specs/capella/light-client/full-node.md), [networking](specs/capella/light-client/p2p-interface.md))
    • [Validator additions](specs/capella/validator.md)
    • [P2P networking](specs/capella/p2p-interface.md)
| -| EIP4844 (tentative) |
  • Core
    • [Beacon Chain changes](specs/eip4844/beacon-chain.md)
    • [EIP-4844 fork](specs/eip4844/fork.md)
    • [Polynomial commitments](specs/eip4844/polynomial-commitments.md)
    • [Fork choice changes](specs/eip4844/fork-choice.md)
  • Additions
    • [Light client sync protocol changes](specs/eip4844/light-client/sync-protocol.md) ([fork](specs/eip4844/light-client/fork.md), [full node](specs/eip4844/light-client/full-node.md), [networking](specs/eip4844/light-client/p2p-interface.md))
    • [Honest validator guide changes](specs/eip4844/validator.md)
    • [P2P networking](specs/eip4844/p2p-interface.md)
| +| Deneb (tentative) |
  • Core
    • [Beacon Chain changes](specs/deneb/beacon-chain.md)
    • [EIP-4844 fork](specs/deneb/fork.md)
    • [Polynomial commitments](specs/deneb/polynomial-commitments.md)
    • [Fork choice changes](specs/deneb/fork-choice.md)
  • Additions
    • [Light client sync protocol changes](specs/deneb/light-client/sync-protocol.md) ([fork](specs/deneb/light-client/fork.md), [full node](specs/deneb/light-client/full-node.md), [networking](specs/deneb/light-client/p2p-interface.md))
    • [Honest validator guide changes](specs/deneb/validator.md)
    • [P2P networking](specs/deneb/p2p-interface.md)
| | Sharding (outdated) |
  • Core
    • [Beacon Chain changes](specs/sharding/beacon-chain.md)
  • Additions
    • [P2P networking](specs/sharding/p2p-interface.md)
| | Custody Game (outdated) |
  • Core
    • [Beacon Chain changes](specs/custody_game/beacon-chain.md)
  • Additions
    • [Honest validator guide changes](specs/custody_game/validator.md)
| Dependent on sharding | | Data Availability Sampling (outdated) |
  • Core
    • [Core types and functions](specs/das/das-core.md)
    • [Fork choice changes](specs/das/fork-choice.md)
  • Additions
    • [P2P Networking](specs/das/p2p-interface.md)
    • [Sampling process](specs/das/sampling.md)
|
  • Dependent on sharding
  • [Technical explainer](https://hackmd.io/@HWeNw8hNRimMm2m2GH56Cw/B1YJPGkpD)
| diff --git a/configs/mainnet.yaml b/configs/mainnet.yaml index 929d39f8a..f7e53d7e1 100644 --- a/configs/mainnet.yaml +++ b/configs/mainnet.yaml @@ -47,9 +47,9 @@ BELLATRIX_FORK_EPOCH: 144896 # Sept 6, 2022, 11:34:47am UTC # Capella CAPELLA_FORK_VERSION: 0x03000000 CAPELLA_FORK_EPOCH: 18446744073709551615 -# EIP4844 -EIP4844_FORK_VERSION: 0x04000000 -EIP4844_FORK_EPOCH: 18446744073709551615 +# Deneb +DENEB_FORK_VERSION: 0x04000000 +DENEB_FORK_EPOCH: 18446744073709551615 diff --git a/configs/minimal.yaml b/configs/minimal.yaml index 5dde4b749..abecb1881 100644 --- a/configs/minimal.yaml +++ b/configs/minimal.yaml @@ -46,9 +46,9 @@ BELLATRIX_FORK_EPOCH: 18446744073709551615 # Capella CAPELLA_FORK_VERSION: 0x03000001 CAPELLA_FORK_EPOCH: 18446744073709551615 -# EIP4844 -EIP4844_FORK_VERSION: 0x04000001 -EIP4844_FORK_EPOCH: 18446744073709551615 +# DENEB +DENEB_FORK_VERSION: 0x04000001 +DENEB_FORK_EPOCH: 18446744073709551615 # Time parameters diff --git a/presets/mainnet/eip4844.yaml b/presets/mainnet/deneb.yaml similarity index 100% rename from presets/mainnet/eip4844.yaml rename to presets/mainnet/deneb.yaml diff --git a/presets/minimal/eip4844.yaml b/presets/minimal/deneb.yaml similarity index 100% rename from presets/minimal/eip4844.yaml rename to presets/minimal/deneb.yaml diff --git a/setup.py b/setup.py index 9102f819b..f87ed5a6c 100644 --- a/setup.py +++ b/setup.py @@ -46,7 +46,7 @@ PHASE0 = 'phase0' ALTAIR = 'altair' BELLATRIX = 'bellatrix' CAPELLA = 'capella' -EIP4844 = 'eip4844' +DENEB = 'deneb' # The helper functions that are used when defining constants @@ -632,10 +632,10 @@ def compute_merkle_proof_for_block_body(body: BeaconBlockBody, return {**super().hardcoded_ssz_dep_constants(), **constants} # -# EIP4844SpecBuilder +# DenebSpecBuilder # -class EIP4844SpecBuilder(CapellaSpecBuilder): - fork: str = EIP4844 +class DenebSpecBuilder(CapellaSpecBuilder): + fork: str = DENEB @classmethod def imports(cls, preset_name: str): @@ -669,7 +669,7 @@ def retrieve_blobs_sidecar(slot: Slot, beacon_block_root: Root) -> PyUnion[Blobs spec_builders = { builder.fork: builder - for builder in (Phase0SpecBuilder, AltairSpecBuilder, BellatrixSpecBuilder, CapellaSpecBuilder, EIP4844SpecBuilder) + for builder in (Phase0SpecBuilder, AltairSpecBuilder, BellatrixSpecBuilder, CapellaSpecBuilder, DenebSpecBuilder) } @@ -968,14 +968,14 @@ class PySpecCommand(Command): 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, EIP4844): + if self.spec_fork in (PHASE0, ALTAIR, BELLATRIX, CAPELLA, DENEB): 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, EIP4844): + if self.spec_fork in (ALTAIR, BELLATRIX, CAPELLA, DENEB): self.md_doc_paths += """ specs/altair/light-client/full-node.md specs/altair/light-client/light-client.md @@ -987,7 +987,7 @@ class PySpecCommand(Command): specs/altair/validator.md specs/altair/p2p-interface.md """ - if self.spec_fork in (BELLATRIX, CAPELLA, EIP4844): + if self.spec_fork in (BELLATRIX, CAPELLA, DENEB): self.md_doc_paths += """ specs/bellatrix/beacon-chain.md specs/bellatrix/fork.md @@ -996,7 +996,7 @@ class PySpecCommand(Command): specs/bellatrix/p2p-interface.md sync/optimistic.md """ - if self.spec_fork in (CAPELLA, EIP4844): + if self.spec_fork in (CAPELLA, DENEB): self.md_doc_paths += """ specs/capella/light-client/fork.md specs/capella/light-client/full-node.md @@ -1008,18 +1008,18 @@ class PySpecCommand(Command): specs/capella/validator.md specs/capella/p2p-interface.md """ - if self.spec_fork == EIP4844: + if self.spec_fork == DENEB: self.md_doc_paths += """ - specs/eip4844/light-client/fork.md - specs/eip4844/light-client/full-node.md - specs/eip4844/light-client/p2p-interface.md - specs/eip4844/light-client/sync-protocol.md - specs/eip4844/beacon-chain.md - specs/eip4844/fork.md - specs/eip4844/fork-choice.md - specs/eip4844/polynomial-commitments.md - specs/eip4844/p2p-interface.md - specs/eip4844/validator.md + specs/deneb/light-client/fork.md + specs/deneb/light-client/full-node.md + specs/deneb/light-client/p2p-interface.md + specs/deneb/light-client/sync-protocol.md + specs/deneb/beacon-chain.md + specs/deneb/fork.md + specs/deneb/fork-choice.md + specs/deneb/polynomial-commitments.md + specs/deneb/p2p-interface.md + specs/deneb/validator.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/eip4844/beacon-chain.md b/specs/deneb/beacon-chain.md similarity index 98% rename from specs/eip4844/beacon-chain.md rename to specs/deneb/beacon-chain.md index f681ab951..87ebf7a9e 100644 --- a/specs/eip4844/beacon-chain.md +++ b/specs/deneb/beacon-chain.md @@ -249,7 +249,7 @@ def process_blob_kzg_commitments(state: BeaconState, body: BeaconBlockBody) -> N *Note*: The function `initialize_beacon_state_from_eth1` is modified for pure EIP-4844 testing only. -The `BeaconState` initialization is unchanged, except for the use of the updated `eip4844.BeaconBlockBody` type +The `BeaconState` initialization is unchanged, except for the use of the updated `deneb.BeaconBlockBody` type when initializing the first body-root. ```python @@ -259,8 +259,8 @@ def initialize_beacon_state_from_eth1(eth1_block_hash: Hash32, execution_payload_header: ExecutionPayloadHeader=ExecutionPayloadHeader() ) -> BeaconState: fork = Fork( - previous_version=EIP4844_FORK_VERSION, # [Modified in EIP-4844] for testing only - current_version=EIP4844_FORK_VERSION, # [Modified in EIP-4844] + previous_version=DENEB_FORK_VERSION, # [Modified in Deneb] for testing only + current_version=DENEB_FORK_VERSION, # [Modified in Deneb] epoch=GENESIS_EPOCH, ) state = BeaconState( diff --git a/specs/eip4844/fork-choice.md b/specs/deneb/fork-choice.md similarity index 100% rename from specs/eip4844/fork-choice.md rename to specs/deneb/fork-choice.md diff --git a/specs/eip4844/fork.md b/specs/deneb/fork.md similarity index 86% rename from specs/eip4844/fork.md rename to specs/deneb/fork.md index 39521879a..864e28888 100644 --- a/specs/eip4844/fork.md +++ b/specs/deneb/fork.md @@ -28,8 +28,8 @@ Warning: this configuration is not definitive. | Name | Value | | - | - | -| `EIP4844_FORK_VERSION` | `Version('0x04000000')` | -| `EIP4844_FORK_EPOCH` | `Epoch(18446744073709551615)` **TBD** | +| `DENEB_FORK_VERSION` | `Version('0x04000000')` | +| `DENEB_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 >= EIP4844_FORK_EPOCH: - return EIP4844_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: @@ -58,16 +58,16 @@ 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. -For now, we assume the condition will be triggered at epoch `EIP4844_FORK_EPOCH`. +For now, we assume the condition will be triggered at epoch `DENEB_FORK_EPOCH`. -Note that for the pure EIP-4844 networks, we don't apply `upgrade_to_eip4844` since it starts with EIP-4844 version logic. +Note that for the pure Deneb networks, we don't apply `upgrade_to_deneb` since it starts with Deneb version logic. ### Upgrading the state -Since the `eip4844.BeaconState` format is equal to the `capella.BeaconState` format, we only have to update `BeaconState.fork`. +Since the `deneb.BeaconState` format is equal to the `capella.BeaconState` format, we only have to update `BeaconState.fork`. ```python -def upgrade_to_eip4844(pre: capella.BeaconState) -> BeaconState: +def upgrade_to_deneb(pre: capella.BeaconState) -> BeaconState: epoch = capella.get_current_epoch(pre) latest_execution_payload_header = ExecutionPayloadHeader( parent_hash=pre.latest_execution_payload_header.parent_hash, @@ -94,7 +94,7 @@ def upgrade_to_eip4844(pre: capella.BeaconState) -> BeaconState: slot=pre.slot, fork=Fork( previous_version=pre.fork.current_version, - current_version=EIP4844_FORK_VERSION, # [Modified in EIP4844] + current_version=DENEB_FORK_VERSION, # [Modified in Deneb] epoch=epoch, ), # History @@ -127,7 +127,7 @@ def upgrade_to_eip4844(pre: capella.BeaconState) -> BeaconState: current_sync_committee=pre.current_sync_committee, next_sync_committee=pre.next_sync_committee, # Execution-layer - latest_execution_payload_header=latest_execution_payload_header, # [Modified in EIP4844] + latest_execution_payload_header=latest_execution_payload_header, # [Modified in Deneb] # Withdrawals next_withdrawal_index=pre.next_withdrawal_index, next_withdrawal_validator_index=pre.next_withdrawal_validator_index, diff --git a/specs/eip4844/light-client/fork.md b/specs/deneb/light-client/fork.md similarity index 62% rename from specs/eip4844/light-client/fork.md rename to specs/deneb/light-client/fork.md index 2d5f74f46..8c552937a 100644 --- a/specs/eip4844/light-client/fork.md +++ b/specs/deneb/light-client/fork.md @@ -1,4 +1,4 @@ -# EIP4844 Light Client -- Fork Logic +# Deneb Light Client -- Fork Logic ## Table of contents @@ -15,14 +15,14 @@ ## Introduction -This document describes how to upgrade existing light client objects based on the [Capella specification](../../capella/light-client/sync-protocol.md) to EIP4844. This is necessary when processing pre-EIP4844 data with a post-EIP4844 `LightClientStore`. Note that the data being exchanged over the network protocols uses the original format. +This document describes how to upgrade existing light client objects based on the [Capella specification](../../capella/light-client/sync-protocol.md) to Deneb. This is necessary when processing pre-Deneb data with a post-Deneb `LightClientStore`. Note that the data being exchanged over the network protocols uses the original format. ### Upgrading light client data -A EIP4844 `LightClientStore` can still process earlier light client data. In order to do so, that pre-EIP4844 data needs to be locally upgraded to EIP4844 before processing. +A Deneb `LightClientStore` can still process earlier light client data. In order to do so, that pre-Deneb data needs to be locally upgraded to Deneb before processing. ```python -def upgrade_lc_header_to_eip4844(pre: capella.LightClientHeader) -> LightClientHeader: +def upgrade_lc_header_to_deneb(pre: capella.LightClientHeader) -> LightClientHeader: return LightClientHeader( beacon=pre.beacon, execution=ExecutionPayloadHeader( @@ -47,21 +47,21 @@ def upgrade_lc_header_to_eip4844(pre: capella.LightClientHeader) -> LightClientH ``` ```python -def upgrade_lc_bootstrap_to_eip4844(pre: capella.LightClientBootstrap) -> LightClientBootstrap: +def upgrade_lc_bootstrap_to_deneb(pre: capella.LightClientBootstrap) -> LightClientBootstrap: return LightClientBootstrap( - header=upgrade_lc_header_to_eip4844(pre.header), + header=upgrade_lc_header_to_deneb(pre.header), current_sync_committee=pre.current_sync_committee, current_sync_committee_branch=pre.current_sync_committee_branch, ) ``` ```python -def upgrade_lc_update_to_eip4844(pre: capella.LightClientUpdate) -> LightClientUpdate: +def upgrade_lc_update_to_deneb(pre: capella.LightClientUpdate) -> LightClientUpdate: return LightClientUpdate( - attested_header=upgrade_lc_header_to_eip4844(pre.attested_header), + attested_header=upgrade_lc_header_to_deneb(pre.attested_header), next_sync_committee=pre.next_sync_committee, next_sync_committee_branch=pre.next_sync_committee_branch, - finalized_header=upgrade_lc_header_to_eip4844(pre.finalized_header), + finalized_header=upgrade_lc_header_to_deneb(pre.finalized_header), finality_branch=pre.finality_branch, sync_aggregate=pre.sync_aggregate, signature_slot=pre.signature_slot, @@ -69,10 +69,10 @@ def upgrade_lc_update_to_eip4844(pre: capella.LightClientUpdate) -> LightClientU ``` ```python -def upgrade_lc_finality_update_to_eip4844(pre: capella.LightClientFinalityUpdate) -> LightClientFinalityUpdate: +def upgrade_lc_finality_update_to_deneb(pre: capella.LightClientFinalityUpdate) -> LightClientFinalityUpdate: return LightClientFinalityUpdate( - attested_header=upgrade_lc_header_to_eip4844(pre.attested_header), - finalized_header=upgrade_lc_header_to_eip4844(pre.finalized_header), + attested_header=upgrade_lc_header_to_deneb(pre.attested_header), + finalized_header=upgrade_lc_header_to_deneb(pre.finalized_header), finality_branch=pre.finality_branch, sync_aggregate=pre.sync_aggregate, signature_slot=pre.signature_slot, @@ -80,9 +80,9 @@ def upgrade_lc_finality_update_to_eip4844(pre: capella.LightClientFinalityUpdate ``` ```python -def upgrade_lc_optimistic_update_to_eip4844(pre: capella.LightClientOptimisticUpdate) -> LightClientOptimisticUpdate: +def upgrade_lc_optimistic_update_to_deneb(pre: capella.LightClientOptimisticUpdate) -> LightClientOptimisticUpdate: return LightClientOptimisticUpdate( - attested_header=upgrade_lc_header_to_eip4844(pre.attested_header), + attested_header=upgrade_lc_header_to_deneb(pre.attested_header), sync_aggregate=pre.sync_aggregate, signature_slot=pre.signature_slot, ) @@ -90,20 +90,20 @@ def upgrade_lc_optimistic_update_to_eip4844(pre: capella.LightClientOptimisticUp ### Upgrading the store -Existing `LightClientStore` objects based on Capella MUST be upgraded to EIP4844 before EIP4844 based light client data can be processed. The `LightClientStore` upgrade MAY be performed before `EIP4844_FORK_EPOCH`. +Existing `LightClientStore` objects based on Capella MUST be upgraded to Deneb before Deneb based light client data can be processed. The `LightClientStore` upgrade MAY be performed before `DENEB_FORK_EPOCH`. ```python -def upgrade_lc_store_to_eip4844(pre: capella.LightClientStore) -> LightClientStore: +def upgrade_lc_store_to_deneb(pre: capella.LightClientStore) -> LightClientStore: if pre.best_valid_update is None: best_valid_update = None else: - best_valid_update = upgrade_lc_update_to_eip4844(pre.best_valid_update) + best_valid_update = upgrade_lc_update_to_deneb(pre.best_valid_update) return LightClientStore( - finalized_header=upgrade_lc_header_to_eip4844(pre.finalized_header), + finalized_header=upgrade_lc_header_to_deneb(pre.finalized_header), current_sync_committee=pre.current_sync_committee, next_sync_committee=pre.next_sync_committee, best_valid_update=best_valid_update, - optimistic_header=upgrade_lc_header_to_eip4844(pre.optimistic_header), + optimistic_header=upgrade_lc_header_to_deneb(pre.optimistic_header), previous_max_active_participants=pre.previous_max_active_participants, current_max_active_participants=pre.current_max_active_participants, ) diff --git a/specs/eip4844/light-client/full-node.md b/specs/deneb/light-client/full-node.md similarity index 94% rename from specs/eip4844/light-client/full-node.md rename to specs/deneb/light-client/full-node.md index 70983e1b3..275194036 100644 --- a/specs/eip4844/light-client/full-node.md +++ b/specs/deneb/light-client/full-node.md @@ -1,4 +1,4 @@ -# EIP4844 Light Client -- Full Node +# Deneb Light Client -- Full Node **Notice**: This document is a work-in-progress for researchers and implementers. @@ -17,7 +17,7 @@ ## Introduction -This upgrade adds information about the execution payload to light client data as part of the EIP4844 upgrade. +This upgrade adds information about the execution payload to light client data as part of the Deneb upgrade. ## Helper functions @@ -47,8 +47,8 @@ def block_to_light_client_header(block: SignedBeaconBlock) -> LightClientHeader: withdrawals_root=hash_tree_root(payload.withdrawals), ) - # [New in EIP4844] - if epoch >= EIP4844_FORK_EPOCH: + # [New in Deneb] + if epoch >= DENEB_FORK_EPOCH: execution_header.excess_data_gas = payload.excess_data_gas execution_branch = compute_merkle_proof_for_block_body(block.message.body, EXECUTION_PAYLOAD_INDEX) diff --git a/specs/eip4844/light-client/p2p-interface.md b/specs/deneb/light-client/p2p-interface.md similarity index 65% rename from specs/eip4844/light-client/p2p-interface.md rename to specs/deneb/light-client/p2p-interface.md index f3d89c130..0ca53056a 100644 --- a/specs/eip4844/light-client/p2p-interface.md +++ b/specs/deneb/light-client/p2p-interface.md @@ -1,4 +1,4 @@ -# EIP4844 Light Client -- Networking +# Deneb Light Client -- Networking **Notice**: This document is a work-in-progress for researchers and implementers. @@ -26,7 +26,7 @@ ## Networking -The [Capella light client networking specification](../../capella/light-client/p2p-interface.md) is extended to exchange [EIP4844 light client data](./sync-protocol.md). +The [Capella light client networking specification](../../capella/light-client/p2p-interface.md) is extended to exchange [Deneb light client data](./sync-protocol.md). ### The gossip domain: gossipsub @@ -38,23 +38,23 @@ The [Capella light client networking specification](../../capella/light-client/p [0]: # (eth2spec: skip) -| `fork_version` | Message SSZ type | -| ------------------------------------------------------ | ------------------------------------- | -| `GENESIS_FORK_VERSION` | n/a | -| `ALTAIR_FORK_VERSION` through `BELLATRIX_FORK_VERSION` | `altair.LightClientFinalityUpdate` | -| `CAPELLA_FORK_VERSION` | `capella.LightClientFinalityUpdate` | -| `EIP4844_FORK_VERSION` and later | `eip4844.LightClientFinalityUpdate` | +| `fork_version` | Message SSZ type | +|--------------------------------------------------------|-------------------------------------| +| `GENESIS_FORK_VERSION` | n/a | +| `ALTAIR_FORK_VERSION` through `BELLATRIX_FORK_VERSION` | `altair.LightClientFinalityUpdate` | +| `CAPELLA_FORK_VERSION` | `capella.LightClientFinalityUpdate` | +| `DENEB_FORK_VERSION` and later | `deneb.LightClientFinalityUpdate` | ###### `light_client_optimistic_update` [0]: # (eth2spec: skip) | `fork_version` | Message SSZ type | -| ------------------------------------------------------ | ------------------------------------- | +|--------------------------------------------------------|---------------------------------------| | `GENESIS_FORK_VERSION` | n/a | | `ALTAIR_FORK_VERSION` through `BELLATRIX_FORK_VERSION` | `altair.LightClientOptimisticUpdate` | | `CAPELLA_FORK_VERSION` | `capella.LightClientOptimisticUpdate` | -| `EIP4844_FORK_VERSION` and later | `eip4844.LightClientOptimisticUpdate` | +| `DENEB_FORK_VERSION` and later | `deneb.LightClientOptimisticUpdate` | ### The Req/Resp domain @@ -64,42 +64,42 @@ The [Capella light client networking specification](../../capella/light-client/p [0]: # (eth2spec: skip) -| `fork_version` | Response SSZ type | -| ------------------------------------------------------ | ------------------------------------- | -| `GENESIS_FORK_VERSION` | n/a | -| `ALTAIR_FORK_VERSION` through `BELLATRIX_FORK_VERSION` | `altair.LightClientBootstrap` | -| `CAPELLA_FORK_VERSION` | `capella.LightClientBootstrap` | -| `EIP4844_FORK_VERSION` and later | `eip4844.LightClientBootstrap` | +| `fork_version` | Response SSZ type | +|--------------------------------------------------------|------------------------------------| +| `GENESIS_FORK_VERSION` | n/a | +| `ALTAIR_FORK_VERSION` through `BELLATRIX_FORK_VERSION` | `altair.LightClientBootstrap` | +| `CAPELLA_FORK_VERSION` | `capella.LightClientBootstrap` | +| `DENEB_FORK_VERSION` and later | `deneb.LightClientBootstrap` | ##### LightClientUpdatesByRange [0]: # (eth2spec: skip) -| `fork_version` | Response chunk SSZ type | -| ------------------------------------------------------ | ------------------------------------- | -| `GENESIS_FORK_VERSION` | n/a | -| `ALTAIR_FORK_VERSION` through `BELLATRIX_FORK_VERSION` | `altair.LightClientUpdate` | -| `CAPELLA_FORK_VERSION` | `capella.LightClientUpdate` | -| `EIP4844_FORK_VERSION` and later | `eip4844.LightClientUpdate` | +| `fork_version` | Response chunk SSZ type | +|--------------------------------------------------------|----------------------------------| +| `GENESIS_FORK_VERSION` | n/a | +| `ALTAIR_FORK_VERSION` through `BELLATRIX_FORK_VERSION` | `altair.LightClientUpdate` | +| `CAPELLA_FORK_VERSION` | `capella.LightClientUpdate` | +| `DENEB_FORK_VERSION` and later | `deneb.LightClientUpdate` | ##### GetLightClientFinalityUpdate [0]: # (eth2spec: skip) -| `fork_version` | Response SSZ type | -| ------------------------------------------------------ | ------------------------------------- | -| `GENESIS_FORK_VERSION` | n/a | -| `ALTAIR_FORK_VERSION` through `BELLATRIX_FORK_VERSION` | `altair.LightClientFinalityUpdate` | -| `CAPELLA_FORK_VERSION` | `capella.LightClientFinalityUpdate` | -| `EIP4844_FORK_VERSION` and later | `eip4844.LightClientFinalityUpdate` | +| `fork_version` | Response SSZ type | +|--------------------------------------------------------|-------------------------------------| +| `GENESIS_FORK_VERSION` | n/a | +| `ALTAIR_FORK_VERSION` through `BELLATRIX_FORK_VERSION` | `altair.LightClientFinalityUpdate` | +| `CAPELLA_FORK_VERSION` | `capella.LightClientFinalityUpdate` | +| `DENEB_FORK_VERSION` and later | `deneb.LightClientFinalityUpdate` | ##### GetLightClientOptimisticUpdate [0]: # (eth2spec: skip) | `fork_version` | Response SSZ type | -| ------------------------------------------------------ | ------------------------------------- | +|--------------------------------------------------------|---------------------------------------| | `GENESIS_FORK_VERSION` | n/a | | `ALTAIR_FORK_VERSION` through `BELLATRIX_FORK_VERSION` | `altair.LightClientOptimisticUpdate` | | `CAPELLA_FORK_VERSION` | `capella.LightClientOptimisticUpdate` | -| `EIP4844_FORK_VERSION` and later | `eip4844.LightClientOptimisticUpdate` | +| `DENEB_FORK_VERSION` and later | `deneb.LightClientOptimisticUpdate` | diff --git a/specs/eip4844/light-client/sync-protocol.md b/specs/deneb/light-client/sync-protocol.md similarity index 84% rename from specs/eip4844/light-client/sync-protocol.md rename to specs/deneb/light-client/sync-protocol.md index 181ca14eb..6f948257b 100644 --- a/specs/eip4844/light-client/sync-protocol.md +++ b/specs/deneb/light-client/sync-protocol.md @@ -1,4 +1,4 @@ -# EIP4844 Light Client -- Sync Protocol +# Deneb Light Client -- Sync Protocol **Notice**: This document is a work-in-progress for researchers and implementers. @@ -18,7 +18,7 @@ ## Introduction -This upgrade updates light client data to include the EIP4844 changes to the [`ExecutionPayload`](../beacon-chain.md) structure. It extends the [Capella Light Client specifications](../../capella/light-client/sync-protocol.md). The [fork document](./fork.md) explains how to upgrade existing Capella based deployments to EIP4844. +This upgrade updates light client data to include the Denbeb changes to the [`ExecutionPayload`](../beacon-chain.md) structure. It extends the [Capella Light Client specifications](../../capella/light-client/sync-protocol.md). The [fork document](./fork.md) explains how to upgrade existing Capella based deployments to Deneb. Additional documents describes the impact of the upgrade on certain roles: - [Full node](./full-node.md) @@ -32,11 +32,11 @@ Additional documents describes the impact of the upgrade on certain roles: def get_lc_execution_root(header: LightClientHeader) -> Root: epoch = compute_epoch_at_slot(header.beacon.slot) - # [New in EIP4844] - if epoch >= EIP4844_FORK_EPOCH: + # [New in Deneb] + if epoch >= DENEB_FORK_EPOCH: return hash_tree_root(header.execution) - # [Modified in EIP4844] + # [Modified in Deneb] if epoch >= CAPELLA_FORK_EPOCH: execution_header = capella.ExecutionPayloadHeader( parent_hash=header.execution.parent_hash, @@ -66,8 +66,8 @@ def get_lc_execution_root(header: LightClientHeader) -> Root: def is_valid_light_client_header(header: LightClientHeader) -> bool: epoch = compute_epoch_at_slot(header.beacon.slot) - # [New in EIP4844] - if epoch < EIP4844_FORK_EPOCH: + # [New in Deneb] + if epoch < DENEB_FORK_EPOCH: if header.execution.excess_data_gas != uint256(0): return False diff --git a/specs/eip4844/p2p-interface.md b/specs/deneb/p2p-interface.md similarity index 95% rename from specs/eip4844/p2p-interface.md rename to specs/deneb/p2p-interface.md index 3e0456713..5e21bc542 100644 --- a/specs/eip4844/p2p-interface.md +++ b/specs/deneb/p2p-interface.md @@ -124,13 +124,13 @@ Per `context = compute_fork_digest(fork_version, genesis_validators_root)`: | `ALTAIR_FORK_VERSION` | `altair.SignedBeaconBlock` | | `BELLATRIX_FORK_VERSION` | `bellatrix.SignedBeaconBlock` | | `CAPELLA_FORK_VERSION` | `capella.SignedBeaconBlock` | -| `EIP4844_FORK_VERSION` | `eip4844.SignedBeaconBlock` | +| `DENEB_FORK_VERSION` | `deneb.SignedBeaconBlock` | #### BeaconBlocksByRoot v2 **Protocol ID:** `/eth2/beacon_chain/req/beacon_blocks_by_root/2/` -After `EIP4844_FORK_EPOCH`, `BeaconBlocksByRootV2` is replaced by `BeaconBlockAndBlobsSidecarByRootV1`. +After `DENEB_FORK_EPOCH`, `BeaconBlocksByRootV2` is replaced by `BeaconBlockAndBlobsSidecarByRootV1`. Clients MUST support requesting blocks by root for pre-fork-epoch blocks. Per `context = compute_fork_digest(fork_version, genesis_validators_root)`: @@ -175,7 +175,7 @@ No more than `MAX_REQUEST_BLOCKS` may be requested at a time. The response MUST consist of zero or more `response_chunk`. Each _successful_ `response_chunk` MUST contain a single `SignedBeaconBlockAndBlobsSidecar` payload. -Clients MUST support requesting blocks and sidecars since `minimum_request_epoch`, where `minimum_request_epoch = max(finalized_epoch, current_epoch - MIN_EPOCHS_FOR_BLOBS_SIDECARS_REQUESTS, EIP4844_FORK_EPOCH)`. If any root in the request content references a block earlier than `minimum_request_epoch`, peers SHOULD respond with error code `3: ResourceUnavailable`. +Clients MUST support requesting blocks and sidecars since `minimum_request_epoch`, where `minimum_request_epoch = max(finalized_epoch, current_epoch - MIN_EPOCHS_FOR_BLOBS_SIDECARS_REQUESTS, DENEB_FORK_EPOCH)`. If any root in the request content references a block earlier than `minimum_request_epoch`, peers SHOULD respond with error code `3: ResourceUnavailable`. Clients MUST respond with at least one block and sidecar, if they have it. Clients MAY limit the number of blocks and sidecars in the response. @@ -216,7 +216,7 @@ The response MUST consist of zero or more `response_chunk`. Each _successful_ `response_chunk` MUST contain a single `BlobsSidecar` payload. Clients MUST keep a record of signed blobs sidecars seen on the epoch range -`[max(current_epoch - MIN_EPOCHS_FOR_BLOBS_SIDECARS_REQUESTS, EIP4844_FORK_EPOCH), current_epoch]` +`[max(current_epoch - MIN_EPOCHS_FOR_BLOBS_SIDECARS_REQUESTS, DENEB_FORK_EPOCH), current_epoch]` where `current_epoch` is defined by the current wall-clock time, and clients MUST support serving requests of blocks on this range. diff --git a/specs/eip4844/polynomial-commitments.md b/specs/deneb/polynomial-commitments.md similarity index 100% rename from specs/eip4844/polynomial-commitments.md rename to specs/deneb/polynomial-commitments.md diff --git a/specs/eip4844/validator.md b/specs/deneb/validator.md similarity index 100% rename from specs/eip4844/validator.md rename to specs/deneb/validator.md diff --git a/tests/core/pyspec/eth2spec/test/altair/light_client/test_sync.py b/tests/core/pyspec/eth2spec/test/altair/light_client/test_sync.py index 664b4fb44..63bec26b0 100644 --- a/tests/core/pyspec/eth2spec/test/altair/light_client/test_sync.py +++ b/tests/core/pyspec/eth2spec/test/altair/light_client/test_sync.py @@ -16,7 +16,7 @@ from eth2spec.test.helpers.attestations import ( state_transition_with_full_block, ) from eth2spec.test.helpers.constants import ( - PHASE0, ALTAIR, BELLATRIX, CAPELLA, EIP4844, + PHASE0, ALTAIR, BELLATRIX, CAPELLA, DENEB, MINIMAL, ALL_PHASES, ) @@ -24,7 +24,7 @@ from eth2spec.test.helpers.fork_transition import ( do_fork, ) from eth2spec.test.helpers.forks import ( - is_post_capella, is_post_eip4844, + is_post_capella, is_post_deneb, is_post_fork, ) from eth2spec.test.helpers.light_client import ( @@ -53,8 +53,8 @@ def needs_upgrade_to_capella(d_spec, s_spec): return is_post_capella(s_spec) and not is_post_capella(d_spec) -def needs_upgrade_to_eip4844(d_spec, s_spec): - return is_post_eip4844(s_spec) and not is_post_eip4844(d_spec) +def needs_upgrade_to_deneb(d_spec, s_spec): + return is_post_deneb(s_spec) and not is_post_deneb(d_spec) def check_lc_header_equal(d_spec, s_spec, data, upgraded): @@ -80,8 +80,8 @@ def upgrade_lc_bootstrap_to_store(d_spec, s_spec, data): upgraded = s_spec.upgrade_lc_bootstrap_to_capella(upgraded) check_lc_bootstrap_equal(d_spec, s_spec, data, upgraded) - if needs_upgrade_to_eip4844(d_spec, s_spec): - upgraded = s_spec.upgrade_lc_bootstrap_to_eip4844(upgraded) + if needs_upgrade_to_deneb(d_spec, s_spec): + upgraded = s_spec.upgrade_lc_bootstrap_to_deneb(upgraded) check_lc_bootstrap_equal(d_spec, s_spec, data, upgraded) return upgraded @@ -103,8 +103,8 @@ def upgrade_lc_update_to_store(d_spec, s_spec, data): upgraded = s_spec.upgrade_lc_update_to_capella(upgraded) check_lc_update_equal(d_spec, s_spec, data, upgraded) - if needs_upgrade_to_eip4844(d_spec, s_spec): - upgraded = s_spec.upgrade_lc_update_to_eip4844(upgraded) + if needs_upgrade_to_deneb(d_spec, s_spec): + upgraded = s_spec.upgrade_lc_update_to_deneb(upgraded) check_lc_update_equal(d_spec, s_spec, data, upgraded) return upgraded @@ -130,8 +130,8 @@ def upgrade_lc_store_to_new_spec(d_spec, s_spec, data): upgraded = s_spec.upgrade_lc_store_to_capella(upgraded) check_lc_store_equal(d_spec, s_spec, data, upgraded) - if needs_upgrade_to_eip4844(d_spec, s_spec): - upgraded = s_spec.upgrade_lc_store_to_eip4844(upgraded) + if needs_upgrade_to_deneb(d_spec, s_spec): + upgraded = s_spec.upgrade_lc_store_to_deneb(upgraded) check_lc_store_equal(d_spec, s_spec, data, upgraded) return upgraded @@ -145,8 +145,8 @@ class LightClientSyncTest(object): def get_store_fork_version(s_spec): - if is_post_eip4844(s_spec): - return s_spec.config.EIP4844_FORK_VERSION + if is_post_deneb(s_spec): + return s_spec.config.DENEB_FORK_VERSION if is_post_capella(s_spec): return s_spec.config.CAPELLA_FORK_VERSION return s_spec.config.ALTAIR_FORK_VERSION @@ -731,16 +731,16 @@ def test_capella_fork(spec, phases, state): yield from run_test_single_fork(spec, phases, state, CAPELLA) -@with_phases(phases=[CAPELLA], other_phases=[EIP4844]) +@with_phases(phases=[CAPELLA], other_phases=[DENEB]) @spec_test @with_config_overrides({ - 'EIP4844_FORK_EPOCH': 3, # `setup_test` advances to epoch 2 + 'DENEB_FORK_EPOCH': 3, # `setup_test` advances to epoch 2 }, emit=False) @with_state -@with_matching_spec_config(emitted_fork=EIP4844) +@with_matching_spec_config(emitted_fork=DENEB) @with_presets([MINIMAL], reason="too slow") -def test_eip4844_fork(spec, phases, state): - yield from run_test_single_fork(spec, phases, state, EIP4844) +def test_deneb_fork(spec, phases, state): + yield from run_test_single_fork(spec, phases, state, DENEB) def run_test_multi_fork(spec, phases, state, fork_1, fork_2): @@ -779,17 +779,17 @@ def run_test_multi_fork(spec, phases, state, fork_1, fork_2): yield from finish_test(test) -@with_phases(phases=[BELLATRIX], other_phases=[CAPELLA, EIP4844]) +@with_phases(phases=[BELLATRIX], other_phases=[CAPELLA, DENEB]) @spec_test @with_config_overrides({ 'CAPELLA_FORK_EPOCH': 3, # `setup_test` advances to epoch 2 - 'EIP4844_FORK_EPOCH': 4, + 'DENEB_FORK_EPOCH': 4, }, emit=False) @with_state -@with_matching_spec_config(emitted_fork=EIP4844) +@with_matching_spec_config(emitted_fork=DENEB) @with_presets([MINIMAL], reason="too slow") -def test_capella_eip4844_fork(spec, phases, state): - yield from run_test_multi_fork(spec, phases, state, CAPELLA, EIP4844) +def test_capella_deneb_fork(spec, phases, state): + yield from run_test_multi_fork(spec, phases, state, CAPELLA, DENEB) def run_test_upgraded_store_with_legacy_data(spec, phases, state, fork): @@ -823,10 +823,10 @@ def test_capella_store_with_legacy_data(spec, phases, state): yield from run_test_upgraded_store_with_legacy_data(spec, phases, state, CAPELLA) -@with_phases(phases=[ALTAIR, BELLATRIX, CAPELLA], other_phases=[EIP4844]) +@with_phases(phases=[ALTAIR, BELLATRIX, CAPELLA], other_phases=[DENEB]) @spec_test @with_state -@with_matching_spec_config(emitted_fork=EIP4844) +@with_matching_spec_config(emitted_fork=DENEB) @with_presets([MINIMAL], reason="too slow") -def test_eip4844_store_with_legacy_data(spec, phases, state): - yield from run_test_upgraded_store_with_legacy_data(spec, phases, state, EIP4844) +def test_deneb_store_with_legacy_data(spec, phases, state): + yield from run_test_upgraded_store_with_legacy_data(spec, phases, state, DENEB) diff --git a/tests/core/pyspec/eth2spec/test/context.py b/tests/core/pyspec/eth2spec/test/context.py index 8401b973e..38e7f0b71 100644 --- a/tests/core/pyspec/eth2spec/test/context.py +++ b/tests/core/pyspec/eth2spec/test/context.py @@ -7,12 +7,12 @@ from eth2spec.phase0 import mainnet as spec_phase0_mainnet, minimal as spec_phas from eth2spec.altair import mainnet as spec_altair_mainnet, minimal as spec_altair_minimal from eth2spec.bellatrix import mainnet as spec_bellatrix_mainnet, minimal as spec_bellatrix_minimal from eth2spec.capella import mainnet as spec_capella_mainnet, minimal as spec_capella_minimal -from eth2spec.eip4844 import mainnet as spec_eip4844_mainnet, minimal as spec_eip4844_minimal +from eth2spec.deneb import mainnet as spec_deneb_mainnet, minimal as spec_deneb_minimal from eth2spec.utils import bls from .exceptions import SkippedTest from .helpers.constants import ( - PHASE0, ALTAIR, BELLATRIX, CAPELLA, EIP4844, + PHASE0, ALTAIR, BELLATRIX, CAPELLA, DENEB, MINIMAL, MAINNET, ALL_PHASES, ALL_FORK_UPGRADES, @@ -78,14 +78,14 @@ spec_targets: Dict[PresetBaseName, Dict[SpecForkName, Spec]] = { ALTAIR: spec_altair_minimal, BELLATRIX: spec_bellatrix_minimal, CAPELLA: spec_capella_minimal, - EIP4844: spec_eip4844_minimal, + DENEB: spec_deneb_minimal, }, MAINNET: { PHASE0: spec_phase0_mainnet, ALTAIR: spec_altair_mainnet, BELLATRIX: spec_bellatrix_mainnet, CAPELLA: spec_capella_mainnet, - EIP4844: spec_eip4844_mainnet + DENEB: spec_deneb_mainnet }, } @@ -427,7 +427,7 @@ def with_all_phases_except(exclusion_phases): with_altair_and_later = with_all_phases_from(ALTAIR) with_bellatrix_and_later = with_all_phases_from(BELLATRIX) with_capella_and_later = with_all_phases_from(CAPELLA) -with_eip4844_and_later = with_all_phases_from(EIP4844) +with_deneb_and_later = with_all_phases_from(DENEB) def _get_preset_targets(kw): diff --git a/tests/core/pyspec/eth2spec/test/eip4844/__init__.py b/tests/core/pyspec/eth2spec/test/deneb/__init__.py similarity index 100% rename from tests/core/pyspec/eth2spec/test/eip4844/__init__.py rename to tests/core/pyspec/eth2spec/test/deneb/__init__.py diff --git a/tests/core/pyspec/eth2spec/test/eip4844/fork/__init__.py b/tests/core/pyspec/eth2spec/test/deneb/fork/__init__.py similarity index 100% rename from tests/core/pyspec/eth2spec/test/eip4844/fork/__init__.py rename to tests/core/pyspec/eth2spec/test/deneb/fork/__init__.py diff --git a/tests/core/pyspec/eth2spec/test/eip4844/fork/test_eip4844_fork_basic.py b/tests/core/pyspec/eth2spec/test/deneb/fork/test_deneb_fork_basic.py similarity index 55% rename from tests/core/pyspec/eth2spec/test/eip4844/fork/test_eip4844_fork_basic.py rename to tests/core/pyspec/eth2spec/test/deneb/fork/test_deneb_fork_basic.py index aca7cb852..1666fdd71 100644 --- a/tests/core/pyspec/eth2spec/test/eip4844/fork/test_eip4844_fork_basic.py +++ b/tests/core/pyspec/eth2spec/test/deneb/fork/test_deneb_fork_basic.py @@ -7,76 +7,76 @@ from eth2spec.test.context import ( ) from eth2spec.test.utils import with_meta_tags from eth2spec.test.helpers.constants import ( - CAPELLA, EIP4844, + CAPELLA, DENEB, MINIMAL, ) from eth2spec.test.helpers.state import ( next_epoch, next_epoch_via_block, ) -from eth2spec.test.helpers.eip4844.fork import ( - EIP4844_FORK_TEST_META_TAGS, +from eth2spec.test.helpers.deneb.fork import ( + DENEB_FORK_TEST_META_TAGS, run_fork_test, ) -@with_phases(phases=[CAPELLA], other_phases=[EIP4844]) +@with_phases(phases=[CAPELLA], other_phases=[DENEB]) @spec_test @with_state -@with_meta_tags(EIP4844_FORK_TEST_META_TAGS) +@with_meta_tags(DENEB_FORK_TEST_META_TAGS) def test_fork_base_state(spec, phases, state): - yield from run_fork_test(phases[EIP4844], state) + yield from run_fork_test(phases[DENEB], state) -@with_phases(phases=[CAPELLA], other_phases=[EIP4844]) +@with_phases(phases=[CAPELLA], other_phases=[DENEB]) @spec_test @with_state -@with_meta_tags(EIP4844_FORK_TEST_META_TAGS) +@with_meta_tags(DENEB_FORK_TEST_META_TAGS) def test_fork_next_epoch(spec, phases, state): next_epoch(spec, state) - yield from run_fork_test(phases[EIP4844], state) + yield from run_fork_test(phases[DENEB], state) -@with_phases(phases=[CAPELLA], other_phases=[EIP4844]) +@with_phases(phases=[CAPELLA], other_phases=[DENEB]) @spec_test @with_state -@with_meta_tags(EIP4844_FORK_TEST_META_TAGS) +@with_meta_tags(DENEB_FORK_TEST_META_TAGS) def test_fork_next_epoch_with_block(spec, phases, state): next_epoch_via_block(spec, state) - yield from run_fork_test(phases[EIP4844], state) + yield from run_fork_test(phases[DENEB], state) -@with_phases(phases=[CAPELLA], other_phases=[EIP4844]) +@with_phases(phases=[CAPELLA], other_phases=[DENEB]) @spec_test @with_state -@with_meta_tags(EIP4844_FORK_TEST_META_TAGS) +@with_meta_tags(DENEB_FORK_TEST_META_TAGS) def test_fork_many_next_epoch(spec, phases, state): for _ in range(3): next_epoch(spec, state) - yield from run_fork_test(phases[EIP4844], state) + yield from run_fork_test(phases[DENEB], state) -@with_phases(phases=[CAPELLA], other_phases=[EIP4844]) +@with_phases(phases=[CAPELLA], other_phases=[DENEB]) @with_custom_state(balances_fn=low_balances, threshold_fn=lambda spec: spec.config.EJECTION_BALANCE) @spec_test -@with_meta_tags(EIP4844_FORK_TEST_META_TAGS) +@with_meta_tags(DENEB_FORK_TEST_META_TAGS) def test_fork_random_low_balances(spec, phases, state): - yield from run_fork_test(phases[EIP4844], state) + yield from run_fork_test(phases[DENEB], state) -@with_phases(phases=[CAPELLA], other_phases=[EIP4844]) +@with_phases(phases=[CAPELLA], other_phases=[DENEB]) @with_custom_state(balances_fn=misc_balances, threshold_fn=lambda spec: spec.config.EJECTION_BALANCE) @spec_test -@with_meta_tags(EIP4844_FORK_TEST_META_TAGS) +@with_meta_tags(DENEB_FORK_TEST_META_TAGS) def test_fork_random_misc_balances(spec, phases, state): - yield from run_fork_test(phases[EIP4844], state) + yield from run_fork_test(phases[DENEB], state) -@with_phases(phases=[CAPELLA], other_phases=[EIP4844]) +@with_phases(phases=[CAPELLA], other_phases=[DENEB]) @with_presets([MINIMAL], reason="mainnet config leads to larger validator set than limit of public/private keys pre-generated") @with_custom_state(balances_fn=large_validator_set, threshold_fn=lambda spec: spec.config.EJECTION_BALANCE) @spec_test -@with_meta_tags(EIP4844_FORK_TEST_META_TAGS) +@with_meta_tags(DENEB_FORK_TEST_META_TAGS) def test_fork_random_large_validator_set(spec, phases, state): - yield from run_fork_test(phases[EIP4844], state) + yield from run_fork_test(phases[DENEB], state) diff --git a/tests/core/pyspec/eth2spec/test/deneb/fork/test_deneb_fork_random.py b/tests/core/pyspec/eth2spec/test/deneb/fork/test_deneb_fork_random.py new file mode 100644 index 000000000..e88b63693 --- /dev/null +++ b/tests/core/pyspec/eth2spec/test/deneb/fork/test_deneb_fork_random.py @@ -0,0 +1,84 @@ +from random import Random + +from eth2spec.test.context import ( + with_phases, + with_custom_state, + with_presets, + spec_test, with_state, + low_balances, misc_balances, large_validator_set, +) +from eth2spec.test.utils import with_meta_tags +from eth2spec.test.helpers.constants import ( + CAPELLA, DENEB, + MINIMAL, +) +from eth2spec.test.helpers.deneb.fork import ( + DENEB_FORK_TEST_META_TAGS, + run_fork_test, +) +from eth2spec.test.helpers.random import randomize_state + + +@with_phases(phases=[CAPELLA], other_phases=[DENEB]) +@spec_test +@with_state +@with_meta_tags(DENEB_FORK_TEST_META_TAGS) +def test_deneb_fork_random_0(spec, phases, state): + randomize_state(spec, state, rng=Random(1010)) + yield from run_fork_test(phases[DENEB], state) + + +@with_phases(phases=[CAPELLA], other_phases=[DENEB]) +@spec_test +@with_state +@with_meta_tags(DENEB_FORK_TEST_META_TAGS) +def test_deneb_fork_random_1(spec, phases, state): + randomize_state(spec, state, rng=Random(2020)) + yield from run_fork_test(phases[DENEB], state) + + +@with_phases(phases=[CAPELLA], other_phases=[DENEB]) +@spec_test +@with_state +@with_meta_tags(DENEB_FORK_TEST_META_TAGS) +def test_deneb_fork_random_2(spec, phases, state): + randomize_state(spec, state, rng=Random(3030)) + yield from run_fork_test(phases[DENEB], state) + + +@with_phases(phases=[CAPELLA], other_phases=[DENEB]) +@spec_test +@with_state +@with_meta_tags(DENEB_FORK_TEST_META_TAGS) +def test_deneb_fork_random_3(spec, phases, state): + randomize_state(spec, state, rng=Random(4040)) + yield from run_fork_test(phases[DENEB], state) + + +@with_phases(phases=[CAPELLA], other_phases=[DENEB]) +@spec_test +@with_custom_state(balances_fn=low_balances, threshold_fn=lambda spec: spec.config.EJECTION_BALANCE) +@with_meta_tags(DENEB_FORK_TEST_META_TAGS) +def test_deneb_fork_random_low_balances(spec, phases, state): + randomize_state(spec, state, rng=Random(5050)) + yield from run_fork_test(phases[DENEB], state) + + +@with_phases(phases=[CAPELLA], other_phases=[DENEB]) +@spec_test +@with_custom_state(balances_fn=misc_balances, threshold_fn=lambda spec: spec.config.EJECTION_BALANCE) +@with_meta_tags(DENEB_FORK_TEST_META_TAGS) +def test_deneb_fork_random_misc_balances(spec, phases, state): + randomize_state(spec, state, rng=Random(6060)) + yield from run_fork_test(phases[DENEB], state) + + +@with_phases(phases=[CAPELLA], other_phases=[DENEB]) +@with_presets([MINIMAL], + reason="mainnet config leads to larger validator set than limit of public/private keys pre-generated") +@spec_test +@with_custom_state(balances_fn=large_validator_set, threshold_fn=lambda spec: spec.config.EJECTION_BALANCE) +@with_meta_tags(DENEB_FORK_TEST_META_TAGS) +def test_deneb_fork_random_large_validator_set(spec, phases, state): + randomize_state(spec, state, rng=Random(7070)) + yield from run_fork_test(phases[DENEB], state) diff --git a/tests/core/pyspec/eth2spec/test/eip4844/random/__init__.py b/tests/core/pyspec/eth2spec/test/deneb/random/__init__.py similarity index 100% rename from tests/core/pyspec/eth2spec/test/eip4844/random/__init__.py rename to tests/core/pyspec/eth2spec/test/deneb/random/__init__.py diff --git a/tests/core/pyspec/eth2spec/test/eip4844/random/test_random.py b/tests/core/pyspec/eth2spec/test/deneb/random/test_random.py similarity index 63% rename from tests/core/pyspec/eth2spec/test/eip4844/random/test_random.py rename to tests/core/pyspec/eth2spec/test/deneb/random/test_random.py index b90b858b2..e8c0a1bb1 100644 --- a/tests/core/pyspec/eth2spec/test/eip4844/random/test_random.py +++ b/tests/core/pyspec/eth2spec/test/deneb/random/test_random.py @@ -4,7 +4,7 @@ Please do not edit this file manually. See the README for that generator for more information. """ -from eth2spec.test.helpers.constants import EIP4844 +from eth2spec.test.helpers.constants import DENEB from eth2spec.test.context import ( misc_balances_in_default_range_with_many_validators, with_phases, @@ -23,7 +23,7 @@ from eth2spec.test.utils.randomized_block_tests import ( @only_generator("randomized test for broad coverage, not point-to-point CI") -@with_phases([EIP4844]) +@with_phases([DENEB]) @with_custom_state( balances_fn=misc_balances_in_default_range_with_many_validators, threshold_fn=zero_activation_threshold @@ -36,11 +36,11 @@ def test_randomized_0(spec, state): # epochs:0,slots:0,with-block:no_block # epochs:0,slots:0,with-block:no_block # epochs:0,slots:0,with-block:no_block - # epochs:0,slots:0,with-block:random_block_eip4844 + # epochs:0,slots:0,with-block:random_block_deneb # epochs:1,slots:0,with-block:no_block # epochs:0,slots:random_slot_in_epoch,with-block:no_block - # epochs:0,slots:0,with-block:random_block_eip4844 - scenario = {'transitions': [{'validation': 'validate_is_not_leaking', 'epochs_to_skip': 0, 'slots_to_skip': 0, 'block_producer': 'no_block'}, {'epochs_to_skip': 0, 'slots_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'slots_to_skip': 0, 'epochs_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'block_producer': 'random_block_eip4844', 'epochs_to_skip': 0, 'slots_to_skip': 0, 'validation': 'no_op_validation'}, {'epochs_to_skip': 1, 'slots_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'slots_to_skip': 'random_slot_in_epoch', 'epochs_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'block_producer': 'random_block_eip4844', 'epochs_to_skip': 0, 'slots_to_skip': 0, 'validation': 'no_op_validation'}], 'state_randomizer': 'randomize_state_eip4844'} # noqa: E501 + # epochs:0,slots:0,with-block:random_block_deneb + scenario = {'transitions': [{'validation': 'validate_is_not_leaking', 'epochs_to_skip': 0, 'slots_to_skip': 0, 'block_producer': 'no_block'}, {'epochs_to_skip': 0, 'slots_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'slots_to_skip': 0, 'epochs_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'block_producer': 'random_block_deneb', 'epochs_to_skip': 0, 'slots_to_skip': 0, 'validation': 'no_op_validation'}, {'epochs_to_skip': 1, 'slots_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'slots_to_skip': 'random_slot_in_epoch', 'epochs_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'block_producer': 'random_block_deneb', 'epochs_to_skip': 0, 'slots_to_skip': 0, 'validation': 'no_op_validation'}], 'state_randomizer': 'randomize_state_deneb'} # noqa: E501 yield from run_generated_randomized_test( spec, state, @@ -49,7 +49,7 @@ def test_randomized_0(spec, state): @only_generator("randomized test for broad coverage, not point-to-point CI") -@with_phases([EIP4844]) +@with_phases([DENEB]) @with_custom_state( balances_fn=misc_balances_in_default_range_with_many_validators, threshold_fn=zero_activation_threshold @@ -62,11 +62,11 @@ def test_randomized_1(spec, state): # epochs:0,slots:0,with-block:no_block # epochs:1,slots:0,with-block:no_block # epochs:0,slots:random_slot_in_epoch,with-block:no_block - # epochs:0,slots:0,with-block:random_block_eip4844 + # epochs:0,slots:0,with-block:random_block_deneb # epochs:0,slots:0,with-block:no_block # epochs:0,slots:0,with-block:no_block - # epochs:0,slots:0,with-block:random_block_eip4844 - scenario = {'transitions': [{'validation': 'validate_is_not_leaking', 'epochs_to_skip': 0, 'slots_to_skip': 0, 'block_producer': 'no_block'}, {'epochs_to_skip': 1, 'slots_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'slots_to_skip': 'random_slot_in_epoch', 'epochs_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'block_producer': 'random_block_eip4844', 'epochs_to_skip': 0, 'slots_to_skip': 0, 'validation': 'no_op_validation'}, {'epochs_to_skip': 0, 'slots_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'slots_to_skip': 0, 'epochs_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'block_producer': 'random_block_eip4844', 'epochs_to_skip': 0, 'slots_to_skip': 0, 'validation': 'no_op_validation'}], 'state_randomizer': 'randomize_state_eip4844'} # noqa: E501 + # epochs:0,slots:0,with-block:random_block_deneb + scenario = {'transitions': [{'validation': 'validate_is_not_leaking', 'epochs_to_skip': 0, 'slots_to_skip': 0, 'block_producer': 'no_block'}, {'epochs_to_skip': 1, 'slots_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'slots_to_skip': 'random_slot_in_epoch', 'epochs_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'block_producer': 'random_block_deneb', 'epochs_to_skip': 0, 'slots_to_skip': 0, 'validation': 'no_op_validation'}, {'epochs_to_skip': 0, 'slots_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'slots_to_skip': 0, 'epochs_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'block_producer': 'random_block_deneb', 'epochs_to_skip': 0, 'slots_to_skip': 0, 'validation': 'no_op_validation'}], 'state_randomizer': 'randomize_state_deneb'} # noqa: E501 yield from run_generated_randomized_test( spec, state, @@ -75,7 +75,7 @@ def test_randomized_1(spec, state): @only_generator("randomized test for broad coverage, not point-to-point CI") -@with_phases([EIP4844]) +@with_phases([DENEB]) @with_custom_state( balances_fn=misc_balances_in_default_range_with_many_validators, threshold_fn=zero_activation_threshold @@ -88,11 +88,11 @@ def test_randomized_2(spec, state): # epochs:0,slots:0,with-block:no_block # epochs:0,slots:0,with-block:no_block # epochs:0,slots:penultimate_slot_in_epoch,with-block:no_block - # epochs:0,slots:0,with-block:random_block_eip4844 + # epochs:0,slots:0,with-block:random_block_deneb # epochs:0,slots:0,with-block:no_block # epochs:0,slots:last_slot_in_epoch,with-block:no_block - # epochs:0,slots:0,with-block:random_block_eip4844 - scenario = {'transitions': [{'validation': 'validate_is_not_leaking', 'epochs_to_skip': 0, 'slots_to_skip': 0, 'block_producer': 'no_block'}, {'epochs_to_skip': 0, 'slots_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'slots_to_skip': 'penultimate_slot_in_epoch', 'epochs_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'block_producer': 'random_block_eip4844', 'epochs_to_skip': 0, 'slots_to_skip': 0, 'validation': 'no_op_validation'}, {'epochs_to_skip': 0, 'slots_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'slots_to_skip': 'last_slot_in_epoch', 'epochs_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'block_producer': 'random_block_eip4844', 'epochs_to_skip': 0, 'slots_to_skip': 0, 'validation': 'no_op_validation'}], 'state_randomizer': 'randomize_state_eip4844'} # noqa: E501 + # epochs:0,slots:0,with-block:random_block_deneb + scenario = {'transitions': [{'validation': 'validate_is_not_leaking', 'epochs_to_skip': 0, 'slots_to_skip': 0, 'block_producer': 'no_block'}, {'epochs_to_skip': 0, 'slots_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'slots_to_skip': 'penultimate_slot_in_epoch', 'epochs_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'block_producer': 'random_block_deneb', 'epochs_to_skip': 0, 'slots_to_skip': 0, 'validation': 'no_op_validation'}, {'epochs_to_skip': 0, 'slots_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'slots_to_skip': 'last_slot_in_epoch', 'epochs_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'block_producer': 'random_block_deneb', 'epochs_to_skip': 0, 'slots_to_skip': 0, 'validation': 'no_op_validation'}], 'state_randomizer': 'randomize_state_deneb'} # noqa: E501 yield from run_generated_randomized_test( spec, state, @@ -101,7 +101,7 @@ def test_randomized_2(spec, state): @only_generator("randomized test for broad coverage, not point-to-point CI") -@with_phases([EIP4844]) +@with_phases([DENEB]) @with_custom_state( balances_fn=misc_balances_in_default_range_with_many_validators, threshold_fn=zero_activation_threshold @@ -114,11 +114,11 @@ def test_randomized_3(spec, state): # epochs:0,slots:0,with-block:no_block # epochs:0,slots:0,with-block:no_block # epochs:0,slots:last_slot_in_epoch,with-block:no_block - # epochs:0,slots:0,with-block:random_block_eip4844 + # epochs:0,slots:0,with-block:random_block_deneb # epochs:1,slots:0,with-block:no_block # epochs:0,slots:last_slot_in_epoch,with-block:no_block - # epochs:0,slots:0,with-block:random_block_eip4844 - scenario = {'transitions': [{'validation': 'validate_is_not_leaking', 'epochs_to_skip': 0, 'slots_to_skip': 0, 'block_producer': 'no_block'}, {'epochs_to_skip': 0, 'slots_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'slots_to_skip': 'last_slot_in_epoch', 'epochs_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'block_producer': 'random_block_eip4844', 'epochs_to_skip': 0, 'slots_to_skip': 0, 'validation': 'no_op_validation'}, {'epochs_to_skip': 1, 'slots_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'slots_to_skip': 'last_slot_in_epoch', 'epochs_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'block_producer': 'random_block_eip4844', 'epochs_to_skip': 0, 'slots_to_skip': 0, 'validation': 'no_op_validation'}], 'state_randomizer': 'randomize_state_eip4844'} # noqa: E501 + # epochs:0,slots:0,with-block:random_block_deneb + scenario = {'transitions': [{'validation': 'validate_is_not_leaking', 'epochs_to_skip': 0, 'slots_to_skip': 0, 'block_producer': 'no_block'}, {'epochs_to_skip': 0, 'slots_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'slots_to_skip': 'last_slot_in_epoch', 'epochs_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'block_producer': 'random_block_deneb', 'epochs_to_skip': 0, 'slots_to_skip': 0, 'validation': 'no_op_validation'}, {'epochs_to_skip': 1, 'slots_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'slots_to_skip': 'last_slot_in_epoch', 'epochs_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'block_producer': 'random_block_deneb', 'epochs_to_skip': 0, 'slots_to_skip': 0, 'validation': 'no_op_validation'}], 'state_randomizer': 'randomize_state_deneb'} # noqa: E501 yield from run_generated_randomized_test( spec, state, @@ -127,7 +127,7 @@ def test_randomized_3(spec, state): @only_generator("randomized test for broad coverage, not point-to-point CI") -@with_phases([EIP4844]) +@with_phases([DENEB]) @with_custom_state( balances_fn=misc_balances_in_default_range_with_many_validators, threshold_fn=zero_activation_threshold @@ -140,11 +140,11 @@ def test_randomized_4(spec, state): # epochs:0,slots:0,with-block:no_block # epochs:1,slots:0,with-block:no_block # epochs:0,slots:last_slot_in_epoch,with-block:no_block - # epochs:0,slots:0,with-block:random_block_eip4844 + # epochs:0,slots:0,with-block:random_block_deneb # epochs:1,slots:0,with-block:no_block # epochs:0,slots:penultimate_slot_in_epoch,with-block:no_block - # epochs:0,slots:0,with-block:random_block_eip4844 - scenario = {'transitions': [{'validation': 'validate_is_not_leaking', 'epochs_to_skip': 0, 'slots_to_skip': 0, 'block_producer': 'no_block'}, {'epochs_to_skip': 1, 'slots_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'slots_to_skip': 'last_slot_in_epoch', 'epochs_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'block_producer': 'random_block_eip4844', 'epochs_to_skip': 0, 'slots_to_skip': 0, 'validation': 'no_op_validation'}, {'epochs_to_skip': 1, 'slots_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'slots_to_skip': 'penultimate_slot_in_epoch', 'epochs_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'block_producer': 'random_block_eip4844', 'epochs_to_skip': 0, 'slots_to_skip': 0, 'validation': 'no_op_validation'}], 'state_randomizer': 'randomize_state_eip4844'} # noqa: E501 + # epochs:0,slots:0,with-block:random_block_deneb + scenario = {'transitions': [{'validation': 'validate_is_not_leaking', 'epochs_to_skip': 0, 'slots_to_skip': 0, 'block_producer': 'no_block'}, {'epochs_to_skip': 1, 'slots_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'slots_to_skip': 'last_slot_in_epoch', 'epochs_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'block_producer': 'random_block_deneb', 'epochs_to_skip': 0, 'slots_to_skip': 0, 'validation': 'no_op_validation'}, {'epochs_to_skip': 1, 'slots_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'slots_to_skip': 'penultimate_slot_in_epoch', 'epochs_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'block_producer': 'random_block_deneb', 'epochs_to_skip': 0, 'slots_to_skip': 0, 'validation': 'no_op_validation'}], 'state_randomizer': 'randomize_state_deneb'} # noqa: E501 yield from run_generated_randomized_test( spec, state, @@ -153,7 +153,7 @@ def test_randomized_4(spec, state): @only_generator("randomized test for broad coverage, not point-to-point CI") -@with_phases([EIP4844]) +@with_phases([DENEB]) @with_custom_state( balances_fn=misc_balances_in_default_range_with_many_validators, threshold_fn=zero_activation_threshold @@ -166,11 +166,11 @@ def test_randomized_5(spec, state): # epochs:0,slots:0,with-block:no_block # epochs:0,slots:0,with-block:no_block # epochs:0,slots:random_slot_in_epoch,with-block:no_block - # epochs:0,slots:0,with-block:random_block_eip4844 + # epochs:0,slots:0,with-block:random_block_deneb # epochs:0,slots:0,with-block:no_block # epochs:0,slots:random_slot_in_epoch,with-block:no_block - # epochs:0,slots:0,with-block:random_block_eip4844 - scenario = {'transitions': [{'validation': 'validate_is_not_leaking', 'epochs_to_skip': 0, 'slots_to_skip': 0, 'block_producer': 'no_block'}, {'epochs_to_skip': 0, 'slots_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'slots_to_skip': 'random_slot_in_epoch', 'epochs_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'block_producer': 'random_block_eip4844', 'epochs_to_skip': 0, 'slots_to_skip': 0, 'validation': 'no_op_validation'}, {'epochs_to_skip': 0, 'slots_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'slots_to_skip': 'random_slot_in_epoch', 'epochs_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'block_producer': 'random_block_eip4844', 'epochs_to_skip': 0, 'slots_to_skip': 0, 'validation': 'no_op_validation'}], 'state_randomizer': 'randomize_state_eip4844'} # noqa: E501 + # epochs:0,slots:0,with-block:random_block_deneb + scenario = {'transitions': [{'validation': 'validate_is_not_leaking', 'epochs_to_skip': 0, 'slots_to_skip': 0, 'block_producer': 'no_block'}, {'epochs_to_skip': 0, 'slots_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'slots_to_skip': 'random_slot_in_epoch', 'epochs_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'block_producer': 'random_block_deneb', 'epochs_to_skip': 0, 'slots_to_skip': 0, 'validation': 'no_op_validation'}, {'epochs_to_skip': 0, 'slots_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'slots_to_skip': 'random_slot_in_epoch', 'epochs_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'block_producer': 'random_block_deneb', 'epochs_to_skip': 0, 'slots_to_skip': 0, 'validation': 'no_op_validation'}], 'state_randomizer': 'randomize_state_deneb'} # noqa: E501 yield from run_generated_randomized_test( spec, state, @@ -179,7 +179,7 @@ def test_randomized_5(spec, state): @only_generator("randomized test for broad coverage, not point-to-point CI") -@with_phases([EIP4844]) +@with_phases([DENEB]) @with_custom_state( balances_fn=misc_balances_in_default_range_with_many_validators, threshold_fn=zero_activation_threshold @@ -192,11 +192,11 @@ def test_randomized_6(spec, state): # epochs:0,slots:0,with-block:no_block # epochs:1,slots:0,with-block:no_block # epochs:0,slots:penultimate_slot_in_epoch,with-block:no_block - # epochs:0,slots:0,with-block:random_block_eip4844 + # epochs:0,slots:0,with-block:random_block_deneb # epochs:0,slots:0,with-block:no_block # epochs:0,slots:penultimate_slot_in_epoch,with-block:no_block - # epochs:0,slots:0,with-block:random_block_eip4844 - scenario = {'transitions': [{'validation': 'validate_is_not_leaking', 'epochs_to_skip': 0, 'slots_to_skip': 0, 'block_producer': 'no_block'}, {'epochs_to_skip': 1, 'slots_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'slots_to_skip': 'penultimate_slot_in_epoch', 'epochs_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'block_producer': 'random_block_eip4844', 'epochs_to_skip': 0, 'slots_to_skip': 0, 'validation': 'no_op_validation'}, {'epochs_to_skip': 0, 'slots_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'slots_to_skip': 'penultimate_slot_in_epoch', 'epochs_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'block_producer': 'random_block_eip4844', 'epochs_to_skip': 0, 'slots_to_skip': 0, 'validation': 'no_op_validation'}], 'state_randomizer': 'randomize_state_eip4844'} # noqa: E501 + # epochs:0,slots:0,with-block:random_block_deneb + scenario = {'transitions': [{'validation': 'validate_is_not_leaking', 'epochs_to_skip': 0, 'slots_to_skip': 0, 'block_producer': 'no_block'}, {'epochs_to_skip': 1, 'slots_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'slots_to_skip': 'penultimate_slot_in_epoch', 'epochs_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'block_producer': 'random_block_deneb', 'epochs_to_skip': 0, 'slots_to_skip': 0, 'validation': 'no_op_validation'}, {'epochs_to_skip': 0, 'slots_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'slots_to_skip': 'penultimate_slot_in_epoch', 'epochs_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'block_producer': 'random_block_deneb', 'epochs_to_skip': 0, 'slots_to_skip': 0, 'validation': 'no_op_validation'}], 'state_randomizer': 'randomize_state_deneb'} # noqa: E501 yield from run_generated_randomized_test( spec, state, @@ -205,7 +205,7 @@ def test_randomized_6(spec, state): @only_generator("randomized test for broad coverage, not point-to-point CI") -@with_phases([EIP4844]) +@with_phases([DENEB]) @with_custom_state( balances_fn=misc_balances_in_default_range_with_many_validators, threshold_fn=zero_activation_threshold @@ -218,11 +218,11 @@ def test_randomized_7(spec, state): # epochs:0,slots:0,with-block:no_block # epochs:1,slots:0,with-block:no_block # epochs:0,slots:0,with-block:no_block - # epochs:0,slots:0,with-block:random_block_eip4844 + # epochs:0,slots:0,with-block:random_block_deneb # epochs:1,slots:0,with-block:no_block # epochs:0,slots:0,with-block:no_block - # epochs:0,slots:0,with-block:random_block_eip4844 - scenario = {'transitions': [{'validation': 'validate_is_not_leaking', 'epochs_to_skip': 0, 'slots_to_skip': 0, 'block_producer': 'no_block'}, {'epochs_to_skip': 1, 'slots_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'slots_to_skip': 0, 'epochs_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'block_producer': 'random_block_eip4844', 'epochs_to_skip': 0, 'slots_to_skip': 0, 'validation': 'no_op_validation'}, {'epochs_to_skip': 1, 'slots_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'slots_to_skip': 0, 'epochs_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'block_producer': 'random_block_eip4844', 'epochs_to_skip': 0, 'slots_to_skip': 0, 'validation': 'no_op_validation'}], 'state_randomizer': 'randomize_state_eip4844'} # noqa: E501 + # epochs:0,slots:0,with-block:random_block_deneb + scenario = {'transitions': [{'validation': 'validate_is_not_leaking', 'epochs_to_skip': 0, 'slots_to_skip': 0, 'block_producer': 'no_block'}, {'epochs_to_skip': 1, 'slots_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'slots_to_skip': 0, 'epochs_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'block_producer': 'random_block_deneb', 'epochs_to_skip': 0, 'slots_to_skip': 0, 'validation': 'no_op_validation'}, {'epochs_to_skip': 1, 'slots_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'slots_to_skip': 0, 'epochs_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'block_producer': 'random_block_deneb', 'epochs_to_skip': 0, 'slots_to_skip': 0, 'validation': 'no_op_validation'}], 'state_randomizer': 'randomize_state_deneb'} # noqa: E501 yield from run_generated_randomized_test( spec, state, @@ -231,7 +231,7 @@ def test_randomized_7(spec, state): @only_generator("randomized test for broad coverage, not point-to-point CI") -@with_phases([EIP4844]) +@with_phases([DENEB]) @with_custom_state( balances_fn=misc_balances_in_default_range_with_many_validators, threshold_fn=zero_activation_threshold @@ -244,11 +244,11 @@ def test_randomized_8(spec, state): # epochs:epochs_until_leak,slots:0,with-block:no_block # epochs:0,slots:0,with-block:no_block # epochs:0,slots:0,with-block:no_block - # epochs:0,slots:0,with-block:random_block_eip4844 + # epochs:0,slots:0,with-block:random_block_deneb # epochs:1,slots:0,with-block:no_block # epochs:0,slots:random_slot_in_epoch,with-block:no_block - # epochs:0,slots:0,with-block:random_block_eip4844 - scenario = {'transitions': [{'epochs_to_skip': 'epochs_until_leak', 'validation': 'validate_is_leaking', 'slots_to_skip': 0, 'block_producer': 'no_block'}, {'epochs_to_skip': 0, 'slots_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'slots_to_skip': 0, 'epochs_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'block_producer': 'random_block_eip4844', 'epochs_to_skip': 0, 'slots_to_skip': 0, 'validation': 'no_op_validation'}, {'epochs_to_skip': 1, 'slots_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'slots_to_skip': 'random_slot_in_epoch', 'epochs_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'block_producer': 'random_block_eip4844', 'epochs_to_skip': 0, 'slots_to_skip': 0, 'validation': 'no_op_validation'}], 'state_randomizer': 'randomize_state_eip4844'} # noqa: E501 + # epochs:0,slots:0,with-block:random_block_deneb + scenario = {'transitions': [{'epochs_to_skip': 'epochs_until_leak', 'validation': 'validate_is_leaking', 'slots_to_skip': 0, 'block_producer': 'no_block'}, {'epochs_to_skip': 0, 'slots_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'slots_to_skip': 0, 'epochs_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'block_producer': 'random_block_deneb', 'epochs_to_skip': 0, 'slots_to_skip': 0, 'validation': 'no_op_validation'}, {'epochs_to_skip': 1, 'slots_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'slots_to_skip': 'random_slot_in_epoch', 'epochs_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'block_producer': 'random_block_deneb', 'epochs_to_skip': 0, 'slots_to_skip': 0, 'validation': 'no_op_validation'}], 'state_randomizer': 'randomize_state_deneb'} # noqa: E501 yield from run_generated_randomized_test( spec, state, @@ -257,7 +257,7 @@ def test_randomized_8(spec, state): @only_generator("randomized test for broad coverage, not point-to-point CI") -@with_phases([EIP4844]) +@with_phases([DENEB]) @with_custom_state( balances_fn=misc_balances_in_default_range_with_many_validators, threshold_fn=zero_activation_threshold @@ -270,11 +270,11 @@ def test_randomized_9(spec, state): # epochs:epochs_until_leak,slots:0,with-block:no_block # epochs:1,slots:0,with-block:no_block # epochs:0,slots:random_slot_in_epoch,with-block:no_block - # epochs:0,slots:0,with-block:random_block_eip4844 + # epochs:0,slots:0,with-block:random_block_deneb # epochs:0,slots:0,with-block:no_block # epochs:0,slots:0,with-block:no_block - # epochs:0,slots:0,with-block:random_block_eip4844 - scenario = {'transitions': [{'epochs_to_skip': 'epochs_until_leak', 'validation': 'validate_is_leaking', 'slots_to_skip': 0, 'block_producer': 'no_block'}, {'epochs_to_skip': 1, 'slots_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'slots_to_skip': 'random_slot_in_epoch', 'epochs_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'block_producer': 'random_block_eip4844', 'epochs_to_skip': 0, 'slots_to_skip': 0, 'validation': 'no_op_validation'}, {'epochs_to_skip': 0, 'slots_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'slots_to_skip': 0, 'epochs_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'block_producer': 'random_block_eip4844', 'epochs_to_skip': 0, 'slots_to_skip': 0, 'validation': 'no_op_validation'}], 'state_randomizer': 'randomize_state_eip4844'} # noqa: E501 + # epochs:0,slots:0,with-block:random_block_deneb + scenario = {'transitions': [{'epochs_to_skip': 'epochs_until_leak', 'validation': 'validate_is_leaking', 'slots_to_skip': 0, 'block_producer': 'no_block'}, {'epochs_to_skip': 1, 'slots_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'slots_to_skip': 'random_slot_in_epoch', 'epochs_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'block_producer': 'random_block_deneb', 'epochs_to_skip': 0, 'slots_to_skip': 0, 'validation': 'no_op_validation'}, {'epochs_to_skip': 0, 'slots_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'slots_to_skip': 0, 'epochs_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'block_producer': 'random_block_deneb', 'epochs_to_skip': 0, 'slots_to_skip': 0, 'validation': 'no_op_validation'}], 'state_randomizer': 'randomize_state_deneb'} # noqa: E501 yield from run_generated_randomized_test( spec, state, @@ -283,7 +283,7 @@ def test_randomized_9(spec, state): @only_generator("randomized test for broad coverage, not point-to-point CI") -@with_phases([EIP4844]) +@with_phases([DENEB]) @with_custom_state( balances_fn=misc_balances_in_default_range_with_many_validators, threshold_fn=zero_activation_threshold @@ -296,11 +296,11 @@ def test_randomized_10(spec, state): # epochs:epochs_until_leak,slots:0,with-block:no_block # epochs:0,slots:0,with-block:no_block # epochs:0,slots:penultimate_slot_in_epoch,with-block:no_block - # epochs:0,slots:0,with-block:random_block_eip4844 + # epochs:0,slots:0,with-block:random_block_deneb # epochs:0,slots:0,with-block:no_block # epochs:0,slots:last_slot_in_epoch,with-block:no_block - # epochs:0,slots:0,with-block:random_block_eip4844 - scenario = {'transitions': [{'epochs_to_skip': 'epochs_until_leak', 'validation': 'validate_is_leaking', 'slots_to_skip': 0, 'block_producer': 'no_block'}, {'epochs_to_skip': 0, 'slots_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'slots_to_skip': 'penultimate_slot_in_epoch', 'epochs_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'block_producer': 'random_block_eip4844', 'epochs_to_skip': 0, 'slots_to_skip': 0, 'validation': 'no_op_validation'}, {'epochs_to_skip': 0, 'slots_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'slots_to_skip': 'last_slot_in_epoch', 'epochs_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'block_producer': 'random_block_eip4844', 'epochs_to_skip': 0, 'slots_to_skip': 0, 'validation': 'no_op_validation'}], 'state_randomizer': 'randomize_state_eip4844'} # noqa: E501 + # epochs:0,slots:0,with-block:random_block_deneb + scenario = {'transitions': [{'epochs_to_skip': 'epochs_until_leak', 'validation': 'validate_is_leaking', 'slots_to_skip': 0, 'block_producer': 'no_block'}, {'epochs_to_skip': 0, 'slots_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'slots_to_skip': 'penultimate_slot_in_epoch', 'epochs_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'block_producer': 'random_block_deneb', 'epochs_to_skip': 0, 'slots_to_skip': 0, 'validation': 'no_op_validation'}, {'epochs_to_skip': 0, 'slots_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'slots_to_skip': 'last_slot_in_epoch', 'epochs_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'block_producer': 'random_block_deneb', 'epochs_to_skip': 0, 'slots_to_skip': 0, 'validation': 'no_op_validation'}], 'state_randomizer': 'randomize_state_deneb'} # noqa: E501 yield from run_generated_randomized_test( spec, state, @@ -309,7 +309,7 @@ def test_randomized_10(spec, state): @only_generator("randomized test for broad coverage, not point-to-point CI") -@with_phases([EIP4844]) +@with_phases([DENEB]) @with_custom_state( balances_fn=misc_balances_in_default_range_with_many_validators, threshold_fn=zero_activation_threshold @@ -322,11 +322,11 @@ def test_randomized_11(spec, state): # epochs:epochs_until_leak,slots:0,with-block:no_block # epochs:0,slots:0,with-block:no_block # epochs:0,slots:last_slot_in_epoch,with-block:no_block - # epochs:0,slots:0,with-block:random_block_eip4844 + # epochs:0,slots:0,with-block:random_block_deneb # epochs:1,slots:0,with-block:no_block # epochs:0,slots:last_slot_in_epoch,with-block:no_block - # epochs:0,slots:0,with-block:random_block_eip4844 - scenario = {'transitions': [{'epochs_to_skip': 'epochs_until_leak', 'validation': 'validate_is_leaking', 'slots_to_skip': 0, 'block_producer': 'no_block'}, {'epochs_to_skip': 0, 'slots_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'slots_to_skip': 'last_slot_in_epoch', 'epochs_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'block_producer': 'random_block_eip4844', 'epochs_to_skip': 0, 'slots_to_skip': 0, 'validation': 'no_op_validation'}, {'epochs_to_skip': 1, 'slots_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'slots_to_skip': 'last_slot_in_epoch', 'epochs_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'block_producer': 'random_block_eip4844', 'epochs_to_skip': 0, 'slots_to_skip': 0, 'validation': 'no_op_validation'}], 'state_randomizer': 'randomize_state_eip4844'} # noqa: E501 + # epochs:0,slots:0,with-block:random_block_deneb + scenario = {'transitions': [{'epochs_to_skip': 'epochs_until_leak', 'validation': 'validate_is_leaking', 'slots_to_skip': 0, 'block_producer': 'no_block'}, {'epochs_to_skip': 0, 'slots_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'slots_to_skip': 'last_slot_in_epoch', 'epochs_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'block_producer': 'random_block_deneb', 'epochs_to_skip': 0, 'slots_to_skip': 0, 'validation': 'no_op_validation'}, {'epochs_to_skip': 1, 'slots_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'slots_to_skip': 'last_slot_in_epoch', 'epochs_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'block_producer': 'random_block_deneb', 'epochs_to_skip': 0, 'slots_to_skip': 0, 'validation': 'no_op_validation'}], 'state_randomizer': 'randomize_state_deneb'} # noqa: E501 yield from run_generated_randomized_test( spec, state, @@ -335,7 +335,7 @@ def test_randomized_11(spec, state): @only_generator("randomized test for broad coverage, not point-to-point CI") -@with_phases([EIP4844]) +@with_phases([DENEB]) @with_custom_state( balances_fn=misc_balances_in_default_range_with_many_validators, threshold_fn=zero_activation_threshold @@ -348,11 +348,11 @@ def test_randomized_12(spec, state): # epochs:epochs_until_leak,slots:0,with-block:no_block # epochs:1,slots:0,with-block:no_block # epochs:0,slots:last_slot_in_epoch,with-block:no_block - # epochs:0,slots:0,with-block:random_block_eip4844 + # epochs:0,slots:0,with-block:random_block_deneb # epochs:1,slots:0,with-block:no_block # epochs:0,slots:penultimate_slot_in_epoch,with-block:no_block - # epochs:0,slots:0,with-block:random_block_eip4844 - scenario = {'transitions': [{'epochs_to_skip': 'epochs_until_leak', 'validation': 'validate_is_leaking', 'slots_to_skip': 0, 'block_producer': 'no_block'}, {'epochs_to_skip': 1, 'slots_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'slots_to_skip': 'last_slot_in_epoch', 'epochs_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'block_producer': 'random_block_eip4844', 'epochs_to_skip': 0, 'slots_to_skip': 0, 'validation': 'no_op_validation'}, {'epochs_to_skip': 1, 'slots_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'slots_to_skip': 'penultimate_slot_in_epoch', 'epochs_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'block_producer': 'random_block_eip4844', 'epochs_to_skip': 0, 'slots_to_skip': 0, 'validation': 'no_op_validation'}], 'state_randomizer': 'randomize_state_eip4844'} # noqa: E501 + # epochs:0,slots:0,with-block:random_block_deneb + scenario = {'transitions': [{'epochs_to_skip': 'epochs_until_leak', 'validation': 'validate_is_leaking', 'slots_to_skip': 0, 'block_producer': 'no_block'}, {'epochs_to_skip': 1, 'slots_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'slots_to_skip': 'last_slot_in_epoch', 'epochs_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'block_producer': 'random_block_deneb', 'epochs_to_skip': 0, 'slots_to_skip': 0, 'validation': 'no_op_validation'}, {'epochs_to_skip': 1, 'slots_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'slots_to_skip': 'penultimate_slot_in_epoch', 'epochs_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'block_producer': 'random_block_deneb', 'epochs_to_skip': 0, 'slots_to_skip': 0, 'validation': 'no_op_validation'}], 'state_randomizer': 'randomize_state_deneb'} # noqa: E501 yield from run_generated_randomized_test( spec, state, @@ -361,7 +361,7 @@ def test_randomized_12(spec, state): @only_generator("randomized test for broad coverage, not point-to-point CI") -@with_phases([EIP4844]) +@with_phases([DENEB]) @with_custom_state( balances_fn=misc_balances_in_default_range_with_many_validators, threshold_fn=zero_activation_threshold @@ -374,11 +374,11 @@ def test_randomized_13(spec, state): # epochs:epochs_until_leak,slots:0,with-block:no_block # epochs:0,slots:0,with-block:no_block # epochs:0,slots:random_slot_in_epoch,with-block:no_block - # epochs:0,slots:0,with-block:random_block_eip4844 + # epochs:0,slots:0,with-block:random_block_deneb # epochs:0,slots:0,with-block:no_block # epochs:0,slots:random_slot_in_epoch,with-block:no_block - # epochs:0,slots:0,with-block:random_block_eip4844 - scenario = {'transitions': [{'epochs_to_skip': 'epochs_until_leak', 'validation': 'validate_is_leaking', 'slots_to_skip': 0, 'block_producer': 'no_block'}, {'epochs_to_skip': 0, 'slots_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'slots_to_skip': 'random_slot_in_epoch', 'epochs_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'block_producer': 'random_block_eip4844', 'epochs_to_skip': 0, 'slots_to_skip': 0, 'validation': 'no_op_validation'}, {'epochs_to_skip': 0, 'slots_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'slots_to_skip': 'random_slot_in_epoch', 'epochs_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'block_producer': 'random_block_eip4844', 'epochs_to_skip': 0, 'slots_to_skip': 0, 'validation': 'no_op_validation'}], 'state_randomizer': 'randomize_state_eip4844'} # noqa: E501 + # epochs:0,slots:0,with-block:random_block_deneb + scenario = {'transitions': [{'epochs_to_skip': 'epochs_until_leak', 'validation': 'validate_is_leaking', 'slots_to_skip': 0, 'block_producer': 'no_block'}, {'epochs_to_skip': 0, 'slots_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'slots_to_skip': 'random_slot_in_epoch', 'epochs_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'block_producer': 'random_block_deneb', 'epochs_to_skip': 0, 'slots_to_skip': 0, 'validation': 'no_op_validation'}, {'epochs_to_skip': 0, 'slots_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'slots_to_skip': 'random_slot_in_epoch', 'epochs_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'block_producer': 'random_block_deneb', 'epochs_to_skip': 0, 'slots_to_skip': 0, 'validation': 'no_op_validation'}], 'state_randomizer': 'randomize_state_deneb'} # noqa: E501 yield from run_generated_randomized_test( spec, state, @@ -387,7 +387,7 @@ def test_randomized_13(spec, state): @only_generator("randomized test for broad coverage, not point-to-point CI") -@with_phases([EIP4844]) +@with_phases([DENEB]) @with_custom_state( balances_fn=misc_balances_in_default_range_with_many_validators, threshold_fn=zero_activation_threshold @@ -400,11 +400,11 @@ def test_randomized_14(spec, state): # epochs:epochs_until_leak,slots:0,with-block:no_block # epochs:1,slots:0,with-block:no_block # epochs:0,slots:penultimate_slot_in_epoch,with-block:no_block - # epochs:0,slots:0,with-block:random_block_eip4844 + # epochs:0,slots:0,with-block:random_block_deneb # epochs:0,slots:0,with-block:no_block # epochs:0,slots:penultimate_slot_in_epoch,with-block:no_block - # epochs:0,slots:0,with-block:random_block_eip4844 - scenario = {'transitions': [{'epochs_to_skip': 'epochs_until_leak', 'validation': 'validate_is_leaking', 'slots_to_skip': 0, 'block_producer': 'no_block'}, {'epochs_to_skip': 1, 'slots_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'slots_to_skip': 'penultimate_slot_in_epoch', 'epochs_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'block_producer': 'random_block_eip4844', 'epochs_to_skip': 0, 'slots_to_skip': 0, 'validation': 'no_op_validation'}, {'epochs_to_skip': 0, 'slots_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'slots_to_skip': 'penultimate_slot_in_epoch', 'epochs_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'block_producer': 'random_block_eip4844', 'epochs_to_skip': 0, 'slots_to_skip': 0, 'validation': 'no_op_validation'}], 'state_randomizer': 'randomize_state_eip4844'} # noqa: E501 + # epochs:0,slots:0,with-block:random_block_deneb + scenario = {'transitions': [{'epochs_to_skip': 'epochs_until_leak', 'validation': 'validate_is_leaking', 'slots_to_skip': 0, 'block_producer': 'no_block'}, {'epochs_to_skip': 1, 'slots_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'slots_to_skip': 'penultimate_slot_in_epoch', 'epochs_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'block_producer': 'random_block_deneb', 'epochs_to_skip': 0, 'slots_to_skip': 0, 'validation': 'no_op_validation'}, {'epochs_to_skip': 0, 'slots_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'slots_to_skip': 'penultimate_slot_in_epoch', 'epochs_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'block_producer': 'random_block_deneb', 'epochs_to_skip': 0, 'slots_to_skip': 0, 'validation': 'no_op_validation'}], 'state_randomizer': 'randomize_state_deneb'} # noqa: E501 yield from run_generated_randomized_test( spec, state, @@ -413,7 +413,7 @@ def test_randomized_14(spec, state): @only_generator("randomized test for broad coverage, not point-to-point CI") -@with_phases([EIP4844]) +@with_phases([DENEB]) @with_custom_state( balances_fn=misc_balances_in_default_range_with_many_validators, threshold_fn=zero_activation_threshold @@ -426,11 +426,11 @@ def test_randomized_15(spec, state): # epochs:epochs_until_leak,slots:0,with-block:no_block # epochs:1,slots:0,with-block:no_block # epochs:0,slots:0,with-block:no_block - # epochs:0,slots:0,with-block:random_block_eip4844 + # epochs:0,slots:0,with-block:random_block_deneb # epochs:1,slots:0,with-block:no_block # epochs:0,slots:0,with-block:no_block - # epochs:0,slots:0,with-block:random_block_eip4844 - scenario = {'transitions': [{'epochs_to_skip': 'epochs_until_leak', 'validation': 'validate_is_leaking', 'slots_to_skip': 0, 'block_producer': 'no_block'}, {'epochs_to_skip': 1, 'slots_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'slots_to_skip': 0, 'epochs_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'block_producer': 'random_block_eip4844', 'epochs_to_skip': 0, 'slots_to_skip': 0, 'validation': 'no_op_validation'}, {'epochs_to_skip': 1, 'slots_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'slots_to_skip': 0, 'epochs_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'block_producer': 'random_block_eip4844', 'epochs_to_skip': 0, 'slots_to_skip': 0, 'validation': 'no_op_validation'}], 'state_randomizer': 'randomize_state_eip4844'} # noqa: E501 + # epochs:0,slots:0,with-block:random_block_deneb + scenario = {'transitions': [{'epochs_to_skip': 'epochs_until_leak', 'validation': 'validate_is_leaking', 'slots_to_skip': 0, 'block_producer': 'no_block'}, {'epochs_to_skip': 1, 'slots_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'slots_to_skip': 0, 'epochs_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'block_producer': 'random_block_deneb', 'epochs_to_skip': 0, 'slots_to_skip': 0, 'validation': 'no_op_validation'}, {'epochs_to_skip': 1, 'slots_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'slots_to_skip': 0, 'epochs_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'block_producer': 'random_block_deneb', 'epochs_to_skip': 0, 'slots_to_skip': 0, 'validation': 'no_op_validation'}], 'state_randomizer': 'randomize_state_deneb'} # noqa: E501 yield from run_generated_randomized_test( spec, state, diff --git a/tests/core/pyspec/eth2spec/test/eip4844/sanity/__init__.py b/tests/core/pyspec/eth2spec/test/deneb/sanity/__init__.py similarity index 100% rename from tests/core/pyspec/eth2spec/test/eip4844/sanity/__init__.py rename to tests/core/pyspec/eth2spec/test/deneb/sanity/__init__.py diff --git a/tests/core/pyspec/eth2spec/test/eip4844/sanity/test_blocks.py b/tests/core/pyspec/eth2spec/test/deneb/sanity/test_blocks.py similarity index 95% rename from tests/core/pyspec/eth2spec/test/eip4844/sanity/test_blocks.py rename to tests/core/pyspec/eth2spec/test/deneb/sanity/test_blocks.py index 0aeafe052..c7fb708b8 100644 --- a/tests/core/pyspec/eth2spec/test/eip4844/sanity/test_blocks.py +++ b/tests/core/pyspec/eth2spec/test/deneb/sanity/test_blocks.py @@ -6,7 +6,7 @@ from eth2spec.test.helpers.block import ( ) from eth2spec.test.context import ( spec_state_test, - with_eip4844_and_later, + with_deneb_and_later, ) from eth2spec.test.helpers.execution_payload import ( compute_el_block_hash, @@ -16,7 +16,7 @@ from eth2spec.test.helpers.sharding import ( ) -@with_eip4844_and_later +@with_deneb_and_later @spec_state_test def test_one_blob(spec, state): yield 'pre', state @@ -32,7 +32,7 @@ def test_one_blob(spec, state): yield 'post', state -@with_eip4844_and_later +@with_deneb_and_later @spec_state_test def test_max_blobs(spec, state): yield 'pre', state diff --git a/tests/core/pyspec/eth2spec/test/eip4844/unittests/__init__.py b/tests/core/pyspec/eth2spec/test/deneb/unittests/__init__.py similarity index 100% rename from tests/core/pyspec/eth2spec/test/eip4844/unittests/__init__.py rename to tests/core/pyspec/eth2spec/test/deneb/unittests/__init__.py diff --git a/tests/core/pyspec/eth2spec/test/eip4844/unittests/fork_choice/__init__.py b/tests/core/pyspec/eth2spec/test/deneb/unittests/fork_choice/__init__.py similarity index 100% rename from tests/core/pyspec/eth2spec/test/eip4844/unittests/fork_choice/__init__.py rename to tests/core/pyspec/eth2spec/test/deneb/unittests/fork_choice/__init__.py diff --git a/tests/core/pyspec/eth2spec/test/eip4844/unittests/fork_choice/test_validate_blobs_sidecar.py b/tests/core/pyspec/eth2spec/test/deneb/unittests/fork_choice/test_validate_blobs_sidecar.py similarity index 93% rename from tests/core/pyspec/eth2spec/test/eip4844/unittests/fork_choice/test_validate_blobs_sidecar.py rename to tests/core/pyspec/eth2spec/test/deneb/unittests/fork_choice/test_validate_blobs_sidecar.py index dbea9f784..87ed9ff8e 100644 --- a/tests/core/pyspec/eth2spec/test/eip4844/unittests/fork_choice/test_validate_blobs_sidecar.py +++ b/tests/core/pyspec/eth2spec/test/deneb/unittests/fork_choice/test_validate_blobs_sidecar.py @@ -6,7 +6,7 @@ from eth2spec.test.helpers.block import ( ) from eth2spec.test.context import ( spec_state_test, - with_eip4844_and_later, + with_deneb_and_later, ) from eth2spec.test.helpers.execution_payload import ( compute_el_block_hash, @@ -29,25 +29,25 @@ def _run_validate_blobs_sidecar_test(spec, state, blob_count): spec.validate_blobs_sidecar(block.slot, block.hash_tree_root(), expected_commitments, blobs_sidecar) -@with_eip4844_and_later +@with_deneb_and_later @spec_state_test def test_validate_blobs_sidecar_zero_blobs(spec, state): _run_validate_blobs_sidecar_test(spec, state, blob_count=0) -@with_eip4844_and_later +@with_deneb_and_later @spec_state_test def test_validate_blobs_sidecar_one_blob(spec, state): _run_validate_blobs_sidecar_test(spec, state, blob_count=1) -@with_eip4844_and_later +@with_deneb_and_later @spec_state_test def test_validate_blobs_sidecar_two_blobs(spec, state): _run_validate_blobs_sidecar_test(spec, state, blob_count=2) -@with_eip4844_and_later +@with_deneb_and_later @spec_state_test def test_validate_blobs_sidecar_max_blobs(spec, state): _run_validate_blobs_sidecar_test(spec, state, blob_count=spec.MAX_BLOBS_PER_BLOCK) diff --git a/tests/core/pyspec/eth2spec/test/eip4844/unittests/polynomial_commitments/__init__.py b/tests/core/pyspec/eth2spec/test/deneb/unittests/polynomial_commitments/__init__.py similarity index 100% rename from tests/core/pyspec/eth2spec/test/eip4844/unittests/polynomial_commitments/__init__.py rename to tests/core/pyspec/eth2spec/test/deneb/unittests/polynomial_commitments/__init__.py diff --git a/tests/core/pyspec/eth2spec/test/eip4844/unittests/polynomial_commitments/test_polynomial_commitments.py b/tests/core/pyspec/eth2spec/test/deneb/unittests/polynomial_commitments/test_polynomial_commitments.py similarity index 96% rename from tests/core/pyspec/eth2spec/test/eip4844/unittests/polynomial_commitments/test_polynomial_commitments.py rename to tests/core/pyspec/eth2spec/test/deneb/unittests/polynomial_commitments/test_polynomial_commitments.py index 24b45475e..f60c79a88 100644 --- a/tests/core/pyspec/eth2spec/test/eip4844/unittests/polynomial_commitments/test_polynomial_commitments.py +++ b/tests/core/pyspec/eth2spec/test/deneb/unittests/polynomial_commitments/test_polynomial_commitments.py @@ -2,7 +2,7 @@ import random from eth2spec.test.context import ( spec_state_test, - with_eip4844_and_later, + with_deneb_and_later, ) from eth2spec.test.helpers.sharding import ( get_sample_blob, @@ -11,7 +11,7 @@ from eth2spec.test.helpers.sharding import ( ) -@with_eip4844_and_later +@with_deneb_and_later @spec_state_test def test_verify_kzg_proof(spec, state): x = 3 @@ -24,7 +24,7 @@ def test_verify_kzg_proof(spec, state): assert spec.verify_kzg_proof_impl(commitment, x, y, proof) -@with_eip4844_and_later +@with_deneb_and_later @spec_state_test def test_barycentric_outside_domain(spec, state): """ @@ -57,7 +57,7 @@ def test_barycentric_outside_domain(spec, state): assert p_z_coeff == p_z_eval -@with_eip4844_and_later +@with_deneb_and_later @spec_state_test def test_barycentric_within_domain(spec, state): """ diff --git a/tests/core/pyspec/eth2spec/test/eip4844/unittests/test_kzg.py b/tests/core/pyspec/eth2spec/test/deneb/unittests/test_kzg.py similarity index 91% rename from tests/core/pyspec/eth2spec/test/eip4844/unittests/test_kzg.py rename to tests/core/pyspec/eth2spec/test/deneb/unittests/test_kzg.py index 7474707b9..71bfae8b8 100644 --- a/tests/core/pyspec/eth2spec/test/eip4844/unittests/test_kzg.py +++ b/tests/core/pyspec/eth2spec/test/deneb/unittests/test_kzg.py @@ -1,6 +1,6 @@ from eth2spec.test.helpers.constants import ( - EIP4844, + DENEB, MINIMAL, ) from eth2spec.test.helpers.sharding import ( @@ -13,7 +13,7 @@ from eth2spec.test.context import ( ) -@with_phases([EIP4844]) +@with_phases([DENEB]) @spec_state_test @with_presets([MINIMAL]) def test_blob_to_kzg_commitment(spec, state): diff --git a/tests/core/pyspec/eth2spec/test/eip4844/unittests/test_offset.py b/tests/core/pyspec/eth2spec/test/deneb/unittests/test_offset.py similarity index 94% rename from tests/core/pyspec/eth2spec/test/eip4844/unittests/test_offset.py rename to tests/core/pyspec/eth2spec/test/deneb/unittests/test_offset.py index 1702ea7e0..13150180b 100644 --- a/tests/core/pyspec/eth2spec/test/eip4844/unittests/test_offset.py +++ b/tests/core/pyspec/eth2spec/test/deneb/unittests/test_offset.py @@ -1,6 +1,6 @@ from eth2spec.test.helpers.constants import ( - EIP4844, + DENEB, MINIMAL, ) from eth2spec.test.helpers.sharding import ( @@ -13,7 +13,7 @@ from eth2spec.test.context import ( ) -@with_phases([EIP4844]) +@with_phases([DENEB]) @spec_state_test @with_presets([MINIMAL]) def test_tx_peek_blob_versioned_hashes(spec, state): diff --git a/tests/core/pyspec/eth2spec/test/eip4844/fork/test_eip4844_fork_random.py b/tests/core/pyspec/eth2spec/test/eip4844/fork/test_eip4844_fork_random.py deleted file mode 100644 index a22de4b59..000000000 --- a/tests/core/pyspec/eth2spec/test/eip4844/fork/test_eip4844_fork_random.py +++ /dev/null @@ -1,84 +0,0 @@ -from random import Random - -from eth2spec.test.context import ( - with_phases, - with_custom_state, - with_presets, - spec_test, with_state, - low_balances, misc_balances, large_validator_set, -) -from eth2spec.test.utils import with_meta_tags -from eth2spec.test.helpers.constants import ( - CAPELLA, EIP4844, - MINIMAL, -) -from eth2spec.test.helpers.eip4844.fork import ( - EIP4844_FORK_TEST_META_TAGS, - run_fork_test, -) -from eth2spec.test.helpers.random import randomize_state - - -@with_phases(phases=[CAPELLA], other_phases=[EIP4844]) -@spec_test -@with_state -@with_meta_tags(EIP4844_FORK_TEST_META_TAGS) -def test_eip4844_fork_random_0(spec, phases, state): - randomize_state(spec, state, rng=Random(1010)) - yield from run_fork_test(phases[EIP4844], state) - - -@with_phases(phases=[CAPELLA], other_phases=[EIP4844]) -@spec_test -@with_state -@with_meta_tags(EIP4844_FORK_TEST_META_TAGS) -def test_eip4844_fork_random_1(spec, phases, state): - randomize_state(spec, state, rng=Random(2020)) - yield from run_fork_test(phases[EIP4844], state) - - -@with_phases(phases=[CAPELLA], other_phases=[EIP4844]) -@spec_test -@with_state -@with_meta_tags(EIP4844_FORK_TEST_META_TAGS) -def test_eip4844_fork_random_2(spec, phases, state): - randomize_state(spec, state, rng=Random(3030)) - yield from run_fork_test(phases[EIP4844], state) - - -@with_phases(phases=[CAPELLA], other_phases=[EIP4844]) -@spec_test -@with_state -@with_meta_tags(EIP4844_FORK_TEST_META_TAGS) -def test_eip4844_fork_random_3(spec, phases, state): - randomize_state(spec, state, rng=Random(4040)) - yield from run_fork_test(phases[EIP4844], state) - - -@with_phases(phases=[CAPELLA], other_phases=[EIP4844]) -@spec_test -@with_custom_state(balances_fn=low_balances, threshold_fn=lambda spec: spec.config.EJECTION_BALANCE) -@with_meta_tags(EIP4844_FORK_TEST_META_TAGS) -def test_eip4844_fork_random_low_balances(spec, phases, state): - randomize_state(spec, state, rng=Random(5050)) - yield from run_fork_test(phases[EIP4844], state) - - -@with_phases(phases=[CAPELLA], other_phases=[EIP4844]) -@spec_test -@with_custom_state(balances_fn=misc_balances, threshold_fn=lambda spec: spec.config.EJECTION_BALANCE) -@with_meta_tags(EIP4844_FORK_TEST_META_TAGS) -def test_eip4844_fork_random_misc_balances(spec, phases, state): - randomize_state(spec, state, rng=Random(6060)) - yield from run_fork_test(phases[EIP4844], state) - - -@with_phases(phases=[CAPELLA], other_phases=[EIP4844]) -@with_presets([MINIMAL], - reason="mainnet config leads to larger validator set than limit of public/private keys pre-generated") -@spec_test -@with_custom_state(balances_fn=large_validator_set, threshold_fn=lambda spec: spec.config.EJECTION_BALANCE) -@with_meta_tags(EIP4844_FORK_TEST_META_TAGS) -def test_eip4844_fork_random_large_validator_set(spec, phases, state): - randomize_state(spec, state, rng=Random(7070)) - yield from run_fork_test(phases[EIP4844], state) diff --git a/tests/core/pyspec/eth2spec/test/helpers/constants.py b/tests/core/pyspec/eth2spec/test/helpers/constants.py index b67b11f10..2c92b1c7e 100644 --- a/tests/core/pyspec/eth2spec/test/helpers/constants.py +++ b/tests/core/pyspec/eth2spec/test/helpers/constants.py @@ -14,25 +14,25 @@ CAPELLA = SpecForkName('capella') SHARDING = SpecForkName('sharding') CUSTODY_GAME = SpecForkName('custody_game') DAS = SpecForkName('das') -EIP4844 = SpecForkName('eip4844') +DENEB = SpecForkName('deneb') # The forks that pytest can run with. ALL_PHASES = ( # Formal forks PHASE0, ALTAIR, BELLATRIX, CAPELLA, # Experimental patches - EIP4844, + DENEB, ) # The forks that output to the test vectors. -TESTGEN_FORKS = (PHASE0, ALTAIR, BELLATRIX, CAPELLA, EIP4844) +TESTGEN_FORKS = (PHASE0, ALTAIR, BELLATRIX, CAPELLA, DENEB) -# TODO: no EIP4844 fork tests now. Should add when we figure out the content of Capella. +# TODO: no DENEB fork tests now. Should add when we figure out the content of Capella. ALL_FORK_UPGRADES = { # pre_fork_name: post_fork_name PHASE0: ALTAIR, ALTAIR: BELLATRIX, BELLATRIX: CAPELLA, - CAPELLA: EIP4844, + CAPELLA: DENEB, } ALL_PRE_POST_FORKS = ALL_FORK_UPGRADES.items() AFTER_BELLATRIX_UPGRADES = {key: value for key, value in ALL_FORK_UPGRADES.items() if key != PHASE0} diff --git a/tests/core/pyspec/eth2spec/test/helpers/eip4844/__init__.py b/tests/core/pyspec/eth2spec/test/helpers/deneb/__init__.py similarity index 100% rename from tests/core/pyspec/eth2spec/test/helpers/eip4844/__init__.py rename to tests/core/pyspec/eth2spec/test/helpers/deneb/__init__.py diff --git a/tests/core/pyspec/eth2spec/test/helpers/eip4844/fork.py b/tests/core/pyspec/eth2spec/test/helpers/deneb/fork.py similarity index 90% rename from tests/core/pyspec/eth2spec/test/helpers/eip4844/fork.py rename to tests/core/pyspec/eth2spec/test/helpers/deneb/fork.py index ed4ae057d..7fe0535c1 100644 --- a/tests/core/pyspec/eth2spec/test/helpers/eip4844/fork.py +++ b/tests/core/pyspec/eth2spec/test/helpers/deneb/fork.py @@ -1,17 +1,17 @@ from eth2spec.test.helpers.constants import ( - EIP4844, + DENEB, ) -EIP4844_FORK_TEST_META_TAGS = { - 'fork': EIP4844, +DENEB_FORK_TEST_META_TAGS = { + 'fork': DENEB, } def run_fork_test(post_spec, pre_state): yield 'pre', pre_state - post_state = post_spec.upgrade_to_eip4844(pre_state) + post_state = post_spec.upgrade_to_deneb(pre_state) # Stable fields stable_fields = [ @@ -57,7 +57,7 @@ def run_fork_test(post_spec, pre_state): assert getattr(pre_validator, field) == getattr(post_validator, field) assert pre_state.fork.current_version == post_state.fork.previous_version - assert post_state.fork.current_version == post_spec.config.EIP4844_FORK_VERSION + assert post_state.fork.current_version == post_spec.config.DENEB_FORK_VERSION assert post_state.fork.epoch == post_spec.get_current_epoch(post_state) yield 'post', post_state diff --git a/tests/core/pyspec/eth2spec/test/helpers/execution_payload.py b/tests/core/pyspec/eth2spec/test/helpers/execution_payload.py index 5e0c160b3..c0a70aca1 100644 --- a/tests/core/pyspec/eth2spec/test/helpers/execution_payload.py +++ b/tests/core/pyspec/eth2spec/test/helpers/execution_payload.py @@ -4,7 +4,7 @@ from rlp import encode from rlp.sedes import big_endian_int, Binary, List from eth2spec.debug.random_value import get_random_bytes_list -from eth2spec.test.helpers.forks import is_post_capella, is_post_eip4844 +from eth2spec.test.helpers.forks import is_post_capella, is_post_deneb def get_execution_payload_header(spec, execution_payload): @@ -26,7 +26,7 @@ def get_execution_payload_header(spec, execution_payload): ) if is_post_capella(spec): payload_header.withdrawals_root = spec.hash_tree_root(execution_payload.withdrawals) - if is_post_eip4844(spec): + if is_post_deneb(spec): payload_header.excess_data_gas = execution_payload.excess_data_gas return payload_header @@ -89,7 +89,7 @@ def compute_el_header_block_hash(spec, if is_post_capella(spec): # withdrawals_root execution_payload_header_rlp.append((Binary(32, 32), withdrawals_trie_root)) - if is_post_eip4844(spec): + if is_post_deneb(spec): # excess_data_gas execution_payload_header_rlp.append((big_endian_int, payload_header.excess_data_gas)) diff --git a/tests/core/pyspec/eth2spec/test/helpers/fork_transition.py b/tests/core/pyspec/eth2spec/test/helpers/fork_transition.py index 1e3374a64..52d1bc67e 100644 --- a/tests/core/pyspec/eth2spec/test/helpers/fork_transition.py +++ b/tests/core/pyspec/eth2spec/test/helpers/fork_transition.py @@ -13,7 +13,7 @@ from eth2spec.test.helpers.constants import ( ALTAIR, BELLATRIX, CAPELLA, - EIP4844, + DENEB, ) from eth2spec.test.helpers.deposits import ( prepare_state_and_deposit, @@ -151,8 +151,8 @@ def do_fork(state, spec, post_spec, fork_epoch, with_block=True, operation_dict= state = post_spec.upgrade_to_bellatrix(state) elif post_spec.fork == CAPELLA: state = post_spec.upgrade_to_capella(state) - elif post_spec.fork == EIP4844: - state = post_spec.upgrade_to_eip4844(state) + elif post_spec.fork == DENEB: + state = post_spec.upgrade_to_deneb(state) assert state.fork.epoch == fork_epoch @@ -165,9 +165,9 @@ def do_fork(state, spec, post_spec, fork_epoch, with_block=True, operation_dict= elif post_spec.fork == CAPELLA: assert state.fork.previous_version == post_spec.config.BELLATRIX_FORK_VERSION assert state.fork.current_version == post_spec.config.CAPELLA_FORK_VERSION - elif post_spec.fork == EIP4844: + elif post_spec.fork == DENEB: assert state.fork.previous_version == post_spec.config.CAPELLA_FORK_VERSION - assert state.fork.current_version == post_spec.config.EIP4844_FORK_VERSION + assert state.fork.current_version == post_spec.config.DENEB_FORK_VERSION if with_block: return state, _state_transition_and_sign_block_at_slot(post_spec, state, operation_dict=operation_dict) diff --git a/tests/core/pyspec/eth2spec/test/helpers/forks.py b/tests/core/pyspec/eth2spec/test/helpers/forks.py index 82ff12ff1..be3103e67 100644 --- a/tests/core/pyspec/eth2spec/test/helpers/forks.py +++ b/tests/core/pyspec/eth2spec/test/helpers/forks.py @@ -1,11 +1,11 @@ from .constants import ( - PHASE0, ALTAIR, BELLATRIX, CAPELLA, EIP4844, + PHASE0, ALTAIR, BELLATRIX, CAPELLA, DENEB, ) def is_post_fork(a, b): - if a == EIP4844: - return b in [PHASE0, ALTAIR, BELLATRIX, CAPELLA, EIP4844] + if a == DENEB: + return b in [PHASE0, ALTAIR, BELLATRIX, CAPELLA, DENEB] if a == CAPELLA: return b in [PHASE0, ALTAIR, BELLATRIX, CAPELLA] if a == BELLATRIX: @@ -29,5 +29,5 @@ def is_post_capella(spec): return is_post_fork(spec.fork, CAPELLA) -def is_post_eip4844(spec): - return is_post_fork(spec.fork, EIP4844) +def is_post_deneb(spec): + return is_post_fork(spec.fork, DENEB) diff --git a/tests/core/pyspec/eth2spec/test/helpers/genesis.py b/tests/core/pyspec/eth2spec/test/helpers/genesis.py index de2dd2647..0610f11ad 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, EIP4844, + ALTAIR, BELLATRIX, CAPELLA, DENEB, ) from eth2spec.test.helpers.execution_payload import ( compute_el_header_block_hash, @@ -77,9 +77,9 @@ def create_genesis_state(spec, validator_balances, activation_threshold): elif spec.fork == CAPELLA: previous_version = spec.config.BELLATRIX_FORK_VERSION current_version = spec.config.CAPELLA_FORK_VERSION - elif spec.fork == EIP4844: + elif spec.fork == DENEB: previous_version = spec.config.CAPELLA_FORK_VERSION - current_version = spec.config.EIP4844_FORK_VERSION + current_version = spec.config.DENEB_FORK_VERSION state = spec.BeaconState( genesis_time=0, diff --git a/tests/core/pyspec/eth2spec/test/utils/randomized_block_tests.py b/tests/core/pyspec/eth2spec/test/utils/randomized_block_tests.py index 4d2ec124d..35ddbc330 100644 --- a/tests/core/pyspec/eth2spec/test/utils/randomized_block_tests.py +++ b/tests/core/pyspec/eth2spec/test/utils/randomized_block_tests.py @@ -88,7 +88,7 @@ def randomize_state_capella(spec, state, stats, exit_fraction=0.1, slash_fractio return scenario_state -def randomize_state_eip4844(spec, state, stats, exit_fraction=0.1, slash_fraction=0.1): +def randomize_state_deneb(spec, state, stats, exit_fraction=0.1, slash_fraction=0.1): scenario_state = randomize_state_capella(spec, state, stats, @@ -232,7 +232,7 @@ def random_block_capella(spec, state, signed_blocks, scenario_state, rng=Random( return block -def random_block_eip4844(spec, state, signed_blocks, scenario_state, rng=Random(3456)): +def random_block_deneb(spec, state, signed_blocks, scenario_state, rng=Random(3456)): block = random_block_capella(spec, state, signed_blocks, scenario_state) # TODO: more commitments. blob_kzg_commitments: List[KZGCommitment, MAX_BLOBS_PER_BLOCK] opaque_tx, _, blob_kzg_commitments = get_sample_opaque_tx(spec, blob_count=1) diff --git a/tests/generators/epoch_processing/main.py b/tests/generators/epoch_processing/main.py index dda4345a8..a485f646a 100644 --- a/tests/generators/epoch_processing/main.py +++ b/tests/generators/epoch_processing/main.py @@ -1,5 +1,5 @@ from eth2spec.gen_helpers.gen_from_tests.gen import run_state_test_generators, combine_mods -from eth2spec.test.helpers.constants import PHASE0, ALTAIR, BELLATRIX, CAPELLA, EIP4844 +from eth2spec.test.helpers.constants import PHASE0, ALTAIR, BELLATRIX, CAPELLA, DENEB if __name__ == "__main__": @@ -32,7 +32,7 @@ if __name__ == "__main__": ]} capella_mods = combine_mods(_new_capella_mods, bellatrix_mods) - eip4844_mods = capella_mods + deneb_mods = capella_mods # TODO Custody Game testgen is disabled for now # custody_game_mods = {**{key: 'eth2spec.test.custody_game.epoch_processing.test_process_' + key for key in [ @@ -46,7 +46,7 @@ if __name__ == "__main__": ALTAIR: altair_mods, BELLATRIX: bellatrix_mods, CAPELLA: capella_mods, - EIP4844: eip4844_mods, + DENEB: deneb_mods, } run_state_test_generators(runner_name="epoch_processing", all_mods=all_mods) diff --git a/tests/generators/finality/main.py b/tests/generators/finality/main.py index de5af9b11..a25f3b8e7 100644 --- a/tests/generators/finality/main.py +++ b/tests/generators/finality/main.py @@ -1,5 +1,5 @@ from eth2spec.gen_helpers.gen_from_tests.gen import run_state_test_generators -from eth2spec.test.helpers.constants import PHASE0, ALTAIR, BELLATRIX, CAPELLA, EIP4844 +from eth2spec.test.helpers.constants import PHASE0, ALTAIR, BELLATRIX, CAPELLA, DENEB if __name__ == "__main__": @@ -7,14 +7,14 @@ if __name__ == "__main__": altair_mods = phase_0_mods # No additional Altair specific finality tests bellatrix_mods = altair_mods # No additional Bellatrix specific finality tests capella_mods = bellatrix_mods # No additional Capella specific finality tests - eip4844_mods = capella_mods # No additional EIP4844 specific finality tests + deneb_mods = capella_mods # No additional Deneb specific finality tests all_mods = { PHASE0: phase_0_mods, ALTAIR: altair_mods, BELLATRIX: bellatrix_mods, CAPELLA: capella_mods, - EIP4844: eip4844_mods, + DENEB: deneb_mods, } run_state_test_generators(runner_name="finality", all_mods=all_mods) diff --git a/tests/generators/fork_choice/main.py b/tests/generators/fork_choice/main.py index 40e19a8ac..c106810f8 100644 --- a/tests/generators/fork_choice/main.py +++ b/tests/generators/fork_choice/main.py @@ -1,5 +1,5 @@ from eth2spec.gen_helpers.gen_from_tests.gen import run_state_test_generators, combine_mods -from eth2spec.test.helpers.constants import PHASE0, ALTAIR, BELLATRIX, CAPELLA, EIP4844 +from eth2spec.test.helpers.constants import PHASE0, ALTAIR, BELLATRIX, CAPELLA, DENEB if __name__ == "__main__": @@ -18,14 +18,14 @@ if __name__ == "__main__": ]} bellatrix_mods = combine_mods(_new_bellatrix_mods, altair_mods) capella_mods = bellatrix_mods # No additional Capella specific fork choice tests - eip4844_mods = capella_mods # No additional Capella specific fork choice tests + deneb_mods = capella_mods # No additional Capella specific fork choice tests all_mods = { PHASE0: phase_0_mods, ALTAIR: altair_mods, BELLATRIX: bellatrix_mods, CAPELLA: capella_mods, - EIP4844: eip4844_mods, + DENEB: deneb_mods, } run_state_test_generators(runner_name="fork_choice", all_mods=all_mods) diff --git a/tests/generators/forks/main.py b/tests/generators/forks/main.py index 42f3f3a1f..7d68a31e7 100644 --- a/tests/generators/forks/main.py +++ b/tests/generators/forks/main.py @@ -1,14 +1,14 @@ from typing import Iterable from eth2spec.test.helpers.constants import ( - PHASE0, ALTAIR, BELLATRIX, CAPELLA, EIP4844, + PHASE0, ALTAIR, BELLATRIX, CAPELLA, DENEB, MINIMAL, MAINNET, ) from eth2spec.test.helpers.typing import SpecForkName, PresetBaseName from eth2spec.test.altair.fork import test_altair_fork_basic, test_altair_fork_random from eth2spec.test.bellatrix.fork import test_bellatrix_fork_basic, test_bellatrix_fork_random from eth2spec.test.capella.fork import test_capella_fork_basic, test_capella_fork_random -from eth2spec.test.eip4844.fork import test_eip4844_fork_basic, test_eip4844_fork_random +from eth2spec.test.deneb.fork import test_deneb_fork_basic, test_deneb_fork_random from eth2spec.gen_helpers.gen_base import gen_runner, gen_typing from eth2spec.gen_helpers.gen_from_tests.gen import generate_from_tests @@ -40,8 +40,8 @@ def _get_fork_tests_providers(): yield create_provider(test_bellatrix_fork_random, preset, ALTAIR, BELLATRIX) yield create_provider(test_capella_fork_basic, preset, BELLATRIX, CAPELLA) yield create_provider(test_capella_fork_random, preset, BELLATRIX, CAPELLA) - yield create_provider(test_eip4844_fork_basic, preset, CAPELLA, EIP4844) - yield create_provider(test_eip4844_fork_random, preset, CAPELLA, EIP4844) + yield create_provider(test_deneb_fork_basic, preset, CAPELLA, DENEB) + yield create_provider(test_deneb_fork_random, preset, CAPELLA, DENEB) if __name__ == "__main__": diff --git a/tests/generators/genesis/main.py b/tests/generators/genesis/main.py index a5c4eba9d..e95afcde1 100644 --- a/tests/generators/genesis/main.py +++ b/tests/generators/genesis/main.py @@ -1,5 +1,5 @@ from eth2spec.gen_helpers.gen_from_tests.gen import run_state_test_generators, combine_mods -from eth2spec.test.helpers.constants import PHASE0, ALTAIR, BELLATRIX, CAPELLA, EIP4844 +from eth2spec.test.helpers.constants import PHASE0, ALTAIR, BELLATRIX, CAPELLA, DENEB if __name__ == "__main__": @@ -16,13 +16,13 @@ if __name__ == "__main__": ]} bellatrix_mods = combine_mods(_new_bellatrix_mods, altair_mods) capella_mods = bellatrix_mods # No additional Capella specific genesis tests - eip4844_mods = capella_mods # No additional EIP4844 specific genesis tests + deneb_mods = capella_mods # No additional Deneb specific genesis tests all_mods = { PHASE0: phase_0_mods, ALTAIR: altair_mods, BELLATRIX: bellatrix_mods, CAPELLA: capella_mods, - EIP4844: eip4844_mods, + DENEB: deneb_mods, } run_state_test_generators(runner_name="genesis", all_mods=all_mods) diff --git a/tests/generators/light_client/main.py b/tests/generators/light_client/main.py index 54c09fae6..cfe34aee4 100644 --- a/tests/generators/light_client/main.py +++ b/tests/generators/light_client/main.py @@ -1,4 +1,4 @@ -from eth2spec.test.helpers.constants import ALTAIR, BELLATRIX, CAPELLA, EIP4844 +from eth2spec.test.helpers.constants import ALTAIR, BELLATRIX, CAPELLA, DENEB from eth2spec.gen_helpers.gen_from_tests.gen import combine_mods, run_state_test_generators @@ -14,13 +14,13 @@ if __name__ == "__main__": 'single_merkle_proof', ]} capella_mods = combine_mods(_new_capella_mods, bellatrix_mods) - eip4844_mods = capella_mods + deneb_mods = capella_mods all_mods = { ALTAIR: altair_mods, BELLATRIX: bellatrix_mods, CAPELLA: capella_mods, - EIP4844: eip4844_mods, + DENEB: deneb_mods, } run_state_test_generators(runner_name="light_client", all_mods=all_mods) diff --git a/tests/generators/operations/main.py b/tests/generators/operations/main.py index d370a1b85..ed4c6c26c 100644 --- a/tests/generators/operations/main.py +++ b/tests/generators/operations/main.py @@ -1,5 +1,5 @@ from eth2spec.gen_helpers.gen_from_tests.gen import run_state_test_generators, combine_mods -from eth2spec.test.helpers.constants import PHASE0, ALTAIR, BELLATRIX, CAPELLA, EIP4844 +from eth2spec.test.helpers.constants import PHASE0, ALTAIR, BELLATRIX, CAPELLA, DENEB if __name__ == "__main__": @@ -36,7 +36,7 @@ if __name__ == "__main__": ]} capella_mods = combine_mods(_new_capella_mods, bellatrix_mods) - eip4844_mods = capella_mods + deneb_mods = capella_mods # TODO Custody Game testgen is disabled for now # _new_custody_game_mods = {key: 'eth2spec.test.custody_game.block_processing.test_process_' + key for key in [ @@ -53,7 +53,7 @@ if __name__ == "__main__": ALTAIR: altair_mods, BELLATRIX: bellatrix_mods, CAPELLA: capella_mods, - EIP4844: eip4844_mods, + DENEB: deneb_mods, } run_state_test_generators(runner_name="operations", all_mods=all_mods) diff --git a/tests/generators/random/Makefile b/tests/generators/random/Makefile index f57221ab4..bb557204a 100644 --- a/tests/generators/random/Makefile +++ b/tests/generators/random/Makefile @@ -6,9 +6,9 @@ all: rm -f ../../core/pyspec/eth2spec/test/altair/random/test_random.py rm -f ../../core/pyspec/eth2spec/test/bellatrix/random/test_random.py rm -f ../../core/pyspec/eth2spec/test/capella/random/test_random.py - rm -f ../../core/pyspec/eth2spec/test/eip4844/random/test_random.py + rm -f ../../core/pyspec/eth2spec/test/deneb/random/test_random.py python3 generate.py phase0 > ../../core/pyspec/eth2spec/test/phase0/random/test_random.py python3 generate.py altair > ../../core/pyspec/eth2spec/test/altair/random/test_random.py python3 generate.py bellatrix > ../../core/pyspec/eth2spec/test/bellatrix/random/test_random.py python3 generate.py capella > ../../core/pyspec/eth2spec/test/capella/random/test_random.py - python3 generate.py eip4844 > ../../core/pyspec/eth2spec/test/eip4844/random/test_random.py + python3 generate.py deneb > ../../core/pyspec/eth2spec/test/deneb/random/test_random.py diff --git a/tests/generators/random/generate.py b/tests/generators/random/generate.py index 129d670fd..3a1eb9c67 100644 --- a/tests/generators/random/generate.py +++ b/tests/generators/random/generate.py @@ -21,12 +21,12 @@ from eth2spec.test.utils.randomized_block_tests import ( randomize_state_altair, randomize_state_bellatrix, randomize_state_capella, - randomize_state_eip4844, + randomize_state_deneb, random_block, random_block_altair_with_cycling_sync_committee_participation, random_block_bellatrix, random_block_capella, - random_block_eip4844, + random_block_deneb, last_slot_in_epoch, random_slot_in_epoch, penultimate_slot_in_epoch, @@ -36,7 +36,7 @@ from eth2spec.test.utils.randomized_block_tests import ( transition_to_leaking, transition_without_leak, ) -from eth2spec.test.helpers.constants import PHASE0, ALTAIR, BELLATRIX, CAPELLA, EIP4844 +from eth2spec.test.helpers.constants import PHASE0, ALTAIR, BELLATRIX, CAPELLA, DENEB # Ensure this many blocks are present in *each* randomized scenario @@ -274,12 +274,12 @@ if __name__ == "__main__": state_randomizer=randomize_state_capella, block_randomizer=random_block_capella, ) - if EIP4844 in sys.argv: + if DENEB in sys.argv: did_generate = True run_generate_tests_to_std_out( - EIP4844, - state_randomizer=randomize_state_eip4844, - block_randomizer=random_block_eip4844, + DENEB, + state_randomizer=randomize_state_deneb, + block_randomizer=random_block_deneb, ) if not did_generate: warnings.warn("no phase given for test generation") diff --git a/tests/generators/random/main.py b/tests/generators/random/main.py index e36678771..c5b991e4a 100644 --- a/tests/generators/random/main.py +++ b/tests/generators/random/main.py @@ -1,4 +1,4 @@ -from eth2spec.test.helpers.constants import PHASE0, ALTAIR, BELLATRIX, CAPELLA, EIP4844 +from eth2spec.test.helpers.constants import PHASE0, ALTAIR, BELLATRIX, CAPELLA, DENEB from eth2spec.gen_helpers.gen_from_tests.gen import run_state_test_generators @@ -15,7 +15,7 @@ if __name__ == "__main__": capella_mods = {key: 'eth2spec.test.capella.random.test_' + key for key in [ 'random', ]} - eip4844_mods = {key: 'eth2spec.test.eip4844.random.test_' + key for key in [ + deneb_mods = {key: 'eth2spec.test.deneb.random.test_' + key for key in [ 'random', ]} @@ -24,7 +24,7 @@ if __name__ == "__main__": ALTAIR: altair_mods, BELLATRIX: bellatrix_mods, CAPELLA: capella_mods, - EIP4844: eip4844_mods, + DENEB: deneb_mods, } run_state_test_generators(runner_name="random", all_mods=all_mods) diff --git a/tests/generators/rewards/main.py b/tests/generators/rewards/main.py index 8958074bc..e6244d172 100644 --- a/tests/generators/rewards/main.py +++ b/tests/generators/rewards/main.py @@ -1,5 +1,5 @@ from eth2spec.gen_helpers.gen_from_tests.gen import run_state_test_generators -from eth2spec.test.helpers.constants import PHASE0, ALTAIR, BELLATRIX, CAPELLA, EIP4844 +from eth2spec.test.helpers.constants import PHASE0, ALTAIR, BELLATRIX, CAPELLA, DENEB if __name__ == "__main__": @@ -16,14 +16,14 @@ if __name__ == "__main__": # Transaction fees are part of the execution-layer. bellatrix_mods = altair_mods capella_mods = bellatrix_mods - eip4844_mods = capella_mods + deneb_mods = capella_mods all_mods = { PHASE0: phase_0_mods, ALTAIR: altair_mods, BELLATRIX: bellatrix_mods, CAPELLA: capella_mods, - EIP4844: eip4844_mods, + DENEB: deneb_mods, } run_state_test_generators(runner_name="rewards", all_mods=all_mods) diff --git a/tests/generators/sanity/main.py b/tests/generators/sanity/main.py index 9dd6d7ac0..8a6c7b39c 100644 --- a/tests/generators/sanity/main.py +++ b/tests/generators/sanity/main.py @@ -1,4 +1,4 @@ -from eth2spec.test.helpers.constants import PHASE0, ALTAIR, BELLATRIX, CAPELLA, EIP4844 +from eth2spec.test.helpers.constants import PHASE0, ALTAIR, BELLATRIX, CAPELLA, DENEB from eth2spec.gen_helpers.gen_from_tests.gen import run_state_test_generators, combine_mods @@ -23,17 +23,17 @@ if __name__ == "__main__": ]} capella_mods = combine_mods(_new_capella_mods, bellatrix_mods) - _new_eip4844_mods = {key: 'eth2spec.test.eip4844.sanity.test_' + key for key in [ + _new_deneb_mods = {key: 'eth2spec.test.deneb.sanity.test_' + key for key in [ 'blocks', ]} - eip4844_mods = combine_mods(_new_eip4844_mods, capella_mods) + deneb_mods = combine_mods(_new_deneb_mods, capella_mods) all_mods = { PHASE0: phase_0_mods, ALTAIR: altair_mods, BELLATRIX: bellatrix_mods, CAPELLA: capella_mods, - EIP4844: eip4844_mods, + DENEB: deneb_mods, } run_state_test_generators(runner_name="sanity", all_mods=all_mods) diff --git a/tests/generators/sync/main.py b/tests/generators/sync/main.py index 8fb395053..11f05a741 100644 --- a/tests/generators/sync/main.py +++ b/tests/generators/sync/main.py @@ -1,5 +1,5 @@ from eth2spec.gen_helpers.gen_from_tests.gen import run_state_test_generators -from eth2spec.test.helpers.constants import BELLATRIX, CAPELLA, EIP4844 +from eth2spec.test.helpers.constants import BELLATRIX, CAPELLA, DENEB if __name__ == "__main__": @@ -7,12 +7,12 @@ if __name__ == "__main__": 'optimistic', ]} capella_mods = bellatrix_mods - eip4844_mods = capella_mods + deneb_mods = capella_mods all_mods = { BELLATRIX: bellatrix_mods, CAPELLA: capella_mods, - EIP4844: eip4844_mods, + DENEB: deneb_mods, } run_state_test_generators(runner_name="sync", all_mods=all_mods) From 26261269354e86f4e095d3c635c44f737c86b29b Mon Sep 17 00:00:00 2001 From: George Kadianakis Date: Tue, 24 Jan 2023 14:02:22 +0100 Subject: [PATCH 087/158] EIP4844: compute_kzg_proof() now takes bytes as input (#3219) --- specs/eip4844/polynomial-commitments.md | 18 +++++++++++++++--- .../test_polynomial_commitments.py | 2 +- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/specs/eip4844/polynomial-commitments.md b/specs/eip4844/polynomial-commitments.md index 26ee00487..53293cee8 100644 --- a/specs/eip4844/polynomial-commitments.md +++ b/specs/eip4844/polynomial-commitments.md @@ -35,6 +35,7 @@ - [`verify_kzg_proof`](#verify_kzg_proof) - [`verify_kzg_proof_impl`](#verify_kzg_proof_impl) - [`compute_kzg_proof`](#compute_kzg_proof) + - [`compute_kzg_proof_impl`](#compute_kzg_proof_impl) - [`compute_aggregated_poly_and_commitment`](#compute_aggregated_poly_and_commitment) - [`compute_aggregate_kzg_proof`](#compute_aggregate_kzg_proof) - [`verify_aggregate_kzg_proof`](#verify_aggregate_kzg_proof) @@ -370,12 +371,23 @@ def verify_kzg_proof_impl(polynomial_kzg: KZGCommitment, #### `compute_kzg_proof` ```python -def compute_kzg_proof(polynomial: Polynomial, z: BLSFieldElement) -> KZGProof: +def compute_kzg_proof(blob: Blob, z: Bytes32) -> KZGProof: """ - Compute KZG proof at point `z` with `polynomial` being in evaluation form. + Compute KZG proof at point `z` for the polynomial represented by `blob`. Do this by computing the quotient polynomial in evaluation form: q(x) = (p(x) - p(z)) / (x - z). Public method. """ + polynomial = blob_to_polynomial(blob) + return compute_kzg_proof_impl(polynomial, bytes_to_bls_field(z)) +``` + +#### `compute_kzg_proof_impl` + +```python +def compute_kzg_proof_impl(polynomial: Polynomial, z: BLSFieldElement) -> KZGProof: + """ + Helper function for compute_kzg_proof() and compute_aggregate_kzg_proof(). + """ y = evaluate_polynomial_in_evaluation_form(polynomial, z) polynomial_shifted = [BLSFieldElement((int(p) - int(y)) % BLS_MODULUS) for p in polynomial] @@ -430,7 +442,7 @@ def compute_aggregate_kzg_proof(blobs: Sequence[Blob]) -> KZGProof: blobs, commitments ) - return compute_kzg_proof(aggregated_poly, evaluation_challenge) + return compute_kzg_proof_impl(aggregated_poly, evaluation_challenge) ``` #### `verify_aggregate_kzg_proof` diff --git a/tests/core/pyspec/eth2spec/test/eip4844/unittests/polynomial_commitments/test_polynomial_commitments.py b/tests/core/pyspec/eth2spec/test/eip4844/unittests/polynomial_commitments/test_polynomial_commitments.py index 24b45475e..04f5857f3 100644 --- a/tests/core/pyspec/eth2spec/test/eip4844/unittests/polynomial_commitments/test_polynomial_commitments.py +++ b/tests/core/pyspec/eth2spec/test/eip4844/unittests/polynomial_commitments/test_polynomial_commitments.py @@ -18,7 +18,7 @@ def test_verify_kzg_proof(spec, state): blob = get_sample_blob(spec) commitment = spec.blob_to_kzg_commitment(blob) polynomial = spec.blob_to_polynomial(blob) - proof = spec.compute_kzg_proof(polynomial, x) + proof = spec.compute_kzg_proof_impl(polynomial, x) y = spec.evaluate_polynomial_in_evaluation_form(polynomial, x) assert spec.verify_kzg_proof_impl(commitment, x, y, proof) From d54c87a5c0703587012c0965cf2351cf4d0fb933 Mon Sep 17 00:00:00 2001 From: Ben Edgington Date: Tue, 24 Jan 2023 13:08:41 +0000 Subject: [PATCH 088/158] Add genesis_block to get_forkchoice_store() params --- specs/phase0/fork-choice.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/specs/phase0/fork-choice.md b/specs/phase0/fork-choice.md index 661ad613b..f8f88cf47 100644 --- a/specs/phase0/fork-choice.md +++ b/specs/phase0/fork-choice.md @@ -43,7 +43,7 @@ This document is the beacon chain fork choice spec, part of Phase 0. It assumes ## Fork choice -The head block root associated with a `store` is defined as `get_head(store)`. At genesis, let `store = get_forkchoice_store(genesis_state)` and update `store` by running: +The head block root associated with a `store` is defined as `get_head(store)`. At genesis, let `store = get_forkchoice_store(genesis_state, genesis_block)` and update `store` by running: - `on_tick(store, time)` whenever `time > store.time` where `time` is the current Unix time - `on_block(store, block)` whenever a block `block: SignedBeaconBlock` is received @@ -485,4 +485,4 @@ def on_attester_slashing(store: Store, attester_slashing: AttesterSlashing) -> N indices = set(attestation_1.attesting_indices).intersection(attestation_2.attesting_indices) for index in indices: store.equivocating_indices.add(index) -``` \ No newline at end of file +``` From 8a0de1c5957bb37654b7181d188700b947598707 Mon Sep 17 00:00:00 2001 From: Ben Edgington Date: Tue, 24 Jan 2023 13:25:40 +0000 Subject: [PATCH 089/158] Add on_attester_slashing() to handlers list --- specs/phase0/fork-choice.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/specs/phase0/fork-choice.md b/specs/phase0/fork-choice.md index 661ad613b..289c7a04c 100644 --- a/specs/phase0/fork-choice.md +++ b/specs/phase0/fork-choice.md @@ -48,6 +48,7 @@ The head block root associated with a `store` is defined as `get_head(store)`. A - `on_tick(store, time)` whenever `time > store.time` where `time` is the current Unix time - `on_block(store, block)` whenever a block `block: SignedBeaconBlock` is received - `on_attestation(store, attestation)` whenever an attestation `attestation` is received +- `on_attester_slashing(store, attester_slashing)` whenever an attester slashing `attester_slashing` is received Any of the above handlers that trigger an unhandled exception (e.g. a failed assert or an out-of-range list access) are considered invalid. Invalid calls to handlers must not modify `store`. @@ -485,4 +486,4 @@ def on_attester_slashing(store: Store, attester_slashing: AttesterSlashing) -> N indices = set(attestation_1.attesting_indices).intersection(attestation_2.attesting_indices) for index in indices: store.equivocating_indices.add(index) -``` \ No newline at end of file +``` From 5eca56901e7f8929b5420c4043cebcb16f89d713 Mon Sep 17 00:00:00 2001 From: kevaundray Date: Tue, 24 Jan 2023 14:14:25 +0000 Subject: [PATCH 090/158] Update polynomial-commitments.md (#3223) --- specs/eip4844/polynomial-commitments.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/specs/eip4844/polynomial-commitments.md b/specs/eip4844/polynomial-commitments.md index 53293cee8..e13bd7e46 100644 --- a/specs/eip4844/polynomial-commitments.md +++ b/specs/eip4844/polynomial-commitments.md @@ -56,10 +56,10 @@ Functions flagged as "Public method" MUST be provided by the underlying KZG libr | `G1Point` | `Bytes48` | | | `G2Point` | `Bytes96` | | | `BLSFieldElement` | `uint256` | `x < BLS_MODULUS` | -| `KZGCommitment` | `Bytes48` | Same as BLS standard "is valid pubkey" check but also allows `0x00..00` for point-at-infinity | +| `KZGCommitment` | `Bytes48` | Same as BLS standard "KeyValidate" check but allows the identity point | | `KZGProof` | `Bytes48` | Same as for `KZGCommitment` | -| `Polynomial` | `Vector[BLSFieldElement, FIELD_ELEMENTS_PER_BLOB]` | a polynomial in evaluation form | -| `Blob` | `ByteVector[BYTES_PER_FIELD_ELEMENT * FIELD_ELEMENTS_PER_BLOB]` | a basic blob data | +| `Polynomial` | `Vector[BLSFieldElement, FIELD_ELEMENTS_PER_BLOB]` | A polynomial in evaluation form | +| `Blob` | `ByteVector[BYTES_PER_FIELD_ELEMENT * FIELD_ELEMENTS_PER_BLOB]` | A basic blob data | ## Constants From 065b303dca6876337a501f86f183ac981ac8c0f7 Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Wed, 25 Jan 2023 10:59:30 +0100 Subject: [PATCH 091/158] Add tests of mixing top-ups and withdrawals, rename old test case --- .../test_process_withdrawals.py | 6 +- .../test/capella/sanity/test_blocks.py | 78 +++++++++++++++++++ 2 files changed, 82 insertions(+), 2 deletions(-) diff --git a/tests/core/pyspec/eth2spec/test/capella/block_processing/test_process_withdrawals.py b/tests/core/pyspec/eth2spec/test/capella/block_processing/test_process_withdrawals.py index 674231096..d7813fb1f 100644 --- a/tests/core/pyspec/eth2spec/test/capella/block_processing/test_process_withdrawals.py +++ b/tests/core/pyspec/eth2spec/test/capella/block_processing/test_process_withdrawals.py @@ -147,12 +147,14 @@ def test_success_one_partial_withdrawal(spec, state): @with_capella_and_later @spec_state_test -def test_success_max_per_slot(spec, state): +def test_success_mixed_fully_and_partial_withdrawable(spec, state): num_full_withdrawals = spec.MAX_WITHDRAWALS_PER_PAYLOAD // 2 num_partial_withdrawals = spec.MAX_WITHDRAWALS_PER_PAYLOAD - num_full_withdrawals fully_withdrawable_indices, partial_withdrawals_indices = prepare_expected_withdrawals( spec, state, - num_full_withdrawals=num_full_withdrawals, num_partial_withdrawals=num_partial_withdrawals) + num_full_withdrawals=num_full_withdrawals, + num_partial_withdrawals=num_partial_withdrawals, + ) next_slot(spec, state) execution_payload = build_empty_execution_payload(spec, state) diff --git a/tests/core/pyspec/eth2spec/test/capella/sanity/test_blocks.py b/tests/core/pyspec/eth2spec/test/capella/sanity/test_blocks.py index 1cd1c1317..6e54b4b55 100644 --- a/tests/core/pyspec/eth2spec/test/capella/sanity/test_blocks.py +++ b/tests/core/pyspec/eth2spec/test/capella/sanity/test_blocks.py @@ -3,6 +3,7 @@ from eth2spec.test.context import ( ) from eth2spec.test.helpers.state import ( state_transition_and_sign_block, + next_epoch_via_block, ) from eth2spec.test.helpers.block import ( build_empty_block_for_next_slot, @@ -13,10 +14,14 @@ from eth2spec.test.helpers.state import ( next_slot, ) from eth2spec.test.helpers.withdrawals import ( + set_eth1_withdrawal_credential_with_balance, set_validator_fully_withdrawable, set_validator_partially_withdrawable, prepare_expected_withdrawals, ) +from eth2spec.test.helpers.deposits import ( + prepare_state_and_deposit, +) from eth2spec.test.helpers.voluntary_exits import prepare_signed_exits @@ -255,3 +260,76 @@ def test_invalid_withdrawal_fail_second_block_payload_isnt_compatible(spec, stat yield 'blocks', [signed_block_2] yield 'post', None + + +# +# Mix top-ups and withdrawals +# + + +@with_capella_and_later +@spec_state_test +def test_top_up_and_partial_withdrawal_validator(spec, state): + next_withdrawal_validator_index = 0 + validator_index = next_withdrawal_validator_index + 1 + + set_eth1_withdrawal_credential_with_balance(spec, state, validator_index, spec.MAX_EFFECTIVE_BALANCE) + validator = state.validators[validator_index] + balance = state.balances[validator_index] + assert not spec.is_partially_withdrawable_validator(validator, balance) + + # Make a top-up balance to validator + amount = spec.MAX_EFFECTIVE_BALANCE // 4 + deposit = prepare_state_and_deposit(spec, state, validator_index, amount, signed=True) + + yield 'pre', state + + block = build_empty_block_for_next_slot(spec, state) + block.body.deposits.append(deposit) + + signed_block = state_transition_and_sign_block(spec, state, block) + + yield 'blocks', [signed_block] + yield 'post', state + + validator = state.validators[validator_index] + balance = state.balances[validator_index] + assert spec.is_partially_withdrawable_validator(validator, balance) + + +@with_capella_and_later +@spec_state_test +def test_top_up_and_fully_withdrawal_validator(spec, state): + """ + Similar to `teste_process_deposit::test_success_top_up_to_withdrawn_validator` test. + """ + next_withdrawal_validator_index = 0 + validator_index = next_withdrawal_validator_index + 1 + + # Fully withdraw validator + set_validator_fully_withdrawable(spec, state, validator_index) + assert state.balances[validator_index] > 0 + next_epoch_via_block(spec, state) + assert state.balances[validator_index] == 0 + assert state.validators[validator_index].effective_balance > 0 + next_epoch_via_block(spec, state) + assert state.validators[validator_index].effective_balance == 0 + + # Make a top-up balance to validator + amount = spec.MAX_EFFECTIVE_BALANCE // 4 + deposit = prepare_state_and_deposit(spec, state, validator_index, amount, signed=True) + + yield 'pre', state + + block = build_empty_block_for_next_slot(spec, state) + block.body.deposits.append(deposit) + + signed_block = state_transition_and_sign_block(spec, state, block) + + yield 'blocks', [signed_block] + yield 'post', state + + validator = state.validators[validator_index] + balance = state.balances[validator_index] + current_epoch = spec.get_current_epoch(state) + assert spec.is_fully_withdrawable_validator(validator, balance, current_epoch) From 6e397b195b8e7d5390a63634038c4615464fb7ff Mon Sep 17 00:00:00 2001 From: George Kadianakis Date: Wed, 25 Jan 2023 16:15:19 +0100 Subject: [PATCH 092/158] EIP4844: Public methods take bytes as input (explicit validation) (#3224) --- specs/eip4844/polynomial-commitments.md | 77 ++++++++++++++++++++----- 1 file changed, 63 insertions(+), 14 deletions(-) diff --git a/specs/eip4844/polynomial-commitments.md b/specs/eip4844/polynomial-commitments.md index e13bd7e46..9a0500d96 100644 --- a/specs/eip4844/polynomial-commitments.md +++ b/specs/eip4844/polynomial-commitments.md @@ -21,6 +21,9 @@ - [BLS12-381 helpers](#bls12-381-helpers) - [`hash_to_bls_field`](#hash_to_bls_field) - [`bytes_to_bls_field`](#bytes_to_bls_field) + - [`validate_kzg_g1`](#validate_kzg_g1) + - [`bytes_to_kzg_commitment`](#bytes_to_kzg_commitment) + - [`bytes_to_kzg_proof`](#bytes_to_kzg_proof) - [`blob_to_polynomial`](#blob_to_polynomial) - [`compute_challenges`](#compute_challenges) - [`bls_modular_inverse`](#bls_modular_inverse) @@ -49,14 +52,16 @@ This document specifies basic polynomial operations and KZG polynomial commitmen Functions flagged as "Public method" MUST be provided by the underlying KZG library as public functions. All other functions are private functions used internally by the KZG library. +Public functions MUST accept raw bytes as input and perform the required cryptographic normalization before invoking any internal functions. + ## Custom types | Name | SSZ equivalent | Description | | - | - | - | | `G1Point` | `Bytes48` | | | `G2Point` | `Bytes96` | | -| `BLSFieldElement` | `uint256` | `x < BLS_MODULUS` | -| `KZGCommitment` | `Bytes48` | Same as BLS standard "KeyValidate" check but allows the identity point | +| `BLSFieldElement` | `uint256` | Validation: `x < BLS_MODULUS` | +| `KZGCommitment` | `Bytes48` | Validation: Perform [BLS standard's](https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-bls-signature-04#section-2.5) "KeyValidate" check but do allow the identity point | | `KZGProof` | `Bytes48` | Same as for `KZGCommitment` | | `Polynomial` | `Vector[BLSFieldElement, FIELD_ELEMENTS_PER_BLOB]` | A polynomial in evaluation form | | `Blob` | `ByteVector[BYTES_PER_FIELD_ELEMENT * FIELD_ELEMENTS_PER_BLOB]` | A basic blob data | @@ -67,6 +72,8 @@ Functions flagged as "Public method" MUST be provided by the underlying KZG libr | - | - | - | | `BLS_MODULUS` | `52435875175126190479447740508185965837690552500527637822603658699938581184513` | Scalar field modulus of BLS12-381 | | `BYTES_PER_FIELD_ELEMENT` | `uint64(32)` | Bytes used to encode a BLS scalar field element | +| `G1_POINT_AT_INFINITY` | `Bytes48(b'\xc0' + b'\x00' * 47)` | Serialized form of the point at infinity on the G1 group | + ## Preset @@ -157,7 +164,7 @@ def hash_to_bls_field(data: bytes) -> BLSFieldElement: ```python def bytes_to_bls_field(b: Bytes32) -> BLSFieldElement: """ - Convert 32-byte value to a BLS scalar field element. + Convert untrusted bytes to a trusted and validated BLS scalar field element. This function does not accept inputs greater than the BLS modulus. """ field_element = int.from_bytes(b, ENDIANNESS) @@ -165,6 +172,42 @@ def bytes_to_bls_field(b: Bytes32) -> BLSFieldElement: return BLSFieldElement(field_element) ``` + +#### `validate_kzg_g1` + +```python +def validate_kzg_g1(b: Bytes48) -> None: + """ + Perform BLS validation required by the types `KZGProof` and `KZGCommitment`. + """ + if b == G1_POINT_AT_INFINITY: + return + + assert bls.KeyValidate(b) +``` + +#### `bytes_to_kzg_commitment` + +```python +def bytes_to_kzg_commitment(b: Bytes48) -> KZGCommitment: + """ + Convert untrusted bytes into a trusted and validated KZGCommitment. + """ + validate_kzg_g1(b) + return KZGCommitment(b) +``` + +#### `bytes_to_kzg_proof` + +```python +def bytes_to_kzg_proof(b: Bytes48) -> KZGProof: + """ + Convert untrusted bytes into a trusted and validated KZGProof. + """ + validate_kzg_g1(b) + return KZGProof(b) +``` + #### `blob_to_polynomial` ```python @@ -336,35 +379,38 @@ def blob_to_kzg_commitment(blob: Blob) -> KZGCommitment: #### `verify_kzg_proof` ```python -def verify_kzg_proof(polynomial_kzg: KZGCommitment, +def verify_kzg_proof(commitment_bytes: Bytes48, z: Bytes32, y: Bytes32, - kzg_proof: KZGProof) -> bool: + proof_bytes: Bytes48) -> bool: """ Verify KZG proof that ``p(z) == y`` where ``p(z)`` is the polynomial represented by ``polynomial_kzg``. Receives inputs as bytes. Public method. """ - return verify_kzg_proof_impl(polynomial_kzg, bytes_to_bls_field(z), bytes_to_bls_field(y), kzg_proof) + return verify_kzg_proof_impl(bytes_to_kzg_commitment(commitment_bytes), + bytes_to_bls_field(z), + bytes_to_bls_field(y), + bytes_to_kzg_proof(proof_bytes)) ``` #### `verify_kzg_proof_impl` ```python -def verify_kzg_proof_impl(polynomial_kzg: KZGCommitment, +def verify_kzg_proof_impl(commitment: KZGCommitment, z: BLSFieldElement, y: BLSFieldElement, - kzg_proof: KZGProof) -> bool: + proof: KZGProof) -> bool: """ Verify KZG proof that ``p(z) == y`` where ``p(z)`` is the polynomial represented by ``polynomial_kzg``. """ # Verify: P - y = Q * (X - z) X_minus_z = bls.add(bls.bytes96_to_G2(KZG_SETUP_G2[1]), bls.multiply(bls.G2, BLS_MODULUS - z)) - P_minus_y = bls.add(bls.bytes48_to_G1(polynomial_kzg), bls.multiply(bls.G1, BLS_MODULUS - y)) + P_minus_y = bls.add(bls.bytes48_to_G1(commitment), bls.multiply(bls.G1, BLS_MODULUS - y)) return bls.pairing_check([ [P_minus_y, bls.neg(bls.G2)], - [bls.bytes48_to_G1(kzg_proof), X_minus_z] + [bls.bytes48_to_G1(proof), X_minus_z] ]) ``` @@ -449,21 +495,24 @@ def compute_aggregate_kzg_proof(blobs: Sequence[Blob]) -> KZGProof: ```python def verify_aggregate_kzg_proof(blobs: Sequence[Blob], - expected_kzg_commitments: Sequence[KZGCommitment], - kzg_aggregated_proof: KZGProof) -> bool: + commitments_bytes: Sequence[Bytes48], + aggregated_proof_bytes: Bytes48) -> bool: """ Given a list of blobs and an aggregated KZG proof, verify that they correspond to the provided commitments. Public method. """ + commitments = [bytes_to_kzg_commitment(c) for c in commitments_bytes] + aggregated_poly, aggregated_poly_commitment, evaluation_challenge = compute_aggregated_poly_and_commitment( blobs, - expected_kzg_commitments, + commitments ) # Evaluate aggregated polynomial at `evaluation_challenge` (evaluation function checks for div-by-zero) y = evaluate_polynomial_in_evaluation_form(aggregated_poly, evaluation_challenge) # Verify aggregated proof - return verify_kzg_proof_impl(aggregated_poly_commitment, evaluation_challenge, y, kzg_aggregated_proof) + aggregated_proof = bytes_to_kzg_proof(aggregated_proof_bytes) + return verify_kzg_proof_impl(aggregated_poly_commitment, evaluation_challenge, y, aggregated_proof) ``` From e3b42ca397bc6a7c03aa8e3dd23822c03039c1f9 Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Wed, 25 Jan 2023 15:01:49 +0100 Subject: [PATCH 093/158] Add activate and partial withdrawal tests --- .../test/capella/sanity/test_blocks.py | 84 ++++++++++++++++++- .../pyspec/eth2spec/test/helpers/state.py | 3 +- 2 files changed, 82 insertions(+), 5 deletions(-) diff --git a/tests/core/pyspec/eth2spec/test/capella/sanity/test_blocks.py b/tests/core/pyspec/eth2spec/test/capella/sanity/test_blocks.py index 6e54b4b55..ff78f0e61 100644 --- a/tests/core/pyspec/eth2spec/test/capella/sanity/test_blocks.py +++ b/tests/core/pyspec/eth2spec/test/capella/sanity/test_blocks.py @@ -1,17 +1,25 @@ +from eth2spec.test.helpers.constants import MINIMAL from eth2spec.test.context import ( - with_capella_and_later, spec_state_test + with_capella_and_later, + spec_state_test, + with_presets, ) +from eth2spec.test.helpers.keys import pubkeys from eth2spec.test.helpers.state import ( - state_transition_and_sign_block, next_epoch_via_block, + state_transition_and_sign_block, + transition_to, + transition_to_slot_via_block, + next_epoch, + next_slot, ) from eth2spec.test.helpers.block import ( build_empty_block_for_next_slot, build_empty_block, ) from eth2spec.test.helpers.bls_to_execution_changes import get_signed_address_change -from eth2spec.test.helpers.state import ( - next_slot, +from eth2spec.test.helpers.attestations import ( + next_epoch_with_attestations, ) from eth2spec.test.helpers.withdrawals import ( set_eth1_withdrawal_credential_with_balance, @@ -333,3 +341,71 @@ def test_top_up_and_fully_withdrawal_validator(spec, state): balance = state.balances[validator_index] current_epoch = spec.get_current_epoch(state) assert spec.is_fully_withdrawable_validator(validator, balance, current_epoch) + + +def _insert_validator(spec, state, balance): + effective_balance = balance if balance < spec.MAX_EFFECTIVE_BALANCE else spec.MAX_EFFECTIVE_BALANCE + validator_index = len(state.validators) + validator = spec.Validator( + pubkey=pubkeys[validator_index], + withdrawal_credentials=spec.ETH1_ADDRESS_WITHDRAWAL_PREFIX + b'\x00' * 11 + b'\x56' * 20, + activation_eligibility_epoch=1, + activation_epoch=2, + exit_epoch=spec.FAR_FUTURE_EPOCH, + withdrawable_epoch=spec.FAR_FUTURE_EPOCH, + effective_balance=effective_balance, + ) + state.validators.append(validator) + state.balances.append(balance) + state.previous_epoch_participation.append(spec.ParticipationFlags(0b0000_0000)) + state.current_epoch_participation.append(spec.ParticipationFlags(0b0000_0000)) + state.inactivity_scores.append(0) + + return validator_index + + +def _run_activate_and_partial_withdrawal(spec, state, initial_balance): + validator_index = _insert_validator(spec, state, balance=initial_balance) + + next_epoch(spec, state) + transition_to(spec, state, spec.compute_start_slot_at_epoch(2) - 1) + + assert not spec.is_active_validator(state.validators[validator_index], spec.get_current_epoch(state)) + + yield 'pre', state + + blocks = [] + # To activate + signed_block = transition_to_slot_via_block(spec, state, state.slot + 1) + blocks.append(signed_block) + + assert spec.is_active_validator(state.validators[validator_index], spec.get_current_epoch(state)) + + if initial_balance > spec.MAX_EFFECTIVE_BALANCE: + assert spec.is_partially_withdrawable_validator( + state.validators[validator_index], state.balances[validator_index]) + else: + assert not spec.is_partially_withdrawable_validator( + state.validators[validator_index], state.balances[validator_index]) + + # Getting attester rewards and getting partial withdrawals + for _ in range(2): + _, new_blocks, state = next_epoch_with_attestations(spec, state, True, True) + blocks += new_blocks + + yield 'blocks', blocks + yield 'post', state + + +@with_capella_and_later +@with_presets([MINIMAL], reason="too many validators with mainnet config") +@spec_state_test +def test_activate_and_partial_withdrawal_max_effective_balance(spec, state): + yield from _run_activate_and_partial_withdrawal(spec, state, initial_balance=spec.MAX_EFFECTIVE_BALANCE) + + +@with_capella_and_later +@with_presets([MINIMAL], reason="too many validators with mainnet config") +@spec_state_test +def test_activate_and_partial_withdrawal_overdeposit(spec, state): + yield from _run_activate_and_partial_withdrawal(spec, state, initial_balance=spec.MAX_EFFECTIVE_BALANCE + 10000000) diff --git a/tests/core/pyspec/eth2spec/test/helpers/state.py b/tests/core/pyspec/eth2spec/test/helpers/state.py index 0dc17b00f..9d01b11ae 100644 --- a/tests/core/pyspec/eth2spec/test/helpers/state.py +++ b/tests/core/pyspec/eth2spec/test/helpers/state.py @@ -38,8 +38,9 @@ def transition_to_slot_via_block(spec, state, slot): Transition to ``slot`` via an empty block transition """ assert state.slot < slot - apply_empty_block(spec, state, slot) + signed_block = apply_empty_block(spec, state, slot) assert state.slot == slot + return signed_block def transition_to_valid_shard_slot(spec, state): From 507a7ec113ff4925a5202fe91eba3fd9478f9269 Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Thu, 26 Jan 2023 10:14:53 +0100 Subject: [PATCH 094/158] Add BLS_TO_EXECUTION_CHANGE fork transition tests --- .../capella/transition/test_operations.py | 54 +++++++++++++++++++ .../pyspec/eth2spec/test/helpers/constants.py | 3 ++ .../eth2spec/test/helpers/fork_transition.py | 9 ++++ 3 files changed, 66 insertions(+) create mode 100644 tests/core/pyspec/eth2spec/test/capella/transition/test_operations.py diff --git a/tests/core/pyspec/eth2spec/test/capella/transition/test_operations.py b/tests/core/pyspec/eth2spec/test/capella/transition/test_operations.py new file mode 100644 index 000000000..cb4021aa4 --- /dev/null +++ b/tests/core/pyspec/eth2spec/test/capella/transition/test_operations.py @@ -0,0 +1,54 @@ +from eth2spec.test.context import ( + ForkMeta, + always_bls, + with_fork_metas, +) +from eth2spec.test.helpers.constants import ( + AFTER_CAPELLA_PRE_POST_FORKS, +) +from eth2spec.test.helpers.fork_transition import ( + OperationType, + run_transition_with_operation, +) + + +# +# BLSToExecutionChange +# + +@with_fork_metas([ForkMeta(pre_fork_name=pre, post_fork_name=post, fork_epoch=2) + for pre, post in AFTER_CAPELLA_PRE_POST_FORKS]) +@always_bls +def test_transition_with_btec_right_after_fork(state, fork_epoch, spec, post_spec, pre_tag, post_tag): + """ + Create a BLS_TO_EXECUTION_CHANGE right *after* the transition + """ + yield from run_transition_with_operation( + state, + fork_epoch, + spec, + post_spec, + pre_tag, + post_tag, + operation_type=OperationType.BLS_TO_EXECUTION_CHANGE, + operation_at_slot=fork_epoch * spec.SLOTS_PER_EPOCH, + ) + + +@with_fork_metas([ForkMeta(pre_fork_name=pre, post_fork_name=post, fork_epoch=2) + for pre, post in AFTER_CAPELLA_PRE_POST_FORKS]) +@always_bls +def test_transition_with_btec_right_before_fork(state, fork_epoch, spec, post_spec, pre_tag, post_tag): + """ + Create a BLS_TO_EXECUTION_CHANGE right *before* the transition + """ + yield from run_transition_with_operation( + state, + fork_epoch, + spec, + post_spec, + pre_tag, + post_tag, + operation_type=OperationType.BLS_TO_EXECUTION_CHANGE, + operation_at_slot=fork_epoch * spec.SLOTS_PER_EPOCH - 1, + ) diff --git a/tests/core/pyspec/eth2spec/test/helpers/constants.py b/tests/core/pyspec/eth2spec/test/helpers/constants.py index b67b11f10..05e5ee19b 100644 --- a/tests/core/pyspec/eth2spec/test/helpers/constants.py +++ b/tests/core/pyspec/eth2spec/test/helpers/constants.py @@ -37,6 +37,9 @@ ALL_FORK_UPGRADES = { ALL_PRE_POST_FORKS = ALL_FORK_UPGRADES.items() AFTER_BELLATRIX_UPGRADES = {key: value for key, value in ALL_FORK_UPGRADES.items() if key != PHASE0} AFTER_BELLATRIX_PRE_POST_FORKS = AFTER_BELLATRIX_UPGRADES.items() +AFTER_CAPELLA_UPGRADES = {key: value for key, value in ALL_FORK_UPGRADES.items() + if key not in [PHASE0, ALTAIR, BELLATRIX]} +AFTER_CAPELLA_PRE_POST_FORKS = AFTER_CAPELLA_UPGRADES.items() # # Config diff --git a/tests/core/pyspec/eth2spec/test/helpers/fork_transition.py b/tests/core/pyspec/eth2spec/test/helpers/fork_transition.py index 1e3374a64..ca961bde4 100644 --- a/tests/core/pyspec/eth2spec/test/helpers/fork_transition.py +++ b/tests/core/pyspec/eth2spec/test/helpers/fork_transition.py @@ -9,6 +9,7 @@ from eth2spec.test.helpers.block import ( build_empty_block, sign_block, ) +from eth2spec.test.helpers.bls_to_execution_changes import get_signed_address_change from eth2spec.test.helpers.constants import ( ALTAIR, BELLATRIX, @@ -36,6 +37,7 @@ class OperationType(Enum): ATTESTER_SLASHING = auto() DEPOSIT = auto() VOLUNTARY_EXIT = auto() + BLS_TO_EXECUTION_CHANGE = auto() def _set_operations_by_dict(block, operation_dict): @@ -267,6 +269,10 @@ def run_transition_with_operation(state, selected_validator_index = 0 signed_exits = prepare_signed_exits(spec, state, [selected_validator_index]) operation_dict = {'voluntary_exits': signed_exits} + elif operation_type == OperationType.BLS_TO_EXECUTION_CHANGE: + selected_validator_index = 0 + bls_to_execution_changes = [get_signed_address_change(spec, state, selected_validator_index)] + operation_dict = {'bls_to_execution_changes': bls_to_execution_changes} def _check_state(): if operation_type == OperationType.PROPOSER_SLASHING: @@ -288,6 +294,9 @@ def run_transition_with_operation(state, elif operation_type == OperationType.VOLUNTARY_EXIT: validator = state.validators[selected_validator_index] assert validator.exit_epoch < post_spec.FAR_FUTURE_EPOCH + elif operation_type == OperationType.BLS_TO_EXECUTION_CHANGE: + validator = state.validators[selected_validator_index] + assert validator.withdrawal_credentials[:1] == spec.ETH1_ADDRESS_WITHDRAWAL_PREFIX yield "pre", state From 230dfb011ee4775b43a4d981bb6f8d1484d858a5 Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Thu, 26 Jan 2023 23:21:07 +0800 Subject: [PATCH 095/158] Apply suggestions from code review Co-authored-by: Danny Ryan --- .../core/pyspec/eth2spec/test/capella/sanity/test_blocks.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/core/pyspec/eth2spec/test/capella/sanity/test_blocks.py b/tests/core/pyspec/eth2spec/test/capella/sanity/test_blocks.py index ff78f0e61..7f5d64186 100644 --- a/tests/core/pyspec/eth2spec/test/capella/sanity/test_blocks.py +++ b/tests/core/pyspec/eth2spec/test/capella/sanity/test_blocks.py @@ -277,7 +277,7 @@ def test_invalid_withdrawal_fail_second_block_payload_isnt_compatible(spec, stat @with_capella_and_later @spec_state_test -def test_top_up_and_partial_withdrawal_validator(spec, state): +def test_top_up_and_partial_withdrawable_validator(spec, state): next_withdrawal_validator_index = 0 validator_index = next_withdrawal_validator_index + 1 @@ -307,7 +307,7 @@ def test_top_up_and_partial_withdrawal_validator(spec, state): @with_capella_and_later @spec_state_test -def test_top_up_and_fully_withdrawal_validator(spec, state): +def test_top_up_to_fully_withdrawn_validator(spec, state): """ Similar to `teste_process_deposit::test_success_top_up_to_withdrawn_validator` test. """ @@ -323,7 +323,7 @@ def test_top_up_and_fully_withdrawal_validator(spec, state): next_epoch_via_block(spec, state) assert state.validators[validator_index].effective_balance == 0 - # Make a top-up balance to validator + # Make a top-up deposit to validator amount = spec.MAX_EFFECTIVE_BALANCE // 4 deposit = prepare_state_and_deposit(spec, state, validator_index, amount, signed=True) From 3e78448fd16ec84bf3fa0e917e54c37874b3abe6 Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Fri, 27 Jan 2023 10:44:32 +0100 Subject: [PATCH 096/158] Address PR feedback --- .../test/capella/sanity/test_blocks.py | 37 ++++++++++++------- .../transition/test_operations.py | 6 +-- .../pyspec/eth2spec/test/helpers/constants.py | 5 ++- 3 files changed, 30 insertions(+), 18 deletions(-) rename tests/core/pyspec/eth2spec/test/{capella => eip4844}/transition/test_operations.py (89%) diff --git a/tests/core/pyspec/eth2spec/test/capella/sanity/test_blocks.py b/tests/core/pyspec/eth2spec/test/capella/sanity/test_blocks.py index 7f5d64186..808f1b581 100644 --- a/tests/core/pyspec/eth2spec/test/capella/sanity/test_blocks.py +++ b/tests/core/pyspec/eth2spec/test/capella/sanity/test_blocks.py @@ -10,7 +10,6 @@ from eth2spec.test.helpers.state import ( state_transition_and_sign_block, transition_to, transition_to_slot_via_block, - next_epoch, next_slot, ) from eth2spec.test.helpers.block import ( @@ -300,6 +299,7 @@ def test_top_up_and_partial_withdrawable_validator(spec, state): yield 'blocks', [signed_block] yield 'post', state + # Since withdrawals happen before deposits, it becomes partially withdrawable after state transition. validator = state.validators[validator_index] balance = state.balances[validator_index] assert spec.is_partially_withdrawable_validator(validator, balance) @@ -332,16 +332,28 @@ def test_top_up_to_fully_withdrawn_validator(spec, state): block = build_empty_block_for_next_slot(spec, state) block.body.deposits.append(deposit) - signed_block = state_transition_and_sign_block(spec, state, block) + signed_block_1 = state_transition_and_sign_block(spec, state, block) - yield 'blocks', [signed_block] + assert spec.is_fully_withdrawable_validator( + state.validators[validator_index], + state.balances[validator_index], + spec.get_current_epoch(state) + ) + + # Apply an empty block + signed_block_2 = transition_to_slot_via_block(spec, state, state.slot + 1) + + # With mainnet preset, it holds + if len(state.validators) <= spec.MAX_VALIDATORS_PER_WITHDRAWALS_SWEEP: + assert not spec.is_fully_withdrawable_validator( + state.validators[validator_index], + state.balances[validator_index], + spec.get_current_epoch(state) + ) + + yield 'blocks', [signed_block_1, signed_block_2] yield 'post', state - validator = state.validators[validator_index] - balance = state.balances[validator_index] - current_epoch = spec.get_current_epoch(state) - assert spec.is_fully_withdrawable_validator(validator, balance, current_epoch) - def _insert_validator(spec, state, balance): effective_balance = balance if balance < spec.MAX_EFFECTIVE_BALANCE else spec.MAX_EFFECTIVE_BALANCE @@ -367,9 +379,8 @@ def _insert_validator(spec, state, balance): def _run_activate_and_partial_withdrawal(spec, state, initial_balance): validator_index = _insert_validator(spec, state, balance=initial_balance) - next_epoch(spec, state) + # To make it eligibile activation transition_to(spec, state, spec.compute_start_slot_at_epoch(2) - 1) - assert not spec.is_active_validator(state.validators[validator_index], spec.get_current_epoch(state)) yield 'pre', state @@ -388,10 +399,8 @@ def _run_activate_and_partial_withdrawal(spec, state, initial_balance): assert not spec.is_partially_withdrawable_validator( state.validators[validator_index], state.balances[validator_index]) - # Getting attester rewards and getting partial withdrawals - for _ in range(2): - _, new_blocks, state = next_epoch_with_attestations(spec, state, True, True) - blocks += new_blocks + _, new_blocks, state = next_epoch_with_attestations(spec, state, True, True) + blocks += new_blocks yield 'blocks', blocks yield 'post', state diff --git a/tests/core/pyspec/eth2spec/test/capella/transition/test_operations.py b/tests/core/pyspec/eth2spec/test/eip4844/transition/test_operations.py similarity index 89% rename from tests/core/pyspec/eth2spec/test/capella/transition/test_operations.py rename to tests/core/pyspec/eth2spec/test/eip4844/transition/test_operations.py index cb4021aa4..f945afa8f 100644 --- a/tests/core/pyspec/eth2spec/test/capella/transition/test_operations.py +++ b/tests/core/pyspec/eth2spec/test/eip4844/transition/test_operations.py @@ -4,7 +4,7 @@ from eth2spec.test.context import ( with_fork_metas, ) from eth2spec.test.helpers.constants import ( - AFTER_CAPELLA_PRE_POST_FORKS, + AFTER_DENEB_PRE_POST_FORKS, ) from eth2spec.test.helpers.fork_transition import ( OperationType, @@ -17,7 +17,7 @@ from eth2spec.test.helpers.fork_transition import ( # @with_fork_metas([ForkMeta(pre_fork_name=pre, post_fork_name=post, fork_epoch=2) - for pre, post in AFTER_CAPELLA_PRE_POST_FORKS]) + for pre, post in AFTER_DENEB_PRE_POST_FORKS]) @always_bls def test_transition_with_btec_right_after_fork(state, fork_epoch, spec, post_spec, pre_tag, post_tag): """ @@ -36,7 +36,7 @@ def test_transition_with_btec_right_after_fork(state, fork_epoch, spec, post_spe @with_fork_metas([ForkMeta(pre_fork_name=pre, post_fork_name=post, fork_epoch=2) - for pre, post in AFTER_CAPELLA_PRE_POST_FORKS]) + for pre, post in AFTER_DENEB_PRE_POST_FORKS]) @always_bls def test_transition_with_btec_right_before_fork(state, fork_epoch, spec, post_spec, pre_tag, post_tag): """ diff --git a/tests/core/pyspec/eth2spec/test/helpers/constants.py b/tests/core/pyspec/eth2spec/test/helpers/constants.py index 05e5ee19b..cd103337f 100644 --- a/tests/core/pyspec/eth2spec/test/helpers/constants.py +++ b/tests/core/pyspec/eth2spec/test/helpers/constants.py @@ -38,8 +38,11 @@ ALL_PRE_POST_FORKS = ALL_FORK_UPGRADES.items() AFTER_BELLATRIX_UPGRADES = {key: value for key, value in ALL_FORK_UPGRADES.items() if key != PHASE0} AFTER_BELLATRIX_PRE_POST_FORKS = AFTER_BELLATRIX_UPGRADES.items() AFTER_CAPELLA_UPGRADES = {key: value for key, value in ALL_FORK_UPGRADES.items() - if key not in [PHASE0, ALTAIR, BELLATRIX]} + if key not in [PHASE0, ALTAIR]} AFTER_CAPELLA_PRE_POST_FORKS = AFTER_CAPELLA_UPGRADES.items() +AFTER_DENEB_UPGRADES = {key: value for key, value in ALL_FORK_UPGRADES.items() + if key not in [PHASE0, ALTAIR, BELLATRIX]} +AFTER_DENEB_PRE_POST_FORKS = AFTER_DENEB_UPGRADES.items() # # Config From 9ab147860c68aaf7f7d94d20d068c97e5de92520 Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Fri, 27 Jan 2023 10:48:00 +0100 Subject: [PATCH 097/158] Update transtion testgen --- .../pyspec/eth2spec/test/eip4844/transition/__init__.py | 0 tests/generators/transition/main.py | 7 +++++-- 2 files changed, 5 insertions(+), 2 deletions(-) create mode 100644 tests/core/pyspec/eth2spec/test/eip4844/transition/__init__.py diff --git a/tests/core/pyspec/eth2spec/test/eip4844/transition/__init__.py b/tests/core/pyspec/eth2spec/test/eip4844/transition/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/tests/generators/transition/main.py b/tests/generators/transition/main.py index 7de7213bd..a4eba90df 100644 --- a/tests/generators/transition/main.py +++ b/tests/generators/transition/main.py @@ -16,6 +16,9 @@ from eth2spec.test.altair.transition import ( test_slashing as test_altair_slashing, test_operations as test_altair_operations, ) +from eth2spec.test.eip4844.transition import ( + test_operations as test_eip4844_operations, +) def create_provider(tests_src, preset_name: str, pre_fork_name: str, post_fork_name: str) -> gen_typing.TestProvider: @@ -37,14 +40,14 @@ def create_provider(tests_src, preset_name: str, pre_fork_name: str, post_fork_n if __name__ == "__main__": - altair_tests = ( + all_tests = ( test_altair_transition, test_altair_activations_and_exits, test_altair_leaking, test_altair_slashing, test_altair_operations, + test_eip4844_operations, ) - all_tests = altair_tests for transition_test_module in all_tests: for pre_fork, post_fork in ALL_PRE_POST_FORKS: gen_runner.run_generator("transition", [ From a2b3cd33ef850f39ca56d97e1a6957963abb75b7 Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Fri, 27 Jan 2023 18:54:09 +0800 Subject: [PATCH 098/158] bump VERSION.txt to 1.3.0-rc.2 --- 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 bf16dded0..1d074f43e 100644 --- a/tests/core/pyspec/eth2spec/VERSION.txt +++ b/tests/core/pyspec/eth2spec/VERSION.txt @@ -1 +1 @@ -1.3.0-rc.1 +1.3.0-rc.2 From 03f4b8fa4dbb0f5de4541cf435fee8b5a5badc0c Mon Sep 17 00:00:00 2001 From: Dankrad Feist Date: Fri, 27 Jan 2023 14:23:38 +0000 Subject: [PATCH 099/158] Add KZG multi verify function --- specs/eip4844/polynomial-commitments.md | 98 +++++++++++++++++++++++-- 1 file changed, 93 insertions(+), 5 deletions(-) diff --git a/specs/eip4844/polynomial-commitments.md b/specs/eip4844/polynomial-commitments.md index 9a0500d96..8ef1fc419 100644 --- a/specs/eip4844/polynomial-commitments.md +++ b/specs/eip4844/polynomial-commitments.md @@ -83,6 +83,7 @@ Public functions MUST accept raw bytes as input and perform the required cryptog | - | - | | `FIELD_ELEMENTS_PER_BLOB` | `uint64(4096)` | | `FIAT_SHAMIR_PROTOCOL_DOMAIN` | `b'FSBLOBVERIFY_V1_'` | +| `RANDOM_CHALLENGE_KZG_MULTI_DOMAIN` | `b'RCKZGMULTI___V1_'` | ### Crypto @@ -414,6 +415,51 @@ def verify_kzg_proof_impl(commitment: KZGCommitment, ]) ``` +#### `verify_kzg_proof_multi` + +```python +def verify_kzg_proof_multi(commitments: Sequence[KZGCommitment], + zs: Sequence[BLSFieldElement], + ys: Sequence[BLSFieldElement], + proofs: Sequence[KZGProof]) -> bool: + """ + Verify multiple KZG proofs efficiently. + """ + + assert len(commitments) == len(zs) == len(ys) == len(proofs) + + # Compute a random challenge. Note that it does not have to be computed from a hash, + # r just has to be random. + degree_poly = int.to_bytes(FIELD_ELEMENTS_PER_BLOB, 8, ENDIANNESS) + num_commitments = int.to_bytes(len(commitments), 8, ENDIANNESS) + data = RANDOM_CHALLENGE_KZG_MULTI_DOMAIN + degree_poly + num_commitments + + # Append each polynomial which is composed by field elements + for commitment, z, y, proof in zip(commitments, zs, ys, proofs): + data += commitment \ + + int.to_bytes(z, BYTES_PER_FIELD_ELEMENT, ENDIANNESS) \ + + int.to_bytes(y, BYTES_PER_FIELD_ELEMENT, ENDIANNESS) \ + + proof + + hashed_data = hash(data) + r = hash_to_bls_field(hashed_data + b'\x00') + r_powers = compute_powers(r, len(commitments)) + + # Verify: e(sum r^i proof_i, [s]) == + # e(sum r^i (commitment_i - [y_i]) + sum r^i z_i proof_i, [1]) + proof_lincomb = g1_lincomb(proofs, r_powers) + proof_z_lincomb = g1_lincomb(proofs, [z * r_power for z, r_power in zip(zs, r_powers)]) + C_minus_ys = [bls.G1_to_bytes48(bls.add(bls.bytes48_to_G1(commitment), bls.multiply(bls.G1, BLS_MODULUS - y))) + for commitment, y in zip(commitments, ys)] + C_minus_y_as_KZGCommitments = [KZGCommitment(x) for x in C_minus_ys] + C_minus_y_lincomb = g1_lincomb(C_minus_y_as_KZGCommitments, r_powers) + + return bls.pairing_check([ + [proof_lincomb, bls.neg(KZG_SETUP_G2[1])], + [bls.add(C_minus_y_lincomb, proof_z_lincomb), bls.G2] + ]) +``` + #### `compute_kzg_proof` ```python @@ -491,12 +537,12 @@ def compute_aggregate_kzg_proof(blobs: Sequence[Blob]) -> KZGProof: return compute_kzg_proof_impl(aggregated_poly, evaluation_challenge) ``` -#### `verify_aggregate_kzg_proof` +#### `verify_aggregate_kzg_proof_aggregation` ```python -def verify_aggregate_kzg_proof(blobs: Sequence[Blob], - commitments_bytes: Sequence[Bytes48], - aggregated_proof_bytes: Bytes48) -> bool: +def verify_aggregate_kzg_proof_aggregation(blobs: Sequence[Blob], + commitments_bytes: Sequence[Bytes48]) \ + -> Tuple[KZGCommitment, BLSFieldElement, BLSFieldElement]: """ Given a list of blobs and an aggregated KZG proof, verify that they correspond to the provided commitments. @@ -512,7 +558,49 @@ def verify_aggregate_kzg_proof(blobs: Sequence[Blob], # Evaluate aggregated polynomial at `evaluation_challenge` (evaluation function checks for div-by-zero) y = evaluate_polynomial_in_evaluation_form(aggregated_poly, evaluation_challenge) - # Verify aggregated proof + return (aggregated_poly_commitment, evaluation_challenge, y) +``` + +#### `verify_aggregate_kzg_proof` + +```python +def verify_aggregate_kzg_proof(blobs: Sequence[Blob], + commitments_bytes: Sequence[Bytes48], + aggregated_proof_bytes: Bytes48) -> bool: + """ + Given a list of blobs and an aggregated KZG proof, verify that they correspond to the provided commitments. + + Public method. + """ + aggregated_poly_commitment, evaluation_challenge, y = \ + verify_aggregate_kzg_proof_aggregation(blobs, commitments_bytes) + aggregated_proof = bytes_to_kzg_proof(aggregated_proof_bytes) + return verify_kzg_proof_impl(aggregated_poly_commitment, evaluation_challenge, y, aggregated_proof) ``` + +#### `verify_aggregate_kzg_proof_multi` + +```python +def verify_aggregate_kzg_proof_multi(list_blobs: Sequence[Sequence[Blob]], + list_commitments_bytes: Sequence[Sequence[Bytes48]], + list_aggregated_proof_bytes: Sequence[Bytes48]) -> bool: + """ + Given a list of blobs and an aggregated KZG proof, verify that they correspond to the provided commitments. + + Public method. + """ + + aggregated_poly_commitments, evaluation_challenges, ys = [], [], [] + for blobs, commitments_bytes in zip(list_blobs, list_commitments_bytes): + aggregated_poly_commitment, evaluation_challenge, y = \ + verify_aggregate_kzg_proof_aggregation(blobs, commitments_bytes) + aggregated_poly_commitments.append(aggregated_poly_commitment) + evaluation_challenges.append(evaluation_challenge) + ys.append(y) + + list_aggregated_proof = [bytes_to_kzg_proof(proof) for proof in list_aggregated_proof_bytes] + + return verify_kzg_proof_multi(aggregated_poly_commitments, evaluation_challenges, ys, list_aggregated_proof) +``` From d89e57908973bb9b2916a22fdf453d3cb3ecea14 Mon Sep 17 00:00:00 2001 From: Dankrad Feist Date: Fri, 27 Jan 2023 14:33:43 +0000 Subject: [PATCH 100/158] Updater toc --- specs/eip4844/polynomial-commitments.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/specs/eip4844/polynomial-commitments.md b/specs/eip4844/polynomial-commitments.md index 8ef1fc419..c6e15f65e 100644 --- a/specs/eip4844/polynomial-commitments.md +++ b/specs/eip4844/polynomial-commitments.md @@ -37,11 +37,14 @@ - [`blob_to_kzg_commitment`](#blob_to_kzg_commitment) - [`verify_kzg_proof`](#verify_kzg_proof) - [`verify_kzg_proof_impl`](#verify_kzg_proof_impl) + - [`verify_kzg_proof_multi`](#verify_kzg_proof_multi) - [`compute_kzg_proof`](#compute_kzg_proof) - [`compute_kzg_proof_impl`](#compute_kzg_proof_impl) - [`compute_aggregated_poly_and_commitment`](#compute_aggregated_poly_and_commitment) - [`compute_aggregate_kzg_proof`](#compute_aggregate_kzg_proof) + - [`verify_aggregate_kzg_proof_aggregation`](#verify_aggregate_kzg_proof_aggregation) - [`verify_aggregate_kzg_proof`](#verify_aggregate_kzg_proof) + - [`verify_aggregate_kzg_proof_multi`](#verify_aggregate_kzg_proof_multi) From 366e3b64c4a26b58922d356b0871fc172cf9a472 Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Fri, 27 Jan 2023 15:37:12 +0100 Subject: [PATCH 101/158] hotfix: `transition_to_slot_via_block` only return unsigned block --- .../pyspec/eth2spec/test/capella/sanity/test_blocks.py | 7 ++++--- tests/core/pyspec/eth2spec/test/helpers/state.py | 3 +-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/core/pyspec/eth2spec/test/capella/sanity/test_blocks.py b/tests/core/pyspec/eth2spec/test/capella/sanity/test_blocks.py index 808f1b581..079990e3e 100644 --- a/tests/core/pyspec/eth2spec/test/capella/sanity/test_blocks.py +++ b/tests/core/pyspec/eth2spec/test/capella/sanity/test_blocks.py @@ -9,7 +9,6 @@ from eth2spec.test.helpers.state import ( next_epoch_via_block, state_transition_and_sign_block, transition_to, - transition_to_slot_via_block, next_slot, ) from eth2spec.test.helpers.block import ( @@ -341,7 +340,8 @@ def test_top_up_to_fully_withdrawn_validator(spec, state): ) # Apply an empty block - signed_block_2 = transition_to_slot_via_block(spec, state, state.slot + 1) + block = build_empty_block_for_next_slot(spec, state) + signed_block_2 = state_transition_and_sign_block(spec, state, block) # With mainnet preset, it holds if len(state.validators) <= spec.MAX_VALIDATORS_PER_WITHDRAWALS_SWEEP: @@ -387,7 +387,8 @@ def _run_activate_and_partial_withdrawal(spec, state, initial_balance): blocks = [] # To activate - signed_block = transition_to_slot_via_block(spec, state, state.slot + 1) + block = build_empty_block_for_next_slot(spec, state) + signed_block = state_transition_and_sign_block(spec, state, block) blocks.append(signed_block) assert spec.is_active_validator(state.validators[validator_index], spec.get_current_epoch(state)) diff --git a/tests/core/pyspec/eth2spec/test/helpers/state.py b/tests/core/pyspec/eth2spec/test/helpers/state.py index 9d01b11ae..0dc17b00f 100644 --- a/tests/core/pyspec/eth2spec/test/helpers/state.py +++ b/tests/core/pyspec/eth2spec/test/helpers/state.py @@ -38,9 +38,8 @@ def transition_to_slot_via_block(spec, state, slot): Transition to ``slot`` via an empty block transition """ assert state.slot < slot - signed_block = apply_empty_block(spec, state, slot) + apply_empty_block(spec, state, slot) assert state.slot == slot - return signed_block def transition_to_valid_shard_slot(spec, state): From 659c7f513f74494371b8b478fe2d930536306e5d Mon Sep 17 00:00:00 2001 From: Dankrad Feist Date: Sun, 29 Jan 2023 13:05:02 +0000 Subject: [PATCH 102/158] Change blob verification fiat-shamir to single blob --- specs/eip4844/polynomial-commitments.md | 177 +++++++----------------- 1 file changed, 49 insertions(+), 128 deletions(-) diff --git a/specs/eip4844/polynomial-commitments.md b/specs/eip4844/polynomial-commitments.md index c6e15f65e..63217c0bc 100644 --- a/specs/eip4844/polynomial-commitments.md +++ b/specs/eip4844/polynomial-commitments.md @@ -25,11 +25,10 @@ - [`bytes_to_kzg_commitment`](#bytes_to_kzg_commitment) - [`bytes_to_kzg_proof`](#bytes_to_kzg_proof) - [`blob_to_polynomial`](#blob_to_polynomial) - - [`compute_challenges`](#compute_challenges) + - [`compute_challenge`](#compute_challenge) - [`bls_modular_inverse`](#bls_modular_inverse) - [`div`](#div) - [`g1_lincomb`](#g1_lincomb) - - [`poly_lincomb`](#poly_lincomb) - [`compute_powers`](#compute_powers) - [Polynomials](#polynomials) - [`evaluate_polynomial_in_evaluation_form`](#evaluate_polynomial_in_evaluation_form) @@ -40,11 +39,9 @@ - [`verify_kzg_proof_multi`](#verify_kzg_proof_multi) - [`compute_kzg_proof`](#compute_kzg_proof) - [`compute_kzg_proof_impl`](#compute_kzg_proof_impl) - - [`compute_aggregated_poly_and_commitment`](#compute_aggregated_poly_and_commitment) - - [`compute_aggregate_kzg_proof`](#compute_aggregate_kzg_proof) - - [`verify_aggregate_kzg_proof_aggregation`](#verify_aggregate_kzg_proof_aggregation) - - [`verify_aggregate_kzg_proof`](#verify_aggregate_kzg_proof) - - [`verify_aggregate_kzg_proof_multi`](#verify_aggregate_kzg_proof_multi) + - [`compute_blob_kzg_proof`](#compute_blob_kzg_proof) + - [`verify_blob_kzg_proof`](#verify_blob_kzg_proof) + - [`verify_blob_kzg_proof_multi`](#verify_blob_kzg_proof_multi) @@ -226,44 +223,34 @@ def blob_to_polynomial(blob: Blob) -> Polynomial: return polynomial ``` -#### `compute_challenges` +#### `compute_challenge` ```python -def compute_challenges(polynomials: Sequence[Polynomial], - commitments: Sequence[KZGCommitment]) -> Tuple[Sequence[BLSFieldElement], BLSFieldElement]: +def compute_challenge(polynomial: Polynomial, + commitment: KZGCommitment) -> BLSFieldElement: """ Return the Fiat-Shamir challenges required by the rest of the protocol. The Fiat-Shamir logic works as per the following pseudocode: - hashed_data = hash(DOMAIN_SEPARATOR, polynomials, commitments) - r = hash(hashed_data, 0) - r_powers = [1, r, r**2, r**3, ...] - eval_challenge = hash(hashed_data, 1) - - Then return `r_powers` and `eval_challenge` after converting them to BLS field elements. - The resulting field elements are not uniform over the BLS field. + hashed_data = hash(DOMAIN_SEPARATOR, polynomial, commitment) + eval_challenge = hash(hashed_data, 0) """ + # Append the number of polynomials and the degree of each polynomial as a domain separator - num_polynomials = int.to_bytes(len(polynomials), 8, ENDIANNESS) + num_polynomials = int.to_bytes(1, 8, ENDIANNESS) degree_poly = int.to_bytes(FIELD_ELEMENTS_PER_BLOB, 8, ENDIANNESS) data = FIAT_SHAMIR_PROTOCOL_DOMAIN + degree_poly + num_polynomials # Append each polynomial which is composed by field elements - for poly in polynomials: - for field_element in poly: - data += int.to_bytes(field_element, BYTES_PER_FIELD_ELEMENT, ENDIANNESS) + for field_element in polynomial: + data += int.to_bytes(field_element, BYTES_PER_FIELD_ELEMENT, ENDIANNESS) # Append serialized G1 points - for commitment in commitments: - data += commitment + data += commitment # Transcript has been prepared: time to create the challenges hashed_data = hash(data) - r = hash_to_bls_field(hashed_data + b'\x00') - r_powers = compute_powers(r, len(commitments)) - eval_challenge = hash_to_bls_field(hashed_data + b'\x01') - - return r_powers, eval_challenge + return hash_to_bls_field(hashed_data + b'\x00') ``` #### `bls_modular_inverse` @@ -301,23 +288,6 @@ def g1_lincomb(points: Sequence[KZGCommitment], scalars: Sequence[BLSFieldElemen return KZGCommitment(bls.G1_to_bytes48(result)) ``` -#### `poly_lincomb` - -```python -def poly_lincomb(polys: Sequence[Polynomial], - scalars: Sequence[BLSFieldElement]) -> Polynomial: - """ - Given a list of ``polynomials``, interpret it as a 2D matrix and compute the linear combination - of each column with `scalars`: return the resulting polynomials. - """ - assert len(polys) == len(scalars) - result = [0] * FIELD_ELEMENTS_PER_BLOB - for v, s in zip(polys, scalars): - for i, x in enumerate(v): - result[i] = (result[i] + int(s) * int(x)) % BLS_MODULUS - return Polynomial([BLSFieldElement(x) for x in result]) -``` - #### `compute_powers` ```python @@ -496,114 +466,65 @@ def compute_kzg_proof_impl(polynomial: Polynomial, z: BLSFieldElement) -> KZGPro return KZGProof(g1_lincomb(bit_reversal_permutation(KZG_SETUP_LAGRANGE), quotient_polynomial)) ``` -#### `compute_aggregated_poly_and_commitment` +#### `compute_blob_kzg_proof` ```python -def compute_aggregated_poly_and_commitment( - blobs: Sequence[Blob], - kzg_commitments: Sequence[KZGCommitment]) -> Tuple[Polynomial, KZGCommitment, BLSFieldElement]: +def compute_blob_kzg_proof(blob: Blob) -> KZGProof: """ - Return (1) the aggregated polynomial, (2) the aggregated KZG commitment, - and (3) the polynomial evaluation random challenge. - This function should also work with blobs == [] and kzg_commitments == [] - """ - assert len(blobs) == len(kzg_commitments) - - # Convert blobs to polynomials - polynomials = [blob_to_polynomial(blob) for blob in blobs] - - # Generate random linear combination and evaluation challenges - r_powers, evaluation_challenge = compute_challenges(polynomials, kzg_commitments) - - # Create aggregated polynomial in evaluation form - aggregated_poly = poly_lincomb(polynomials, r_powers) - - # Compute commitment to aggregated polynomial - aggregated_poly_commitment = KZGCommitment(g1_lincomb(kzg_commitments, r_powers)) - - return aggregated_poly, aggregated_poly_commitment, evaluation_challenge -``` - -#### `compute_aggregate_kzg_proof` - -```python -def compute_aggregate_kzg_proof(blobs: Sequence[Blob]) -> KZGProof: - """ - Given a list of blobs, return the aggregated KZG proof that is used to verify them against their commitments. + Given a blob, return the KZG proof that is used to verify it against the commitment. Public method. """ - commitments = [blob_to_kzg_commitment(blob) for blob in blobs] - aggregated_poly, aggregated_poly_commitment, evaluation_challenge = compute_aggregated_poly_and_commitment( - blobs, - commitments - ) - return compute_kzg_proof_impl(aggregated_poly, evaluation_challenge) + commitment = blob_to_kzg_commitment(blob) + evaluation_challenge = compute_challenge(blob, commitment) + polynomial = blob_to_polynomial(blob) + return compute_kzg_proof_impl(polynomial, evaluation_challenge) ``` -#### `verify_aggregate_kzg_proof_aggregation` +#### `verify_blob_kzg_proof` ```python -def verify_aggregate_kzg_proof_aggregation(blobs: Sequence[Blob], - commitments_bytes: Sequence[Bytes48]) \ - -> Tuple[KZGCommitment, BLSFieldElement, BLSFieldElement]: +def verify_blob_kzg_proof(blob: Blob, + commitment_bytes: Bytes48, + proof_bytes: Bytes48) -> bool: """ - Given a list of blobs and an aggregated KZG proof, verify that they correspond to the provided commitments. + Given a blob and a KZG proof, verify that the blob data corresponds to the provided commitment. Public method. """ - commitments = [bytes_to_kzg_commitment(c) for c in commitments_bytes] + commitment = bytes_to_kzg_commitment(commitment_bytes) - aggregated_poly, aggregated_poly_commitment, evaluation_challenge = compute_aggregated_poly_and_commitment( - blobs, - commitments - ) + evaluation_challenge = compute_challenge(blob, commitment) + polynomial = blob_to_polynomial(blob) - # Evaluate aggregated polynomial at `evaluation_challenge` (evaluation function checks for div-by-zero) - y = evaluate_polynomial_in_evaluation_form(aggregated_poly, evaluation_challenge) + # Evaluate polynomial at `evaluation_challenge` (evaluation function checks for div-by-zero) + y = evaluate_polynomial_in_evaluation_form(polynomial, evaluation_challenge) - return (aggregated_poly_commitment, evaluation_challenge, y) + # Verify proof + proof = bytes_to_kzg_proof(proof_bytes) + return verify_kzg_proof_impl(commitment, evaluation_challenge, y, proof) ``` -#### `verify_aggregate_kzg_proof` +#### `verify_blob_kzg_proof_multi` ```python -def verify_aggregate_kzg_proof(blobs: Sequence[Blob], - commitments_bytes: Sequence[Bytes48], - aggregated_proof_bytes: Bytes48) -> bool: +def verify_blob_kzg_proof_multi(blobs: Sequence[Blob], + commitments_bytes: Sequence[Bytes48], + proofs_bytes: Sequence[Bytes48]) -> bool: """ - Given a list of blobs and an aggregated KZG proof, verify that they correspond to the provided commitments. - - Public method. - """ - aggregated_poly_commitment, evaluation_challenge, y = \ - verify_aggregate_kzg_proof_aggregation(blobs, commitments_bytes) - - aggregated_proof = bytes_to_kzg_proof(aggregated_proof_bytes) - - return verify_kzg_proof_impl(aggregated_poly_commitment, evaluation_challenge, y, aggregated_proof) -``` - -#### `verify_aggregate_kzg_proof_multi` - -```python -def verify_aggregate_kzg_proof_multi(list_blobs: Sequence[Sequence[Blob]], - list_commitments_bytes: Sequence[Sequence[Bytes48]], - list_aggregated_proof_bytes: Sequence[Bytes48]) -> bool: - """ - Given a list of blobs and an aggregated KZG proof, verify that they correspond to the provided commitments. + Given a list of blobs and blob KZG proofs, verify that they correspond to the provided commitments. Public method. """ - aggregated_poly_commitments, evaluation_challenges, ys = [], [], [] - for blobs, commitments_bytes in zip(list_blobs, list_commitments_bytes): - aggregated_poly_commitment, evaluation_challenge, y = \ - verify_aggregate_kzg_proof_aggregation(blobs, commitments_bytes) - aggregated_poly_commitments.append(aggregated_poly_commitment) + commitments, evaluation_challenges, ys, proofs = [], [], [], [] + for blob, commitment_bytes, proof_bytes in zip(blobs, commitments_bytes, proofs_bytes): + commitment = bytes_to_kzg_commitment(commitment_bytes) + commitments.append(commitment) + evaluation_challenge = compute_challenge(blob, commitment) evaluation_challenges.append(evaluation_challenge) - ys.append(y) + polynomial = blob_to_polynomial(blob) + ys.append(evaluate_polynomial_in_evaluation_form(polynomial, evaluation_challenge)) + proofs.append(bytes_to_kzg_proof(proof_bytes)) - list_aggregated_proof = [bytes_to_kzg_proof(proof) for proof in list_aggregated_proof_bytes] - - return verify_kzg_proof_multi(aggregated_poly_commitments, evaluation_challenges, ys, list_aggregated_proof) + return verify_kzg_proof_multi(commitments, evaluation_challenges, ys, proofs) ``` From 65d3c6aeb68ecd5b168929ccedc877bad197988e Mon Sep 17 00:00:00 2001 From: Jacek Sieka Date: Tue, 7 Feb 2023 10:55:51 +0100 Subject: [PATCH 103/158] Free the blobs This PR reintroduces and further decouples blocks and blobs in EIP-4844, so as to improve network and processing performance. Block and blob processing, for the purpose of gossip validation, are independent: they can both be propagated and gossip-validated in parallel - the decoupled design allows 4 important optimizations (or, if you are so inclined, removes 4 unnecessary pessimizations): * Blocks and blobs travel on independent meshes allowing for better parallelization and utilization of high-bandwidth peers * Re-broadcasting after validation can start earlier allowing more efficient use of upload bandwidth - blocks for example can be rebroadcast to peers while blobs are still being downloaded * bandwidth-reduction techniques such as per-peer deduplication are more efficient because of the smaller message size * gossip verification happens independently for blocks and blobs, allowing better sharing / use of CPU and I/O resources in clients With growing block sizes and additional blob data to stream, the network streaming time becomes a dominant factor in propagation times - on a 100mbit line, streaming 1mb to 8 peers takes ~1s - this process is repeated for each hop in both incoming and outgoing directions. This design in particular sends each blob on a separate subnet, thus maximising the potential for parallelisation and providing a natural path for growing the number of blobs per block should the network be judged to be able to handle it. Changes compared to the current design include: * `BlobsSidecar` is split into individual `BlobSidecar` containers - each container is signed individually by the proposer * the signature is used during gossip validation but later dropped. * KZG commitment verification is moved out of the gossip pipeline and instead done before fork choice addition, when both block and sidecars have arrived * clients may verify individual blob commitments earlier * more generally and similar to block verification, gossip propagation is performed solely based on trivial consistency checks and proposer signature verification * by-root blob requests are done per-blob, so as to retain the ability to fill in blobs one-by-one assuming clients generally receive blobs from gossip * by-range blob requests are done per-block, so as to simplify historical sync * range and root requests are limited to `128` entries for both blocks and blobs - practically, the current higher limit of `1024` for blocks does not get used and keeping the limits consistent simplifies implementation - with the merge, block sizes have grown significantly and clients generally fetch smaller chunks. --- specs/eip4844/beacon-chain.md | 5 +- specs/eip4844/fork-choice.md | 39 +++------ specs/eip4844/p2p-interface.md | 147 ++++++++++++++++++++------------- specs/eip4844/validator.md | 33 ++++---- 4 files changed, 124 insertions(+), 100 deletions(-) diff --git a/specs/eip4844/beacon-chain.md b/specs/eip4844/beacon-chain.md index f681ab951..145710a89 100644 --- a/specs/eip4844/beacon-chain.md +++ b/specs/eip4844/beacon-chain.md @@ -44,6 +44,7 @@ This upgrade adds blobs to the beacon chain as part of EIP-4844. This is an exte | Name | SSZ equivalent | Description | | - | - | - | | `VersionedHash` | `Bytes32` | | +| `BlobIndex` | `uint64` | | ## Constants @@ -52,7 +53,7 @@ This upgrade adds blobs to the beacon chain as part of EIP-4844. This is an exte | Name | Value | | - | - | | `BLOB_TX_TYPE` | `uint8(0x05)` | -| `VERSIONED_HASH_VERSION_KZG` | `Bytes1('0x01')` | +| `VERSIONED_HASH_VERSION_KZG` | `Bytes1('0x01')` | ## Preset @@ -249,7 +250,7 @@ def process_blob_kzg_commitments(state: BeaconState, body: BeaconBlockBody) -> N *Note*: The function `initialize_beacon_state_from_eth1` is modified for pure EIP-4844 testing only. -The `BeaconState` initialization is unchanged, except for the use of the updated `eip4844.BeaconBlockBody` type +The `BeaconState` initialization is unchanged, except for the use of the updated `eip4844.BeaconBlockBody` type when initializing the first body-root. ```python diff --git a/specs/eip4844/fork-choice.md b/specs/eip4844/fork-choice.md index 8dea28ded..3e909423e 100644 --- a/specs/eip4844/fork-choice.md +++ b/specs/eip4844/fork-choice.md @@ -7,9 +7,8 @@ - [Introduction](#introduction) - [Containers](#containers) - - [`BlobsSidecar`](#blobssidecar) - [Helpers](#helpers) - - [`validate_blobs_sidecar`](#validate_blobs_sidecar) + - [`validate_blob_sidecars`](#validate_blob_sidecars) - [`is_data_available`](#is_data_available) - [Updated fork-choice handlers](#updated-fork-choice-handlers) - [`on_block`](#on_block) @@ -23,54 +22,42 @@ This is the modification of the fork choice accompanying the EIP-4844 upgrade. ## Containers -### `BlobsSidecar` - -```python -class BlobsSidecar(Container): - beacon_block_root: Root - beacon_block_slot: Slot - blobs: List[Blob, MAX_BLOBS_PER_BLOCK] - kzg_aggregated_proof: KZGProof -``` - ## Helpers -#### `validate_blobs_sidecar` +#### `validate_blob_sidecars` ```python -def validate_blobs_sidecar(slot: Slot, +def validate_blob_sidecars(slot: Slot, beacon_block_root: Root, expected_kzg_commitments: Sequence[KZGCommitment], - blobs_sidecar: BlobsSidecar) -> None: + blob_sidecars: Sequence[BlobSidecar]) -> None: assert slot == blobs_sidecar.beacon_block_slot assert beacon_block_root == blobs_sidecar.beacon_block_root - blobs = blobs_sidecar.blobs - kzg_aggregated_proof = blobs_sidecar.kzg_aggregated_proof - assert len(expected_kzg_commitments) == len(blobs) - - assert verify_aggregate_kzg_proof(blobs, expected_kzg_commitments, kzg_aggregated_proof) + assert len(expected_kzg_commitments) == len(blob_sidecars) + # TODO validate commitments individually or aggregate first? + # assert verify_aggregate_kzg_proof(blobs, expected_kzg_commitments, kzg_aggregated_proof) ``` #### `is_data_available` The implementation of `is_data_available` will become more sophisticated during later scaling upgrades. -Initially, verification requires every verifying actor to retrieve the matching `BlobsSidecar`, -and validate the sidecar with `validate_blobs_sidecar`. +Initially, verification requires every verifying actor to retrieve all matching `BlobSidecar`s, +and validate the sidecar with `validate_blob_sidecars`. -The block MUST NOT be considered valid until a valid `BlobsSidecar` has been downloaded. Blocks that have been previously validated as available SHOULD be considered available even if the associated `BlobsSidecar` has subsequently been pruned. +The block MUST NOT be considered valid until all valid `BlobSidecar`s have been downloaded. Blocks that have been previously validated as available SHOULD be considered available even if the associated `BlobSidecar`s has subsequently been pruned. ```python def is_data_available(slot: Slot, beacon_block_root: Root, blob_kzg_commitments: Sequence[KZGCommitment]) -> bool: # `retrieve_blobs_sidecar` is implementation and context dependent, raises an exception if not available. # Note: the p2p network does not guarantee sidecar retrieval outside of `MIN_EPOCHS_FOR_BLOBS_SIDECARS_REQUESTS` - sidecar = retrieve_blobs_sidecar(slot, beacon_block_root) + sidecars = retrieve_blob_sidecars(slot, beacon_block_root) # For testing, `retrieve_blobs_sidecar` returns "TEST". # TODO: Remove it once we have a way to inject `BlobsSidecar` into tests. if isinstance(sidecar, str): return True - validate_blobs_sidecar(slot, beacon_block_root, blob_kzg_commitments, sidecar) + validate_blob_sidecars(slot, beacon_block_root, blob_kzg_commitments, sidecars) return True ``` @@ -102,7 +89,7 @@ def on_block(store: Store, signed_block: SignedBeaconBlock) -> None: # [New in EIP-4844] # Check if blob data is available # If not, this block MAY be queued and subsequently considered when blob data becomes available - assert is_data_available(block.slot, hash_tree_root(block), block.body.blob_kzg_commitments) + assert is_data_available(block.slot, hash_tree_root(block), block.body.blob_kzg_commitments) # Check the block is valid and compute the post-state state = pre_state.copy() diff --git a/specs/eip4844/p2p-interface.md b/specs/eip4844/p2p-interface.md index ae9380f7a..94821a82c 100644 --- a/specs/eip4844/p2p-interface.md +++ b/specs/eip4844/p2p-interface.md @@ -10,23 +10,22 @@ The specification of these changes continues in the same format as the network s - - [Configuration](#configuration) - - [Containers](#containers) - - [`SignedBeaconBlockAndBlobsSidecar`](#signedbeaconblockandblobssidecar) - - [The gossip domain: gossipsub](#the-gossip-domain-gossipsub) - - [Topics and messages](#topics-and-messages) - - [Global topics](#global-topics) - - [`beacon_block`](#beacon_block) - - [`beacon_block_and_blobs_sidecar`](#beacon_block_and_blobs_sidecar) - - [Transitioning the gossip](#transitioning-the-gossip) - - [The Req/Resp domain](#the-reqresp-domain) - - [Messages](#messages) - - [BeaconBlocksByRange v2](#beaconblocksbyrange-v2) - - [BeaconBlocksByRoot v2](#beaconblocksbyroot-v2) - - [BeaconBlockAndBlobsSidecarByRoot v1](#beaconblockandblobssidecarbyroot-v1) - - [BlobsSidecarsByRange v1](#blobssidecarsbyrange-v1) -- [Design decision rationale](#design-decision-rationale) - - [Why are blobs relayed as a sidecar, separate from beacon blocks?](#why-are-blobs-relayed-as-a-sidecar-separate-from-beacon-blocks) +- [Configuration](#configuration) +- [Containers](#containers) + - [`BlobSidecar`](#blobsidecar) + - [`SignedBlobSidecar`](#signedblobsidecar) +- [The gossip domain: gossipsub](#the-gossip-domain-gossipsub) + - [Topics and messages](#topics-and-messages) + - [Global topics](#global-topics) + - [`beacon_block`](#beacon_block) + - [`blob_sidecar_{index}`](#blob_sidecar_index) + - [Transitioning the gossip](#transitioning-the-gossip) +- [The Req/Resp domain](#the-reqresp-domain) + - [Messages](#messages) + - [BeaconBlocksByRange v2](#beaconblocksbyrange-v2) + - [BeaconBlocksByRoot v2](#beaconblocksbyroot-v2) + - [BlobSidecarsByRoot v1](#blobsidecarsbyroot-v1) + - [BlobsSidecarsByRange v1](#blobssidecarsbyrange-v1) @@ -35,17 +34,31 @@ The specification of these changes continues in the same format as the network s | Name | Value | Description | |------------------------------------------|-----------------------------------|---------------------------------------------------------------------| -| `MAX_REQUEST_BLOBS_SIDECARS` | `2**7` (= 128) | Maximum number of blobs sidecars in a single request | +| `MAX_REQUEST_BLOCKS_EIP4844` | `2**7` (= 128) | Maximum number of blocks in a single request | | `MIN_EPOCHS_FOR_BLOBS_SIDECARS_REQUESTS` | `2**12` (= 4096 epochs, ~18 days) | The minimum epoch range over which a node must serve blobs sidecars | ## Containers -### `SignedBeaconBlockAndBlobsSidecar` +### `BlobSidecar` ```python -class SignedBeaconBlockAndBlobsSidecar(Container): - beacon_block: SignedBeaconBlock - blobs_sidecar: BlobsSidecar +class BlobSidecar(Container): + block_root: Root + index: BlobIndex # Index of blob in block + slot: Slot + block_parent_root: Root # Proposer shuffling determinant + proposer_index: ValidatorIndex + blob: Blob + kzg_commitment: KZGCommitment + kzg_proof: KZGProof # Allows for quick verification of kzg_commitment +``` + +### `SignedBlobSidecar` + +```python +class SignedBlobSidecar(Container): + message: BlobSidecar + signature: Signature ``` ## The gossip domain: gossipsub @@ -65,34 +78,35 @@ The new topics along with the type of the `data` field of a gossipsub message ar | Name | Message Type | | - | - | -| `beacon_block_and_blobs_sidecar` | `SignedBeaconBlockAndBlobsSidecar` (new) | +| `blob_sidecar_{index}` | `SignedBlobSidecar` (new) | #### Global topics -EIP-4844 introduces a new global topic for beacon block and blobs-sidecars. +EIP-4844 introduces new global topics for blob sidecars. ##### `beacon_block` -This topic is deprecated and clients **MUST NOT** expose in their topic set to any peer. Implementers do not need to do -anything beyond simply skip implementation, and it is explicitly called out as it is a departure from previous versioning -of this topic. +The *type* of the payload of this topic changes to the (modified) `SignedBeaconBlock` found in EIP4844. -Refer to [the section below](#transitioning-the-gossip) for details on how to transition the gossip. +##### `blob_sidecar_{index}` -##### `beacon_block_and_blobs_sidecar` +This topic is used to propagate signed blob sidecars, one for each sidecar index. -This topic is used to propagate new signed and coupled beacon blocks and blobs sidecars to all nodes on the networks. +The following validations MUST pass before forwarding the `sidecar` on the network, assuming the alias `sidecar = signed_blob_sidecar.message`: -In addition to the gossip validations for the `beacon_block` topic from prior specifications, the following validations MUST pass before forwarding the `signed_beacon_block_and_blobs_sidecar` on the network. -Alias `signed_beacon_block = signed_beacon_block_and_blobs_sidecar.beacon_block`, `block = signed_beacon_block.message`, `execution_payload = block.body.execution_payload`. -- _[REJECT]_ The KZG commitments correspond to the versioned hashes in the transactions list - -- i.e. `verify_kzg_commitments_against_transactions(block.body.execution_payload.transactions, block.body.blob_kzg_commitments)` - -Alias `sidecar = signed_beacon_block_and_blobs_sidecar.blobs_sidecar`. -- _[IGNORE]_ the `sidecar.beacon_block_slot` is for the current slot (with a `MAXIMUM_GOSSIP_CLOCK_DISPARITY` allowance) - -- i.e. `sidecar.beacon_block_slot == block.slot`. -- _[REJECT]_ The KZG commitments in the block are valid against the provided blobs sidecar - -- i.e. `validate_blobs_sidecar(block.slot, hash_tree_root(block), block.body.blob_kzg_commitments, sidecar)` +- _[REJECT]_ The sidecar is for the correct topic -- + i.e. `sidecar.index` matches the topic `{index}`. +- _[IGNORE]_ The sidecar is not from a future slot (with a `MAXIMUM_GOSSIP_CLOCK_DISPARITY` allowance) +- _[IGNORE]_ The sidecar is from a slot greater than the latest finalized slot -- + i.e. validate that `sidecar.slot > compute_start_slot_at_epoch(state.finalized_checkpoint.epoch)` +- _[REJECT]_ The proposer signature, `signed_blob_sidecar.signature`, is valid with respect to the `sidecar.proposer_index` pubkey. +- _[IGNORE]_ The sidecar is the only sidecar with valid signature received for the tuple `(sidecar.slot, sidecar.proposer_index, sidecar.index)`. + -- Clients MUST discard blocks where multiple sidecars for the same proposer and index have been observed. +- _[REJECT]_ The sidecar is proposed by the expected `proposer_index` for the block's slot + in the context of the current shuffling (defined by `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. ### Transitioning the gossip @@ -121,6 +135,8 @@ Per `context = compute_fork_digest(fork_version, genesis_validators_root)`: | `CAPELLA_FORK_VERSION` | `capella.SignedBeaconBlock` | | `EIP4844_FORK_VERSION` | `eip4844.SignedBeaconBlock` | +No more than `MAX_REQUEST_BLOCKS_EIP4844` may be requested at a time. + #### BeaconBlocksByRoot v2 **Protocol ID:** `/eth2/beacon_chain/req/beacon_blocks_by_root/2/` @@ -139,15 +155,23 @@ Per `context = compute_fork_digest(fork_version, genesis_validators_root)`: | `BELLATRIX_FORK_VERSION` | `bellatrix.SignedBeaconBlock` | | `CAPELLA_FORK_VERSION` | `capella.SignedBeaconBlock` | -#### BeaconBlockAndBlobsSidecarByRoot v1 +No more than `MAX_REQUEST_BLOCKS_EIP4844` may be requested at a time. -**Protocol ID:** `/eth2/beacon_chain/req/beacon_block_and_blobs_sidecar_by_root/1/` +#### BlobSidecarsByRoot v1 + +**Protocol ID:** `/eth2/beacon_chain/req/blob_sidecars_by_root/1/` Request Content: +```python +class BlobIdentifier(Container): + block_root: Root + index: uint64 +``` + ``` ( - List[Root, MAX_REQUEST_BLOCKS] + List[BlobIdentifier, MAX_REQUEST_BLOCKS_EIP4844] ) ``` @@ -155,29 +179,32 @@ Response Content: ``` ( - List[SignedBeaconBlockAndBlobsSidecar, MAX_REQUEST_BLOCKS] + List[BlobSidecar, MAX_REQUEST_BLOCKS_EIP4844] ) ``` -Requests blocks by block root (= `hash_tree_root(SignedBeaconBlockAndBlobsSidecar.beacon_block.message)`). -The response is a list of `SignedBeaconBlockAndBlobsSidecar` whose length is less than or equal to the number of requests. +Requests sidecars by block root and index. +The response is a list of `BlobSidecar` whose length is less than or equal to the number of requests. It may be less in the case that the responding peer is missing blocks and sidecars. -No more than `MAX_REQUEST_BLOCKS` may be requested at a time. +The response is unsigned, i.e. `BlobSidecar`, as the signature of the beacon block proposer +may not be available beyond the initial distribution via gossip. -`BeaconBlockAndBlobsSidecarByRoot` is primarily used to recover recent blocks and sidecars (e.g. when receiving a block or attestation whose parent is unknown). +No more than `MAX_REQUEST_BLOCKS_EIP4844` may be requested at a time. + +`BlobSidecarsByRoot` is primarily used to recover recent blocks and sidecars (e.g. when receiving a block or attestation whose parent is unknown). The response MUST consist of zero or more `response_chunk`. -Each _successful_ `response_chunk` MUST contain a single `SignedBeaconBlockAndBlobsSidecar` payload. +Each _successful_ `response_chunk` MUST contain a single `BlobSidecar` payload. -Clients MUST support requesting blocks and sidecars since `minimum_request_epoch`, where `minimum_request_epoch = max(finalized_epoch, current_epoch - MIN_EPOCHS_FOR_BLOBS_SIDECARS_REQUESTS, EIP4844_FORK_EPOCH)`. If any root in the request content references a block earlier than `minimum_request_epoch`, peers SHOULD respond with error code `3: ResourceUnavailable`. +Clients MUST support requesting sidecars since `minimum_request_epoch`, where `minimum_request_epoch = max(finalized_epoch, current_epoch - MIN_EPOCHS_FOR_BLOBS_SIDECARS_REQUESTS, EIP4844_FORK_EPOCH)`. If any root in the request content references a block earlier than `minimum_request_epoch`, peers MAY respond with error code `3: ResourceUnavailable` or not include the blob in the response. -Clients MUST respond with at least one block and sidecar, if they have it. +Clients MUST respond with at least one sidecar, if they have it. Clients MAY limit the number of blocks and sidecars in the response. #### BlobsSidecarsByRange v1 -**Protocol ID:** `/eth2/beacon_chain/req/blobs_sidecars_by_range/1/` +**Protocol ID:** `/eth2/beacon_chain/req/blob_sidecars_by_range/1/` Request Content: ``` @@ -188,16 +215,22 @@ Request Content: ``` Response Content: + +```python +class BlobSidecars(Container): + block_root: Root + List[BlobSidecar, MAX_BLOBS_PER_BLOCK] + ``` ( - List[BlobsSidecar, MAX_REQUEST_BLOBS_SIDECARS] + List[BlobSidecars, MAX_REQUEST_BLOCKS_EIP4844] ) ``` -Requests blobs sidecars in the slot range `[start_slot, start_slot + count)`, +Requests blob sidecars in the slot range `[start_slot, start_slot + count)`, leading up to the current head block as selected by fork choice. -The response is unsigned, i.e. `BlobsSidecarsByRange`, as the signature of the beacon block proposer +The response is unsigned, i.e. `BlobSidecarsByRange`, as the signature of the beacon block proposer may not be available beyond the initial distribution via gossip. Before consuming the next response chunk, the response reader SHOULD verify the blobs sidecar is well-formatted and @@ -215,7 +248,7 @@ Clients MUST keep a record of signed blobs sidecars seen on the epoch range where `current_epoch` is defined by the current wall-clock time, and clients MUST support serving requests of blobs on this range. -Peers that are unable to reply to blobs sidecars requests within the `MIN_EPOCHS_FOR_BLOBS_SIDECARS_REQUESTS` +Peers that are unable to reply to blob sidecar requests within the `MIN_EPOCHS_FOR_BLOBS_SIDECARS_REQUESTS` epoch range SHOULD respond with error code `3: ResourceUnavailable`. Such peers that are unable to successfully reply to this range of requests MAY get descored or disconnected at any time. @@ -229,7 +262,7 @@ participating in the networking immediately, other peers MAY disconnect and/or temporarily ban such an un-synced or semi-synced client. Clients MUST respond with at least the first blobs sidecar that exists in the range, if they have it, -and no more than `MAX_REQUEST_BLOBS_SIDECARS` sidecars. +and no more than `MAX_REQUEST_BLOCKS_EIP4844` sidecars. The following blobs sidecars, where they exist, MUST be sent in consecutive order. diff --git a/specs/eip4844/validator.md b/specs/eip4844/validator.md index bfdd69370..619444351 100644 --- a/specs/eip4844/validator.md +++ b/specs/eip4844/validator.md @@ -79,27 +79,30 @@ def validate_blobs_and_kzg_commitments(execution_payload: ExecutionPayload, 3. If valid, set `block.body.blob_kzg_commitments = blob_kzg_commitments`. -#### Constructing the `SignedBeaconBlockAndBlobsSidecar` -To construct a `SignedBeaconBlockAndBlobsSidecar`, a `signed_beacon_block_and_blobs_sidecar` is defined with the necessary context for block and sidecar proposal. - -##### Block -Set `signed_beacon_block_and_blobs_sidecar.beacon_block = block` where `block` is obtained above. +#### Constructing the `SignedBlobSidecar` +To construct a `SignedBlobSidecar`, a `signed_blob_sidecar` is defined with the necessary context for block and sidecar proposal. ##### Sidecar -Coupled with block, the corresponding blobs are packaged into a sidecar object for distribution to the network. -Set `signed_beacon_block_and_blobs_sidecar.blobs_sidecar = sidecar` where `sidecar` is obtained from: +Coupled with block, the corresponding blobs are packaged into sidecar objects for distribution to the network. + +Each `sidecar` is obtained from: ```python -def get_blobs_sidecar(block: BeaconBlock, blobs: Sequence[Blob]) -> BlobsSidecar: - return BlobsSidecar( - beacon_block_root=hash_tree_root(block), - beacon_block_slot=block.slot, - blobs=blobs, - kzg_aggregated_proof=compute_aggregate_kzg_proof(blobs), - ) +def get_blob_sidecar(block: BeaconBlock, blobs: Sequence[Blob]) -> Sequence[BlobsSidecar]: + return [ + BlobsSidecar( + block_root=hash_tree_root(block), + index=idx + slot=block.slot, + block_parent_root=block.parent_root, + blob=blob, + kzg_commitment=block.body.blob_kzg_commitments[idx], + kzg_aggregated_proof=compute_kzg_proof(blob),) + for idx, blob in enumerate(blobs) + ] ``` -This `signed_beacon_block_and_blobs_sidecar` is then published to the global `beacon_block_and_blobs_sidecar` topic. +Each `sidecar` is then published to the global `blob_sidecar_{index}` topics according to its index. After publishing the peers on the network may request the sidecar through sync-requests, or a local user may be interested. The validator MUST hold on to sidecars for `MIN_EPOCHS_FOR_BLOBS_SIDECARS_REQUESTS` epochs and serve when capable, From 1e07685f74bf9d508d2acbb8c6b82aace53142d7 Mon Sep 17 00:00:00 2001 From: Jacek Sieka Date: Tue, 7 Feb 2023 11:14:59 +0100 Subject: [PATCH 104/158] doctoc --- specs/eip4844/validator.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/specs/eip4844/validator.md b/specs/eip4844/validator.md index 619444351..4ea7051e9 100644 --- a/specs/eip4844/validator.md +++ b/specs/eip4844/validator.md @@ -16,8 +16,7 @@ - [Block and sidecar proposal](#block-and-sidecar-proposal) - [Constructing the `BeaconBlockBody`](#constructing-the-beaconblockbody) - [Blob KZG commitments](#blob-kzg-commitments) - - [Constructing the `SignedBeaconBlockAndBlobsSidecar`](#constructing-the-signedbeaconblockandblobssidecar) - - [Block](#block) + - [Constructing the `SignedBlobSidecar`](#constructing-the-signedblobsidecar) - [Sidecar](#sidecar) From deb82e2f26e9a7cf3062bcce544e842fcfdb72b5 Mon Sep 17 00:00:00 2001 From: Jacek Sieka Date: Tue, 7 Feb 2023 11:23:18 +0100 Subject: [PATCH 105/158] fix member --- specs/eip4844/validator.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/specs/eip4844/validator.md b/specs/eip4844/validator.md index 4ea7051e9..a4ff8b8f2 100644 --- a/specs/eip4844/validator.md +++ b/specs/eip4844/validator.md @@ -96,7 +96,7 @@ def get_blob_sidecar(block: BeaconBlock, blobs: Sequence[Blob]) -> Sequence[Blob block_parent_root=block.parent_root, blob=blob, kzg_commitment=block.body.blob_kzg_commitments[idx], - kzg_aggregated_proof=compute_kzg_proof(blob),) + kzg_proof=compute_kzg_proof(blob),) for idx, blob in enumerate(blobs) ] ``` From 078e1cc871bae0c8810ead32dea8dcb8d3578a24 Mon Sep 17 00:00:00 2001 From: Paul Harris Date: Wed, 8 Feb 2023 09:22:28 +1000 Subject: [PATCH 106/158] fix references to eip4844 --- README.md | 2 +- specs/deneb/beacon-chain.md | 22 +++++++++---------- specs/deneb/fork-choice.md | 6 ++--- specs/deneb/fork.md | 10 ++++----- specs/deneb/p2p-interface.md | 10 ++++----- specs/deneb/polynomial-commitments.md | 6 ++--- specs/deneb/validator.md | 6 ++--- .../pyspec/eth2spec/test/helpers/sharding.py | 2 +- tests/generators/transition/main.py | 6 ++--- 9 files changed, 35 insertions(+), 35 deletions(-) diff --git a/README.md b/README.md index 466c15193..da893a53d 100644 --- a/README.md +++ b/README.md @@ -25,7 +25,7 @@ Features are researched and developed in parallel, and then consolidated into se | Code Name or Topic | Specs | Notes | | - | - | - | | Capella (tentative) |
  • Core
    • [Beacon chain changes](specs/capella/beacon-chain.md)
    • [Capella fork](specs/capella/fork.md)
  • Additions
    • [Light client sync protocol changes](specs/capella/light-client/sync-protocol.md) ([fork](specs/capella/light-client/fork.md), [full node](specs/capella/light-client/full-node.md), [networking](specs/capella/light-client/p2p-interface.md))
    • [Validator additions](specs/capella/validator.md)
    • [P2P networking](specs/capella/p2p-interface.md)
| -| Deneb (tentative) |
  • Core
    • [Beacon Chain changes](specs/deneb/beacon-chain.md)
    • [EIP-4844 fork](specs/deneb/fork.md)
    • [Polynomial commitments](specs/deneb/polynomial-commitments.md)
    • [Fork choice changes](specs/deneb/fork-choice.md)
  • Additions
    • [Light client sync protocol changes](specs/deneb/light-client/sync-protocol.md) ([fork](specs/deneb/light-client/fork.md), [full node](specs/deneb/light-client/full-node.md), [networking](specs/deneb/light-client/p2p-interface.md))
    • [Honest validator guide changes](specs/deneb/validator.md)
    • [P2P networking](specs/deneb/p2p-interface.md)
| +| Deneb (tentative) |
  • Core
    • [Beacon Chain changes](specs/deneb/beacon-chain.md)
    • [Deneb fork](specs/deneb/fork.md)
    • [Polynomial commitments](specs/deneb/polynomial-commitments.md)
    • [Fork choice changes](specs/deneb/fork-choice.md)
  • Additions
    • [Light client sync protocol changes](specs/deneb/light-client/sync-protocol.md) ([fork](specs/deneb/light-client/fork.md), [full node](specs/deneb/light-client/full-node.md), [networking](specs/deneb/light-client/p2p-interface.md))
    • [Honest validator guide changes](specs/deneb/validator.md)
    • [P2P networking](specs/deneb/p2p-interface.md)
| | Sharding (outdated) |
  • Core
    • [Beacon Chain changes](specs/sharding/beacon-chain.md)
  • Additions
    • [P2P networking](specs/sharding/p2p-interface.md)
| | Custody Game (outdated) |
  • Core
    • [Beacon Chain changes](specs/custody_game/beacon-chain.md)
  • Additions
    • [Honest validator guide changes](specs/custody_game/validator.md)
| Dependent on sharding | | Data Availability Sampling (outdated) |
  • Core
    • [Core types and functions](specs/das/das-core.md)
    • [Fork choice changes](specs/das/fork-choice.md)
  • Additions
    • [P2P Networking](specs/das/p2p-interface.md)
    • [Sampling process](specs/das/sampling.md)
|
  • Dependent on sharding
  • [Technical explainer](https://hackmd.io/@HWeNw8hNRimMm2m2GH56Cw/B1YJPGkpD)
| diff --git a/specs/deneb/beacon-chain.md b/specs/deneb/beacon-chain.md index 87ebf7a9e..e82fdfdcb 100644 --- a/specs/deneb/beacon-chain.md +++ b/specs/deneb/beacon-chain.md @@ -1,4 +1,4 @@ -# EIP-4844 -- The Beacon Chain +# Deneb -- The Beacon Chain **Notice**: This document is a work-in-progress for researchers and implementers. @@ -37,7 +37,7 @@ ## Introduction -This upgrade adds blobs to the beacon chain as part of EIP-4844. This is an extension of the Capella upgrade. +This upgrade adds blobs to the beacon chain as part of Deneb. This is an extension of the Capella upgrade. ## Custom types @@ -86,9 +86,9 @@ class BeaconBlockBody(Container): voluntary_exits: List[SignedVoluntaryExit, MAX_VOLUNTARY_EXITS] sync_aggregate: SyncAggregate # Execution - execution_payload: ExecutionPayload # [Modified in EIP-4844] + execution_payload: ExecutionPayload # [Modified in Deneb] bls_to_execution_changes: List[SignedBLSToExecutionChange, MAX_BLS_TO_EXECUTION_CHANGES] - blob_kzg_commitments: List[KZGCommitment, MAX_BLOBS_PER_BLOCK] # [New in EIP-4844] + blob_kzg_commitments: List[KZGCommitment, MAX_BLOBS_PER_BLOCK] # [New in Deneb] ``` #### `ExecutionPayload` @@ -108,7 +108,7 @@ class ExecutionPayload(Container): timestamp: uint64 extra_data: ByteList[MAX_EXTRA_DATA_BYTES] base_fee_per_gas: uint256 - excess_data_gas: uint256 # [New in EIP-4844] + excess_data_gas: uint256 # [New in Deneb] # Extra payload fields block_hash: Hash32 # Hash of execution block transactions: List[Transaction, MAX_TRANSACTIONS_PER_PAYLOAD] @@ -132,7 +132,7 @@ class ExecutionPayloadHeader(Container): timestamp: uint64 extra_data: ByteList[MAX_EXTRA_DATA_BYTES] base_fee_per_gas: uint256 - excess_data_gas: uint256 # [New in EIP-4844] + excess_data_gas: uint256 # [New in Deneb] # Extra payload fields block_hash: Hash32 # Hash of execution block transactions_root: Root @@ -152,7 +152,7 @@ def kzg_commitment_to_versioned_hash(kzg_commitment: KZGCommitment) -> Versioned #### `tx_peek_blob_versioned_hashes` -This function retrieves the hashes from the `SignedBlobTransaction` as defined in EIP-4844, using SSZ offsets. +This function retrieves the hashes from the `SignedBlobTransaction` as defined in Deneb, using SSZ offsets. Offsets are little-endian `uint32` values, as defined in the [SSZ specification](../../ssz/simple-serialize.md). See [the full details of `blob_versioned_hashes` offset calculation](https://gist.github.com/protolambda/23bd106b66f6d4bb854ce46044aa3ca3). @@ -192,12 +192,12 @@ def process_block(state: BeaconState, block: BeaconBlock) -> None: process_block_header(state, block) if is_execution_enabled(state, block.body): process_withdrawals(state, block.body.execution_payload) - process_execution_payload(state, block.body.execution_payload, EXECUTION_ENGINE) # [Modified in EIP-4844] + 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_sync_aggregate(state, block.body.sync_aggregate) - process_blob_kzg_commitments(state, block.body) # [New in EIP-4844] + process_blob_kzg_commitments(state, block.body) # [New in Deneb] ``` #### Execution payload @@ -230,7 +230,7 @@ def process_execution_payload(state: BeaconState, payload: ExecutionPayload, exe timestamp=payload.timestamp, extra_data=payload.extra_data, base_fee_per_gas=payload.base_fee_per_gas, - excess_data_gas=payload.excess_data_gas, # [New in EIP-4844] + excess_data_gas=payload.excess_data_gas, # [New in Deneb] block_hash=payload.block_hash, transactions_root=hash_tree_root(payload.transactions), withdrawals_root=hash_tree_root(payload.withdrawals), @@ -247,7 +247,7 @@ def process_blob_kzg_commitments(state: BeaconState, body: BeaconBlockBody) -> N ## Testing -*Note*: The function `initialize_beacon_state_from_eth1` is modified for pure EIP-4844 testing only. +*Note*: The function `initialize_beacon_state_from_eth1` is modified for pure Deneb testing only. The `BeaconState` initialization is unchanged, except for the use of the updated `deneb.BeaconBlockBody` type when initializing the first body-root. diff --git a/specs/deneb/fork-choice.md b/specs/deneb/fork-choice.md index 8dea28ded..97f345668 100644 --- a/specs/deneb/fork-choice.md +++ b/specs/deneb/fork-choice.md @@ -1,4 +1,4 @@ -# EIP-4844 -- Fork Choice +# Deneb -- Fork Choice ## Table of contents @@ -19,7 +19,7 @@ ## Introduction -This is the modification of the fork choice accompanying the EIP-4844 upgrade. +This is the modification of the fork choice accompanying the Deneb upgrade. ## Containers @@ -99,7 +99,7 @@ def on_block(store: Store, signed_block: SignedBeaconBlock) -> None: # Check block is a descendant of the finalized block at the checkpoint finalized slot assert get_ancestor(store, block.parent_root, finalized_slot) == store.finalized_checkpoint.root - # [New in EIP-4844] + # [New in Deneb] # Check if blob data is available # If not, this block MAY be queued and subsequently considered when blob data becomes available assert is_data_available(block.slot, hash_tree_root(block), block.body.blob_kzg_commitments) diff --git a/specs/deneb/fork.md b/specs/deneb/fork.md index 864e28888..1ace26c7f 100644 --- a/specs/deneb/fork.md +++ b/specs/deneb/fork.md @@ -1,4 +1,4 @@ -# EIP-4844 -- Fork Logic +# Deneb -- Fork Logic **Notice**: This document is a work-in-progress for researchers and implementers. @@ -12,7 +12,7 @@ - [Helper functions](#helper-functions) - [Misc](#misc) - [Modified `compute_fork_version`](#modified-compute_fork_version) -- [Fork to EIP-4844](#fork-to-eip-4844) +- [Fork to Deneb](#fork-to-deneb) - [Fork trigger](#fork-trigger) - [Upgrading the state](#upgrading-the-state) @@ -20,7 +20,7 @@ ## Introduction -This document describes the process of EIP-4844 upgrade. +This document describes the process of Deneb upgrade. ## Configuration @@ -53,7 +53,7 @@ def compute_fork_version(epoch: Epoch) -> Version: return GENESIS_FORK_VERSION ``` -## Fork to EIP-4844 +## Fork to Deneb ### Fork trigger @@ -82,7 +82,7 @@ def upgrade_to_deneb(pre: capella.BeaconState) -> BeaconState: timestamp=pre.latest_execution_payload_header.timestamp, extra_data=pre.latest_execution_payload_header.extra_data, base_fee_per_gas=pre.latest_execution_payload_header.base_fee_per_gas, - excess_data_gas=uint256(0), # [New in EIP-4844] + excess_data_gas=uint256(0), # [New in Deneb] block_hash=pre.latest_execution_payload_header.block_hash, transactions_root=pre.latest_execution_payload_header.transactions_root, withdrawals_root=pre.latest_execution_payload_header.withdrawals_root, diff --git a/specs/deneb/p2p-interface.md b/specs/deneb/p2p-interface.md index 852597b09..b1ff8b922 100644 --- a/specs/deneb/p2p-interface.md +++ b/specs/deneb/p2p-interface.md @@ -1,6 +1,6 @@ -# EIP-4844 -- Networking +# Deneb -- Networking -This document contains the consensus-layer networking specification for EIP-4844. +This document contains the consensus-layer networking specification for Deneb. The specification of these changes continues in the same format as the network specifications of previous upgrades, and assumes them as pre-requisite. @@ -50,7 +50,7 @@ class SignedBeaconBlockAndBlobsSidecar(Container): ## The gossip domain: gossipsub -Some gossip meshes are upgraded in the fork of EIP-4844 to support upgraded types. +Some gossip meshes are upgraded in the fork of Deneb to support upgraded types. ### Topics and messages @@ -69,7 +69,7 @@ The new topics along with the type of the `data` field of a gossipsub message ar #### Global topics -EIP-4844 introduces a new global topic for beacon block and blobs-sidecars. +Deneb introduces a new global topic for beacon block and blobs-sidecars. ##### `beacon_block` @@ -107,7 +107,7 @@ details on how to handle transitioning gossip topics for this upgrade. **Protocol ID:** `/eth2/beacon_chain/req/beacon_blocks_by_range/2/` -The EIP-4844 fork-digest is introduced to the `context` enum to specify EIP-4844 beacon block type. +The Deneb fork-digest is introduced to the `context` enum to specify Deneb beacon block type. Per `context = compute_fork_digest(fork_version, genesis_validators_root)`: diff --git a/specs/deneb/polynomial-commitments.md b/specs/deneb/polynomial-commitments.md index 9a0500d96..facf1dbc2 100644 --- a/specs/deneb/polynomial-commitments.md +++ b/specs/deneb/polynomial-commitments.md @@ -1,4 +1,4 @@ -# EIP-4844 -- Polynomial Commitments +# Deneb -- Polynomial Commitments ## Table of contents @@ -48,7 +48,7 @@ ## Introduction -This document specifies basic polynomial operations and KZG polynomial commitment operations as they are needed for the EIP-4844 specification. The implementations are not optimized for performance, but readability. All practical implementations should optimize the polynomial operations. +This document specifies basic polynomial operations and KZG polynomial commitment operations as they are needed for the Deneb specification. The implementations are not optimized for performance, but readability. All practical implementations should optimize the polynomial operations. Functions flagged as "Public method" MUST be provided by the underlying KZG library as public functions. All other functions are private functions used internally by the KZG library. @@ -364,7 +364,7 @@ def evaluate_polynomial_in_evaluation_form(polynomial: Polynomial, ### KZG -KZG core functions. These are also defined in EIP-4844 execution specs. +KZG core functions. These are also defined in Deneb execution specs. #### `blob_to_kzg_commitment` diff --git a/specs/deneb/validator.md b/specs/deneb/validator.md index bfdd69370..7c1b763d1 100644 --- a/specs/deneb/validator.md +++ b/specs/deneb/validator.md @@ -1,4 +1,4 @@ -# EIP-4844 -- Honest Validator +# Deneb -- Honest Validator **Notice**: This document is a work-in-progress for researchers and implementers. @@ -25,14 +25,14 @@ ## Introduction -This document represents the changes to be made in the code of an "honest validator" to implement EIP-4844. +This document represents the changes to be made in the code of an "honest validator" to implement Deneb. ## 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 EIP-4844](./beacon-chain.md) are requisite for this document and used throughout. +All terminology, constants, functions, and protocol mechanics defined in the updated [Beacon Chain doc of Deneb](./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 diff --git a/tests/core/pyspec/eth2spec/test/helpers/sharding.py b/tests/core/pyspec/eth2spec/test/helpers/sharding.py index 2ea8c94bc..fd60d5d3b 100644 --- a/tests/core/pyspec/eth2spec/test/helpers/sharding.py +++ b/tests/core/pyspec/eth2spec/test/helpers/sharding.py @@ -12,7 +12,7 @@ from eth2spec.utils.ssz.ssz_impl import serialize # -# Containers from EIP-4844 +# Containers from Deneb # MAX_CALLDATA_SIZE = 2**24 MAX_VERSIONED_HASHES_LIST_SIZE = 2**24 diff --git a/tests/generators/transition/main.py b/tests/generators/transition/main.py index a4eba90df..303f309c2 100644 --- a/tests/generators/transition/main.py +++ b/tests/generators/transition/main.py @@ -16,8 +16,8 @@ from eth2spec.test.altair.transition import ( test_slashing as test_altair_slashing, test_operations as test_altair_operations, ) -from eth2spec.test.eip4844.transition import ( - test_operations as test_eip4844_operations, +from eth2spec.test.deneb.transition import ( + test_operations as test_deneb_operations, ) @@ -46,7 +46,7 @@ if __name__ == "__main__": test_altair_leaking, test_altair_slashing, test_altair_operations, - test_eip4844_operations, + test_deneb_operations, ) for transition_test_module in all_tests: for pre_fork, post_fork in ALL_PRE_POST_FORKS: From f6b8827eca8b0b7a1ced3bddd6a721f8f31cfca1 Mon Sep 17 00:00:00 2001 From: protolambda Date: Mon, 23 Jan 2023 22:51:55 +0100 Subject: [PATCH 107/158] eip4844: move excess data gas field to end of execution payload for merkle proof path compat --- specs/deneb/beacon-chain.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/specs/deneb/beacon-chain.md b/specs/deneb/beacon-chain.md index e82fdfdcb..aba3b3df4 100644 --- a/specs/deneb/beacon-chain.md +++ b/specs/deneb/beacon-chain.md @@ -108,11 +108,11 @@ class ExecutionPayload(Container): timestamp: uint64 extra_data: ByteList[MAX_EXTRA_DATA_BYTES] base_fee_per_gas: uint256 - excess_data_gas: uint256 # [New in Deneb] # Extra payload fields block_hash: Hash32 # Hash of execution block transactions: List[Transaction, MAX_TRANSACTIONS_PER_PAYLOAD] withdrawals: List[Withdrawal, MAX_WITHDRAWALS_PER_PAYLOAD] + excess_data_gas: uint256 # [New in Deneb] ``` #### `ExecutionPayloadHeader` @@ -132,11 +132,11 @@ class ExecutionPayloadHeader(Container): timestamp: uint64 extra_data: ByteList[MAX_EXTRA_DATA_BYTES] base_fee_per_gas: uint256 - excess_data_gas: uint256 # [New in Deneb] # Extra payload fields block_hash: Hash32 # Hash of execution block transactions_root: Root withdrawals_root: Root + excess_data_gas: uint256 # [New in Deneb] ``` ## Helper functions @@ -230,10 +230,10 @@ def process_execution_payload(state: BeaconState, payload: ExecutionPayload, exe timestamp=payload.timestamp, extra_data=payload.extra_data, base_fee_per_gas=payload.base_fee_per_gas, - excess_data_gas=payload.excess_data_gas, # [New in Deneb] block_hash=payload.block_hash, transactions_root=hash_tree_root(payload.transactions), withdrawals_root=hash_tree_root(payload.withdrawals), + excess_data_gas=payload.excess_data_gas, # [New in Deneb] ) ``` From 832e96412ce8bc0d3d6f93e8048825db576bf562 Mon Sep 17 00:00:00 2001 From: protolambda Date: Tue, 24 Jan 2023 15:30:33 +0100 Subject: [PATCH 108/158] fix container fork check with remerkleable v0.1.26 --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index f87ed5a6c..45dd635d3 100644 --- a/setup.py +++ b/setup.py @@ -1169,7 +1169,7 @@ setup( "pycryptodome==3.15.0", "py_ecc==6.0.0", "milagro_bls_binding==1.9.0", - "remerkleable==0.1.25", + "remerkleable==0.1.26", "trie==2.0.2", RUAMEL_YAML_VERSION, "lru-dict==1.1.8", From 902a9c996784334a02891936417db88400c19c9b Mon Sep 17 00:00:00 2001 From: protolambda Date: Thu, 26 Jan 2023 11:57:47 +0100 Subject: [PATCH 109/158] remerkleable: fix container dict key hashing --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 45dd635d3..34a1083d6 100644 --- a/setup.py +++ b/setup.py @@ -1169,7 +1169,7 @@ setup( "pycryptodome==3.15.0", "py_ecc==6.0.0", "milagro_bls_binding==1.9.0", - "remerkleable==0.1.26", + "remerkleable==0.1.27", "trie==2.0.2", RUAMEL_YAML_VERSION, "lru-dict==1.1.8", From 7b5acbfd21d0b0fd7a46034f43362124e2f88899 Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Fri, 27 Jan 2023 11:00:37 +0100 Subject: [PATCH 110/158] Fix Capella fork test assertions --- specs/capella/beacon-chain.md | 2 +- tests/core/pyspec/eth2spec/test/helpers/capella/fork.py | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/specs/capella/beacon-chain.md b/specs/capella/beacon-chain.md index 1be41e7eb..1df617daa 100644 --- a/specs/capella/beacon-chain.md +++ b/specs/capella/beacon-chain.md @@ -242,7 +242,7 @@ class BeaconState(Container): current_sync_committee: SyncCommittee next_sync_committee: SyncCommittee # Execution - latest_execution_payload_header: ExecutionPayloadHeader + latest_execution_payload_header: ExecutionPayloadHeader # [Modified in Capella] # Withdrawals next_withdrawal_index: WithdrawalIndex # [New in Capella] next_withdrawal_validator_index: ValidatorIndex # [New in Capella] diff --git a/tests/core/pyspec/eth2spec/test/helpers/capella/fork.py b/tests/core/pyspec/eth2spec/test/helpers/capella/fork.py index 8e0aec9c6..bca8ddb8d 100644 --- a/tests/core/pyspec/eth2spec/test/helpers/capella/fork.py +++ b/tests/core/pyspec/eth2spec/test/helpers/capella/fork.py @@ -29,14 +29,12 @@ def run_fork_test(post_spec, pre_state): 'inactivity_scores', # Sync 'current_sync_committee', 'next_sync_committee', - # Execution - 'latest_execution_payload_header', ] for field in stable_fields: assert getattr(pre_state, field) == getattr(post_state, field) # Modified fields - modified_fields = ['fork'] + modified_fields = ['fork', 'latest_execution_payload_header'] for field in modified_fields: assert getattr(pre_state, field) != getattr(post_state, field) From ffc78e99282e65cc4da92c4dba0743be434d367b Mon Sep 17 00:00:00 2001 From: Jacek Sieka Date: Fri, 10 Feb 2023 10:40:43 +0100 Subject: [PATCH 111/158] fixes * separate constant for blob requests * pedantry --- specs/eip4844/p2p-interface.md | 62 +++++++++++++++++----------------- specs/eip4844/validator.md | 32 ++++++++++-------- 2 files changed, 48 insertions(+), 46 deletions(-) diff --git a/specs/eip4844/p2p-interface.md b/specs/eip4844/p2p-interface.md index 94821a82c..98365f823 100644 --- a/specs/eip4844/p2p-interface.md +++ b/specs/eip4844/p2p-interface.md @@ -10,22 +10,24 @@ The specification of these changes continues in the same format as the network s -- [Configuration](#configuration) -- [Containers](#containers) - - [`BlobSidecar`](#blobsidecar) - - [`SignedBlobSidecar`](#signedblobsidecar) -- [The gossip domain: gossipsub](#the-gossip-domain-gossipsub) - - [Topics and messages](#topics-and-messages) - - [Global topics](#global-topics) - - [`beacon_block`](#beacon_block) - - [`blob_sidecar_{index}`](#blob_sidecar_index) - - [Transitioning the gossip](#transitioning-the-gossip) -- [The Req/Resp domain](#the-reqresp-domain) - - [Messages](#messages) - - [BeaconBlocksByRange v2](#beaconblocksbyrange-v2) - - [BeaconBlocksByRoot v2](#beaconblocksbyroot-v2) - - [BlobSidecarsByRoot v1](#blobsidecarsbyroot-v1) - - [BlobsSidecarsByRange v1](#blobssidecarsbyrange-v1) + - [Configuration](#configuration) + - [Containers](#containers) + - [`BlobSidecar`](#blobsidecar) + - [`SignedBlobSidecar`](#signedblobsidecar) + - [The gossip domain: gossipsub](#the-gossip-domain-gossipsub) + - [Topics and messages](#topics-and-messages) + - [Global topics](#global-topics) + - [`beacon_block`](#beacon_block) + - [`blob_sidecar_{index}`](#blob_sidecar_index) + - [Transitioning the gossip](#transitioning-the-gossip) + - [The Req/Resp domain](#the-reqresp-domain) + - [Messages](#messages) + - [BeaconBlocksByRange v2](#beaconblocksbyrange-v2) + - [BeaconBlocksByRoot v2](#beaconblocksbyroot-v2) + - [BlobSidecarsByRoot v1](#blobsidecarsbyroot-v1) + - [BlobSidecarsByRange v1](#blobsidecarsbyrange-v1) +- [Design decision rationale](#design-decision-rationale) + - [Why are blobs relayed as a sidecar, separate from beacon blocks?](#why-are-blobs-relayed-as-a-sidecar-separate-from-beacon-blocks) @@ -35,6 +37,7 @@ The specification of these changes continues in the same format as the network s | Name | Value | Description | |------------------------------------------|-----------------------------------|---------------------------------------------------------------------| | `MAX_REQUEST_BLOCKS_EIP4844` | `2**7` (= 128) | Maximum number of blocks in a single request | +| `MAX_REQUEST_BLOB_SIDECARS` | `2**7` (= 128) | Maximum number of blob sidecars in a single request | | `MIN_EPOCHS_FOR_BLOBS_SIDECARS_REQUESTS` | `2**12` (= 4096 epochs, ~18 days) | The minimum epoch range over which a node must serve blobs sidecars | ## Containers @@ -68,7 +71,8 @@ Some gossip meshes are upgraded in the fork of EIP-4844 to support upgraded type ### Topics and messages Topics follow the same specification as in prior upgrades. -The `beacon_block` topic is deprecated and replaced by the `beacon_block_and_blobs_sidecar` topic. All other topics remain stable. + +The `beacon_block` topic is modified to also support EIP4844 blocks and new topics are added per table below. All other topics remain stable. The specification around the creation, validation, and dissemination of messages has not changed from the Capella document unless explicitly noted here. @@ -94,19 +98,14 @@ This topic is used to propagate signed blob sidecars, one for each sidecar index The following validations MUST pass before forwarding the `sidecar` on the network, assuming the alias `sidecar = signed_blob_sidecar.message`: -- _[REJECT]_ The sidecar is for the correct topic -- - i.e. `sidecar.index` matches the topic `{index}`. +- _[REJECT]_ The sidecar is for the correct topic -- i.e. `sidecar.index` matches the topic `{index}`. - _[IGNORE]_ The sidecar is not from a future slot (with a `MAXIMUM_GOSSIP_CLOCK_DISPARITY` allowance) -- _[IGNORE]_ The sidecar is from a slot greater than the latest finalized slot -- - i.e. validate that `sidecar.slot > compute_start_slot_at_epoch(state.finalized_checkpoint.epoch)` +- _[IGNORE]_ The sidecar is from a slot greater than the latest finalized slot -- i.e. validate that `sidecar.slot > compute_start_slot_at_epoch(state.finalized_checkpoint.epoch)` - _[REJECT]_ The proposer signature, `signed_blob_sidecar.signature`, is valid with respect to the `sidecar.proposer_index` pubkey. - _[IGNORE]_ The sidecar is the only sidecar with valid signature received for the tuple `(sidecar.slot, sidecar.proposer_index, sidecar.index)`. -- Clients MUST discard blocks where multiple sidecars for the same proposer and index have been observed. -- _[REJECT]_ The sidecar is proposed by the expected `proposer_index` for the block's slot - in the context of the current shuffling (defined by `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. +- _[REJECT]_ The sidecar is proposed by the expected `proposer_index` for the block's slot in the context of the current shuffling (defined by `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. ### Transitioning the gossip @@ -171,7 +170,7 @@ class BlobIdentifier(Container): ``` ( - List[BlobIdentifier, MAX_REQUEST_BLOCKS_EIP4844] + List[BlobIdentifier, MAX_REQUEST_BLOBS_SIDECARS * MAX_BLOBS_PER_BLOCK] ) ``` @@ -179,7 +178,7 @@ Response Content: ``` ( - List[BlobSidecar, MAX_REQUEST_BLOCKS_EIP4844] + List[BlobSidecar, MAX_REQUEST_BLOBS_SIDECARS * MAX_BLOBS_PER_BLOCK] ) ``` @@ -190,7 +189,7 @@ It may be less in the case that the responding peer is missing blocks and sideca The response is unsigned, i.e. `BlobSidecar`, as the signature of the beacon block proposer may not be available beyond the initial distribution via gossip. -No more than `MAX_REQUEST_BLOCKS_EIP4844` may be requested at a time. +No more than `MAX_REQUEST_BLOBS_SIDECARS * MAX_BLOBS_PER_BLOCK` may be requested at a time. `BlobSidecarsByRoot` is primarily used to recover recent blocks and sidecars (e.g. when receiving a block or attestation whose parent is unknown). @@ -202,7 +201,7 @@ Clients MUST support requesting sidecars since `minimum_request_epoch`, where `m Clients MUST respond with at least one sidecar, if they have it. Clients MAY limit the number of blocks and sidecars in the response. -#### BlobsSidecarsByRange v1 +#### BlobSidecarsByRange v1 **Protocol ID:** `/eth2/beacon_chain/req/blob_sidecars_by_range/1/` @@ -220,10 +219,11 @@ Response Content: class BlobSidecars(Container): block_root: Root List[BlobSidecar, MAX_BLOBS_PER_BLOCK] +``` ``` ( - List[BlobSidecars, MAX_REQUEST_BLOCKS_EIP4844] + List[BlobSidecars, MAX_REQUEST_BLOB_SIDECARS] ) ``` diff --git a/specs/eip4844/validator.md b/specs/eip4844/validator.md index a4ff8b8f2..8c3fc6faf 100644 --- a/specs/eip4844/validator.md +++ b/specs/eip4844/validator.md @@ -16,7 +16,7 @@ - [Block and sidecar proposal](#block-and-sidecar-proposal) - [Constructing the `BeaconBlockBody`](#constructing-the-beaconblockbody) - [Blob KZG commitments](#blob-kzg-commitments) - - [Constructing the `SignedBlobSidecar`](#constructing-the-signedblobsidecar) + - [Constructing the `SignedBlobSidecar`s](#constructing-the-signedblobsidecars) - [Sidecar](#sidecar) @@ -78,27 +78,29 @@ def validate_blobs_and_kzg_commitments(execution_payload: ExecutionPayload, 3. If valid, set `block.body.blob_kzg_commitments = blob_kzg_commitments`. -#### Constructing the `SignedBlobSidecar` +#### Constructing the `SignedBlobSidecar`s + To construct a `SignedBlobSidecar`, a `signed_blob_sidecar` is defined with the necessary context for block and sidecar proposal. ##### Sidecar -Coupled with block, the corresponding blobs are packaged into sidecar objects for distribution to the network. +Blobs associated with a block are packaged into sidecar objects for distribution to the network. Each `sidecar` is obtained from: ```python -def get_blob_sidecar(block: BeaconBlock, blobs: Sequence[Blob]) -> Sequence[BlobsSidecar]: - return [ - BlobsSidecar( - block_root=hash_tree_root(block), - index=idx - slot=block.slot, - block_parent_root=block.parent_root, - blob=blob, - kzg_commitment=block.body.blob_kzg_commitments[idx], - kzg_proof=compute_kzg_proof(blob),) - for idx, blob in enumerate(blobs) - ] +def get_blob_sidecars(block: BeaconBlock, blobs: Sequence[Blob]) -> Sequence[BlobsSidecar]: + return [ + BlobsSidecar( + block_root=hash_tree_root(block), + index=index, + slot=block.slot, + block_parent_root=block.parent_root, + blob=blob, + kzg_commitment=block.body.blob_kzg_commitments[idx], + kzg_proof=compute_kzg_proof(blob), + ) + for index, blob in enumerate(blobs) + ] ``` Each `sidecar` is then published to the global `blob_sidecar_{index}` topics according to its index. From 8bc19d99aea32897be7eace506b1b344b33b0de1 Mon Sep 17 00:00:00 2001 From: Jacek Sieka Date: Fri, 10 Feb 2023 11:16:51 +0100 Subject: [PATCH 112/158] fixes * expand sidecar gossip conditions * editing * add spec text for `BlobSidecar` signatures --- specs/deneb/fork-choice.md | 2 +- specs/deneb/p2p-interface.md | 49 +++++++++++++++++++----------------- specs/deneb/validator.md | 19 +++++++++++--- 3 files changed, 43 insertions(+), 27 deletions(-) diff --git a/specs/deneb/fork-choice.md b/specs/deneb/fork-choice.md index 89eac2202..ea235c055 100644 --- a/specs/deneb/fork-choice.md +++ b/specs/deneb/fork-choice.md @@ -53,7 +53,7 @@ def is_data_available(slot: Slot, beacon_block_root: Root, blob_kzg_commitments: sidecars = retrieve_blob_sidecars(slot, beacon_block_root) # For testing, `retrieve_blobs_sidecar` returns "TEST". - # TODO: Remove it once we have a way to inject `BlobsSidecar` into tests. + # TODO: Remove it once we have a way to inject `BlobSidecar` into tests. if isinstance(sidecar, str): return True diff --git a/specs/deneb/p2p-interface.md b/specs/deneb/p2p-interface.md index f02365795..41af2f9f1 100644 --- a/specs/deneb/p2p-interface.md +++ b/specs/deneb/p2p-interface.md @@ -10,22 +10,22 @@ The specification of these changes continues in the same format as the network s - - [Configuration](#configuration) - - [Containers](#containers) - - [`BlobSidecar`](#blobsidecar) - - [`SignedBlobSidecar`](#signedblobsidecar) - - [The gossip domain: gossipsub](#the-gossip-domain-gossipsub) - - [Topics and messages](#topics-and-messages) - - [Global topics](#global-topics) - - [`beacon_block`](#beacon_block) - - [`blob_sidecar_{index}`](#blob_sidecar_index) - - [Transitioning the gossip](#transitioning-the-gossip) - - [The Req/Resp domain](#the-reqresp-domain) - - [Messages](#messages) - - [BeaconBlocksByRange v2](#beaconblocksbyrange-v2) - - [BeaconBlocksByRoot v2](#beaconblocksbyroot-v2) - - [BlobSidecarsByRoot v1](#blobsidecarsbyroot-v1) - - [BlobSidecarsByRange v1](#blobsidecarsbyrange-v1) +- [Configuration](#configuration) +- [Containers](#containers) + - [`BlobSidecar`](#blobsidecar) + - [`SignedBlobSidecar`](#signedblobsidecar) +- [The gossip domain: gossipsub](#the-gossip-domain-gossipsub) + - [Topics and messages](#topics-and-messages) + - [Global topics](#global-topics) + - [`beacon_block`](#beacon_block) + - [`blob_sidecar_{index}`](#blob_sidecar_index) + - [Transitioning the gossip](#transitioning-the-gossip) +- [The Req/Resp domain](#the-reqresp-domain) + - [Messages](#messages) + - [BeaconBlocksByRange v2](#beaconblocksbyrange-v2) + - [BeaconBlocksByRoot v2](#beaconblocksbyroot-v2) + - [BlobSidecarsByRoot v1](#blobsidecarsbyroot-v1) + - [BlobSidecarsByRange v1](#blobsidecarsbyrange-v1) - [Design decision rationale](#design-decision-rationale) - [Why are blobs relayed as a sidecar, separate from beacon blocks?](#why-are-blobs-relayed-as-a-sidecar-separate-from-beacon-blocks) @@ -99,8 +99,9 @@ This topic is used to propagate signed blob sidecars, one for each sidecar index The following validations MUST pass before forwarding the `sidecar` on the network, assuming the alias `sidecar = signed_blob_sidecar.message`: - _[REJECT]_ The sidecar is for the correct topic -- i.e. `sidecar.index` matches the topic `{index}`. -- _[IGNORE]_ The sidecar is not from a future slot (with a `MAXIMUM_GOSSIP_CLOCK_DISPARITY` allowance) +- _[IGNORE]_ The sidecar is not from a future slot (with a `MAXIMUM_GOSSIP_CLOCK_DISPARITY` allowance) -- i.e. validate that `sidecar.slot <= current_slot` (a client MAY queue future blocks for processing at the appropriate slot). - _[IGNORE]_ The sidecar is from a slot greater than the latest finalized slot -- i.e. validate that `sidecar.slot > compute_start_slot_at_epoch(state.finalized_checkpoint.epoch)` +- _[IGNORE]_ The blob's block's parent defined by `sidecar.block_parent_root`) has been seen (via both gossip and non-gossip sources) (a client MAY queue blocks for processing once the parent block is retrieved). - _[REJECT]_ The proposer signature, `signed_blob_sidecar.signature`, is valid with respect to the `sidecar.proposer_index` pubkey. - _[IGNORE]_ The sidecar is the only sidecar with valid signature received for the tuple `(sidecar.slot, sidecar.proposer_index, sidecar.index)`. -- Clients MUST discard blocks where multiple sidecars for the same proposer and index have been observed. @@ -140,9 +141,6 @@ No more than `MAX_REQUEST_BLOCKS_DENEB` may be requested at a time. **Protocol ID:** `/eth2/beacon_chain/req/beacon_blocks_by_root/2/` -After `DENEB_FORK_EPOCH`, `BeaconBlocksByRootV2` is replaced by `BeaconBlockAndBlobsSidecarByRootV1`. -Clients MUST support requesting blocks by root for pre-fork-epoch blocks. - Per `context = compute_fork_digest(fork_version, genesis_validators_root)`: [1]: # (eth2spec: skip) @@ -153,6 +151,7 @@ Per `context = compute_fork_digest(fork_version, genesis_validators_root)`: | `ALTAIR_FORK_VERSION` | `altair.SignedBeaconBlock` | | `BELLATRIX_FORK_VERSION` | `bellatrix.SignedBeaconBlock` | | `CAPELLA_FORK_VERSION` | `capella.SignedBeaconBlock` | +| `DENEB_FORK_VERSION` | `deneb.SignedBeaconBlock` | No more than `MAX_REQUEST_BLOCKS_DENEB` may be requested at a time. @@ -160,6 +159,8 @@ No more than `MAX_REQUEST_BLOCKS_DENEB` may be requested at a time. **Protocol ID:** `/eth2/beacon_chain/req/blob_sidecars_by_root/1/` +New in deneb. + Request Content: ```python @@ -191,7 +192,7 @@ may not be available beyond the initial distribution via gossip. No more than `MAX_REQUEST_BLOBS_SIDECARS * MAX_BLOBS_PER_BLOCK` may be requested at a time. -`BlobSidecarsByRoot` is primarily used to recover recent blocks and sidecars (e.g. when receiving a block or attestation whose parent is unknown). +`BlobSidecarsByRoot` is primarily used to recover recent blobs (e.g. when receiving a block with a transaction whose corresponding blob is missing). The response MUST consist of zero or more `response_chunk`. Each _successful_ `response_chunk` MUST contain a single `BlobSidecar` payload. @@ -205,6 +206,8 @@ Clients MAY limit the number of blocks and sidecars in the response. **Protocol ID:** `/eth2/beacon_chain/req/blob_sidecars_by_range/1/` +New in deneb. + Request Content: ``` ( @@ -282,9 +285,9 @@ Clients MUST respond with blobs sidecars that are consistent from a single chain After the initial blobs sidecar, clients MAY stop in the process of responding if their fork choice changes the view of the chain in the context of the request. -# Design decision rationale +## Design decision rationale -## Why are blobs relayed as a sidecar, separate from beacon blocks? +### Why are blobs relayed as a sidecar, separate from beacon blocks? This "sidecar" design provides forward compatibility for further data increases by black-boxing `is_data_available()`: with full sharding `is_data_available()` can be replaced by data-availability-sampling (DAS) diff --git a/specs/deneb/validator.md b/specs/deneb/validator.md index 1b6995ad8..bd05c31d2 100644 --- a/specs/deneb/validator.md +++ b/specs/deneb/validator.md @@ -88,9 +88,9 @@ Blobs associated with a block are packaged into sidecar objects for distribution Each `sidecar` is obtained from: ```python -def get_blob_sidecars(block: BeaconBlock, blobs: Sequence[Blob]) -> Sequence[BlobsSidecar]: +def get_blob_sidecars(block: BeaconBlock, blobs: Sequence[Blob]) -> Sequence[BlobSidecar]: return [ - BlobsSidecar( + BlobSidecar( block_root=hash_tree_root(block), index=index, slot=block.slot, @@ -101,11 +101,24 @@ def get_blob_sidecars(block: BeaconBlock, blobs: Sequence[Blob]) -> Sequence[Blo ) for index, blob in enumerate(blobs) ] + ``` -Each `sidecar` is then published to the global `blob_sidecar_{index}` topics according to its index. +Then `signed_sidecar = SignedBlobSidecar(message=sidecar, signature=signature)` is constructed and to the global `blob_sidecar_{index}` topics according to its index. + +`signature` is obtained from: + +```python +def get_blob_sidecar_signature(state: BeaconState, + sidecar: BlobSidecar, + privkey: int) -> BLSSignature: + domain = get_domain(state, DOMAIN_BEACON_PROPOSER, compute_epoch_at_slot(sidecar.slot)) + signing_root = compute_signing_root(sidecar, domain) + return bls.Sign(privkey, signing_root) +``` After publishing the peers on the network may request the sidecar through sync-requests, or a local user may be interested. + The validator MUST hold on to sidecars for `MIN_EPOCHS_FOR_BLOBS_SIDECARS_REQUESTS` epochs and serve when capable, to ensure the data-availability of these blobs throughout the network. From 86962b94377f549989ff7273fec8dc7faee70627 Mon Sep 17 00:00:00 2001 From: Potuz Date: Fri, 10 Feb 2023 11:43:38 -0300 Subject: [PATCH 113/158] Simplify commitee weight computation --- specs/phase0/fork-choice.md | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/specs/phase0/fork-choice.md b/specs/phase0/fork-choice.md index e535184af..f2ccc24b9 100644 --- a/specs/phase0/fork-choice.md +++ b/specs/phase0/fork-choice.md @@ -194,10 +194,7 @@ def get_latest_attesting_balance(store: Store, root: Root) -> Gwei: proposer_score = Gwei(0) # Boost is applied if ``root`` is an ancestor of ``proposer_boost_root`` if get_ancestor(store, store.proposer_boost_root, store.blocks[root].slot) == root: - num_validators = len(get_active_validator_indices(state, get_current_epoch(state))) - avg_balance = get_total_active_balance(state) // num_validators - committee_size = num_validators // SLOTS_PER_EPOCH - committee_weight = committee_size * avg_balance + committee_weight = get_total_active_balance(state) // SLOTS_PER_EPOCH proposer_score = (committee_weight * PROPOSER_SCORE_BOOST) // 100 return attestation_score + proposer_score From fc10714f42888a26a52f17a0ba7dabfdc83811cd Mon Sep 17 00:00:00 2001 From: Dankrad Feist Date: Mon, 13 Feb 2023 14:32:50 +0000 Subject: [PATCH 114/158] Call compute_challenge with polynomial as argument --- specs/eip4844/polynomial-commitments.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/specs/eip4844/polynomial-commitments.md b/specs/eip4844/polynomial-commitments.md index 63217c0bc..0e2c671da 100644 --- a/specs/eip4844/polynomial-commitments.md +++ b/specs/eip4844/polynomial-commitments.md @@ -475,8 +475,8 @@ def compute_blob_kzg_proof(blob: Blob) -> KZGProof: Public method. """ commitment = blob_to_kzg_commitment(blob) - evaluation_challenge = compute_challenge(blob, commitment) polynomial = blob_to_polynomial(blob) + evaluation_challenge = compute_challenge(polynomial, commitment) return compute_kzg_proof_impl(polynomial, evaluation_challenge) ``` @@ -493,8 +493,8 @@ def verify_blob_kzg_proof(blob: Blob, """ commitment = bytes_to_kzg_commitment(commitment_bytes) - evaluation_challenge = compute_challenge(blob, commitment) polynomial = blob_to_polynomial(blob) + evaluation_challenge = compute_challenge(polynomial, commitment) # Evaluate polynomial at `evaluation_challenge` (evaluation function checks for div-by-zero) y = evaluate_polynomial_in_evaluation_form(polynomial, evaluation_challenge) @@ -520,9 +520,9 @@ def verify_blob_kzg_proof_multi(blobs: Sequence[Blob], for blob, commitment_bytes, proof_bytes in zip(blobs, commitments_bytes, proofs_bytes): commitment = bytes_to_kzg_commitment(commitment_bytes) commitments.append(commitment) - evaluation_challenge = compute_challenge(blob, commitment) - evaluation_challenges.append(evaluation_challenge) polynomial = blob_to_polynomial(blob) + evaluation_challenge = compute_challenge(polynomial, commitment) + evaluation_challenges.append(evaluation_challenge) ys.append(evaluate_polynomial_in_evaluation_form(polynomial, evaluation_challenge)) proofs.append(bytes_to_kzg_proof(proof_bytes)) From 7b642a2884189e821254b596db29ab0cc4c892ec Mon Sep 17 00:00:00 2001 From: Dankrad Feist Date: Mon, 13 Feb 2023 14:57:04 +0000 Subject: [PATCH 115/158] compute_challenge takes blobs + linter --- specs/eip4844/fork-choice.md | 5 +++-- specs/eip4844/polynomial-commitments.md | 11 +++++------ specs/eip4844/validator.md | 3 ++- 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/specs/eip4844/fork-choice.md b/specs/eip4844/fork-choice.md index 8dea28ded..962987907 100644 --- a/specs/eip4844/fork-choice.md +++ b/specs/eip4844/fork-choice.md @@ -45,10 +45,11 @@ def validate_blobs_sidecar(slot: Slot, assert slot == blobs_sidecar.beacon_block_slot assert beacon_block_root == blobs_sidecar.beacon_block_root blobs = blobs_sidecar.blobs - kzg_aggregated_proof = blobs_sidecar.kzg_aggregated_proof + # kzg_aggregated_proof = blobs_sidecar.kzg_aggregated_proof assert len(expected_kzg_commitments) == len(blobs) - assert verify_aggregate_kzg_proof(blobs, expected_kzg_commitments, kzg_aggregated_proof) + # Disabled because not available before switch to single blob sidecars + # assert verify_aggregate_kzg_proof(blobs, expected_kzg_commitments, kzg_aggregated_proof) ``` #### `is_data_available` diff --git a/specs/eip4844/polynomial-commitments.md b/specs/eip4844/polynomial-commitments.md index 0e2c671da..ac99313ce 100644 --- a/specs/eip4844/polynomial-commitments.md +++ b/specs/eip4844/polynomial-commitments.md @@ -226,7 +226,7 @@ def blob_to_polynomial(blob: Blob) -> Polynomial: #### `compute_challenge` ```python -def compute_challenge(polynomial: Polynomial, +def compute_challenge(blob: Blob, commitment: KZGCommitment) -> BLSFieldElement: """ Return the Fiat-Shamir challenges required by the rest of the protocol. @@ -242,8 +242,7 @@ def compute_challenge(polynomial: Polynomial, data = FIAT_SHAMIR_PROTOCOL_DOMAIN + degree_poly + num_polynomials # Append each polynomial which is composed by field elements - for field_element in polynomial: - data += int.to_bytes(field_element, BYTES_PER_FIELD_ELEMENT, ENDIANNESS) + data += blob # Append serialized G1 points data += commitment @@ -476,7 +475,7 @@ def compute_blob_kzg_proof(blob: Blob) -> KZGProof: """ commitment = blob_to_kzg_commitment(blob) polynomial = blob_to_polynomial(blob) - evaluation_challenge = compute_challenge(polynomial, commitment) + evaluation_challenge = compute_challenge(blob, commitment) return compute_kzg_proof_impl(polynomial, evaluation_challenge) ``` @@ -494,7 +493,7 @@ def verify_blob_kzg_proof(blob: Blob, commitment = bytes_to_kzg_commitment(commitment_bytes) polynomial = blob_to_polynomial(blob) - evaluation_challenge = compute_challenge(polynomial, commitment) + evaluation_challenge = compute_challenge(blob, commitment) # Evaluate polynomial at `evaluation_challenge` (evaluation function checks for div-by-zero) y = evaluate_polynomial_in_evaluation_form(polynomial, evaluation_challenge) @@ -521,7 +520,7 @@ def verify_blob_kzg_proof_multi(blobs: Sequence[Blob], commitment = bytes_to_kzg_commitment(commitment_bytes) commitments.append(commitment) polynomial = blob_to_polynomial(blob) - evaluation_challenge = compute_challenge(polynomial, commitment) + evaluation_challenge = compute_challenge(blob, commitment) evaluation_challenges.append(evaluation_challenge) ys.append(evaluate_polynomial_in_evaluation_form(polynomial, evaluation_challenge)) proofs.append(bytes_to_kzg_proof(proof_bytes)) diff --git a/specs/eip4844/validator.md b/specs/eip4844/validator.md index bfdd69370..413e315fc 100644 --- a/specs/eip4844/validator.md +++ b/specs/eip4844/validator.md @@ -95,7 +95,8 @@ def get_blobs_sidecar(block: BeaconBlock, blobs: Sequence[Blob]) -> BlobsSidecar beacon_block_root=hash_tree_root(block), beacon_block_slot=block.slot, blobs=blobs, - kzg_aggregated_proof=compute_aggregate_kzg_proof(blobs), + # Disabled because not available before switch to single blob sidecars + kzg_aggregated_proof=KZGProof(), # compute_aggregate_kzg_proof(blobs), ) ``` From 901303f14fbb2153393fd2b5d7b88f160ba569ac Mon Sep 17 00:00:00 2001 From: Paul Harris Date: Mon, 23 Jan 2023 15:08:34 +0100 Subject: [PATCH 116/158] Replaced EIP4844 references with Deneb Fixes #3207 --- .circleci/config.yml | 6 +- .github/workflows/run-tests.yml | 2 +- .gitignore | 2 +- Makefile | 12 +- README.md | 2 +- configs/mainnet.yaml | 6 +- configs/minimal.yaml | 6 +- presets/mainnet/{eip4844.yaml => deneb.yaml} | 0 presets/minimal/{eip4844.yaml => deneb.yaml} | 0 setup.py | 40 +++--- specs/{eip4844 => deneb}/beacon-chain.md | 6 +- specs/{eip4844 => deneb}/fork-choice.md | 0 specs/{eip4844 => deneb}/fork.md | 20 +-- specs/{eip4844 => deneb}/light-client/fork.md | 38 ++--- .../light-client/full-node.md | 8 +- .../light-client/p2p-interface.md | 60 ++++---- .../light-client/sync-protocol.md | 14 +- specs/{eip4844 => deneb}/p2p-interface.md | 8 +- .../polynomial-commitments.md | 0 specs/{eip4844 => deneb}/validator.md | 0 .../test/altair/light_client/test_sync.py | 52 +++---- tests/core/pyspec/eth2spec/test/context.py | 10 +- .../test/{eip4844 => deneb}/__init__.py | 0 .../test/{eip4844 => deneb}/fork/__init__.py | 0 .../fork/test_deneb_fork_basic.py} | 48 +++---- .../test/deneb/fork/test_deneb_fork_random.py | 84 +++++++++++ .../{eip4844 => deneb}/random/__init__.py | 0 .../{eip4844 => deneb}/random/test_random.py | 130 +++++++++--------- .../{eip4844 => deneb}/sanity/__init__.py | 0 .../{eip4844 => deneb}/sanity/test_blocks.py | 6 +- .../{eip4844 => deneb}/unittests/__init__.py | 0 .../unittests/fork_choice/__init__.py | 0 .../test_validate_blobs_sidecar.py | 10 +- .../polynomial_commitments/__init__.py | 0 .../test_polynomial_commitments.py | 8 +- .../{eip4844 => deneb}/unittests/test_kzg.py | 4 +- .../unittests/test_offset.py | 4 +- .../eip4844/fork/test_eip4844_fork_random.py | 84 ----------- .../pyspec/eth2spec/test/helpers/constants.py | 10 +- .../helpers/{eip4844 => deneb}/__init__.py | 0 .../test/helpers/{eip4844 => deneb}/fork.py | 10 +- .../test/helpers/execution_payload.py | 6 +- .../eth2spec/test/helpers/fork_transition.py | 10 +- .../pyspec/eth2spec/test/helpers/forks.py | 10 +- .../pyspec/eth2spec/test/helpers/genesis.py | 6 +- .../test/utils/randomized_block_tests.py | 4 +- tests/generators/epoch_processing/main.py | 6 +- tests/generators/finality/main.py | 6 +- tests/generators/fork_choice/main.py | 6 +- tests/generators/forks/main.py | 8 +- tests/generators/genesis/main.py | 6 +- tests/generators/light_client/main.py | 6 +- tests/generators/operations/main.py | 6 +- tests/generators/random/Makefile | 4 +- tests/generators/random/generate.py | 14 +- tests/generators/random/main.py | 6 +- tests/generators/rewards/main.py | 6 +- tests/generators/sanity/main.py | 8 +- tests/generators/sync/main.py | 6 +- 59 files changed, 407 insertions(+), 407 deletions(-) rename presets/mainnet/{eip4844.yaml => deneb.yaml} (100%) rename presets/minimal/{eip4844.yaml => deneb.yaml} (100%) rename specs/{eip4844 => deneb}/beacon-chain.md (98%) rename specs/{eip4844 => deneb}/fork-choice.md (100%) rename specs/{eip4844 => deneb}/fork.md (86%) rename specs/{eip4844 => deneb}/light-client/fork.md (62%) rename specs/{eip4844 => deneb}/light-client/full-node.md (94%) rename specs/{eip4844 => deneb}/light-client/p2p-interface.md (65%) rename specs/{eip4844 => deneb}/light-client/sync-protocol.md (84%) rename specs/{eip4844 => deneb}/p2p-interface.md (95%) rename specs/{eip4844 => deneb}/polynomial-commitments.md (100%) rename specs/{eip4844 => deneb}/validator.md (100%) rename tests/core/pyspec/eth2spec/test/{eip4844 => deneb}/__init__.py (100%) rename tests/core/pyspec/eth2spec/test/{eip4844 => deneb}/fork/__init__.py (100%) rename tests/core/pyspec/eth2spec/test/{eip4844/fork/test_eip4844_fork_basic.py => deneb/fork/test_deneb_fork_basic.py} (55%) create mode 100644 tests/core/pyspec/eth2spec/test/deneb/fork/test_deneb_fork_random.py rename tests/core/pyspec/eth2spec/test/{eip4844 => deneb}/random/__init__.py (100%) rename tests/core/pyspec/eth2spec/test/{eip4844 => deneb}/random/test_random.py (63%) rename tests/core/pyspec/eth2spec/test/{eip4844 => deneb}/sanity/__init__.py (100%) rename tests/core/pyspec/eth2spec/test/{eip4844 => deneb}/sanity/test_blocks.py (95%) rename tests/core/pyspec/eth2spec/test/{eip4844 => deneb}/unittests/__init__.py (100%) rename tests/core/pyspec/eth2spec/test/{eip4844 => deneb}/unittests/fork_choice/__init__.py (100%) rename tests/core/pyspec/eth2spec/test/{eip4844 => deneb}/unittests/fork_choice/test_validate_blobs_sidecar.py (93%) rename tests/core/pyspec/eth2spec/test/{eip4844 => deneb}/unittests/polynomial_commitments/__init__.py (100%) rename tests/core/pyspec/eth2spec/test/{eip4844 => deneb}/unittests/polynomial_commitments/test_polynomial_commitments.py (96%) rename tests/core/pyspec/eth2spec/test/{eip4844 => deneb}/unittests/test_kzg.py (91%) rename tests/core/pyspec/eth2spec/test/{eip4844 => deneb}/unittests/test_offset.py (94%) delete mode 100644 tests/core/pyspec/eth2spec/test/eip4844/fork/test_eip4844_fork_random.py rename tests/core/pyspec/eth2spec/test/helpers/{eip4844 => deneb}/__init__.py (100%) rename tests/core/pyspec/eth2spec/test/helpers/{eip4844 => deneb}/fork.py (90%) diff --git a/.circleci/config.yml b/.circleci/config.yml index 94065d0bb..665207bdd 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -142,7 +142,7 @@ jobs: command: make citest fork=capella - store_test_results: path: tests/core/pyspec/test-reports - test-eip4844: + test-deneb: docker: - image: circleci/python:3.8 working_directory: ~/specs-repo @@ -152,7 +152,7 @@ jobs: - restore_pyspec_cached_venv - run: name: Run py-tests - command: make citest fork=eip4844 + command: make citest fork=deneb - store_test_results: path: tests/core/pyspec/test-reports table_of_contents: @@ -272,7 +272,7 @@ workflows: - test-capella: requires: - install_pyspec_test - - test-eip4844: + - test-deneb: requires: - install_pyspec_test - table_of_contents diff --git a/.github/workflows/run-tests.yml b/.github/workflows/run-tests.yml index 2c7b9d883..926c3fbbf 100644 --- a/.github/workflows/run-tests.yml +++ b/.github/workflows/run-tests.yml @@ -83,7 +83,7 @@ jobs: needs: [preclear,lint,codespell,table_of_contents] strategy: matrix: - version: ["phase0", "altair", "bellatrix", "capella", "eip4844"] + version: ["phase0", "altair", "bellatrix", "capella", "deneb"] steps: - name: Checkout this repo uses: actions/checkout@v3.2.0 diff --git a/.gitignore b/.gitignore index 219251599..c49e6c006 100644 --- a/.gitignore +++ b/.gitignore @@ -19,7 +19,7 @@ tests/core/pyspec/eth2spec/phase0/ tests/core/pyspec/eth2spec/altair/ tests/core/pyspec/eth2spec/bellatrix/ tests/core/pyspec/eth2spec/capella/ -tests/core/pyspec/eth2spec/eip4844/ +tests/core/pyspec/eth2spec/deneb/ # coverage reports .htmlcov diff --git a/Makefile b/Makefile index 8604fac27..854f42ce3 100644 --- a/Makefile +++ b/Makefile @@ -30,7 +30,7 @@ MARKDOWN_FILES = $(wildcard $(SPEC_DIR)/phase0/*.md) \ $(wildcard $(SPEC_DIR)/custody/*.md) \ $(wildcard $(SPEC_DIR)/das/*.md) \ $(wildcard $(SPEC_DIR)/sharding/*.md) \ - $(wildcard $(SPEC_DIR)/eip4844/*.md) $(wildcard $(SPEC_DIR)/eip4844/**/*.md) \ + $(wildcard $(SPEC_DIR)/deneb/*.md) $(wildcard $(SPEC_DIR)/deneb/**/*.md) \ $(wildcard $(SSZ_DIR)/*.md) COV_HTML_OUT=.htmlcov @@ -67,7 +67,7 @@ partial_clean: rm -rf $(ETH2SPEC_MODULE_DIR)/altair rm -rf $(ETH2SPEC_MODULE_DIR)/bellatrix rm -rf $(ETH2SPEC_MODULE_DIR)/capella - rm -rf $(ETH2SPEC_MODULE_DIR)/eip4844 + rm -rf $(ETH2SPEC_MODULE_DIR)/deneb rm -rf $(COV_HTML_OUT_DIR) rm -rf $(TEST_REPORT_DIR) rm -rf eth2spec.egg-info dist build @@ -105,12 +105,12 @@ install_test: # Testing against `minimal` or `mainnet` config by default test: pyspec . venv/bin/activate; cd $(PY_SPEC_DIR); \ - python3 -m pytest -n 4 --disable-bls --cov=eth2spec.phase0.$(TEST_PRESET_TYPE) --cov=eth2spec.altair.$(TEST_PRESET_TYPE) --cov=eth2spec.bellatrix.$(TEST_PRESET_TYPE) --cov=eth2spec.capella.$(TEST_PRESET_TYPE) --cov=eth2spec.eip4844.$(TEST_PRESET_TYPE) --cov-report="html:$(COV_HTML_OUT)" --cov-branch eth2spec + python3 -m pytest -n 4 --disable-bls --cov=eth2spec.phase0.$(TEST_PRESET_TYPE) --cov=eth2spec.altair.$(TEST_PRESET_TYPE) --cov=eth2spec.bellatrix.$(TEST_PRESET_TYPE) --cov=eth2spec.capella.$(TEST_PRESET_TYPE) --cov=eth2spec.deneb.$(TEST_PRESET_TYPE) --cov-report="html:$(COV_HTML_OUT)" --cov-branch eth2spec # Testing against `minimal` or `mainnet` config by default find_test: pyspec . venv/bin/activate; cd $(PY_SPEC_DIR); \ - python3 -m pytest -k=$(K) --disable-bls --cov=eth2spec.phase0.$(TEST_PRESET_TYPE) --cov=eth2spec.altair.$(TEST_PRESET_TYPE) --cov=eth2spec.bellatrix.$(TEST_PRESET_TYPE) --cov=eth2spec.capella.$(TEST_PRESET_TYPE) --cov=eth2spec.eip4844.$(TEST_PRESET_TYPE) --cov-report="html:$(COV_HTML_OUT)" --cov-branch eth2spec + python3 -m pytest -k=$(K) --disable-bls --cov=eth2spec.phase0.$(TEST_PRESET_TYPE) --cov=eth2spec.altair.$(TEST_PRESET_TYPE) --cov=eth2spec.bellatrix.$(TEST_PRESET_TYPE) --cov=eth2spec.capella.$(TEST_PRESET_TYPE) --cov=eth2spec.deneb.$(TEST_PRESET_TYPE) --cov-report="html:$(COV_HTML_OUT)" --cov-branch eth2spec citest: pyspec mkdir -p $(TEST_REPORT_DIR); @@ -142,8 +142,8 @@ codespell: lint: pyspec . venv/bin/activate; cd $(PY_SPEC_DIR); \ flake8 --config $(LINTER_CONFIG_FILE) ./eth2spec \ - && pylint --rcfile $(LINTER_CONFIG_FILE) ./eth2spec/phase0 ./eth2spec/altair ./eth2spec/bellatrix ./eth2spec/capella ./eth2spec/eip4844 \ - && mypy --config-file $(LINTER_CONFIG_FILE) -p eth2spec.phase0 -p eth2spec.altair -p eth2spec.bellatrix -p eth2spec.capella -p eth2spec.eip4844 + && pylint --rcfile $(LINTER_CONFIG_FILE) ./eth2spec/phase0 ./eth2spec/altair ./eth2spec/bellatrix ./eth2spec/capella ./eth2spec/deneb \ + && mypy --config-file $(LINTER_CONFIG_FILE) -p eth2spec.phase0 -p eth2spec.altair -p eth2spec.bellatrix -p eth2spec.capella -p eth2spec.deneb lint_generators: pyspec . venv/bin/activate; cd $(TEST_GENERATORS_DIR); \ diff --git a/README.md b/README.md index ed8771cb0..466c15193 100644 --- a/README.md +++ b/README.md @@ -25,7 +25,7 @@ Features are researched and developed in parallel, and then consolidated into se | Code Name or Topic | Specs | Notes | | - | - | - | | Capella (tentative) |
  • Core
    • [Beacon chain changes](specs/capella/beacon-chain.md)
    • [Capella fork](specs/capella/fork.md)
  • Additions
    • [Light client sync protocol changes](specs/capella/light-client/sync-protocol.md) ([fork](specs/capella/light-client/fork.md), [full node](specs/capella/light-client/full-node.md), [networking](specs/capella/light-client/p2p-interface.md))
    • [Validator additions](specs/capella/validator.md)
    • [P2P networking](specs/capella/p2p-interface.md)
| -| EIP4844 (tentative) |
  • Core
    • [Beacon Chain changes](specs/eip4844/beacon-chain.md)
    • [EIP-4844 fork](specs/eip4844/fork.md)
    • [Polynomial commitments](specs/eip4844/polynomial-commitments.md)
    • [Fork choice changes](specs/eip4844/fork-choice.md)
  • Additions
    • [Light client sync protocol changes](specs/eip4844/light-client/sync-protocol.md) ([fork](specs/eip4844/light-client/fork.md), [full node](specs/eip4844/light-client/full-node.md), [networking](specs/eip4844/light-client/p2p-interface.md))
    • [Honest validator guide changes](specs/eip4844/validator.md)
    • [P2P networking](specs/eip4844/p2p-interface.md)
| +| Deneb (tentative) |
  • Core
    • [Beacon Chain changes](specs/deneb/beacon-chain.md)
    • [EIP-4844 fork](specs/deneb/fork.md)
    • [Polynomial commitments](specs/deneb/polynomial-commitments.md)
    • [Fork choice changes](specs/deneb/fork-choice.md)
  • Additions
    • [Light client sync protocol changes](specs/deneb/light-client/sync-protocol.md) ([fork](specs/deneb/light-client/fork.md), [full node](specs/deneb/light-client/full-node.md), [networking](specs/deneb/light-client/p2p-interface.md))
    • [Honest validator guide changes](specs/deneb/validator.md)
    • [P2P networking](specs/deneb/p2p-interface.md)
| | Sharding (outdated) |
  • Core
    • [Beacon Chain changes](specs/sharding/beacon-chain.md)
  • Additions
    • [P2P networking](specs/sharding/p2p-interface.md)
| | Custody Game (outdated) |
  • Core
    • [Beacon Chain changes](specs/custody_game/beacon-chain.md)
  • Additions
    • [Honest validator guide changes](specs/custody_game/validator.md)
| Dependent on sharding | | Data Availability Sampling (outdated) |
  • Core
    • [Core types and functions](specs/das/das-core.md)
    • [Fork choice changes](specs/das/fork-choice.md)
  • Additions
    • [P2P Networking](specs/das/p2p-interface.md)
    • [Sampling process](specs/das/sampling.md)
|
  • Dependent on sharding
  • [Technical explainer](https://hackmd.io/@HWeNw8hNRimMm2m2GH56Cw/B1YJPGkpD)
| diff --git a/configs/mainnet.yaml b/configs/mainnet.yaml index 929d39f8a..f7e53d7e1 100644 --- a/configs/mainnet.yaml +++ b/configs/mainnet.yaml @@ -47,9 +47,9 @@ BELLATRIX_FORK_EPOCH: 144896 # Sept 6, 2022, 11:34:47am UTC # Capella CAPELLA_FORK_VERSION: 0x03000000 CAPELLA_FORK_EPOCH: 18446744073709551615 -# EIP4844 -EIP4844_FORK_VERSION: 0x04000000 -EIP4844_FORK_EPOCH: 18446744073709551615 +# Deneb +DENEB_FORK_VERSION: 0x04000000 +DENEB_FORK_EPOCH: 18446744073709551615 diff --git a/configs/minimal.yaml b/configs/minimal.yaml index 5dde4b749..abecb1881 100644 --- a/configs/minimal.yaml +++ b/configs/minimal.yaml @@ -46,9 +46,9 @@ BELLATRIX_FORK_EPOCH: 18446744073709551615 # Capella CAPELLA_FORK_VERSION: 0x03000001 CAPELLA_FORK_EPOCH: 18446744073709551615 -# EIP4844 -EIP4844_FORK_VERSION: 0x04000001 -EIP4844_FORK_EPOCH: 18446744073709551615 +# DENEB +DENEB_FORK_VERSION: 0x04000001 +DENEB_FORK_EPOCH: 18446744073709551615 # Time parameters diff --git a/presets/mainnet/eip4844.yaml b/presets/mainnet/deneb.yaml similarity index 100% rename from presets/mainnet/eip4844.yaml rename to presets/mainnet/deneb.yaml diff --git a/presets/minimal/eip4844.yaml b/presets/minimal/deneb.yaml similarity index 100% rename from presets/minimal/eip4844.yaml rename to presets/minimal/deneb.yaml diff --git a/setup.py b/setup.py index 9102f819b..f87ed5a6c 100644 --- a/setup.py +++ b/setup.py @@ -46,7 +46,7 @@ PHASE0 = 'phase0' ALTAIR = 'altair' BELLATRIX = 'bellatrix' CAPELLA = 'capella' -EIP4844 = 'eip4844' +DENEB = 'deneb' # The helper functions that are used when defining constants @@ -632,10 +632,10 @@ def compute_merkle_proof_for_block_body(body: BeaconBlockBody, return {**super().hardcoded_ssz_dep_constants(), **constants} # -# EIP4844SpecBuilder +# DenebSpecBuilder # -class EIP4844SpecBuilder(CapellaSpecBuilder): - fork: str = EIP4844 +class DenebSpecBuilder(CapellaSpecBuilder): + fork: str = DENEB @classmethod def imports(cls, preset_name: str): @@ -669,7 +669,7 @@ def retrieve_blobs_sidecar(slot: Slot, beacon_block_root: Root) -> PyUnion[Blobs spec_builders = { builder.fork: builder - for builder in (Phase0SpecBuilder, AltairSpecBuilder, BellatrixSpecBuilder, CapellaSpecBuilder, EIP4844SpecBuilder) + for builder in (Phase0SpecBuilder, AltairSpecBuilder, BellatrixSpecBuilder, CapellaSpecBuilder, DenebSpecBuilder) } @@ -968,14 +968,14 @@ class PySpecCommand(Command): 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, EIP4844): + if self.spec_fork in (PHASE0, ALTAIR, BELLATRIX, CAPELLA, DENEB): 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, EIP4844): + if self.spec_fork in (ALTAIR, BELLATRIX, CAPELLA, DENEB): self.md_doc_paths += """ specs/altair/light-client/full-node.md specs/altair/light-client/light-client.md @@ -987,7 +987,7 @@ class PySpecCommand(Command): specs/altair/validator.md specs/altair/p2p-interface.md """ - if self.spec_fork in (BELLATRIX, CAPELLA, EIP4844): + if self.spec_fork in (BELLATRIX, CAPELLA, DENEB): self.md_doc_paths += """ specs/bellatrix/beacon-chain.md specs/bellatrix/fork.md @@ -996,7 +996,7 @@ class PySpecCommand(Command): specs/bellatrix/p2p-interface.md sync/optimistic.md """ - if self.spec_fork in (CAPELLA, EIP4844): + if self.spec_fork in (CAPELLA, DENEB): self.md_doc_paths += """ specs/capella/light-client/fork.md specs/capella/light-client/full-node.md @@ -1008,18 +1008,18 @@ class PySpecCommand(Command): specs/capella/validator.md specs/capella/p2p-interface.md """ - if self.spec_fork == EIP4844: + if self.spec_fork == DENEB: self.md_doc_paths += """ - specs/eip4844/light-client/fork.md - specs/eip4844/light-client/full-node.md - specs/eip4844/light-client/p2p-interface.md - specs/eip4844/light-client/sync-protocol.md - specs/eip4844/beacon-chain.md - specs/eip4844/fork.md - specs/eip4844/fork-choice.md - specs/eip4844/polynomial-commitments.md - specs/eip4844/p2p-interface.md - specs/eip4844/validator.md + specs/deneb/light-client/fork.md + specs/deneb/light-client/full-node.md + specs/deneb/light-client/p2p-interface.md + specs/deneb/light-client/sync-protocol.md + specs/deneb/beacon-chain.md + specs/deneb/fork.md + specs/deneb/fork-choice.md + specs/deneb/polynomial-commitments.md + specs/deneb/p2p-interface.md + specs/deneb/validator.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/eip4844/beacon-chain.md b/specs/deneb/beacon-chain.md similarity index 98% rename from specs/eip4844/beacon-chain.md rename to specs/deneb/beacon-chain.md index f681ab951..87ebf7a9e 100644 --- a/specs/eip4844/beacon-chain.md +++ b/specs/deneb/beacon-chain.md @@ -249,7 +249,7 @@ def process_blob_kzg_commitments(state: BeaconState, body: BeaconBlockBody) -> N *Note*: The function `initialize_beacon_state_from_eth1` is modified for pure EIP-4844 testing only. -The `BeaconState` initialization is unchanged, except for the use of the updated `eip4844.BeaconBlockBody` type +The `BeaconState` initialization is unchanged, except for the use of the updated `deneb.BeaconBlockBody` type when initializing the first body-root. ```python @@ -259,8 +259,8 @@ def initialize_beacon_state_from_eth1(eth1_block_hash: Hash32, execution_payload_header: ExecutionPayloadHeader=ExecutionPayloadHeader() ) -> BeaconState: fork = Fork( - previous_version=EIP4844_FORK_VERSION, # [Modified in EIP-4844] for testing only - current_version=EIP4844_FORK_VERSION, # [Modified in EIP-4844] + previous_version=DENEB_FORK_VERSION, # [Modified in Deneb] for testing only + current_version=DENEB_FORK_VERSION, # [Modified in Deneb] epoch=GENESIS_EPOCH, ) state = BeaconState( diff --git a/specs/eip4844/fork-choice.md b/specs/deneb/fork-choice.md similarity index 100% rename from specs/eip4844/fork-choice.md rename to specs/deneb/fork-choice.md diff --git a/specs/eip4844/fork.md b/specs/deneb/fork.md similarity index 86% rename from specs/eip4844/fork.md rename to specs/deneb/fork.md index 39521879a..864e28888 100644 --- a/specs/eip4844/fork.md +++ b/specs/deneb/fork.md @@ -28,8 +28,8 @@ Warning: this configuration is not definitive. | Name | Value | | - | - | -| `EIP4844_FORK_VERSION` | `Version('0x04000000')` | -| `EIP4844_FORK_EPOCH` | `Epoch(18446744073709551615)` **TBD** | +| `DENEB_FORK_VERSION` | `Version('0x04000000')` | +| `DENEB_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 >= EIP4844_FORK_EPOCH: - return EIP4844_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: @@ -58,16 +58,16 @@ 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. -For now, we assume the condition will be triggered at epoch `EIP4844_FORK_EPOCH`. +For now, we assume the condition will be triggered at epoch `DENEB_FORK_EPOCH`. -Note that for the pure EIP-4844 networks, we don't apply `upgrade_to_eip4844` since it starts with EIP-4844 version logic. +Note that for the pure Deneb networks, we don't apply `upgrade_to_deneb` since it starts with Deneb version logic. ### Upgrading the state -Since the `eip4844.BeaconState` format is equal to the `capella.BeaconState` format, we only have to update `BeaconState.fork`. +Since the `deneb.BeaconState` format is equal to the `capella.BeaconState` format, we only have to update `BeaconState.fork`. ```python -def upgrade_to_eip4844(pre: capella.BeaconState) -> BeaconState: +def upgrade_to_deneb(pre: capella.BeaconState) -> BeaconState: epoch = capella.get_current_epoch(pre) latest_execution_payload_header = ExecutionPayloadHeader( parent_hash=pre.latest_execution_payload_header.parent_hash, @@ -94,7 +94,7 @@ def upgrade_to_eip4844(pre: capella.BeaconState) -> BeaconState: slot=pre.slot, fork=Fork( previous_version=pre.fork.current_version, - current_version=EIP4844_FORK_VERSION, # [Modified in EIP4844] + current_version=DENEB_FORK_VERSION, # [Modified in Deneb] epoch=epoch, ), # History @@ -127,7 +127,7 @@ def upgrade_to_eip4844(pre: capella.BeaconState) -> BeaconState: current_sync_committee=pre.current_sync_committee, next_sync_committee=pre.next_sync_committee, # Execution-layer - latest_execution_payload_header=latest_execution_payload_header, # [Modified in EIP4844] + latest_execution_payload_header=latest_execution_payload_header, # [Modified in Deneb] # Withdrawals next_withdrawal_index=pre.next_withdrawal_index, next_withdrawal_validator_index=pre.next_withdrawal_validator_index, diff --git a/specs/eip4844/light-client/fork.md b/specs/deneb/light-client/fork.md similarity index 62% rename from specs/eip4844/light-client/fork.md rename to specs/deneb/light-client/fork.md index 2d5f74f46..8c552937a 100644 --- a/specs/eip4844/light-client/fork.md +++ b/specs/deneb/light-client/fork.md @@ -1,4 +1,4 @@ -# EIP4844 Light Client -- Fork Logic +# Deneb Light Client -- Fork Logic ## Table of contents @@ -15,14 +15,14 @@ ## Introduction -This document describes how to upgrade existing light client objects based on the [Capella specification](../../capella/light-client/sync-protocol.md) to EIP4844. This is necessary when processing pre-EIP4844 data with a post-EIP4844 `LightClientStore`. Note that the data being exchanged over the network protocols uses the original format. +This document describes how to upgrade existing light client objects based on the [Capella specification](../../capella/light-client/sync-protocol.md) to Deneb. This is necessary when processing pre-Deneb data with a post-Deneb `LightClientStore`. Note that the data being exchanged over the network protocols uses the original format. ### Upgrading light client data -A EIP4844 `LightClientStore` can still process earlier light client data. In order to do so, that pre-EIP4844 data needs to be locally upgraded to EIP4844 before processing. +A Deneb `LightClientStore` can still process earlier light client data. In order to do so, that pre-Deneb data needs to be locally upgraded to Deneb before processing. ```python -def upgrade_lc_header_to_eip4844(pre: capella.LightClientHeader) -> LightClientHeader: +def upgrade_lc_header_to_deneb(pre: capella.LightClientHeader) -> LightClientHeader: return LightClientHeader( beacon=pre.beacon, execution=ExecutionPayloadHeader( @@ -47,21 +47,21 @@ def upgrade_lc_header_to_eip4844(pre: capella.LightClientHeader) -> LightClientH ``` ```python -def upgrade_lc_bootstrap_to_eip4844(pre: capella.LightClientBootstrap) -> LightClientBootstrap: +def upgrade_lc_bootstrap_to_deneb(pre: capella.LightClientBootstrap) -> LightClientBootstrap: return LightClientBootstrap( - header=upgrade_lc_header_to_eip4844(pre.header), + header=upgrade_lc_header_to_deneb(pre.header), current_sync_committee=pre.current_sync_committee, current_sync_committee_branch=pre.current_sync_committee_branch, ) ``` ```python -def upgrade_lc_update_to_eip4844(pre: capella.LightClientUpdate) -> LightClientUpdate: +def upgrade_lc_update_to_deneb(pre: capella.LightClientUpdate) -> LightClientUpdate: return LightClientUpdate( - attested_header=upgrade_lc_header_to_eip4844(pre.attested_header), + attested_header=upgrade_lc_header_to_deneb(pre.attested_header), next_sync_committee=pre.next_sync_committee, next_sync_committee_branch=pre.next_sync_committee_branch, - finalized_header=upgrade_lc_header_to_eip4844(pre.finalized_header), + finalized_header=upgrade_lc_header_to_deneb(pre.finalized_header), finality_branch=pre.finality_branch, sync_aggregate=pre.sync_aggregate, signature_slot=pre.signature_slot, @@ -69,10 +69,10 @@ def upgrade_lc_update_to_eip4844(pre: capella.LightClientUpdate) -> LightClientU ``` ```python -def upgrade_lc_finality_update_to_eip4844(pre: capella.LightClientFinalityUpdate) -> LightClientFinalityUpdate: +def upgrade_lc_finality_update_to_deneb(pre: capella.LightClientFinalityUpdate) -> LightClientFinalityUpdate: return LightClientFinalityUpdate( - attested_header=upgrade_lc_header_to_eip4844(pre.attested_header), - finalized_header=upgrade_lc_header_to_eip4844(pre.finalized_header), + attested_header=upgrade_lc_header_to_deneb(pre.attested_header), + finalized_header=upgrade_lc_header_to_deneb(pre.finalized_header), finality_branch=pre.finality_branch, sync_aggregate=pre.sync_aggregate, signature_slot=pre.signature_slot, @@ -80,9 +80,9 @@ def upgrade_lc_finality_update_to_eip4844(pre: capella.LightClientFinalityUpdate ``` ```python -def upgrade_lc_optimistic_update_to_eip4844(pre: capella.LightClientOptimisticUpdate) -> LightClientOptimisticUpdate: +def upgrade_lc_optimistic_update_to_deneb(pre: capella.LightClientOptimisticUpdate) -> LightClientOptimisticUpdate: return LightClientOptimisticUpdate( - attested_header=upgrade_lc_header_to_eip4844(pre.attested_header), + attested_header=upgrade_lc_header_to_deneb(pre.attested_header), sync_aggregate=pre.sync_aggregate, signature_slot=pre.signature_slot, ) @@ -90,20 +90,20 @@ def upgrade_lc_optimistic_update_to_eip4844(pre: capella.LightClientOptimisticUp ### Upgrading the store -Existing `LightClientStore` objects based on Capella MUST be upgraded to EIP4844 before EIP4844 based light client data can be processed. The `LightClientStore` upgrade MAY be performed before `EIP4844_FORK_EPOCH`. +Existing `LightClientStore` objects based on Capella MUST be upgraded to Deneb before Deneb based light client data can be processed. The `LightClientStore` upgrade MAY be performed before `DENEB_FORK_EPOCH`. ```python -def upgrade_lc_store_to_eip4844(pre: capella.LightClientStore) -> LightClientStore: +def upgrade_lc_store_to_deneb(pre: capella.LightClientStore) -> LightClientStore: if pre.best_valid_update is None: best_valid_update = None else: - best_valid_update = upgrade_lc_update_to_eip4844(pre.best_valid_update) + best_valid_update = upgrade_lc_update_to_deneb(pre.best_valid_update) return LightClientStore( - finalized_header=upgrade_lc_header_to_eip4844(pre.finalized_header), + finalized_header=upgrade_lc_header_to_deneb(pre.finalized_header), current_sync_committee=pre.current_sync_committee, next_sync_committee=pre.next_sync_committee, best_valid_update=best_valid_update, - optimistic_header=upgrade_lc_header_to_eip4844(pre.optimistic_header), + optimistic_header=upgrade_lc_header_to_deneb(pre.optimistic_header), previous_max_active_participants=pre.previous_max_active_participants, current_max_active_participants=pre.current_max_active_participants, ) diff --git a/specs/eip4844/light-client/full-node.md b/specs/deneb/light-client/full-node.md similarity index 94% rename from specs/eip4844/light-client/full-node.md rename to specs/deneb/light-client/full-node.md index 70983e1b3..275194036 100644 --- a/specs/eip4844/light-client/full-node.md +++ b/specs/deneb/light-client/full-node.md @@ -1,4 +1,4 @@ -# EIP4844 Light Client -- Full Node +# Deneb Light Client -- Full Node **Notice**: This document is a work-in-progress for researchers and implementers. @@ -17,7 +17,7 @@ ## Introduction -This upgrade adds information about the execution payload to light client data as part of the EIP4844 upgrade. +This upgrade adds information about the execution payload to light client data as part of the Deneb upgrade. ## Helper functions @@ -47,8 +47,8 @@ def block_to_light_client_header(block: SignedBeaconBlock) -> LightClientHeader: withdrawals_root=hash_tree_root(payload.withdrawals), ) - # [New in EIP4844] - if epoch >= EIP4844_FORK_EPOCH: + # [New in Deneb] + if epoch >= DENEB_FORK_EPOCH: execution_header.excess_data_gas = payload.excess_data_gas execution_branch = compute_merkle_proof_for_block_body(block.message.body, EXECUTION_PAYLOAD_INDEX) diff --git a/specs/eip4844/light-client/p2p-interface.md b/specs/deneb/light-client/p2p-interface.md similarity index 65% rename from specs/eip4844/light-client/p2p-interface.md rename to specs/deneb/light-client/p2p-interface.md index f3d89c130..0ca53056a 100644 --- a/specs/eip4844/light-client/p2p-interface.md +++ b/specs/deneb/light-client/p2p-interface.md @@ -1,4 +1,4 @@ -# EIP4844 Light Client -- Networking +# Deneb Light Client -- Networking **Notice**: This document is a work-in-progress for researchers and implementers. @@ -26,7 +26,7 @@ ## Networking -The [Capella light client networking specification](../../capella/light-client/p2p-interface.md) is extended to exchange [EIP4844 light client data](./sync-protocol.md). +The [Capella light client networking specification](../../capella/light-client/p2p-interface.md) is extended to exchange [Deneb light client data](./sync-protocol.md). ### The gossip domain: gossipsub @@ -38,23 +38,23 @@ The [Capella light client networking specification](../../capella/light-client/p [0]: # (eth2spec: skip) -| `fork_version` | Message SSZ type | -| ------------------------------------------------------ | ------------------------------------- | -| `GENESIS_FORK_VERSION` | n/a | -| `ALTAIR_FORK_VERSION` through `BELLATRIX_FORK_VERSION` | `altair.LightClientFinalityUpdate` | -| `CAPELLA_FORK_VERSION` | `capella.LightClientFinalityUpdate` | -| `EIP4844_FORK_VERSION` and later | `eip4844.LightClientFinalityUpdate` | +| `fork_version` | Message SSZ type | +|--------------------------------------------------------|-------------------------------------| +| `GENESIS_FORK_VERSION` | n/a | +| `ALTAIR_FORK_VERSION` through `BELLATRIX_FORK_VERSION` | `altair.LightClientFinalityUpdate` | +| `CAPELLA_FORK_VERSION` | `capella.LightClientFinalityUpdate` | +| `DENEB_FORK_VERSION` and later | `deneb.LightClientFinalityUpdate` | ###### `light_client_optimistic_update` [0]: # (eth2spec: skip) | `fork_version` | Message SSZ type | -| ------------------------------------------------------ | ------------------------------------- | +|--------------------------------------------------------|---------------------------------------| | `GENESIS_FORK_VERSION` | n/a | | `ALTAIR_FORK_VERSION` through `BELLATRIX_FORK_VERSION` | `altair.LightClientOptimisticUpdate` | | `CAPELLA_FORK_VERSION` | `capella.LightClientOptimisticUpdate` | -| `EIP4844_FORK_VERSION` and later | `eip4844.LightClientOptimisticUpdate` | +| `DENEB_FORK_VERSION` and later | `deneb.LightClientOptimisticUpdate` | ### The Req/Resp domain @@ -64,42 +64,42 @@ The [Capella light client networking specification](../../capella/light-client/p [0]: # (eth2spec: skip) -| `fork_version` | Response SSZ type | -| ------------------------------------------------------ | ------------------------------------- | -| `GENESIS_FORK_VERSION` | n/a | -| `ALTAIR_FORK_VERSION` through `BELLATRIX_FORK_VERSION` | `altair.LightClientBootstrap` | -| `CAPELLA_FORK_VERSION` | `capella.LightClientBootstrap` | -| `EIP4844_FORK_VERSION` and later | `eip4844.LightClientBootstrap` | +| `fork_version` | Response SSZ type | +|--------------------------------------------------------|------------------------------------| +| `GENESIS_FORK_VERSION` | n/a | +| `ALTAIR_FORK_VERSION` through `BELLATRIX_FORK_VERSION` | `altair.LightClientBootstrap` | +| `CAPELLA_FORK_VERSION` | `capella.LightClientBootstrap` | +| `DENEB_FORK_VERSION` and later | `deneb.LightClientBootstrap` | ##### LightClientUpdatesByRange [0]: # (eth2spec: skip) -| `fork_version` | Response chunk SSZ type | -| ------------------------------------------------------ | ------------------------------------- | -| `GENESIS_FORK_VERSION` | n/a | -| `ALTAIR_FORK_VERSION` through `BELLATRIX_FORK_VERSION` | `altair.LightClientUpdate` | -| `CAPELLA_FORK_VERSION` | `capella.LightClientUpdate` | -| `EIP4844_FORK_VERSION` and later | `eip4844.LightClientUpdate` | +| `fork_version` | Response chunk SSZ type | +|--------------------------------------------------------|----------------------------------| +| `GENESIS_FORK_VERSION` | n/a | +| `ALTAIR_FORK_VERSION` through `BELLATRIX_FORK_VERSION` | `altair.LightClientUpdate` | +| `CAPELLA_FORK_VERSION` | `capella.LightClientUpdate` | +| `DENEB_FORK_VERSION` and later | `deneb.LightClientUpdate` | ##### GetLightClientFinalityUpdate [0]: # (eth2spec: skip) -| `fork_version` | Response SSZ type | -| ------------------------------------------------------ | ------------------------------------- | -| `GENESIS_FORK_VERSION` | n/a | -| `ALTAIR_FORK_VERSION` through `BELLATRIX_FORK_VERSION` | `altair.LightClientFinalityUpdate` | -| `CAPELLA_FORK_VERSION` | `capella.LightClientFinalityUpdate` | -| `EIP4844_FORK_VERSION` and later | `eip4844.LightClientFinalityUpdate` | +| `fork_version` | Response SSZ type | +|--------------------------------------------------------|-------------------------------------| +| `GENESIS_FORK_VERSION` | n/a | +| `ALTAIR_FORK_VERSION` through `BELLATRIX_FORK_VERSION` | `altair.LightClientFinalityUpdate` | +| `CAPELLA_FORK_VERSION` | `capella.LightClientFinalityUpdate` | +| `DENEB_FORK_VERSION` and later | `deneb.LightClientFinalityUpdate` | ##### GetLightClientOptimisticUpdate [0]: # (eth2spec: skip) | `fork_version` | Response SSZ type | -| ------------------------------------------------------ | ------------------------------------- | +|--------------------------------------------------------|---------------------------------------| | `GENESIS_FORK_VERSION` | n/a | | `ALTAIR_FORK_VERSION` through `BELLATRIX_FORK_VERSION` | `altair.LightClientOptimisticUpdate` | | `CAPELLA_FORK_VERSION` | `capella.LightClientOptimisticUpdate` | -| `EIP4844_FORK_VERSION` and later | `eip4844.LightClientOptimisticUpdate` | +| `DENEB_FORK_VERSION` and later | `deneb.LightClientOptimisticUpdate` | diff --git a/specs/eip4844/light-client/sync-protocol.md b/specs/deneb/light-client/sync-protocol.md similarity index 84% rename from specs/eip4844/light-client/sync-protocol.md rename to specs/deneb/light-client/sync-protocol.md index 181ca14eb..6f948257b 100644 --- a/specs/eip4844/light-client/sync-protocol.md +++ b/specs/deneb/light-client/sync-protocol.md @@ -1,4 +1,4 @@ -# EIP4844 Light Client -- Sync Protocol +# Deneb Light Client -- Sync Protocol **Notice**: This document is a work-in-progress for researchers and implementers. @@ -18,7 +18,7 @@ ## Introduction -This upgrade updates light client data to include the EIP4844 changes to the [`ExecutionPayload`](../beacon-chain.md) structure. It extends the [Capella Light Client specifications](../../capella/light-client/sync-protocol.md). The [fork document](./fork.md) explains how to upgrade existing Capella based deployments to EIP4844. +This upgrade updates light client data to include the Denbeb changes to the [`ExecutionPayload`](../beacon-chain.md) structure. It extends the [Capella Light Client specifications](../../capella/light-client/sync-protocol.md). The [fork document](./fork.md) explains how to upgrade existing Capella based deployments to Deneb. Additional documents describes the impact of the upgrade on certain roles: - [Full node](./full-node.md) @@ -32,11 +32,11 @@ Additional documents describes the impact of the upgrade on certain roles: def get_lc_execution_root(header: LightClientHeader) -> Root: epoch = compute_epoch_at_slot(header.beacon.slot) - # [New in EIP4844] - if epoch >= EIP4844_FORK_EPOCH: + # [New in Deneb] + if epoch >= DENEB_FORK_EPOCH: return hash_tree_root(header.execution) - # [Modified in EIP4844] + # [Modified in Deneb] if epoch >= CAPELLA_FORK_EPOCH: execution_header = capella.ExecutionPayloadHeader( parent_hash=header.execution.parent_hash, @@ -66,8 +66,8 @@ def get_lc_execution_root(header: LightClientHeader) -> Root: def is_valid_light_client_header(header: LightClientHeader) -> bool: epoch = compute_epoch_at_slot(header.beacon.slot) - # [New in EIP4844] - if epoch < EIP4844_FORK_EPOCH: + # [New in Deneb] + if epoch < DENEB_FORK_EPOCH: if header.execution.excess_data_gas != uint256(0): return False diff --git a/specs/eip4844/p2p-interface.md b/specs/deneb/p2p-interface.md similarity index 95% rename from specs/eip4844/p2p-interface.md rename to specs/deneb/p2p-interface.md index ae9380f7a..852597b09 100644 --- a/specs/eip4844/p2p-interface.md +++ b/specs/deneb/p2p-interface.md @@ -119,13 +119,13 @@ Per `context = compute_fork_digest(fork_version, genesis_validators_root)`: | `ALTAIR_FORK_VERSION` | `altair.SignedBeaconBlock` | | `BELLATRIX_FORK_VERSION` | `bellatrix.SignedBeaconBlock` | | `CAPELLA_FORK_VERSION` | `capella.SignedBeaconBlock` | -| `EIP4844_FORK_VERSION` | `eip4844.SignedBeaconBlock` | +| `DENEB_FORK_VERSION` | `deneb.SignedBeaconBlock` | #### BeaconBlocksByRoot v2 **Protocol ID:** `/eth2/beacon_chain/req/beacon_blocks_by_root/2/` -After `EIP4844_FORK_EPOCH`, `BeaconBlocksByRootV2` is replaced by `BeaconBlockAndBlobsSidecarByRootV1`. +After `DENEB_FORK_EPOCH`, `BeaconBlocksByRootV2` is replaced by `BeaconBlockAndBlobsSidecarByRootV1`. Clients MUST support requesting blocks by root for pre-fork-epoch blocks. Per `context = compute_fork_digest(fork_version, genesis_validators_root)`: @@ -170,7 +170,7 @@ No more than `MAX_REQUEST_BLOCKS` may be requested at a time. The response MUST consist of zero or more `response_chunk`. Each _successful_ `response_chunk` MUST contain a single `SignedBeaconBlockAndBlobsSidecar` payload. -Clients MUST support requesting blocks and sidecars since `minimum_request_epoch`, where `minimum_request_epoch = max(finalized_epoch, current_epoch - MIN_EPOCHS_FOR_BLOBS_SIDECARS_REQUESTS, EIP4844_FORK_EPOCH)`. If any root in the request content references a block earlier than `minimum_request_epoch`, peers SHOULD respond with error code `3: ResourceUnavailable`. +Clients MUST support requesting blocks and sidecars since `minimum_request_epoch`, where `minimum_request_epoch = max(finalized_epoch, current_epoch - MIN_EPOCHS_FOR_BLOBS_SIDECARS_REQUESTS, DENEB_FORK_EPOCH)`. If any root in the request content references a block earlier than `minimum_request_epoch`, peers SHOULD respond with error code `3: ResourceUnavailable`. Clients MUST respond with at least one block and sidecar, if they have it. Clients MAY limit the number of blocks and sidecars in the response. @@ -211,7 +211,7 @@ The response MUST consist of zero or more `response_chunk`. Each _successful_ `response_chunk` MUST contain a single `BlobsSidecar` payload. Clients MUST keep a record of signed blobs sidecars seen on the epoch range -`[max(current_epoch - MIN_EPOCHS_FOR_BLOBS_SIDECARS_REQUESTS, EIP4844_FORK_EPOCH), current_epoch]` +`[max(current_epoch - MIN_EPOCHS_FOR_BLOBS_SIDECARS_REQUESTS, DENEB_FORK_EPOCH), current_epoch]` where `current_epoch` is defined by the current wall-clock time, and clients MUST support serving requests of blobs on this range. diff --git a/specs/eip4844/polynomial-commitments.md b/specs/deneb/polynomial-commitments.md similarity index 100% rename from specs/eip4844/polynomial-commitments.md rename to specs/deneb/polynomial-commitments.md diff --git a/specs/eip4844/validator.md b/specs/deneb/validator.md similarity index 100% rename from specs/eip4844/validator.md rename to specs/deneb/validator.md diff --git a/tests/core/pyspec/eth2spec/test/altair/light_client/test_sync.py b/tests/core/pyspec/eth2spec/test/altair/light_client/test_sync.py index 664b4fb44..63bec26b0 100644 --- a/tests/core/pyspec/eth2spec/test/altair/light_client/test_sync.py +++ b/tests/core/pyspec/eth2spec/test/altair/light_client/test_sync.py @@ -16,7 +16,7 @@ from eth2spec.test.helpers.attestations import ( state_transition_with_full_block, ) from eth2spec.test.helpers.constants import ( - PHASE0, ALTAIR, BELLATRIX, CAPELLA, EIP4844, + PHASE0, ALTAIR, BELLATRIX, CAPELLA, DENEB, MINIMAL, ALL_PHASES, ) @@ -24,7 +24,7 @@ from eth2spec.test.helpers.fork_transition import ( do_fork, ) from eth2spec.test.helpers.forks import ( - is_post_capella, is_post_eip4844, + is_post_capella, is_post_deneb, is_post_fork, ) from eth2spec.test.helpers.light_client import ( @@ -53,8 +53,8 @@ def needs_upgrade_to_capella(d_spec, s_spec): return is_post_capella(s_spec) and not is_post_capella(d_spec) -def needs_upgrade_to_eip4844(d_spec, s_spec): - return is_post_eip4844(s_spec) and not is_post_eip4844(d_spec) +def needs_upgrade_to_deneb(d_spec, s_spec): + return is_post_deneb(s_spec) and not is_post_deneb(d_spec) def check_lc_header_equal(d_spec, s_spec, data, upgraded): @@ -80,8 +80,8 @@ def upgrade_lc_bootstrap_to_store(d_spec, s_spec, data): upgraded = s_spec.upgrade_lc_bootstrap_to_capella(upgraded) check_lc_bootstrap_equal(d_spec, s_spec, data, upgraded) - if needs_upgrade_to_eip4844(d_spec, s_spec): - upgraded = s_spec.upgrade_lc_bootstrap_to_eip4844(upgraded) + if needs_upgrade_to_deneb(d_spec, s_spec): + upgraded = s_spec.upgrade_lc_bootstrap_to_deneb(upgraded) check_lc_bootstrap_equal(d_spec, s_spec, data, upgraded) return upgraded @@ -103,8 +103,8 @@ def upgrade_lc_update_to_store(d_spec, s_spec, data): upgraded = s_spec.upgrade_lc_update_to_capella(upgraded) check_lc_update_equal(d_spec, s_spec, data, upgraded) - if needs_upgrade_to_eip4844(d_spec, s_spec): - upgraded = s_spec.upgrade_lc_update_to_eip4844(upgraded) + if needs_upgrade_to_deneb(d_spec, s_spec): + upgraded = s_spec.upgrade_lc_update_to_deneb(upgraded) check_lc_update_equal(d_spec, s_spec, data, upgraded) return upgraded @@ -130,8 +130,8 @@ def upgrade_lc_store_to_new_spec(d_spec, s_spec, data): upgraded = s_spec.upgrade_lc_store_to_capella(upgraded) check_lc_store_equal(d_spec, s_spec, data, upgraded) - if needs_upgrade_to_eip4844(d_spec, s_spec): - upgraded = s_spec.upgrade_lc_store_to_eip4844(upgraded) + if needs_upgrade_to_deneb(d_spec, s_spec): + upgraded = s_spec.upgrade_lc_store_to_deneb(upgraded) check_lc_store_equal(d_spec, s_spec, data, upgraded) return upgraded @@ -145,8 +145,8 @@ class LightClientSyncTest(object): def get_store_fork_version(s_spec): - if is_post_eip4844(s_spec): - return s_spec.config.EIP4844_FORK_VERSION + if is_post_deneb(s_spec): + return s_spec.config.DENEB_FORK_VERSION if is_post_capella(s_spec): return s_spec.config.CAPELLA_FORK_VERSION return s_spec.config.ALTAIR_FORK_VERSION @@ -731,16 +731,16 @@ def test_capella_fork(spec, phases, state): yield from run_test_single_fork(spec, phases, state, CAPELLA) -@with_phases(phases=[CAPELLA], other_phases=[EIP4844]) +@with_phases(phases=[CAPELLA], other_phases=[DENEB]) @spec_test @with_config_overrides({ - 'EIP4844_FORK_EPOCH': 3, # `setup_test` advances to epoch 2 + 'DENEB_FORK_EPOCH': 3, # `setup_test` advances to epoch 2 }, emit=False) @with_state -@with_matching_spec_config(emitted_fork=EIP4844) +@with_matching_spec_config(emitted_fork=DENEB) @with_presets([MINIMAL], reason="too slow") -def test_eip4844_fork(spec, phases, state): - yield from run_test_single_fork(spec, phases, state, EIP4844) +def test_deneb_fork(spec, phases, state): + yield from run_test_single_fork(spec, phases, state, DENEB) def run_test_multi_fork(spec, phases, state, fork_1, fork_2): @@ -779,17 +779,17 @@ def run_test_multi_fork(spec, phases, state, fork_1, fork_2): yield from finish_test(test) -@with_phases(phases=[BELLATRIX], other_phases=[CAPELLA, EIP4844]) +@with_phases(phases=[BELLATRIX], other_phases=[CAPELLA, DENEB]) @spec_test @with_config_overrides({ 'CAPELLA_FORK_EPOCH': 3, # `setup_test` advances to epoch 2 - 'EIP4844_FORK_EPOCH': 4, + 'DENEB_FORK_EPOCH': 4, }, emit=False) @with_state -@with_matching_spec_config(emitted_fork=EIP4844) +@with_matching_spec_config(emitted_fork=DENEB) @with_presets([MINIMAL], reason="too slow") -def test_capella_eip4844_fork(spec, phases, state): - yield from run_test_multi_fork(spec, phases, state, CAPELLA, EIP4844) +def test_capella_deneb_fork(spec, phases, state): + yield from run_test_multi_fork(spec, phases, state, CAPELLA, DENEB) def run_test_upgraded_store_with_legacy_data(spec, phases, state, fork): @@ -823,10 +823,10 @@ def test_capella_store_with_legacy_data(spec, phases, state): yield from run_test_upgraded_store_with_legacy_data(spec, phases, state, CAPELLA) -@with_phases(phases=[ALTAIR, BELLATRIX, CAPELLA], other_phases=[EIP4844]) +@with_phases(phases=[ALTAIR, BELLATRIX, CAPELLA], other_phases=[DENEB]) @spec_test @with_state -@with_matching_spec_config(emitted_fork=EIP4844) +@with_matching_spec_config(emitted_fork=DENEB) @with_presets([MINIMAL], reason="too slow") -def test_eip4844_store_with_legacy_data(spec, phases, state): - yield from run_test_upgraded_store_with_legacy_data(spec, phases, state, EIP4844) +def test_deneb_store_with_legacy_data(spec, phases, state): + yield from run_test_upgraded_store_with_legacy_data(spec, phases, state, DENEB) diff --git a/tests/core/pyspec/eth2spec/test/context.py b/tests/core/pyspec/eth2spec/test/context.py index 8401b973e..38e7f0b71 100644 --- a/tests/core/pyspec/eth2spec/test/context.py +++ b/tests/core/pyspec/eth2spec/test/context.py @@ -7,12 +7,12 @@ from eth2spec.phase0 import mainnet as spec_phase0_mainnet, minimal as spec_phas from eth2spec.altair import mainnet as spec_altair_mainnet, minimal as spec_altair_minimal from eth2spec.bellatrix import mainnet as spec_bellatrix_mainnet, minimal as spec_bellatrix_minimal from eth2spec.capella import mainnet as spec_capella_mainnet, minimal as spec_capella_minimal -from eth2spec.eip4844 import mainnet as spec_eip4844_mainnet, minimal as spec_eip4844_minimal +from eth2spec.deneb import mainnet as spec_deneb_mainnet, minimal as spec_deneb_minimal from eth2spec.utils import bls from .exceptions import SkippedTest from .helpers.constants import ( - PHASE0, ALTAIR, BELLATRIX, CAPELLA, EIP4844, + PHASE0, ALTAIR, BELLATRIX, CAPELLA, DENEB, MINIMAL, MAINNET, ALL_PHASES, ALL_FORK_UPGRADES, @@ -78,14 +78,14 @@ spec_targets: Dict[PresetBaseName, Dict[SpecForkName, Spec]] = { ALTAIR: spec_altair_minimal, BELLATRIX: spec_bellatrix_minimal, CAPELLA: spec_capella_minimal, - EIP4844: spec_eip4844_minimal, + DENEB: spec_deneb_minimal, }, MAINNET: { PHASE0: spec_phase0_mainnet, ALTAIR: spec_altair_mainnet, BELLATRIX: spec_bellatrix_mainnet, CAPELLA: spec_capella_mainnet, - EIP4844: spec_eip4844_mainnet + DENEB: spec_deneb_mainnet }, } @@ -427,7 +427,7 @@ def with_all_phases_except(exclusion_phases): with_altair_and_later = with_all_phases_from(ALTAIR) with_bellatrix_and_later = with_all_phases_from(BELLATRIX) with_capella_and_later = with_all_phases_from(CAPELLA) -with_eip4844_and_later = with_all_phases_from(EIP4844) +with_deneb_and_later = with_all_phases_from(DENEB) def _get_preset_targets(kw): diff --git a/tests/core/pyspec/eth2spec/test/eip4844/__init__.py b/tests/core/pyspec/eth2spec/test/deneb/__init__.py similarity index 100% rename from tests/core/pyspec/eth2spec/test/eip4844/__init__.py rename to tests/core/pyspec/eth2spec/test/deneb/__init__.py diff --git a/tests/core/pyspec/eth2spec/test/eip4844/fork/__init__.py b/tests/core/pyspec/eth2spec/test/deneb/fork/__init__.py similarity index 100% rename from tests/core/pyspec/eth2spec/test/eip4844/fork/__init__.py rename to tests/core/pyspec/eth2spec/test/deneb/fork/__init__.py diff --git a/tests/core/pyspec/eth2spec/test/eip4844/fork/test_eip4844_fork_basic.py b/tests/core/pyspec/eth2spec/test/deneb/fork/test_deneb_fork_basic.py similarity index 55% rename from tests/core/pyspec/eth2spec/test/eip4844/fork/test_eip4844_fork_basic.py rename to tests/core/pyspec/eth2spec/test/deneb/fork/test_deneb_fork_basic.py index aca7cb852..1666fdd71 100644 --- a/tests/core/pyspec/eth2spec/test/eip4844/fork/test_eip4844_fork_basic.py +++ b/tests/core/pyspec/eth2spec/test/deneb/fork/test_deneb_fork_basic.py @@ -7,76 +7,76 @@ from eth2spec.test.context import ( ) from eth2spec.test.utils import with_meta_tags from eth2spec.test.helpers.constants import ( - CAPELLA, EIP4844, + CAPELLA, DENEB, MINIMAL, ) from eth2spec.test.helpers.state import ( next_epoch, next_epoch_via_block, ) -from eth2spec.test.helpers.eip4844.fork import ( - EIP4844_FORK_TEST_META_TAGS, +from eth2spec.test.helpers.deneb.fork import ( + DENEB_FORK_TEST_META_TAGS, run_fork_test, ) -@with_phases(phases=[CAPELLA], other_phases=[EIP4844]) +@with_phases(phases=[CAPELLA], other_phases=[DENEB]) @spec_test @with_state -@with_meta_tags(EIP4844_FORK_TEST_META_TAGS) +@with_meta_tags(DENEB_FORK_TEST_META_TAGS) def test_fork_base_state(spec, phases, state): - yield from run_fork_test(phases[EIP4844], state) + yield from run_fork_test(phases[DENEB], state) -@with_phases(phases=[CAPELLA], other_phases=[EIP4844]) +@with_phases(phases=[CAPELLA], other_phases=[DENEB]) @spec_test @with_state -@with_meta_tags(EIP4844_FORK_TEST_META_TAGS) +@with_meta_tags(DENEB_FORK_TEST_META_TAGS) def test_fork_next_epoch(spec, phases, state): next_epoch(spec, state) - yield from run_fork_test(phases[EIP4844], state) + yield from run_fork_test(phases[DENEB], state) -@with_phases(phases=[CAPELLA], other_phases=[EIP4844]) +@with_phases(phases=[CAPELLA], other_phases=[DENEB]) @spec_test @with_state -@with_meta_tags(EIP4844_FORK_TEST_META_TAGS) +@with_meta_tags(DENEB_FORK_TEST_META_TAGS) def test_fork_next_epoch_with_block(spec, phases, state): next_epoch_via_block(spec, state) - yield from run_fork_test(phases[EIP4844], state) + yield from run_fork_test(phases[DENEB], state) -@with_phases(phases=[CAPELLA], other_phases=[EIP4844]) +@with_phases(phases=[CAPELLA], other_phases=[DENEB]) @spec_test @with_state -@with_meta_tags(EIP4844_FORK_TEST_META_TAGS) +@with_meta_tags(DENEB_FORK_TEST_META_TAGS) def test_fork_many_next_epoch(spec, phases, state): for _ in range(3): next_epoch(spec, state) - yield from run_fork_test(phases[EIP4844], state) + yield from run_fork_test(phases[DENEB], state) -@with_phases(phases=[CAPELLA], other_phases=[EIP4844]) +@with_phases(phases=[CAPELLA], other_phases=[DENEB]) @with_custom_state(balances_fn=low_balances, threshold_fn=lambda spec: spec.config.EJECTION_BALANCE) @spec_test -@with_meta_tags(EIP4844_FORK_TEST_META_TAGS) +@with_meta_tags(DENEB_FORK_TEST_META_TAGS) def test_fork_random_low_balances(spec, phases, state): - yield from run_fork_test(phases[EIP4844], state) + yield from run_fork_test(phases[DENEB], state) -@with_phases(phases=[CAPELLA], other_phases=[EIP4844]) +@with_phases(phases=[CAPELLA], other_phases=[DENEB]) @with_custom_state(balances_fn=misc_balances, threshold_fn=lambda spec: spec.config.EJECTION_BALANCE) @spec_test -@with_meta_tags(EIP4844_FORK_TEST_META_TAGS) +@with_meta_tags(DENEB_FORK_TEST_META_TAGS) def test_fork_random_misc_balances(spec, phases, state): - yield from run_fork_test(phases[EIP4844], state) + yield from run_fork_test(phases[DENEB], state) -@with_phases(phases=[CAPELLA], other_phases=[EIP4844]) +@with_phases(phases=[CAPELLA], other_phases=[DENEB]) @with_presets([MINIMAL], reason="mainnet config leads to larger validator set than limit of public/private keys pre-generated") @with_custom_state(balances_fn=large_validator_set, threshold_fn=lambda spec: spec.config.EJECTION_BALANCE) @spec_test -@with_meta_tags(EIP4844_FORK_TEST_META_TAGS) +@with_meta_tags(DENEB_FORK_TEST_META_TAGS) def test_fork_random_large_validator_set(spec, phases, state): - yield from run_fork_test(phases[EIP4844], state) + yield from run_fork_test(phases[DENEB], state) diff --git a/tests/core/pyspec/eth2spec/test/deneb/fork/test_deneb_fork_random.py b/tests/core/pyspec/eth2spec/test/deneb/fork/test_deneb_fork_random.py new file mode 100644 index 000000000..e88b63693 --- /dev/null +++ b/tests/core/pyspec/eth2spec/test/deneb/fork/test_deneb_fork_random.py @@ -0,0 +1,84 @@ +from random import Random + +from eth2spec.test.context import ( + with_phases, + with_custom_state, + with_presets, + spec_test, with_state, + low_balances, misc_balances, large_validator_set, +) +from eth2spec.test.utils import with_meta_tags +from eth2spec.test.helpers.constants import ( + CAPELLA, DENEB, + MINIMAL, +) +from eth2spec.test.helpers.deneb.fork import ( + DENEB_FORK_TEST_META_TAGS, + run_fork_test, +) +from eth2spec.test.helpers.random import randomize_state + + +@with_phases(phases=[CAPELLA], other_phases=[DENEB]) +@spec_test +@with_state +@with_meta_tags(DENEB_FORK_TEST_META_TAGS) +def test_deneb_fork_random_0(spec, phases, state): + randomize_state(spec, state, rng=Random(1010)) + yield from run_fork_test(phases[DENEB], state) + + +@with_phases(phases=[CAPELLA], other_phases=[DENEB]) +@spec_test +@with_state +@with_meta_tags(DENEB_FORK_TEST_META_TAGS) +def test_deneb_fork_random_1(spec, phases, state): + randomize_state(spec, state, rng=Random(2020)) + yield from run_fork_test(phases[DENEB], state) + + +@with_phases(phases=[CAPELLA], other_phases=[DENEB]) +@spec_test +@with_state +@with_meta_tags(DENEB_FORK_TEST_META_TAGS) +def test_deneb_fork_random_2(spec, phases, state): + randomize_state(spec, state, rng=Random(3030)) + yield from run_fork_test(phases[DENEB], state) + + +@with_phases(phases=[CAPELLA], other_phases=[DENEB]) +@spec_test +@with_state +@with_meta_tags(DENEB_FORK_TEST_META_TAGS) +def test_deneb_fork_random_3(spec, phases, state): + randomize_state(spec, state, rng=Random(4040)) + yield from run_fork_test(phases[DENEB], state) + + +@with_phases(phases=[CAPELLA], other_phases=[DENEB]) +@spec_test +@with_custom_state(balances_fn=low_balances, threshold_fn=lambda spec: spec.config.EJECTION_BALANCE) +@with_meta_tags(DENEB_FORK_TEST_META_TAGS) +def test_deneb_fork_random_low_balances(spec, phases, state): + randomize_state(spec, state, rng=Random(5050)) + yield from run_fork_test(phases[DENEB], state) + + +@with_phases(phases=[CAPELLA], other_phases=[DENEB]) +@spec_test +@with_custom_state(balances_fn=misc_balances, threshold_fn=lambda spec: spec.config.EJECTION_BALANCE) +@with_meta_tags(DENEB_FORK_TEST_META_TAGS) +def test_deneb_fork_random_misc_balances(spec, phases, state): + randomize_state(spec, state, rng=Random(6060)) + yield from run_fork_test(phases[DENEB], state) + + +@with_phases(phases=[CAPELLA], other_phases=[DENEB]) +@with_presets([MINIMAL], + reason="mainnet config leads to larger validator set than limit of public/private keys pre-generated") +@spec_test +@with_custom_state(balances_fn=large_validator_set, threshold_fn=lambda spec: spec.config.EJECTION_BALANCE) +@with_meta_tags(DENEB_FORK_TEST_META_TAGS) +def test_deneb_fork_random_large_validator_set(spec, phases, state): + randomize_state(spec, state, rng=Random(7070)) + yield from run_fork_test(phases[DENEB], state) diff --git a/tests/core/pyspec/eth2spec/test/eip4844/random/__init__.py b/tests/core/pyspec/eth2spec/test/deneb/random/__init__.py similarity index 100% rename from tests/core/pyspec/eth2spec/test/eip4844/random/__init__.py rename to tests/core/pyspec/eth2spec/test/deneb/random/__init__.py diff --git a/tests/core/pyspec/eth2spec/test/eip4844/random/test_random.py b/tests/core/pyspec/eth2spec/test/deneb/random/test_random.py similarity index 63% rename from tests/core/pyspec/eth2spec/test/eip4844/random/test_random.py rename to tests/core/pyspec/eth2spec/test/deneb/random/test_random.py index b90b858b2..e8c0a1bb1 100644 --- a/tests/core/pyspec/eth2spec/test/eip4844/random/test_random.py +++ b/tests/core/pyspec/eth2spec/test/deneb/random/test_random.py @@ -4,7 +4,7 @@ Please do not edit this file manually. See the README for that generator for more information. """ -from eth2spec.test.helpers.constants import EIP4844 +from eth2spec.test.helpers.constants import DENEB from eth2spec.test.context import ( misc_balances_in_default_range_with_many_validators, with_phases, @@ -23,7 +23,7 @@ from eth2spec.test.utils.randomized_block_tests import ( @only_generator("randomized test for broad coverage, not point-to-point CI") -@with_phases([EIP4844]) +@with_phases([DENEB]) @with_custom_state( balances_fn=misc_balances_in_default_range_with_many_validators, threshold_fn=zero_activation_threshold @@ -36,11 +36,11 @@ def test_randomized_0(spec, state): # epochs:0,slots:0,with-block:no_block # epochs:0,slots:0,with-block:no_block # epochs:0,slots:0,with-block:no_block - # epochs:0,slots:0,with-block:random_block_eip4844 + # epochs:0,slots:0,with-block:random_block_deneb # epochs:1,slots:0,with-block:no_block # epochs:0,slots:random_slot_in_epoch,with-block:no_block - # epochs:0,slots:0,with-block:random_block_eip4844 - scenario = {'transitions': [{'validation': 'validate_is_not_leaking', 'epochs_to_skip': 0, 'slots_to_skip': 0, 'block_producer': 'no_block'}, {'epochs_to_skip': 0, 'slots_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'slots_to_skip': 0, 'epochs_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'block_producer': 'random_block_eip4844', 'epochs_to_skip': 0, 'slots_to_skip': 0, 'validation': 'no_op_validation'}, {'epochs_to_skip': 1, 'slots_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'slots_to_skip': 'random_slot_in_epoch', 'epochs_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'block_producer': 'random_block_eip4844', 'epochs_to_skip': 0, 'slots_to_skip': 0, 'validation': 'no_op_validation'}], 'state_randomizer': 'randomize_state_eip4844'} # noqa: E501 + # epochs:0,slots:0,with-block:random_block_deneb + scenario = {'transitions': [{'validation': 'validate_is_not_leaking', 'epochs_to_skip': 0, 'slots_to_skip': 0, 'block_producer': 'no_block'}, {'epochs_to_skip': 0, 'slots_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'slots_to_skip': 0, 'epochs_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'block_producer': 'random_block_deneb', 'epochs_to_skip': 0, 'slots_to_skip': 0, 'validation': 'no_op_validation'}, {'epochs_to_skip': 1, 'slots_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'slots_to_skip': 'random_slot_in_epoch', 'epochs_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'block_producer': 'random_block_deneb', 'epochs_to_skip': 0, 'slots_to_skip': 0, 'validation': 'no_op_validation'}], 'state_randomizer': 'randomize_state_deneb'} # noqa: E501 yield from run_generated_randomized_test( spec, state, @@ -49,7 +49,7 @@ def test_randomized_0(spec, state): @only_generator("randomized test for broad coverage, not point-to-point CI") -@with_phases([EIP4844]) +@with_phases([DENEB]) @with_custom_state( balances_fn=misc_balances_in_default_range_with_many_validators, threshold_fn=zero_activation_threshold @@ -62,11 +62,11 @@ def test_randomized_1(spec, state): # epochs:0,slots:0,with-block:no_block # epochs:1,slots:0,with-block:no_block # epochs:0,slots:random_slot_in_epoch,with-block:no_block - # epochs:0,slots:0,with-block:random_block_eip4844 + # epochs:0,slots:0,with-block:random_block_deneb # epochs:0,slots:0,with-block:no_block # epochs:0,slots:0,with-block:no_block - # epochs:0,slots:0,with-block:random_block_eip4844 - scenario = {'transitions': [{'validation': 'validate_is_not_leaking', 'epochs_to_skip': 0, 'slots_to_skip': 0, 'block_producer': 'no_block'}, {'epochs_to_skip': 1, 'slots_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'slots_to_skip': 'random_slot_in_epoch', 'epochs_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'block_producer': 'random_block_eip4844', 'epochs_to_skip': 0, 'slots_to_skip': 0, 'validation': 'no_op_validation'}, {'epochs_to_skip': 0, 'slots_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'slots_to_skip': 0, 'epochs_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'block_producer': 'random_block_eip4844', 'epochs_to_skip': 0, 'slots_to_skip': 0, 'validation': 'no_op_validation'}], 'state_randomizer': 'randomize_state_eip4844'} # noqa: E501 + # epochs:0,slots:0,with-block:random_block_deneb + scenario = {'transitions': [{'validation': 'validate_is_not_leaking', 'epochs_to_skip': 0, 'slots_to_skip': 0, 'block_producer': 'no_block'}, {'epochs_to_skip': 1, 'slots_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'slots_to_skip': 'random_slot_in_epoch', 'epochs_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'block_producer': 'random_block_deneb', 'epochs_to_skip': 0, 'slots_to_skip': 0, 'validation': 'no_op_validation'}, {'epochs_to_skip': 0, 'slots_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'slots_to_skip': 0, 'epochs_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'block_producer': 'random_block_deneb', 'epochs_to_skip': 0, 'slots_to_skip': 0, 'validation': 'no_op_validation'}], 'state_randomizer': 'randomize_state_deneb'} # noqa: E501 yield from run_generated_randomized_test( spec, state, @@ -75,7 +75,7 @@ def test_randomized_1(spec, state): @only_generator("randomized test for broad coverage, not point-to-point CI") -@with_phases([EIP4844]) +@with_phases([DENEB]) @with_custom_state( balances_fn=misc_balances_in_default_range_with_many_validators, threshold_fn=zero_activation_threshold @@ -88,11 +88,11 @@ def test_randomized_2(spec, state): # epochs:0,slots:0,with-block:no_block # epochs:0,slots:0,with-block:no_block # epochs:0,slots:penultimate_slot_in_epoch,with-block:no_block - # epochs:0,slots:0,with-block:random_block_eip4844 + # epochs:0,slots:0,with-block:random_block_deneb # epochs:0,slots:0,with-block:no_block # epochs:0,slots:last_slot_in_epoch,with-block:no_block - # epochs:0,slots:0,with-block:random_block_eip4844 - scenario = {'transitions': [{'validation': 'validate_is_not_leaking', 'epochs_to_skip': 0, 'slots_to_skip': 0, 'block_producer': 'no_block'}, {'epochs_to_skip': 0, 'slots_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'slots_to_skip': 'penultimate_slot_in_epoch', 'epochs_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'block_producer': 'random_block_eip4844', 'epochs_to_skip': 0, 'slots_to_skip': 0, 'validation': 'no_op_validation'}, {'epochs_to_skip': 0, 'slots_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'slots_to_skip': 'last_slot_in_epoch', 'epochs_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'block_producer': 'random_block_eip4844', 'epochs_to_skip': 0, 'slots_to_skip': 0, 'validation': 'no_op_validation'}], 'state_randomizer': 'randomize_state_eip4844'} # noqa: E501 + # epochs:0,slots:0,with-block:random_block_deneb + scenario = {'transitions': [{'validation': 'validate_is_not_leaking', 'epochs_to_skip': 0, 'slots_to_skip': 0, 'block_producer': 'no_block'}, {'epochs_to_skip': 0, 'slots_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'slots_to_skip': 'penultimate_slot_in_epoch', 'epochs_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'block_producer': 'random_block_deneb', 'epochs_to_skip': 0, 'slots_to_skip': 0, 'validation': 'no_op_validation'}, {'epochs_to_skip': 0, 'slots_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'slots_to_skip': 'last_slot_in_epoch', 'epochs_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'block_producer': 'random_block_deneb', 'epochs_to_skip': 0, 'slots_to_skip': 0, 'validation': 'no_op_validation'}], 'state_randomizer': 'randomize_state_deneb'} # noqa: E501 yield from run_generated_randomized_test( spec, state, @@ -101,7 +101,7 @@ def test_randomized_2(spec, state): @only_generator("randomized test for broad coverage, not point-to-point CI") -@with_phases([EIP4844]) +@with_phases([DENEB]) @with_custom_state( balances_fn=misc_balances_in_default_range_with_many_validators, threshold_fn=zero_activation_threshold @@ -114,11 +114,11 @@ def test_randomized_3(spec, state): # epochs:0,slots:0,with-block:no_block # epochs:0,slots:0,with-block:no_block # epochs:0,slots:last_slot_in_epoch,with-block:no_block - # epochs:0,slots:0,with-block:random_block_eip4844 + # epochs:0,slots:0,with-block:random_block_deneb # epochs:1,slots:0,with-block:no_block # epochs:0,slots:last_slot_in_epoch,with-block:no_block - # epochs:0,slots:0,with-block:random_block_eip4844 - scenario = {'transitions': [{'validation': 'validate_is_not_leaking', 'epochs_to_skip': 0, 'slots_to_skip': 0, 'block_producer': 'no_block'}, {'epochs_to_skip': 0, 'slots_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'slots_to_skip': 'last_slot_in_epoch', 'epochs_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'block_producer': 'random_block_eip4844', 'epochs_to_skip': 0, 'slots_to_skip': 0, 'validation': 'no_op_validation'}, {'epochs_to_skip': 1, 'slots_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'slots_to_skip': 'last_slot_in_epoch', 'epochs_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'block_producer': 'random_block_eip4844', 'epochs_to_skip': 0, 'slots_to_skip': 0, 'validation': 'no_op_validation'}], 'state_randomizer': 'randomize_state_eip4844'} # noqa: E501 + # epochs:0,slots:0,with-block:random_block_deneb + scenario = {'transitions': [{'validation': 'validate_is_not_leaking', 'epochs_to_skip': 0, 'slots_to_skip': 0, 'block_producer': 'no_block'}, {'epochs_to_skip': 0, 'slots_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'slots_to_skip': 'last_slot_in_epoch', 'epochs_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'block_producer': 'random_block_deneb', 'epochs_to_skip': 0, 'slots_to_skip': 0, 'validation': 'no_op_validation'}, {'epochs_to_skip': 1, 'slots_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'slots_to_skip': 'last_slot_in_epoch', 'epochs_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'block_producer': 'random_block_deneb', 'epochs_to_skip': 0, 'slots_to_skip': 0, 'validation': 'no_op_validation'}], 'state_randomizer': 'randomize_state_deneb'} # noqa: E501 yield from run_generated_randomized_test( spec, state, @@ -127,7 +127,7 @@ def test_randomized_3(spec, state): @only_generator("randomized test for broad coverage, not point-to-point CI") -@with_phases([EIP4844]) +@with_phases([DENEB]) @with_custom_state( balances_fn=misc_balances_in_default_range_with_many_validators, threshold_fn=zero_activation_threshold @@ -140,11 +140,11 @@ def test_randomized_4(spec, state): # epochs:0,slots:0,with-block:no_block # epochs:1,slots:0,with-block:no_block # epochs:0,slots:last_slot_in_epoch,with-block:no_block - # epochs:0,slots:0,with-block:random_block_eip4844 + # epochs:0,slots:0,with-block:random_block_deneb # epochs:1,slots:0,with-block:no_block # epochs:0,slots:penultimate_slot_in_epoch,with-block:no_block - # epochs:0,slots:0,with-block:random_block_eip4844 - scenario = {'transitions': [{'validation': 'validate_is_not_leaking', 'epochs_to_skip': 0, 'slots_to_skip': 0, 'block_producer': 'no_block'}, {'epochs_to_skip': 1, 'slots_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'slots_to_skip': 'last_slot_in_epoch', 'epochs_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'block_producer': 'random_block_eip4844', 'epochs_to_skip': 0, 'slots_to_skip': 0, 'validation': 'no_op_validation'}, {'epochs_to_skip': 1, 'slots_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'slots_to_skip': 'penultimate_slot_in_epoch', 'epochs_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'block_producer': 'random_block_eip4844', 'epochs_to_skip': 0, 'slots_to_skip': 0, 'validation': 'no_op_validation'}], 'state_randomizer': 'randomize_state_eip4844'} # noqa: E501 + # epochs:0,slots:0,with-block:random_block_deneb + scenario = {'transitions': [{'validation': 'validate_is_not_leaking', 'epochs_to_skip': 0, 'slots_to_skip': 0, 'block_producer': 'no_block'}, {'epochs_to_skip': 1, 'slots_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'slots_to_skip': 'last_slot_in_epoch', 'epochs_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'block_producer': 'random_block_deneb', 'epochs_to_skip': 0, 'slots_to_skip': 0, 'validation': 'no_op_validation'}, {'epochs_to_skip': 1, 'slots_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'slots_to_skip': 'penultimate_slot_in_epoch', 'epochs_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'block_producer': 'random_block_deneb', 'epochs_to_skip': 0, 'slots_to_skip': 0, 'validation': 'no_op_validation'}], 'state_randomizer': 'randomize_state_deneb'} # noqa: E501 yield from run_generated_randomized_test( spec, state, @@ -153,7 +153,7 @@ def test_randomized_4(spec, state): @only_generator("randomized test for broad coverage, not point-to-point CI") -@with_phases([EIP4844]) +@with_phases([DENEB]) @with_custom_state( balances_fn=misc_balances_in_default_range_with_many_validators, threshold_fn=zero_activation_threshold @@ -166,11 +166,11 @@ def test_randomized_5(spec, state): # epochs:0,slots:0,with-block:no_block # epochs:0,slots:0,with-block:no_block # epochs:0,slots:random_slot_in_epoch,with-block:no_block - # epochs:0,slots:0,with-block:random_block_eip4844 + # epochs:0,slots:0,with-block:random_block_deneb # epochs:0,slots:0,with-block:no_block # epochs:0,slots:random_slot_in_epoch,with-block:no_block - # epochs:0,slots:0,with-block:random_block_eip4844 - scenario = {'transitions': [{'validation': 'validate_is_not_leaking', 'epochs_to_skip': 0, 'slots_to_skip': 0, 'block_producer': 'no_block'}, {'epochs_to_skip': 0, 'slots_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'slots_to_skip': 'random_slot_in_epoch', 'epochs_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'block_producer': 'random_block_eip4844', 'epochs_to_skip': 0, 'slots_to_skip': 0, 'validation': 'no_op_validation'}, {'epochs_to_skip': 0, 'slots_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'slots_to_skip': 'random_slot_in_epoch', 'epochs_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'block_producer': 'random_block_eip4844', 'epochs_to_skip': 0, 'slots_to_skip': 0, 'validation': 'no_op_validation'}], 'state_randomizer': 'randomize_state_eip4844'} # noqa: E501 + # epochs:0,slots:0,with-block:random_block_deneb + scenario = {'transitions': [{'validation': 'validate_is_not_leaking', 'epochs_to_skip': 0, 'slots_to_skip': 0, 'block_producer': 'no_block'}, {'epochs_to_skip': 0, 'slots_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'slots_to_skip': 'random_slot_in_epoch', 'epochs_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'block_producer': 'random_block_deneb', 'epochs_to_skip': 0, 'slots_to_skip': 0, 'validation': 'no_op_validation'}, {'epochs_to_skip': 0, 'slots_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'slots_to_skip': 'random_slot_in_epoch', 'epochs_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'block_producer': 'random_block_deneb', 'epochs_to_skip': 0, 'slots_to_skip': 0, 'validation': 'no_op_validation'}], 'state_randomizer': 'randomize_state_deneb'} # noqa: E501 yield from run_generated_randomized_test( spec, state, @@ -179,7 +179,7 @@ def test_randomized_5(spec, state): @only_generator("randomized test for broad coverage, not point-to-point CI") -@with_phases([EIP4844]) +@with_phases([DENEB]) @with_custom_state( balances_fn=misc_balances_in_default_range_with_many_validators, threshold_fn=zero_activation_threshold @@ -192,11 +192,11 @@ def test_randomized_6(spec, state): # epochs:0,slots:0,with-block:no_block # epochs:1,slots:0,with-block:no_block # epochs:0,slots:penultimate_slot_in_epoch,with-block:no_block - # epochs:0,slots:0,with-block:random_block_eip4844 + # epochs:0,slots:0,with-block:random_block_deneb # epochs:0,slots:0,with-block:no_block # epochs:0,slots:penultimate_slot_in_epoch,with-block:no_block - # epochs:0,slots:0,with-block:random_block_eip4844 - scenario = {'transitions': [{'validation': 'validate_is_not_leaking', 'epochs_to_skip': 0, 'slots_to_skip': 0, 'block_producer': 'no_block'}, {'epochs_to_skip': 1, 'slots_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'slots_to_skip': 'penultimate_slot_in_epoch', 'epochs_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'block_producer': 'random_block_eip4844', 'epochs_to_skip': 0, 'slots_to_skip': 0, 'validation': 'no_op_validation'}, {'epochs_to_skip': 0, 'slots_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'slots_to_skip': 'penultimate_slot_in_epoch', 'epochs_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'block_producer': 'random_block_eip4844', 'epochs_to_skip': 0, 'slots_to_skip': 0, 'validation': 'no_op_validation'}], 'state_randomizer': 'randomize_state_eip4844'} # noqa: E501 + # epochs:0,slots:0,with-block:random_block_deneb + scenario = {'transitions': [{'validation': 'validate_is_not_leaking', 'epochs_to_skip': 0, 'slots_to_skip': 0, 'block_producer': 'no_block'}, {'epochs_to_skip': 1, 'slots_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'slots_to_skip': 'penultimate_slot_in_epoch', 'epochs_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'block_producer': 'random_block_deneb', 'epochs_to_skip': 0, 'slots_to_skip': 0, 'validation': 'no_op_validation'}, {'epochs_to_skip': 0, 'slots_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'slots_to_skip': 'penultimate_slot_in_epoch', 'epochs_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'block_producer': 'random_block_deneb', 'epochs_to_skip': 0, 'slots_to_skip': 0, 'validation': 'no_op_validation'}], 'state_randomizer': 'randomize_state_deneb'} # noqa: E501 yield from run_generated_randomized_test( spec, state, @@ -205,7 +205,7 @@ def test_randomized_6(spec, state): @only_generator("randomized test for broad coverage, not point-to-point CI") -@with_phases([EIP4844]) +@with_phases([DENEB]) @with_custom_state( balances_fn=misc_balances_in_default_range_with_many_validators, threshold_fn=zero_activation_threshold @@ -218,11 +218,11 @@ def test_randomized_7(spec, state): # epochs:0,slots:0,with-block:no_block # epochs:1,slots:0,with-block:no_block # epochs:0,slots:0,with-block:no_block - # epochs:0,slots:0,with-block:random_block_eip4844 + # epochs:0,slots:0,with-block:random_block_deneb # epochs:1,slots:0,with-block:no_block # epochs:0,slots:0,with-block:no_block - # epochs:0,slots:0,with-block:random_block_eip4844 - scenario = {'transitions': [{'validation': 'validate_is_not_leaking', 'epochs_to_skip': 0, 'slots_to_skip': 0, 'block_producer': 'no_block'}, {'epochs_to_skip': 1, 'slots_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'slots_to_skip': 0, 'epochs_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'block_producer': 'random_block_eip4844', 'epochs_to_skip': 0, 'slots_to_skip': 0, 'validation': 'no_op_validation'}, {'epochs_to_skip': 1, 'slots_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'slots_to_skip': 0, 'epochs_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'block_producer': 'random_block_eip4844', 'epochs_to_skip': 0, 'slots_to_skip': 0, 'validation': 'no_op_validation'}], 'state_randomizer': 'randomize_state_eip4844'} # noqa: E501 + # epochs:0,slots:0,with-block:random_block_deneb + scenario = {'transitions': [{'validation': 'validate_is_not_leaking', 'epochs_to_skip': 0, 'slots_to_skip': 0, 'block_producer': 'no_block'}, {'epochs_to_skip': 1, 'slots_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'slots_to_skip': 0, 'epochs_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'block_producer': 'random_block_deneb', 'epochs_to_skip': 0, 'slots_to_skip': 0, 'validation': 'no_op_validation'}, {'epochs_to_skip': 1, 'slots_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'slots_to_skip': 0, 'epochs_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'block_producer': 'random_block_deneb', 'epochs_to_skip': 0, 'slots_to_skip': 0, 'validation': 'no_op_validation'}], 'state_randomizer': 'randomize_state_deneb'} # noqa: E501 yield from run_generated_randomized_test( spec, state, @@ -231,7 +231,7 @@ def test_randomized_7(spec, state): @only_generator("randomized test for broad coverage, not point-to-point CI") -@with_phases([EIP4844]) +@with_phases([DENEB]) @with_custom_state( balances_fn=misc_balances_in_default_range_with_many_validators, threshold_fn=zero_activation_threshold @@ -244,11 +244,11 @@ def test_randomized_8(spec, state): # epochs:epochs_until_leak,slots:0,with-block:no_block # epochs:0,slots:0,with-block:no_block # epochs:0,slots:0,with-block:no_block - # epochs:0,slots:0,with-block:random_block_eip4844 + # epochs:0,slots:0,with-block:random_block_deneb # epochs:1,slots:0,with-block:no_block # epochs:0,slots:random_slot_in_epoch,with-block:no_block - # epochs:0,slots:0,with-block:random_block_eip4844 - scenario = {'transitions': [{'epochs_to_skip': 'epochs_until_leak', 'validation': 'validate_is_leaking', 'slots_to_skip': 0, 'block_producer': 'no_block'}, {'epochs_to_skip': 0, 'slots_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'slots_to_skip': 0, 'epochs_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'block_producer': 'random_block_eip4844', 'epochs_to_skip': 0, 'slots_to_skip': 0, 'validation': 'no_op_validation'}, {'epochs_to_skip': 1, 'slots_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'slots_to_skip': 'random_slot_in_epoch', 'epochs_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'block_producer': 'random_block_eip4844', 'epochs_to_skip': 0, 'slots_to_skip': 0, 'validation': 'no_op_validation'}], 'state_randomizer': 'randomize_state_eip4844'} # noqa: E501 + # epochs:0,slots:0,with-block:random_block_deneb + scenario = {'transitions': [{'epochs_to_skip': 'epochs_until_leak', 'validation': 'validate_is_leaking', 'slots_to_skip': 0, 'block_producer': 'no_block'}, {'epochs_to_skip': 0, 'slots_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'slots_to_skip': 0, 'epochs_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'block_producer': 'random_block_deneb', 'epochs_to_skip': 0, 'slots_to_skip': 0, 'validation': 'no_op_validation'}, {'epochs_to_skip': 1, 'slots_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'slots_to_skip': 'random_slot_in_epoch', 'epochs_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'block_producer': 'random_block_deneb', 'epochs_to_skip': 0, 'slots_to_skip': 0, 'validation': 'no_op_validation'}], 'state_randomizer': 'randomize_state_deneb'} # noqa: E501 yield from run_generated_randomized_test( spec, state, @@ -257,7 +257,7 @@ def test_randomized_8(spec, state): @only_generator("randomized test for broad coverage, not point-to-point CI") -@with_phases([EIP4844]) +@with_phases([DENEB]) @with_custom_state( balances_fn=misc_balances_in_default_range_with_many_validators, threshold_fn=zero_activation_threshold @@ -270,11 +270,11 @@ def test_randomized_9(spec, state): # epochs:epochs_until_leak,slots:0,with-block:no_block # epochs:1,slots:0,with-block:no_block # epochs:0,slots:random_slot_in_epoch,with-block:no_block - # epochs:0,slots:0,with-block:random_block_eip4844 + # epochs:0,slots:0,with-block:random_block_deneb # epochs:0,slots:0,with-block:no_block # epochs:0,slots:0,with-block:no_block - # epochs:0,slots:0,with-block:random_block_eip4844 - scenario = {'transitions': [{'epochs_to_skip': 'epochs_until_leak', 'validation': 'validate_is_leaking', 'slots_to_skip': 0, 'block_producer': 'no_block'}, {'epochs_to_skip': 1, 'slots_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'slots_to_skip': 'random_slot_in_epoch', 'epochs_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'block_producer': 'random_block_eip4844', 'epochs_to_skip': 0, 'slots_to_skip': 0, 'validation': 'no_op_validation'}, {'epochs_to_skip': 0, 'slots_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'slots_to_skip': 0, 'epochs_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'block_producer': 'random_block_eip4844', 'epochs_to_skip': 0, 'slots_to_skip': 0, 'validation': 'no_op_validation'}], 'state_randomizer': 'randomize_state_eip4844'} # noqa: E501 + # epochs:0,slots:0,with-block:random_block_deneb + scenario = {'transitions': [{'epochs_to_skip': 'epochs_until_leak', 'validation': 'validate_is_leaking', 'slots_to_skip': 0, 'block_producer': 'no_block'}, {'epochs_to_skip': 1, 'slots_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'slots_to_skip': 'random_slot_in_epoch', 'epochs_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'block_producer': 'random_block_deneb', 'epochs_to_skip': 0, 'slots_to_skip': 0, 'validation': 'no_op_validation'}, {'epochs_to_skip': 0, 'slots_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'slots_to_skip': 0, 'epochs_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'block_producer': 'random_block_deneb', 'epochs_to_skip': 0, 'slots_to_skip': 0, 'validation': 'no_op_validation'}], 'state_randomizer': 'randomize_state_deneb'} # noqa: E501 yield from run_generated_randomized_test( spec, state, @@ -283,7 +283,7 @@ def test_randomized_9(spec, state): @only_generator("randomized test for broad coverage, not point-to-point CI") -@with_phases([EIP4844]) +@with_phases([DENEB]) @with_custom_state( balances_fn=misc_balances_in_default_range_with_many_validators, threshold_fn=zero_activation_threshold @@ -296,11 +296,11 @@ def test_randomized_10(spec, state): # epochs:epochs_until_leak,slots:0,with-block:no_block # epochs:0,slots:0,with-block:no_block # epochs:0,slots:penultimate_slot_in_epoch,with-block:no_block - # epochs:0,slots:0,with-block:random_block_eip4844 + # epochs:0,slots:0,with-block:random_block_deneb # epochs:0,slots:0,with-block:no_block # epochs:0,slots:last_slot_in_epoch,with-block:no_block - # epochs:0,slots:0,with-block:random_block_eip4844 - scenario = {'transitions': [{'epochs_to_skip': 'epochs_until_leak', 'validation': 'validate_is_leaking', 'slots_to_skip': 0, 'block_producer': 'no_block'}, {'epochs_to_skip': 0, 'slots_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'slots_to_skip': 'penultimate_slot_in_epoch', 'epochs_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'block_producer': 'random_block_eip4844', 'epochs_to_skip': 0, 'slots_to_skip': 0, 'validation': 'no_op_validation'}, {'epochs_to_skip': 0, 'slots_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'slots_to_skip': 'last_slot_in_epoch', 'epochs_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'block_producer': 'random_block_eip4844', 'epochs_to_skip': 0, 'slots_to_skip': 0, 'validation': 'no_op_validation'}], 'state_randomizer': 'randomize_state_eip4844'} # noqa: E501 + # epochs:0,slots:0,with-block:random_block_deneb + scenario = {'transitions': [{'epochs_to_skip': 'epochs_until_leak', 'validation': 'validate_is_leaking', 'slots_to_skip': 0, 'block_producer': 'no_block'}, {'epochs_to_skip': 0, 'slots_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'slots_to_skip': 'penultimate_slot_in_epoch', 'epochs_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'block_producer': 'random_block_deneb', 'epochs_to_skip': 0, 'slots_to_skip': 0, 'validation': 'no_op_validation'}, {'epochs_to_skip': 0, 'slots_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'slots_to_skip': 'last_slot_in_epoch', 'epochs_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'block_producer': 'random_block_deneb', 'epochs_to_skip': 0, 'slots_to_skip': 0, 'validation': 'no_op_validation'}], 'state_randomizer': 'randomize_state_deneb'} # noqa: E501 yield from run_generated_randomized_test( spec, state, @@ -309,7 +309,7 @@ def test_randomized_10(spec, state): @only_generator("randomized test for broad coverage, not point-to-point CI") -@with_phases([EIP4844]) +@with_phases([DENEB]) @with_custom_state( balances_fn=misc_balances_in_default_range_with_many_validators, threshold_fn=zero_activation_threshold @@ -322,11 +322,11 @@ def test_randomized_11(spec, state): # epochs:epochs_until_leak,slots:0,with-block:no_block # epochs:0,slots:0,with-block:no_block # epochs:0,slots:last_slot_in_epoch,with-block:no_block - # epochs:0,slots:0,with-block:random_block_eip4844 + # epochs:0,slots:0,with-block:random_block_deneb # epochs:1,slots:0,with-block:no_block # epochs:0,slots:last_slot_in_epoch,with-block:no_block - # epochs:0,slots:0,with-block:random_block_eip4844 - scenario = {'transitions': [{'epochs_to_skip': 'epochs_until_leak', 'validation': 'validate_is_leaking', 'slots_to_skip': 0, 'block_producer': 'no_block'}, {'epochs_to_skip': 0, 'slots_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'slots_to_skip': 'last_slot_in_epoch', 'epochs_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'block_producer': 'random_block_eip4844', 'epochs_to_skip': 0, 'slots_to_skip': 0, 'validation': 'no_op_validation'}, {'epochs_to_skip': 1, 'slots_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'slots_to_skip': 'last_slot_in_epoch', 'epochs_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'block_producer': 'random_block_eip4844', 'epochs_to_skip': 0, 'slots_to_skip': 0, 'validation': 'no_op_validation'}], 'state_randomizer': 'randomize_state_eip4844'} # noqa: E501 + # epochs:0,slots:0,with-block:random_block_deneb + scenario = {'transitions': [{'epochs_to_skip': 'epochs_until_leak', 'validation': 'validate_is_leaking', 'slots_to_skip': 0, 'block_producer': 'no_block'}, {'epochs_to_skip': 0, 'slots_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'slots_to_skip': 'last_slot_in_epoch', 'epochs_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'block_producer': 'random_block_deneb', 'epochs_to_skip': 0, 'slots_to_skip': 0, 'validation': 'no_op_validation'}, {'epochs_to_skip': 1, 'slots_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'slots_to_skip': 'last_slot_in_epoch', 'epochs_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'block_producer': 'random_block_deneb', 'epochs_to_skip': 0, 'slots_to_skip': 0, 'validation': 'no_op_validation'}], 'state_randomizer': 'randomize_state_deneb'} # noqa: E501 yield from run_generated_randomized_test( spec, state, @@ -335,7 +335,7 @@ def test_randomized_11(spec, state): @only_generator("randomized test for broad coverage, not point-to-point CI") -@with_phases([EIP4844]) +@with_phases([DENEB]) @with_custom_state( balances_fn=misc_balances_in_default_range_with_many_validators, threshold_fn=zero_activation_threshold @@ -348,11 +348,11 @@ def test_randomized_12(spec, state): # epochs:epochs_until_leak,slots:0,with-block:no_block # epochs:1,slots:0,with-block:no_block # epochs:0,slots:last_slot_in_epoch,with-block:no_block - # epochs:0,slots:0,with-block:random_block_eip4844 + # epochs:0,slots:0,with-block:random_block_deneb # epochs:1,slots:0,with-block:no_block # epochs:0,slots:penultimate_slot_in_epoch,with-block:no_block - # epochs:0,slots:0,with-block:random_block_eip4844 - scenario = {'transitions': [{'epochs_to_skip': 'epochs_until_leak', 'validation': 'validate_is_leaking', 'slots_to_skip': 0, 'block_producer': 'no_block'}, {'epochs_to_skip': 1, 'slots_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'slots_to_skip': 'last_slot_in_epoch', 'epochs_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'block_producer': 'random_block_eip4844', 'epochs_to_skip': 0, 'slots_to_skip': 0, 'validation': 'no_op_validation'}, {'epochs_to_skip': 1, 'slots_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'slots_to_skip': 'penultimate_slot_in_epoch', 'epochs_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'block_producer': 'random_block_eip4844', 'epochs_to_skip': 0, 'slots_to_skip': 0, 'validation': 'no_op_validation'}], 'state_randomizer': 'randomize_state_eip4844'} # noqa: E501 + # epochs:0,slots:0,with-block:random_block_deneb + scenario = {'transitions': [{'epochs_to_skip': 'epochs_until_leak', 'validation': 'validate_is_leaking', 'slots_to_skip': 0, 'block_producer': 'no_block'}, {'epochs_to_skip': 1, 'slots_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'slots_to_skip': 'last_slot_in_epoch', 'epochs_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'block_producer': 'random_block_deneb', 'epochs_to_skip': 0, 'slots_to_skip': 0, 'validation': 'no_op_validation'}, {'epochs_to_skip': 1, 'slots_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'slots_to_skip': 'penultimate_slot_in_epoch', 'epochs_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'block_producer': 'random_block_deneb', 'epochs_to_skip': 0, 'slots_to_skip': 0, 'validation': 'no_op_validation'}], 'state_randomizer': 'randomize_state_deneb'} # noqa: E501 yield from run_generated_randomized_test( spec, state, @@ -361,7 +361,7 @@ def test_randomized_12(spec, state): @only_generator("randomized test for broad coverage, not point-to-point CI") -@with_phases([EIP4844]) +@with_phases([DENEB]) @with_custom_state( balances_fn=misc_balances_in_default_range_with_many_validators, threshold_fn=zero_activation_threshold @@ -374,11 +374,11 @@ def test_randomized_13(spec, state): # epochs:epochs_until_leak,slots:0,with-block:no_block # epochs:0,slots:0,with-block:no_block # epochs:0,slots:random_slot_in_epoch,with-block:no_block - # epochs:0,slots:0,with-block:random_block_eip4844 + # epochs:0,slots:0,with-block:random_block_deneb # epochs:0,slots:0,with-block:no_block # epochs:0,slots:random_slot_in_epoch,with-block:no_block - # epochs:0,slots:0,with-block:random_block_eip4844 - scenario = {'transitions': [{'epochs_to_skip': 'epochs_until_leak', 'validation': 'validate_is_leaking', 'slots_to_skip': 0, 'block_producer': 'no_block'}, {'epochs_to_skip': 0, 'slots_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'slots_to_skip': 'random_slot_in_epoch', 'epochs_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'block_producer': 'random_block_eip4844', 'epochs_to_skip': 0, 'slots_to_skip': 0, 'validation': 'no_op_validation'}, {'epochs_to_skip': 0, 'slots_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'slots_to_skip': 'random_slot_in_epoch', 'epochs_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'block_producer': 'random_block_eip4844', 'epochs_to_skip': 0, 'slots_to_skip': 0, 'validation': 'no_op_validation'}], 'state_randomizer': 'randomize_state_eip4844'} # noqa: E501 + # epochs:0,slots:0,with-block:random_block_deneb + scenario = {'transitions': [{'epochs_to_skip': 'epochs_until_leak', 'validation': 'validate_is_leaking', 'slots_to_skip': 0, 'block_producer': 'no_block'}, {'epochs_to_skip': 0, 'slots_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'slots_to_skip': 'random_slot_in_epoch', 'epochs_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'block_producer': 'random_block_deneb', 'epochs_to_skip': 0, 'slots_to_skip': 0, 'validation': 'no_op_validation'}, {'epochs_to_skip': 0, 'slots_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'slots_to_skip': 'random_slot_in_epoch', 'epochs_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'block_producer': 'random_block_deneb', 'epochs_to_skip': 0, 'slots_to_skip': 0, 'validation': 'no_op_validation'}], 'state_randomizer': 'randomize_state_deneb'} # noqa: E501 yield from run_generated_randomized_test( spec, state, @@ -387,7 +387,7 @@ def test_randomized_13(spec, state): @only_generator("randomized test for broad coverage, not point-to-point CI") -@with_phases([EIP4844]) +@with_phases([DENEB]) @with_custom_state( balances_fn=misc_balances_in_default_range_with_many_validators, threshold_fn=zero_activation_threshold @@ -400,11 +400,11 @@ def test_randomized_14(spec, state): # epochs:epochs_until_leak,slots:0,with-block:no_block # epochs:1,slots:0,with-block:no_block # epochs:0,slots:penultimate_slot_in_epoch,with-block:no_block - # epochs:0,slots:0,with-block:random_block_eip4844 + # epochs:0,slots:0,with-block:random_block_deneb # epochs:0,slots:0,with-block:no_block # epochs:0,slots:penultimate_slot_in_epoch,with-block:no_block - # epochs:0,slots:0,with-block:random_block_eip4844 - scenario = {'transitions': [{'epochs_to_skip': 'epochs_until_leak', 'validation': 'validate_is_leaking', 'slots_to_skip': 0, 'block_producer': 'no_block'}, {'epochs_to_skip': 1, 'slots_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'slots_to_skip': 'penultimate_slot_in_epoch', 'epochs_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'block_producer': 'random_block_eip4844', 'epochs_to_skip': 0, 'slots_to_skip': 0, 'validation': 'no_op_validation'}, {'epochs_to_skip': 0, 'slots_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'slots_to_skip': 'penultimate_slot_in_epoch', 'epochs_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'block_producer': 'random_block_eip4844', 'epochs_to_skip': 0, 'slots_to_skip': 0, 'validation': 'no_op_validation'}], 'state_randomizer': 'randomize_state_eip4844'} # noqa: E501 + # epochs:0,slots:0,with-block:random_block_deneb + scenario = {'transitions': [{'epochs_to_skip': 'epochs_until_leak', 'validation': 'validate_is_leaking', 'slots_to_skip': 0, 'block_producer': 'no_block'}, {'epochs_to_skip': 1, 'slots_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'slots_to_skip': 'penultimate_slot_in_epoch', 'epochs_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'block_producer': 'random_block_deneb', 'epochs_to_skip': 0, 'slots_to_skip': 0, 'validation': 'no_op_validation'}, {'epochs_to_skip': 0, 'slots_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'slots_to_skip': 'penultimate_slot_in_epoch', 'epochs_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'block_producer': 'random_block_deneb', 'epochs_to_skip': 0, 'slots_to_skip': 0, 'validation': 'no_op_validation'}], 'state_randomizer': 'randomize_state_deneb'} # noqa: E501 yield from run_generated_randomized_test( spec, state, @@ -413,7 +413,7 @@ def test_randomized_14(spec, state): @only_generator("randomized test for broad coverage, not point-to-point CI") -@with_phases([EIP4844]) +@with_phases([DENEB]) @with_custom_state( balances_fn=misc_balances_in_default_range_with_many_validators, threshold_fn=zero_activation_threshold @@ -426,11 +426,11 @@ def test_randomized_15(spec, state): # epochs:epochs_until_leak,slots:0,with-block:no_block # epochs:1,slots:0,with-block:no_block # epochs:0,slots:0,with-block:no_block - # epochs:0,slots:0,with-block:random_block_eip4844 + # epochs:0,slots:0,with-block:random_block_deneb # epochs:1,slots:0,with-block:no_block # epochs:0,slots:0,with-block:no_block - # epochs:0,slots:0,with-block:random_block_eip4844 - scenario = {'transitions': [{'epochs_to_skip': 'epochs_until_leak', 'validation': 'validate_is_leaking', 'slots_to_skip': 0, 'block_producer': 'no_block'}, {'epochs_to_skip': 1, 'slots_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'slots_to_skip': 0, 'epochs_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'block_producer': 'random_block_eip4844', 'epochs_to_skip': 0, 'slots_to_skip': 0, 'validation': 'no_op_validation'}, {'epochs_to_skip': 1, 'slots_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'slots_to_skip': 0, 'epochs_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'block_producer': 'random_block_eip4844', 'epochs_to_skip': 0, 'slots_to_skip': 0, 'validation': 'no_op_validation'}], 'state_randomizer': 'randomize_state_eip4844'} # noqa: E501 + # epochs:0,slots:0,with-block:random_block_deneb + scenario = {'transitions': [{'epochs_to_skip': 'epochs_until_leak', 'validation': 'validate_is_leaking', 'slots_to_skip': 0, 'block_producer': 'no_block'}, {'epochs_to_skip': 1, 'slots_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'slots_to_skip': 0, 'epochs_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'block_producer': 'random_block_deneb', 'epochs_to_skip': 0, 'slots_to_skip': 0, 'validation': 'no_op_validation'}, {'epochs_to_skip': 1, 'slots_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'slots_to_skip': 0, 'epochs_to_skip': 0, 'block_producer': 'no_block', 'validation': 'no_op_validation'}, {'block_producer': 'random_block_deneb', 'epochs_to_skip': 0, 'slots_to_skip': 0, 'validation': 'no_op_validation'}], 'state_randomizer': 'randomize_state_deneb'} # noqa: E501 yield from run_generated_randomized_test( spec, state, diff --git a/tests/core/pyspec/eth2spec/test/eip4844/sanity/__init__.py b/tests/core/pyspec/eth2spec/test/deneb/sanity/__init__.py similarity index 100% rename from tests/core/pyspec/eth2spec/test/eip4844/sanity/__init__.py rename to tests/core/pyspec/eth2spec/test/deneb/sanity/__init__.py diff --git a/tests/core/pyspec/eth2spec/test/eip4844/sanity/test_blocks.py b/tests/core/pyspec/eth2spec/test/deneb/sanity/test_blocks.py similarity index 95% rename from tests/core/pyspec/eth2spec/test/eip4844/sanity/test_blocks.py rename to tests/core/pyspec/eth2spec/test/deneb/sanity/test_blocks.py index 0aeafe052..c7fb708b8 100644 --- a/tests/core/pyspec/eth2spec/test/eip4844/sanity/test_blocks.py +++ b/tests/core/pyspec/eth2spec/test/deneb/sanity/test_blocks.py @@ -6,7 +6,7 @@ from eth2spec.test.helpers.block import ( ) from eth2spec.test.context import ( spec_state_test, - with_eip4844_and_later, + with_deneb_and_later, ) from eth2spec.test.helpers.execution_payload import ( compute_el_block_hash, @@ -16,7 +16,7 @@ from eth2spec.test.helpers.sharding import ( ) -@with_eip4844_and_later +@with_deneb_and_later @spec_state_test def test_one_blob(spec, state): yield 'pre', state @@ -32,7 +32,7 @@ def test_one_blob(spec, state): yield 'post', state -@with_eip4844_and_later +@with_deneb_and_later @spec_state_test def test_max_blobs(spec, state): yield 'pre', state diff --git a/tests/core/pyspec/eth2spec/test/eip4844/unittests/__init__.py b/tests/core/pyspec/eth2spec/test/deneb/unittests/__init__.py similarity index 100% rename from tests/core/pyspec/eth2spec/test/eip4844/unittests/__init__.py rename to tests/core/pyspec/eth2spec/test/deneb/unittests/__init__.py diff --git a/tests/core/pyspec/eth2spec/test/eip4844/unittests/fork_choice/__init__.py b/tests/core/pyspec/eth2spec/test/deneb/unittests/fork_choice/__init__.py similarity index 100% rename from tests/core/pyspec/eth2spec/test/eip4844/unittests/fork_choice/__init__.py rename to tests/core/pyspec/eth2spec/test/deneb/unittests/fork_choice/__init__.py diff --git a/tests/core/pyspec/eth2spec/test/eip4844/unittests/fork_choice/test_validate_blobs_sidecar.py b/tests/core/pyspec/eth2spec/test/deneb/unittests/fork_choice/test_validate_blobs_sidecar.py similarity index 93% rename from tests/core/pyspec/eth2spec/test/eip4844/unittests/fork_choice/test_validate_blobs_sidecar.py rename to tests/core/pyspec/eth2spec/test/deneb/unittests/fork_choice/test_validate_blobs_sidecar.py index dbea9f784..87ed9ff8e 100644 --- a/tests/core/pyspec/eth2spec/test/eip4844/unittests/fork_choice/test_validate_blobs_sidecar.py +++ b/tests/core/pyspec/eth2spec/test/deneb/unittests/fork_choice/test_validate_blobs_sidecar.py @@ -6,7 +6,7 @@ from eth2spec.test.helpers.block import ( ) from eth2spec.test.context import ( spec_state_test, - with_eip4844_and_later, + with_deneb_and_later, ) from eth2spec.test.helpers.execution_payload import ( compute_el_block_hash, @@ -29,25 +29,25 @@ def _run_validate_blobs_sidecar_test(spec, state, blob_count): spec.validate_blobs_sidecar(block.slot, block.hash_tree_root(), expected_commitments, blobs_sidecar) -@with_eip4844_and_later +@with_deneb_and_later @spec_state_test def test_validate_blobs_sidecar_zero_blobs(spec, state): _run_validate_blobs_sidecar_test(spec, state, blob_count=0) -@with_eip4844_and_later +@with_deneb_and_later @spec_state_test def test_validate_blobs_sidecar_one_blob(spec, state): _run_validate_blobs_sidecar_test(spec, state, blob_count=1) -@with_eip4844_and_later +@with_deneb_and_later @spec_state_test def test_validate_blobs_sidecar_two_blobs(spec, state): _run_validate_blobs_sidecar_test(spec, state, blob_count=2) -@with_eip4844_and_later +@with_deneb_and_later @spec_state_test def test_validate_blobs_sidecar_max_blobs(spec, state): _run_validate_blobs_sidecar_test(spec, state, blob_count=spec.MAX_BLOBS_PER_BLOCK) diff --git a/tests/core/pyspec/eth2spec/test/eip4844/unittests/polynomial_commitments/__init__.py b/tests/core/pyspec/eth2spec/test/deneb/unittests/polynomial_commitments/__init__.py similarity index 100% rename from tests/core/pyspec/eth2spec/test/eip4844/unittests/polynomial_commitments/__init__.py rename to tests/core/pyspec/eth2spec/test/deneb/unittests/polynomial_commitments/__init__.py diff --git a/tests/core/pyspec/eth2spec/test/eip4844/unittests/polynomial_commitments/test_polynomial_commitments.py b/tests/core/pyspec/eth2spec/test/deneb/unittests/polynomial_commitments/test_polynomial_commitments.py similarity index 96% rename from tests/core/pyspec/eth2spec/test/eip4844/unittests/polynomial_commitments/test_polynomial_commitments.py rename to tests/core/pyspec/eth2spec/test/deneb/unittests/polynomial_commitments/test_polynomial_commitments.py index 04f5857f3..4d881e3e3 100644 --- a/tests/core/pyspec/eth2spec/test/eip4844/unittests/polynomial_commitments/test_polynomial_commitments.py +++ b/tests/core/pyspec/eth2spec/test/deneb/unittests/polynomial_commitments/test_polynomial_commitments.py @@ -2,7 +2,7 @@ import random from eth2spec.test.context import ( spec_state_test, - with_eip4844_and_later, + with_deneb_and_later, ) from eth2spec.test.helpers.sharding import ( get_sample_blob, @@ -11,7 +11,7 @@ from eth2spec.test.helpers.sharding import ( ) -@with_eip4844_and_later +@with_deneb_and_later @spec_state_test def test_verify_kzg_proof(spec, state): x = 3 @@ -24,7 +24,7 @@ def test_verify_kzg_proof(spec, state): assert spec.verify_kzg_proof_impl(commitment, x, y, proof) -@with_eip4844_and_later +@with_deneb_and_later @spec_state_test def test_barycentric_outside_domain(spec, state): """ @@ -57,7 +57,7 @@ def test_barycentric_outside_domain(spec, state): assert p_z_coeff == p_z_eval -@with_eip4844_and_later +@with_deneb_and_later @spec_state_test def test_barycentric_within_domain(spec, state): """ diff --git a/tests/core/pyspec/eth2spec/test/eip4844/unittests/test_kzg.py b/tests/core/pyspec/eth2spec/test/deneb/unittests/test_kzg.py similarity index 91% rename from tests/core/pyspec/eth2spec/test/eip4844/unittests/test_kzg.py rename to tests/core/pyspec/eth2spec/test/deneb/unittests/test_kzg.py index 7474707b9..71bfae8b8 100644 --- a/tests/core/pyspec/eth2spec/test/eip4844/unittests/test_kzg.py +++ b/tests/core/pyspec/eth2spec/test/deneb/unittests/test_kzg.py @@ -1,6 +1,6 @@ from eth2spec.test.helpers.constants import ( - EIP4844, + DENEB, MINIMAL, ) from eth2spec.test.helpers.sharding import ( @@ -13,7 +13,7 @@ from eth2spec.test.context import ( ) -@with_phases([EIP4844]) +@with_phases([DENEB]) @spec_state_test @with_presets([MINIMAL]) def test_blob_to_kzg_commitment(spec, state): diff --git a/tests/core/pyspec/eth2spec/test/eip4844/unittests/test_offset.py b/tests/core/pyspec/eth2spec/test/deneb/unittests/test_offset.py similarity index 94% rename from tests/core/pyspec/eth2spec/test/eip4844/unittests/test_offset.py rename to tests/core/pyspec/eth2spec/test/deneb/unittests/test_offset.py index 1702ea7e0..13150180b 100644 --- a/tests/core/pyspec/eth2spec/test/eip4844/unittests/test_offset.py +++ b/tests/core/pyspec/eth2spec/test/deneb/unittests/test_offset.py @@ -1,6 +1,6 @@ from eth2spec.test.helpers.constants import ( - EIP4844, + DENEB, MINIMAL, ) from eth2spec.test.helpers.sharding import ( @@ -13,7 +13,7 @@ from eth2spec.test.context import ( ) -@with_phases([EIP4844]) +@with_phases([DENEB]) @spec_state_test @with_presets([MINIMAL]) def test_tx_peek_blob_versioned_hashes(spec, state): diff --git a/tests/core/pyspec/eth2spec/test/eip4844/fork/test_eip4844_fork_random.py b/tests/core/pyspec/eth2spec/test/eip4844/fork/test_eip4844_fork_random.py deleted file mode 100644 index a22de4b59..000000000 --- a/tests/core/pyspec/eth2spec/test/eip4844/fork/test_eip4844_fork_random.py +++ /dev/null @@ -1,84 +0,0 @@ -from random import Random - -from eth2spec.test.context import ( - with_phases, - with_custom_state, - with_presets, - spec_test, with_state, - low_balances, misc_balances, large_validator_set, -) -from eth2spec.test.utils import with_meta_tags -from eth2spec.test.helpers.constants import ( - CAPELLA, EIP4844, - MINIMAL, -) -from eth2spec.test.helpers.eip4844.fork import ( - EIP4844_FORK_TEST_META_TAGS, - run_fork_test, -) -from eth2spec.test.helpers.random import randomize_state - - -@with_phases(phases=[CAPELLA], other_phases=[EIP4844]) -@spec_test -@with_state -@with_meta_tags(EIP4844_FORK_TEST_META_TAGS) -def test_eip4844_fork_random_0(spec, phases, state): - randomize_state(spec, state, rng=Random(1010)) - yield from run_fork_test(phases[EIP4844], state) - - -@with_phases(phases=[CAPELLA], other_phases=[EIP4844]) -@spec_test -@with_state -@with_meta_tags(EIP4844_FORK_TEST_META_TAGS) -def test_eip4844_fork_random_1(spec, phases, state): - randomize_state(spec, state, rng=Random(2020)) - yield from run_fork_test(phases[EIP4844], state) - - -@with_phases(phases=[CAPELLA], other_phases=[EIP4844]) -@spec_test -@with_state -@with_meta_tags(EIP4844_FORK_TEST_META_TAGS) -def test_eip4844_fork_random_2(spec, phases, state): - randomize_state(spec, state, rng=Random(3030)) - yield from run_fork_test(phases[EIP4844], state) - - -@with_phases(phases=[CAPELLA], other_phases=[EIP4844]) -@spec_test -@with_state -@with_meta_tags(EIP4844_FORK_TEST_META_TAGS) -def test_eip4844_fork_random_3(spec, phases, state): - randomize_state(spec, state, rng=Random(4040)) - yield from run_fork_test(phases[EIP4844], state) - - -@with_phases(phases=[CAPELLA], other_phases=[EIP4844]) -@spec_test -@with_custom_state(balances_fn=low_balances, threshold_fn=lambda spec: spec.config.EJECTION_BALANCE) -@with_meta_tags(EIP4844_FORK_TEST_META_TAGS) -def test_eip4844_fork_random_low_balances(spec, phases, state): - randomize_state(spec, state, rng=Random(5050)) - yield from run_fork_test(phases[EIP4844], state) - - -@with_phases(phases=[CAPELLA], other_phases=[EIP4844]) -@spec_test -@with_custom_state(balances_fn=misc_balances, threshold_fn=lambda spec: spec.config.EJECTION_BALANCE) -@with_meta_tags(EIP4844_FORK_TEST_META_TAGS) -def test_eip4844_fork_random_misc_balances(spec, phases, state): - randomize_state(spec, state, rng=Random(6060)) - yield from run_fork_test(phases[EIP4844], state) - - -@with_phases(phases=[CAPELLA], other_phases=[EIP4844]) -@with_presets([MINIMAL], - reason="mainnet config leads to larger validator set than limit of public/private keys pre-generated") -@spec_test -@with_custom_state(balances_fn=large_validator_set, threshold_fn=lambda spec: spec.config.EJECTION_BALANCE) -@with_meta_tags(EIP4844_FORK_TEST_META_TAGS) -def test_eip4844_fork_random_large_validator_set(spec, phases, state): - randomize_state(spec, state, rng=Random(7070)) - yield from run_fork_test(phases[EIP4844], state) diff --git a/tests/core/pyspec/eth2spec/test/helpers/constants.py b/tests/core/pyspec/eth2spec/test/helpers/constants.py index cd103337f..0d31adb43 100644 --- a/tests/core/pyspec/eth2spec/test/helpers/constants.py +++ b/tests/core/pyspec/eth2spec/test/helpers/constants.py @@ -14,25 +14,25 @@ CAPELLA = SpecForkName('capella') SHARDING = SpecForkName('sharding') CUSTODY_GAME = SpecForkName('custody_game') DAS = SpecForkName('das') -EIP4844 = SpecForkName('eip4844') +DENEB = SpecForkName('deneb') # The forks that pytest can run with. ALL_PHASES = ( # Formal forks PHASE0, ALTAIR, BELLATRIX, CAPELLA, # Experimental patches - EIP4844, + DENEB, ) # The forks that output to the test vectors. -TESTGEN_FORKS = (PHASE0, ALTAIR, BELLATRIX, CAPELLA, EIP4844) +TESTGEN_FORKS = (PHASE0, ALTAIR, BELLATRIX, CAPELLA, DENEB) -# TODO: no EIP4844 fork tests now. Should add when we figure out the content of Capella. +# TODO: no DENEB fork tests now. Should add when we figure out the content of Capella. ALL_FORK_UPGRADES = { # pre_fork_name: post_fork_name PHASE0: ALTAIR, ALTAIR: BELLATRIX, BELLATRIX: CAPELLA, - CAPELLA: EIP4844, + CAPELLA: DENEB, } ALL_PRE_POST_FORKS = ALL_FORK_UPGRADES.items() AFTER_BELLATRIX_UPGRADES = {key: value for key, value in ALL_FORK_UPGRADES.items() if key != PHASE0} diff --git a/tests/core/pyspec/eth2spec/test/helpers/eip4844/__init__.py b/tests/core/pyspec/eth2spec/test/helpers/deneb/__init__.py similarity index 100% rename from tests/core/pyspec/eth2spec/test/helpers/eip4844/__init__.py rename to tests/core/pyspec/eth2spec/test/helpers/deneb/__init__.py diff --git a/tests/core/pyspec/eth2spec/test/helpers/eip4844/fork.py b/tests/core/pyspec/eth2spec/test/helpers/deneb/fork.py similarity index 90% rename from tests/core/pyspec/eth2spec/test/helpers/eip4844/fork.py rename to tests/core/pyspec/eth2spec/test/helpers/deneb/fork.py index ed4ae057d..7fe0535c1 100644 --- a/tests/core/pyspec/eth2spec/test/helpers/eip4844/fork.py +++ b/tests/core/pyspec/eth2spec/test/helpers/deneb/fork.py @@ -1,17 +1,17 @@ from eth2spec.test.helpers.constants import ( - EIP4844, + DENEB, ) -EIP4844_FORK_TEST_META_TAGS = { - 'fork': EIP4844, +DENEB_FORK_TEST_META_TAGS = { + 'fork': DENEB, } def run_fork_test(post_spec, pre_state): yield 'pre', pre_state - post_state = post_spec.upgrade_to_eip4844(pre_state) + post_state = post_spec.upgrade_to_deneb(pre_state) # Stable fields stable_fields = [ @@ -57,7 +57,7 @@ def run_fork_test(post_spec, pre_state): assert getattr(pre_validator, field) == getattr(post_validator, field) assert pre_state.fork.current_version == post_state.fork.previous_version - assert post_state.fork.current_version == post_spec.config.EIP4844_FORK_VERSION + assert post_state.fork.current_version == post_spec.config.DENEB_FORK_VERSION assert post_state.fork.epoch == post_spec.get_current_epoch(post_state) yield 'post', post_state diff --git a/tests/core/pyspec/eth2spec/test/helpers/execution_payload.py b/tests/core/pyspec/eth2spec/test/helpers/execution_payload.py index 5e0c160b3..c0a70aca1 100644 --- a/tests/core/pyspec/eth2spec/test/helpers/execution_payload.py +++ b/tests/core/pyspec/eth2spec/test/helpers/execution_payload.py @@ -4,7 +4,7 @@ from rlp import encode from rlp.sedes import big_endian_int, Binary, List from eth2spec.debug.random_value import get_random_bytes_list -from eth2spec.test.helpers.forks import is_post_capella, is_post_eip4844 +from eth2spec.test.helpers.forks import is_post_capella, is_post_deneb def get_execution_payload_header(spec, execution_payload): @@ -26,7 +26,7 @@ def get_execution_payload_header(spec, execution_payload): ) if is_post_capella(spec): payload_header.withdrawals_root = spec.hash_tree_root(execution_payload.withdrawals) - if is_post_eip4844(spec): + if is_post_deneb(spec): payload_header.excess_data_gas = execution_payload.excess_data_gas return payload_header @@ -89,7 +89,7 @@ def compute_el_header_block_hash(spec, if is_post_capella(spec): # withdrawals_root execution_payload_header_rlp.append((Binary(32, 32), withdrawals_trie_root)) - if is_post_eip4844(spec): + if is_post_deneb(spec): # excess_data_gas execution_payload_header_rlp.append((big_endian_int, payload_header.excess_data_gas)) diff --git a/tests/core/pyspec/eth2spec/test/helpers/fork_transition.py b/tests/core/pyspec/eth2spec/test/helpers/fork_transition.py index ca961bde4..96d0d20dc 100644 --- a/tests/core/pyspec/eth2spec/test/helpers/fork_transition.py +++ b/tests/core/pyspec/eth2spec/test/helpers/fork_transition.py @@ -14,7 +14,7 @@ from eth2spec.test.helpers.constants import ( ALTAIR, BELLATRIX, CAPELLA, - EIP4844, + DENEB, ) from eth2spec.test.helpers.deposits import ( prepare_state_and_deposit, @@ -153,8 +153,8 @@ def do_fork(state, spec, post_spec, fork_epoch, with_block=True, operation_dict= state = post_spec.upgrade_to_bellatrix(state) elif post_spec.fork == CAPELLA: state = post_spec.upgrade_to_capella(state) - elif post_spec.fork == EIP4844: - state = post_spec.upgrade_to_eip4844(state) + elif post_spec.fork == DENEB: + state = post_spec.upgrade_to_deneb(state) assert state.fork.epoch == fork_epoch @@ -167,9 +167,9 @@ def do_fork(state, spec, post_spec, fork_epoch, with_block=True, operation_dict= elif post_spec.fork == CAPELLA: assert state.fork.previous_version == post_spec.config.BELLATRIX_FORK_VERSION assert state.fork.current_version == post_spec.config.CAPELLA_FORK_VERSION - elif post_spec.fork == EIP4844: + elif post_spec.fork == DENEB: assert state.fork.previous_version == post_spec.config.CAPELLA_FORK_VERSION - assert state.fork.current_version == post_spec.config.EIP4844_FORK_VERSION + assert state.fork.current_version == post_spec.config.DENEB_FORK_VERSION if with_block: return state, _state_transition_and_sign_block_at_slot(post_spec, state, operation_dict=operation_dict) diff --git a/tests/core/pyspec/eth2spec/test/helpers/forks.py b/tests/core/pyspec/eth2spec/test/helpers/forks.py index 82ff12ff1..be3103e67 100644 --- a/tests/core/pyspec/eth2spec/test/helpers/forks.py +++ b/tests/core/pyspec/eth2spec/test/helpers/forks.py @@ -1,11 +1,11 @@ from .constants import ( - PHASE0, ALTAIR, BELLATRIX, CAPELLA, EIP4844, + PHASE0, ALTAIR, BELLATRIX, CAPELLA, DENEB, ) def is_post_fork(a, b): - if a == EIP4844: - return b in [PHASE0, ALTAIR, BELLATRIX, CAPELLA, EIP4844] + if a == DENEB: + return b in [PHASE0, ALTAIR, BELLATRIX, CAPELLA, DENEB] if a == CAPELLA: return b in [PHASE0, ALTAIR, BELLATRIX, CAPELLA] if a == BELLATRIX: @@ -29,5 +29,5 @@ def is_post_capella(spec): return is_post_fork(spec.fork, CAPELLA) -def is_post_eip4844(spec): - return is_post_fork(spec.fork, EIP4844) +def is_post_deneb(spec): + return is_post_fork(spec.fork, DENEB) diff --git a/tests/core/pyspec/eth2spec/test/helpers/genesis.py b/tests/core/pyspec/eth2spec/test/helpers/genesis.py index de2dd2647..0610f11ad 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, EIP4844, + ALTAIR, BELLATRIX, CAPELLA, DENEB, ) from eth2spec.test.helpers.execution_payload import ( compute_el_header_block_hash, @@ -77,9 +77,9 @@ def create_genesis_state(spec, validator_balances, activation_threshold): elif spec.fork == CAPELLA: previous_version = spec.config.BELLATRIX_FORK_VERSION current_version = spec.config.CAPELLA_FORK_VERSION - elif spec.fork == EIP4844: + elif spec.fork == DENEB: previous_version = spec.config.CAPELLA_FORK_VERSION - current_version = spec.config.EIP4844_FORK_VERSION + current_version = spec.config.DENEB_FORK_VERSION state = spec.BeaconState( genesis_time=0, diff --git a/tests/core/pyspec/eth2spec/test/utils/randomized_block_tests.py b/tests/core/pyspec/eth2spec/test/utils/randomized_block_tests.py index 4d2ec124d..35ddbc330 100644 --- a/tests/core/pyspec/eth2spec/test/utils/randomized_block_tests.py +++ b/tests/core/pyspec/eth2spec/test/utils/randomized_block_tests.py @@ -88,7 +88,7 @@ def randomize_state_capella(spec, state, stats, exit_fraction=0.1, slash_fractio return scenario_state -def randomize_state_eip4844(spec, state, stats, exit_fraction=0.1, slash_fraction=0.1): +def randomize_state_deneb(spec, state, stats, exit_fraction=0.1, slash_fraction=0.1): scenario_state = randomize_state_capella(spec, state, stats, @@ -232,7 +232,7 @@ def random_block_capella(spec, state, signed_blocks, scenario_state, rng=Random( return block -def random_block_eip4844(spec, state, signed_blocks, scenario_state, rng=Random(3456)): +def random_block_deneb(spec, state, signed_blocks, scenario_state, rng=Random(3456)): block = random_block_capella(spec, state, signed_blocks, scenario_state) # TODO: more commitments. blob_kzg_commitments: List[KZGCommitment, MAX_BLOBS_PER_BLOCK] opaque_tx, _, blob_kzg_commitments = get_sample_opaque_tx(spec, blob_count=1) diff --git a/tests/generators/epoch_processing/main.py b/tests/generators/epoch_processing/main.py index dda4345a8..a485f646a 100644 --- a/tests/generators/epoch_processing/main.py +++ b/tests/generators/epoch_processing/main.py @@ -1,5 +1,5 @@ from eth2spec.gen_helpers.gen_from_tests.gen import run_state_test_generators, combine_mods -from eth2spec.test.helpers.constants import PHASE0, ALTAIR, BELLATRIX, CAPELLA, EIP4844 +from eth2spec.test.helpers.constants import PHASE0, ALTAIR, BELLATRIX, CAPELLA, DENEB if __name__ == "__main__": @@ -32,7 +32,7 @@ if __name__ == "__main__": ]} capella_mods = combine_mods(_new_capella_mods, bellatrix_mods) - eip4844_mods = capella_mods + deneb_mods = capella_mods # TODO Custody Game testgen is disabled for now # custody_game_mods = {**{key: 'eth2spec.test.custody_game.epoch_processing.test_process_' + key for key in [ @@ -46,7 +46,7 @@ if __name__ == "__main__": ALTAIR: altair_mods, BELLATRIX: bellatrix_mods, CAPELLA: capella_mods, - EIP4844: eip4844_mods, + DENEB: deneb_mods, } run_state_test_generators(runner_name="epoch_processing", all_mods=all_mods) diff --git a/tests/generators/finality/main.py b/tests/generators/finality/main.py index de5af9b11..a25f3b8e7 100644 --- a/tests/generators/finality/main.py +++ b/tests/generators/finality/main.py @@ -1,5 +1,5 @@ from eth2spec.gen_helpers.gen_from_tests.gen import run_state_test_generators -from eth2spec.test.helpers.constants import PHASE0, ALTAIR, BELLATRIX, CAPELLA, EIP4844 +from eth2spec.test.helpers.constants import PHASE0, ALTAIR, BELLATRIX, CAPELLA, DENEB if __name__ == "__main__": @@ -7,14 +7,14 @@ if __name__ == "__main__": altair_mods = phase_0_mods # No additional Altair specific finality tests bellatrix_mods = altair_mods # No additional Bellatrix specific finality tests capella_mods = bellatrix_mods # No additional Capella specific finality tests - eip4844_mods = capella_mods # No additional EIP4844 specific finality tests + deneb_mods = capella_mods # No additional Deneb specific finality tests all_mods = { PHASE0: phase_0_mods, ALTAIR: altair_mods, BELLATRIX: bellatrix_mods, CAPELLA: capella_mods, - EIP4844: eip4844_mods, + DENEB: deneb_mods, } run_state_test_generators(runner_name="finality", all_mods=all_mods) diff --git a/tests/generators/fork_choice/main.py b/tests/generators/fork_choice/main.py index 40e19a8ac..c106810f8 100644 --- a/tests/generators/fork_choice/main.py +++ b/tests/generators/fork_choice/main.py @@ -1,5 +1,5 @@ from eth2spec.gen_helpers.gen_from_tests.gen import run_state_test_generators, combine_mods -from eth2spec.test.helpers.constants import PHASE0, ALTAIR, BELLATRIX, CAPELLA, EIP4844 +from eth2spec.test.helpers.constants import PHASE0, ALTAIR, BELLATRIX, CAPELLA, DENEB if __name__ == "__main__": @@ -18,14 +18,14 @@ if __name__ == "__main__": ]} bellatrix_mods = combine_mods(_new_bellatrix_mods, altair_mods) capella_mods = bellatrix_mods # No additional Capella specific fork choice tests - eip4844_mods = capella_mods # No additional Capella specific fork choice tests + deneb_mods = capella_mods # No additional Capella specific fork choice tests all_mods = { PHASE0: phase_0_mods, ALTAIR: altair_mods, BELLATRIX: bellatrix_mods, CAPELLA: capella_mods, - EIP4844: eip4844_mods, + DENEB: deneb_mods, } run_state_test_generators(runner_name="fork_choice", all_mods=all_mods) diff --git a/tests/generators/forks/main.py b/tests/generators/forks/main.py index 42f3f3a1f..7d68a31e7 100644 --- a/tests/generators/forks/main.py +++ b/tests/generators/forks/main.py @@ -1,14 +1,14 @@ from typing import Iterable from eth2spec.test.helpers.constants import ( - PHASE0, ALTAIR, BELLATRIX, CAPELLA, EIP4844, + PHASE0, ALTAIR, BELLATRIX, CAPELLA, DENEB, MINIMAL, MAINNET, ) from eth2spec.test.helpers.typing import SpecForkName, PresetBaseName from eth2spec.test.altair.fork import test_altair_fork_basic, test_altair_fork_random from eth2spec.test.bellatrix.fork import test_bellatrix_fork_basic, test_bellatrix_fork_random from eth2spec.test.capella.fork import test_capella_fork_basic, test_capella_fork_random -from eth2spec.test.eip4844.fork import test_eip4844_fork_basic, test_eip4844_fork_random +from eth2spec.test.deneb.fork import test_deneb_fork_basic, test_deneb_fork_random from eth2spec.gen_helpers.gen_base import gen_runner, gen_typing from eth2spec.gen_helpers.gen_from_tests.gen import generate_from_tests @@ -40,8 +40,8 @@ def _get_fork_tests_providers(): yield create_provider(test_bellatrix_fork_random, preset, ALTAIR, BELLATRIX) yield create_provider(test_capella_fork_basic, preset, BELLATRIX, CAPELLA) yield create_provider(test_capella_fork_random, preset, BELLATRIX, CAPELLA) - yield create_provider(test_eip4844_fork_basic, preset, CAPELLA, EIP4844) - yield create_provider(test_eip4844_fork_random, preset, CAPELLA, EIP4844) + yield create_provider(test_deneb_fork_basic, preset, CAPELLA, DENEB) + yield create_provider(test_deneb_fork_random, preset, CAPELLA, DENEB) if __name__ == "__main__": diff --git a/tests/generators/genesis/main.py b/tests/generators/genesis/main.py index a5c4eba9d..e95afcde1 100644 --- a/tests/generators/genesis/main.py +++ b/tests/generators/genesis/main.py @@ -1,5 +1,5 @@ from eth2spec.gen_helpers.gen_from_tests.gen import run_state_test_generators, combine_mods -from eth2spec.test.helpers.constants import PHASE0, ALTAIR, BELLATRIX, CAPELLA, EIP4844 +from eth2spec.test.helpers.constants import PHASE0, ALTAIR, BELLATRIX, CAPELLA, DENEB if __name__ == "__main__": @@ -16,13 +16,13 @@ if __name__ == "__main__": ]} bellatrix_mods = combine_mods(_new_bellatrix_mods, altair_mods) capella_mods = bellatrix_mods # No additional Capella specific genesis tests - eip4844_mods = capella_mods # No additional EIP4844 specific genesis tests + deneb_mods = capella_mods # No additional Deneb specific genesis tests all_mods = { PHASE0: phase_0_mods, ALTAIR: altair_mods, BELLATRIX: bellatrix_mods, CAPELLA: capella_mods, - EIP4844: eip4844_mods, + DENEB: deneb_mods, } run_state_test_generators(runner_name="genesis", all_mods=all_mods) diff --git a/tests/generators/light_client/main.py b/tests/generators/light_client/main.py index 54c09fae6..cfe34aee4 100644 --- a/tests/generators/light_client/main.py +++ b/tests/generators/light_client/main.py @@ -1,4 +1,4 @@ -from eth2spec.test.helpers.constants import ALTAIR, BELLATRIX, CAPELLA, EIP4844 +from eth2spec.test.helpers.constants import ALTAIR, BELLATRIX, CAPELLA, DENEB from eth2spec.gen_helpers.gen_from_tests.gen import combine_mods, run_state_test_generators @@ -14,13 +14,13 @@ if __name__ == "__main__": 'single_merkle_proof', ]} capella_mods = combine_mods(_new_capella_mods, bellatrix_mods) - eip4844_mods = capella_mods + deneb_mods = capella_mods all_mods = { ALTAIR: altair_mods, BELLATRIX: bellatrix_mods, CAPELLA: capella_mods, - EIP4844: eip4844_mods, + DENEB: deneb_mods, } run_state_test_generators(runner_name="light_client", all_mods=all_mods) diff --git a/tests/generators/operations/main.py b/tests/generators/operations/main.py index d370a1b85..ed4c6c26c 100644 --- a/tests/generators/operations/main.py +++ b/tests/generators/operations/main.py @@ -1,5 +1,5 @@ from eth2spec.gen_helpers.gen_from_tests.gen import run_state_test_generators, combine_mods -from eth2spec.test.helpers.constants import PHASE0, ALTAIR, BELLATRIX, CAPELLA, EIP4844 +from eth2spec.test.helpers.constants import PHASE0, ALTAIR, BELLATRIX, CAPELLA, DENEB if __name__ == "__main__": @@ -36,7 +36,7 @@ if __name__ == "__main__": ]} capella_mods = combine_mods(_new_capella_mods, bellatrix_mods) - eip4844_mods = capella_mods + deneb_mods = capella_mods # TODO Custody Game testgen is disabled for now # _new_custody_game_mods = {key: 'eth2spec.test.custody_game.block_processing.test_process_' + key for key in [ @@ -53,7 +53,7 @@ if __name__ == "__main__": ALTAIR: altair_mods, BELLATRIX: bellatrix_mods, CAPELLA: capella_mods, - EIP4844: eip4844_mods, + DENEB: deneb_mods, } run_state_test_generators(runner_name="operations", all_mods=all_mods) diff --git a/tests/generators/random/Makefile b/tests/generators/random/Makefile index f57221ab4..bb557204a 100644 --- a/tests/generators/random/Makefile +++ b/tests/generators/random/Makefile @@ -6,9 +6,9 @@ all: rm -f ../../core/pyspec/eth2spec/test/altair/random/test_random.py rm -f ../../core/pyspec/eth2spec/test/bellatrix/random/test_random.py rm -f ../../core/pyspec/eth2spec/test/capella/random/test_random.py - rm -f ../../core/pyspec/eth2spec/test/eip4844/random/test_random.py + rm -f ../../core/pyspec/eth2spec/test/deneb/random/test_random.py python3 generate.py phase0 > ../../core/pyspec/eth2spec/test/phase0/random/test_random.py python3 generate.py altair > ../../core/pyspec/eth2spec/test/altair/random/test_random.py python3 generate.py bellatrix > ../../core/pyspec/eth2spec/test/bellatrix/random/test_random.py python3 generate.py capella > ../../core/pyspec/eth2spec/test/capella/random/test_random.py - python3 generate.py eip4844 > ../../core/pyspec/eth2spec/test/eip4844/random/test_random.py + python3 generate.py deneb > ../../core/pyspec/eth2spec/test/deneb/random/test_random.py diff --git a/tests/generators/random/generate.py b/tests/generators/random/generate.py index 129d670fd..3a1eb9c67 100644 --- a/tests/generators/random/generate.py +++ b/tests/generators/random/generate.py @@ -21,12 +21,12 @@ from eth2spec.test.utils.randomized_block_tests import ( randomize_state_altair, randomize_state_bellatrix, randomize_state_capella, - randomize_state_eip4844, + randomize_state_deneb, random_block, random_block_altair_with_cycling_sync_committee_participation, random_block_bellatrix, random_block_capella, - random_block_eip4844, + random_block_deneb, last_slot_in_epoch, random_slot_in_epoch, penultimate_slot_in_epoch, @@ -36,7 +36,7 @@ from eth2spec.test.utils.randomized_block_tests import ( transition_to_leaking, transition_without_leak, ) -from eth2spec.test.helpers.constants import PHASE0, ALTAIR, BELLATRIX, CAPELLA, EIP4844 +from eth2spec.test.helpers.constants import PHASE0, ALTAIR, BELLATRIX, CAPELLA, DENEB # Ensure this many blocks are present in *each* randomized scenario @@ -274,12 +274,12 @@ if __name__ == "__main__": state_randomizer=randomize_state_capella, block_randomizer=random_block_capella, ) - if EIP4844 in sys.argv: + if DENEB in sys.argv: did_generate = True run_generate_tests_to_std_out( - EIP4844, - state_randomizer=randomize_state_eip4844, - block_randomizer=random_block_eip4844, + DENEB, + state_randomizer=randomize_state_deneb, + block_randomizer=random_block_deneb, ) if not did_generate: warnings.warn("no phase given for test generation") diff --git a/tests/generators/random/main.py b/tests/generators/random/main.py index e36678771..c5b991e4a 100644 --- a/tests/generators/random/main.py +++ b/tests/generators/random/main.py @@ -1,4 +1,4 @@ -from eth2spec.test.helpers.constants import PHASE0, ALTAIR, BELLATRIX, CAPELLA, EIP4844 +from eth2spec.test.helpers.constants import PHASE0, ALTAIR, BELLATRIX, CAPELLA, DENEB from eth2spec.gen_helpers.gen_from_tests.gen import run_state_test_generators @@ -15,7 +15,7 @@ if __name__ == "__main__": capella_mods = {key: 'eth2spec.test.capella.random.test_' + key for key in [ 'random', ]} - eip4844_mods = {key: 'eth2spec.test.eip4844.random.test_' + key for key in [ + deneb_mods = {key: 'eth2spec.test.deneb.random.test_' + key for key in [ 'random', ]} @@ -24,7 +24,7 @@ if __name__ == "__main__": ALTAIR: altair_mods, BELLATRIX: bellatrix_mods, CAPELLA: capella_mods, - EIP4844: eip4844_mods, + DENEB: deneb_mods, } run_state_test_generators(runner_name="random", all_mods=all_mods) diff --git a/tests/generators/rewards/main.py b/tests/generators/rewards/main.py index 8958074bc..e6244d172 100644 --- a/tests/generators/rewards/main.py +++ b/tests/generators/rewards/main.py @@ -1,5 +1,5 @@ from eth2spec.gen_helpers.gen_from_tests.gen import run_state_test_generators -from eth2spec.test.helpers.constants import PHASE0, ALTAIR, BELLATRIX, CAPELLA, EIP4844 +from eth2spec.test.helpers.constants import PHASE0, ALTAIR, BELLATRIX, CAPELLA, DENEB if __name__ == "__main__": @@ -16,14 +16,14 @@ if __name__ == "__main__": # Transaction fees are part of the execution-layer. bellatrix_mods = altair_mods capella_mods = bellatrix_mods - eip4844_mods = capella_mods + deneb_mods = capella_mods all_mods = { PHASE0: phase_0_mods, ALTAIR: altair_mods, BELLATRIX: bellatrix_mods, CAPELLA: capella_mods, - EIP4844: eip4844_mods, + DENEB: deneb_mods, } run_state_test_generators(runner_name="rewards", all_mods=all_mods) diff --git a/tests/generators/sanity/main.py b/tests/generators/sanity/main.py index 9dd6d7ac0..8a6c7b39c 100644 --- a/tests/generators/sanity/main.py +++ b/tests/generators/sanity/main.py @@ -1,4 +1,4 @@ -from eth2spec.test.helpers.constants import PHASE0, ALTAIR, BELLATRIX, CAPELLA, EIP4844 +from eth2spec.test.helpers.constants import PHASE0, ALTAIR, BELLATRIX, CAPELLA, DENEB from eth2spec.gen_helpers.gen_from_tests.gen import run_state_test_generators, combine_mods @@ -23,17 +23,17 @@ if __name__ == "__main__": ]} capella_mods = combine_mods(_new_capella_mods, bellatrix_mods) - _new_eip4844_mods = {key: 'eth2spec.test.eip4844.sanity.test_' + key for key in [ + _new_deneb_mods = {key: 'eth2spec.test.deneb.sanity.test_' + key for key in [ 'blocks', ]} - eip4844_mods = combine_mods(_new_eip4844_mods, capella_mods) + deneb_mods = combine_mods(_new_deneb_mods, capella_mods) all_mods = { PHASE0: phase_0_mods, ALTAIR: altair_mods, BELLATRIX: bellatrix_mods, CAPELLA: capella_mods, - EIP4844: eip4844_mods, + DENEB: deneb_mods, } run_state_test_generators(runner_name="sanity", all_mods=all_mods) diff --git a/tests/generators/sync/main.py b/tests/generators/sync/main.py index 8fb395053..11f05a741 100644 --- a/tests/generators/sync/main.py +++ b/tests/generators/sync/main.py @@ -1,5 +1,5 @@ from eth2spec.gen_helpers.gen_from_tests.gen import run_state_test_generators -from eth2spec.test.helpers.constants import BELLATRIX, CAPELLA, EIP4844 +from eth2spec.test.helpers.constants import BELLATRIX, CAPELLA, DENEB if __name__ == "__main__": @@ -7,12 +7,12 @@ if __name__ == "__main__": 'optimistic', ]} capella_mods = bellatrix_mods - eip4844_mods = capella_mods + deneb_mods = capella_mods all_mods = { BELLATRIX: bellatrix_mods, CAPELLA: capella_mods, - EIP4844: eip4844_mods, + DENEB: deneb_mods, } run_state_test_generators(runner_name="sync", all_mods=all_mods) From 470c1b14b35c64151114bca07a9a90154f77fe0e Mon Sep 17 00:00:00 2001 From: Paul Harris Date: Wed, 8 Feb 2023 09:22:28 +1000 Subject: [PATCH 117/158] fix references to eip4844 --- README.md | 2 +- specs/deneb/beacon-chain.md | 22 +++++++++---------- specs/deneb/fork-choice.md | 6 ++--- specs/deneb/fork.md | 10 ++++----- specs/deneb/p2p-interface.md | 10 ++++----- specs/deneb/polynomial-commitments.md | 6 ++--- specs/deneb/validator.md | 6 ++--- .../pyspec/eth2spec/test/helpers/sharding.py | 2 +- tests/generators/transition/main.py | 6 ++--- 9 files changed, 35 insertions(+), 35 deletions(-) diff --git a/README.md b/README.md index 466c15193..da893a53d 100644 --- a/README.md +++ b/README.md @@ -25,7 +25,7 @@ Features are researched and developed in parallel, and then consolidated into se | Code Name or Topic | Specs | Notes | | - | - | - | | Capella (tentative) |
  • Core
    • [Beacon chain changes](specs/capella/beacon-chain.md)
    • [Capella fork](specs/capella/fork.md)
  • Additions
    • [Light client sync protocol changes](specs/capella/light-client/sync-protocol.md) ([fork](specs/capella/light-client/fork.md), [full node](specs/capella/light-client/full-node.md), [networking](specs/capella/light-client/p2p-interface.md))
    • [Validator additions](specs/capella/validator.md)
    • [P2P networking](specs/capella/p2p-interface.md)
| -| Deneb (tentative) |
  • Core
    • [Beacon Chain changes](specs/deneb/beacon-chain.md)
    • [EIP-4844 fork](specs/deneb/fork.md)
    • [Polynomial commitments](specs/deneb/polynomial-commitments.md)
    • [Fork choice changes](specs/deneb/fork-choice.md)
  • Additions
    • [Light client sync protocol changes](specs/deneb/light-client/sync-protocol.md) ([fork](specs/deneb/light-client/fork.md), [full node](specs/deneb/light-client/full-node.md), [networking](specs/deneb/light-client/p2p-interface.md))
    • [Honest validator guide changes](specs/deneb/validator.md)
    • [P2P networking](specs/deneb/p2p-interface.md)
| +| Deneb (tentative) |
  • Core
    • [Beacon Chain changes](specs/deneb/beacon-chain.md)
    • [Deneb fork](specs/deneb/fork.md)
    • [Polynomial commitments](specs/deneb/polynomial-commitments.md)
    • [Fork choice changes](specs/deneb/fork-choice.md)
  • Additions
    • [Light client sync protocol changes](specs/deneb/light-client/sync-protocol.md) ([fork](specs/deneb/light-client/fork.md), [full node](specs/deneb/light-client/full-node.md), [networking](specs/deneb/light-client/p2p-interface.md))
    • [Honest validator guide changes](specs/deneb/validator.md)
    • [P2P networking](specs/deneb/p2p-interface.md)
| | Sharding (outdated) |
  • Core
    • [Beacon Chain changes](specs/sharding/beacon-chain.md)
  • Additions
    • [P2P networking](specs/sharding/p2p-interface.md)
| | Custody Game (outdated) |
  • Core
    • [Beacon Chain changes](specs/custody_game/beacon-chain.md)
  • Additions
    • [Honest validator guide changes](specs/custody_game/validator.md)
| Dependent on sharding | | Data Availability Sampling (outdated) |
  • Core
    • [Core types and functions](specs/das/das-core.md)
    • [Fork choice changes](specs/das/fork-choice.md)
  • Additions
    • [P2P Networking](specs/das/p2p-interface.md)
    • [Sampling process](specs/das/sampling.md)
|
  • Dependent on sharding
  • [Technical explainer](https://hackmd.io/@HWeNw8hNRimMm2m2GH56Cw/B1YJPGkpD)
| diff --git a/specs/deneb/beacon-chain.md b/specs/deneb/beacon-chain.md index 87ebf7a9e..e82fdfdcb 100644 --- a/specs/deneb/beacon-chain.md +++ b/specs/deneb/beacon-chain.md @@ -1,4 +1,4 @@ -# EIP-4844 -- The Beacon Chain +# Deneb -- The Beacon Chain **Notice**: This document is a work-in-progress for researchers and implementers. @@ -37,7 +37,7 @@ ## Introduction -This upgrade adds blobs to the beacon chain as part of EIP-4844. This is an extension of the Capella upgrade. +This upgrade adds blobs to the beacon chain as part of Deneb. This is an extension of the Capella upgrade. ## Custom types @@ -86,9 +86,9 @@ class BeaconBlockBody(Container): voluntary_exits: List[SignedVoluntaryExit, MAX_VOLUNTARY_EXITS] sync_aggregate: SyncAggregate # Execution - execution_payload: ExecutionPayload # [Modified in EIP-4844] + execution_payload: ExecutionPayload # [Modified in Deneb] bls_to_execution_changes: List[SignedBLSToExecutionChange, MAX_BLS_TO_EXECUTION_CHANGES] - blob_kzg_commitments: List[KZGCommitment, MAX_BLOBS_PER_BLOCK] # [New in EIP-4844] + blob_kzg_commitments: List[KZGCommitment, MAX_BLOBS_PER_BLOCK] # [New in Deneb] ``` #### `ExecutionPayload` @@ -108,7 +108,7 @@ class ExecutionPayload(Container): timestamp: uint64 extra_data: ByteList[MAX_EXTRA_DATA_BYTES] base_fee_per_gas: uint256 - excess_data_gas: uint256 # [New in EIP-4844] + excess_data_gas: uint256 # [New in Deneb] # Extra payload fields block_hash: Hash32 # Hash of execution block transactions: List[Transaction, MAX_TRANSACTIONS_PER_PAYLOAD] @@ -132,7 +132,7 @@ class ExecutionPayloadHeader(Container): timestamp: uint64 extra_data: ByteList[MAX_EXTRA_DATA_BYTES] base_fee_per_gas: uint256 - excess_data_gas: uint256 # [New in EIP-4844] + excess_data_gas: uint256 # [New in Deneb] # Extra payload fields block_hash: Hash32 # Hash of execution block transactions_root: Root @@ -152,7 +152,7 @@ def kzg_commitment_to_versioned_hash(kzg_commitment: KZGCommitment) -> Versioned #### `tx_peek_blob_versioned_hashes` -This function retrieves the hashes from the `SignedBlobTransaction` as defined in EIP-4844, using SSZ offsets. +This function retrieves the hashes from the `SignedBlobTransaction` as defined in Deneb, using SSZ offsets. Offsets are little-endian `uint32` values, as defined in the [SSZ specification](../../ssz/simple-serialize.md). See [the full details of `blob_versioned_hashes` offset calculation](https://gist.github.com/protolambda/23bd106b66f6d4bb854ce46044aa3ca3). @@ -192,12 +192,12 @@ def process_block(state: BeaconState, block: BeaconBlock) -> None: process_block_header(state, block) if is_execution_enabled(state, block.body): process_withdrawals(state, block.body.execution_payload) - process_execution_payload(state, block.body.execution_payload, EXECUTION_ENGINE) # [Modified in EIP-4844] + 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_sync_aggregate(state, block.body.sync_aggregate) - process_blob_kzg_commitments(state, block.body) # [New in EIP-4844] + process_blob_kzg_commitments(state, block.body) # [New in Deneb] ``` #### Execution payload @@ -230,7 +230,7 @@ def process_execution_payload(state: BeaconState, payload: ExecutionPayload, exe timestamp=payload.timestamp, extra_data=payload.extra_data, base_fee_per_gas=payload.base_fee_per_gas, - excess_data_gas=payload.excess_data_gas, # [New in EIP-4844] + excess_data_gas=payload.excess_data_gas, # [New in Deneb] block_hash=payload.block_hash, transactions_root=hash_tree_root(payload.transactions), withdrawals_root=hash_tree_root(payload.withdrawals), @@ -247,7 +247,7 @@ def process_blob_kzg_commitments(state: BeaconState, body: BeaconBlockBody) -> N ## Testing -*Note*: The function `initialize_beacon_state_from_eth1` is modified for pure EIP-4844 testing only. +*Note*: The function `initialize_beacon_state_from_eth1` is modified for pure Deneb testing only. The `BeaconState` initialization is unchanged, except for the use of the updated `deneb.BeaconBlockBody` type when initializing the first body-root. diff --git a/specs/deneb/fork-choice.md b/specs/deneb/fork-choice.md index 962987907..d245034cf 100644 --- a/specs/deneb/fork-choice.md +++ b/specs/deneb/fork-choice.md @@ -1,4 +1,4 @@ -# EIP-4844 -- Fork Choice +# Deneb -- Fork Choice ## Table of contents @@ -19,7 +19,7 @@ ## Introduction -This is the modification of the fork choice accompanying the EIP-4844 upgrade. +This is the modification of the fork choice accompanying the Deneb upgrade. ## Containers @@ -100,7 +100,7 @@ def on_block(store: Store, signed_block: SignedBeaconBlock) -> None: # Check block is a descendant of the finalized block at the checkpoint finalized slot assert get_ancestor(store, block.parent_root, finalized_slot) == store.finalized_checkpoint.root - # [New in EIP-4844] + # [New in Deneb] # Check if blob data is available # If not, this block MAY be queued and subsequently considered when blob data becomes available assert is_data_available(block.slot, hash_tree_root(block), block.body.blob_kzg_commitments) diff --git a/specs/deneb/fork.md b/specs/deneb/fork.md index 864e28888..1ace26c7f 100644 --- a/specs/deneb/fork.md +++ b/specs/deneb/fork.md @@ -1,4 +1,4 @@ -# EIP-4844 -- Fork Logic +# Deneb -- Fork Logic **Notice**: This document is a work-in-progress for researchers and implementers. @@ -12,7 +12,7 @@ - [Helper functions](#helper-functions) - [Misc](#misc) - [Modified `compute_fork_version`](#modified-compute_fork_version) -- [Fork to EIP-4844](#fork-to-eip-4844) +- [Fork to Deneb](#fork-to-deneb) - [Fork trigger](#fork-trigger) - [Upgrading the state](#upgrading-the-state) @@ -20,7 +20,7 @@ ## Introduction -This document describes the process of EIP-4844 upgrade. +This document describes the process of Deneb upgrade. ## Configuration @@ -53,7 +53,7 @@ def compute_fork_version(epoch: Epoch) -> Version: return GENESIS_FORK_VERSION ``` -## Fork to EIP-4844 +## Fork to Deneb ### Fork trigger @@ -82,7 +82,7 @@ def upgrade_to_deneb(pre: capella.BeaconState) -> BeaconState: timestamp=pre.latest_execution_payload_header.timestamp, extra_data=pre.latest_execution_payload_header.extra_data, base_fee_per_gas=pre.latest_execution_payload_header.base_fee_per_gas, - excess_data_gas=uint256(0), # [New in EIP-4844] + excess_data_gas=uint256(0), # [New in Deneb] block_hash=pre.latest_execution_payload_header.block_hash, transactions_root=pre.latest_execution_payload_header.transactions_root, withdrawals_root=pre.latest_execution_payload_header.withdrawals_root, diff --git a/specs/deneb/p2p-interface.md b/specs/deneb/p2p-interface.md index 852597b09..b1ff8b922 100644 --- a/specs/deneb/p2p-interface.md +++ b/specs/deneb/p2p-interface.md @@ -1,6 +1,6 @@ -# EIP-4844 -- Networking +# Deneb -- Networking -This document contains the consensus-layer networking specification for EIP-4844. +This document contains the consensus-layer networking specification for Deneb. The specification of these changes continues in the same format as the network specifications of previous upgrades, and assumes them as pre-requisite. @@ -50,7 +50,7 @@ class SignedBeaconBlockAndBlobsSidecar(Container): ## The gossip domain: gossipsub -Some gossip meshes are upgraded in the fork of EIP-4844 to support upgraded types. +Some gossip meshes are upgraded in the fork of Deneb to support upgraded types. ### Topics and messages @@ -69,7 +69,7 @@ The new topics along with the type of the `data` field of a gossipsub message ar #### Global topics -EIP-4844 introduces a new global topic for beacon block and blobs-sidecars. +Deneb introduces a new global topic for beacon block and blobs-sidecars. ##### `beacon_block` @@ -107,7 +107,7 @@ details on how to handle transitioning gossip topics for this upgrade. **Protocol ID:** `/eth2/beacon_chain/req/beacon_blocks_by_range/2/` -The EIP-4844 fork-digest is introduced to the `context` enum to specify EIP-4844 beacon block type. +The Deneb fork-digest is introduced to the `context` enum to specify Deneb beacon block type. Per `context = compute_fork_digest(fork_version, genesis_validators_root)`: diff --git a/specs/deneb/polynomial-commitments.md b/specs/deneb/polynomial-commitments.md index ac99313ce..959057558 100644 --- a/specs/deneb/polynomial-commitments.md +++ b/specs/deneb/polynomial-commitments.md @@ -1,4 +1,4 @@ -# EIP-4844 -- Polynomial Commitments +# Deneb -- Polynomial Commitments ## Table of contents @@ -48,7 +48,7 @@ ## Introduction -This document specifies basic polynomial operations and KZG polynomial commitment operations as they are needed for the EIP-4844 specification. The implementations are not optimized for performance, but readability. All practical implementations should optimize the polynomial operations. +This document specifies basic polynomial operations and KZG polynomial commitment operations as they are needed for the Deneb specification. The implementations are not optimized for performance, but readability. All practical implementations should optimize the polynomial operations. Functions flagged as "Public method" MUST be provided by the underlying KZG library as public functions. All other functions are private functions used internally by the KZG library. @@ -337,7 +337,7 @@ def evaluate_polynomial_in_evaluation_form(polynomial: Polynomial, ### KZG -KZG core functions. These are also defined in EIP-4844 execution specs. +KZG core functions. These are also defined in Deneb execution specs. #### `blob_to_kzg_commitment` diff --git a/specs/deneb/validator.md b/specs/deneb/validator.md index 413e315fc..92a5e5333 100644 --- a/specs/deneb/validator.md +++ b/specs/deneb/validator.md @@ -1,4 +1,4 @@ -# EIP-4844 -- Honest Validator +# Deneb -- Honest Validator **Notice**: This document is a work-in-progress for researchers and implementers. @@ -25,14 +25,14 @@ ## Introduction -This document represents the changes to be made in the code of an "honest validator" to implement EIP-4844. +This document represents the changes to be made in the code of an "honest validator" to implement Deneb. ## 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 EIP-4844](./beacon-chain.md) are requisite for this document and used throughout. +All terminology, constants, functions, and protocol mechanics defined in the updated [Beacon Chain doc of Deneb](./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 diff --git a/tests/core/pyspec/eth2spec/test/helpers/sharding.py b/tests/core/pyspec/eth2spec/test/helpers/sharding.py index 2ea8c94bc..fd60d5d3b 100644 --- a/tests/core/pyspec/eth2spec/test/helpers/sharding.py +++ b/tests/core/pyspec/eth2spec/test/helpers/sharding.py @@ -12,7 +12,7 @@ from eth2spec.utils.ssz.ssz_impl import serialize # -# Containers from EIP-4844 +# Containers from Deneb # MAX_CALLDATA_SIZE = 2**24 MAX_VERSIONED_HASHES_LIST_SIZE = 2**24 diff --git a/tests/generators/transition/main.py b/tests/generators/transition/main.py index a4eba90df..303f309c2 100644 --- a/tests/generators/transition/main.py +++ b/tests/generators/transition/main.py @@ -16,8 +16,8 @@ from eth2spec.test.altair.transition import ( test_slashing as test_altair_slashing, test_operations as test_altair_operations, ) -from eth2spec.test.eip4844.transition import ( - test_operations as test_eip4844_operations, +from eth2spec.test.deneb.transition import ( + test_operations as test_deneb_operations, ) @@ -46,7 +46,7 @@ if __name__ == "__main__": test_altair_leaking, test_altair_slashing, test_altair_operations, - test_eip4844_operations, + test_deneb_operations, ) for transition_test_module in all_tests: for pre_fork, post_fork in ALL_PRE_POST_FORKS: From f91b9863cec50895143ec0d60249d0d2cb34eec6 Mon Sep 17 00:00:00 2001 From: Potuz Date: Fri, 10 Feb 2023 11:43:38 -0300 Subject: [PATCH 118/158] Simplify commitee weight computation --- specs/phase0/fork-choice.md | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/specs/phase0/fork-choice.md b/specs/phase0/fork-choice.md index e535184af..f2ccc24b9 100644 --- a/specs/phase0/fork-choice.md +++ b/specs/phase0/fork-choice.md @@ -194,10 +194,7 @@ def get_latest_attesting_balance(store: Store, root: Root) -> Gwei: proposer_score = Gwei(0) # Boost is applied if ``root`` is an ancestor of ``proposer_boost_root`` if get_ancestor(store, store.proposer_boost_root, store.blocks[root].slot) == root: - num_validators = len(get_active_validator_indices(state, get_current_epoch(state))) - avg_balance = get_total_active_balance(state) // num_validators - committee_size = num_validators // SLOTS_PER_EPOCH - committee_weight = committee_size * avg_balance + committee_weight = get_total_active_balance(state) // SLOTS_PER_EPOCH proposer_score = (committee_weight * PROPOSER_SCORE_BOOST) // 100 return attestation_score + proposer_score From b76ea49feceb4e6c00c068dd769fdc987a0ed1a2 Mon Sep 17 00:00:00 2001 From: Dankrad Feist Date: Fri, 27 Jan 2023 14:23:38 +0000 Subject: [PATCH 119/158] Add KZG multi verify function --- specs/deneb/polynomial-commitments.md | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/specs/deneb/polynomial-commitments.md b/specs/deneb/polynomial-commitments.md index 959057558..a7df3c84d 100644 --- a/specs/deneb/polynomial-commitments.md +++ b/specs/deneb/polynomial-commitments.md @@ -527,3 +527,28 @@ def verify_blob_kzg_proof_multi(blobs: Sequence[Blob], return verify_kzg_proof_multi(commitments, evaluation_challenges, ys, proofs) ``` + +#### `verify_aggregate_kzg_proof_multi` + +```python +def verify_aggregate_kzg_proof_multi(list_blobs: Sequence[Sequence[Blob]], + list_commitments_bytes: Sequence[Sequence[Bytes48]], + list_aggregated_proof_bytes: Sequence[Bytes48]) -> bool: + """ + Given a list of blobs and an aggregated KZG proof, verify that they correspond to the provided commitments. + + Public method. + """ + + aggregated_poly_commitments, evaluation_challenges, ys = [], [], [] + for blobs, commitments_bytes in zip(list_blobs, list_commitments_bytes): + aggregated_poly_commitment, evaluation_challenge, y = \ + verify_aggregate_kzg_proof_aggregation(blobs, commitments_bytes) + aggregated_poly_commitments.append(aggregated_poly_commitment) + evaluation_challenges.append(evaluation_challenge) + ys.append(y) + + list_aggregated_proof = [bytes_to_kzg_proof(proof) for proof in list_aggregated_proof_bytes] + + return verify_kzg_proof_multi(aggregated_poly_commitments, evaluation_challenges, ys, list_aggregated_proof) +``` From 7f1748b3c876db2ed818a036a16ba117573eafea Mon Sep 17 00:00:00 2001 From: Dankrad Feist Date: Sun, 29 Jan 2023 13:05:02 +0000 Subject: [PATCH 120/158] Change blob verification fiat-shamir to single blob --- specs/deneb/polynomial-commitments.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/specs/deneb/polynomial-commitments.md b/specs/deneb/polynomial-commitments.md index a7df3c84d..40fb83ad4 100644 --- a/specs/deneb/polynomial-commitments.md +++ b/specs/deneb/polynomial-commitments.md @@ -540,15 +540,15 @@ def verify_aggregate_kzg_proof_multi(list_blobs: Sequence[Sequence[Blob]], Public method. """ - aggregated_poly_commitments, evaluation_challenges, ys = [], [], [] - for blobs, commitments_bytes in zip(list_blobs, list_commitments_bytes): - aggregated_poly_commitment, evaluation_challenge, y = \ - verify_aggregate_kzg_proof_aggregation(blobs, commitments_bytes) - aggregated_poly_commitments.append(aggregated_poly_commitment) + commitments, evaluation_challenges, ys, proofs = [], [], [], [] + for blob, commitment_bytes, proof_bytes in zip(blobs, commitments_bytes, proofs_bytes): + commitment = bytes_to_kzg_commitment(commitment_bytes) + commitments.append(commitment) + evaluation_challenge = compute_challenge(blob, commitment) evaluation_challenges.append(evaluation_challenge) - ys.append(y) + polynomial = blob_to_polynomial(blob) + ys.append(evaluate_polynomial_in_evaluation_form(polynomial, evaluation_challenge)) + proofs.append(bytes_to_kzg_proof(proof_bytes)) - list_aggregated_proof = [bytes_to_kzg_proof(proof) for proof in list_aggregated_proof_bytes] - - return verify_kzg_proof_multi(aggregated_poly_commitments, evaluation_challenges, ys, list_aggregated_proof) + return verify_kzg_proof_multi(commitments, evaluation_challenges, ys, proofs) ``` From 86d955ab7f286a2595ec7f3966785de38f717ccf Mon Sep 17 00:00:00 2001 From: Dankrad Feist Date: Mon, 13 Feb 2023 14:32:50 +0000 Subject: [PATCH 121/158] Call compute_challenge with polynomial as argument --- specs/deneb/polynomial-commitments.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/specs/deneb/polynomial-commitments.md b/specs/deneb/polynomial-commitments.md index 40fb83ad4..d4e3b26d6 100644 --- a/specs/deneb/polynomial-commitments.md +++ b/specs/deneb/polynomial-commitments.md @@ -547,6 +547,8 @@ def verify_aggregate_kzg_proof_multi(list_blobs: Sequence[Sequence[Blob]], evaluation_challenge = compute_challenge(blob, commitment) evaluation_challenges.append(evaluation_challenge) polynomial = blob_to_polynomial(blob) + evaluation_challenge = compute_challenge(polynomial, commitment) + evaluation_challenges.append(evaluation_challenge) ys.append(evaluate_polynomial_in_evaluation_form(polynomial, evaluation_challenge)) proofs.append(bytes_to_kzg_proof(proof_bytes)) From c8719f85246a64383bd8cd0a977f88d7a3a255bb Mon Sep 17 00:00:00 2001 From: Jacek Sieka Date: Tue, 14 Feb 2023 13:32:18 +0100 Subject: [PATCH 122/158] Apply suggestions from code review Co-authored-by: Danny Ryan --- specs/deneb/p2p-interface.md | 12 ++++++------ specs/deneb/validator.md | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/specs/deneb/p2p-interface.md b/specs/deneb/p2p-interface.md index 41af2f9f1..d77e4f371 100644 --- a/specs/deneb/p2p-interface.md +++ b/specs/deneb/p2p-interface.md @@ -47,13 +47,13 @@ The specification of these changes continues in the same format as the network s ```python class BlobSidecar(Container): block_root: Root - index: BlobIndex # Index of blob in block + index: BlobIndex # Index of blob in block slot: Slot - block_parent_root: Root # Proposer shuffling determinant + block_parent_root: Root # Proposer shuffling determinant proposer_index: ValidatorIndex blob: Blob kzg_commitment: KZGCommitment - kzg_proof: KZGProof # Allows for quick verification of kzg_commitment + kzg_proof: KZGProof # Allows for quick verification of kzg_commitment ``` ### `SignedBlobSidecar` @@ -101,11 +101,11 @@ The following validations MUST pass before forwarding the `sidecar` on the netwo - _[REJECT]_ The sidecar is for the correct topic -- i.e. `sidecar.index` matches the topic `{index}`. - _[IGNORE]_ The sidecar is not from a future slot (with a `MAXIMUM_GOSSIP_CLOCK_DISPARITY` allowance) -- i.e. validate that `sidecar.slot <= current_slot` (a client MAY queue future blocks for processing at the appropriate slot). - _[IGNORE]_ The sidecar is from a slot greater than the latest finalized slot -- i.e. validate that `sidecar.slot > compute_start_slot_at_epoch(state.finalized_checkpoint.epoch)` -- _[IGNORE]_ The blob's block's parent defined by `sidecar.block_parent_root`) has been seen (via both gossip and non-gossip sources) (a client MAY queue blocks for processing once the parent block is retrieved). +- _[IGNORE]_ The blob's block's parent (defined by `sidecar.block_parent_root`) has been seen (via both gossip and non-gossip sources) (a client MAY queue blocks for processing once the parent block is retrieved). - _[REJECT]_ The proposer signature, `signed_blob_sidecar.signature`, is valid with respect to the `sidecar.proposer_index` pubkey. - _[IGNORE]_ The sidecar is the only sidecar with valid signature received for the tuple `(sidecar.slot, sidecar.proposer_index, sidecar.index)`. -- Clients MUST discard blocks where multiple sidecars for the same proposer and index have been observed. -- _[REJECT]_ The sidecar is proposed by the expected `proposer_index` for the block's slot in the context of the current shuffling (defined by `parent_root`/`slot`). +- _[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. ### Transitioning the gossip @@ -185,7 +185,7 @@ Response Content: Requests sidecars by block root and index. The response is a list of `BlobSidecar` whose length is less than or equal to the number of requests. -It may be less in the case that the responding peer is missing blocks and sidecars. +It may be less in the case that the responding peer is missing blocks or sidecars. The response is unsigned, i.e. `BlobSidecar`, as the signature of the beacon block proposer may not be available beyond the initial distribution via gossip. diff --git a/specs/deneb/validator.md b/specs/deneb/validator.md index bd05c31d2..a415fbf43 100644 --- a/specs/deneb/validator.md +++ b/specs/deneb/validator.md @@ -96,7 +96,7 @@ def get_blob_sidecars(block: BeaconBlock, blobs: Sequence[Blob]) -> Sequence[Blo slot=block.slot, block_parent_root=block.parent_root, blob=blob, - kzg_commitment=block.body.blob_kzg_commitments[idx], + kzg_commitment=block.body.blob_kzg_commitments[index], kzg_proof=compute_kzg_proof(blob), ) for index, blob in enumerate(blobs) @@ -104,7 +104,7 @@ def get_blob_sidecars(block: BeaconBlock, blobs: Sequence[Blob]) -> Sequence[Blo ``` -Then `signed_sidecar = SignedBlobSidecar(message=sidecar, signature=signature)` is constructed and to the global `blob_sidecar_{index}` topics according to its index. +Then `signed_sidecar = SignedBlobSidecar(message=sidecar, signature=signature)` is constructed and published to the `blob_sidecar_{index}` topics according to its index. `signature` is obtained from: From e6b8324e25f4e2151346629cd4535b6fde3ca083 Mon Sep 17 00:00:00 2001 From: Jacek Sieka Date: Tue, 14 Feb 2023 13:39:59 +0100 Subject: [PATCH 123/158] sidecar domain --- specs/deneb/beacon-chain.md | 6 ++++++ specs/deneb/validator.md | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/specs/deneb/beacon-chain.md b/specs/deneb/beacon-chain.md index 97b426f5d..c06e44f39 100644 --- a/specs/deneb/beacon-chain.md +++ b/specs/deneb/beacon-chain.md @@ -48,6 +48,12 @@ This upgrade adds blobs to the beacon chain as part of Deneb. This is an extensi ## Constants +### Domain types + +| Name | Value | +| - | - | +| `DOMAIN_BLOB_SIDECAR` | `DomainType('0x0B000000')` | + ### Blob | Name | Value | diff --git a/specs/deneb/validator.md b/specs/deneb/validator.md index a415fbf43..1d4a7287e 100644 --- a/specs/deneb/validator.md +++ b/specs/deneb/validator.md @@ -112,7 +112,7 @@ Then `signed_sidecar = SignedBlobSidecar(message=sidecar, signature=signature)` def get_blob_sidecar_signature(state: BeaconState, sidecar: BlobSidecar, privkey: int) -> BLSSignature: - domain = get_domain(state, DOMAIN_BEACON_PROPOSER, compute_epoch_at_slot(sidecar.slot)) + domain = get_domain(state, DOMAIN_BLOB_SIDECAR, compute_epoch_at_slot(sidecar.slot)) signing_root = compute_signing_root(sidecar, domain) return bls.Sign(privkey, signing_root) ``` From fc4e1a9acfc6565d42c6756b54b2ec42ec3171a3 Mon Sep 17 00:00:00 2001 From: George Kadianakis Date: Tue, 14 Feb 2023 14:50:44 +0200 Subject: [PATCH 124/158] EIP4844: compute_kzg_proof() can now create proofs within the domain (#3243) This will be used by optimistic rollups to create proofs about past data --- specs/deneb/polynomial-commitments.md | 47 +++++++++++++++++-- .../test_polynomial_commitments.py | 20 ++++++++ 2 files changed, 63 insertions(+), 4 deletions(-) diff --git a/specs/deneb/polynomial-commitments.md b/specs/deneb/polynomial-commitments.md index facf1dbc2..dde75bdcd 100644 --- a/specs/deneb/polynomial-commitments.md +++ b/specs/deneb/polynomial-commitments.md @@ -38,6 +38,7 @@ - [`verify_kzg_proof`](#verify_kzg_proof) - [`verify_kzg_proof_impl`](#verify_kzg_proof_impl) - [`compute_kzg_proof`](#compute_kzg_proof) + - [`compute_quotient_eval_within_domain`](#compute_quotient_eval_within_domain) - [`compute_kzg_proof_impl`](#compute_kzg_proof_impl) - [`compute_aggregated_poly_and_commitment`](#compute_aggregated_poly_and_commitment) - [`compute_aggregate_kzg_proof`](#compute_aggregate_kzg_proof) @@ -427,6 +428,34 @@ def compute_kzg_proof(blob: Blob, z: Bytes32) -> KZGProof: return compute_kzg_proof_impl(polynomial, bytes_to_bls_field(z)) ``` +#### `compute_quotient_eval_within_domain` + +```python +def compute_quotient_eval_within_domain(z: BLSFieldElement, + polynomial: Polynomial, + y: BLSFieldElement + ) -> BLSFieldElement: + """ + Given `y == p(z)` for a polynomial `p(x)`, compute `q(z)`: the KZG quotient polynomial evaluated at `z` for the + special case where `z` is in `ROOTS_OF_UNITY`. + + For more details, read https://dankradfeist.de/ethereum/2021/06/18/pcs-multiproofs.html section "Dividing + when one of the points is zero". The code below computes q(x_m) for the roots of unity special case. + """ + roots_of_unity_brp = bit_reversal_permutation(ROOTS_OF_UNITY) + result = 0 + for i, omega_i in enumerate(roots_of_unity_brp): + if omega_i == z: # skip the evaluation point in the sum + continue + + f_i = int(BLS_MODULUS) + int(polynomial[i]) - int(y) % BLS_MODULUS + numerator = f_i * int(omega_i) % BLS_MODULUS + denominator = int(z) * (int(BLS_MODULUS) + int(z) - int(omega_i)) % BLS_MODULUS + result += div(BLSFieldElement(numerator), BLSFieldElement(denominator)) + + return BLSFieldElement(result % BLS_MODULUS) +``` + #### `compute_kzg_proof_impl` ```python @@ -434,16 +463,26 @@ def compute_kzg_proof_impl(polynomial: Polynomial, z: BLSFieldElement) -> KZGPro """ Helper function for compute_kzg_proof() and compute_aggregate_kzg_proof(). """ + roots_of_unity_brp = bit_reversal_permutation(ROOTS_OF_UNITY) + + # For all x_i, compute p(x_i) - p(z) y = evaluate_polynomial_in_evaluation_form(polynomial, z) polynomial_shifted = [BLSFieldElement((int(p) - int(y)) % BLS_MODULUS) for p in polynomial] - # Make sure we won't divide by zero during division - assert z not in ROOTS_OF_UNITY + # For all x_i, compute (x_i - z) denominator_poly = [BLSFieldElement((int(x) - int(z)) % BLS_MODULUS) for x in bit_reversal_permutation(ROOTS_OF_UNITY)] - # Calculate quotient polynomial by doing point-by-point division - quotient_polynomial = [div(a, b) for a, b in zip(polynomial_shifted, denominator_poly)] + # Compute the quotient polynomial directly in evaluation form + quotient_polynomial = [BLSFieldElement(0)] * FIELD_ELEMENTS_PER_BLOB + for i, (a, b) in enumerate(zip(polynomial_shifted, denominator_poly)): + if b == 0: + # The denominator is zero hence `z` is a root of unity: we must handle it as a special case + quotient_polynomial[i] = compute_quotient_eval_within_domain(roots_of_unity_brp[i], polynomial, y) + else: + # Compute: q(x_i) = (p(x_i) - p(z)) / (x_i - z). + quotient_polynomial[i] = div(a, b) + return KZGProof(g1_lincomb(bit_reversal_permutation(KZG_SETUP_LAGRANGE), quotient_polynomial)) ``` diff --git a/tests/core/pyspec/eth2spec/test/deneb/unittests/polynomial_commitments/test_polynomial_commitments.py b/tests/core/pyspec/eth2spec/test/deneb/unittests/polynomial_commitments/test_polynomial_commitments.py index 4d881e3e3..67dce5c5b 100644 --- a/tests/core/pyspec/eth2spec/test/deneb/unittests/polynomial_commitments/test_polynomial_commitments.py +++ b/tests/core/pyspec/eth2spec/test/deneb/unittests/polynomial_commitments/test_polynomial_commitments.py @@ -87,3 +87,23 @@ def test_barycentric_within_domain(spec, state): # The two evaluations should be agree and p(z) should also be the i-th "coefficient" of the polynomial in # evaluation form assert p_z_coeff == p_z_eval == poly_eval[i] + + +@with_deneb_and_later +@spec_state_test +def test_compute_kzg_proof_within_domain(spec, state): + """ + Create and verify KZG proof that p(z) == y + where z is in the domain of our KZG scheme (i.e. a relevant root of unity). + """ + blob = get_sample_blob(spec) + commitment = spec.blob_to_kzg_commitment(blob) + polynomial = spec.blob_to_polynomial(blob) + + roots_of_unity_brp = spec.bit_reversal_permutation(spec.ROOTS_OF_UNITY) + + for i, z in enumerate(roots_of_unity_brp): + proof = spec.compute_kzg_proof_impl(polynomial, z) + + y = spec.evaluate_polynomial_in_evaluation_form(polynomial, z) + assert spec.verify_kzg_proof_impl(commitment, z, y, proof) From 58207c1c05b494b97bf01176547e2ed8749783f5 Mon Sep 17 00:00:00 2001 From: Jacek Sieka Date: Tue, 14 Feb 2023 14:18:29 +0100 Subject: [PATCH 125/158] Upper limit on indices --- specs/deneb/fork-choice.md | 2 +- specs/deneb/p2p-interface.md | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/specs/deneb/fork-choice.md b/specs/deneb/fork-choice.md index ea235c055..29d59048b 100644 --- a/specs/deneb/fork-choice.md +++ b/specs/deneb/fork-choice.md @@ -44,7 +44,7 @@ The implementation of `is_data_available` will become more sophisticated during Initially, verification requires every verifying actor to retrieve all matching `BlobSidecar`s, and validate the sidecar with `validate_blob_sidecars`. -The block MUST NOT be considered valid until all valid `BlobSidecar`s have been downloaded. Blocks that have been previously validated as available SHOULD be considered available even if the associated `BlobSidecar`s has subsequently been pruned. +The block MUST NOT be considered valid until all valid `BlobSidecar`s have been downloaded. Blocks that have been previously validated as available SHOULD be considered available even if the associated `BlobSidecar`s have subsequently been pruned. ```python def is_data_available(slot: Slot, beacon_block_root: Root, blob_kzg_commitments: Sequence[KZGCommitment]) -> bool: diff --git a/specs/deneb/p2p-interface.md b/specs/deneb/p2p-interface.md index d77e4f371..3cbc00052 100644 --- a/specs/deneb/p2p-interface.md +++ b/specs/deneb/p2p-interface.md @@ -94,7 +94,7 @@ The *type* of the payload of this topic changes to the (modified) `SignedBeaconB ##### `blob_sidecar_{index}` -This topic is used to propagate signed blob sidecars, one for each sidecar index. +This topic is used to propagate signed blob sidecars, one for each sidecar index. The number of indices is defined by `MAX_BLOBS_PER_BLOCK`. The following validations MUST pass before forwarding the `sidecar` on the network, assuming the alias `sidecar = signed_blob_sidecar.message`: @@ -108,6 +108,7 @@ The following validations MUST pass before forwarding the `sidecar` on the netwo - _[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. + ### Transitioning the gossip See gossip transition details found in the [Altair document](../altair/p2p-interface.md#transitioning-the-gossip) for From db5a168f3b073cf525116bca7433fede0172c422 Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Tue, 14 Feb 2023 23:39:43 +0800 Subject: [PATCH 126/158] Move experimental features to `specs/_features` folder --- specs/{ => _features}/custody_game/beacon-chain.md | 0 specs/{ => _features}/custody_game/validator.md | 4 ++-- specs/{ => _features}/das/das-core.md | 0 specs/{ => _features}/das/fork-choice.md | 0 specs/{ => _features}/das/p2p-interface.md | 4 ++-- specs/{ => _features}/das/sampling.md | 0 specs/{ => _features}/sharding/beacon-chain.md | 0 specs/{ => _features}/sharding/p2p-interface.md | 2 +- specs/{ => _features}/sharding/polynomial-commitments.md | 0 specs/{ => _features}/sharding/validator.md | 2 +- 10 files changed, 6 insertions(+), 6 deletions(-) rename specs/{ => _features}/custody_game/beacon-chain.md (100%) rename specs/{ => _features}/custody_game/validator.md (96%) rename specs/{ => _features}/das/das-core.md (100%) rename specs/{ => _features}/das/fork-choice.md (100%) rename specs/{ => _features}/das/p2p-interface.md (98%) rename specs/{ => _features}/das/sampling.md (100%) rename specs/{ => _features}/sharding/beacon-chain.md (100%) rename specs/{ => _features}/sharding/p2p-interface.md (97%) rename specs/{ => _features}/sharding/polynomial-commitments.md (100%) rename specs/{ => _features}/sharding/validator.md (99%) diff --git a/specs/custody_game/beacon-chain.md b/specs/_features/custody_game/beacon-chain.md similarity index 100% rename from specs/custody_game/beacon-chain.md rename to specs/_features/custody_game/beacon-chain.md diff --git a/specs/custody_game/validator.md b/specs/_features/custody_game/validator.md similarity index 96% rename from specs/custody_game/validator.md rename to specs/_features/custody_game/validator.md index 05ceb854d..ed47eb0ac 100644 --- a/specs/custody_game/validator.md +++ b/specs/_features/custody_game/validator.md @@ -36,11 +36,11 @@ docs are requisite for this document and used throughout. Please see the Custody ## Becoming a validator -Becoming a validator in Custody Game is unchanged from Phase 0. See the [Phase 0 validator guide](../phase0/validator.md#becoming-a-validator) for details. +Becoming a validator in Custody Game is unchanged from Phase 0. See the [Phase 0 validator guide](../../phase0/validator.md#becoming-a-validator) for details. ## Beacon chain validator assignments -Beacon chain validator assignments to beacon committees and beacon block proposal are unchanged from Phase 0. See the [Phase 0 validator guide](../phase0/validator.md#validator-assignments) for details. +Beacon chain validator assignments to beacon committees and beacon block proposal are unchanged from Phase 0. See the [Phase 0 validator guide](../../phase0/validator.md#validator-assignments) for details. ##### Custody slashings diff --git a/specs/das/das-core.md b/specs/_features/das/das-core.md similarity index 100% rename from specs/das/das-core.md rename to specs/_features/das/das-core.md diff --git a/specs/das/fork-choice.md b/specs/_features/das/fork-choice.md similarity index 100% rename from specs/das/fork-choice.md rename to specs/_features/das/fork-choice.md diff --git a/specs/das/p2p-interface.md b/specs/_features/das/p2p-interface.md similarity index 98% rename from specs/das/p2p-interface.md rename to specs/_features/das/p2p-interface.md index a60bd9c85..b166c9c3e 100644 --- a/specs/das/p2p-interface.md +++ b/specs/_features/das/p2p-interface.md @@ -143,7 +143,7 @@ If the node does not already have connected peers on the topic it needs to sampl ### Topics and messages -Following the same scheme as the [Phase0 gossip topics](../phase0/p2p-interface.md#topics-and-messages), names and payload types are: +Following the same scheme as the [Phase0 gossip topics](../../phase0/p2p-interface.md#topics-and-messages), names and payload types are: | Name | Message Type | |----------------------------------|---------------------------| | `das_sample_{subnet_index}` | `DASSample` | @@ -192,7 +192,7 @@ This is to serve other peers that may have missed it. To pull samples from nodes, in case of network instability when samples are unavailable, a new query method is added to the Req-Resp domain. -This builds on top of the protocol identification and encoding spec which was introduced in [the Phase0 network spec](../phase0/p2p-interface.md). +This builds on top of the protocol identification and encoding spec which was introduced in [the Phase0 network spec](../../phase0/p2p-interface.md). Note that DAS networking uses a different protocol prefix: `/eth2/das/req` diff --git a/specs/das/sampling.md b/specs/_features/das/sampling.md similarity index 100% rename from specs/das/sampling.md rename to specs/_features/das/sampling.md diff --git a/specs/sharding/beacon-chain.md b/specs/_features/sharding/beacon-chain.md similarity index 100% rename from specs/sharding/beacon-chain.md rename to specs/_features/sharding/beacon-chain.md diff --git a/specs/sharding/p2p-interface.md b/specs/_features/sharding/p2p-interface.md similarity index 97% rename from specs/sharding/p2p-interface.md rename to specs/_features/sharding/p2p-interface.md index 3b627a339..c29146fe9 100644 --- a/specs/sharding/p2p-interface.md +++ b/specs/_features/sharding/p2p-interface.md @@ -39,7 +39,7 @@ The adjustments and additions for Shards are outlined in this document. ### Topics and messages -Following the same scheme as the [Phase0 gossip topics](../phase0/p2p-interface.md#topics-and-messages), names and payload types are: +Following the same scheme as the [Phase0 gossip topics](../../phase0/p2p-interface.md#topics-and-messages), names and payload types are: | Name | Message Type | |---------------------------------|--------------------------| diff --git a/specs/sharding/polynomial-commitments.md b/specs/_features/sharding/polynomial-commitments.md similarity index 100% rename from specs/sharding/polynomial-commitments.md rename to specs/_features/sharding/polynomial-commitments.md diff --git a/specs/sharding/validator.md b/specs/_features/sharding/validator.md similarity index 99% rename from specs/sharding/validator.md rename to specs/_features/sharding/validator.md index 38914095f..466c4df66 100644 --- a/specs/sharding/validator.md +++ b/specs/_features/sharding/validator.md @@ -33,7 +33,7 @@ This document represents the changes to be made in the code of an "honest valida ## Prerequisites -This document is an extension of the [Bellatrix -- Honest Validator](../bellatrix/validator.md) guide. +This document is an extension of the [Bellatrix -- Honest Validator](../../bellatrix/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 [Sharding](./beacon-chain.md) are requisite for this document and used throughout. From 95720872e6097505be325eb5be2e1e348f5cd390 Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Tue, 14 Feb 2023 23:50:00 +0800 Subject: [PATCH 127/158] Update README.md --- Makefile | 6 +++--- README.md | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Makefile b/Makefile index 854f42ce3..d4259b2fe 100644 --- a/Makefile +++ b/Makefile @@ -27,10 +27,10 @@ MARKDOWN_FILES = $(wildcard $(SPEC_DIR)/phase0/*.md) \ $(wildcard $(SPEC_DIR)/altair/*.md) $(wildcard $(SPEC_DIR)/altair/**/*.md) \ $(wildcard $(SPEC_DIR)/bellatrix/*.md) \ $(wildcard $(SPEC_DIR)/capella/*.md) $(wildcard $(SPEC_DIR)/capella/**/*.md) \ - $(wildcard $(SPEC_DIR)/custody/*.md) \ - $(wildcard $(SPEC_DIR)/das/*.md) \ - $(wildcard $(SPEC_DIR)/sharding/*.md) \ $(wildcard $(SPEC_DIR)/deneb/*.md) $(wildcard $(SPEC_DIR)/deneb/**/*.md) \ + $(wildcard $(SPEC_DIR)/_features/custody/*.md) \ + $(wildcard $(SPEC_DIR)/_features/das/*.md) \ + $(wildcard $(SPEC_DIR)/_features/sharding/*.md) \ $(wildcard $(SSZ_DIR)/*.md) COV_HTML_OUT=.htmlcov diff --git a/README.md b/README.md index da893a53d..49e1c3a4d 100644 --- a/README.md +++ b/README.md @@ -26,9 +26,9 @@ Features are researched and developed in parallel, and then consolidated into se | - | - | - | | Capella (tentative) |
  • Core
    • [Beacon chain changes](specs/capella/beacon-chain.md)
    • [Capella fork](specs/capella/fork.md)
  • Additions
    • [Light client sync protocol changes](specs/capella/light-client/sync-protocol.md) ([fork](specs/capella/light-client/fork.md), [full node](specs/capella/light-client/full-node.md), [networking](specs/capella/light-client/p2p-interface.md))
    • [Validator additions](specs/capella/validator.md)
    • [P2P networking](specs/capella/p2p-interface.md)
| | Deneb (tentative) |
  • Core
    • [Beacon Chain changes](specs/deneb/beacon-chain.md)
    • [Deneb fork](specs/deneb/fork.md)
    • [Polynomial commitments](specs/deneb/polynomial-commitments.md)
    • [Fork choice changes](specs/deneb/fork-choice.md)
  • Additions
    • [Light client sync protocol changes](specs/deneb/light-client/sync-protocol.md) ([fork](specs/deneb/light-client/fork.md), [full node](specs/deneb/light-client/full-node.md), [networking](specs/deneb/light-client/p2p-interface.md))
    • [Honest validator guide changes](specs/deneb/validator.md)
    • [P2P networking](specs/deneb/p2p-interface.md)
| -| Sharding (outdated) |
  • Core
    • [Beacon Chain changes](specs/sharding/beacon-chain.md)
  • Additions
    • [P2P networking](specs/sharding/p2p-interface.md)
| -| Custody Game (outdated) |
  • Core
    • [Beacon Chain changes](specs/custody_game/beacon-chain.md)
  • Additions
    • [Honest validator guide changes](specs/custody_game/validator.md)
| Dependent on sharding | -| Data Availability Sampling (outdated) |
  • Core
    • [Core types and functions](specs/das/das-core.md)
    • [Fork choice changes](specs/das/fork-choice.md)
  • Additions
    • [P2P Networking](specs/das/p2p-interface.md)
    • [Sampling process](specs/das/sampling.md)
|
  • Dependent on sharding
  • [Technical explainer](https://hackmd.io/@HWeNw8hNRimMm2m2GH56Cw/B1YJPGkpD)
| +| Sharding (outdated) |
  • Core
    • [Beacon Chain changes](specs/_features/sharding/beacon-chain.md)
  • Additions
    • [P2P networking](specs/_features/sharding/p2p-interface.md)
| +| Custody Game (outdated) |
  • Core
    • [Beacon Chain changes](specs/_features/custody_game/beacon-chain.md)
  • Additions
    • [Honest validator guide changes](specs/_features/custody_game/validator.md)
| Dependent on sharding | +| Data Availability Sampling (outdated) |
  • Core
    • [Core types and functions](specs/_features/das/das-core.md)
    • [Fork choice changes](specs/_features/das/fork-choice.md)
  • Additions
    • [P2P Networking](specs/_features/das/p2p-interface.md)
    • [Sampling process](specs/_features/das/sampling.md)
|
  • Dependent on sharding
  • [Technical explainer](https://hackmd.io/@HWeNw8hNRimMm2m2GH56Cw/B1YJPGkpD)
| ### Accompanying documents can be found in [specs](specs) and include: From c49a2c2855cb19bcbf350540e130f9478633bdb7 Mon Sep 17 00:00:00 2001 From: dankrad Date: Tue, 14 Feb 2023 20:00:58 +0000 Subject: [PATCH 128/158] Update specs/deneb/polynomial-commitments.md Co-authored-by: George Kadianakis --- specs/deneb/polynomial-commitments.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/specs/deneb/polynomial-commitments.md b/specs/deneb/polynomial-commitments.md index d4e3b26d6..b604e7431 100644 --- a/specs/deneb/polynomial-commitments.md +++ b/specs/deneb/polynomial-commitments.md @@ -406,7 +406,7 @@ def verify_kzg_proof_multi(commitments: Sequence[KZGCommitment], num_commitments = int.to_bytes(len(commitments), 8, ENDIANNESS) data = RANDOM_CHALLENGE_KZG_MULTI_DOMAIN + degree_poly + num_commitments - # Append each polynomial which is composed by field elements + # Append all inputs to the transcript before we hash for commitment, z, y, proof in zip(commitments, zs, ys, proofs): data += commitment \ + int.to_bytes(z, BYTES_PER_FIELD_ELEMENT, ENDIANNESS) \ From 855cf062f01f6b66915e007d2bdba673c31c51c7 Mon Sep 17 00:00:00 2001 From: Dankrad Feist Date: Tue, 14 Feb 2023 20:07:22 +0000 Subject: [PATCH 129/158] Remove additional function --- specs/deneb/polynomial-commitments.md | 27 --------------------------- 1 file changed, 27 deletions(-) diff --git a/specs/deneb/polynomial-commitments.md b/specs/deneb/polynomial-commitments.md index b604e7431..c9d7496fa 100644 --- a/specs/deneb/polynomial-commitments.md +++ b/specs/deneb/polynomial-commitments.md @@ -527,30 +527,3 @@ def verify_blob_kzg_proof_multi(blobs: Sequence[Blob], return verify_kzg_proof_multi(commitments, evaluation_challenges, ys, proofs) ``` - -#### `verify_aggregate_kzg_proof_multi` - -```python -def verify_aggregate_kzg_proof_multi(list_blobs: Sequence[Sequence[Blob]], - list_commitments_bytes: Sequence[Sequence[Bytes48]], - list_aggregated_proof_bytes: Sequence[Bytes48]) -> bool: - """ - Given a list of blobs and an aggregated KZG proof, verify that they correspond to the provided commitments. - - Public method. - """ - - commitments, evaluation_challenges, ys, proofs = [], [], [], [] - for blob, commitment_bytes, proof_bytes in zip(blobs, commitments_bytes, proofs_bytes): - commitment = bytes_to_kzg_commitment(commitment_bytes) - commitments.append(commitment) - evaluation_challenge = compute_challenge(blob, commitment) - evaluation_challenges.append(evaluation_challenge) - polynomial = blob_to_polynomial(blob) - evaluation_challenge = compute_challenge(polynomial, commitment) - evaluation_challenges.append(evaluation_challenge) - ys.append(evaluate_polynomial_in_evaluation_form(polynomial, evaluation_challenge)) - proofs.append(bytes_to_kzg_proof(proof_bytes)) - - return verify_kzg_proof_multi(commitments, evaluation_challenges, ys, proofs) -``` From 3a6fccd389de63c80b45c08cf62b6d867e36597a Mon Sep 17 00:00:00 2001 From: Dankrad Feist Date: Tue, 14 Feb 2023 20:17:25 +0000 Subject: [PATCH 130/158] Remove double hashing --- specs/deneb/polynomial-commitments.md | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/specs/deneb/polynomial-commitments.md b/specs/deneb/polynomial-commitments.md index c9d7496fa..e4e899d67 100644 --- a/specs/deneb/polynomial-commitments.md +++ b/specs/deneb/polynomial-commitments.md @@ -248,8 +248,7 @@ def compute_challenge(blob: Blob, data += commitment # Transcript has been prepared: time to create the challenges - hashed_data = hash(data) - return hash_to_bls_field(hashed_data + b'\x00') + return hash_to_bls_field(data) ``` #### `bls_modular_inverse` @@ -413,8 +412,7 @@ def verify_kzg_proof_multi(commitments: Sequence[KZGCommitment], + int.to_bytes(y, BYTES_PER_FIELD_ELEMENT, ENDIANNESS) \ + proof - hashed_data = hash(data) - r = hash_to_bls_field(hashed_data + b'\x00') + r = hash_to_bls_field(data) r_powers = compute_powers(r, len(commitments)) # Verify: e(sum r^i proof_i, [s]) == From aafbd45a19d75dc825d94ec513b920e63dae98c5 Mon Sep 17 00:00:00 2001 From: dankrad Date: Tue, 14 Feb 2023 20:59:24 +0000 Subject: [PATCH 131/158] Update specs/deneb/polynomial-commitments.md Co-authored-by: George Kadianakis --- specs/deneb/polynomial-commitments.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/specs/deneb/polynomial-commitments.md b/specs/deneb/polynomial-commitments.md index e4e899d67..04f1b97c6 100644 --- a/specs/deneb/polynomial-commitments.md +++ b/specs/deneb/polynomial-commitments.md @@ -419,9 +419,9 @@ def verify_kzg_proof_multi(commitments: Sequence[KZGCommitment], # e(sum r^i (commitment_i - [y_i]) + sum r^i z_i proof_i, [1]) proof_lincomb = g1_lincomb(proofs, r_powers) proof_z_lincomb = g1_lincomb(proofs, [z * r_power for z, r_power in zip(zs, r_powers)]) - C_minus_ys = [bls.G1_to_bytes48(bls.add(bls.bytes48_to_G1(commitment), bls.multiply(bls.G1, BLS_MODULUS - y))) + C_minus_ys = [bls.add(bls.bytes48_to_G1(commitment), bls.multiply(bls.G1, BLS_MODULUS - y)) for commitment, y in zip(commitments, ys)] - C_minus_y_as_KZGCommitments = [KZGCommitment(x) for x in C_minus_ys] + C_minus_y_as_KZGCommitments = [KZGCommitment(bls.G1_to_bytes48(x)) for x in C_minus_ys] C_minus_y_lincomb = g1_lincomb(C_minus_y_as_KZGCommitments, r_powers) return bls.pairing_check([ From d8509e42c6c02f97ec738843ba617d292b5f8554 Mon Sep 17 00:00:00 2001 From: dankrad Date: Tue, 14 Feb 2023 20:59:41 +0000 Subject: [PATCH 132/158] Update specs/deneb/polynomial-commitments.md Co-authored-by: George Kadianakis --- specs/deneb/polynomial-commitments.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/specs/deneb/polynomial-commitments.md b/specs/deneb/polynomial-commitments.md index 04f1b97c6..4d990113d 100644 --- a/specs/deneb/polynomial-commitments.md +++ b/specs/deneb/polynomial-commitments.md @@ -493,7 +493,7 @@ def verify_blob_kzg_proof(blob: Blob, polynomial = blob_to_polynomial(blob) evaluation_challenge = compute_challenge(blob, commitment) - # Evaluate polynomial at `evaluation_challenge` (evaluation function checks for div-by-zero) + # Evaluate polynomial at `evaluation_challenge` y = evaluate_polynomial_in_evaluation_form(polynomial, evaluation_challenge) # Verify proof From c3cb7fa773e10e14695536b6576491636cac58c3 Mon Sep 17 00:00:00 2001 From: Dankrad Feist Date: Tue, 14 Feb 2023 21:10:09 +0000 Subject: [PATCH 133/158] Comment on compute_challenge, assert on verify_blob_kzg_proof_multi --- specs/deneb/polynomial-commitments.md | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/specs/deneb/polynomial-commitments.md b/specs/deneb/polynomial-commitments.md index 4d990113d..2484e1a2c 100644 --- a/specs/deneb/polynomial-commitments.md +++ b/specs/deneb/polynomial-commitments.md @@ -229,11 +229,8 @@ def blob_to_polynomial(blob: Blob) -> Polynomial: def compute_challenge(blob: Blob, commitment: KZGCommitment) -> BLSFieldElement: """ - Return the Fiat-Shamir challenges required by the rest of the protocol. + Return the Fiat-Shamir challenge required by the rest of the protocol. The Fiat-Shamir logic works as per the following pseudocode: - - hashed_data = hash(DOMAIN_SEPARATOR, polynomial, commitment) - eval_challenge = hash(hashed_data, 0) """ # Append the number of polynomials and the degree of each polynomial as a domain separator @@ -512,6 +509,8 @@ def verify_blob_kzg_proof_multi(blobs: Sequence[Blob], Public method. """ + + assert len(blobs) == len(commitments_bytes) == len(proofs_bytes) commitments, evaluation_challenges, ys, proofs = [], [], [], [] for blob, commitment_bytes, proof_bytes in zip(blobs, commitments_bytes, proofs_bytes): From 4086a09d0fdc8e21bc96b68160051cb53c3c24ea Mon Sep 17 00:00:00 2001 From: Dankrad Feist Date: Tue, 14 Feb 2023 21:21:46 +0000 Subject: [PATCH 134/158] multi -> batch --- specs/deneb/polynomial-commitments.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/specs/deneb/polynomial-commitments.md b/specs/deneb/polynomial-commitments.md index 2484e1a2c..39ae3570c 100644 --- a/specs/deneb/polynomial-commitments.md +++ b/specs/deneb/polynomial-commitments.md @@ -36,12 +36,12 @@ - [`blob_to_kzg_commitment`](#blob_to_kzg_commitment) - [`verify_kzg_proof`](#verify_kzg_proof) - [`verify_kzg_proof_impl`](#verify_kzg_proof_impl) - - [`verify_kzg_proof_multi`](#verify_kzg_proof_multi) + - [`verify_kzg_proof_batch`](#verify_kzg_proof_batch) - [`compute_kzg_proof`](#compute_kzg_proof) - [`compute_kzg_proof_impl`](#compute_kzg_proof_impl) - [`compute_blob_kzg_proof`](#compute_blob_kzg_proof) - [`verify_blob_kzg_proof`](#verify_blob_kzg_proof) - - [`verify_blob_kzg_proof_multi`](#verify_blob_kzg_proof_multi) + - [`verify_blob_kzg_proof_batch`](#verify_blob_kzg_proof_batch) @@ -83,7 +83,7 @@ Public functions MUST accept raw bytes as input and perform the required cryptog | - | - | | `FIELD_ELEMENTS_PER_BLOB` | `uint64(4096)` | | `FIAT_SHAMIR_PROTOCOL_DOMAIN` | `b'FSBLOBVERIFY_V1_'` | -| `RANDOM_CHALLENGE_KZG_MULTI_DOMAIN` | `b'RCKZGMULTI___V1_'` | +| `RANDOM_CHALLENGE_KZG_BATCH_DOMAIN` | `b'RCKZGBATCH___V1_'` | ### Crypto @@ -383,10 +383,10 @@ def verify_kzg_proof_impl(commitment: KZGCommitment, ]) ``` -#### `verify_kzg_proof_multi` +#### `verify_kzg_proof_batch` ```python -def verify_kzg_proof_multi(commitments: Sequence[KZGCommitment], +def verify_kzg_proof_batch(commitments: Sequence[KZGCommitment], zs: Sequence[BLSFieldElement], ys: Sequence[BLSFieldElement], proofs: Sequence[KZGProof]) -> bool: @@ -400,7 +400,7 @@ def verify_kzg_proof_multi(commitments: Sequence[KZGCommitment], # r just has to be random. degree_poly = int.to_bytes(FIELD_ELEMENTS_PER_BLOB, 8, ENDIANNESS) num_commitments = int.to_bytes(len(commitments), 8, ENDIANNESS) - data = RANDOM_CHALLENGE_KZG_MULTI_DOMAIN + degree_poly + num_commitments + data = RANDOM_CHALLENGE_KZG_BATCH_DOMAIN + degree_poly + num_commitments # Append all inputs to the transcript before we hash for commitment, z, y, proof in zip(commitments, zs, ys, proofs): @@ -498,10 +498,10 @@ def verify_blob_kzg_proof(blob: Blob, return verify_kzg_proof_impl(commitment, evaluation_challenge, y, proof) ``` -#### `verify_blob_kzg_proof_multi` +#### `verify_blob_kzg_proof_batch` ```python -def verify_blob_kzg_proof_multi(blobs: Sequence[Blob], +def verify_blob_kzg_proof_batch(blobs: Sequence[Blob], commitments_bytes: Sequence[Bytes48], proofs_bytes: Sequence[Bytes48]) -> bool: """ @@ -522,5 +522,5 @@ def verify_blob_kzg_proof_multi(blobs: Sequence[Blob], ys.append(evaluate_polynomial_in_evaluation_form(polynomial, evaluation_challenge)) proofs.append(bytes_to_kzg_proof(proof_bytes)) - return verify_kzg_proof_multi(commitments, evaluation_challenges, ys, proofs) + return verify_kzg_proof_batch(commitments, evaluation_challenges, ys, proofs) ``` From 3a37c3c4978467f8909f66d8899b80b9e1373e72 Mon Sep 17 00:00:00 2001 From: Jacek Sieka Date: Wed, 15 Feb 2023 08:00:39 +0100 Subject: [PATCH 135/158] Allow clients to orphan blocks from spammy proposers Proposers that spam the blob topic with multiple blob versions, some of which are invalid, MAY see their block orphaned. --- specs/deneb/p2p-interface.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/specs/deneb/p2p-interface.md b/specs/deneb/p2p-interface.md index 3cbc00052..6f64e5514 100644 --- a/specs/deneb/p2p-interface.md +++ b/specs/deneb/p2p-interface.md @@ -104,7 +104,7 @@ The following validations MUST pass before forwarding the `sidecar` on the netwo - _[IGNORE]_ The blob's block's parent (defined by `sidecar.block_parent_root`) has been seen (via both gossip and non-gossip sources) (a client MAY queue blocks for processing once the parent block is retrieved). - _[REJECT]_ The proposer signature, `signed_blob_sidecar.signature`, is valid with respect to the `sidecar.proposer_index` pubkey. - _[IGNORE]_ The sidecar is the only sidecar with valid signature received for the tuple `(sidecar.slot, sidecar.proposer_index, sidecar.index)`. - -- Clients MUST discard blocks where multiple sidecars for the same proposer and index have been observed. + -- If full verification of the blob fails at a later processing stage, clients MUST clear the blob from this "seen" cache so as to allow a the valid blob to propagate. Block producers MAY orphan blocks if they have observed multiple blobs signed by the proposer for the same "seen" tuple. - _[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. From da34af97d4b6575131e67c2bf22acb6de4f0951d Mon Sep 17 00:00:00 2001 From: Jacek Sieka Date: Wed, 15 Feb 2023 08:51:57 +0100 Subject: [PATCH 136/158] simplify blob verification, range request * validate blobs using raw types * remove `BlobSidecars` and send flattened list of `BlobSidecar` instances instead --- specs/deneb/fork-choice.md | 35 +++++++++++++++--------------- specs/deneb/p2p-interface.md | 41 ++++++++++++------------------------ 2 files changed, 30 insertions(+), 46 deletions(-) diff --git a/specs/deneb/fork-choice.md b/specs/deneb/fork-choice.md index 29d59048b..58c281a59 100644 --- a/specs/deneb/fork-choice.md +++ b/specs/deneb/fork-choice.md @@ -27,37 +27,36 @@ This is the modification of the fork choice accompanying the Deneb upgrade. #### `validate_blob_sidecars` ```python -def validate_blob_sidecars(slot: Slot, - beacon_block_root: Root, - expected_kzg_commitments: Sequence[KZGCommitment], - blob_sidecars: Sequence[BlobSidecar]) -> None: - assert slot == blobs_sidecar.beacon_block_slot - assert beacon_block_root == blobs_sidecar.beacon_block_root - assert len(expected_kzg_commitments) == len(blob_sidecars) - # TODO validate commitments individually or aggregate first? - # assert verify_aggregate_kzg_proof(blobs, expected_kzg_commitments, kzg_aggregated_proof) +def validate_blobs(expected_kzg_commitments: Sequence[KZGCommitment], + blobs: Sequence[Blob], + proofs: Sequence[KZGProof]) -> None: + assert len(expected_kzg_commitments) == len(blobs) + assert len(blobs) == len(proofs) + + # Clients MAY use `verify_blob_kzg_proof_multi` for efficiency + for commitment, blob, proof in zip(expected_kzg_commitments, blobs, proofs): + assert verify_blob_kzg_proof(commitment, blob, proof) ``` #### `is_data_available` The implementation of `is_data_available` will become more sophisticated during later scaling upgrades. -Initially, verification requires every verifying actor to retrieve all matching `BlobSidecar`s, -and validate the sidecar with `validate_blob_sidecars`. +Initially, verification requires every verifying actor to retrieve all matching `Blob`s and `KZGProof`s, and validate them with `validate_blobs`. -The block MUST NOT be considered valid until all valid `BlobSidecar`s have been downloaded. Blocks that have been previously validated as available SHOULD be considered available even if the associated `BlobSidecar`s have subsequently been pruned. +The block MUST NOT be considered valid until all valid `Blob`s have been downloaded. Blocks that have been previously validated as available SHOULD be considered available even if the associated `Blob`s have subsequently been pruned. ```python -def is_data_available(slot: Slot, beacon_block_root: Root, blob_kzg_commitments: Sequence[KZGCommitment]) -> bool: - # `retrieve_blobs_sidecar` is implementation and context dependent, raises an exception if not available. +def is_data_available(beacon_block_root: Root, blob_kzg_commitments: Sequence[KZGCommitment]) -> bool: + # `retrieve_blobs_and_proofs` is implementation and context dependent, raises an exception if not available. It returns all the blobs for the given block root. # Note: the p2p network does not guarantee sidecar retrieval outside of `MIN_EPOCHS_FOR_BLOBS_SIDECARS_REQUESTS` - sidecars = retrieve_blob_sidecars(slot, beacon_block_root) + blobs, proofs = retrieve_blobs_and_proofs(beacon_block_root) - # For testing, `retrieve_blobs_sidecar` returns "TEST". + # For testing, `retrieve_blobs_and_proofs` returns "TEST". # TODO: Remove it once we have a way to inject `BlobSidecar` into tests. if isinstance(sidecar, str): return True - validate_blob_sidecars(slot, beacon_block_root, blob_kzg_commitments, sidecars) + validate_blobs(expected_kzg_commitments, blobs, proofs) return True ``` @@ -89,7 +88,7 @@ def on_block(store: Store, signed_block: SignedBeaconBlock) -> None: # [New in Deneb] # Check if blob data is available # If not, this block MAY be queued and subsequently considered when blob data becomes available - assert is_data_available(block.slot, hash_tree_root(block), block.body.blob_kzg_commitments) + assert is_data_available(hash_tree_root(block), block.body.blob_kzg_commitments) # Check the block is valid and compute the post-state state = pre_state.copy() diff --git a/specs/deneb/p2p-interface.md b/specs/deneb/p2p-interface.md index 6f64e5514..63a63feda 100644 --- a/specs/deneb/p2p-interface.md +++ b/specs/deneb/p2p-interface.md @@ -218,34 +218,24 @@ Request Content: ``` Response Content: - -```python -class BlobSidecars(Container): - block_root: Root - List[BlobSidecar, MAX_BLOBS_PER_BLOCK] -``` - ``` ( - List[BlobSidecars, MAX_REQUEST_BLOB_SIDECARS] + List[BlobSidecar, MAX_REQUEST_BLOB_SIDECARS * MAX_BLOBS_PER_BLOCK] ) ``` -Requests blob sidecars in the slot range `[start_slot, start_slot + count)`, -leading up to the current head block as selected by fork choice. +Requests blob sidecars in the slot range `[start_slot, start_slot + count)`, leading up to the current head block as selected by fork choice. -The response is unsigned, i.e. `BlobSidecarsByRange`, as the signature of the beacon block proposer -may not be available beyond the initial distribution via gossip. +The response is unsigned, i.e. `BlobSidecarsByRange`, as the signature of the beacon block proposer may not be available beyond the initial distribution via gossip. -Before consuming the next response chunk, the response reader SHOULD verify the blobs sidecar is well-formatted and -correct w.r.t. the expected KZG commitments through `validate_blobs_sidecar`. +Before consuming the next response chunk, the response reader SHOULD verify the blobs sidecar is well-formatted and correct w.r.t. the expected KZG commitments through `validate_blobs_sidecar`. -`BlobsSidecarsByRange` is primarily used to sync blobs that may have been missed on gossip and to sync within the `MIN_EPOCHS_FOR_BLOBS_SIDECARS_REQUESTS` window. +`BlobSidecarsByRange` is primarily used to sync blobs that may have been missed on gossip and to sync within the `MIN_EPOCHS_FOR_BLOBS_SIDECARS_REQUESTS` window. The request MUST be encoded as an SSZ-container. The response MUST consist of zero or more `response_chunk`. -Each _successful_ `response_chunk` MUST contain a single `BlobsSidecar` payload. +Each _successful_ `response_chunk` MUST contain a single `BlobSidecar` payload. Clients MUST keep a record of signed blobs sidecars seen on the epoch range `[max(current_epoch - MIN_EPOCHS_FOR_BLOBS_SIDECARS_REQUESTS, DENEB_FORK_EPOCH), current_epoch]` @@ -265,26 +255,21 @@ to be fully compliant with `BlobsSidecarsByRange` requests. participating in the networking immediately, other peers MAY disconnect and/or temporarily ban such an un-synced or semi-synced client. -Clients MUST respond with at least the first blobs sidecar that exists in the range, if they have it, -and no more than `MAX_REQUEST_BLOCKS_DENEB` sidecars. +Clients MUST respond with at least the first blobs sidecar that exists in the range, if they have it, and no more than `MAX_REQUEST_BLOB_SIDECARS * MAX_BLOBS_PER_BLOCK` sidecars. -The following blobs sidecars, where they exist, MUST be sent in consecutive order. +The following blobs sidecars, where they exist, MUST be sent in consecutive `(slot, index)` order. Clients MAY limit the number of blobs sidecars in the response. -An empty `BlobSidecar` is one that does not contain any blobs, but contains non-zero `beacon_block_root`, `beacon_block_slot` and a valid `kzg_aggregated_proof`. -Clients MAY NOT want to consider empty `BlobSidecar`s in rate limiting logic. +The response MUST contain no more than `count * MAX_BLOBS_PER_BLOCK` blob sidecars. -The response MUST contain no more than `count` blobs sidecars. - -Clients MUST respond with blobs sidecars from their view of the current fork choice --- that is, blobs sidecars as included by blocks from the single chain defined by the current head. +Clients MUST respond with blob sidecars from their view of the current fork choice +-- that is, blob sidecars as included by blocks from the single chain defined by the current head. Of note, blocks from slots before the finalization MUST lead to the finalized block reported in the `Status` handshake. -Clients MUST respond with blobs sidecars that are consistent from a single chain within the context of the request. +Clients MUST respond with blob sidecars that are consistent from a single chain within the context of the request. -After the initial blobs sidecar, clients MAY stop in the process of responding -if their fork choice changes the view of the chain in the context of the request. +After the initial blob sidecar, clients MAY stop in the process of responding if their fork choice changes the view of the chain in the context of the request. ## Design decision rationale From a5f61fc173cc4c8bf350bc72945f5cf3dc39bae5 Mon Sep 17 00:00:00 2001 From: Jacek Sieka Date: Wed, 15 Feb 2023 08:57:23 +0100 Subject: [PATCH 137/158] correct function --- specs/deneb/validator.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/specs/deneb/validator.md b/specs/deneb/validator.md index 1d4a7287e..d86709874 100644 --- a/specs/deneb/validator.md +++ b/specs/deneb/validator.md @@ -97,7 +97,7 @@ def get_blob_sidecars(block: BeaconBlock, blobs: Sequence[Blob]) -> Sequence[Blo block_parent_root=block.parent_root, blob=blob, kzg_commitment=block.body.blob_kzg_commitments[index], - kzg_proof=compute_kzg_proof(blob), + kzg_proof=compute_blob_kzg_proof(blob), ) for index, blob in enumerate(blobs) ] From f0dc126602041679ed50f3cc8d6f6efccc0fa0ab Mon Sep 17 00:00:00 2001 From: Jacek Sieka Date: Wed, 15 Feb 2023 09:10:31 +0100 Subject: [PATCH 138/158] doctoc --- specs/deneb/beacon-chain.md | 1 + 1 file changed, 1 insertion(+) diff --git a/specs/deneb/beacon-chain.md b/specs/deneb/beacon-chain.md index c06e44f39..ba0148d47 100644 --- a/specs/deneb/beacon-chain.md +++ b/specs/deneb/beacon-chain.md @@ -11,6 +11,7 @@ - [Introduction](#introduction) - [Custom types](#custom-types) - [Constants](#constants) + - [Domain types](#domain-types) - [Blob](#blob) - [Preset](#preset) - [Execution](#execution) From b26c136b34e7fd4cc35cd6c690bcf3af2389848f Mon Sep 17 00:00:00 2001 From: Stefan Bratanov Date: Wed, 15 Feb 2023 17:25:08 +0000 Subject: [PATCH 139/158] fix Deneb reference in presets --- presets/mainnet/deneb.yaml | 2 +- presets/minimal/deneb.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/presets/mainnet/deneb.yaml b/presets/mainnet/deneb.yaml index 3866e82ff..ebe33f2d1 100644 --- a/presets/mainnet/deneb.yaml +++ b/presets/mainnet/deneb.yaml @@ -1,4 +1,4 @@ -# Mainnet preset - Phase0 +# Mainnet preset - Deneb # Misc # --------------------------------------------------------------- diff --git a/presets/minimal/deneb.yaml b/presets/minimal/deneb.yaml index dacacf5b8..e51b5587d 100644 --- a/presets/minimal/deneb.yaml +++ b/presets/minimal/deneb.yaml @@ -1,4 +1,4 @@ -# Minimal preset - Phase0 +# Minimal preset - Deneb # Misc # --------------------------------------------------------------- From 48e7be7dd0e1ce10ce151f797dbfa58a31c76b2d Mon Sep 17 00:00:00 2001 From: Dankrad Feist Date: Wed, 15 Feb 2023 18:23:04 +0000 Subject: [PATCH 140/158] Fix doctoc --- specs/deneb/polynomial-commitments.md | 1 + 1 file changed, 1 insertion(+) diff --git a/specs/deneb/polynomial-commitments.md b/specs/deneb/polynomial-commitments.md index 460fb8297..6b94e1d9a 100644 --- a/specs/deneb/polynomial-commitments.md +++ b/specs/deneb/polynomial-commitments.md @@ -38,6 +38,7 @@ - [`verify_kzg_proof_impl`](#verify_kzg_proof_impl) - [`verify_kzg_proof_batch`](#verify_kzg_proof_batch) - [`compute_kzg_proof`](#compute_kzg_proof) + - [`compute_quotient_eval_within_domain`](#compute_quotient_eval_within_domain) - [`compute_kzg_proof_impl`](#compute_kzg_proof_impl) - [`compute_blob_kzg_proof`](#compute_blob_kzg_proof) - [`verify_blob_kzg_proof`](#verify_blob_kzg_proof) From 078d62e6ffe1f840e2d2ae9bc43d3b2e48c5926a Mon Sep 17 00:00:00 2001 From: Dankrad Feist Date: Wed, 15 Feb 2023 19:48:58 +0000 Subject: [PATCH 141/158] Simplify compute_challenge --- specs/deneb/polynomial-commitments.md | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/specs/deneb/polynomial-commitments.md b/specs/deneb/polynomial-commitments.md index 6b94e1d9a..afcf934fc 100644 --- a/specs/deneb/polynomial-commitments.md +++ b/specs/deneb/polynomial-commitments.md @@ -231,21 +231,16 @@ def compute_challenge(blob: Blob, commitment: KZGCommitment) -> BLSFieldElement: """ Return the Fiat-Shamir challenge required by the rest of the protocol. - The Fiat-Shamir logic works as per the following pseudocode: """ - # Append the number of polynomials and the degree of each polynomial as a domain separator - num_polynomials = int.to_bytes(1, 8, ENDIANNESS) - degree_poly = int.to_bytes(FIELD_ELEMENTS_PER_BLOB, 8, ENDIANNESS) - data = FIAT_SHAMIR_PROTOCOL_DOMAIN + degree_poly + num_polynomials + # Append the degree of the polynomial as a domain separator + degree_poly = int.to_bytes(FIELD_ELEMENTS_PER_BLOB, 16, ENDIANNESS) + data = FIAT_SHAMIR_PROTOCOL_DOMAIN + degree_poly - # Append each polynomial which is composed by field elements data += blob - - # Append serialized G1 points data += commitment - # Transcript has been prepared: time to create the challenges + # Transcript has been prepared: time to create the challenge return hash_to_bls_field(data) ``` From c39fda19c6bfdb39054c4f3e02d2316886efaa04 Mon Sep 17 00:00:00 2001 From: Jacek Sieka Date: Thu, 16 Feb 2023 08:18:52 +0100 Subject: [PATCH 142/158] Apply suggestions from code review Co-authored-by: Danny Ryan Co-authored-by: Jimmy Chen --- specs/deneb/fork-choice.md | 5 +++-- specs/deneb/p2p-interface.md | 8 ++++---- specs/deneb/validator.md | 2 +- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/specs/deneb/fork-choice.md b/specs/deneb/fork-choice.md index 58c281a59..46403cbe9 100644 --- a/specs/deneb/fork-choice.md +++ b/specs/deneb/fork-choice.md @@ -24,7 +24,7 @@ This is the modification of the fork choice accompanying the Deneb upgrade. ## Helpers -#### `validate_blob_sidecars` +#### `validate_blobs` ```python def validate_blobs(expected_kzg_commitments: Sequence[KZGCommitment], @@ -47,7 +47,8 @@ The block MUST NOT be considered valid until all valid `Blob`s have been downloa ```python def is_data_available(beacon_block_root: Root, blob_kzg_commitments: Sequence[KZGCommitment]) -> bool: - # `retrieve_blobs_and_proofs` is implementation and context dependent, raises an exception if not available. It returns all the blobs for the given block root. + # `retrieve_blobs_and_proofs` is implementation and context dependent + # It returns all the blobs for the given block root, and raises an exception if not available # Note: the p2p network does not guarantee sidecar retrieval outside of `MIN_EPOCHS_FOR_BLOBS_SIDECARS_REQUESTS` blobs, proofs = retrieve_blobs_and_proofs(beacon_block_root) diff --git a/specs/deneb/p2p-interface.md b/specs/deneb/p2p-interface.md index 63a63feda..258b9e3f1 100644 --- a/specs/deneb/p2p-interface.md +++ b/specs/deneb/p2p-interface.md @@ -228,7 +228,7 @@ Requests blob sidecars in the slot range `[start_slot, start_slot + count)`, lea The response is unsigned, i.e. `BlobSidecarsByRange`, as the signature of the beacon block proposer may not be available beyond the initial distribution via gossip. -Before consuming the next response chunk, the response reader SHOULD verify the blobs sidecar is well-formatted and correct w.r.t. the expected KZG commitments through `validate_blobs_sidecar`. +Before consuming the next response chunk, the response reader SHOULD verify the blob sidecar is well-formatted and correct w.r.t. the expected KZG commitments through `validate_blobs`. `BlobSidecarsByRange` is primarily used to sync blobs that may have been missed on gossip and to sync within the `MIN_EPOCHS_FOR_BLOBS_SIDECARS_REQUESTS` window. @@ -255,11 +255,11 @@ to be fully compliant with `BlobsSidecarsByRange` requests. participating in the networking immediately, other peers MAY disconnect and/or temporarily ban such an un-synced or semi-synced client. -Clients MUST respond with at least the first blobs sidecar that exists in the range, if they have it, and no more than `MAX_REQUEST_BLOB_SIDECARS * MAX_BLOBS_PER_BLOCK` sidecars. +Clients MUST respond with at least the first blob sidecar that exists in the range, if they have it, and no more than `MAX_REQUEST_BLOB_SIDECARS * MAX_BLOBS_PER_BLOCK` sidecars. -The following blobs sidecars, where they exist, MUST be sent in consecutive `(slot, index)` order. +The following blob sidecars, where they exist, MUST be sent in consecutive `(slot, index)` order. -Clients MAY limit the number of blobs sidecars in the response. +Clients MAY limit the number of blob sidecars in the response. The response MUST contain no more than `count * MAX_BLOBS_PER_BLOCK` blob sidecars. diff --git a/specs/deneb/validator.md b/specs/deneb/validator.md index d86709874..45a8e5c83 100644 --- a/specs/deneb/validator.md +++ b/specs/deneb/validator.md @@ -104,7 +104,7 @@ def get_blob_sidecars(block: BeaconBlock, blobs: Sequence[Blob]) -> Sequence[Blo ``` -Then `signed_sidecar = SignedBlobSidecar(message=sidecar, signature=signature)` is constructed and published to the `blob_sidecar_{index}` topics according to its index. +Then for each sidecar, `signed_sidecar = SignedBlobSidecar(message=sidecar, signature=signature)` is constructed and published to the `blob_sidecar_{index}` topics according to its index. `signature` is obtained from: From 639ff9b2b0acfbba0e642e04da6efa76ad1f5292 Mon Sep 17 00:00:00 2001 From: Jacek Sieka Date: Thu, 16 Feb 2023 08:30:40 +0100 Subject: [PATCH 143/158] Update specs/deneb/p2p-interface.md Co-authored-by: Jimmy Chen --- specs/deneb/p2p-interface.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/specs/deneb/p2p-interface.md b/specs/deneb/p2p-interface.md index 258b9e3f1..2ba8de409 100644 --- a/specs/deneb/p2p-interface.md +++ b/specs/deneb/p2p-interface.md @@ -38,7 +38,7 @@ The specification of these changes continues in the same format as the network s |------------------------------------------|-----------------------------------|---------------------------------------------------------------------| | `MAX_REQUEST_BLOCKS_DENEB` | `2**7` (= 128) | Maximum number of blocks in a single request | | `MAX_REQUEST_BLOB_SIDECARS` | `2**7` (= 128) | Maximum number of blob sidecars in a single request | -| `MIN_EPOCHS_FOR_BLOBS_SIDECARS_REQUESTS` | `2**12` (= 4096 epochs, ~18 days) | The minimum epoch range over which a node must serve blobs sidecars | +| `MIN_EPOCHS_FOR_BLOB_SIDECARS_REQUESTS` | `2**12` (= 4096 epochs, ~18 days) | The minimum epoch range over which a node must serve blob sidecars | ## Containers From 24a19bb886f7294f8b9c8ff990818936b044f5fa Mon Sep 17 00:00:00 2001 From: Jacek Sieka Date: Thu, 16 Feb 2023 09:12:34 +0100 Subject: [PATCH 144/158] fixes * fight the test suite * clarify who orphans the block * must supply all blobs of a block in range request --- setup.py | 4 ++-- specs/deneb/fork-choice.md | 6 +++--- specs/deneb/p2p-interface.md | 23 ++++++++++++++--------- 3 files changed, 19 insertions(+), 14 deletions(-) diff --git a/setup.py b/setup.py index f87ed5a6c..7b1c718b8 100644 --- a/setup.py +++ b/setup.py @@ -653,9 +653,9 @@ T = TypeVar('T') # For generic function @classmethod def sundry_functions(cls) -> str: return super().sundry_functions() + '\n\n' + ''' -def retrieve_blobs_sidecar(slot: Slot, beacon_block_root: Root) -> PyUnion[BlobsSidecar, str]: +def retrieve_blobs_and_proofs(slot: Slot, beacon_block_root: Root) -> PyUnion[BlobsSidecar, str]: # pylint: disable=unused-argument - return "TEST"''' + return ("TEST", "TEST")''' @classmethod def hardcoded_custom_type_dep_constants(cls, spec_object) -> str: diff --git a/specs/deneb/fork-choice.md b/specs/deneb/fork-choice.md index 46403cbe9..a2866092d 100644 --- a/specs/deneb/fork-choice.md +++ b/specs/deneb/fork-choice.md @@ -8,7 +8,7 @@ - [Introduction](#introduction) - [Containers](#containers) - [Helpers](#helpers) - - [`validate_blob_sidecars`](#validate_blob_sidecars) + - [`validate_blobs`](#validate_blobs) - [`is_data_available`](#is_data_available) - [Updated fork-choice handlers](#updated-fork-choice-handlers) - [`on_block`](#on_block) @@ -52,9 +52,9 @@ def is_data_available(beacon_block_root: Root, blob_kzg_commitments: Sequence[KZ # Note: the p2p network does not guarantee sidecar retrieval outside of `MIN_EPOCHS_FOR_BLOBS_SIDECARS_REQUESTS` blobs, proofs = retrieve_blobs_and_proofs(beacon_block_root) - # For testing, `retrieve_blobs_and_proofs` returns "TEST". + # For testing, `retrieve_blobs_and_proofs` returns ("TEST", "TEST"). # TODO: Remove it once we have a way to inject `BlobSidecar` into tests. - if isinstance(sidecar, str): + if isinstance(blobs, str): return True validate_blobs(expected_kzg_commitments, blobs, proofs) diff --git a/specs/deneb/p2p-interface.md b/specs/deneb/p2p-interface.md index 2ba8de409..5e0b16207 100644 --- a/specs/deneb/p2p-interface.md +++ b/specs/deneb/p2p-interface.md @@ -14,6 +14,7 @@ The specification of these changes continues in the same format as the network s - [Containers](#containers) - [`BlobSidecar`](#blobsidecar) - [`SignedBlobSidecar`](#signedblobsidecar) + - [`BlobIdentifier`](#blobidentifier) - [The gossip domain: gossipsub](#the-gossip-domain-gossipsub) - [Topics and messages](#topics-and-messages) - [Global topics](#global-topics) @@ -61,7 +62,15 @@ class BlobSidecar(Container): ```python class SignedBlobSidecar(Container): message: BlobSidecar - signature: Signature + signature: BLSSignature +``` + +### `BlobIdentifier` + +```python +class BlobIdentifier(Container): + block_root: Root + index: uint64 ``` ## The gossip domain: gossipsub @@ -104,7 +113,7 @@ The following validations MUST pass before forwarding the `sidecar` on the netwo - _[IGNORE]_ The blob's block's parent (defined by `sidecar.block_parent_root`) has been seen (via both gossip and non-gossip sources) (a client MAY queue blocks for processing once the parent block is retrieved). - _[REJECT]_ The proposer signature, `signed_blob_sidecar.signature`, is valid with respect to the `sidecar.proposer_index` pubkey. - _[IGNORE]_ The sidecar is the only sidecar with valid signature received for the tuple `(sidecar.slot, sidecar.proposer_index, sidecar.index)`. - -- If full verification of the blob fails at a later processing stage, clients MUST clear the blob from this "seen" cache so as to allow a the valid blob to propagate. Block producers MAY orphan blocks if they have observed multiple blobs signed by the proposer for the same "seen" tuple. + -- If full verification of the blob fails at a later processing stage, clients MUST clear the blob from this "seen" cache so as to allow a the valid blob to propagate. The next block producer MAY orphan the block if they have observed multiple blobs signed by the proposer for the same "seen" tuple. - _[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. @@ -164,12 +173,6 @@ New in deneb. Request Content: -```python -class BlobIdentifier(Container): - block_root: Root - index: uint64 -``` - ``` ( List[BlobIdentifier, MAX_REQUEST_BLOBS_SIDECARS * MAX_BLOBS_PER_BLOCK] @@ -255,7 +258,9 @@ to be fully compliant with `BlobsSidecarsByRange` requests. participating in the networking immediately, other peers MAY disconnect and/or temporarily ban such an un-synced or semi-synced client. -Clients MUST respond with at least the first blob sidecar that exists in the range, if they have it, and no more than `MAX_REQUEST_BLOB_SIDECARS * MAX_BLOBS_PER_BLOCK` sidecars. +Clients MUST respond with at least the blob sidecars of the first blob-carrying block that exists in the range, if they have it, and no more than `MAX_REQUEST_BLOB_SIDECARS * MAX_BLOBS_PER_BLOCK` sidecars. + +Clients MUST include all blob sidecars of each block from which they include blob sidecars. The following blob sidecars, where they exist, MUST be sent in consecutive `(slot, index)` order. From 5fe857b2096c6a903ac0c822cae66e2236f03feb Mon Sep 17 00:00:00 2001 From: Jacek Sieka Date: Thu, 16 Feb 2023 09:20:40 +0100 Subject: [PATCH 145/158] fixes --- setup.py | 2 +- specs/deneb/p2p-interface.md | 2 +- specs/deneb/validator.md | 1 - 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/setup.py b/setup.py index 7b1c718b8..666ba8afc 100644 --- a/setup.py +++ b/setup.py @@ -653,7 +653,7 @@ T = TypeVar('T') # For generic function @classmethod def sundry_functions(cls) -> str: return super().sundry_functions() + '\n\n' + ''' -def retrieve_blobs_and_proofs(slot: Slot, beacon_block_root: Root) -> PyUnion[BlobsSidecar, str]: +def retrieve_blobs_and_proofs(slot: Slot, beacon_block_root: Root) -> PyUnion[(Blob, KZGProof), (str, str)]: # pylint: disable=unused-argument return ("TEST", "TEST")''' diff --git a/specs/deneb/p2p-interface.md b/specs/deneb/p2p-interface.md index 5e0b16207..163522ec3 100644 --- a/specs/deneb/p2p-interface.md +++ b/specs/deneb/p2p-interface.md @@ -284,5 +284,5 @@ This "sidecar" design provides forward compatibility for further data increases with full sharding `is_data_available()` can be replaced by data-availability-sampling (DAS) thus avoiding all blobs being downloaded by all beacon nodes on the network. -Such sharding design may introduce an updated `BlobsSidecar` to identify the shard, +Such sharding design may introduce an updated `BlobSidecar` to identify the shard, but does not affect the `BeaconBlock` structure. diff --git a/specs/deneb/validator.md b/specs/deneb/validator.md index 45a8e5c83..b29330ce5 100644 --- a/specs/deneb/validator.md +++ b/specs/deneb/validator.md @@ -52,7 +52,6 @@ def get_blobs_and_kzg_commitments(payload_id: PayloadId) -> Tuple[Sequence[BLSFi ## Beacon chain responsibilities All validator responsibilities remain unchanged other than those noted below. -Namely, the blob handling and the addition of `SignedBeaconBlockAndBlobsSidecar`. ### Block and sidecar proposal From f23ed0cdbc4d7590212653a460eb709350e7ed37 Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Thu, 16 Feb 2023 21:11:18 +0800 Subject: [PATCH 146/158] Make linter happy --- setup.py | 2 +- specs/deneb/fork-choice.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/setup.py b/setup.py index 031ac7457..9c5488f12 100644 --- a/setup.py +++ b/setup.py @@ -653,7 +653,7 @@ T = TypeVar('T') # For generic function @classmethod def sundry_functions(cls) -> str: return super().sundry_functions() + '\n\n' + ''' -def retrieve_blobs_and_proofs(slot: Slot, beacon_block_root: Root) -> PyUnion[(Blob, KZGProof), (str, str)]: +def retrieve_blobs_and_proofs(beacon_block_root: Root) -> PyUnion[Tuple[Blob, KZGProof], Tuple[str, str]]: # pylint: disable=unused-argument return ("TEST", "TEST")''' diff --git a/specs/deneb/fork-choice.md b/specs/deneb/fork-choice.md index 2757e591e..8fa08357a 100644 --- a/specs/deneb/fork-choice.md +++ b/specs/deneb/fork-choice.md @@ -54,7 +54,7 @@ def is_data_available(beacon_block_root: Root, blob_kzg_commitments: Sequence[KZ # For testing, `retrieve_blobs_and_proofs` returns ("TEST", "TEST"). # TODO: Remove it once we have a way to inject `BlobSidecar` into tests. - if isinstance(blobs, str): + if isinstance(blobs, str) or isinstance(proofs, str): return True validate_blobs(blob_kzg_commitments, blobs, proofs) From a7e45db9ac2b60a33e144444969ad3ac0aae3d4c Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Thu, 16 Feb 2023 22:09:57 +0800 Subject: [PATCH 147/158] Fix `verify_kzg_proof_batch` and the tests --- specs/deneb/fork-choice.md | 4 +-- specs/deneb/polynomial-commitments.md | 9 ++++--- ...lobs_sidecar.py => test_validate_blobs.py} | 26 ++++++++++--------- 3 files changed, 21 insertions(+), 18 deletions(-) rename tests/core/pyspec/eth2spec/test/deneb/unittests/fork_choice/{test_validate_blobs_sidecar.py => test_validate_blobs.py} (54%) diff --git a/specs/deneb/fork-choice.md b/specs/deneb/fork-choice.md index 8fa08357a..e93eb54fa 100644 --- a/specs/deneb/fork-choice.md +++ b/specs/deneb/fork-choice.md @@ -33,9 +33,7 @@ def validate_blobs(expected_kzg_commitments: Sequence[KZGCommitment], assert len(expected_kzg_commitments) == len(blobs) assert len(blobs) == len(proofs) - # Clients MAY use `verify_blob_kzg_proof_multi` for efficiency - for commitment, blob, proof in zip(expected_kzg_commitments, blobs, proofs): - assert verify_blob_kzg_proof(commitment, blob, proof) + assert verify_blob_kzg_proof_batch(blobs, expected_kzg_commitments, proofs) ``` #### `is_data_available` diff --git a/specs/deneb/polynomial-commitments.md b/specs/deneb/polynomial-commitments.md index afcf934fc..76affe620 100644 --- a/specs/deneb/polynomial-commitments.md +++ b/specs/deneb/polynomial-commitments.md @@ -411,15 +411,18 @@ def verify_kzg_proof_batch(commitments: Sequence[KZGCommitment], # Verify: e(sum r^i proof_i, [s]) == # e(sum r^i (commitment_i - [y_i]) + sum r^i z_i proof_i, [1]) proof_lincomb = g1_lincomb(proofs, r_powers) - proof_z_lincomb = g1_lincomb(proofs, [z * r_power for z, r_power in zip(zs, r_powers)]) + proof_z_lincomb = g1_lincomb( + proofs, + [BLSFieldElement((int(z) * int(r_power)) % BLS_MODULUS) for z, r_power in zip(zs, r_powers)], + ) C_minus_ys = [bls.add(bls.bytes48_to_G1(commitment), bls.multiply(bls.G1, BLS_MODULUS - y)) for commitment, y in zip(commitments, ys)] C_minus_y_as_KZGCommitments = [KZGCommitment(bls.G1_to_bytes48(x)) for x in C_minus_ys] C_minus_y_lincomb = g1_lincomb(C_minus_y_as_KZGCommitments, r_powers) return bls.pairing_check([ - [proof_lincomb, bls.neg(KZG_SETUP_G2[1])], - [bls.add(C_minus_y_lincomb, proof_z_lincomb), bls.G2] + [bls.bytes48_to_G1(proof_lincomb), bls.neg(bls.bytes96_to_G2(KZG_SETUP_G2[1]))], + [bls.add(bls.bytes48_to_G1(C_minus_y_lincomb), bls.bytes48_to_G1(proof_z_lincomb)), bls.G2] ]) ``` diff --git a/tests/core/pyspec/eth2spec/test/deneb/unittests/fork_choice/test_validate_blobs_sidecar.py b/tests/core/pyspec/eth2spec/test/deneb/unittests/fork_choice/test_validate_blobs.py similarity index 54% rename from tests/core/pyspec/eth2spec/test/deneb/unittests/fork_choice/test_validate_blobs_sidecar.py rename to tests/core/pyspec/eth2spec/test/deneb/unittests/fork_choice/test_validate_blobs.py index 87ed9ff8e..d9934c5ad 100644 --- a/tests/core/pyspec/eth2spec/test/deneb/unittests/fork_choice/test_validate_blobs_sidecar.py +++ b/tests/core/pyspec/eth2spec/test/deneb/unittests/fork_choice/test_validate_blobs.py @@ -16,7 +16,7 @@ from eth2spec.test.helpers.sharding import ( ) -def _run_validate_blobs_sidecar_test(spec, state, blob_count): +def _run_validate_blobs(spec, state, blob_count): block = build_empty_block_for_next_slot(spec, state) opaque_tx, blobs, blob_kzg_commitments = get_sample_opaque_tx(spec, blob_count=blob_count) block.body.blob_kzg_commitments = blob_kzg_commitments @@ -24,30 +24,32 @@ def _run_validate_blobs_sidecar_test(spec, state, blob_count): block.body.execution_payload.block_hash = compute_el_block_hash(spec, block.body.execution_payload) state_transition_and_sign_block(spec, state, block) - blobs_sidecar = spec.get_blobs_sidecar(block, blobs) - expected_commitments = [spec.blob_to_kzg_commitment(blobs[i]) for i in range(blob_count)] - spec.validate_blobs_sidecar(block.slot, block.hash_tree_root(), expected_commitments, blobs_sidecar) + # Also test the proof generation in `get_blob_sidecars` + blob_sidecars = spec.get_blob_sidecars(block, blobs) + blobs = [sidecar.blob for sidecar in blob_sidecars] + kzg_proofs = [sidecar.kzg_proof for sidecar in blob_sidecars] + spec.validate_blobs(blob_kzg_commitments, blobs, kzg_proofs) @with_deneb_and_later @spec_state_test -def test_validate_blobs_sidecar_zero_blobs(spec, state): - _run_validate_blobs_sidecar_test(spec, state, blob_count=0) +def test_validate_blobs_zero_blobs(spec, state): + _run_validate_blobs(spec, state, blob_count=0) @with_deneb_and_later @spec_state_test -def test_validate_blobs_sidecar_one_blob(spec, state): - _run_validate_blobs_sidecar_test(spec, state, blob_count=1) +def test_validate_blobs_one_blob(spec, state): + _run_validate_blobs(spec, state, blob_count=1) @with_deneb_and_later @spec_state_test -def test_validate_blobs_sidecar_two_blobs(spec, state): - _run_validate_blobs_sidecar_test(spec, state, blob_count=2) +def test_validate_blobs_two_blobs(spec, state): + _run_validate_blobs(spec, state, blob_count=2) @with_deneb_and_later @spec_state_test -def test_validate_blobs_sidecar_max_blobs(spec, state): - _run_validate_blobs_sidecar_test(spec, state, blob_count=spec.MAX_BLOBS_PER_BLOCK) +def test_validate_blobs_max_blobs(spec, state): + _run_validate_blobs(spec, state, blob_count=spec.MAX_BLOBS_PER_BLOCK) From a562710fe6f6c15f93f06f6d40ba7599133747b5 Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Fri, 17 Feb 2023 01:22:11 +0800 Subject: [PATCH 148/158] Fix `compute_quotient_eval_within_domain` overflow --- specs/deneb/polynomial-commitments.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/specs/deneb/polynomial-commitments.md b/specs/deneb/polynomial-commitments.md index afcf934fc..593c1a4f3 100644 --- a/specs/deneb/polynomial-commitments.md +++ b/specs/deneb/polynomial-commitments.md @@ -459,7 +459,7 @@ def compute_quotient_eval_within_domain(z: BLSFieldElement, f_i = int(BLS_MODULUS) + int(polynomial[i]) - int(y) % BLS_MODULUS numerator = f_i * int(omega_i) % BLS_MODULUS denominator = int(z) * (int(BLS_MODULUS) + int(z) - int(omega_i)) % BLS_MODULUS - result += div(BLSFieldElement(numerator), BLSFieldElement(denominator)) + result += int(div(BLSFieldElement(numerator), BLSFieldElement(denominator))) return BLSFieldElement(result % BLS_MODULUS) ``` From 9dd7d2ba2f5b9bb1ce50494d1971d483764afcb6 Mon Sep 17 00:00:00 2001 From: Danny Ryan Date: Fri, 17 Feb 2023 11:59:56 -0700 Subject: [PATCH 149/158] fix Blob pluralization in a few places --- specs/deneb/p2p-interface.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/specs/deneb/p2p-interface.md b/specs/deneb/p2p-interface.md index 163522ec3..8357776ab 100644 --- a/specs/deneb/p2p-interface.md +++ b/specs/deneb/p2p-interface.md @@ -201,7 +201,7 @@ No more than `MAX_REQUEST_BLOBS_SIDECARS * MAX_BLOBS_PER_BLOCK` may be requested The response MUST consist of zero or more `response_chunk`. Each _successful_ `response_chunk` MUST contain a single `BlobSidecar` payload. -Clients MUST support requesting sidecars since `minimum_request_epoch`, where `minimum_request_epoch = max(finalized_epoch, current_epoch - MIN_EPOCHS_FOR_BLOBS_SIDECARS_REQUESTS, DENEB_FORK_EPOCH)`. If any root in the request content references a block earlier than `minimum_request_epoch`, peers MAY respond with error code `3: ResourceUnavailable` or not include the blob in the response. +Clients MUST support requesting sidecars since `minimum_request_epoch`, where `minimum_request_epoch = max(finalized_epoch, current_epoch - MIN_EPOCHS_FOR_BLOB_SIDECARS_REQUESTS, DENEB_FORK_EPOCH)`. If any root in the request content references a block earlier than `minimum_request_epoch`, peers MAY respond with error code `3: ResourceUnavailable` or not include the blob in the response. Clients MUST respond with at least one sidecar, if they have it. Clients MAY limit the number of blocks and sidecars in the response. @@ -233,7 +233,7 @@ The response is unsigned, i.e. `BlobSidecarsByRange`, as the signature of the be Before consuming the next response chunk, the response reader SHOULD verify the blob sidecar is well-formatted and correct w.r.t. the expected KZG commitments through `validate_blobs`. -`BlobSidecarsByRange` is primarily used to sync blobs that may have been missed on gossip and to sync within the `MIN_EPOCHS_FOR_BLOBS_SIDECARS_REQUESTS` window. +`BlobSidecarsByRange` is primarily used to sync blobs that may have been missed on gossip and to sync within the `MIN_EPOCHS_FOR_BLOB_SIDECARS_REQUESTS` window. The request MUST be encoded as an SSZ-container. @@ -241,18 +241,18 @@ The response MUST consist of zero or more `response_chunk`. Each _successful_ `response_chunk` MUST contain a single `BlobSidecar` payload. Clients MUST keep a record of signed blobs sidecars seen on the epoch range -`[max(current_epoch - MIN_EPOCHS_FOR_BLOBS_SIDECARS_REQUESTS, DENEB_FORK_EPOCH), current_epoch]` +`[max(current_epoch - MIN_EPOCHS_FOR_BLOB_SIDECARS_REQUESTS, DENEB_FORK_EPOCH), current_epoch]` where `current_epoch` is defined by the current wall-clock time, and clients MUST support serving requests of blobs on this range. -Peers that are unable to reply to blob sidecar requests within the `MIN_EPOCHS_FOR_BLOBS_SIDECARS_REQUESTS` +Peers that are unable to reply to blob sidecar requests within the `MIN_EPOCHS_FOR_BLOB_SIDECARS_REQUESTS` epoch range SHOULD respond with error code `3: ResourceUnavailable`. Such peers that are unable to successfully reply to this range of requests MAY get descored or disconnected at any time. *Note*: The above requirement implies that nodes that start from a recent weak subjectivity checkpoint -MUST backfill the local blobs database to at least epoch `current_epoch - MIN_EPOCHS_FOR_BLOBS_SIDECARS_REQUESTS` -to be fully compliant with `BlobsSidecarsByRange` requests. +MUST backfill the local blobs database to at least epoch `current_epoch - MIN_EPOCHS_FOR_BLOB_SIDECARS_REQUESTS` +to be fully compliant with `BlobSidecarsByRange` requests. *Note*: Although clients that bootstrap from a weak subjectivity checkpoint can begin participating in the networking immediately, other peers MAY From c1a2962b31ee17c9795308e690a568a26c2e8917 Mon Sep 17 00:00:00 2001 From: kevaundray Date: Sat, 18 Feb 2023 15:09:43 +0000 Subject: [PATCH 150/158] Update polynomial-commitments.md --- specs/deneb/polynomial-commitments.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/specs/deneb/polynomial-commitments.md b/specs/deneb/polynomial-commitments.md index 593c1a4f3..0e076cd4e 100644 --- a/specs/deneb/polynomial-commitments.md +++ b/specs/deneb/polynomial-commitments.md @@ -469,7 +469,7 @@ def compute_quotient_eval_within_domain(z: BLSFieldElement, ```python def compute_kzg_proof_impl(polynomial: Polynomial, z: BLSFieldElement) -> KZGProof: """ - Helper function for compute_kzg_proof() and compute_aggregate_kzg_proof(). + Helper function for compute_kzg_proof(). """ roots_of_unity_brp = bit_reversal_permutation(ROOTS_OF_UNITY) From 54d2559eb54db217844d30098662e0be3c8d9e5c Mon Sep 17 00:00:00 2001 From: Jacek Sieka Date: Sat, 18 Feb 2023 17:45:16 +0100 Subject: [PATCH 151/158] remove producer reorg on multi-blob * also, use root/index for uniqueness --- specs/deneb/p2p-interface.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/specs/deneb/p2p-interface.md b/specs/deneb/p2p-interface.md index 8357776ab..b11e61ef6 100644 --- a/specs/deneb/p2p-interface.md +++ b/specs/deneb/p2p-interface.md @@ -112,8 +112,7 @@ The following validations MUST pass before forwarding the `sidecar` on the netwo - _[IGNORE]_ The sidecar is from a slot greater than the latest finalized slot -- i.e. validate that `sidecar.slot > compute_start_slot_at_epoch(state.finalized_checkpoint.epoch)` - _[IGNORE]_ The blob's block's parent (defined by `sidecar.block_parent_root`) has been seen (via both gossip and non-gossip sources) (a client MAY queue blocks for processing once the parent block is retrieved). - _[REJECT]_ The proposer signature, `signed_blob_sidecar.signature`, is valid with respect to the `sidecar.proposer_index` pubkey. -- _[IGNORE]_ The sidecar is the only sidecar with valid signature received for the tuple `(sidecar.slot, sidecar.proposer_index, sidecar.index)`. - -- If full verification of the blob fails at a later processing stage, clients MUST clear the blob from this "seen" cache so as to allow a the valid blob to propagate. The next block producer MAY orphan the block if they have observed multiple blobs signed by the proposer for the same "seen" tuple. +- _[IGNORE]_ The sidecar is the only sidecar with valid signature received for the tuple `(sidecar.block_root, sidecar.index)`. - _[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. From 0632a5a32ca0e7915a8d63600d47f950f4c64c31 Mon Sep 17 00:00:00 2001 From: kevaundray Date: Mon, 20 Feb 2023 10:54:16 +0000 Subject: [PATCH 152/158] Update specs/deneb/polynomial-commitments.md Co-authored-by: Hsiao-Wei Wang --- specs/deneb/polynomial-commitments.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/specs/deneb/polynomial-commitments.md b/specs/deneb/polynomial-commitments.md index 0e076cd4e..31138a5ef 100644 --- a/specs/deneb/polynomial-commitments.md +++ b/specs/deneb/polynomial-commitments.md @@ -469,7 +469,7 @@ def compute_quotient_eval_within_domain(z: BLSFieldElement, ```python def compute_kzg_proof_impl(polynomial: Polynomial, z: BLSFieldElement) -> KZGProof: """ - Helper function for compute_kzg_proof(). + Helper function for `compute_kzg_proof()` and `compute_blob_kzg_proof()`. """ roots_of_unity_brp = bit_reversal_permutation(ROOTS_OF_UNITY) From 83cf02f66818b71256d7c2d6cf41f66118cf4951 Mon Sep 17 00:00:00 2001 From: kevaundray Date: Mon, 20 Feb 2023 10:57:39 +0000 Subject: [PATCH 153/158] Remove repeated computation --- specs/deneb/polynomial-commitments.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/specs/deneb/polynomial-commitments.md b/specs/deneb/polynomial-commitments.md index 593c1a4f3..6978317d7 100644 --- a/specs/deneb/polynomial-commitments.md +++ b/specs/deneb/polynomial-commitments.md @@ -479,7 +479,7 @@ def compute_kzg_proof_impl(polynomial: Polynomial, z: BLSFieldElement) -> KZGPro # For all x_i, compute (x_i - z) denominator_poly = [BLSFieldElement((int(x) - int(z)) % BLS_MODULUS) - for x in bit_reversal_permutation(ROOTS_OF_UNITY)] + for x in roots_of_unity_brp] # Compute the quotient polynomial directly in evaluation form quotient_polynomial = [BLSFieldElement(0)] * FIELD_ELEMENTS_PER_BLOB From 4e2a9920f1e1f1f7496289161fa7d830bb5b1d0e Mon Sep 17 00:00:00 2001 From: Jacek Sieka Date: Mon, 20 Feb 2023 12:15:53 +0100 Subject: [PATCH 154/158] Update specs/deneb/p2p-interface.md Co-authored-by: g11tech --- specs/deneb/p2p-interface.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/specs/deneb/p2p-interface.md b/specs/deneb/p2p-interface.md index b11e61ef6..531161b4e 100644 --- a/specs/deneb/p2p-interface.md +++ b/specs/deneb/p2p-interface.md @@ -70,7 +70,7 @@ class SignedBlobSidecar(Container): ```python class BlobIdentifier(Container): block_root: Root - index: uint64 + index: BlobIndex ``` ## The gossip domain: gossipsub From ac0ec660d39e9d2470c0efb6be8ad53815085833 Mon Sep 17 00:00:00 2001 From: Jacek Sieka Date: Mon, 20 Feb 2023 16:35:11 +0100 Subject: [PATCH 155/158] add parent validation requirement sama as block --- specs/deneb/p2p-interface.md | 1 + 1 file changed, 1 insertion(+) diff --git a/specs/deneb/p2p-interface.md b/specs/deneb/p2p-interface.md index 531161b4e..040d594dd 100644 --- a/specs/deneb/p2p-interface.md +++ b/specs/deneb/p2p-interface.md @@ -111,6 +111,7 @@ The following validations MUST pass before forwarding the `sidecar` on the netwo - _[IGNORE]_ The sidecar is not from a future slot (with a `MAXIMUM_GOSSIP_CLOCK_DISPARITY` allowance) -- i.e. validate that `sidecar.slot <= current_slot` (a client MAY queue future blocks for processing at the appropriate slot). - _[IGNORE]_ The sidecar is from a slot greater than the latest finalized slot -- i.e. validate that `sidecar.slot > compute_start_slot_at_epoch(state.finalized_checkpoint.epoch)` - _[IGNORE]_ The blob's block's parent (defined by `sidecar.block_parent_root`) has been seen (via both gossip and non-gossip sources) (a client MAY queue blocks for processing once the parent block is retrieved). +- _[REJECT]_ The blob's block's parent (defined by `sidecar.block_parent_root`) passes validation. - _[REJECT]_ The proposer signature, `signed_blob_sidecar.signature`, is valid with respect to the `sidecar.proposer_index` pubkey. - _[IGNORE]_ The sidecar is the only sidecar with valid signature received for the tuple `(sidecar.block_root, sidecar.index)`. - _[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`). From dff740752b9b0f20792e242c2e789cc88f1fe787 Mon Sep 17 00:00:00 2001 From: djrtwo Date: Mon, 20 Feb 2023 10:07:24 -0700 Subject: [PATCH 156/158] add deposit+bls_change test --- .../test/capella/sanity/test_blocks.py | 43 ++++++++++++++++++- 1 file changed, 41 insertions(+), 2 deletions(-) diff --git a/tests/core/pyspec/eth2spec/test/capella/sanity/test_blocks.py b/tests/core/pyspec/eth2spec/test/capella/sanity/test_blocks.py index 079990e3e..d62e458be 100644 --- a/tests/core/pyspec/eth2spec/test/capella/sanity/test_blocks.py +++ b/tests/core/pyspec/eth2spec/test/capella/sanity/test_blocks.py @@ -37,7 +37,7 @@ from eth2spec.test.helpers.voluntary_exits import prepare_signed_exits @with_capella_and_later @spec_state_test -def test_success_bls_change(spec, state): +def test_bls_change(spec, state): index = 0 signed_address_change = get_signed_address_change(spec, state, validator_index=index) pre_credentials = state.validators[index].withdrawal_credentials @@ -60,7 +60,46 @@ def test_success_bls_change(spec, state): @with_capella_and_later @spec_state_test -def test_success_exit_and_bls_change(spec, state): +def test_deposit_and_bls_change(spec, state): + initial_registry_len = len(state.validators) + initial_balances_len = len(state.balances) + + validator_index = len(state.validators) + amount = spec.MAX_EFFECTIVE_BALANCE + deposit = prepare_state_and_deposit(spec, state, validator_index, amount, signed=True) + + signed_address_change = get_signed_address_change( + spec, state, + validator_index=validator_index, + withdrawal_pubkey=deposit.data.pubkey, # Deposit helper defaults to use pubkey as withdrawal credential + ) + + deposit_credentials = deposit.data.withdrawal_credentials + assert deposit_credentials[:1] == spec.BLS_WITHDRAWAL_PREFIX + + yield 'pre', state + + block = build_empty_block_for_next_slot(spec, state) + block.body.deposits.append(deposit) + block.body.bls_to_execution_changes.append(signed_address_change) + + signed_block = state_transition_and_sign_block(spec, state, block) + + yield 'blocks', [signed_block] + yield 'post', state + + assert len(state.validators) == initial_registry_len + 1 + assert len(state.balances) == initial_balances_len + 1 + validator_credentials = state.validators[validator_index].withdrawal_credentials + assert deposit_credentials != validator_credentials + assert validator_credentials[:1] == spec.ETH1_ADDRESS_WITHDRAWAL_PREFIX + assert validator_credentials[1:12] == b'\x00' * 11 + assert validator_credentials[12:] == signed_address_change.message.to_execution_address + + +@with_capella_and_later +@spec_state_test +def test_exit_and_bls_change(spec, state): # move state forward SHARD_COMMITTEE_PERIOD epochs to allow for exit state.slot += spec.config.SHARD_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH From 95401cf6e46aa9ba47d78e9a50ccc2ca87e4e1ec Mon Sep 17 00:00:00 2001 From: Age Manning Date: Thu, 26 Jan 2023 19:30:49 +1100 Subject: [PATCH 157/158] Clarify context bytes in the RPC methods in 4844 --- specs/deneb/p2p-interface.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/specs/deneb/p2p-interface.md b/specs/deneb/p2p-interface.md index 040d594dd..ea29eb7f4 100644 --- a/specs/deneb/p2p-interface.md +++ b/specs/deneb/p2p-interface.md @@ -171,6 +171,14 @@ No more than `MAX_REQUEST_BLOCKS_DENEB` may be requested at a time. New in deneb. +The `` field is calculated as `context = compute_fork_digest(fork_version, genesis_validators_root)`: + +[1]: # (eth2spec: skip) + +| `fork_version` | Chunk SSZ type | +|--------------------------|-------------------------------| +| `DENEB_FORK_VERSION` | `deneb.BlobSidecar` | + Request Content: ``` @@ -212,6 +220,14 @@ Clients MAY limit the number of blocks and sidecars in the response. New in deneb. +The `` field is calculated as `context = compute_fork_digest(fork_version, genesis_validators_root)`: + +[1]: # (eth2spec: skip) + +| `fork_version` | Chunk SSZ type | +|--------------------------|-------------------------------| +| `DENEB_FORK_VERSION` | `deneb.BlobSidecar` | + Request Content: ``` ( From 7ff627e03290e2706d811c3915256f45351f3151 Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Tue, 21 Feb 2023 01:14:46 +0800 Subject: [PATCH 158/158] bump VERSION.txt to 1.3.0-rc.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 1d074f43e..99aab26b2 100644 --- a/tests/core/pyspec/eth2spec/VERSION.txt +++ b/tests/core/pyspec/eth2spec/VERSION.txt @@ -1 +1 @@ -1.3.0-rc.2 +1.3.0-rc.3