@@ -907,6 +907,126 @@ def test_initcode_state_growth_persists_to_post_deploy(
907907 )
908908
909909
910+ def test_creation_tx_initcode_sload_warming (
911+ state_test : StateTestFiller ,
912+ pre : Alloc ,
913+ fork : Fork ,
914+ ) -> None :
915+ """
916+ SLOAD inside a top-level creation-tx initcode follows
917+ cold/warm rules on the new contract's pages.
918+ """
919+ overhead = Op .PUSH1 (0 ).gas_cost (fork )
920+ initcode = Initcode (
921+ deploy_code = Op .STOP ,
922+ initcode_prefix = (
923+ CodeGasMeasure (
924+ code = Op .SLOAD (0 ),
925+ overhead_cost = overhead ,
926+ extra_stack_items = 1 ,
927+ sstore_key = slot_gas_measured ,
928+ stop = False ,
929+ )
930+ + CodeGasMeasure (
931+ code = Op .SLOAD (1 ),
932+ overhead_cost = overhead ,
933+ extra_stack_items = 1 ,
934+ sstore_key = slot_gas_measured_2 ,
935+ stop = False ,
936+ )
937+ ),
938+ )
939+ sender = pre .fund_eoa ()
940+ new_contract_address = compute_create_address (
941+ address = sender , nonce = sender .nonce , opcode = Op .CREATE
942+ )
943+
944+ tx = Transaction (
945+ gas_limit = generous_gas_with_create (fork ),
946+ to = None ,
947+ data = bytes (initcode ),
948+ sender = sender ,
949+ )
950+
951+ state_test (
952+ pre = pre ,
953+ post = {
954+ new_contract_address : Account (
955+ storage = {
956+ slot_gas_measured : Op .SLOAD (page_load_warm = False ).gas_cost (
957+ fork
958+ ),
959+ slot_gas_measured_2 : Op .SLOAD (
960+ page_load_warm = True
961+ ).gas_cost (fork ),
962+ },
963+ ),
964+ },
965+ tx = tx ,
966+ )
967+
968+
969+ def test_creation_tx_initcode_sstore_warming (
970+ state_test : StateTestFiller ,
971+ pre : Alloc ,
972+ fork : Fork ,
973+ ) -> None :
974+ """
975+ SSTORE inside a top-level creation-tx initcode follows
976+ cold/warm + state-growth rules on the new contract's pages.
977+ """
978+ overhead = (Op .PUSH1 (0 ) + Op .PUSH1 (0 )).gas_cost (fork )
979+ initcode = Initcode (
980+ deploy_code = Op .STOP ,
981+ initcode_prefix = (
982+ CodeGasMeasure (
983+ code = Op .SSTORE (0 , 1 ),
984+ overhead_cost = overhead ,
985+ extra_stack_items = 0 ,
986+ sstore_key = slot_gas_measured ,
987+ stop = False ,
988+ )
989+ + CodeGasMeasure (
990+ code = Op .SSTORE (1 , 1 ),
991+ overhead_cost = overhead ,
992+ extra_stack_items = 0 ,
993+ sstore_key = slot_gas_measured_2 ,
994+ stop = False ,
995+ )
996+ ),
997+ )
998+ sender = pre .fund_eoa ()
999+ new_contract_address = compute_create_address (
1000+ address = sender , nonce = sender .nonce , opcode = Op .CREATE
1001+ )
1002+
1003+ page = TxPageState ()
1004+ expected_first_gas = simulate_sstore (page , 0 , 1 , fork )
1005+ expected_second_gas = simulate_sstore (page , 1 , 1 , fork )
1006+
1007+ tx = Transaction (
1008+ gas_limit = generous_gas_with_create (fork ),
1009+ to = None ,
1010+ data = bytes (initcode ),
1011+ sender = sender ,
1012+ )
1013+
1014+ state_test (
1015+ pre = pre ,
1016+ post = {
1017+ new_contract_address : Account (
1018+ storage = {
1019+ 0 : 1 ,
1020+ 1 : 1 ,
1021+ slot_gas_measured : expected_first_gas ,
1022+ slot_gas_measured_2 : expected_second_gas ,
1023+ },
1024+ ),
1025+ },
1026+ tx = tx ,
1027+ )
1028+
1029+
9101030@pytest .mark .parametrize (
9111031 "call_kind" ,
9121032 ["call" , "callcode" , "delegatecall_chain" , "call_chain" ],
@@ -972,6 +1092,117 @@ def test_cross_account_page_propagation(
9721092 )
9731093
9741094
1095+ @pytest .mark .parametrize (
1096+ "call_kind" ,
1097+ ["callcode" , "delegatecall" ],
1098+ )
1099+ def test_cross_account_caller_warm_propagates (
1100+ state_test : StateTestFiller ,
1101+ pre : Alloc ,
1102+ fork : Fork ,
1103+ call_kind : str ,
1104+ ) -> None :
1105+ """CALLCODE/DELEGATECALL preserve caller's storage-context pages."""
1106+ overhead = Op .PUSH1 (0 ).gas_cost (fork )
1107+ inner = pre .deploy_contract (
1108+ CodeGasMeasure (
1109+ code = Op .SLOAD (0 ),
1110+ overhead_cost = overhead ,
1111+ extra_stack_items = 1 ,
1112+ sstore_key = slot_gas_measured ,
1113+ )
1114+ )
1115+
1116+ sub_call = (
1117+ Op .CALLCODE (address = inner )
1118+ if call_kind == "callcode"
1119+ else Op .DELEGATECALL (address = inner )
1120+ )
1121+ outer = pre .deploy_contract (Op .SLOAD (0 ) + sub_call )
1122+
1123+ tx = Transaction (
1124+ gas_limit = generous_gas (fork ),
1125+ to = outer ,
1126+ sender = pre .fund_eoa (),
1127+ )
1128+
1129+ state_test (
1130+ pre = pre ,
1131+ post = {
1132+ outer : Account (
1133+ storage = {
1134+ slot_gas_measured : Op .SLOAD (page_load_warm = True ).gas_cost (
1135+ fork
1136+ ),
1137+ },
1138+ ),
1139+ },
1140+ tx = tx ,
1141+ )
1142+
1143+
1144+ def test_delegated_eoa_owns_pages (
1145+ state_test : StateTestFiller ,
1146+ pre : Alloc ,
1147+ fork : Fork ,
1148+ ) -> None :
1149+ """
1150+ Pages warmed inside delegated-EOA code are keyed by the EOA
1151+ address.
1152+ """
1153+ overhead = Op .PUSH1 (0 ).gas_cost (fork )
1154+ delegate_code = Conditional (
1155+ condition = Op .CALLDATASIZE ,
1156+ if_true = CodeGasMeasure (
1157+ code = Op .SLOAD (0 ),
1158+ overhead_cost = overhead ,
1159+ extra_stack_items = 1 ,
1160+ sstore_key = slot_gas_measured_2 ,
1161+ ),
1162+ if_false = CodeGasMeasure (
1163+ code = Op .SLOAD (0 ),
1164+ overhead_cost = overhead ,
1165+ extra_stack_items = 1 ,
1166+ sstore_key = slot_gas_measured ,
1167+ ),
1168+ )
1169+ delegate_target = pre .deploy_contract (delegate_code )
1170+ eoa1 = pre .fund_eoa (delegation = delegate_target )
1171+ eoa2 = pre .fund_eoa (delegation = delegate_target )
1172+
1173+ runner_code = (
1174+ Op .CALL (address = delegate_target )
1175+ + Op .CALL (address = eoa1 )
1176+ + Op .CALL (address = eoa2 )
1177+ + Op .CALL (address = eoa2 , args_size = 1 )
1178+ )
1179+ runner_address = pre .deploy_contract (runner_code )
1180+
1181+ tx = Transaction (
1182+ gas_limit = generous_gas (fork ),
1183+ to = runner_address ,
1184+ sender = pre .fund_eoa (),
1185+ )
1186+
1187+ cold = Op .SLOAD (page_load_warm = False ).gas_cost (fork )
1188+ warm = Op .SLOAD (page_load_warm = True ).gas_cost (fork )
1189+
1190+ state_test (
1191+ pre = pre ,
1192+ post = {
1193+ delegate_target : Account (storage = {slot_gas_measured : cold }),
1194+ eoa1 : Account (storage = {slot_gas_measured : cold }),
1195+ eoa2 : Account (
1196+ storage = {
1197+ slot_gas_measured : cold ,
1198+ slot_gas_measured_2 : warm ,
1199+ },
1200+ ),
1201+ },
1202+ tx = tx ,
1203+ )
1204+
1205+
9751206@pytest .mark .parametrize (
9761207 "revert_cause" ,
9771208 [
0 commit comments