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
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_tools .vm .opcode 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,16 @@ def test_worst_storage_access_cold(
362
339
363
340
op_tx = Transaction (
364
341
to = contract_address ,
365
- gas_limit = attack_gas_limit ,
366
342
sender = pre .fund_eoa (),
367
343
)
368
344
blocks .append (Block (txs = [op_tx ]))
369
345
370
- blockchain_test (
346
+ benchmark_test (
371
347
pre = pre ,
372
348
post = {},
373
349
blocks = blocks ,
374
- exclude_full_post_state_in_output = True ,
375
350
expected_benchmark_gas_used = (
376
- total_gas_used if tx_result != TransactionResult .OUT_OF_GAS else attack_gas_limit
351
+ total_gas_used if tx_result != TransactionResult .OUT_OF_GAS else gas_benchmark_value
377
352
),
378
353
)
379
354
@@ -387,15 +362,12 @@ def test_worst_storage_access_cold(
387
362
],
388
363
)
389
364
def test_worst_storage_access_warm (
390
- blockchain_test : BlockchainTestFiller ,
365
+ benchmark_test : BenchmarkTestFiller ,
391
366
pre : Alloc ,
392
367
storage_action : StorageAction ,
393
368
env : Environment ,
394
- gas_benchmark_value : int ,
395
369
):
396
370
"""Test running a block with as many warm storage slot accesses as possible."""
397
- attack_gas_limit = gas_benchmark_value
398
-
399
371
blocks = []
400
372
401
373
# The target storage slot for the warm access is storage slot 0.
@@ -438,12 +410,11 @@ def test_worst_storage_access_warm(
438
410
439
411
op_tx = Transaction (
440
412
to = contract_address ,
441
- gas_limit = attack_gas_limit ,
442
413
sender = pre .fund_eoa (),
443
414
)
444
415
blocks .append (Block (txs = [op_tx ]))
445
416
446
- blockchain_test (
417
+ benchmark_test (
447
418
pre = pre ,
448
419
post = {},
449
420
blocks = blocks ,
@@ -453,7 +424,6 @@ def test_worst_storage_access_warm(
453
424
def test_worst_blockhash (
454
425
blockchain_test : BlockchainTestFiller ,
455
426
pre : Alloc ,
456
- gas_benchmark_value : int ,
457
427
):
458
428
"""Test running a block with as many blockhash accessing oldest allowed block as possible."""
459
429
# Create 256 dummy blocks to fill the blockhash window.
@@ -466,7 +436,6 @@ def test_worst_blockhash(
466
436
execution_code_address = pre .deploy_contract (code = execution_code )
467
437
op_tx = Transaction (
468
438
to = execution_code_address ,
469
- gas_limit = gas_benchmark_value ,
470
439
sender = pre .fund_eoa (),
471
440
)
472
441
blocks .append (Block (txs = [op_tx ]))
@@ -479,35 +448,14 @@ def test_worst_blockhash(
479
448
480
449
481
450
def test_worst_selfbalance (
482
- state_test : StateTestFiller ,
451
+ benchmark_test : BenchmarkTestFiller ,
483
452
pre : Alloc ,
484
- fork : Fork ,
485
- gas_benchmark_value : int ,
486
453
):
487
454
"""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 (
455
+ benchmark_test (
508
456
pre = pre ,
509
457
post = {},
510
- tx = tx ,
458
+ code_generator = ExtCallGenerator ( setup = Bytecode (), attack_block = Op . SELFBALANCE ) ,
511
459
)
512
460
513
461
@@ -520,7 +468,7 @@ def test_worst_selfbalance(
520
468
],
521
469
)
522
470
def test_worst_extcodecopy_warm (
523
- state_test : StateTestFiller ,
471
+ benchmark_test : BenchmarkTestFiller ,
524
472
pre : Alloc ,
525
473
copied_size : int ,
526
474
gas_benchmark_value : int ,
@@ -544,7 +492,7 @@ def test_worst_extcodecopy_warm(
544
492
sender = pre .fund_eoa (),
545
493
)
546
494
547
- state_test (
495
+ benchmark_test (
548
496
pre = pre ,
549
497
post = {},
550
498
tx = tx ,
@@ -553,7 +501,7 @@ def test_worst_extcodecopy_warm(
553
501
554
502
@pytest .mark .parametrize ("value_bearing" , [True , False ])
555
503
def test_worst_selfdestruct_existing (
556
- blockchain_test : BlockchainTestFiller ,
504
+ benchmark_test : BenchmarkTestFiller ,
557
505
fork : Fork ,
558
506
pre : Alloc ,
559
507
value_bearing : bool ,
@@ -678,21 +626,20 @@ def test_worst_selfdestruct_existing(
678
626
post [deployed_contract_address ] = Account (nonce = 1 )
679
627
deployed_contract_addresses .append (deployed_contract_address )
680
628
681
- blockchain_test (
629
+ benchmark_test (
682
630
pre = pre ,
683
631
post = post ,
684
632
blocks = [
685
633
Block (txs = [contracts_deployment_tx ]),
686
634
Block (txs = [opcode_tx ], fee_recipient = fee_recipient ),
687
635
],
688
- exclude_full_post_state_in_output = True ,
689
636
expected_benchmark_gas_used = expected_benchmark_gas_used ,
690
637
)
691
638
692
639
693
640
@pytest .mark .parametrize ("value_bearing" , [True , False ])
694
641
def test_worst_selfdestruct_created (
695
- state_test : StateTestFiller ,
642
+ benchmark_test : BenchmarkTestFiller ,
696
643
pre : Alloc ,
697
644
value_bearing : bool ,
698
645
fork : Fork ,
@@ -775,13 +722,11 @@ def test_worst_selfdestruct_created(
775
722
)
776
723
code_tx = Transaction (
777
724
to = code_addr ,
778
- gas_limit = gas_benchmark_value ,
779
725
sender = pre .fund_eoa (),
780
726
)
781
727
782
728
post = {code_addr : Account (storage = {0 : 42 })} # Check for successful execution.
783
- state_test (
784
- env = env ,
729
+ benchmark_test (
785
730
pre = pre ,
786
731
post = post ,
787
732
tx = code_tx ,
@@ -791,7 +736,7 @@ def test_worst_selfdestruct_created(
791
736
792
737
@pytest .mark .parametrize ("value_bearing" , [True , False ])
793
738
def test_worst_selfdestruct_initcode (
794
- state_test : StateTestFiller ,
739
+ benchmark_test : BenchmarkTestFiller ,
795
740
pre : Alloc ,
796
741
value_bearing : bool ,
797
742
fork : Fork ,
@@ -862,7 +807,7 @@ def test_worst_selfdestruct_initcode(
862
807
)
863
808
864
809
post = {code_addr : Account (storage = {0 : 42 })} # Check for successful execution.
865
- state_test (
810
+ benchmark_test (
866
811
env = env ,
867
812
pre = pre ,
868
813
post = post ,
0 commit comments