Skip to content

Commit 33f75a9

Browse files
authored
Merge pull request #13 from marioevz/shanghai-evm-tests-port
Shanghai EVM EIPs Tests: EIP-3651, EIP-3855, EIP-3860
2 parents 24554fc + 567b42e commit 33f75a9

File tree

16 files changed

+1664
-110
lines changed

16 files changed

+1664
-110
lines changed

fillers/eips/__init__.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
"""
2+
Cross-client Ethereum Improvement Proposal Tests
3+
"""

fillers/eips/eip3651.py

Lines changed: 340 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,340 @@
1+
"""
2+
Test EIP-3651: Warm COINBASE
3+
EIP: https://eips.ethereum.org/EIPS/eip-3651
4+
Source tests: https://github.com/ethereum/tests/pull/1082
5+
"""
6+
from typing import Dict
7+
8+
from ethereum_test_tools import (
9+
Account,
10+
CodeGasMeasure,
11+
Environment,
12+
StateTest,
13+
TestAddress,
14+
Transaction,
15+
Yul,
16+
is_fork,
17+
test_from,
18+
to_address,
19+
to_hash,
20+
)
21+
22+
23+
@test_from(fork="merged")
24+
def test_warm_coinbase_call_out_of_gas(fork):
25+
"""
26+
Test warm coinbase.
27+
"""
28+
env = Environment(
29+
coinbase="0x2adc25665018aa1fe0e6bc666dac8fc2697ff9ba",
30+
difficulty=0x20000,
31+
gas_limit=10000000000,
32+
number=1,
33+
timestamp=1000,
34+
)
35+
36+
caller_code = Yul(
37+
"""
38+
{
39+
// Depending on the called contract here, the subcall will perform
40+
// another call/delegatecall/staticcall/callcode that will only
41+
// succeed if coinbase is considered warm by default
42+
// (post-Shanghai).
43+
let calladdr := calldataload(0)
44+
45+
// Amount of gas required to make a call to a warm account.
46+
// Calling a cold account with this amount of gas results in
47+
// exception.
48+
let callgas := 100
49+
50+
switch calladdr
51+
case 0x100 {
52+
// Extra: COINBASE + 6xPUSH1 + DUP6 + 2xPOP
53+
callgas := add(callgas, 27)
54+
}
55+
case 0x200 {
56+
// Extra: COINBASE + 6xPUSH1 + DUP6 + 2xPOP
57+
callgas := add(callgas, 27)
58+
}
59+
case 0x300 {
60+
// Extra: COINBASE + 5xPUSH1 + DUP6 + 2xPOP
61+
callgas := add(callgas, 24)
62+
}
63+
case 0x400 {
64+
// Extra: COINBASE + 5xPUSH1 + DUP6 + 2xPOP
65+
callgas := add(callgas, 24)
66+
}
67+
// Call and save result
68+
sstore(0, call(callgas, calladdr, 0, 0, 0, 0, 0))
69+
}
70+
"""
71+
)
72+
73+
call_code = Yul(
74+
"""
75+
{
76+
let cb := coinbase()
77+
pop(call(0, cb, 0, 0, 0, 0, 0))
78+
}
79+
"""
80+
)
81+
82+
callcode_code = Yul(
83+
"""
84+
{
85+
let cb := coinbase()
86+
pop(callcode(0, cb, 0, 0, 0, 0, 0))
87+
}
88+
"""
89+
)
90+
91+
delegatecall_code = Yul(
92+
"""
93+
{
94+
let cb := coinbase()
95+
pop(delegatecall(0, cb, 0, 0, 0, 0))
96+
}
97+
"""
98+
)
99+
100+
staticcall_code = Yul(
101+
"""
102+
{
103+
let cb := coinbase()
104+
pop(staticcall(0, cb, 0, 0, 0, 0))
105+
}
106+
"""
107+
)
108+
109+
pre = {
110+
TestAddress: Account(balance=1000000000000000000000),
111+
"0xcccccccccccccccccccccccccccccccccccccccc": Account(
112+
code=caller_code
113+
),
114+
to_address(0x100): Account(code=call_code),
115+
to_address(0x200): Account(code=callcode_code),
116+
to_address(0x300): Account(code=delegatecall_code),
117+
to_address(0x400): Account(code=staticcall_code),
118+
}
119+
120+
for i, data in enumerate(
121+
[to_hash(x) for x in range(0x100, 0x400 + 1, 0x100)]
122+
):
123+
124+
tx = Transaction(
125+
ty=0x0,
126+
data=data,
127+
chain_id=0x0,
128+
nonce=0,
129+
to="0xcccccccccccccccccccccccccccccccccccccccc",
130+
gas_limit=100000000,
131+
gas_price=10,
132+
protected=False,
133+
)
134+
135+
post = {}
136+
137+
if is_fork(fork=fork, which="shanghai"):
138+
post["0xcccccccccccccccccccccccccccccccccccccccc"] = Account(
139+
storage={
140+
# On shanghai and beyond, calls with only 100 gas to
141+
# coinbase will succeed.
142+
0: 1,
143+
}
144+
)
145+
else:
146+
post["0xcccccccccccccccccccccccccccccccccccccccc"] = Account(
147+
storage={
148+
# Before shanghai, calls with only 100 gas to
149+
# coinbase will fail.
150+
0: 0,
151+
}
152+
)
153+
154+
yield StateTest(env=env, pre=pre, post=post, txs=[tx])
155+
156+
157+
@test_from(fork="merged")
158+
def test_warm_coinbase_gas_usage(fork):
159+
"""
160+
Test gas usage of different opcodes assuming warm coinbase.
161+
"""
162+
env = Environment(
163+
coinbase="0x2adc25665018aa1fe0e6bc666dac8fc2697ff9ba",
164+
difficulty=0x20000,
165+
gas_limit=10000000000,
166+
number=1,
167+
timestamp=1000,
168+
)
169+
170+
# List of opcodes that are affected by
171+
gas_measured_opcodes: Dict[str, CodeGasMeasure] = {
172+
"EXTCODESIZE": CodeGasMeasure(
173+
code=bytes(
174+
[
175+
0x41, # addr: COINBASE
176+
0x3B, # EXTCODESIZE
177+
]
178+
),
179+
overhead_cost=2,
180+
extra_stack_items=1,
181+
),
182+
"EXTCODECOPY": CodeGasMeasure(
183+
code=bytes(
184+
[
185+
0x60, # length
186+
0x00,
187+
0x60, # offset
188+
0x00,
189+
0x60, # offset
190+
0x00,
191+
0x41, # addr: COINBASE
192+
0x3C, # EXTCODECOPY
193+
]
194+
),
195+
overhead_cost=2 + 3 + 3 + 3,
196+
),
197+
"EXTCODEHASH": CodeGasMeasure(
198+
code=bytes(
199+
[
200+
0x41, # addr: COINBASE
201+
0x3F, # EXTCODEHASH
202+
]
203+
),
204+
overhead_cost=2,
205+
extra_stack_items=1,
206+
),
207+
"BALANCE": CodeGasMeasure(
208+
code=bytes(
209+
[
210+
0x41, # addr: COINBASE
211+
0x31, # BALANCE
212+
]
213+
),
214+
overhead_cost=2,
215+
extra_stack_items=1,
216+
),
217+
"CALL": CodeGasMeasure(
218+
code=bytes(
219+
[
220+
0x60, # returnLength
221+
0x00,
222+
0x60, # returnOffset
223+
0x00,
224+
0x60, # argsLength
225+
0x00,
226+
0x60, # argsOffset
227+
0x00,
228+
0x60, # value
229+
0x00,
230+
0x41, # addr: COINBASE
231+
0x60, # gas
232+
0xFF,
233+
0xF1, # CALL
234+
]
235+
),
236+
overhead_cost=3 + 2 + 3 + 3 + 3 + 3 + 3,
237+
extra_stack_items=1,
238+
),
239+
"CALLCODE": CodeGasMeasure(
240+
code=bytes(
241+
[
242+
0x60, # returnLength
243+
0x00,
244+
0x60, # returnOffset
245+
0x00,
246+
0x60, # argsLength
247+
0x00,
248+
0x60, # argsOffset
249+
0x00,
250+
0x60, # value
251+
0x00,
252+
0x41, # addr: COINBASE
253+
0x60, # gas
254+
0xFF,
255+
0xF2, # CALLCODE
256+
]
257+
),
258+
overhead_cost=3 + 2 + 3 + 3 + 3 + 3 + 3,
259+
extra_stack_items=1,
260+
),
261+
"DELEGATECALL": CodeGasMeasure(
262+
code=bytes(
263+
[
264+
0x60, # returnLength
265+
0x00,
266+
0x60, # returnOffset
267+
0x00,
268+
0x60, # argsLength
269+
0x00,
270+
0x60, # argsOffset
271+
0x00,
272+
0x41, # addr: COINBASE
273+
0x60, # gas
274+
0xFF,
275+
0xF4, # DELEGATECALL
276+
]
277+
),
278+
overhead_cost=3 + 2 + 3 + 3 + 3 + 3,
279+
extra_stack_items=1,
280+
),
281+
"STATICCALL": CodeGasMeasure(
282+
code=bytes(
283+
[
284+
0x60, # returnLength
285+
0x00,
286+
0x60, # returnOffset
287+
0x00,
288+
0x60, # argsLength
289+
0x00,
290+
0x60, # argsOffset
291+
0x00,
292+
0x41, # addr: COINBASE
293+
0x60, # gas
294+
0xFF,
295+
0xFA, # STATICCALL
296+
]
297+
),
298+
overhead_cost=3 + 2 + 3 + 3 + 3 + 3,
299+
extra_stack_items=1,
300+
),
301+
}
302+
303+
for opcode in gas_measured_opcodes:
304+
measure_address = to_address(0x100)
305+
pre = {
306+
TestAddress: Account(balance=1000000000000000000000),
307+
measure_address: Account(
308+
code=gas_measured_opcodes[opcode],
309+
),
310+
}
311+
312+
if is_fork(fork, "shanghai"):
313+
expected_gas = 100 # Warm account access cost after EIP-3651
314+
else:
315+
expected_gas = 2600 # Cold account access cost before EIP-3651
316+
317+
post = {
318+
measure_address: Account(
319+
storage={
320+
0x00: expected_gas,
321+
}
322+
)
323+
}
324+
tx = Transaction(
325+
ty=0x0,
326+
chain_id=0x0,
327+
nonce=0,
328+
to=measure_address,
329+
gas_limit=100000000,
330+
gas_price=10,
331+
protected=False,
332+
)
333+
334+
yield StateTest(
335+
env=env,
336+
pre=pre,
337+
post=post,
338+
txs=[tx],
339+
name="warm_coinbase_opcode_" + opcode.lower(),
340+
)

0 commit comments

Comments
 (0)