Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ Users can select any of the artifacts depending on their testing needs for their
- πŸ”€ Refactored `SELFDESTRUCT` opcode collision tests to use the `pre_alloc` plugin in order to avoid contract and EOA address collisions ([#1643](https://github.com/ethereum/execution-spec-tests/pull/1643)).
- ✨ EIP-7594: Sanity test cases to send blob transactions and verify `engine_getBlobsVX` using the `execute` command ([#1644](https://github.com/ethereum/execution-spec-tests/pull/1644)).
- πŸ”€ Refactored EIP-145 static tests into python ([#1683](https://github.com/ethereum/execution-spec-tests/pull/1683)).
- ✨ EIP-7823, EIP-7883: Add test cases for ModExp precompile gas-cost updates and input limits on Osaka ([#1579](https://github.com/ethereum/execution-spec-tests/pull/1579)).

## [v4.5.0](https://github.com/ethereum/execution-spec-tests/releases/tag/v4.5.0) - 2025-05-14

Expand Down
11 changes: 8 additions & 3 deletions eels_resolutions.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,13 @@
"same_as": "EELSMaster"
},
"Prague": {
"git_url": "https://github.com/marioevz/execution-specs.git",
"branch": "forks/prague",
"commit": "bb0eb750d643ced0ebf5dec732cdd23558d0b7f2"
"git_url": "https://github.com/marioevz/execution-specs.git",
"branch": "forks/prague",
"commit": "bb0eb750d643ced0ebf5dec732cdd23558d0b7f2"
},
"Osaka": {
"git_url": "https://github.com/spencer-tb/execution-specs.git",
"branch": "forks/osaka",
"commit": "e59c6e3eaed0dbbca639b6f5b6acaa832e51ca00"
}
}
17 changes: 8 additions & 9 deletions src/ethereum_test_types/helpers.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
"""Helper functions/classes used to generate Ethereum tests."""

from dataclasses import MISSING, dataclass, fields
from typing import List, SupportsBytes

import ethereum_rlp as eth_rlp
from pydantic import BaseModel, ConfigDict

from ethereum_test_base_types.base_types import Address, Bytes, Hash
from ethereum_test_base_types.conversions import BytesConvertible, FixedSizeBytesConvertible
Expand Down Expand Up @@ -93,8 +93,7 @@ def add_kzg_version(
return kzg_versioned_hashes


@dataclass(kw_only=True, frozen=True, repr=False)
class TestParameterGroup:
class TestParameterGroup(BaseModel):
"""
Base class for grouping test parameters in a dataclass. Provides a generic
__repr__ method to generate clean test ids, including only non-default
Expand All @@ -103,18 +102,18 @@ class TestParameterGroup:

__test__ = False # explicitly prevent pytest collecting this class

model_config = ConfigDict(frozen=True, validate_default=True)

def __repr__(self):
"""
Generate repr string, intended to be used as a test id, based on the class
name and the values of the non-default optional fields.
"""
class_name = self.__class__.__name__
field_strings = []

for field in fields(self):
value = getattr(self, field.name)
field_strings = [
f"{field}_{value}"
# Include the field only if it is not optional or not set to its default value
if field.default is MISSING or field.default != value:
field_strings.append(f"{field.name}_{value}")
for field, value in self.model_dump(exclude_defaults=True, exclude_unset=True).items()
]

return f"{class_name}_{'-'.join(field_strings)}"
91 changes: 91 additions & 0 deletions tests/byzantium/eip198_modexp_precompile/helpers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
"""Helper functions for the EIP-198 ModExp precompile tests."""

from pydantic import Field

from ethereum_test_tools import Bytes, TestParameterGroup


class ModExpInput(TestParameterGroup):
"""
Helper class that defines the MODEXP precompile inputs and creates the
call data from them.

Attributes:
base (str): The base value for the MODEXP precompile.
exponent (str): The exponent value for the MODEXP precompile.
modulus (str): The modulus value for the MODEXP precompile.
extra_data (str): Defines extra padded data to be added at the end of the calldata
to the precompile. Defaults to an empty string.

"""

base: Bytes
exponent: Bytes
modulus: Bytes
extra_data: Bytes = Field(default_factory=Bytes)

@property
def length_base(self) -> Bytes:
"""Return the length of the base."""
return Bytes(len(self.base).to_bytes(32, "big"))

@property
def length_exponent(self) -> Bytes:
"""Return the length of the exponent."""
return Bytes(len(self.exponent).to_bytes(32, "big"))

@property
def length_modulus(self) -> Bytes:
"""Return the length of the modulus."""
return Bytes(len(self.modulus).to_bytes(32, "big"))

def __bytes__(self):
"""Generate input for the MODEXP precompile."""
return (
self.length_base
+ self.length_exponent
+ self.length_modulus
+ self.base
+ self.exponent
+ self.modulus
+ self.extra_data
)

@classmethod
def from_bytes(cls, input_data: Bytes | str) -> "ModExpInput":
"""
Create a ModExpInput from a bytes object.

Assumes correct formatting of the input data.
"""
if isinstance(input_data, str):
input_data = Bytes(input_data)
base_length = int.from_bytes(input_data[0:32], byteorder="big")
exponent_length = int.from_bytes(input_data[32:64], byteorder="big")
modulus_length = int.from_bytes(input_data[64:96], byteorder="big")

current_index = 96
base = input_data[current_index : current_index + base_length]
current_index += base_length

exponent = input_data[current_index : current_index + exponent_length]
current_index += exponent_length

modulus = input_data[current_index : current_index + modulus_length]

return cls(base=base, exponent=exponent, modulus=modulus)


class ModExpOutput(TestParameterGroup):
"""
Expected test result.

Attributes:
call_success (bool): The return_code from CALL, 0 indicates unsuccessful call
(out-of-gas), 1 indicates call succeeded.
returned_data (str): The output returnData is the expected output of the call

"""

call_success: bool = True
returned_data: Bytes
Loading
Loading