3
3
"""
4
4
5
5
import math
6
+ from enum import auto
6
7
7
8
import pytest
8
9
10
+ from ethereum_test_benchmark .benchmark_code_generator import ExtCallGenerator , JumpLoopGenerator
9
11
from ethereum_test_forks import Fork
12
+ from ethereum_test_specs import BlockchainTestFiller , StateTestFiller
13
+ from ethereum_test_specs .benchmark import BenchmarkTestFiller
10
14
from ethereum_test_tools import (
11
15
Account ,
12
16
Address ,
13
17
Alloc ,
14
18
Block ,
15
- BlockchainTestFiller ,
16
19
Bytecode ,
17
20
Environment ,
18
21
Hash ,
19
- StateTestFiller ,
20
22
Transaction ,
21
23
While ,
22
24
compute_create2_address ,
23
25
compute_create_address ,
24
26
)
25
27
from ethereum_test_vm import Opcodes as Op
26
28
27
- from .helpers import code_loop_precompile_call
28
-
29
29
REFERENCE_SPEC_GIT_PATH = "TODO"
30
30
REFERENCE_SPEC_VERSION = "TODO"
31
31
44
44
],
45
45
)
46
46
def test_worst_address_state_cold (
47
- blockchain_test : BlockchainTestFiller ,
47
+ benchmark_test : BenchmarkTestFiller ,
48
48
pre : Alloc ,
49
49
fork : Fork ,
50
50
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,20 +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
- """
146
- Test running a block with as many stateful opcodes doing warm access for an
147
- account.
148
- """
149
- max_code_size = fork .max_code_size ()
150
- attack_gas_limit = gas_benchmark_value
151
-
142
+ """Test running a block with as many stateful opcodes doing warm access for an account."""
152
143
# Setup
153
144
target_addr = Address (100_000 )
154
145
post = {}
@@ -158,45 +149,29 @@ def test_worst_address_state_warm(
158
149
post [target_addr ] = Account (balance = 100 , code = code )
159
150
160
151
# Execution
161
- prep = Op .MSTORE (0 , target_addr )
162
- jumpdest = Op .JUMPDEST
163
- jump_back = Op .JUMP (len (prep ))
164
- iter_block = Op .POP (opcode (address = Op .MLOAD (0 )))
165
- max_iters_loop = (max_code_size - len (prep ) - len (jumpdest ) - len (jump_back )) // len (
166
- iter_block
167
- )
168
- op_code = prep + jumpdest + sum ([iter_block ] * max_iters_loop ) + jump_back
169
- if len (op_code ) > max_code_size :
170
- # Must never happen, but keep it as a sanity check.
171
- raise ValueError (f"Code size { len (op_code )} exceeds maximum code size { max_code_size } " )
172
- op_address = pre .deploy_contract (code = op_code )
173
- tx = Transaction (
174
- to = op_address ,
175
- gas_limit = attack_gas_limit ,
176
- sender = pre .fund_eoa (),
177
- )
178
-
179
- state_test (
152
+ setup = Op .MSTORE (0 , target_addr )
153
+ attack_block = Op .POP (opcode (address = Op .MLOAD (0 )))
154
+ benchmark_test (
180
155
pre = pre ,
181
156
post = post ,
182
- tx = tx ,
157
+ code_generator = JumpLoopGenerator ( setup = setup , attack_block = attack_block ) ,
183
158
)
184
159
185
160
186
161
class StorageAction :
187
162
"""Enum for storage actions."""
188
163
189
- READ = 1
190
- WRITE_SAME_VALUE = 2
191
- WRITE_NEW_VALUE = 3
164
+ READ = auto ()
165
+ WRITE_SAME_VALUE = auto ()
166
+ WRITE_NEW_VALUE = auto ()
192
167
193
168
194
169
class TransactionResult :
195
170
"""Enum for the possible transaction outcomes."""
196
171
197
- SUCCESS = 1
198
- OUT_OF_GAS = 2
199
- REVERT = 3
172
+ SUCCESS = auto ()
173
+ OUT_OF_GAS = auto ()
174
+ REVERT = auto ()
200
175
201
176
202
177
@pytest .mark .parametrize (
@@ -247,7 +222,7 @@ class TransactionResult:
247
222
],
248
223
)
249
224
def test_worst_storage_access_cold (
250
- blockchain_test : BlockchainTestFiller ,
225
+ benchmark_test : BenchmarkTestFiller ,
251
226
pre : Alloc ,
252
227
fork : Fork ,
253
228
storage_action : StorageAction ,
@@ -261,7 +236,6 @@ def test_worst_storage_access_cold(
261
236
"""
262
237
gas_costs = fork .gas_costs ()
263
238
intrinsic_gas_cost_calc = fork .transaction_intrinsic_cost_calculator ()
264
- attack_gas_limit = gas_benchmark_value
265
239
266
240
loop_cost = gas_costs .G_COLD_SLOAD # All accesses are always cold
267
241
if storage_action == StorageAction .WRITE_NEW_VALUE :
@@ -311,7 +285,7 @@ def test_worst_storage_access_cold(
311
285
)
312
286
313
287
num_target_slots = (
314
- attack_gas_limit - intrinsic_gas_cost_calc () - prefix_cost - suffix_cost
288
+ gas_benchmark_value - intrinsic_gas_cost_calc () - prefix_cost - suffix_cost
315
289
) // loop_cost
316
290
if tx_result == TransactionResult .OUT_OF_GAS :
317
291
# Add an extra slot to make it run out-of-gas
@@ -369,18 +343,17 @@ def test_worst_storage_access_cold(
369
343
370
344
op_tx = Transaction (
371
345
to = contract_address ,
372
- gas_limit = attack_gas_limit ,
346
+ gas_limit = gas_benchmark_value ,
373
347
sender = pre .fund_eoa (),
374
348
)
375
349
blocks .append (Block (txs = [op_tx ]))
376
350
377
- blockchain_test (
351
+ benchmark_test (
378
352
pre = pre ,
379
353
post = {},
380
354
blocks = blocks ,
381
- exclude_full_post_state_in_output = True ,
382
355
expected_benchmark_gas_used = (
383
- total_gas_used if tx_result != TransactionResult .OUT_OF_GAS else attack_gas_limit
356
+ total_gas_used if tx_result != TransactionResult .OUT_OF_GAS else gas_benchmark_value
384
357
),
385
358
)
386
359
@@ -394,17 +367,13 @@ def test_worst_storage_access_cold(
394
367
],
395
368
)
396
369
def test_worst_storage_access_warm (
397
- blockchain_test : BlockchainTestFiller ,
370
+ benchmark_test : BenchmarkTestFiller ,
398
371
pre : Alloc ,
399
372
storage_action : StorageAction ,
400
- env : Environment ,
401
373
gas_benchmark_value : int ,
374
+ env : Environment ,
402
375
):
403
- """
404
- Test running a block with as many warm storage slot accesses as possible.
405
- """
406
- attack_gas_limit = gas_benchmark_value
407
-
376
+ """Test running a block with as many warm storage slot accesses as possible."""
408
377
blocks = []
409
378
410
379
# The target storage slot for the warm access is storage slot 0.
@@ -447,12 +416,12 @@ def test_worst_storage_access_warm(
447
416
448
417
op_tx = Transaction (
449
418
to = contract_address ,
450
- gas_limit = attack_gas_limit ,
419
+ gas_limit = gas_benchmark_value ,
451
420
sender = pre .fund_eoa (),
452
421
)
453
422
blocks .append (Block (txs = [op_tx ]))
454
423
455
- blockchain_test (
424
+ benchmark_test (
456
425
pre = pre ,
457
426
post = {},
458
427
blocks = blocks ,
@@ -491,35 +460,14 @@ def test_worst_blockhash(
491
460
492
461
493
462
def test_worst_selfbalance (
494
- state_test : StateTestFiller ,
463
+ benchmark_test : BenchmarkTestFiller ,
495
464
pre : Alloc ,
496
- fork : Fork ,
497
- gas_benchmark_value : int ,
498
465
):
499
466
"""Test running a block with as many SELFBALANCE opcodes as possible."""
500
- max_stack_height = fork .max_stack_height ()
501
-
502
- code_sequence = Op .SELFBALANCE * max_stack_height
503
- target_address = pre .deploy_contract (code = code_sequence )
504
-
505
- calldata = Bytecode ()
506
- attack_block = Op .POP (Op .STATICCALL (Op .GAS , target_address , 0 , 0 , 0 , 0 ))
507
-
508
- code = code_loop_precompile_call (calldata , attack_block , fork )
509
- assert len (code ) <= fork .max_code_size ()
510
-
511
- code_address = pre .deploy_contract (code = code )
512
-
513
- tx = Transaction (
514
- to = code_address ,
515
- gas_limit = gas_benchmark_value ,
516
- sender = pre .fund_eoa (),
517
- )
518
-
519
- state_test (
467
+ benchmark_test (
520
468
pre = pre ,
521
469
post = {},
522
- tx = tx ,
470
+ code_generator = ExtCallGenerator ( setup = Bytecode (), attack_block = Op . SELFBALANCE ) ,
523
471
)
524
472
525
473
@@ -532,7 +480,7 @@ def test_worst_selfbalance(
532
480
],
533
481
)
534
482
def test_worst_extcodecopy_warm (
535
- state_test : StateTestFiller ,
483
+ benchmark_test : BenchmarkTestFiller ,
536
484
pre : Alloc ,
537
485
copied_size : int ,
538
486
gas_benchmark_value : int ,
@@ -556,7 +504,7 @@ def test_worst_extcodecopy_warm(
556
504
sender = pre .fund_eoa (),
557
505
)
558
506
559
- state_test (
507
+ benchmark_test (
560
508
pre = pre ,
561
509
post = {},
562
510
tx = tx ,
@@ -565,7 +513,7 @@ def test_worst_extcodecopy_warm(
565
513
566
514
@pytest .mark .parametrize ("value_bearing" , [True , False ])
567
515
def test_worst_selfdestruct_existing (
568
- blockchain_test : BlockchainTestFiller ,
516
+ benchmark_test : BenchmarkTestFiller ,
569
517
fork : Fork ,
570
518
pre : Alloc ,
571
519
value_bearing : bool ,
@@ -696,14 +644,13 @@ def test_worst_selfdestruct_existing(
696
644
post [deployed_contract_address ] = Account (nonce = 1 )
697
645
deployed_contract_addresses .append (deployed_contract_address )
698
646
699
- blockchain_test (
647
+ benchmark_test (
700
648
pre = pre ,
701
649
post = post ,
702
650
blocks = [
703
651
Block (txs = [contracts_deployment_tx ]),
704
652
Block (txs = [opcode_tx ], fee_recipient = fee_recipient ),
705
653
],
706
- exclude_full_post_state_in_output = True ,
707
654
expected_benchmark_gas_used = expected_benchmark_gas_used ,
708
655
)
709
656
@@ -800,7 +747,6 @@ def test_worst_selfdestruct_created(
800
747
post = {code_addr : Account (storage = {0 : 42 })} # Check for successful
801
748
# execution.
802
749
state_test (
803
- env = env ,
804
750
pre = pre ,
805
751
post = post ,
806
752
tx = code_tx ,
@@ -886,7 +832,6 @@ def test_worst_selfdestruct_initcode(
886
832
post = {code_addr : Account (storage = {0 : 42 })} # Check for successful
887
833
# execution.
888
834
state_test (
889
- env = env ,
890
835
pre = pre ,
891
836
post = post ,
892
837
tx = code_tx ,
0 commit comments