Skip to content

Commit dfbf4c6

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 forks (except cancun)
1 parent b22e901 commit dfbf4c6

File tree

1 file changed

+98
-0
lines changed

1 file changed

+98
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
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):
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.parametrize_by_fork("data,precompile_exists", precompile_addresses)
41+
def test_precompiles(state_test: StateTestFiller, data: str, precompile_exists: bool, pre: Alloc):
42+
"""Test the MODEXP precompile."""
43+
env = Environment()
44+
45+
args_offset = 0x1000
46+
args_size = 0x20
47+
output_offset = 0x2000
48+
output_size = 0x20
49+
50+
gas_test = 0x00
51+
gas_10000 = 0x20
52+
53+
account = pre.deploy_contract(
54+
Op.MSTORE(gas_test, Op.GAS())
55+
+ Op.CALL(
56+
address=Op.CALLDATALOAD(0),
57+
args_offset=args_offset,
58+
args_size=args_size,
59+
output_offset=output_offset,
60+
output_size=output_size,
61+
)
62+
+ Op.MSTORE(gas_test, Op.SUB(Op.GAS(), Op.MLOAD(gas_test)))
63+
+ Op.MSTORE(gas_10000, Op.GAS())
64+
+ Op.CALL(
65+
address=0x10000,
66+
args_offset=args_offset,
67+
args_size=args_size,
68+
output_offset=output_offset,
69+
output_size=output_size,
70+
)
71+
+ Op.MSTORE(gas_10000, Op.SUB(Op.GAS(), Op.MLOAD(gas_10000)))
72+
+ Op.SSTORE(
73+
0,
74+
Conditional(
75+
condition=Op.GT(Op.MLOAD(gas_test), Op.MLOAD(gas_10000)),
76+
if_true=Op.SUB(Op.MLOAD(gas_test), Op.MLOAD(gas_10000)),
77+
if_false=Op.SUB(Op.MLOAD(gas_10000), Op.MLOAD(gas_test)),
78+
),
79+
)
80+
+ Op.SSTORE(0, Op.LT(Op.SLOAD(0), 0x10))
81+
+ Op.STOP,
82+
storage={0: 0xDEADBEEF},
83+
)
84+
sender = pre.fund_eoa()
85+
86+
tx = Transaction(
87+
to=account,
88+
data=bytes.fromhex(data),
89+
sender=sender,
90+
gas_limit=1_000_000,
91+
value=0,
92+
)
93+
94+
# A high gas cost will result from calling a precompile
95+
# Expect 0x00 when a precompile exists at the address, 0x01 otherwise
96+
post = {account: Account(storage={0: "0x00" if precompile_exists else "0x01"})}
97+
98+
state_test(env=env, pre=pre, post=post, tx=tx)

0 commit comments

Comments
 (0)