Skip to content

Commit cc03678

Browse files
refactor(benchmark): update worst statefule scenario
1 parent 2219e67 commit cc03678

File tree

1 file changed

+33
-83
lines changed

1 file changed

+33
-83
lines changed

tests/benchmark/test_worst_stateful_opcodes.py

Lines changed: 33 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -6,29 +6,29 @@
66
"""
77

88
import math
9+
from enum import auto
910

1011
import pytest
1112

13+
from ethereum_test_benchmark.benchmark_code_generator import ExtCallGenerator, JumpLoopGenerator
1214
from ethereum_test_forks import Fork
15+
from ethereum_test_specs import BlockchainTestFiller, StateTestFiller
16+
from ethereum_test_specs.benchmark import BenchmarkTestFiller
1317
from ethereum_test_tools import (
1418
Account,
1519
Address,
1620
Alloc,
1721
Block,
18-
BlockchainTestFiller,
1922
Bytecode,
2023
Environment,
2124
Hash,
22-
StateTestFiller,
2325
Transaction,
2426
While,
2527
compute_create2_address,
2628
compute_create_address,
2729
)
2830
from ethereum_test_vm import Opcodes as Op
2931

30-
from .helpers import code_loop_precompile_call
31-
3232
REFERENCE_SPEC_GIT_PATH = "TODO"
3333
REFERENCE_SPEC_VERSION = "TODO"
3434

@@ -47,7 +47,7 @@
4747
],
4848
)
4949
def test_worst_address_state_cold(
50-
blockchain_test: BlockchainTestFiller,
50+
benchmark_test: BenchmarkTestFiller,
5151
pre: Alloc,
5252
fork: Fork,
5353
opcode: Op,
@@ -107,11 +107,10 @@ def test_worst_address_state_cold(
107107
)
108108
blocks.append(Block(txs=[op_tx]))
109109

110-
blockchain_test(
110+
benchmark_test(
111111
pre=pre,
112112
post=post,
113113
blocks=blocks,
114-
exclude_full_post_state_in_output=True,
115114
)
116115

117116

@@ -135,17 +134,12 @@ def test_worst_address_state_cold(
135134
],
136135
)
137136
def test_worst_address_state_warm(
138-
state_test: StateTestFiller,
137+
benchmark_test: BenchmarkTestFiller,
139138
pre: Alloc,
140-
fork: Fork,
141139
opcode: Op,
142140
absent_target: bool,
143-
gas_benchmark_value: int,
144141
):
145142
"""Test running a block with as many stateful opcodes doing warm access for an account."""
146-
max_code_size = fork.max_code_size()
147-
attack_gas_limit = gas_benchmark_value
148-
149143
# Setup
150144
target_addr = Address(100_000)
151145
post = {}
@@ -155,45 +149,29 @@ def test_worst_address_state_warm(
155149
post[target_addr] = Account(balance=100, code=code)
156150

157151
# Execution
158-
prep = Op.MSTORE(0, target_addr)
159-
jumpdest = Op.JUMPDEST
160-
jump_back = Op.JUMP(len(prep))
161-
iter_block = Op.POP(opcode(address=Op.MLOAD(0)))
162-
max_iters_loop = (max_code_size - len(prep) - len(jumpdest) - len(jump_back)) // len(
163-
iter_block
164-
)
165-
op_code = prep + jumpdest + sum([iter_block] * max_iters_loop) + jump_back
166-
if len(op_code) > max_code_size:
167-
# Must never happen, but keep it as a sanity check.
168-
raise ValueError(f"Code size {len(op_code)} exceeds maximum code size {max_code_size}")
169-
op_address = pre.deploy_contract(code=op_code)
170-
tx = Transaction(
171-
to=op_address,
172-
gas_limit=attack_gas_limit,
173-
sender=pre.fund_eoa(),
174-
)
175-
176-
state_test(
152+
setup = Op.MSTORE(0, target_addr)
153+
attack_block = Op.POP(opcode(address=Op.MLOAD(0)))
154+
benchmark_test(
177155
pre=pre,
178156
post=post,
179-
tx=tx,
157+
code_generator=JumpLoopGenerator(setup=setup, attack_block=attack_block),
180158
)
181159

182160

183161
class StorageAction:
184162
"""Enum for storage actions."""
185163

186-
READ = 1
187-
WRITE_SAME_VALUE = 2
188-
WRITE_NEW_VALUE = 3
164+
READ = auto()
165+
WRITE_SAME_VALUE = auto()
166+
WRITE_NEW_VALUE = auto()
189167

190168

191169
class TransactionResult:
192170
"""Enum for the possible transaction outcomes."""
193171

194-
SUCCESS = 1
195-
OUT_OF_GAS = 2
196-
REVERT = 3
172+
SUCCESS = auto()
173+
OUT_OF_GAS = auto()
174+
REVERT = auto()
197175

198176

199177
@pytest.mark.parametrize(
@@ -244,7 +222,7 @@ class TransactionResult:
244222
],
245223
)
246224
def test_worst_storage_access_cold(
247-
blockchain_test: BlockchainTestFiller,
225+
benchmark_test: BenchmarkTestFiller,
248226
pre: Alloc,
249227
fork: Fork,
250228
storage_action: StorageAction,
@@ -256,7 +234,6 @@ def test_worst_storage_access_cold(
256234
"""Test running a block with as many cold storage slot accesses as possible."""
257235
gas_costs = fork.gas_costs()
258236
intrinsic_gas_cost_calc = fork.transaction_intrinsic_cost_calculator()
259-
attack_gas_limit = gas_benchmark_value
260237

261238
loop_cost = gas_costs.G_COLD_SLOAD # All accesses are always cold
262239
if storage_action == StorageAction.WRITE_NEW_VALUE:
@@ -305,7 +282,7 @@ def test_worst_storage_access_cold(
305282
)
306283

307284
num_target_slots = (
308-
attack_gas_limit - intrinsic_gas_cost_calc() - prefix_cost - suffix_cost
285+
gas_benchmark_value - intrinsic_gas_cost_calc() - prefix_cost - suffix_cost
309286
) // loop_cost
310287
if tx_result == TransactionResult.OUT_OF_GAS:
311288
# Add an extra slot to make it run out-of-gas
@@ -362,18 +339,17 @@ def test_worst_storage_access_cold(
362339

363340
op_tx = Transaction(
364341
to=contract_address,
365-
gas_limit=attack_gas_limit,
342+
gas_limit=gas_benchmark_value,
366343
sender=pre.fund_eoa(),
367344
)
368345
blocks.append(Block(txs=[op_tx]))
369346

370-
blockchain_test(
347+
benchmark_test(
371348
pre=pre,
372349
post={},
373350
blocks=blocks,
374-
exclude_full_post_state_in_output=True,
375351
expected_benchmark_gas_used=(
376-
total_gas_used if tx_result != TransactionResult.OUT_OF_GAS else attack_gas_limit
352+
total_gas_used if tx_result != TransactionResult.OUT_OF_GAS else gas_benchmark_value
377353
),
378354
)
379355

@@ -387,15 +363,13 @@ def test_worst_storage_access_cold(
387363
],
388364
)
389365
def test_worst_storage_access_warm(
390-
blockchain_test: BlockchainTestFiller,
366+
benchmark_test: BenchmarkTestFiller,
391367
pre: Alloc,
392368
storage_action: StorageAction,
393-
env: Environment,
394369
gas_benchmark_value: int,
370+
env: Environment,
395371
):
396372
"""Test running a block with as many warm storage slot accesses as possible."""
397-
attack_gas_limit = gas_benchmark_value
398-
399373
blocks = []
400374

401375
# The target storage slot for the warm access is storage slot 0.
@@ -438,12 +412,12 @@ def test_worst_storage_access_warm(
438412

439413
op_tx = Transaction(
440414
to=contract_address,
441-
gas_limit=attack_gas_limit,
415+
gas_limit=gas_benchmark_value,
442416
sender=pre.fund_eoa(),
443417
)
444418
blocks.append(Block(txs=[op_tx]))
445419

446-
blockchain_test(
420+
benchmark_test(
447421
pre=pre,
448422
post={},
449423
blocks=blocks,
@@ -479,35 +453,14 @@ def test_worst_blockhash(
479453

480454

481455
def test_worst_selfbalance(
482-
state_test: StateTestFiller,
456+
benchmark_test: BenchmarkTestFiller,
483457
pre: Alloc,
484-
fork: Fork,
485-
gas_benchmark_value: int,
486458
):
487459
"""Test running a block with as many SELFBALANCE opcodes as possible."""
488-
max_stack_height = fork.max_stack_height()
489-
490-
code_sequence = Op.SELFBALANCE * max_stack_height
491-
target_address = pre.deploy_contract(code=code_sequence)
492-
493-
calldata = Bytecode()
494-
attack_block = Op.POP(Op.STATICCALL(Op.GAS, target_address, 0, 0, 0, 0))
495-
496-
code = code_loop_precompile_call(calldata, attack_block, fork)
497-
assert len(code) <= fork.max_code_size()
498-
499-
code_address = pre.deploy_contract(code=code)
500-
501-
tx = Transaction(
502-
to=code_address,
503-
gas_limit=gas_benchmark_value,
504-
sender=pre.fund_eoa(),
505-
)
506-
507-
state_test(
460+
benchmark_test(
508461
pre=pre,
509462
post={},
510-
tx=tx,
463+
code_generator=ExtCallGenerator(setup=Bytecode(), attack_block=Op.SELFBALANCE),
511464
)
512465

513466

@@ -520,7 +473,7 @@ def test_worst_selfbalance(
520473
],
521474
)
522475
def test_worst_extcodecopy_warm(
523-
state_test: StateTestFiller,
476+
benchmark_test: BenchmarkTestFiller,
524477
pre: Alloc,
525478
copied_size: int,
526479
gas_benchmark_value: int,
@@ -544,7 +497,7 @@ def test_worst_extcodecopy_warm(
544497
sender=pre.fund_eoa(),
545498
)
546499

547-
state_test(
500+
benchmark_test(
548501
pre=pre,
549502
post={},
550503
tx=tx,
@@ -553,7 +506,7 @@ def test_worst_extcodecopy_warm(
553506

554507
@pytest.mark.parametrize("value_bearing", [True, False])
555508
def test_worst_selfdestruct_existing(
556-
blockchain_test: BlockchainTestFiller,
509+
benchmark_test: BenchmarkTestFiller,
557510
fork: Fork,
558511
pre: Alloc,
559512
value_bearing: bool,
@@ -678,14 +631,13 @@ def test_worst_selfdestruct_existing(
678631
post[deployed_contract_address] = Account(nonce=1)
679632
deployed_contract_addresses.append(deployed_contract_address)
680633

681-
blockchain_test(
634+
benchmark_test(
682635
pre=pre,
683636
post=post,
684637
blocks=[
685638
Block(txs=[contracts_deployment_tx]),
686639
Block(txs=[opcode_tx], fee_recipient=fee_recipient),
687640
],
688-
exclude_full_post_state_in_output=True,
689641
expected_benchmark_gas_used=expected_benchmark_gas_used,
690642
)
691643

@@ -781,7 +733,6 @@ def test_worst_selfdestruct_created(
781733

782734
post = {code_addr: Account(storage={0: 42})} # Check for successful execution.
783735
state_test(
784-
env=env,
785736
pre=pre,
786737
post=post,
787738
tx=code_tx,
@@ -863,7 +814,6 @@ def test_worst_selfdestruct_initcode(
863814

864815
post = {code_addr: Account(storage={0: 42})} # Check for successful execution.
865816
state_test(
866-
env=env,
867817
pre=pre,
868818
post=post,
869819
tx=code_tx,

0 commit comments

Comments
 (0)