Skip to content

Commit 558a38c

Browse files
refactor(tests): update MSIZE and SELFBALANCE benchmark test (#1771)
* refactor: create helper function for the repeated code sequence * refactor: update memsize opcode * refactor: update selfbalance opcode
1 parent 66b363e commit 558a38c

File tree

3 files changed

+52
-32
lines changed

3 files changed

+52
-32
lines changed

tests/zkevm/helpers.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
"""Helper functions for the EVM benchmark worst-case tests."""
2+
3+
from ethereum_test_forks import Fork
4+
from ethereum_test_tools import Bytecode
5+
from ethereum_test_tools.vm.opcode import Opcodes as Op
6+
7+
8+
def code_loop_precompile_call(calldata: Bytecode, attack_block: Bytecode, fork: Fork):
9+
"""Create a code loop that calls a precompile with the given calldata."""
10+
max_code_size = fork.max_code_size()
11+
12+
# The attack contract is: CALLDATA_PREP + #JUMPDEST + [attack_block]* + JUMP(#)
13+
jumpdest = Op.JUMPDEST
14+
jump_back = Op.JUMP(len(calldata))
15+
max_iters_loop = (max_code_size - len(calldata) - len(jumpdest) - len(jump_back)) // len(
16+
attack_block
17+
)
18+
code = calldata + jumpdest + sum([attack_block] * max_iters_loop) + jump_back
19+
if len(code) > max_code_size:
20+
# Must never happen, but keep it as a sanity check.
21+
raise ValueError(f"Code size {len(code)} exceeds maximum code size {max_code_size}")
22+
23+
return code

tests/zkevm/test_worst_compute.py

Lines changed: 13 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@
3939
from tests.prague.eip2537_bls_12_381_precompiles import spec as bls12381_spec
4040
from tests.prague.eip2537_bls_12_381_precompiles.spec import BytesConcatenation
4141

42+
from .helpers import code_loop_precompile_call
43+
4244
REFERENCE_SPEC_GIT_PATH = "TODO"
4345
REFERENCE_SPEC_VERSION = "TODO"
4446

@@ -311,18 +313,20 @@ def test_worst_msize(
311313
The `mem_size` parameter indicates by how much the memory is expanded.
312314
"""
313315
env = Environment()
314-
max_code_size = fork.max_code_size()
316+
max_stack_height = fork.max_stack_height()
315317

316-
# We use CALLVALUE for the parameter since is 1 gas cheaper than PUSHX.
317-
code_prefix = Op.MLOAD(Op.CALLVALUE) + Op.JUMPDEST
318-
iter_loop = Op.POP(Op.MSIZE)
319-
code_suffix = Op.JUMP(len(code_prefix) - 1)
320-
code_iter_len = (max_code_size - len(code_prefix) - len(code_suffix)) // len(iter_loop)
321-
code = code_prefix + iter_loop * code_iter_len + code_suffix
322-
assert len(code) <= max_code_size
318+
code_sequence = Op.MLOAD(Op.CALLVALUE) + Op.POP + Op.MSIZE * max_stack_height
319+
target_address = pre.deploy_contract(code=code_sequence)
320+
321+
calldata = Bytecode()
322+
attack_block = Op.POP(Op.STATICCALL(Op.GAS, target_address, 0, 0, 0, 0))
323+
code = code_loop_precompile_call(calldata, attack_block, fork)
324+
assert len(code) <= fork.max_code_size()
325+
326+
code_address = pre.deploy_contract(code=code)
323327

324328
tx = Transaction(
325-
to=pre.deploy_contract(code=bytes(code)),
329+
to=code_address,
326330
gas_limit=env.gas_limit,
327331
sender=pre.fund_eoa(),
328332
value=mem_size,
@@ -823,24 +827,6 @@ def test_worst_precompile_fixed_cost(
823827
)
824828

825829

826-
def code_loop_precompile_call(calldata: Bytecode, attack_block: Bytecode, fork: Fork):
827-
"""Create a code loop that calls a precompile with the given calldata."""
828-
max_code_size = fork.max_code_size()
829-
830-
# The attack contract is: CALLDATA_PREP + #JUMPDEST + [attack_block]* + JUMP(#)
831-
jumpdest = Op.JUMPDEST
832-
jump_back = Op.JUMP(len(calldata))
833-
max_iters_loop = (max_code_size - len(calldata) - len(jumpdest) - len(jump_back)) // len(
834-
attack_block
835-
)
836-
code = calldata + jumpdest + sum([attack_block] * max_iters_loop) + jump_back
837-
if len(code) > max_code_size:
838-
# Must never happen, but keep it as a sanity check.
839-
raise ValueError(f"Code size {len(code)} exceeds maximum code size {max_code_size}")
840-
841-
return code
842-
843-
844830
@pytest.mark.zkevm
845831
@pytest.mark.valid_from("Cancun")
846832
@pytest.mark.slow

tests/zkevm/test_worst_stateful_opcodes.py

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@
2727
)
2828
from ethereum_test_tools.vm.opcode import Opcodes as Op
2929

30+
from .helpers import code_loop_precompile_call
31+
3032
REFERENCE_SPEC_GIT_PATH = "TODO"
3133
REFERENCE_SPEC_VERSION = "TODO"
3234

@@ -415,16 +417,25 @@ def test_worst_blockhash(
415417
def test_worst_selfbalance(
416418
state_test: StateTestFiller,
417419
pre: Alloc,
420+
fork: Fork,
418421
):
419422
"""Test running a block with as many SELFBALANCE opcodes as possible."""
420423
env = Environment()
424+
max_stack_height = fork.max_stack_height()
425+
426+
code_sequence = Op.SELFBALANCE * max_stack_height
427+
target_address = pre.deploy_contract(code=code_sequence)
428+
429+
calldata = Bytecode()
430+
attack_block = Op.POP(Op.STATICCALL(Op.GAS, target_address, 0, 0, 0, 0))
431+
432+
code = code_loop_precompile_call(calldata, attack_block, fork)
433+
assert len(code) <= fork.max_code_size()
434+
435+
code_address = pre.deploy_contract(code=code)
421436

422-
execution_code = While(
423-
body=Op.POP(Op.SELFBALANCE),
424-
)
425-
execution_code_address = pre.deploy_contract(code=execution_code)
426437
tx = Transaction(
427-
to=execution_code_address,
438+
to=code_address,
428439
gas_limit=env.gas_limit,
429440
sender=pre.fund_eoa(),
430441
)

0 commit comments

Comments
 (0)