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