6
6
"""
7
7
8
8
import math
9
+ from enum import auto
9
10
10
11
import pytest
11
12
13
+ from ethereum_test_benchmark .benchmark_code_generator import ExtCallGenerator , JumpLoopGenerator
12
14
from ethereum_test_forks import Fork
15
+ from ethereum_test_specs import BlockchainTestFiller , StateTestFiller
16
+ from ethereum_test_specs .benchmark import BenchmarkTestFiller
13
17
from ethereum_test_tools import (
14
18
Account ,
15
19
Address ,
16
20
Alloc ,
17
21
Block ,
18
- BlockchainTestFiller ,
19
22
Bytecode ,
20
23
Environment ,
21
24
Hash ,
22
- StateTestFiller ,
23
25
Transaction ,
24
26
While ,
25
27
compute_create2_address ,
26
28
compute_create_address ,
27
29
)
28
30
from ethereum_test_vm import Opcodes as Op
29
31
30
- from .helpers import code_loop_precompile_call
31
-
32
32
REFERENCE_SPEC_GIT_PATH = "TODO"
33
33
REFERENCE_SPEC_VERSION = "TODO"
34
34
47
47
],
48
48
)
49
49
def test_worst_address_state_cold (
50
- blockchain_test : BlockchainTestFiller ,
50
+ benchmark_test : BenchmarkTestFiller ,
51
51
pre : Alloc ,
52
52
fork : Fork ,
53
53
opcode : Op ,
@@ -107,11 +107,10 @@ def test_worst_address_state_cold(
107
107
)
108
108
blocks .append (Block (txs = [op_tx ]))
109
109
110
- blockchain_test (
110
+ benchmark_test (
111
111
pre = pre ,
112
112
post = post ,
113
113
blocks = blocks ,
114
- exclude_full_post_state_in_output = True ,
115
114
)
116
115
117
116
@@ -135,17 +134,12 @@ def test_worst_address_state_cold(
135
134
],
136
135
)
137
136
def test_worst_address_state_warm (
138
- state_test : StateTestFiller ,
137
+ benchmark_test : BenchmarkTestFiller ,
139
138
pre : Alloc ,
140
- fork : Fork ,
141
139
opcode : Op ,
142
140
absent_target : bool ,
143
- gas_benchmark_value : int ,
144
141
):
145
142
"""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
-
149
143
# Setup
150
144
target_addr = Address (100_000 )
151
145
post = {}
@@ -155,45 +149,29 @@ def test_worst_address_state_warm(
155
149
post [target_addr ] = Account (balance = 100 , code = code )
156
150
157
151
# 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 (
177
155
pre = pre ,
178
156
post = post ,
179
- tx = tx ,
157
+ code_generator = JumpLoopGenerator ( setup = setup , attack_block = attack_block ) ,
180
158
)
181
159
182
160
183
161
class StorageAction :
184
162
"""Enum for storage actions."""
185
163
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 ()
189
167
190
168
191
169
class TransactionResult :
192
170
"""Enum for the possible transaction outcomes."""
193
171
194
- SUCCESS = 1
195
- OUT_OF_GAS = 2
196
- REVERT = 3
172
+ SUCCESS = auto ()
173
+ OUT_OF_GAS = auto ()
174
+ REVERT = auto ()
197
175
198
176
199
177
@pytest .mark .parametrize (
@@ -244,7 +222,7 @@ class TransactionResult:
244
222
],
245
223
)
246
224
def test_worst_storage_access_cold (
247
- blockchain_test : BlockchainTestFiller ,
225
+ benchmark_test : BenchmarkTestFiller ,
248
226
pre : Alloc ,
249
227
fork : Fork ,
250
228
storage_action : StorageAction ,
@@ -256,7 +234,6 @@ def test_worst_storage_access_cold(
256
234
"""Test running a block with as many cold storage slot accesses as possible."""
257
235
gas_costs = fork .gas_costs ()
258
236
intrinsic_gas_cost_calc = fork .transaction_intrinsic_cost_calculator ()
259
- attack_gas_limit = gas_benchmark_value
260
237
261
238
loop_cost = gas_costs .G_COLD_SLOAD # All accesses are always cold
262
239
if storage_action == StorageAction .WRITE_NEW_VALUE :
@@ -305,7 +282,7 @@ def test_worst_storage_access_cold(
305
282
)
306
283
307
284
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
309
286
) // loop_cost
310
287
if tx_result == TransactionResult .OUT_OF_GAS :
311
288
# Add an extra slot to make it run out-of-gas
@@ -362,18 +339,17 @@ def test_worst_storage_access_cold(
362
339
363
340
op_tx = Transaction (
364
341
to = contract_address ,
365
- gas_limit = attack_gas_limit ,
342
+ gas_limit = gas_benchmark_value ,
366
343
sender = pre .fund_eoa (),
367
344
)
368
345
blocks .append (Block (txs = [op_tx ]))
369
346
370
- blockchain_test (
347
+ benchmark_test (
371
348
pre = pre ,
372
349
post = {},
373
350
blocks = blocks ,
374
- exclude_full_post_state_in_output = True ,
375
351
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
377
353
),
378
354
)
379
355
@@ -387,15 +363,13 @@ def test_worst_storage_access_cold(
387
363
],
388
364
)
389
365
def test_worst_storage_access_warm (
390
- blockchain_test : BlockchainTestFiller ,
366
+ benchmark_test : BenchmarkTestFiller ,
391
367
pre : Alloc ,
392
368
storage_action : StorageAction ,
393
- env : Environment ,
394
369
gas_benchmark_value : int ,
370
+ env : Environment ,
395
371
):
396
372
"""Test running a block with as many warm storage slot accesses as possible."""
397
- attack_gas_limit = gas_benchmark_value
398
-
399
373
blocks = []
400
374
401
375
# The target storage slot for the warm access is storage slot 0.
@@ -438,12 +412,12 @@ def test_worst_storage_access_warm(
438
412
439
413
op_tx = Transaction (
440
414
to = contract_address ,
441
- gas_limit = attack_gas_limit ,
415
+ gas_limit = gas_benchmark_value ,
442
416
sender = pre .fund_eoa (),
443
417
)
444
418
blocks .append (Block (txs = [op_tx ]))
445
419
446
- blockchain_test (
420
+ benchmark_test (
447
421
pre = pre ,
448
422
post = {},
449
423
blocks = blocks ,
@@ -479,35 +453,14 @@ def test_worst_blockhash(
479
453
480
454
481
455
def test_worst_selfbalance (
482
- state_test : StateTestFiller ,
456
+ benchmark_test : BenchmarkTestFiller ,
483
457
pre : Alloc ,
484
- fork : Fork ,
485
- gas_benchmark_value : int ,
486
458
):
487
459
"""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 (
508
461
pre = pre ,
509
462
post = {},
510
- tx = tx ,
463
+ code_generator = ExtCallGenerator ( setup = Bytecode (), attack_block = Op . SELFBALANCE ) ,
511
464
)
512
465
513
466
@@ -520,7 +473,7 @@ def test_worst_selfbalance(
520
473
],
521
474
)
522
475
def test_worst_extcodecopy_warm (
523
- state_test : StateTestFiller ,
476
+ benchmark_test : BenchmarkTestFiller ,
524
477
pre : Alloc ,
525
478
copied_size : int ,
526
479
gas_benchmark_value : int ,
@@ -544,7 +497,7 @@ def test_worst_extcodecopy_warm(
544
497
sender = pre .fund_eoa (),
545
498
)
546
499
547
- state_test (
500
+ benchmark_test (
548
501
pre = pre ,
549
502
post = {},
550
503
tx = tx ,
@@ -553,7 +506,7 @@ def test_worst_extcodecopy_warm(
553
506
554
507
@pytest .mark .parametrize ("value_bearing" , [True , False ])
555
508
def test_worst_selfdestruct_existing (
556
- blockchain_test : BlockchainTestFiller ,
509
+ benchmark_test : BenchmarkTestFiller ,
557
510
fork : Fork ,
558
511
pre : Alloc ,
559
512
value_bearing : bool ,
@@ -678,14 +631,13 @@ def test_worst_selfdestruct_existing(
678
631
post [deployed_contract_address ] = Account (nonce = 1 )
679
632
deployed_contract_addresses .append (deployed_contract_address )
680
633
681
- blockchain_test (
634
+ benchmark_test (
682
635
pre = pre ,
683
636
post = post ,
684
637
blocks = [
685
638
Block (txs = [contracts_deployment_tx ]),
686
639
Block (txs = [opcode_tx ], fee_recipient = fee_recipient ),
687
640
],
688
- exclude_full_post_state_in_output = True ,
689
641
expected_benchmark_gas_used = expected_benchmark_gas_used ,
690
642
)
691
643
@@ -781,7 +733,6 @@ def test_worst_selfdestruct_created(
781
733
782
734
post = {code_addr : Account (storage = {0 : 42 })} # Check for successful execution.
783
735
state_test (
784
- env = env ,
785
736
pre = pre ,
786
737
post = post ,
787
738
tx = code_tx ,
@@ -863,7 +814,6 @@ def test_worst_selfdestruct_initcode(
863
814
864
815
post = {code_addr : Account (storage = {0 : 42 })} # Check for successful execution.
865
816
state_test (
866
- env = env ,
867
817
pre = pre ,
868
818
post = post ,
869
819
tx = code_tx ,
0 commit comments