diff --git a/.github/actions/build-fixtures/action.yaml b/.github/actions/build-fixtures/action.yaml index 36fff598e02..98148e97246 100644 --- a/.github/actions/build-fixtures/action.yaml +++ b/.github/actions/build-fixtures/action.yaml @@ -25,6 +25,9 @@ inputs: evm_ref: description: "Override the t8n tool branch / tag / commit" default: "" + upload: + description: "Upload the filled fixtures. Set to false to rehearse a fill and discard its output." + default: "true" runs: using: "composite" steps: @@ -77,11 +80,12 @@ runs: exit "$EXIT_CODE" fi - uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 + if: inputs.upload == 'true' with: name: fixtures_${{ inputs.release_name }} path: fixtures_${{ inputs.release_name }}.tar.gz - name: Upload fixture directory (split) - if: inputs.split_label != '' + if: inputs.upload == 'true' && inputs.split_label != '' uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: fixtures__${{ inputs.split_label }} diff --git a/.github/configs/feature.yaml b/.github/configs/feature.yaml index 7fca18fd9ef..91eed36ca8a 100644 --- a/.github/configs/feature.yaml +++ b/.github/configs/feature.yaml @@ -1,8 +1,3 @@ -# Unless filling for special features, all features should fill for previous forks (starting from Frontier) too -mainnet: - evm-type: eels - fill-params: --until=BPO4 --generate-all-formats - monad: evm-type: eels fill-params: -m blockchain_test --from=MONAD_EIGHT --until=MONAD_TEN --chain-id=143 -k "not invalid_header" @@ -11,3 +6,7 @@ monad_runloop: evm-type: eels # Like `monad`, but `--monad-runloop` and eestnet chain id `30143` fill-params: -m blockchain_test --from=MONAD_EIGHT --until=MONAD_TEN --chain-id=30143 --monad-runloop -k "not invalid_header" + +monad_eip8246: + evm-type: eels + fill-params: -m blockchain_test --fork=MONAD_NEXT --chain-id=143 -k "not invalid_header" diff --git a/.github/scripts/check_release_matrix.py b/.github/scripts/check_release_matrix.py new file mode 100755 index 00000000000..556d5b92bf7 --- /dev/null +++ b/.github/scripts/check_release_matrix.py @@ -0,0 +1,124 @@ +#!/usr/bin/env -S uv run --script +# +# /// script +# requires-python = ">=3.12" +# dependencies = [ +# "pyyaml", +# ] +# /// +""" +Build the job matrix for a fixture release rehearsal. + +Usage: `check_release_matrix.py [features] [branch]`, where `features` +is an optional comma- or space-separated subset of the feature names in +`.github/configs/feature.yaml`. + +With no `features`, an EIP branch rehearses the feature it releases for +its own EIP and nothing else, and every other branch rehearses every +feature. Either way a branch that adds a feature is covered without +touching the workflow. + +Reuse `generate_build_matrix.py` so a rehearsal fills exactly what the +release fills, then flatten the per-feature matrices into the single +`fill_matrix` a `strategy.matrix` consumes. +""" + +import json +import re +import sys +from pathlib import Path + +sys.path.insert(0, str(Path(__file__).parent)) + +from generate_build_matrix import ( # noqa: E402 + FEATURE_CONFIG, + FORK_RANGES_CONFIG, + build_matrix, + fail, + load_config, +) + +# EIP branches follow `eips//eip-`, with `+` joining the EIP +# numbers a combined branch carries, e.g. `eips/amsterdam/eip-2345+3456`. +EIP_BRANCH_RE = re.compile(r"^eips/[^/]+/eip-([0-9]+(?:\+[0-9]+)*)$") + + +def eip_features(defined: list[str], branch: str) -> list[str]: + """ + Return the features *branch* releases for its own EIPs. + + An EIP branch names its feature after the EIPs it carries, so + `eips/monad_next/eip-7997` releases `monad_eip7997` and + `eips/amsterdam/eip-2345+3456` releases `monad_eip2345+3456`. The + numbers must match in full: a combined branch does not claim the + feature of either EIP on its own, and neither claims the combined + one. Return an empty list for any other branch, and for an EIP + branch that has not declared a feature of its own yet. + """ + match = EIP_BRANCH_RE.match(branch) + if not match: + return [] + numbers = re.compile(rf"eip{re.escape(match.group(1))}(?![0-9+])") + return [name for name in defined if numbers.search(name)] + + +def defined_features(config: dict) -> list[str]: + """Return every feature name in `feature.yaml`, in config order.""" + return [ + name for name, feature in config.items() if isinstance(feature, dict) + ] + + +def select_features(config: dict, requested: str, branch: str) -> list[str]: + """ + Narrow the rehearsal to the requested features. + + An empty request falls back to the features *branch* releases for + its own EIPs, then to every feature: this fork releases all of + them. An unknown name fails the run rather than silently + rehearsing less than was asked for. + """ + defined = defined_features(config) + names = [name for name in requested.replace(",", " ").split() if name] + if names: + unknown = [name for name in names if name not in defined] + if unknown: + fail( + f"unknown feature(s) {', '.join(unknown)}; " + f"{FEATURE_CONFIG} defines {', '.join(defined)}" + ) + return names + from_branch = eip_features(defined, branch) + if from_branch: + print( + f"Branch '{branch}' releases {', '.join(from_branch)}; " + "rehearsing only that.", + file=sys.stderr, + ) + return from_branch + return defined + + +def main() -> None: + """Print the rehearsal's feature list and fill matrix to stdout.""" + requested = sys.argv[1] if len(sys.argv) > 1 else "" + branch = sys.argv[2] if len(sys.argv) > 2 else "" + + config = load_config(FEATURE_CONFIG) + fork_ranges = load_config(FORK_RANGES_CONFIG) or [] + + features = select_features(config, requested, branch) + if not features: + fail(f"{FEATURE_CONFIG} defines no feature") + + matrix: list[dict] = [] + for name in features: + entries, _ = build_matrix(config[name], name, fork_ranges) + matrix.extend(entries) + + print(f"features={json.dumps(features)}") + print(f"fill_matrix={json.dumps(matrix)}") + + +if __name__ == "__main__": + main() diff --git a/.github/workflows/check_release.yaml b/.github/workflows/check_release.yaml new file mode 100644 index 00000000000..8b1f7447b6f --- /dev/null +++ b/.github/workflows/check_release.yaml @@ -0,0 +1,174 @@ +name: Check Fixture Release + +run-name: ${{ github.event_name == 'workflow_dispatch' && format('Check Fixture Release ({0}) {1}', inputs.depth, inputs.features) || 'Check Fixture Release' }} + +# Rehearse the fixture releases this fork ships, so a fill that a change +# breaks surfaces on the branch that broke it rather than on the next +# release attempt. +# +# Two tiers, both running on every pull request and on pushes to the +# branches that release in parallel with the fork branch, +# `from-upstream` and `eips/**`. +# +# `collect` is cheap: it reads the features the branch releases out of +# `.github/configs/feature.yaml`, builds the release's job matrix +# from it and collects its tests, catching malformed feature entries, +# import errors and parametrization errors in a few minutes. It gates +# `fill`, which is comprehensive: `fill` runs the very fill the release +# runs, via the release's own action, and is the only tier that catches +# a test that fills wrong. A manual dispatch can ask for `collect` +# alone, and can narrow the run to a subset of the features. + +on: + push: + branches: + - from-upstream + - "eips/**" + paths-ignore: + - "**.md" + - "LICENSE*" + - ".gitignore" + - ".vscode/**" + - "whitelist.txt" + - "docs/**" + - "mkdocs.yml" + pull_request: + paths-ignore: + - "**.md" + - "LICENSE*" + - ".gitignore" + - ".vscode/**" + - "whitelist.txt" + - "docs/**" + - "mkdocs.yml" + workflow_dispatch: + inputs: + depth: + description: "full = fill every feature (hours); collect = validate the config and collect the tests (minutes)" + required: true + type: choice + options: [full, collect] + default: full + features: + description: "Features to rehearse, e.g. monad_runloop. Empty = an EIP branch's own feature, or every feature elsewhere." + required: false + type: string + +concurrency: + group: ${{ github.workflow }}-${{ github.ref || github.run_id }} + cancel-in-progress: ${{ github.ref_name != github.event.repository.default_branch }} + +permissions: + contents: read + +jobs: + setup: + runs-on: ubuntu-latest + outputs: + features: ${{ steps.matrix.outputs.features }} + fill_matrix: ${{ steps.matrix.outputs.fill_matrix }} + fill: ${{ steps.depth.outputs.fill }} + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + submodules: false + - uses: ./.github/actions/setup-uv + + - name: Select the features to rehearse + id: matrix + shell: bash + env: + INPUT_FEATURES: ${{ inputs.features }} + # The head branch, so a pull request from an EIP branch + # rehearses that branch's feature; `ref_name` is the merge ref + # on a pull request and the branch everywhere else. + BRANCH: ${{ github.head_ref || github.ref_name }} + run: | + # The feature selection and the per-feature release matrix live + # in (and are shared with the release workflow via) + # check_release_matrix.py. + uv run -q .github/scripts/check_release_matrix.py \ + "$INPUT_FEATURES" "$BRANCH" | tee -a "$GITHUB_OUTPUT" + + - name: Decide whether to fill + id: depth + shell: bash + env: + EVENT: ${{ github.event_name }} + DEPTH: ${{ inputs.depth }} + run: | + # Every automatic trigger fills; only a dispatch can ask for + # the cheap tier alone. + if [ "$EVENT" = "workflow_dispatch" ] && [ "$DEPTH" != "full" ] + then + fill=false + else + fill=true + fi + echo "Fill: $fill" + echo "fill=$fill" >> "$GITHUB_OUTPUT" + + collect: + name: collect (${{ matrix.feature }}) + needs: setup + runs-on: ubuntu-24.04 + timeout-minutes: 30 + strategy: + # A rehearsal wants every feature's verdict, not the first failure. + fail-fast: false + matrix: + feature: ${{ fromJson(needs.setup.outputs.features) }} + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + submodules: true + - uses: ./.github/actions/setup-uv + - name: Install EEST + run: uv sync --no-progress + + - name: Extract fixture release properties from config + id: properties + run: | + uv run -q .github/scripts/get_release_props.py ${{ matrix.feature }} >> "$GITHUB_OUTPUT" + + - name: Collect the release's tests + shell: bash + run: | + # `fill-params` is interpolated rather than passed through a + # variable so its quoting survives, as in `build-fixtures`. + # Collecting nothing means an empty release, so pytest's exit + # code 5 fails here where a release's fork-range split + # tolerates it. + status=0 + uv run fill --collect-only -q \ + ${{ steps.properties.outputs.fill-params }} > collected.txt \ + || status=$? + tail -n 20 collected.txt + exit "$status" + + fill: + name: fill (${{ matrix.label || matrix.feature }}) + needs: [setup, collect] + if: needs.setup.outputs.fill == 'true' + runs-on: ubuntu-24.04 + # Hosted runners cap a job at six hours regardless; the explicit + # timeout keeps a wedged fill from burning the whole budget. + timeout-minutes: 360 + strategy: + fail-fast: false + matrix: + include: ${{ fromJson(needs.setup.outputs.fill_matrix) }} + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + submodules: true + + - uses: ./.github/actions/build-fixtures + with: + release_name: ${{ matrix.feature }} + from_fork: ${{ matrix.from_fork }} + until_fork: ${{ matrix.until_fork }} + split_label: ${{ matrix.label }} + # A rehearsal only reports whether the fill succeeds; keeping + # its fixtures would cost storage for output nothing consumes. + upload: "false" diff --git a/packages/testing/src/execution_testing/cli/pytest_commands/plugins/forks/forks.py b/packages/testing/src/execution_testing/cli/pytest_commands/plugins/forks/forks.py index 6075481806c..29ef4dc86e3 100644 --- a/packages/testing/src/execution_testing/cli/pytest_commands/plugins/forks/forks.py +++ b/packages/testing/src/execution_testing/cli/pytest_commands/plugins/forks/forks.py @@ -1265,7 +1265,9 @@ def _process_with_marker_args( "Missing fork argument with 'valid_at_transition_to' marker." ) - if len(forks) > 1: + # A single EIP argument expands to one fork per enabling fork, so + # the limit is on the arguments rather than on the resolved forks. + if len(fork_args) > 1: raise Exception( "Too many forks specified to 'valid_at_transition_to' marker." ) diff --git a/packages/testing/src/execution_testing/forks/base_fork.py b/packages/testing/src/execution_testing/forks/base_fork.py index f842878c42f..38dea7ca65c 100644 --- a/packages/testing/src/execution_testing/forks/base_fork.py +++ b/packages/testing/src/execution_testing/forks/base_fork.py @@ -333,12 +333,25 @@ def _maybe_transitioned(fork_cls: "BaseForkMeta") -> "BaseForkMeta": @staticmethod def _is_subclass_of(a: "BaseForkMeta", b: "BaseForkMeta") -> bool: """ - Check if `a` is a subclass of `b`, taking fork transitions into - account. + Check if `a` is a subclass of `b`, taking fork transitions and + declared succession into account. + + A fork can follow another fork it does not inherit from, which + places it after that fork (and after everything that fork comes + after) in the fork order without adopting its behavior. """ a = BaseForkMeta._maybe_transitioned(a) b = BaseForkMeta._maybe_transitioned(b) - return issubclass(a, b) + if issubclass(a, b): + return True + # The metaclass sees its instances as plain classes, so the + # trait is reached through a cast, as elsewhere in this class. + followed = cast(Type["BaseFork"], a).follows() + while followed is not None: + if issubclass(followed, b): + return True + followed = followed.follows() + return False def __gt__(cls, other: "BaseForkMeta") -> bool: """Compare if a fork is newer than some other fork (cls > other).""" @@ -1407,6 +1420,17 @@ def enabling_forks(cls) -> Set[Type["BaseFork"]]: raise Exception(f"Class {cls.__name__} is not an EIP.") return cls._enabling_forks + @classmethod + def follows(cls) -> Type["BaseFork"] | None: + """ + Return the fork this one comes after without inheriting it. + + A fork that reuses another lineage's ordering overrides this; + comparisons then place it after that fork, and after everything + that fork comes after, while its behavior stays its own. + """ + return None + @classmethod def parent(cls) -> Type["BaseFork"] | None: """Return the parent fork.""" diff --git a/packages/testing/src/execution_testing/forks/forks/forks.py b/packages/testing/src/execution_testing/forks/forks/forks.py index ecf3b02f3ae..52c47fcb45b 100644 --- a/packages/testing/src/execution_testing/forks/forks/forks.py +++ b/packages/testing/src/execution_testing/forks/forks/forks.py @@ -1805,12 +1805,6 @@ def _calculate_sstore_gas_mip8( return gas_cost -class MONAD_NEXT(MONAD_TEN): # noqa: N801 - """MONAD_NEXT fork, a placeholder identical to MONAD_TEN.""" - - pass - - class BPO1( Osaka, bpo_fork=True, @@ -1904,3 +1898,22 @@ def engine_payload_attribute_target_gas_limit(cls) -> bool: limit. """ return True + + +class MONAD_NEXT( # noqa: N801 + eips.EIP8246, + MONAD_TEN, +): + """ + MONAD_NEXT fork. + + Amsterdam-based successor to MONAD_TEN, adopting the EIP-8246 + changes. The Amsterdam changes it does not adopt stay out of the + fork by not being inherited at all; the fork order still places + MONAD_NEXT after Amsterdam through `follows`. + """ + + @classmethod + def follows(cls) -> type[BaseFork] | None: + """MONAD_NEXT comes after Amsterdam without inheriting it.""" + return Amsterdam diff --git a/src/ethereum/forks/monad_next/fork.py b/src/ethereum/forks/monad_next/fork.py index 653f05d030f..7b27bf2d821 100644 --- a/src/ethereum/forks/monad_next/fork.py +++ b/src/ethereum/forks/monad_next/fork.py @@ -61,8 +61,8 @@ BlockState, TransactionState, add_sender_authority, + clear_account_preserving_balance, create_ether, - destroy_account, extract_block_diff, forget_senders_authorities, get_account, @@ -974,7 +974,7 @@ def process_transaction( create_ether(tx_state, block_env.coinbase, U256(transaction_fee)) for address in tx_output.accounts_to_delete: - destroy_account(tx_state, address) + clear_account_preserving_balance(tx_state, address) # block_output.block_gas_used += tx_gas_used_after_refund block_output.block_gas_used += tx.gas diff --git a/src/ethereum/forks/monad_next/state_tracker.py b/src/ethereum/forks/monad_next/state_tracker.py index 5b3d4be0bd2..1d0914461d2 100644 --- a/src/ethereum/forks/monad_next/state_tracker.py +++ b/src/ethereum/forks/monad_next/state_tracker.py @@ -423,10 +423,9 @@ def destroy_account(tx_state: TransactionState, address: Address) -> None: """ Completely remove the account at ``address`` and all of its storage. - This function is made available exclusively for the ``SELFDESTRUCT`` - opcode. It is expected that ``SELFDESTRUCT`` will be disabled in a - future hardfork and this function will be removed. Only supports same - transaction destruction. + Invoked by ``modify_state`` (and the coinbase fee-credit path) to + clean up an account that has become empty (zero nonce, empty + code, and zero balance) so it does not appear in the post-state. Parameters ---------- @@ -440,6 +439,30 @@ def destroy_account(tx_state: TransactionState, address: Address) -> None: set_account(tx_state, address, None) +def clear_account_preserving_balance( + tx_state: TransactionState, address: Address +) -> None: + """ + Clear an account's nonce, code, and storage while preserving its + balance. + + Parameters + ---------- + tx_state : + The transaction state. + address : + Address of the account to modify. + + """ + + def clear_account(account: Account) -> None: + account.nonce = Uint(0) + account.code_hash = EMPTY_CODE_HASH + + destroy_storage(tx_state, address) + modify_state(tx_state, address, clear_account) + + def destroy_storage(tx_state: TransactionState, address: Address) -> None: """ Completely remove the storage at ``address``. diff --git a/src/ethereum/forks/monad_next/vm/instructions/system.py b/src/ethereum/forks/monad_next/vm/instructions/system.py index 7b8634c5d7e..764bcec38fe 100644 --- a/src/ethereum/forks/monad_next/vm/instructions/system.py +++ b/src/ethereum/forks/monad_next/vm/instructions/system.py @@ -24,7 +24,6 @@ increment_nonce, is_account_alive, move_ether, - set_account_balance, ) from ...utils.address import ( compute_contract_address, @@ -587,9 +586,6 @@ def selfdestruct(evm: Evm) -> None: # register account for deletion only if it was created # in the same transaction if originator in evm.message.tx_env.state.created_accounts: - # If beneficiary is the same as originator, then - # the ether is burnt. - set_account_balance(evm.message.tx_env.state, originator, U256(0)) evm.accounts_to_delete.add(originator) # HALT the execution diff --git a/tests/amsterdam/eip2780_reduce_intrinsic_tx_gas/conftest.py b/tests/amsterdam/eip2780_reduce_intrinsic_tx_gas/conftest.py new file mode 100644 index 00000000000..de52075d396 --- /dev/null +++ b/tests/amsterdam/eip2780_reduce_intrinsic_tx_gas/conftest.py @@ -0,0 +1,10 @@ +"""Pytest (plugin) definitions local to EIP-2780 tests.""" + +import pytest + + +def pytest_generate_tests(metafunc: pytest.Metafunc) -> None: + """Mark all tests in this subdir as not valid for Monad forks.""" + metafunc.definition.add_marker( + pytest.mark.not_valid_for("MONAD_EIGHT", subsequent_forks=True) + ) diff --git a/tests/amsterdam/eip7708_eth_transfer_logs/conftest.py b/tests/amsterdam/eip7708_eth_transfer_logs/conftest.py new file mode 100644 index 00000000000..fb1d9465b3e --- /dev/null +++ b/tests/amsterdam/eip7708_eth_transfer_logs/conftest.py @@ -0,0 +1,10 @@ +"""Pytest (plugin) definitions local to EIP-7708 tests.""" + +import pytest + + +def pytest_generate_tests(metafunc: pytest.Metafunc) -> None: + """Mark all tests in this subdir as not valid for Monad forks.""" + metafunc.definition.add_marker( + pytest.mark.not_valid_for("MONAD_EIGHT", subsequent_forks=True) + ) diff --git a/tests/amsterdam/eip7778_block_gas_accounting_without_refunds/conftest.py b/tests/amsterdam/eip7778_block_gas_accounting_without_refunds/conftest.py new file mode 100644 index 00000000000..5cbdebdc9ef --- /dev/null +++ b/tests/amsterdam/eip7778_block_gas_accounting_without_refunds/conftest.py @@ -0,0 +1,10 @@ +"""Pytest (plugin) definitions local to EIP-7778 tests.""" + +import pytest + + +def pytest_generate_tests(metafunc: pytest.Metafunc) -> None: + """Mark all tests in this subdir as not valid for Monad forks.""" + metafunc.definition.add_marker( + pytest.mark.not_valid_for("MONAD_EIGHT", subsequent_forks=True) + ) diff --git a/tests/amsterdam/eip7843_slotnum/conftest.py b/tests/amsterdam/eip7843_slotnum/conftest.py new file mode 100644 index 00000000000..6e43f18fb35 --- /dev/null +++ b/tests/amsterdam/eip7843_slotnum/conftest.py @@ -0,0 +1,10 @@ +"""Pytest (plugin) definitions local to EIP-7843 tests.""" + +import pytest + + +def pytest_generate_tests(metafunc: pytest.Metafunc) -> None: + """Mark all tests in this subdir as not valid for Monad forks.""" + metafunc.definition.add_marker( + pytest.mark.not_valid_for("MONAD_EIGHT", subsequent_forks=True) + ) diff --git a/tests/amsterdam/eip7928_block_level_access_lists/conftest.py b/tests/amsterdam/eip7928_block_level_access_lists/conftest.py new file mode 100644 index 00000000000..3bedcfe2651 --- /dev/null +++ b/tests/amsterdam/eip7928_block_level_access_lists/conftest.py @@ -0,0 +1,10 @@ +"""Pytest (plugin) definitions local to EIP-7928 tests.""" + +import pytest + + +def pytest_generate_tests(metafunc: pytest.Metafunc) -> None: + """Mark all tests in this subdir as not valid for Monad forks.""" + metafunc.definition.add_marker( + pytest.mark.not_valid_for("MONAD_EIGHT", subsequent_forks=True) + ) diff --git a/tests/amsterdam/eip7976_increase_calldata_floor_cost/conftest.py b/tests/amsterdam/eip7976_increase_calldata_floor_cost/conftest.py index f92a0e003a0..9a252257297 100644 --- a/tests/amsterdam/eip7976_increase_calldata_floor_cost/conftest.py +++ b/tests/amsterdam/eip7976_increase_calldata_floor_cost/conftest.py @@ -370,3 +370,10 @@ def tx( blob_versioned_hashes=blob_versioned_hashes, error=tx_error, ) + + +def pytest_generate_tests(metafunc: pytest.Metafunc) -> None: + """Mark all tests in this subdir as not valid for Monad forks.""" + metafunc.definition.add_marker( + pytest.mark.not_valid_for("MONAD_EIGHT", subsequent_forks=True) + ) diff --git a/tests/amsterdam/eip7997_deterministic_factory_predeploy/conftest.py b/tests/amsterdam/eip7997_deterministic_factory_predeploy/conftest.py new file mode 100644 index 00000000000..de93abfcfef --- /dev/null +++ b/tests/amsterdam/eip7997_deterministic_factory_predeploy/conftest.py @@ -0,0 +1,10 @@ +"""Pytest (plugin) definitions local to EIP-7997 tests.""" + +import pytest + + +def pytest_generate_tests(metafunc: pytest.Metafunc) -> None: + """Mark all tests in this subdir as not valid for Monad forks.""" + metafunc.definition.add_marker( + pytest.mark.not_valid_for("MONAD_EIGHT", subsequent_forks=True) + ) diff --git a/tests/amsterdam/eip8024_dupn_swapn_exchange/conftest.py b/tests/amsterdam/eip8024_dupn_swapn_exchange/conftest.py new file mode 100644 index 00000000000..d8c781bb489 --- /dev/null +++ b/tests/amsterdam/eip8024_dupn_swapn_exchange/conftest.py @@ -0,0 +1,10 @@ +"""Pytest (plugin) definitions local to EIP-8024 tests.""" + +import pytest + + +def pytest_generate_tests(metafunc: pytest.Metafunc) -> None: + """Mark all tests in this subdir as not valid for Monad forks.""" + metafunc.definition.add_marker( + pytest.mark.not_valid_for("MONAD_EIGHT", subsequent_forks=True) + ) diff --git a/tests/amsterdam/eip8037_state_creation_gas_cost_increase/conftest.py b/tests/amsterdam/eip8037_state_creation_gas_cost_increase/conftest.py new file mode 100644 index 00000000000..2d16c275db4 --- /dev/null +++ b/tests/amsterdam/eip8037_state_creation_gas_cost_increase/conftest.py @@ -0,0 +1,10 @@ +"""Pytest (plugin) definitions local to EIP-8037 tests.""" + +import pytest + + +def pytest_generate_tests(metafunc: pytest.Metafunc) -> None: + """Mark all tests in this subdir as not valid for Monad forks.""" + metafunc.definition.add_marker( + pytest.mark.not_valid_for("MONAD_EIGHT", subsequent_forks=True) + ) diff --git a/tests/amsterdam/eip8038_state_access_gas_cost_increase/conftest.py b/tests/amsterdam/eip8038_state_access_gas_cost_increase/conftest.py new file mode 100644 index 00000000000..cd29eb50dcb --- /dev/null +++ b/tests/amsterdam/eip8038_state_access_gas_cost_increase/conftest.py @@ -0,0 +1,10 @@ +"""Pytest (plugin) definitions local to EIP-8038 tests.""" + +import pytest + + +def pytest_generate_tests(metafunc: pytest.Metafunc) -> None: + """Mark all tests in this subdir as not valid for Monad forks.""" + metafunc.definition.add_marker( + pytest.mark.not_valid_for("MONAD_EIGHT", subsequent_forks=True) + ) diff --git a/tests/amsterdam/eip8070_sparse_blobpool/conftest.py b/tests/amsterdam/eip8070_sparse_blobpool/conftest.py index cb2a757494c..dc3ee7c3ecd 100644 --- a/tests/amsterdam/eip8070_sparse_blobpool/conftest.py +++ b/tests/amsterdam/eip8070_sparse_blobpool/conftest.py @@ -148,3 +148,10 @@ def txs( ) txs.append(network_wrapped_tx) return txs + + +def pytest_generate_tests(metafunc: pytest.Metafunc) -> None: + """Mark all tests in this subdir as not valid for Monad forks.""" + metafunc.definition.add_marker( + pytest.mark.not_valid_for("MONAD_EIGHT", subsequent_forks=True) + ) diff --git a/tests/amsterdam/eip8282_builder_execution_requests/conftest.py b/tests/amsterdam/eip8282_builder_execution_requests/conftest.py index e17cee467fc..7a42ba76785 100644 --- a/tests/amsterdam/eip8282_builder_execution_requests/conftest.py +++ b/tests/amsterdam/eip8282_builder_execution_requests/conftest.py @@ -1,8 +1,17 @@ """Fixtures for the EIP-8282 builder execution request tests.""" +import pytest + from ...common.system_contract_request_fixtures import ( blocks, # noqa: F401 included_requests, # noqa: F401 system_contract_interactions_per_block_copy, # noqa: F401 timestamp, # noqa: F401 ) + + +def pytest_generate_tests(metafunc: pytest.Metafunc) -> None: + """Mark all tests in this subdir as not valid for Monad forks.""" + metafunc.definition.add_marker( + pytest.mark.not_valid_for("MONAD_EIGHT", subsequent_forks=True) + ) diff --git a/tests/monad_nine/mip4_checkreservebalance/test_transfers.py b/tests/monad_nine/mip4_checkreservebalance/test_transfers.py index ec43d75dd91..c217fd2cd6e 100644 --- a/tests/monad_nine/mip4_checkreservebalance/test_transfers.py +++ b/tests/monad_nine/mip4_checkreservebalance/test_transfers.py @@ -1462,6 +1462,15 @@ def test_contract_unrestricted_within_initcode( new_balance = balance - value + Spec.RESERVE_BALANCE + # EIP-8246 stops the end-of-transaction cleanup from burning the + # balance, so the refill that follows SELFDESTRUCT is left behind on + # a cleared account. + selfdestructed_account = ( + Account(nonce=0, balance=Spec.RESERVE_BALANCE, code=b"", storage={}) + if fork.is_eip_enabled(8246) + else None + ) + txs = [tx_1] if new_address_pre_funded: txs.insert( @@ -1491,7 +1500,7 @@ def test_contract_unrestricted_within_initcode( balance=new_balance, code=deploy_code ) if not selfdestruct - else None, + else selfdestructed_account, target: Account(balance=value) if value != 0 else None, # SELFDESTRUCT runs during initcode (before factory # refill), so it sends balance - value only.