@@ -496,7 +496,7 @@ def test_worst_selfdestruct_existing(
496
496
# Create an account that will be used as the beneficiary of the SELFDESTRUCT calls, to avoid
497
497
# account creation costs. All SELFDESTRUCT calls will target the same account to avoid
498
498
# cold costs.
499
- selfdestruct_beneficiary = pre .fund_eoa (amount = 100 )
499
+ selfdestruct_beneficiary = pre .fund_eoa ()
500
500
501
501
# Template code that will be used to deploy a large number of contracts.
502
502
selfdestructable_contract_addr = pre .deploy_contract (
@@ -563,19 +563,7 @@ def test_worst_selfdestruct_existing(
563
563
sender = pre .fund_eoa (),
564
564
)
565
565
566
- post = {}
567
- deployed_contract_addresses = []
568
- for i in range (num_contracts ):
569
- deployed_contract_address = compute_create2_address (
570
- address = factory_address ,
571
- salt = i ,
572
- initcode = initcode ,
573
- )
574
- post [deployed_contract_address ] = Account (nonce = 1 )
575
- deployed_contract_addresses .append (deployed_contract_address )
576
-
577
- attack_call = Op .POP (Op .CALL (address = Op .SHA3 (32 - 20 - 1 , 85 )))
578
- attack_code = (
566
+ code = (
579
567
# Setup memory for later CREATE2 address generation loop.
580
568
# 0xFF+[Address(20bytes)]+[seed(32bytes)]+[initcode keccak(32bytes)]
581
569
Op .MSTORE (0 , factory_address )
@@ -584,22 +572,37 @@ def test_worst_selfdestruct_existing(
584
572
+ Op .MSTORE (64 , initcode .keccak256 ())
585
573
# Main loop
586
574
+ While (
587
- body = attack_call + Op .MSTORE (32 , Op .ADD (Op .MLOAD (32 ), 1 )),
588
- # The condition is having enough gas for at least one more iteration.
589
- # 2+2600+5000 is the `attack_call` gas cost, and 2* is a rough safety margin.
590
- condition = Op .GT (Op .GAS , 2 * (2 + 2600 + 5000 )),
575
+ body = Op .POP (Op .CALL (address = Op .SHA3 (32 - 20 - 1 , 85 )))
576
+ + Op .MSTORE (32 , Op .ADD (Op .MLOAD (32 ), 1 )),
577
+ # Stop before we run out of gas for the whole tx execution.
578
+ # The value was discovered practically rounded to the next 1000 multiple.
579
+ condition = Op .GT (Op .GAS , 28_000 ),
591
580
)
581
+ + Op .SSTORE (0 , 42 ) # Done for successful tx execution assertion below.
592
582
)
593
- assert len (attack_code ) <= fork .max_code_size ()
583
+ assert len (code ) <= fork .max_code_size ()
594
584
595
- attack_code_addr = pre .deploy_contract (code = attack_code )
585
+ code_addr = pre .deploy_contract (code = code )
596
586
opcode_tx = Transaction (
597
- to = attack_code_addr ,
587
+ to = code_addr ,
598
588
gas_limit = attack_gas_limit ,
599
589
gas_price = 10 ** 9 ,
600
590
sender = pre .fund_eoa (),
601
591
)
602
592
593
+ post = {
594
+ code_addr : Account (storage = {0 : 42 }) # Check for successful execution.
595
+ }
596
+ deployed_contract_addresses = []
597
+ for i in range (num_contracts ):
598
+ deployed_contract_address = compute_create2_address (
599
+ address = factory_address ,
600
+ salt = i ,
601
+ initcode = initcode ,
602
+ )
603
+ post [deployed_contract_address ] = Account (nonce = 1 )
604
+ deployed_contract_addresses .append (deployed_contract_address )
605
+
603
606
blockchain_test (
604
607
genesis_environment = env ,
605
608
pre = pre ,
@@ -610,3 +613,74 @@ def test_worst_selfdestruct_existing(
610
613
],
611
614
exclude_full_post_state_in_output = True ,
612
615
)
616
+
617
+
618
+ @pytest .mark .valid_from ("Cancun" )
619
+ @pytest .mark .parametrize ("value_bearing" , [True , False ])
620
+ def test_worst_selfdestruct_created (
621
+ state_test : StateTestFiller ,
622
+ pre : Alloc ,
623
+ value_bearing : bool ,
624
+ ):
625
+ """
626
+ Test running a block with as SELFDESTRUCT calls as possible for deployed contracts in
627
+ the same transaction.
628
+ """
629
+ env = Environment ()
630
+
631
+ # Create an account that will be used as the beneficiary of the SELFDESTRUCT calls, to avoid
632
+ # account creation costs. All SELFDESTRUCT calls will target the same account to avoid
633
+ # cold costs.
634
+ selfdestruct_beneficiary = pre .fund_eoa ()
635
+
636
+ # Template code that will be used to deploy a large number of contracts.
637
+ selfdestructable_contract_addr = pre .deploy_contract (
638
+ code = Op .SELFDESTRUCT (selfdestruct_beneficiary )
639
+ )
640
+ initcode = Op .EXTCODECOPY (
641
+ address = selfdestructable_contract_addr ,
642
+ dest_offset = 0 ,
643
+ offset = 0 ,
644
+ size = Op .EXTCODESIZE (selfdestructable_contract_addr ),
645
+ ) + Op .RETURN (0 , Op .EXTCODESIZE (selfdestructable_contract_addr ))
646
+ initcode_address = pre .deploy_contract (code = initcode )
647
+
648
+ code = (
649
+ Op .EXTCODECOPY (
650
+ address = initcode_address ,
651
+ dest_offset = 0 ,
652
+ offset = 0 ,
653
+ size = Op .EXTCODESIZE (initcode_address ),
654
+ )
655
+ + While (
656
+ body = Op .POP (
657
+ Op .CALL (
658
+ address = Op .CREATE (
659
+ value = 1 if value_bearing else 0 ,
660
+ offset = 0 ,
661
+ size = Op .EXTCODESIZE (initcode_address ),
662
+ )
663
+ )
664
+ ),
665
+ # Stop before we run out of gas for the whole tx execution.
666
+ # The value was discovered practically rounded to the next 1000 multiple.
667
+ condition = Op .GT (Op .GAS , 40_000 ),
668
+ )
669
+ + Op .SSTORE (0 , 42 ) # Done for successful tx execution assertion below.
670
+ )
671
+ code_addr = pre .deploy_contract (code = code )
672
+ code_tx = Transaction (
673
+ to = code_addr ,
674
+ gas_limit = env .gas_limit ,
675
+ gas_price = 10 ** 9 ,
676
+ sender = pre .fund_eoa (),
677
+ )
678
+
679
+ post = {code_addr : Account (storage = {0 : 42 })} # Check for successful execution.
680
+
681
+ state_test (
682
+ env = env ,
683
+ pre = pre ,
684
+ post = post ,
685
+ tx = code_tx ,
686
+ )
0 commit comments