Skip to content

Commit f78c534

Browse files
committed
Contract opcodes to compare gas cost for each precompile
Include all test cases and expect precompiles at addresses 01-09 Only include case 0A and 0B to verify no precompile in all valid forks (except cancun)
1 parent b22e901 commit f78c534

File tree

1 file changed

+99
-0
lines changed

1 file changed

+99
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
import pytest
2+
3+
from ethereum_test_tools import (
4+
Account,
5+
Alloc,
6+
Environment,
7+
StateTestFiller,
8+
Transaction,
9+
)
10+
from ethereum_test_tools.code.generators import Conditional
11+
from ethereum_test_tools.vm.opcode import Opcodes as Op
12+
13+
14+
def precompile_addresses(fork: str) -> list[tuple[str, bool]]:
15+
"""
16+
Return the precompile addresses for the given fork.
17+
18+
Args:
19+
fork (str): The fork name.
20+
21+
Returns:
22+
list[tuple[str, bool]]: The precompile addresses and whether they exist.
23+
24+
"""
25+
return [
26+
("01", True),
27+
("02", True),
28+
("03", True),
29+
("04", True),
30+
("05", True),
31+
("06", True),
32+
("07", True),
33+
("08", True),
34+
("09", True),
35+
("0A", True) if fork == "cancun" else ("0A", False),
36+
("0B", False),
37+
]
38+
39+
40+
@pytest.mark.valid_from("Byzantium")
41+
@pytest.mark.parametrize_by_fork("data,precompile_exists", precompile_addresses)
42+
def test_precompiles(state_test: StateTestFiller, data: str, precompile_exists: bool, pre: Alloc):
43+
"""Test the MODEXP precompile."""
44+
env = Environment()
45+
46+
args_offset = 0x1000
47+
args_size = 0x20
48+
output_offset = 0x2000
49+
output_size = 0x20
50+
51+
gas_test = 0x00
52+
gas_10000 = 0x20
53+
54+
account = pre.deploy_contract(
55+
Op.MSTORE(gas_test, Op.GAS())
56+
+ Op.CALL(
57+
address=Op.CALLDATALOAD(0),
58+
args_offset=args_offset,
59+
args_size=args_size,
60+
output_offset=output_offset,
61+
output_size=output_size,
62+
)
63+
+ Op.MSTORE(gas_test, Op.SUB(Op.GAS(), Op.MLOAD(gas_test)))
64+
+ Op.MSTORE(gas_10000, Op.GAS())
65+
+ Op.CALL(
66+
address=0x10000,
67+
args_offset=args_offset,
68+
args_size=args_size,
69+
output_offset=output_offset,
70+
output_size=output_size,
71+
)
72+
+ Op.MSTORE(gas_10000, Op.SUB(Op.GAS(), Op.MLOAD(gas_10000)))
73+
+ Op.SSTORE(
74+
0,
75+
Conditional(
76+
condition=Op.GT(Op.MLOAD(gas_test), Op.MLOAD(gas_10000)),
77+
if_true=Op.SUB(Op.MLOAD(gas_test), Op.MLOAD(gas_10000)),
78+
if_false=Op.SUB(Op.MLOAD(gas_10000), Op.MLOAD(gas_test)),
79+
),
80+
)
81+
+ Op.SSTORE(0, Op.LT(Op.SLOAD(0), 0x10))
82+
+ Op.STOP,
83+
storage={0: 0xDEADBEEF},
84+
)
85+
sender = pre.fund_eoa()
86+
87+
tx = Transaction(
88+
to=account,
89+
data=bytes.fromhex(data),
90+
sender=sender,
91+
gas_limit=1_000_000,
92+
value=0,
93+
)
94+
95+
# A high gas cost will result from calling a precompile
96+
# Expect 0x00 when a precompile exists at the address, 0x01 otherwise
97+
post = {account: Account(storage={0: "0x00" if precompile_exists else "0x01"})}
98+
99+
state_test(env=env, pre=pre, post=post, tx=tx)

0 commit comments

Comments
 (0)