Skip to content

Commit 96906a1

Browse files
winsvegamarioevz
authored andcommitted
feat(tests/port): convert stShiftCombinationsFiller (>30Mgas) (ethereum#1683)
* port stShiftCobinationsFiller * minor optimization * docs: Changelog * update spec sha --------- Co-authored-by: Mario Vega <marioevz@gmail.com>
1 parent 730f953 commit 96906a1

File tree

5 files changed

+215
-2152
lines changed

5 files changed

+215
-2152
lines changed

docs/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ Users can select any of the artifacts depending on their testing needs for their
5959
- 🔀 Refactored `BLOBHASH` opcode context tests to use the `pre_alloc` plugin in order to avoid contract and EOA address collisions ([#1637](https://github.com/ethereum/execution-spec-tests/pull/1637)).
6060
- 🔀 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)).
6161
- ✨ 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)).
62+
- 🔀 Refactored EIP-145 static tests into python ([#1683](https://github.com/ethereum/execution-spec-tests/pull/1683)).
6263

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
"""
2+
abstract: Test [EIP-145: Bitwise shifting instructions in EVM](https://eips.ethereum.org/EIPS/eip-145).
3+
4+
Tests for [EIP-145: Bitwise shifting instructions in EVM](https://eips.ethereum.org/EIPS/eip-145).
5+
"""
Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
"""Defines EIP-145 specification constants and functions."""
2+
3+
from dataclasses import dataclass
4+
5+
6+
@dataclass(frozen=True)
7+
class ReferenceSpec:
8+
"""Defines the reference spec version and git path."""
9+
10+
git_path: str
11+
version: str
12+
13+
14+
ref_spec_145 = ReferenceSpec("EIPS/eip-145.md", "be0aca3e57f1eeb8ae265e58da6e2dffc5b67f81")
15+
16+
17+
@dataclass(frozen=True)
18+
class Spec:
19+
"""
20+
Parameters from the EIP-145 specifications as defined at
21+
https://eips.ethereum.org/EIPS/eip-145.
22+
"""
23+
24+
# Below are GPT o4-mini-high implementation of shift functions
25+
# It can contain bugs, treat it with caution and refer to EVM implementations
26+
@staticmethod
27+
def sar(shift: int, value: int) -> int:
28+
"""
29+
Simulate the EVM SAR (Signed Arithmetic Right shift) operation.
30+
31+
Parameters
32+
----------
33+
shift : int
34+
Number of bits to shift to the right (interpreted as full unsigned;
35+
no low-8-bit truncation here).
36+
value : int
37+
The 256-bit value to shift, interpreted as a signed integer.
38+
39+
Returns
40+
-------
41+
int
42+
The result of the arithmetic right shift, pushed as an unsigned
43+
256-bit integer on the EVM stack.
44+
45+
"""
46+
mask256 = (1 << 256) - 1 # Clamp value to 256 bits
47+
48+
# Interpret as signed
49+
v = value & mask256
50+
if v >> 255:
51+
v_signed = v - (1 << 256)
52+
else:
53+
v_signed = v
54+
55+
# If shift >= 256, spec says:
56+
# • result = 0 if v_signed >= 0
57+
# • result = -1 if v_signed < 0
58+
if shift >= 256:
59+
result_signed = -1 if v_signed < 0 else 0
60+
else:
61+
# Normal arithmetic right shift
62+
result_signed = v_signed >> shift
63+
64+
# Wrap back to unsigned 256-bit
65+
return result_signed & mask256
66+
67+
@staticmethod
68+
def shl(shift: int, value: int) -> int:
69+
"""
70+
Simulate the EVM SHL (Logical Left shift) operation.
71+
72+
Parameters
73+
----------
74+
shift : int
75+
Number of bits to shift to the left.
76+
value : int
77+
The 256-bit value to shift, interpreted as an unsigned integer.
78+
79+
Returns
80+
-------
81+
int
82+
The result of the logical left shift, pushed as an unsigned
83+
256-bit integer on the EVM stack.
84+
85+
"""
86+
mask256 = (1 << 256) - 1
87+
# Clamp input to 256 bits
88+
v = value & mask256
89+
90+
# If shift >= 256, spec returns 0
91+
if shift >= 256:
92+
return 0
93+
94+
# Logical left shift and wrap to 256 bits
95+
return (v << shift) & mask256
96+
97+
@staticmethod
98+
def shr(shift: int, value: int) -> int:
99+
"""
100+
Simulate the EVM SHR (Logical Right shift) operation.
101+
102+
Parameters
103+
----------
104+
shift : int
105+
Number of bits to shift to the right.
106+
value : int
107+
The 256-bit value to shift, interpreted as an unsigned integer.
108+
109+
Returns
110+
-------
111+
int
112+
The result of the logical right shift, pushed as an unsigned
113+
256-bit integer on the EVM stack.
114+
115+
"""
116+
mask256 = (1 << 256) - 1
117+
# Clamp input to 256 bits
118+
v = value & mask256
119+
120+
# If shift >= 256, the EVM spec returns 0
121+
if shift >= 256:
122+
return 0
123+
124+
# Logical right shift and mask back to 256 bits
125+
return (v >> shift) & mask256
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
"""Test bitwise shift opcodes in different combinations."""
2+
3+
import itertools
4+
from typing import Callable
5+
6+
import pytest
7+
8+
from ethereum_test_tools import (
9+
Account,
10+
Alloc,
11+
StateTestFiller,
12+
Storage,
13+
Transaction,
14+
)
15+
from ethereum_test_tools import Opcodes as Op
16+
17+
from .spec import Spec, ref_spec_145
18+
19+
REFERENCE_SPEC_GIT_PATH = ref_spec_145.git_path
20+
REFERENCE_SPEC_VERSION = ref_spec_145.version
21+
22+
list_of_args = [
23+
0,
24+
1,
25+
2,
26+
5,
27+
0xFE,
28+
0xFF,
29+
0x100,
30+
0x101,
31+
0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF,
32+
0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE,
33+
0x8000000000000000000000000000000000000000000000000000000000000000,
34+
0xA000000000000000000000000000000000000000000000000000000000000000,
35+
0x5555555555555555555555555555555555555555555555555555555555555555,
36+
0xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,
37+
0x0000000000000000000000000000000000000000000000000000000000000080,
38+
0x0000000000000000000000000000000000000000000000000000000000008000,
39+
0x0000000000000000000000000000000000000000000000000000000080000000,
40+
0x0000000000000000000000000000000000000000000000008000000000000000,
41+
0x0000000000000000000000000000000080000000000000000000000000000000,
42+
0x8000000000000000000000000000000000000000000000000000000000000000,
43+
]
44+
combinations = list(itertools.product(list_of_args, repeat=2))
45+
46+
47+
@pytest.mark.parametrize(
48+
"opcode,operation",
49+
[
50+
pytest.param(Op.SAR, Spec.sar, id="sar"),
51+
pytest.param(Op.SHL, Spec.shl, id="shl"),
52+
pytest.param(Op.SHR, Spec.shr, id="shr"),
53+
],
54+
)
55+
@pytest.mark.valid_from("Constantinople")
56+
@pytest.mark.ported_from(
57+
[
58+
"https://github.com/ethereum/tests/blob/v13.3/src/GeneralStateTestsFiller/stShift/shiftCombinationsFiller.yml",
59+
"https://github.com/ethereum/tests/blob/v13.3/src/GeneralStateTestsFiller/stShift/shiftSignedCombinationsFiller.yml",
60+
],
61+
pr=["https://github.com/ethereum/execution-spec-tests/pull/1683"],
62+
)
63+
def test_combinations(state_test: StateTestFiller, pre: Alloc, opcode: Op, operation: Callable):
64+
"""Test bitwise shift combinations."""
65+
result = Storage()
66+
address_to = pre.deploy_contract(
67+
code=sum(
68+
Op.SSTORE(
69+
result.store_next(operation(shift=a, value=b), f"{str(opcode).lower()}({a}, {b})"),
70+
opcode(a, b),
71+
)
72+
for a, b in combinations
73+
)
74+
+ Op.SSTORE(result.store_next(1, "code_finished"), 1)
75+
+ Op.STOP,
76+
)
77+
78+
tx = Transaction(
79+
sender=pre.fund_eoa(),
80+
to=address_to,
81+
gas_limit=5_000_000,
82+
)
83+
84+
state_test(pre=pre, post={address_to: Account(storage=result)}, tx=tx)

0 commit comments

Comments
 (0)