diff --git a/.github/workflows/run-tests.yml b/.github/workflows/run-tests.yml index 0e9126e392..a56270030f 100644 --- a/.github/workflows/run-tests.yml +++ b/.github/workflows/run-tests.yml @@ -24,41 +24,42 @@ on: - cron: '0 0 * * *' jobs: - preclear: - runs-on: self-hosted - if: always() - steps: - - name: 'Cleanup build folder' - run: | - ls -la ./ - rm -rf ./* || true - rm -rf ./.??* || true - ls -la ./ - table_of_contents: - runs-on: self-hosted - needs: preclear + runs-on: [self-hosted-ghr-custom, size-s-x64, profile-consensusSpecs] steps: - - name: Checkout this repo - uses: actions/checkout@v3.2.0 + - name: Checkout repository + uses: actions/checkout@v4 + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: '20' + cache: '' - name: Check table of contents - run: sudo npm install -g doctoc@2.2.0 && make check_toc + run: npm install -g doctoc@2.2.0 && make check_toc codespell: - runs-on: self-hosted - needs: preclear + runs-on: [self-hosted-ghr-custom, size-s-x64, profile-consensusSpecs] steps: - - name: Checkout this repo - uses: actions/checkout@v3.2.0 + - name: Checkout repository + uses: actions/checkout@v4 + - name: Setup Python + uses: actions/setup-python@v5 + with: + python-version: '3.10' + cache: '' - name: Check codespell - run: pip install 'codespell<3.0.0,>=2.0.0' --user && make codespell + run: make codespell lint: - runs-on: self-hosted - needs: preclear + runs-on: [self-hosted-ghr-custom, size-l-x64, profile-consensusSpecs] steps: - - name: Checkout this repo - uses: actions/checkout@v3.2.0 + - name: Checkout repository + uses: actions/checkout@v4 + - name: Setup Python + uses: actions/setup-python@v5 + with: + python-version: '3.10' + cache: '' - name: Install pyspec requirements run: make install_test - name: Run linter for pyspec @@ -67,14 +68,19 @@ jobs: run: make lint_generators pyspec-tests: - runs-on: self-hosted - needs: [preclear,lint,codespell,table_of_contents] + runs-on: [self-hosted-ghr-custom, size-xl-x64, profile-consensusSpecs] + needs: [lint,codespell,table_of_contents] strategy: matrix: version: ["phase0", "altair", "bellatrix", "capella", "deneb", "electra", "whisk", "eip7594"] steps: - - name: Checkout this repo - uses: actions/checkout@v3.2.0 + - name: Checkout repository + uses: actions/checkout@v4 + - name: Setup Python + uses: actions/setup-python@v5 + with: + python-version: '3.10' + cache: '' - name: set TEST_PRESET_TYPE if: github.event.inputs.test_preset_type != '' run: | @@ -95,20 +101,8 @@ jobs: 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 + - uses: actions/upload-artifact@v4 if: always() with: - name: test-${{ matrix.version }} + name: test-reports-${{ matrix.version }} path: tests/core/pyspec/test-reports - - cleanup: - runs-on: self-hosted - needs: [preclear,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 ./ diff --git a/Makefile b/Makefile index 1025a2a1ea..8fbedf2518 100644 --- a/Makefile +++ b/Makefile @@ -107,13 +107,13 @@ pyspec: # check the setup tool requirements preinstallation: - python3 -m venv venv; . venv/bin/activate; \ + python3 -m venv venv && \ + . venv/bin/activate && \ python3 -m pip install -r requirements_preinstallation.txt -# installs the packages to run pyspec tests install_test: preinstallation - python3 -m venv venv; . venv/bin/activate; \ - python3 -m pip install -e .[lint]; python3 -m pip install -e .[test] + . venv/bin/activate && \ + python3 -m pip install -e .[lint,test] # Testing against `minimal` or `mainnet` config by default test: pyspec diff --git a/specs/_features/eip7594/das-core.md b/specs/_features/eip7594/das-core.md index efd5d6c212..dc50365b1e 100644 --- a/specs/_features/eip7594/das-core.md +++ b/specs/_features/eip7594/das-core.md @@ -105,19 +105,20 @@ class DataColumnSidecar(Container): def get_custody_columns(node_id: NodeID, custody_subnet_count: uint64) -> Sequence[ColumnIndex]: assert custody_subnet_count <= DATA_COLUMN_SIDECAR_SUBNET_COUNT - subnet_ids = [] - i = 0 + subnet_ids: List[uint64] = [] + current_id = uint256(node_id) while len(subnet_ids) < custody_subnet_count: - if node_id == UINT256_MAX: - node_id = 0 - subnet_id = ( - bytes_to_uint64(hash(uint_to_bytes(uint256(node_id + i)))[0:8]) + bytes_to_uint64(hash(uint_to_bytes(uint256(current_id)))[0:8]) % DATA_COLUMN_SIDECAR_SUBNET_COUNT ) if subnet_id not in subnet_ids: subnet_ids.append(subnet_id) - i += 1 + if current_id == UINT256_MAX: + # Overflow prevention + current_id = NodeID(0) + current_id += 1 + assert len(subnet_ids) == len(set(subnet_ids)) columns_per_subnet = NUMBER_OF_COLUMNS // DATA_COLUMN_SIDECAR_SUBNET_COUNT @@ -154,10 +155,10 @@ def recover_matrix(cells_dict: Dict[Tuple[BlobIndex, CellID], Cell], blob_count: This helper demonstrates how to apply ``recover_all_cells``. The data structure for storing cells is implementation-dependent. """ - extended_matrix = [] + extended_matrix: List[Cell] = [] for blob_index in range(blob_count): cell_ids = [cell_id for b_index, cell_id in cells_dict.keys() if b_index == blob_index] - cells = [cells_dict[(blob_index, cell_id)] for cell_id in cell_ids] + cells = [cells_dict[(BlobIndex(blob_index), cell_id)] for cell_id in cell_ids] all_cells_for_row = recover_all_cells(cell_ids, cells) extended_matrix.extend(all_cells_for_row) diff --git a/specs/_features/eip7594/p2p-interface.md b/specs/_features/eip7594/p2p-interface.md index 2434d875ec..ea372026d9 100644 --- a/specs/_features/eip7594/p2p-interface.md +++ b/specs/_features/eip7594/p2p-interface.md @@ -25,6 +25,7 @@ - [The Req/Resp domain](#the-reqresp-domain) - [Messages](#messages) - [DataColumnSidecarsByRoot v1](#datacolumnsidecarsbyroot-v1) + - [DataColumnSidecarsByRange v1](#datacolumnsidecarsbyrange-v1) - [The discovery domain: discv5](#the-discovery-domain-discv5) - [ENR structure](#enr-structure) - [`custody_subnet_count`](#custody_subnet_count) @@ -71,15 +72,17 @@ def verify_data_column_sidecar_kzg_proofs(sidecar: DataColumnSidecar) -> bool: """ assert sidecar.index < NUMBER_OF_COLUMNS assert len(sidecar.column) == len(sidecar.kzg_commitments) == len(sidecar.kzg_proofs) - row_ids = [RowIndex(i) for i in range(len(sidecar.column))] + + row_indices = [RowIndex(i) for i in range(len(sidecar.column))] + column_indices = [sidecar.index] * len(sidecar.column) # KZG batch verifies that the cells match the corresponding commitments and proofs return verify_cell_kzg_proof_batch( - row_commitments=sidecar.kzg_commitments, - row_indices=row_ids, # all rows - column_indices=[sidecar.index], + row_commitments_bytes=sidecar.kzg_commitments, + row_indices=row_indices, # all rows + column_indices=column_indices, # specific column cells=sidecar.column, - proofs=sidecar.kzg_proofs, + proofs_bytes=sidecar.kzg_proofs, ) ``` @@ -198,6 +201,85 @@ Clients SHOULD include a sidecar in the response as soon as it passes the gossip Clients SHOULD NOT respond with sidecars related to blocks that fail gossip validation rules. Clients SHOULD NOT respond with sidecars related to blocks that fail the beacon chain state transition +##### DataColumnSidecarsByRange v1 + +**Protocol ID:** `/eth2/beacon_chain/req/data_column_sidecars_by_range/1/` + +The `` field is calculated as `context = compute_fork_digest(fork_version, genesis_validators_root)`: + +[1]: # (eth2spec: skip) + +| `fork_version` | Chunk SSZ type | +|--------------------------|-------------------------------| +| `EIP7594_FORK_VERSION` | `eip7594.DataColumnSidecar` | + +Request Content: +``` +( + start_slot: Slot + count: uint64 + columns: List[ColumnIndex] +) +``` + +Response Content: +``` +( + List[DataColumnSidecar, MAX_REQUEST_DATA_COLUMN_SIDECARS] +) +``` + +Requests data column sidecars in the slot range `[start_slot, start_slot + count)` of the given `columns`, leading up to the current head block as selected by fork choice. + +Before consuming the next response chunk, the response reader SHOULD verify the data column sidecar is well-formatted, has valid inclusion proof, and is correct w.r.t. the expected KZG commitments through `verify_data_column_sidecar_kzg_proofs`. + +`DataColumnSidecarsByRange` is primarily used to sync data columns that may have been missed on gossip and to sync within the `MIN_EPOCHS_FOR_DATA_COLUMN_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 `DataColumnSidecar` payload. + +Let `data_column_serve_range` be `[max(current_epoch - MIN_EPOCHS_FOR_DATA_COLUMN_SIDECARS_REQUESTS, EIP7594_FORK_EPOCH), current_epoch]`. +Clients MUST keep a record of data column sidecars seen on the epoch range `data_column_serve_range` +where `current_epoch` is defined by the current wall-clock time, +and clients MUST support serving requests of data columns on this range. + +Peers that are unable to reply to data column sidecar requests within the +range `data_column_serve_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 data columns database to at least the range `data_column_serve_range` +to be fully compliant with `DataColumnSidecarsByRange` requests. + +*Note*: Although clients that bootstrap from a weak subjectivity checkpoint can begin +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 data column sidecars of the first blob-carrying block that exists in the range, if they have it, and no more than `MAX_REQUEST_DATA_COLUMN_SIDECARS` sidecars. + +Clients MUST include all data column sidecars of each block from which they include data column sidecars. + +The following data column sidecars, where they exist, MUST be sent in `(slot, column_index)` order. + +Slots that do not contain known data columns MUST be skipped, mimicking the behaviour +of the `BlocksByRange` request. Only response chunks with known data columns should +therefore be sent. + +Clients MAY limit the number of data column sidecars in the response. + +The response MUST contain no more than `count * NUMBER_OF_COLUMNS` data column sidecars. + +Clients MUST respond with data columns sidecars from their view of the current fork choice +-- that is, data column 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 data column sidecars that are consistent from a single chain within the context of the request. + +After the initial data column 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. + ### The discovery domain: discv5 #### ENR structure diff --git a/specs/_features/eip7594/polynomial-commitments-sampling.md b/specs/_features/eip7594/polynomial-commitments-sampling.md index 6d30d6ed6c..08a414c418 100644 --- a/specs/_features/eip7594/polynomial-commitments-sampling.md +++ b/specs/_features/eip7594/polynomial-commitments-sampling.md @@ -243,7 +243,7 @@ def divide_polynomialcoeff(a: PolynomialCoeff, b: PolynomialCoeff) -> Polynomial Long polynomial division for two coefficient form polynomials ``a`` and ``b`` """ a = a.copy() # Make a copy since `a` is passed by reference - o = [] + o: List[BLSFieldElement] = [] apos = len(a) - 1 bpos = len(b) - 1 diff = apos - bpos @@ -441,7 +441,7 @@ def compute_cells_and_kzg_proofs(blob: Blob) -> Tuple[ proofs = [] for i in range(CELLS_PER_EXT_BLOB): - coset = coset_for_cell(i) + coset = coset_for_cell(CellID(i)) proof, ys = compute_kzg_proof_multi_impl(polynomial_coeff, coset) cells.append(coset_evals_to_cell(ys)) proofs.append(proof) @@ -470,7 +470,7 @@ def compute_cells(blob: Blob) -> Vector[Cell, CELLS_PER_EXT_BLOB]: for cell_id in range(CELLS_PER_EXT_BLOB): start = cell_id * FIELD_ELEMENTS_PER_CELL end = (cell_id + 1) * FIELD_ELEMENTS_PER_CELL - cells.append(coset_evals_to_cell(extended_data_rbo[start:end])) + cells.append(coset_evals_to_cell(CosetEvals(extended_data_rbo[start:end]))) return cells ``` @@ -572,7 +572,7 @@ def construct_vanishing_polynomial(missing_cell_ids: Sequence[CellID]) -> Tuple[ ]) # Extend vanishing polynomial to full domain using the closed form of the vanishing polynomial over a coset - zero_poly_coeff = [0] * FIELD_ELEMENTS_PER_EXT_BLOB + zero_poly_coeff = [BLSFieldElement(0)] * FIELD_ELEMENTS_PER_EXT_BLOB for i, coeff in enumerate(short_zero_poly): zero_poly_coeff[i * FIELD_ELEMENTS_PER_CELL] = coeff @@ -690,7 +690,7 @@ def recover_all_cells(cell_ids: Sequence[CellID], cells: Sequence[Cell]) -> Sequ # Convert cells to coset evals cosets_evals = [cell_to_coset_evals(cell) for cell in cells] - missing_cell_ids = [cell_id for cell_id in range(CELLS_PER_EXT_BLOB) if cell_id not in cell_ids] + missing_cell_ids = [CellID(cell_id) for cell_id in range(CELLS_PER_EXT_BLOB) if cell_id not in cell_ids] zero_poly_coeff, zero_poly_eval = construct_vanishing_polynomial(missing_cell_ids) eval_shifted_extended_evaluation, eval_shifted_zero_poly, shift_inv = recover_shifted_data( diff --git a/specs/electra/beacon-chain.md b/specs/electra/beacon-chain.md index 262401f0e6..62da891146 100644 --- a/specs/electra/beacon-chain.md +++ b/specs/electra/beacon-chain.md @@ -514,8 +514,8 @@ def is_partially_withdrawable_validator(validator: Validator, balance: Gwei) -> #### `get_committee_indices` ```python -def get_committee_indices(commitee_bits: Bitvector) -> Sequence[CommitteeIndex]: - return [CommitteeIndex(index) for index, bit in enumerate(commitee_bits) if bit] +def get_committee_indices(committee_bits: Bitvector) -> Sequence[CommitteeIndex]: + return [CommitteeIndex(index) for index, bit in enumerate(committee_bits) if bit] ``` #### `get_validator_max_effective_balance` diff --git a/specs/phase0/p2p-interface.md b/specs/phase0/p2p-interface.md index ff1bd03a1d..bc29b9ad92 100644 --- a/specs/phase0/p2p-interface.md +++ b/specs/phase0/p2p-interface.md @@ -356,7 +356,7 @@ to subscribing nodes (typically validators) to be included in future blocks. We define the following variables for convenience: - `aggregate_and_proof = signed_aggregate_and_proof.message` - `aggregate = aggregate_and_proof.aggregate` -- `index = aggregate.index` +- `index = aggregate.data.index` - `aggregation_bits = attestation.aggregation_bits` The following validations MUST pass before forwarding the `signed_aggregate_and_proof` on the network. @@ -436,7 +436,7 @@ The `beacon_attestation_{subnet_id}` topics are used to propagate unaggregated a to the subnet `subnet_id` (typically beacon and persistent committees) to be aggregated before being gossiped to `beacon_aggregate_and_proof`. We define the following variables for convenience: -- `index = attestation.index` +- `index = attestation.data.index` - `aggregation_bits = attestation.aggregation_bits` The following validations MUST pass before forwarding the `attestation` on the subnet. diff --git a/tests/core/pyspec/eth2spec/VERSION.txt b/tests/core/pyspec/eth2spec/VERSION.txt index dc1605fa64..ead8dd9dd9 100644 --- a/tests/core/pyspec/eth2spec/VERSION.txt +++ b/tests/core/pyspec/eth2spec/VERSION.txt @@ -1 +1 @@ -1.5.0-alpha.1 +1.5.0-alpha.2 diff --git a/tests/core/pyspec/eth2spec/test/bellatrix/block_processing/test_process_execution_payload.py b/tests/core/pyspec/eth2spec/test/bellatrix/block_processing/test_process_execution_payload.py index 8eb6b4eab3..a55a6e12a4 100644 --- a/tests/core/pyspec/eth2spec/test/bellatrix/block_processing/test_process_execution_payload.py +++ b/tests/core/pyspec/eth2spec/test/bellatrix/block_processing/test_process_execution_payload.py @@ -324,7 +324,7 @@ def test_zero_length_transaction_regular_payload(spec, state): yield from run_zero_length_transaction_test(spec, state) -def run_randomized_non_validated_execution_fields_test(spec, state, execution_valid=True, rng=Random(5555)): +def run_randomized_non_validated_execution_fields_test(spec, state, rng, execution_valid=True): next_slot(spec, state) execution_payload = build_randomized_execution_payload(spec, state, rng) @@ -340,7 +340,7 @@ def run_randomized_non_validated_execution_fields_test(spec, state, execution_va def test_randomized_non_validated_execution_fields_first_payload__execution_valid(spec, state): rng = Random(1111) state = build_state_with_incomplete_transition(spec, state) - yield from run_randomized_non_validated_execution_fields_test(spec, state, rng=rng) + yield from run_randomized_non_validated_execution_fields_test(spec, state, rng) @with_bellatrix_and_later @@ -348,7 +348,7 @@ def test_randomized_non_validated_execution_fields_first_payload__execution_vali def test_randomized_non_validated_execution_fields_regular_payload__execution_valid(spec, state): rng = Random(2222) state = build_state_with_complete_transition(spec, state) - yield from run_randomized_non_validated_execution_fields_test(spec, state, rng=rng) + yield from run_randomized_non_validated_execution_fields_test(spec, state, rng) @with_bellatrix_and_later @@ -356,7 +356,7 @@ def test_randomized_non_validated_execution_fields_regular_payload__execution_va def test_invalid_randomized_non_validated_execution_fields_first_payload__execution_invalid(spec, state): rng = Random(3333) state = build_state_with_incomplete_transition(spec, state) - yield from run_randomized_non_validated_execution_fields_test(spec, state, execution_valid=False, rng=rng) + yield from run_randomized_non_validated_execution_fields_test(spec, state, rng, execution_valid=False) @with_bellatrix_and_later @@ -364,4 +364,4 @@ def test_invalid_randomized_non_validated_execution_fields_first_payload__execut def test_invalid_randomized_non_validated_execution_fields_regular_payload__execution_invalid(spec, state): rng = Random(4444) state = build_state_with_complete_transition(spec, state) - yield from run_randomized_non_validated_execution_fields_test(spec, state, execution_valid=False, rng=rng) + yield from run_randomized_non_validated_execution_fields_test(spec, state, rng, execution_valid=False) 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 756528be9f..1fe05c18df 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 @@ -113,7 +113,7 @@ def test_success_zero_expected_withdrawals(spec, state): @spec_state_test def test_success_one_full_withdrawal(spec, state): fully_withdrawable_indices, partial_withdrawals_indices = prepare_expected_withdrawals( - spec, state, num_full_withdrawals=1) + spec, state, rng=random.Random(42), num_full_withdrawals=1) assert len(fully_withdrawable_indices) == 1 assert len(partial_withdrawals_indices) == 0 @@ -130,7 +130,7 @@ def test_success_one_full_withdrawal(spec, state): @spec_state_test def test_success_one_partial_withdrawal(spec, state): fully_withdrawable_indices, partial_withdrawals_indices = prepare_expected_withdrawals( - spec, state, num_partial_withdrawals=1) + spec, state, rng=random.Random(42), num_partial_withdrawals=1) assert len(fully_withdrawable_indices) == 0 assert len(partial_withdrawals_indices) == 1 for index in partial_withdrawals_indices: @@ -153,6 +153,7 @@ def test_success_mixed_fully_and_partial_withdrawable(spec, state): num_partial_withdrawals = spec.MAX_WITHDRAWALS_PER_PAYLOAD - num_full_withdrawals fully_withdrawable_indices, partial_withdrawals_indices = prepare_expected_withdrawals( spec, state, + rng=random.Random(42), num_full_withdrawals=num_full_withdrawals, num_partial_withdrawals=num_partial_withdrawals, ) @@ -174,7 +175,7 @@ def test_success_all_fully_withdrawable_in_one_sweep(spec, state): withdrawal_count = len(state.validators) fully_withdrawable_indices, partial_withdrawals_indices = prepare_expected_withdrawals( - spec, state, num_full_withdrawals=withdrawal_count) + spec, state, rng=random.Random(42), num_full_withdrawals=withdrawal_count) next_slot(spec, state) execution_payload = build_empty_execution_payload(spec, state) @@ -193,7 +194,7 @@ def test_success_all_fully_withdrawable(spec, state): withdrawal_count = spec.MAX_VALIDATORS_PER_WITHDRAWALS_SWEEP fully_withdrawable_indices, partial_withdrawals_indices = prepare_expected_withdrawals( - spec, state, num_full_withdrawals=withdrawal_count) + spec, state, rng=random.Random(42), num_full_withdrawals=withdrawal_count) next_slot(spec, state) execution_payload = build_empty_execution_payload(spec, state) @@ -212,7 +213,7 @@ def test_success_all_partially_withdrawable_in_one_sweep(spec, state): withdrawal_count = len(state.validators) fully_withdrawable_indices, partial_withdrawals_indices = prepare_expected_withdrawals( - spec, state, num_partial_withdrawals=withdrawal_count) + spec, state, rng=random.Random(42), num_partial_withdrawals=withdrawal_count) next_slot(spec, state) execution_payload = build_empty_execution_payload(spec, state) @@ -231,7 +232,7 @@ def test_success_all_partially_withdrawable(spec, state): withdrawal_count = spec.MAX_VALIDATORS_PER_WITHDRAWALS_SWEEP fully_withdrawable_indices, partial_withdrawals_indices = prepare_expected_withdrawals( - spec, state, num_partial_withdrawals=withdrawal_count) + spec, state, rng=random.Random(42), num_partial_withdrawals=withdrawal_count) next_slot(spec, state) execution_payload = build_empty_execution_payload(spec, state) @@ -266,7 +267,7 @@ def test_invalid_non_withdrawable_non_empty_withdrawals(spec, state): @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) + prepare_expected_withdrawals(spec, state, rng=random.Random(42), num_full_withdrawals=1) next_slot(spec, state) execution_payload = build_empty_execution_payload(spec, state) @@ -279,7 +280,7 @@ def test_invalid_one_expected_full_withdrawal_and_none_in_withdrawals(spec, stat @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) + prepare_expected_withdrawals(spec, state, rng=random.Random(42), num_partial_withdrawals=1) next_slot(spec, state) execution_payload = build_empty_execution_payload(spec, state) @@ -292,7 +293,7 @@ def test_invalid_one_expected_partial_withdrawal_and_none_in_withdrawals(spec, s @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) + prepare_expected_withdrawals(spec, state, rng=random.Random(42), num_full_withdrawals=2) next_slot(spec, state) execution_payload = build_empty_execution_payload(spec, state) @@ -305,7 +306,7 @@ def test_invalid_one_expected_full_withdrawal_and_duplicate_in_withdrawals(spec, @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) + prepare_expected_withdrawals(spec, state, rng=random.Random(42), num_partial_withdrawals=2) next_slot(spec, state) execution_payload = build_empty_execution_payload(spec, state) @@ -318,7 +319,8 @@ def test_invalid_two_expected_partial_withdrawal_and_duplicate_in_withdrawals(sp @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) + prepare_expected_withdrawals(spec, state, rng=random.Random(42), + num_full_withdrawals=spec.MAX_WITHDRAWALS_PER_PAYLOAD) next_slot(spec, state) execution_payload = build_empty_execution_payload(spec, state) @@ -331,7 +333,8 @@ def test_invalid_max_per_slot_full_withdrawals_and_one_less_in_withdrawals(spec, @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) + prepare_expected_withdrawals(spec, state, rng=random.Random(42), + num_partial_withdrawals=spec.MAX_WITHDRAWALS_PER_PAYLOAD) next_slot(spec, state) execution_payload = build_empty_execution_payload(spec, state) @@ -344,7 +347,8 @@ def test_invalid_max_per_slot_partial_withdrawals_and_one_less_in_withdrawals(sp @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) + prepare_expected_withdrawals(spec, state, rng=random.Random(42), + num_full_withdrawals=spec.MAX_WITHDRAWALS_PER_PAYLOAD * 4) next_slot(spec, state) execution_payload = build_empty_execution_payload(spec, state) @@ -357,7 +361,8 @@ def test_invalid_a_lot_fully_withdrawable_too_few_in_withdrawals(spec, state): @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) + prepare_expected_withdrawals(spec, state, rng=random.Random(42), + num_partial_withdrawals=spec.MAX_WITHDRAWALS_PER_PAYLOAD * 4) next_slot(spec, state) execution_payload = build_empty_execution_payload(spec, state) @@ -370,7 +375,8 @@ def test_invalid_a_lot_partially_withdrawable_too_few_in_withdrawals(spec, state @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, + prepare_expected_withdrawals(spec, state, rng=random.Random(42), + num_full_withdrawals=spec.MAX_WITHDRAWALS_PER_PAYLOAD, num_partial_withdrawals=spec.MAX_WITHDRAWALS_PER_PAYLOAD) next_slot(spec, state) @@ -388,7 +394,8 @@ def test_invalid_a_lot_mixed_withdrawable_in_queue_too_few_in_withdrawals(spec, @with_capella_and_later @spec_state_test def test_invalid_incorrect_withdrawal_index(spec, state): - prepare_expected_withdrawals(spec, state, num_full_withdrawals=1) + prepare_expected_withdrawals(spec, state, rng=random.Random(42), + num_full_withdrawals=1) next_slot(spec, state) execution_payload = build_empty_execution_payload(spec, state) @@ -401,7 +408,8 @@ def test_invalid_incorrect_withdrawal_index(spec, state): @with_capella_and_later @spec_state_test def test_invalid_incorrect_address_full(spec, state): - prepare_expected_withdrawals(spec, state, num_full_withdrawals=1) + prepare_expected_withdrawals(spec, state, rng=random.Random(42), + num_full_withdrawals=1) next_slot(spec, state) execution_payload = build_empty_execution_payload(spec, state) @@ -414,7 +422,8 @@ def test_invalid_incorrect_address_full(spec, state): @with_capella_and_later @spec_state_test def test_invalid_incorrect_address_partial(spec, state): - prepare_expected_withdrawals(spec, state, num_partial_withdrawals=1) + prepare_expected_withdrawals(spec, state, rng=random.Random(42), + num_partial_withdrawals=1) next_slot(spec, state) execution_payload = build_empty_execution_payload(spec, state) @@ -427,7 +436,7 @@ def test_invalid_incorrect_address_partial(spec, state): @with_capella_and_later @spec_state_test def test_invalid_incorrect_amount_full(spec, state): - prepare_expected_withdrawals(spec, state, num_full_withdrawals=1) + prepare_expected_withdrawals(spec, state, rng=random.Random(42), num_full_withdrawals=1) next_slot(spec, state) execution_payload = build_empty_execution_payload(spec, state) @@ -440,7 +449,7 @@ def test_invalid_incorrect_amount_full(spec, state): @with_capella_and_later @spec_state_test def test_invalid_incorrect_amount_partial(spec, state): - prepare_expected_withdrawals(spec, state, num_full_withdrawals=1) + prepare_expected_withdrawals(spec, state, rng=random.Random(42), num_full_withdrawals=1) next_slot(spec, state) execution_payload = build_empty_execution_payload(spec, state) @@ -453,7 +462,8 @@ def test_invalid_incorrect_amount_partial(spec, state): @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) + prepare_expected_withdrawals(spec, state, rng=random.Random(42), + num_full_withdrawals=spec.MAX_WITHDRAWALS_PER_PAYLOAD * 4) next_slot(spec, state) execution_payload = build_empty_execution_payload(spec, state) @@ -472,7 +482,8 @@ def test_invalid_one_of_many_incorrectly_full(spec, state): @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) + prepare_expected_withdrawals(spec, state, rng=random.Random(42), + num_partial_withdrawals=spec.MAX_WITHDRAWALS_PER_PAYLOAD * 4) next_slot(spec, state) execution_payload = build_empty_execution_payload(spec, state) @@ -491,7 +502,8 @@ def test_invalid_one_of_many_incorrectly_partial(spec, state): @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) + prepare_expected_withdrawals(spec, state, rng=random.Random(42), + num_full_withdrawals=spec.MAX_WITHDRAWALS_PER_PAYLOAD * 4) next_slot(spec, state) execution_payload = build_empty_execution_payload(spec, state) @@ -510,7 +522,8 @@ def test_invalid_many_incorrectly_full(spec, state): @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) + prepare_expected_withdrawals(spec, state, rng=random.Random(42), + num_partial_withdrawals=spec.MAX_WITHDRAWALS_PER_PAYLOAD * 4) 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 874b13bd15..dabc2be18b 100644 --- a/tests/core/pyspec/eth2spec/test/capella/sanity/test_blocks.py +++ b/tests/core/pyspec/eth2spec/test/capella/sanity/test_blocks.py @@ -1,3 +1,4 @@ +import random from eth2spec.test.helpers.constants import MINIMAL from eth2spec.test.helpers.forks import is_post_electra from eth2spec.test.context import ( @@ -268,7 +269,8 @@ def test_many_partial_withdrawals_in_epoch_transition(spec, state): def _perform_valid_withdrawal(spec, state): fully_withdrawable_indices, partial_withdrawals_indices = prepare_expected_withdrawals( - spec, state, num_partial_withdrawals=spec.MAX_WITHDRAWALS_PER_PAYLOAD * 2, + spec, state, rng=random.Random(42), + num_partial_withdrawals=spec.MAX_WITHDRAWALS_PER_PAYLOAD * 2, num_full_withdrawals=spec.MAX_WITHDRAWALS_PER_PAYLOAD * 2) next_slot(spec, state) diff --git a/tests/core/pyspec/eth2spec/test/eip7594/merkle_proof/test_single_merkle_proof.py b/tests/core/pyspec/eth2spec/test/eip7594/merkle_proof/test_single_merkle_proof.py index e2970a25e4..8e67b3d0bf 100644 --- a/tests/core/pyspec/eth2spec/test/eip7594/merkle_proof/test_single_merkle_proof.py +++ b/tests/core/pyspec/eth2spec/test/eip7594/merkle_proof/test_single_merkle_proof.py @@ -56,6 +56,7 @@ def _run_blob_kzg_commitments_merkle_proof_test(spec, state, rng=None): index=spec.get_subtree_index(gindex), root=column_sidcar.signed_block_header.message.body_root, ) + assert spec.verify_data_column_sidecar_kzg_proofs(column_sidcar) assert spec.verify_data_column_sidecar_inclusion_proof(column_sidcar) diff --git a/tests/core/pyspec/eth2spec/test/eip7594/networking/test_get_custody_columns.py b/tests/core/pyspec/eth2spec/test/eip7594/networking/test_get_custody_columns.py index cadaa90d9b..b41f19a6ca 100644 --- a/tests/core/pyspec/eth2spec/test/eip7594/networking/test_get_custody_columns.py +++ b/tests/core/pyspec/eth2spec/test/eip7594/networking/test_get_custody_columns.py @@ -65,6 +65,25 @@ def test_get_custody_columns__max_node_id_max_custody_subnet_count(spec): ) +@with_eip7594_and_later +@spec_test +@single_phase +def test_get_custody_columns__max_node_id_max_custody_subnet_count_minus_1(spec): + rng = random.Random(1111) + yield from _run_get_custody_columns( + spec, rng, node_id=2**256 - 2, + custody_subnet_count=spec.config.DATA_COLUMN_SIDECAR_SUBNET_COUNT, + ) + + +@with_eip7594_and_later +@spec_test +@single_phase +def test_get_custody_columns__short_node_id(spec): + rng = random.Random(1111) + yield from _run_get_custody_columns(spec, rng, node_id=1048576, custody_subnet_count=1) + + @with_eip7594_and_later @spec_test @single_phase diff --git a/tests/core/pyspec/eth2spec/test/electra/block_processing/test_process_consolidation.py b/tests/core/pyspec/eth2spec/test/electra/block_processing/test_process_consolidation.py index 95bd812e38..a1267cb716 100644 --- a/tests/core/pyspec/eth2spec/test/electra/block_processing/test_process_consolidation.py +++ b/tests/core/pyspec/eth2spec/test/electra/block_processing/test_process_consolidation.py @@ -1,6 +1,5 @@ from eth2spec.test.helpers.constants import MINIMAL from eth2spec.test.context import ( - spec_state_test, with_electra_and_later, with_presets, always_bls, @@ -407,7 +406,13 @@ def test_consolidation_balance_through_two_churn_epochs(spec, state): # Failing tests @with_electra_and_later -@spec_state_test +@with_presets([MINIMAL], "need sufficient consolidation churn limit") +@with_custom_state( + balances_fn=scaled_churn_balances_exceed_activation_exit_churn_limit, + threshold_fn=default_activation_threshold, +) +@spec_test +@single_phase def test_invalid_source_equals_target(spec, state): current_epoch = spec.get_current_epoch(state) validator_index = spec.get_active_validator_indices(state, current_epoch)[0] @@ -433,7 +438,13 @@ def test_invalid_source_equals_target(spec, state): @with_electra_and_later -@spec_state_test +@with_presets([MINIMAL], "need sufficient consolidation churn limit") +@with_custom_state( + balances_fn=scaled_churn_balances_exceed_activation_exit_churn_limit, + threshold_fn=default_activation_threshold, +) +@spec_test +@single_phase def test_invalid_exceed_pending_consolidations_limit(spec, state): state.pending_consolidations = [ spec.PendingConsolidation(source_index=0, target_index=1) @@ -457,7 +468,13 @@ def test_invalid_exceed_pending_consolidations_limit(spec, state): @with_electra_and_later -@spec_state_test +@with_presets([MINIMAL], "need sufficient consolidation churn limit") +@with_custom_state( + balances_fn=scaled_churn_balances_exceed_activation_exit_churn_limit, + threshold_fn=default_activation_threshold, +) +@spec_test +@single_phase def test_invalid_not_enough_consolidation_churn_available(spec, state): state.validators = state.validators[0:2] state.pending_consolidations = [ @@ -482,7 +499,13 @@ def test_invalid_not_enough_consolidation_churn_available(spec, state): @with_electra_and_later -@spec_state_test +@with_presets([MINIMAL], "need sufficient consolidation churn limit") +@with_custom_state( + balances_fn=scaled_churn_balances_exceed_activation_exit_churn_limit, + threshold_fn=default_activation_threshold, +) +@spec_test +@single_phase def test_invalid_exited_source(spec, state): current_epoch = spec.get_current_epoch(state) source_privkey = pubkey_to_privkey[state.validators[0].pubkey] @@ -504,7 +527,13 @@ def test_invalid_exited_source(spec, state): @with_electra_and_later -@spec_state_test +@with_presets([MINIMAL], "need sufficient consolidation churn limit") +@with_custom_state( + balances_fn=scaled_churn_balances_exceed_activation_exit_churn_limit, + threshold_fn=default_activation_threshold, +) +@spec_test +@single_phase def test_invalid_exited_target(spec, state): current_epoch = spec.get_current_epoch(state) source_privkey = pubkey_to_privkey[state.validators[0].pubkey] @@ -527,7 +556,13 @@ def test_invalid_exited_target(spec, state): @with_electra_and_later -@spec_state_test +@with_presets([MINIMAL], "need sufficient consolidation churn limit") +@with_custom_state( + balances_fn=scaled_churn_balances_exceed_activation_exit_churn_limit, + threshold_fn=default_activation_threshold, +) +@spec_test +@single_phase def test_invalid_inactive_source(spec, state): current_epoch = spec.get_current_epoch(state) source_privkey = pubkey_to_privkey[state.validators[0].pubkey] @@ -549,7 +584,13 @@ def test_invalid_inactive_source(spec, state): @with_electra_and_later -@spec_state_test +@with_presets([MINIMAL], "need sufficient consolidation churn limit") +@with_custom_state( + balances_fn=scaled_churn_balances_exceed_activation_exit_churn_limit, + threshold_fn=default_activation_threshold, +) +@spec_test +@single_phase def test_invalid_inactive_target(spec, state): current_epoch = spec.get_current_epoch(state) source_privkey = pubkey_to_privkey[state.validators[0].pubkey] @@ -572,7 +613,13 @@ def test_invalid_inactive_target(spec, state): @with_electra_and_later -@spec_state_test +@with_presets([MINIMAL], "need sufficient consolidation churn limit") +@with_custom_state( + balances_fn=scaled_churn_balances_exceed_activation_exit_churn_limit, + threshold_fn=default_activation_threshold, +) +@spec_test +@single_phase def test_invalid_no_execution_withdrawal_credential(spec, state): current_epoch = spec.get_current_epoch(state) source_privkey = pubkey_to_privkey[state.validators[0].pubkey] @@ -590,7 +637,13 @@ def test_invalid_no_execution_withdrawal_credential(spec, state): @with_electra_and_later -@spec_state_test +@with_presets([MINIMAL], "need sufficient consolidation churn limit") +@with_custom_state( + balances_fn=scaled_churn_balances_exceed_activation_exit_churn_limit, + threshold_fn=default_activation_threshold, +) +@spec_test +@single_phase def test_invalid_different_credentials(spec, state): current_epoch = spec.get_current_epoch(state) source_privkey = pubkey_to_privkey[state.validators[0].pubkey] @@ -731,7 +784,13 @@ def test_invalid_target_signature(spec, state): @with_electra_and_later -@spec_state_test +@with_presets([MINIMAL], "need sufficient consolidation churn limit") +@with_custom_state( + balances_fn=scaled_churn_balances_exceed_activation_exit_churn_limit, + threshold_fn=default_activation_threshold, +) +@spec_test +@single_phase def test_invalid_before_specified_epoch(spec, state): current_epoch = spec.get_current_epoch(state) source_privkey = pubkey_to_privkey[state.validators[0].pubkey] diff --git a/tests/core/pyspec/eth2spec/test/electra/block_processing/test_process_execution_layer_withdrawal_request.py b/tests/core/pyspec/eth2spec/test/electra/block_processing/test_process_execution_layer_withdrawal_request.py index 4e540b41f6..554fc53bda 100644 --- a/tests/core/pyspec/eth2spec/test/electra/block_processing/test_process_execution_layer_withdrawal_request.py +++ b/tests/core/pyspec/eth2spec/test/electra/block_processing/test_process_execution_layer_withdrawal_request.py @@ -774,7 +774,7 @@ def run_execution_layer_withdrawal_request_processing( pre_pending_partial_withdrawals = state.pending_partial_withdrawals.copy() pre_balance = state.balances[validator_index] pre_effective_balance = state.validators[validator_index].effective_balance - pre_state = state + pre_state = state.copy() expected_amount_to_withdraw = compute_amount_to_withdraw( spec, state, validator_index, execution_layer_withdrawal_request.amount ) diff --git a/tests/core/pyspec/eth2spec/test/electra/epoch_processing/test_process_pending_balance_deposits.py b/tests/core/pyspec/eth2spec/test/electra/epoch_processing/test_process_pending_balance_deposits.py index 42783d31e2..981851bc80 100644 --- a/tests/core/pyspec/eth2spec/test/electra/epoch_processing/test_process_pending_balance_deposits.py +++ b/tests/core/pyspec/eth2spec/test/electra/epoch_processing/test_process_pending_balance_deposits.py @@ -95,7 +95,7 @@ def test_multiple_pending_deposits_below_churn(spec, state): state.pending_balance_deposits.append( spec.PendingBalanceDeposit(index=1, amount=amount) ) - pre_balances = state.balances + pre_balances = state.balances.copy() yield from run_epoch_processing_with( spec, state, "process_pending_balance_deposits" ) @@ -115,7 +115,7 @@ def test_multiple_pending_deposits_above_churn(spec, state): state.pending_balance_deposits.append( spec.PendingBalanceDeposit(index=i, amount=amount) ) - pre_balances = state.balances + pre_balances = state.balances.copy() yield from run_epoch_processing_with( spec, state, "process_pending_balance_deposits" ) diff --git a/tests/core/pyspec/eth2spec/test/electra/sanity/blocks/__init__.py b/tests/core/pyspec/eth2spec/test/electra/sanity/blocks/__init__.py index 46e3659cd3..3c0e060f3d 100644 --- a/tests/core/pyspec/eth2spec/test/electra/sanity/blocks/__init__.py +++ b/tests/core/pyspec/eth2spec/test/electra/sanity/blocks/__init__.py @@ -1,2 +1 @@ -from .test_consolidation import * # noqa: F401 F403 from .test_deposit_transition import * # noqa: F401 F403 diff --git a/tests/core/pyspec/eth2spec/test/electra/sanity/blocks/test_consolidation.py b/tests/core/pyspec/eth2spec/test/electra/sanity/blocks/test_consolidation.py deleted file mode 100644 index 2d8613b528..0000000000 --- a/tests/core/pyspec/eth2spec/test/electra/sanity/blocks/test_consolidation.py +++ /dev/null @@ -1,271 +0,0 @@ - -from eth2spec.test.context import ( - with_electra_and_later, - with_presets, - spec_test, - single_phase, - with_custom_state, - scaled_churn_balances_exceed_activation_exit_churn_limit, - default_activation_threshold, -) -from eth2spec.test.helpers.block import ( - build_empty_block_for_next_slot -) -from eth2spec.test.helpers.consolidations import ( - sign_consolidation, -) -from eth2spec.test.helpers.constants import MINIMAL -from eth2spec.test.helpers.keys import pubkey_to_privkey -from eth2spec.test.helpers.state import ( - state_transition_and_sign_block, -) -from eth2spec.test.helpers.withdrawals import ( - set_eth1_withdrawal_credential_with_balance, -) - - -@with_electra_and_later -@with_presets([MINIMAL], "need sufficient consolidation churn limit") -@with_custom_state( - balances_fn=scaled_churn_balances_exceed_activation_exit_churn_limit, - threshold_fn=default_activation_threshold, -) -@spec_test -@single_phase -def test_multiple_consolidations_below_churn(spec, state): - # This state has 256 validators each with 32 ETH in MINIMAL preset, 128 ETH consolidation churn - consolidation_churn_limit = spec.get_consolidation_churn_limit(state) - # Set the consolidation balance to consume equal to churn limit - state.consolidation_balance_to_consume = consolidation_churn_limit - current_epoch = spec.get_current_epoch(state) - - yield "pre", state - - # Prepare a bunch of consolidations, each of them in a block, based on the current state - blocks = [] - consolidation_count = 3 - for i in range(consolidation_count): - source_index = 2 * i - target_index = 2 * i + 1 - source_privkey = pubkey_to_privkey[state.validators[source_index].pubkey] - target_privkey = pubkey_to_privkey[state.validators[target_index].pubkey] - # Set source and target withdrawal credentials to the same eth1 credential - set_eth1_withdrawal_credential_with_balance(spec, state, source_index) - set_eth1_withdrawal_credential_with_balance(spec, state, target_index) - signed_consolidation = sign_consolidation( - spec, - state, - spec.Consolidation( - epoch=current_epoch, - source_index=source_index, - target_index=target_index, - ), - source_privkey, - target_privkey, - ) - block = build_empty_block_for_next_slot(spec, state) - block.body.consolidations = [signed_consolidation] - signed_block = state_transition_and_sign_block(spec, state, block) - blocks.append(signed_block) - - yield "blocks", blocks - yield "post", state - - expected_exit_epoch = spec.compute_activation_exit_epoch(current_epoch) - assert state.earliest_consolidation_epoch == expected_exit_epoch - assert ( - state.consolidation_balance_to_consume - == consolidation_churn_limit - 3 * spec.MIN_ACTIVATION_BALANCE - ) - for i in range(consolidation_count): - assert state.validators[2 * i].exit_epoch == expected_exit_epoch - - -@with_electra_and_later -@with_presets([MINIMAL], "need sufficient consolidation churn limit") -@with_custom_state( - balances_fn=scaled_churn_balances_exceed_activation_exit_churn_limit, - threshold_fn=default_activation_threshold, -) -@spec_test -@single_phase -def test_multiple_consolidations_equal_churn(spec, state): - # This state has 256 validators each with 32 ETH in MINIMAL preset, 128 ETH consolidation churn - consolidation_churn_limit = spec.get_consolidation_churn_limit(state) - # Set the consolidation balance to consume equal to churn limit - state.consolidation_balance_to_consume = consolidation_churn_limit - current_epoch = spec.get_current_epoch(state) - - yield "pre", state - # Prepare a bunch of consolidations, each of them in a block, based on the current state - blocks = [] - consolidation_count = 4 - for i in range(consolidation_count): - source_index = 2 * i - target_index = 2 * i + 1 - source_privkey = pubkey_to_privkey[state.validators[source_index].pubkey] - target_privkey = pubkey_to_privkey[state.validators[target_index].pubkey] - # Set source and target withdrawal credentials to the same eth1 credential - set_eth1_withdrawal_credential_with_balance(spec, state, source_index) - set_eth1_withdrawal_credential_with_balance(spec, state, target_index) - signed_consolidation = sign_consolidation( - spec, - state, - spec.Consolidation( - epoch=current_epoch, - source_index=source_index, - target_index=target_index, - ), - source_privkey, - target_privkey, - ) - block = build_empty_block_for_next_slot(spec, state) - block.body.consolidations = [signed_consolidation] - signed_block = state_transition_and_sign_block(spec, state, block) - blocks.append(signed_block) - - yield "blocks", blocks - yield "post", state - - expected_exit_epoch = spec.compute_activation_exit_epoch(current_epoch) - assert state.earliest_consolidation_epoch == expected_exit_epoch - assert state.consolidation_balance_to_consume == 0 - for i in range(consolidation_count): - assert state.validators[2 * i].exit_epoch == expected_exit_epoch - - -@with_electra_and_later -@with_presets([MINIMAL], "need sufficient consolidation churn limit") -@with_custom_state( - balances_fn=scaled_churn_balances_exceed_activation_exit_churn_limit, - threshold_fn=default_activation_threshold, -) -@spec_test -@single_phase -def test_multiple_consolidations_above_churn(spec, state): - # This state has 256 validators each with 32 ETH in MINIMAL preset, 128 ETH consolidation churn - consolidation_churn_limit = spec.get_consolidation_churn_limit(state) - # Set the consolidation balance to consume equal to churn limit - state.consolidation_balance_to_consume = consolidation_churn_limit - current_epoch = spec.get_current_epoch(state) - - # Prepare a bunch of consolidations, each of them in a block, based on the current state - blocks = [] - consolidation_count = 4 - for i in range(consolidation_count): - source_index = 2 * i - target_index = 2 * i + 1 - source_privkey = pubkey_to_privkey[state.validators[source_index].pubkey] - target_privkey = pubkey_to_privkey[state.validators[target_index].pubkey] - # Set source and target withdrawal credentials to the same eth1 credential - set_eth1_withdrawal_credential_with_balance(spec, state, source_index) - set_eth1_withdrawal_credential_with_balance(spec, state, target_index) - signed_consolidation = sign_consolidation( - spec, - state, - spec.Consolidation( - epoch=current_epoch, - source_index=source_index, - target_index=target_index, - ), - source_privkey, - target_privkey, - ) - block = build_empty_block_for_next_slot(spec, state) - block.body.consolidations = [signed_consolidation] - signed_block = state_transition_and_sign_block(spec, state, block) - blocks.append(signed_block) - - # consolidate an additional validator - source_index = spec.get_active_validator_indices(state, current_epoch)[-2] - target_index = spec.get_active_validator_indices(state, current_epoch)[-1] - source_privkey = pubkey_to_privkey[state.validators[source_index].pubkey] - target_privkey = pubkey_to_privkey[state.validators[target_index].pubkey] - - # Set source and target withdrawal credentials to the same eth1 credential - set_eth1_withdrawal_credential_with_balance(spec, state, source_index) - set_eth1_withdrawal_credential_with_balance(spec, state, target_index) - - # This is the interesting part of the test: on a pre-state with full consolidation queue, - # when processing an additional consolidation, it results in an exit in a later epoch - signed_consolidation = sign_consolidation( - spec, - state, - spec.Consolidation( - epoch=current_epoch, source_index=source_index, target_index=target_index - ), - source_privkey, - target_privkey, - ) - block = build_empty_block_for_next_slot(spec, state) - block.body.consolidations = [signed_consolidation] - signed_block = state_transition_and_sign_block(spec, state, block) - blocks.append(signed_block) - - yield "blocks", blocks - yield "post", state - - expected_exit_epoch = spec.compute_activation_exit_epoch(current_epoch) - assert state.earliest_consolidation_epoch == expected_exit_epoch + 1 - assert ( - state.consolidation_balance_to_consume - == consolidation_churn_limit - spec.MIN_ACTIVATION_BALANCE - ) - assert state.validators[source_index].exit_epoch == expected_exit_epoch + 1 - for i in range(consolidation_count): - assert state.validators[2 * i].exit_epoch == expected_exit_epoch - - -@with_electra_and_later -@with_presets([MINIMAL], "need sufficient consolidation churn limit") -@with_custom_state( - balances_fn=scaled_churn_balances_exceed_activation_exit_churn_limit, - threshold_fn=default_activation_threshold, -) -@spec_test -@single_phase -def test_multiple_consolidations_equal_twice_churn(spec, state): - # This state has 256 validators each with 32 ETH in MINIMAL preset, 128 ETH consolidation churn - consolidation_churn_limit = spec.get_consolidation_churn_limit(state) - # Set the consolidation balance to consume equal to churn limit - state.consolidation_balance_to_consume = consolidation_churn_limit - current_epoch = spec.get_current_epoch(state) - - yield "pre", state - # Prepare a bunch of consolidations, each of them in a block, based on the current state - blocks = [] - consolidation_count = 8 - for i in range(consolidation_count): - source_index = 2 * i - target_index = 2 * i + 1 - source_privkey = pubkey_to_privkey[state.validators[source_index].pubkey] - target_privkey = pubkey_to_privkey[state.validators[target_index].pubkey] - # Set source and target withdrawal credentials to the same eth1 credential - set_eth1_withdrawal_credential_with_balance(spec, state, source_index) - set_eth1_withdrawal_credential_with_balance(spec, state, target_index) - signed_consolidation = sign_consolidation( - spec, - state, - spec.Consolidation( - epoch=current_epoch, - source_index=source_index, - target_index=target_index, - ), - source_privkey, - target_privkey, - ) - block = build_empty_block_for_next_slot(spec, state) - block.body.consolidations = [signed_consolidation] - signed_block = state_transition_and_sign_block(spec, state, block) - blocks.append(signed_block) - - yield "blocks", blocks - yield "post", state - - first_exit_epoch = spec.compute_activation_exit_epoch(current_epoch) - assert state.consolidation_balance_to_consume == 0 - assert state.earliest_consolidation_epoch == first_exit_epoch + 1 - for i in range(consolidation_count // 2): - assert state.validators[2 * i].exit_epoch == first_exit_epoch - for i in range(consolidation_count // 2, consolidation_count): - assert state.validators[2 * i].exit_epoch == first_exit_epoch + 1 diff --git a/tests/core/pyspec/eth2spec/test/helpers/withdrawals.py b/tests/core/pyspec/eth2spec/test/helpers/withdrawals.py index 170d335025..0ce476c86f 100644 --- a/tests/core/pyspec/eth2spec/test/helpers/withdrawals.py +++ b/tests/core/pyspec/eth2spec/test/helpers/withdrawals.py @@ -1,4 +1,3 @@ -import random from eth2spec.test.helpers.forks import is_post_electra @@ -48,8 +47,8 @@ def set_validator_partially_withdrawable(spec, state, index, excess_balance=1000 assert spec.is_partially_withdrawable_validator(validator, state.balances[index]) -def prepare_expected_withdrawals(spec, state, - num_full_withdrawals=0, num_partial_withdrawals=0, rng=random.Random(5566)): +def prepare_expected_withdrawals(spec, state, rng, + num_full_withdrawals=0, num_partial_withdrawals=0): bound = min(len(state.validators), spec.MAX_VALIDATORS_PER_WITHDRAWALS_SWEEP) assert num_full_withdrawals + num_partial_withdrawals <= bound eligible_validator_indices = list(range(bound)) diff --git a/tests/formats/networking/get_custody_columns.md b/tests/formats/networking/get_custody_columns.md index 03b21f729e..ee0c30859c 100644 --- a/tests/formats/networking/get_custody_columns.md +++ b/tests/formats/networking/get_custody_columns.md @@ -8,7 +8,7 @@ ```yaml description: string -- optional: description of test case, purely for debugging purposes. -node_id: int -- argument: the NodeId input. +node_id: int -- argument: the NodeID input. custody_subnet_count: int -- argument: the count of custody subnets. result: list of int -- output: the list of resulting column indices. ```