diff --git a/.github/workflows/fixtures.yaml b/.github/workflows/fixtures.yaml index a68ed5dcb0..5812a7f819 100644 --- a/.github/workflows/fixtures.yaml +++ b/.github/workflows/fixtures.yaml @@ -21,7 +21,7 @@ jobs: python: '3.11' - name: 'fixtures_develop' evm-type: 'develop' - fill-params: '--until=Cancun' + fill-params: '--until=Prague' solc: '0.8.21' python: '3.11' steps: diff --git a/.vscode/launch.recommended.json b/.vscode/launch.recommended.json index da2885969c..8d87af8719 100644 --- a/.vscode/launch.recommended.json +++ b/.vscode/launch.recommended.json @@ -42,7 +42,7 @@ "cwd": "${workspaceFolder}" }, { - "name": "Launch fill --until Shanghai", + "name": "Launch fill --until Cancun", "type": "python", "request": "launch", "module": "pytest", @@ -50,7 +50,7 @@ "-c", "pytest.ini", "--until", - "Shanghai", + "Cancun", "--evm-bin", "${input:evmBinary}", "-v" @@ -58,7 +58,7 @@ "cwd": "${workspaceFolder}" }, { - "name": "Launch fill --until Cancun", + "name": "Launch fill --until Prague", "type": "python", "request": "launch", "module": "pytest", @@ -66,7 +66,7 @@ "-c", "pytest.ini", "--until", - "Cancun", + "Prague", "--evm-bin", "${input:evmBinary}", "-v" @@ -132,8 +132,9 @@ "Paris", "Shanghai", "Cancun", + "Prague", ], - "default": "Shanghai" + "default": "Cancun" }, { "type": "promptString", diff --git a/.vscode/settings.recommended.json b/.vscode/settings.recommended.json index 08d60b4320..930c67df78 100644 --- a/.vscode/settings.recommended.json +++ b/.vscode/settings.recommended.json @@ -23,7 +23,7 @@ "python.testing.pytestEnabled": true, "python.testing.pytestArgs": [ // To discover tests for an upcoming fork, use the `--until` argument as following. - // "--until=Cancun", + // "--until=Prague", // Hopefully vscode-python will support multiple test framework environments sooon, see // https://github.com/microsoft/vscode-python/issues/12075 // For now, to toggle between running "framework tests" and "filling tests" comment/ diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index 4c2dc3437f..1ca674d775 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -27,6 +27,10 @@ Test fixtures for use by clients are available for each release on the [Github r - State test field `transaction` now uses the proper zero-padded hex number format for fields `maxPriorityFeePerGas`, `maxFeePerGas`, and `maxFeePerBlobGas` - Fixtures' hashes (in the `_info` field) are now calculated by removing the "_info" field entirely instead of it being set to an empty dict. +### ๐Ÿ’ฅ Breaking Change + +- Cancun is now the latest deployed fork, and the development fork is now Prague ([#489](https://github.com/ethereum/execution-spec-tests/pull/489)). + ## ๐Ÿ”œ [v2.1.1](https://github.com/ethereum/execution-spec-tests/releases/tag/v2.1.1) - 2024-03-09 ### ๐Ÿงช Test Cases diff --git a/docs/consuming_tests/index.md b/docs/consuming_tests/index.md index e511e54f78..6d579ea4de 100644 --- a/docs/consuming_tests/index.md +++ b/docs/consuming_tests/index.md @@ -45,7 +45,7 @@ Artifacts can be downloaded directly from [the release page](https://github.com/ # The following two artifacts are intended for consumption by clients: # - fixtures.tar.gz: Generated up to the last deployed fork. # - fixtures_develop.tar.gz: Generated up to and including the latest dev fork. -# As of Oct 2023, dev is Cancun, deployed is Shanghai. +# As of March 2024, dev is Prague, deployed is Cancun. ARTIFACT="fixtures_develop.tar.gz" diff --git a/src/ethereum_test_forks/forks/forks.py b/src/ethereum_test_forks/forks/forks.py index 909b5d7d8d..1fba542a3e 100644 --- a/src/ethereum_test_forks/forks/forks.py +++ b/src/ethereum_test_forks/forks/forks.py @@ -366,14 +366,6 @@ class Cancun(Shanghai): Cancun fork """ - @classmethod - def is_deployed(cls): - """ - Flags that Cancun has not been deployed to mainnet; it is under active - development. - """ - return False - @classmethod def solc_min_version(cls) -> Version: """ diff --git a/src/ethereum_test_forks/tests/test_forks.py b/src/ethereum_test_forks/tests/test_forks.py index 60680a9495..a48e249544 100644 --- a/src/ethereum_test_forks/tests/test_forks.py +++ b/src/ethereum_test_forks/tests/test_forks.py @@ -23,9 +23,9 @@ from ..transition_base_fork import transition_fork FIRST_DEPLOYED = Frontier -LAST_DEPLOYED = Shanghai +LAST_DEPLOYED = Cancun LAST_DEVELOPMENT = Prague -DEVELOPMENT_FORKS = [Cancun, Prague] +DEVELOPMENT_FORKS = [Prague] def test_transition_forks(): @@ -67,9 +67,12 @@ def test_transition_forks(): def test_forks_from(): # noqa: D103 - assert forks_from(Paris) == [Paris, LAST_DEPLOYED] - assert forks_from(Paris, deployed_only=True) == [Paris, LAST_DEPLOYED] - assert forks_from(Paris, deployed_only=False) == [Paris, LAST_DEPLOYED] + DEVELOPMENT_FORKS + assert forks_from(Paris)[0] == Paris + assert forks_from(Paris)[-1] == LAST_DEPLOYED + assert forks_from(Paris, deployed_only=True)[0] == Paris + assert forks_from(Paris, deployed_only=True)[-1] == LAST_DEPLOYED + assert forks_from(Paris, deployed_only=False)[0] == Paris + assert forks_from(Paris, deployed_only=False)[-1] == LAST_DEVELOPMENT def test_forks(): diff --git a/src/ethereum_test_tools/code/__init__.py b/src/ethereum_test_tools/code/__init__.py index 86add81a2f..d3abd2ab30 100644 --- a/src/ethereum_test_tools/code/__init__.py +++ b/src/ethereum_test_tools/code/__init__.py @@ -3,7 +3,7 @@ """ from .code import Code from .generators import CalldataCase, Case, CodeGasMeasure, Conditional, Initcode, Switch -from .yul import Yul, YulCompiler +from .yul import Solc, Yul, YulCompiler __all__ = ( "Case", @@ -12,6 +12,7 @@ "CodeGasMeasure", "Conditional", "Initcode", + "Solc", "Switch", "Yul", "YulCompiler", diff --git a/src/ethereum_test_tools/code/yul.py b/src/ethereum_test_tools/code/yul.py index 80343516d5..e3effed504 100644 --- a/src/ethereum_test_tools/code/yul.py +++ b/src/ethereum_test_tools/code/yul.py @@ -4,10 +4,11 @@ import re import warnings +from functools import cached_property from pathlib import Path from shutil import which -from subprocess import PIPE, run -from typing import Optional, Sized, SupportsBytes, Tuple, Type, Union +from subprocess import CompletedProcess, run +from typing import Optional, Sized, SupportsBytes, Type from semver import Version @@ -17,33 +18,59 @@ from .code import Code DEFAULT_SOLC_ARGS = ("--assemble", "-") +VERSION_PATTERN = re.compile(r"Version: (.*)") -def get_evm_version_from_fork(fork: Fork | None): - """ - Get the solc evm version corresponding to `fork`. +class Solc: + """Solc compiler.""" - Args - ---- - fork (Fork): The fork to retrieve the corresponding evm version for. + binary: Path - Returns - ------- - str: The name of evm version as required by solc's --evm-version. - """ - if not fork: - return None - return fork.solc_name() + def __init__( + self, + binary: Optional[Path | str] = None, + ): + if binary is None: + which_path = which("solc") + if which_path is not None: + binary = Path(which_path) + if binary is None or not Path(binary).exists(): + raise Exception( + """`solc` binary executable not found, please refer to + https://docs.soliditylang.org/en/latest/installing-solidity.html + for help downloading and installing `solc`""" + ) + self.binary = Path(binary) + + def run(self, *args: str, input: str | None = None) -> CompletedProcess: + """Run solc with the given arguments""" + return run( + [self.binary, *args], + capture_output=True, + text=True, + input=input, + ) + + @cached_property + def version(self) -> Version: + """Return solc's version""" + for line in self.run("--version").stdout.splitlines(): + if match := VERSION_PATTERN.search(line): + # Sanitize + solc_version_string = match.group(1).replace("g++", "gpp") + return Version.parse(solc_version_string) + warnings.warn("Unable to determine solc version.") + return Version(0) -class Yul(SupportsBytes, Sized): +class Yul(Solc, SupportsBytes, Sized): """ Yul compiler. Compiles Yul source code into bytecode. """ source: str - compiled: Optional[bytes] = None + evm_version: str | None def __init__( self, @@ -51,52 +78,32 @@ def __init__( fork: Optional[Fork] = None, binary: Optional[Path | str] = None, ): + super().__init__(binary) self.source = source - self.evm_version = get_evm_version_from_fork(fork) - if binary is None: - which_path = which("solc") - if which_path is not None: - binary = Path(which_path) - if binary is None or not Path(binary).exists(): - raise Exception( - """`solc` binary executable not found, please refer to - https://docs.soliditylang.org/en/latest/installing-solidity.html - for help downloading and installing `solc`""" - ) - self.binary = Path(binary) + self.evm_version = fork.solc_name() if fork else None - def __bytes__(self) -> bytes: - """ - Assembles using `solc --assemble`. - """ - if not self.compiled: - solc_args: Tuple[Union[Path, str], ...] = () - if self.evm_version: - solc_args = ( - self.binary, - "--evm-version", - self.evm_version, - *DEFAULT_SOLC_ARGS, - ) - else: - solc_args = (self.binary, *DEFAULT_SOLC_ARGS) - result = run( - solc_args, - input=str.encode(self.source), - stdout=PIPE, - stderr=PIPE, - ) + @cached_property + def compiled(self) -> bytes: + """Returns the compiled Yul source code.""" + solc_args = ("--evm-version", self.evm_version) if self.evm_version else () + + result = self.run(*solc_args, *DEFAULT_SOLC_ARGS, input=self.source) + + if result.returncode: + stderr_lines = result.stderr.splitlines() + stderr_message = "\n".join(line.strip() for line in stderr_lines) + raise Exception(f"failed to compile yul source:\n{stderr_message[7:]}") - if result.returncode != 0: - stderr_lines = result.stderr.decode().split("\n") - stderr_message = "\n".join(line.strip() for line in stderr_lines) - raise Exception(f"failed to compile yul source:\n{stderr_message[7:]}") + lines = result.stdout.splitlines() - lines = result.stdout.decode().split("\n") + hex_str = lines[lines.index("Binary representation:") + 1] - hex_str = lines[lines.index("Binary representation:") + 1] + return bytes.fromhex(hex_str) - self.compiled = bytes.fromhex(hex_str) + def __bytes__(self) -> bytes: + """ + Assembles using `solc --assemble`. + """ return self.compiled def __len__(self) -> int: @@ -117,28 +124,5 @@ def __radd__(self, other: str | bytes | SupportsBytes) -> Code: """ return Code(to_bytes(other) + bytes(self)) - def version(self) -> Version: - """ - Return solc's version string - """ - result = run( - [self.binary, "--version"], - stdout=PIPE, - stderr=PIPE, - ) - solc_output = result.stdout.decode().split("\n") - version_pattern = r"Version: (.*)" - solc_version_string = "" - for line in solc_output: - if match := re.search(version_pattern, line): - solc_version_string = match.group(1) - break - if not solc_version_string: - warnings.warn("Unable to determine solc version.") - return Version(0) - # Sanitize - solc_version_string = solc_version_string.replace("g++", "gpp") - return Version.parse(solc_version_string) - YulCompiler = Type[Yul] diff --git a/src/ethereum_test_tools/tests/conftest.py b/src/ethereum_test_tools/tests/conftest.py index 16a6068eb9..b07b29cfdc 100644 --- a/src/ethereum_test_tools/tests/conftest.py +++ b/src/ethereum_test_tools/tests/conftest.py @@ -15,7 +15,7 @@ @pytest.fixture(scope="session") def solc_version() -> Version: """Return the version of solc being used for tests.""" - solc_version = Yul("").version().finalize_version() + solc_version = Yul("").version.finalize_version() if solc_version < Frontier.solc_min_version(): raise Exception("Unsupported solc version: {}".format(solc_version)) return solc_version diff --git a/src/ethereum_test_tools/tests/test_code.py b/src/ethereum_test_tools/tests/test_code.py index f6d58bf4cc..4d8e509cfb 100644 --- a/src/ethereum_test_tools/tests/test_code.py +++ b/src/ethereum_test_tools/tests/test_code.py @@ -8,10 +8,17 @@ import pytest from semver import Version -from ethereum_test_forks import Fork, Homestead, Shanghai, get_deployed_forks +from ethereum_test_forks import ( + Cancun, + Fork, + Homestead, + Shanghai, + get_closest_fork_with_solc_support, + get_deployed_forks, +) from evm_transition_tool import FixtureFormats, GethTransitionTool -from ..code import CalldataCase, Case, Code, Conditional, Initcode, Switch, Yul +from ..code import CalldataCase, Case, Code, Conditional, Initcode, Solc, Switch, Yul from ..common import Account, Environment, Hash, TestAddress, Transaction from ..spec import StateTest from ..vm.opcode import Opcodes as Op @@ -66,7 +73,9 @@ def yul_code(request: pytest.FixtureRequest, fork: Fork, padding_before: str, pa else: compiled_yul_code = Code("") for yul_code in yul_code_snippets: - compiled_yul_code += Yul(yul_code, fork=fork) + compiled_yul_code += Yul( + yul_code, fork=get_closest_fork_with_solc_support(fork, Solc().version) + ) if padding_after is not None: compiled_yul_code += Code(padding_after) return compiled_yul_code @@ -83,7 +92,7 @@ def expected_bytes(request: pytest.FixtureRequest, solc_version: Version, fork: solc_padding = "00" return bytes.fromhex(expected_bytes.substitute(solc_padding=solc_padding)) if isinstance(expected_bytes, bytes): - if fork == Shanghai: + if fork >= Shanghai: expected_bytes = b"\x5f" + expected_bytes[2:] if solc_version < SOLC_PADDING_VERSION or fork <= Homestead: return expected_bytes @@ -650,7 +659,7 @@ def test_switch(tx_data: bytes, switch_bytecode: bytes, expected_storage: Mappin ) state_test.generate( t8n=GethTransitionTool(), - fork=Shanghai, + fork=Cancun, fixture_format=FixtureFormats.BLOCKCHAIN_TEST, eips=None, ) diff --git a/src/pytest_plugins/test_filler/test_filler.py b/src/pytest_plugins/test_filler/test_filler.py index f1407596de..911f61ad30 100644 --- a/src/pytest_plugins/test_filler/test_filler.py +++ b/src/pytest_plugins/test_filler/test_filler.py @@ -168,7 +168,7 @@ def pytest_configure(config): "The Besu t8n tool does not work well with the xdist plugin; use -n=0.", returncode=pytest.ExitCode.USAGE_ERROR, ) - config.solc_version = Yul("", binary=config.getoption("solc_bin")).version() + config.solc_version = Yul("", binary=config.getoption("solc_bin")).version if config.solc_version < Frontier.solc_min_version(): pytest.exit( f"Unsupported solc version: {config.solc_version}. Minimum required version is " diff --git a/tox.ini b/tox.ini index ca015022b4..c29e91130d 100644 --- a/tox.ini +++ b/tox.ini @@ -5,7 +5,7 @@ env_list = docs [main] -development_fork = Cancun +development_fork = Prague [testenv] package = wheel