@@ -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,35 @@ 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 ) <= MAX_CONTRACT_SIZE
594
-
595
- attack_code_addr = pre .deploy_contract (code = attack_code )
583
+ code_addr = pre .deploy_contract (code = code )
596
584
opcode_tx = Transaction (
597
- to = attack_code_addr ,
585
+ to = code_addr ,
598
586
gas_limit = attack_gas_limit ,
599
587
gas_price = 10 ** 9 ,
600
588
sender = pre .fund_eoa (),
601
589
)
602
590
591
+ post = {
592
+ code_addr : Account (storage = {0 : 42 }) # Check for successful execution.
593
+ }
594
+ deployed_contract_addresses = []
595
+ for i in range (num_contracts ):
596
+ deployed_contract_address = compute_create2_address (
597
+ address = factory_address ,
598
+ salt = i ,
599
+ initcode = initcode ,
600
+ )
601
+ post [deployed_contract_address ] = Account (nonce = 1 )
602
+ deployed_contract_addresses .append (deployed_contract_address )
603
+
603
604
blockchain_test (
604
605
genesis_environment = env ,
605
606
pre = pre ,
@@ -610,3 +611,74 @@ def test_worst_selfdestruct_existing(
610
611
],
611
612
exclude_full_post_state_in_output = True ,
612
613
)
614
+
615
+
616
+ @pytest .mark .valid_from ("Cancun" )
617
+ @pytest .mark .parametrize ("value_bearing" , [True , False ])
618
+ def test_worst_selfdestruct_created (
619
+ state_test : StateTestFiller ,
620
+ pre : Alloc ,
621
+ value_bearing : bool ,
622
+ ):
623
+ """
624
+ Test running a block with as SELFDESTRUCT calls as possible for deployed contracts in
625
+ the same transaction.
626
+ """
627
+ env = Environment ()
628
+
629
+ # Create an account that will be used as the beneficiary of the SELFDESTRUCT calls, to avoid
630
+ # account creation costs. All SELFDESTRUCT calls will target the same account to avoid
631
+ # cold costs.
632
+ selfdestruct_beneficiary = pre .fund_eoa ()
633
+
634
+ # Template code that will be used to deploy a large number of contracts.
635
+ selfdestructable_contract_addr = pre .deploy_contract (
636
+ code = Op .SELFDESTRUCT (selfdestruct_beneficiary )
637
+ )
638
+ initcode = Op .EXTCODECOPY (
639
+ address = selfdestructable_contract_addr ,
640
+ dest_offset = 0 ,
641
+ offset = 0 ,
642
+ size = Op .EXTCODESIZE (selfdestructable_contract_addr ),
643
+ ) + Op .RETURN (0 , Op .EXTCODESIZE (selfdestructable_contract_addr ))
644
+ initcode_address = pre .deploy_contract (code = initcode )
645
+
646
+ code = (
647
+ Op .EXTCODECOPY (
648
+ address = initcode_address ,
649
+ dest_offset = 0 ,
650
+ offset = 0 ,
651
+ size = Op .EXTCODESIZE (initcode_address ),
652
+ )
653
+ + While (
654
+ body = Op .POP (
655
+ Op .CALL (
656
+ address = Op .CREATE (
657
+ value = 1 if value_bearing else 0 ,
658
+ offset = 0 ,
659
+ size = Op .EXTCODESIZE (initcode_address ),
660
+ )
661
+ )
662
+ ),
663
+ # Stop before we run out of gas for the whole tx execution.
664
+ # The value was discovered practically rounded to the next 1000 multiple.
665
+ condition = Op .GT (Op .GAS , 40_000 ),
666
+ )
667
+ + Op .SSTORE (0 , 42 ) # Done for successful tx execution assertion below.
668
+ )
669
+ code_addr = pre .deploy_contract (code = code )
670
+ code_tx = Transaction (
671
+ to = code_addr ,
672
+ gas_limit = env .gas_limit ,
673
+ gas_price = 10 ** 9 ,
674
+ sender = pre .fund_eoa (),
675
+ )
676
+
677
+ post = {code_addr : Account (storage = {0 : 42 })} # Check for successful execution.
678
+
679
+ state_test (
680
+ env = env ,
681
+ pre = pre ,
682
+ post = post ,
683
+ tx = code_tx ,
684
+ )
0 commit comments