@@ -1031,6 +1031,107 @@ def test_worst_unop(state_test: StateTestFiller, pre: Alloc, opcode: Op, fork: F
1031
1031
)
1032
1032
1033
1033
1034
+ @pytest .mark .valid_from ("Cancun" )
1035
+ # `key_mut` indicates the key isn't fixed.
1036
+ @pytest .mark .parametrize ("key_mut" , [True , False ])
1037
+ # `val_mut` indicates that at the end of each big-loop, the value of the target key changes.
1038
+ @pytest .mark .parametrize ("val_mut" , [True , False ])
1039
+ def test_worst_tload (
1040
+ state_test : StateTestFiller ,
1041
+ fork : Fork ,
1042
+ pre : Alloc ,
1043
+ key_mut : bool ,
1044
+ val_mut : bool ,
1045
+ ):
1046
+ """Test running a block with as many TLOAD calls as possible."""
1047
+ env = Environment ()
1048
+ max_code_size = fork .max_code_size ()
1049
+
1050
+ start_key = 41
1051
+ code_key_mut = Bytecode ()
1052
+ code_val_mut = Bytecode ()
1053
+ if key_mut and val_mut :
1054
+ code_prefix = Op .PUSH1 (start_key ) + Op .JUMPDEST
1055
+ loop_iter = Op .POP (Op .TLOAD (Op .DUP1 ))
1056
+ code_key_mut = Op .POP + Op .GAS
1057
+ code_val_mut = Op .TSTORE (Op .DUP2 , Op .GAS )
1058
+ if key_mut and not val_mut :
1059
+ code_prefix = Op .JUMPDEST
1060
+ loop_iter = Op .POP (Op .TLOAD (Op .GAS ))
1061
+ if not key_mut and val_mut :
1062
+ code_prefix = Op .JUMPDEST
1063
+ loop_iter = Op .POP (Op .TLOAD (Op .CALLVALUE ))
1064
+ code_val_mut = Op .TSTORE (Op .CALLVALUE , Op .GAS ) # CALLVALUE configured in the tx
1065
+ if not key_mut and not val_mut :
1066
+ code_prefix = Op .JUMPDEST
1067
+ loop_iter = Op .POP (Op .TLOAD (Op .CALLVALUE ))
1068
+
1069
+ code_suffix = code_key_mut + code_val_mut + Op .JUMP (len (code_prefix ) - 1 )
1070
+
1071
+ code_body_len = (max_code_size - len (code_prefix ) - len (code_suffix )) // len (loop_iter )
1072
+ code_body = loop_iter * code_body_len
1073
+ code = code_prefix + code_body + code_suffix
1074
+ assert len (code ) <= max_code_size
1075
+
1076
+ tx = Transaction (
1077
+ to = pre .deploy_contract (code ),
1078
+ gas_limit = env .gas_limit ,
1079
+ sender = pre .fund_eoa (),
1080
+ value = start_key if not key_mut and val_mut else 0 ,
1081
+ )
1082
+
1083
+ state_test (
1084
+ env = env ,
1085
+ pre = pre ,
1086
+ post = {},
1087
+ tx = tx ,
1088
+ )
1089
+
1090
+
1091
+ @pytest .mark .valid_from ("Cancun" )
1092
+ @pytest .mark .parametrize ("key_mut" , [True , False ])
1093
+ @pytest .mark .parametrize ("dense_val_mut" , [True , False ])
1094
+ def test_worst_tstore (
1095
+ state_test : StateTestFiller ,
1096
+ fork : Fork ,
1097
+ pre : Alloc ,
1098
+ key_mut : bool ,
1099
+ dense_val_mut : bool ,
1100
+ ):
1101
+ """Test running a block with as many TSTORE calls as possible."""
1102
+ env = Environment ()
1103
+ max_code_size = fork .max_code_size ()
1104
+
1105
+ init_key = 42
1106
+ code_prefix = Op .PUSH1 (init_key ) + Op .JUMPDEST
1107
+
1108
+ # If `key_mut` is True, we mutate the key on every iteration of the big loop.
1109
+ code_key_mut = Op .POP + Op .GAS if key_mut else Bytecode ()
1110
+ code_suffix = code_key_mut + Op .JUMP (len (code_prefix ) - 1 )
1111
+
1112
+ # If `dense_val_mut` is set, we use GAS as a cheap way of always storing a different value than
1113
+ # the previous one.
1114
+ loop_iter = Op .TSTORE (Op .DUP2 , Op .GAS if dense_val_mut else Op .DUP1 )
1115
+
1116
+ code_body_len = (max_code_size - len (code_prefix ) - len (code_suffix )) // len (loop_iter )
1117
+ code_body = loop_iter * code_body_len
1118
+ code = code_prefix + code_body + code_suffix
1119
+ assert len (code ) <= max_code_size
1120
+
1121
+ tx = Transaction (
1122
+ to = pre .deploy_contract (code ),
1123
+ gas_limit = env .gas_limit ,
1124
+ sender = pre .fund_eoa (),
1125
+ )
1126
+
1127
+ state_test (
1128
+ env = env ,
1129
+ pre = pre ,
1130
+ post = {},
1131
+ tx = tx ,
1132
+ )
1133
+
1134
+
1034
1135
@pytest .mark .valid_from ("Cancun" )
1035
1136
@pytest .mark .parametrize ("shift_right" , [Op .SHR , Op .SAR ])
1036
1137
def test_worst_shifts (
0 commit comments