@@ -103,3 +103,80 @@ def test_worst_keccak(
103
103
post = {},
104
104
blocks = [Block (txs = [tx ])],
105
105
)
106
+
107
+
108
+ @pytest .mark .zkevm
109
+ @pytest .mark .valid_from ("Cancun" )
110
+ @pytest .mark .parametrize (
111
+ "gas_limit" ,
112
+ [
113
+ 36_000_000 ,
114
+ 60_000_000 ,
115
+ 100_000_000 ,
116
+ 300_000_000 ,
117
+ ],
118
+ )
119
+ @pytest .mark .parametrize (
120
+ "base_mod_length, exp_length" ,
121
+ [
122
+ (32 , 32 ),
123
+ ],
124
+ )
125
+ def test_worst_modexp (
126
+ blockchain_test : BlockchainTestFiller ,
127
+ pre : Alloc ,
128
+ fork : Fork ,
129
+ gas_limit : int ,
130
+ base_mod_length : int ,
131
+ exp_length : int ,
132
+ ):
133
+ """Test running a block with as many MODEXP calls as possible."""
134
+ env = Environment (gas_limit = gas_limit )
135
+
136
+ base = 2 ** (8 * base_mod_length ) - 1
137
+ mod = 2 ** (8 * base_mod_length ) - 1
138
+ exp = 2 ** (8 * exp_length ) - 1
139
+
140
+ # EIP-7883 (TODO: generalize)
141
+ mul_complexity = math .ceil (base_mod_length / 8 ) ** 2
142
+ iter_complexity = exp .bit_length () - 1
143
+ gas_cost = math .floor ((mul_complexity * iter_complexity ) / 3 )
144
+
145
+ mem_prep = (
146
+ Op .MSTORE (0 * 32 , 32 )
147
+ + Op .MSTORE (1 * 32 , 32 )
148
+ + Op .MSTORE (2 * 32 , 32 )
149
+ + Op .MSTORE (3 * 32 , base )
150
+ + Op .MSTORE (4 * 32 , exp )
151
+ + Op .MSTORE (5 * 32 , mod )
152
+ )
153
+
154
+ attack_block = Op .STATICCALL (gas_cost , 0x5 , 0 , 32 * 6 , 0 , 0 ) + Op .POP
155
+
156
+ jumpdest = Op .JUMPDEST
157
+ jump_back = Op .JUMP (len (mem_prep ))
158
+ max_iters_loop = (MAX_CODE_SIZE - len (mem_prep ) - len (jumpdest ) - len (jump_back )) // len (
159
+ attack_block
160
+ )
161
+ code = mem_prep + jumpdest + sum ([attack_block ] * max_iters_loop ) + jump_back
162
+ if len (code ) > MAX_CODE_SIZE :
163
+ # Must never happen, but keep it as a sanity check.
164
+ raise ValueError (f"Code size { len (code )} exceeds maximum code size { MAX_CODE_SIZE } " )
165
+
166
+ code_address = pre .deploy_contract (code = bytes (code ))
167
+
168
+ tx = Transaction (
169
+ to = code_address ,
170
+ gas_limit = gas_limit ,
171
+ gas_price = 10 ,
172
+ sender = pre .fund_eoa (),
173
+ data = [],
174
+ value = 0 ,
175
+ )
176
+
177
+ blockchain_test (
178
+ env = env ,
179
+ pre = pre ,
180
+ post = {},
181
+ blocks = [Block (txs = [tx ])],
182
+ )
0 commit comments