Skip to content

Commit 613cffe

Browse files
committed
new(tests): Backfill tests for OOGing on constant gas
1 parent ecd3462 commit 613cffe

File tree

3 files changed

+181
-17
lines changed

3 files changed

+181
-17
lines changed

tests/frontier/opcodes/test_all_opcodes.py

Lines changed: 163 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -19,24 +19,20 @@
1919
)
2020
from ethereum_test_vm import Opcode, UndefinedOpcodes
2121
from ethereum_test_vm import Opcodes as Op
22+
from tests.unscheduled.eip7692_eof_v1.eip3540_eof_v1.opcodes import V1_EOF_ONLY_OPCODES
23+
from tests.unscheduled.eip7692_eof_v1.gas_test import gas_test
2224

2325
REFERENCE_SPEC_GIT_PATH = "N/A"
2426
REFERENCE_SPEC_VERSION = "N/A"
2527

2628

2729
def prepare_stack(opcode: Opcode) -> Bytecode:
2830
"""Prepare valid stack for opcode."""
29-
if opcode == Op.CREATE:
30-
return Op.MSTORE(0, 0x6001600155) + Op.PUSH1(5) + Op.PUSH1(27) + Op.PUSH1(5)
31-
if opcode == Op.CREATE2:
32-
return Op.MSTORE(0, 0x6001600155) + Op.PUSH1(1) + Op.PUSH1(5) + Op.PUSH1(27) + Op.PUSH1(5)
3331
if opcode == Op.JUMPI:
34-
return Op.PUSH1(1) + Op.PUSH1(5)
32+
return Op.PUSH1(1) + Op.PUSH1(3) + Op.PC + Op.ADD
3533
if opcode == Op.JUMP:
36-
return Op.PUSH1(3)
37-
if opcode == Op.RETURNDATACOPY:
38-
return Op.PUSH1(0) * 3
39-
return Op.PUSH1(0x01) * 32
34+
return Op.PUSH1(3) + Op.PC + Op.ADD
35+
return Op.PUSH1(0x00) * 32
4036

4137

4238
def prepare_suffix(opcode: Opcode) -> Bytecode:
@@ -122,3 +118,161 @@ def test_cover_revert(state_test: StateTestFiller, pre: Alloc) -> None:
122118
)
123119

124120
state_test(env=Environment(), pre=pre, post={}, tx=tx)
121+
122+
123+
opcode_to_gas = {
124+
Op.ADD: 3,
125+
Op.MUL: 5,
126+
Op.SUB: 3,
127+
Op.DIV: 5,
128+
Op.SDIV: 5,
129+
Op.MOD: 5,
130+
Op.SMOD: 5,
131+
Op.ADDMOD: 8,
132+
Op.MULMOD: 8,
133+
Op.EXP: 10,
134+
Op.SIGNEXTEND: 5,
135+
Op.LT: 3,
136+
Op.GT: 3,
137+
Op.SLT: 3,
138+
Op.SGT: 3,
139+
Op.EQ: 3,
140+
Op.ISZERO: 3,
141+
Op.AND: 3,
142+
Op.OR: 3,
143+
Op.XOR: 3,
144+
Op.NOT: 3,
145+
Op.BYTE: 3,
146+
Op.SHL: 3,
147+
Op.SHR: 3,
148+
Op.SAR: 3,
149+
Op.CLZ: 5,
150+
Op.SHA3: 30,
151+
Op.ADDRESS: 2,
152+
Op.BALANCE: 100,
153+
Op.ORIGIN: 2,
154+
Op.CALLER: 2,
155+
Op.CALLVALUE: 2,
156+
Op.CALLDATALOAD: 3,
157+
Op.CALLDATASIZE: 2,
158+
Op.CALLDATACOPY: 3,
159+
Op.CODESIZE: 2,
160+
Op.CODECOPY: 3,
161+
Op.GASPRICE: 2,
162+
Op.EXTCODESIZE: 100,
163+
Op.EXTCODECOPY: 100,
164+
Op.RETURNDATASIZE: 2,
165+
Op.RETURNDATACOPY: 3,
166+
Op.EXTCODEHASH: 100,
167+
Op.BLOCKHASH: 20,
168+
Op.COINBASE: 2,
169+
Op.TIMESTAMP: 2,
170+
Op.NUMBER: 2,
171+
Op.PREVRANDAO: 2,
172+
Op.GASLIMIT: 2,
173+
Op.CHAINID: 2,
174+
Op.SELFBALANCE: 5,
175+
Op.BASEFEE: 2,
176+
Op.BLOBHASH: 3,
177+
Op.BLOBBASEFEE: 2,
178+
Op.POP: 2,
179+
Op.MLOAD: 3,
180+
Op.MSTORE: 3,
181+
Op.MSTORE8: 3,
182+
Op.SLOAD: 100,
183+
Op.JUMP: 8,
184+
Op.JUMPI: 10,
185+
Op.PC: 2,
186+
Op.MSIZE: 2,
187+
Op.GAS: 2,
188+
Op.JUMPDEST: 1,
189+
Op.TLOAD: 100,
190+
Op.TSTORE: 100,
191+
Op.MCOPY: 3,
192+
Op.PUSH0: 2,
193+
Op.LOG0: 375,
194+
Op.LOG1: 2 * 375,
195+
Op.LOG2: 3 * 375,
196+
Op.LOG3: 4 * 375,
197+
Op.LOG4: 5 * 375,
198+
Op.CREATE: 32000,
199+
Op.CALL: 100,
200+
Op.CALLCODE: 100,
201+
Op.DELEGATECALL: 100,
202+
Op.CREATE2: 32000,
203+
Op.STATICCALL: 100,
204+
Op.SELFDESTRUCT: 5000,
205+
}
206+
207+
# PUSHx, SWAPx, DUPx have uniform gas costs
208+
for opcode in set(Op):
209+
if 0x60 <= opcode.int() <= 0x9F:
210+
opcode_to_gas[opcode] = 3
211+
212+
constant_gas_opcodes = (
213+
set(Op)
214+
-
215+
# zero constant gas opcodes - untestable
216+
{Op.STOP, Op.RETURN, Op.REVERT, Op.INVALID}
217+
-
218+
# TODO: EOF opcodes. Remove once EOF is removed
219+
set(V1_EOF_ONLY_OPCODES)
220+
-
221+
# SSTORE - untestable due to 2300 gas stipend rule
222+
{Op.SSTORE}
223+
)
224+
225+
226+
# NOTE: Gas costs varying across forks not being supported yet would make this
227+
# test very complex.
228+
@pytest.mark.valid_at("Osaka")
229+
@pytest.mark.parametrize("opcode", sorted(constant_gas_opcodes))
230+
def test_constant_gas(
231+
state_test: StateTestFiller, pre: Alloc, opcode: Op, fork: Fork, env: Environment
232+
) -> None:
233+
"""Test that constant gas opcodes work as expected."""
234+
warm_gas = opcode_to_gas[opcode]
235+
cold_gas = warm_gas + (
236+
2500
237+
if opcode
238+
in [
239+
Op.BALANCE,
240+
Op.EXTCODESIZE,
241+
Op.EXTCODECOPY,
242+
Op.EXTCODEHASH,
243+
Op.CALL,
244+
Op.CALLCODE,
245+
Op.DELEGATECALL,
246+
Op.STATICCALL,
247+
]
248+
else 2600
249+
if opcode == Op.SELFDESTRUCT
250+
else 2000
251+
if opcode == Op.SLOAD
252+
else 0
253+
)
254+
255+
if fork.transaction_gas_limit_cap():
256+
env.gas_limit = fork.transaction_gas_limit_cap()
257+
258+
# Using `TLOAD` / `TSTORE` to work around warm/cold gas differences. We
259+
# need a counter to pick a distinct salt on each `CREATE2` and avoid
260+
# running into address conflicts.
261+
code_increment_counter = Op.TLOAD(1234) + Op.DUP1 + Op.TSTORE(1234, Op.PUSH1(1) + Op.ADD)
262+
setup_code = (
263+
Op.MLOAD(0)
264+
+ Op.POP
265+
+ prepare_stack(opcode)
266+
+ (code_increment_counter if opcode == Op.CREATE2 else Bytecode())
267+
)
268+
gas_test(
269+
state_test,
270+
env,
271+
pre,
272+
setup_code=setup_code,
273+
subject_code=opcode,
274+
tear_down_code=prepare_suffix(opcode),
275+
cold_gas=cold_gas,
276+
warm_gas=warm_gas,
277+
eof=False,
278+
)

tests/unscheduled/eip7692_eof_v1/eip3540_eof_v1/opcodes.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,7 @@
212212
Op.EXTCALL,
213213
Op.EXTDELEGATECALL,
214214
Op.EXTSTATICCALL,
215+
Op.RETURNDATALOAD,
215216
# EIP-7480 EOF Data Section Access
216217
Op.DATALOAD,
217218
Op.DATALOADN,
@@ -220,6 +221,8 @@
220221
# EIP-7620 EOF Create and Return Contract operation
221222
Op.EOFCREATE,
222223
Op.RETURNCODE,
224+
# EIP-7873 TXCREATE and InitcodeTransaction
225+
Op.TXCREATE,
223226
]
224227
"""
225228
List of valid EOF V1 opcodes that are disabled in legacy bytecode.

tests/unscheduled/eip7692_eof_v1/gas_test.py

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ def gas_test(
3939
out_of_gas_testing: bool = True,
4040
*,
4141
prelude_code: Bytecode | None = None,
42+
eof: bool = True,
4243
) -> None:
4344
"""
4445
Create State Test to check the gas cost of a sequence of EOF code.
@@ -54,16 +55,22 @@ def gas_test(
5455

5556
sender = pre.fund_eoa()
5657

57-
address_baseline = pre.deploy_contract(Container.Code(setup_code + tear_down_code))
58+
address_baseline = pre.deploy_contract(
59+
Container.Code(setup_code + tear_down_code) if eof else setup_code + tear_down_code
60+
)
5861
code_subject = setup_code + subject_code + tear_down_code
5962
address_subject = pre.deploy_contract(
60-
Container.Code(code_subject)
61-
if not subject_subcontainer
62-
else Container(
63-
sections=[
64-
Section.Code(code_subject),
65-
Section.Container(subject_subcontainer),
66-
]
63+
code_subject
64+
if not eof
65+
else (
66+
Container.Code(code_subject)
67+
if not subject_subcontainer
68+
else Container(
69+
sections=[
70+
Section.Code(code_subject),
71+
Section.Container(subject_subcontainer),
72+
]
73+
)
6774
),
6875
balance=subject_balance,
6976
address=subject_address,

0 commit comments

Comments
 (0)