|
1 | 1 | """Common constants, classes & functions local to EIP-4844 tests."""
|
2 | 2 |
|
3 | 3 | from dataclasses import dataclass
|
4 |
| -from typing import List, Literal, Tuple, Union |
5 |
| - |
6 |
| -from ethereum_test_tools import ( |
7 |
| - Address, |
8 |
| - Hash, |
9 |
| - TestAddress, |
10 |
| - YulCompiler, |
11 |
| - add_kzg_version, |
12 |
| - compute_create2_address, |
13 |
| - compute_create_address, |
14 |
| -) |
15 |
| -from ethereum_test_tools.vm.opcode import Opcodes as Op |
| 4 | +from typing import List, Literal, Tuple |
16 | 5 |
|
17 | 6 | from .spec import Spec
|
18 | 7 |
|
@@ -51,283 +40,3 @@ def blobs_to_transaction_input(
|
51 | 40 | kzg_commitments.append(blob.kzg_commitment)
|
52 | 41 | kzg_proofs.append(blob.kzg_proof)
|
53 | 42 | return (blobs, kzg_commitments, kzg_proofs)
|
54 |
| - |
55 |
| - |
56 |
| -# Random fixed list of blob versioned hashes |
57 |
| -random_blob_hashes = add_kzg_version( |
58 |
| - [ |
59 |
| - "0x00b8c5b09810b5fc07355d3da42e2c3a3e200c1d9a678491b7e8e256fc50cc4f", |
60 |
| - "0x005b4c8cc4f86aa2d2cf9e9ce97fca704a11a6c20f6b1d6c00a6e15f6d60a6df", |
61 |
| - "0x00878f80eaf10be1a6f618e6f8c071b10a6c14d9b89a3bf2a3f3cf2db6c5681d", |
62 |
| - "0x004eb72b108d562c639faeb6f8c6f366a28b0381c7d30431117ec8c7bb89f834", |
63 |
| - "0x00a9b2a6c3f3f0675b768d49b5f5dc5b5d988f88d55766247ba9e40b125f16bb", |
64 |
| - "0x00a4d4cde4aa01e57fb2c880d1d9c778c33bdf85e48ef4c4d4b4de51abccf4ed", |
65 |
| - "0x0071c9b8a0c72d38f5e5b5d08e5cb5ce5e23fb1bc5d75f9c29f7b94df0bceeb7", |
66 |
| - "0x002c8b6a8b11410c7d98d790e1098f1ed6d93cb7a64711481aaab1848e13212f", |
67 |
| - "0x00d78c25f8a1d6aa04d0e2e2a71cf8dfaa4239fa0f301eb57c249d1e6bfe3c3d", |
68 |
| - "0x00c778eb1348a73b9c30c7b1d282a5f8b2c5b5a12d5c5e4a4a35f9c5f639b4a4", |
69 |
| - ], |
70 |
| - Spec.BLOB_COMMITMENT_VERSION_KZG, |
71 |
| -) |
72 |
| - |
73 |
| - |
74 |
| -class BlobhashContext: |
75 |
| - """ |
76 |
| - A utility class for mapping common EVM opcodes in different contexts |
77 |
| - to specific bytecode (with BLOBHASH), addresses and contracts. |
78 |
| - """ |
79 |
| - |
80 |
| - yul_compiler: Union[YulCompiler, None] = None |
81 |
| - addresses = { |
82 |
| - "blobhash_sstore": Address(0x100), |
83 |
| - "blobhash_return": Address(0x600), |
84 |
| - "call": Address(0x200), |
85 |
| - "delegatecall": Address(0x300), |
86 |
| - "callcode": Address(0x800), |
87 |
| - "staticcall": Address(0x700), |
88 |
| - "create": Address(0x400), |
89 |
| - "create2": Address(0x500), |
90 |
| - } |
91 |
| - |
92 |
| - @staticmethod |
93 |
| - def _get_blobhash_verbatim(): |
94 |
| - """Return BLOBHASH verbatim as a formatted string.""" |
95 |
| - return "verbatim_{}i_{}o".format( |
96 |
| - Op.BLOBHASH.popped_stack_items, |
97 |
| - Op.BLOBHASH.pushed_stack_items, |
98 |
| - ) |
99 |
| - |
100 |
| - @classmethod |
101 |
| - def address(cls, context_name): |
102 |
| - """Map opcode context to a specific address.""" |
103 |
| - address = cls.addresses.get(context_name) |
104 |
| - if address is None: |
105 |
| - raise ValueError(f"Invalid context: {context_name}") |
106 |
| - return address |
107 |
| - |
108 |
| - @classmethod |
109 |
| - def code(cls, context_name): |
110 |
| - """Map opcode context to bytecode that utilizes the BLOBHASH opcode.""" |
111 |
| - assert cls.yul_compiler is not None, "YulCompiler not set" |
112 |
| - |
113 |
| - blobhash_verbatim = cls._get_blobhash_verbatim() |
114 |
| - |
115 |
| - code = { |
116 |
| - "blobhash_sstore": cls.yul_compiler( |
117 |
| - f""" |
118 |
| - {{ |
119 |
| - let pos := calldataload(0) |
120 |
| - let end := calldataload(32) |
121 |
| - for {{}} lt(pos, end) {{ pos := add(pos, 1) }} |
122 |
| - {{ |
123 |
| - let blobhash := {blobhash_verbatim} |
124 |
| - (hex"{Op.BLOBHASH.hex()}", pos) |
125 |
| - sstore(pos, blobhash) |
126 |
| - }} |
127 |
| - let blobhash := {blobhash_verbatim} |
128 |
| - (hex"{Op.BLOBHASH.hex()}", end) |
129 |
| - sstore(end, blobhash) |
130 |
| - return(0, 0) |
131 |
| - }} |
132 |
| - """ # noqa: E272, E201, E202 |
133 |
| - ), |
134 |
| - "blobhash_return": cls.yul_compiler( |
135 |
| - f""" |
136 |
| - {{ |
137 |
| - let pos := calldataload(0) |
138 |
| - let blobhash := {blobhash_verbatim} |
139 |
| - (hex"{Op.BLOBHASH.hex()}", pos) |
140 |
| - mstore(0, blobhash) |
141 |
| - return(0, 32) |
142 |
| - }} |
143 |
| - """ # noqa: E272, E201, E202 |
144 |
| - ), |
145 |
| - "call": cls.yul_compiler( |
146 |
| - """ |
147 |
| - { |
148 |
| - calldatacopy(0, 0, calldatasize()) |
149 |
| - pop(call(gas(), 0x100, 0, 0, calldatasize(), 0, 0)) |
150 |
| - } |
151 |
| - """ # noqa: E272, E201, E202 |
152 |
| - ), |
153 |
| - "delegatecall": cls.yul_compiler( |
154 |
| - """ |
155 |
| - { |
156 |
| - calldatacopy(0, 0, calldatasize()) |
157 |
| - pop(delegatecall(gas(), 0x100, 0, calldatasize(), 0, 0)) |
158 |
| - } |
159 |
| - """ # noqa: E272, E201, E202 |
160 |
| - ), |
161 |
| - "callcode": cls.yul_compiler( |
162 |
| - f""" |
163 |
| - {{ |
164 |
| - let pos := calldataload(0) |
165 |
| - let end := calldataload(32) |
166 |
| - for {{ }} lt(pos, end) {{ pos := add(pos, 1) }} |
167 |
| - {{ |
168 |
| - mstore(0, pos) |
169 |
| - pop(callcode(gas(), |
170 |
| - {cls.address("blobhash_return")}, 0, 0, 32, 0, 32)) |
171 |
| - let blobhash := mload(0) |
172 |
| - sstore(pos, blobhash) |
173 |
| - }} |
174 |
| -
|
175 |
| - mstore(0, end) |
176 |
| - pop(callcode(gas(), |
177 |
| - {cls.address("blobhash_return")}, 0, 0, 32, 0, 32)) |
178 |
| - let blobhash := mload(0) |
179 |
| - sstore(end, blobhash) |
180 |
| - return(0, 0) |
181 |
| - }} |
182 |
| - """ # noqa: E272, E201, E202 |
183 |
| - ), |
184 |
| - "staticcall": cls.yul_compiler( |
185 |
| - f""" |
186 |
| - {{ |
187 |
| - let pos := calldataload(0) |
188 |
| - let end := calldataload(32) |
189 |
| - for {{ }} lt(pos, end) {{ pos := add(pos, 1) }} |
190 |
| - {{ |
191 |
| - mstore(0, pos) |
192 |
| - pop(staticcall(gas(), |
193 |
| - {cls.address("blobhash_return")}, 0, 32, 0, 32)) |
194 |
| - let blobhash := mload(0) |
195 |
| - sstore(pos, blobhash) |
196 |
| - }} |
197 |
| -
|
198 |
| - mstore(0, end) |
199 |
| - pop(staticcall(gas(), |
200 |
| - {cls.address("blobhash_return")}, 0, 32, 0, 32)) |
201 |
| - let blobhash := mload(0) |
202 |
| - sstore(end, blobhash) |
203 |
| - return(0, 0) |
204 |
| - }} |
205 |
| - """ # noqa: E272, E201, E202 |
206 |
| - ), |
207 |
| - "create": cls.yul_compiler( |
208 |
| - """ |
209 |
| - { |
210 |
| - calldatacopy(0, 0, calldatasize()) |
211 |
| - pop(create(0, 0, calldatasize())) |
212 |
| - } |
213 |
| - """ # noqa: E272, E201, E202 |
214 |
| - ), |
215 |
| - "create2": cls.yul_compiler( |
216 |
| - """ |
217 |
| - { |
218 |
| - calldatacopy(0, 0, calldatasize()) |
219 |
| - pop(create2(0, 0, calldatasize(), 0)) |
220 |
| - } |
221 |
| - """ # noqa: E272, E201, E202 |
222 |
| - ), |
223 |
| - "initcode": cls.yul_compiler( |
224 |
| - f""" |
225 |
| - {{ |
226 |
| - for {{ let pos := 0 }} lt(pos, 10) {{ pos := add(pos, 1) }} |
227 |
| - {{ |
228 |
| - let blobhash := {blobhash_verbatim} |
229 |
| - (hex"{Op.BLOBHASH.hex()}", pos) |
230 |
| - sstore(pos, blobhash) |
231 |
| - }} |
232 |
| - return(0, 0) |
233 |
| - }} |
234 |
| - """ # noqa: E272, E201, E202 |
235 |
| - ), |
236 |
| - } |
237 |
| - code = code.get(context_name) |
238 |
| - if code is None: |
239 |
| - raise ValueError(f"Invalid context: {context_name}") |
240 |
| - return code |
241 |
| - |
242 |
| - @classmethod |
243 |
| - def created_contract(cls, context_name): |
244 |
| - """Map contract creation to a specific context to a specific address.""" |
245 |
| - contract = { |
246 |
| - "tx_created_contract": compute_create_address(address=TestAddress, nonce=0), |
247 |
| - "create": compute_create_address( |
248 |
| - address=cls.address("create"), |
249 |
| - nonce=0, |
250 |
| - ), |
251 |
| - "create2": compute_create2_address( |
252 |
| - address=cls.address("create2"), |
253 |
| - salt=0, |
254 |
| - initcode=cls.code("initcode"), |
255 |
| - ), |
256 |
| - } |
257 |
| - contract = contract.get(context_name) |
258 |
| - if contract is None: |
259 |
| - raise ValueError(f"Invalid contract: {context_name}") |
260 |
| - return contract |
261 |
| - |
262 |
| - |
263 |
| -class BlobhashScenario: |
264 |
| - """A utility class for generating blobhash calls.""" |
265 |
| - |
266 |
| - @staticmethod |
267 |
| - def create_blob_hashes_list(length: int, max_blobs_per_block: int) -> List[List[Hash]]: |
268 |
| - """ |
269 |
| - Create list of MAX_BLOBS_PER_BLOCK blob hashes |
270 |
| - using `random_blob_hashes`. |
271 |
| -
|
272 |
| - Cycle over random_blob_hashes to get a large list of |
273 |
| - length: MAX_BLOBS_PER_BLOCK * length |
274 |
| - -> [0x01, 0x02, 0x03, 0x04, ..., 0x0A, 0x0B, 0x0C, 0x0D] |
275 |
| -
|
276 |
| - Then split list into smaller chunks of max_blobs_per_block |
277 |
| - -> [[0x01, 0x02, 0x03, 0x04], ..., [0x0a, 0x0b, 0x0c, 0x0d]] |
278 |
| - """ |
279 |
| - b_hashes = [ |
280 |
| - random_blob_hashes[i % len(random_blob_hashes)] |
281 |
| - for i in range(max_blobs_per_block * length) |
282 |
| - ] |
283 |
| - return [ |
284 |
| - b_hashes[i : i + max_blobs_per_block] |
285 |
| - for i in range(0, len(b_hashes), max_blobs_per_block) |
286 |
| - ] |
287 |
| - |
288 |
| - @staticmethod |
289 |
| - def blobhash_sstore(index: int, max_blobs_per_block: int): |
290 |
| - """ |
291 |
| - Return BLOBHASH sstore to the given index. |
292 |
| -
|
293 |
| - If the index is out of the valid bounds, 0x01 is written |
294 |
| - in storage, as we later check it is overwritten by |
295 |
| - the BLOBHASH sstore. |
296 |
| - """ |
297 |
| - invalidity_check = Op.SSTORE(index, 0x01) |
298 |
| - if index < 0 or index >= max_blobs_per_block: |
299 |
| - return invalidity_check + Op.SSTORE(index, Op.BLOBHASH(index)) |
300 |
| - return Op.SSTORE(index, Op.BLOBHASH(index)) |
301 |
| - |
302 |
| - @classmethod |
303 |
| - def generate_blobhash_bytecode(cls, scenario_name: str, max_blobs_per_block: int) -> bytes: |
304 |
| - """Return BLOBHASH bytecode for the given scenario.""" |
305 |
| - scenarios = { |
306 |
| - "single_valid": sum( |
307 |
| - cls.blobhash_sstore(i, max_blobs_per_block) for i in range(max_blobs_per_block) |
308 |
| - ), |
309 |
| - "repeated_valid": sum( |
310 |
| - sum(cls.blobhash_sstore(i, max_blobs_per_block) for _ in range(10)) |
311 |
| - for i in range(max_blobs_per_block) |
312 |
| - ), |
313 |
| - "valid_invalid": sum( |
314 |
| - cls.blobhash_sstore(i, max_blobs_per_block) |
315 |
| - + cls.blobhash_sstore(max_blobs_per_block, max_blobs_per_block) |
316 |
| - + cls.blobhash_sstore(i, max_blobs_per_block) |
317 |
| - for i in range(max_blobs_per_block) |
318 |
| - ), |
319 |
| - "varied_valid": sum( |
320 |
| - cls.blobhash_sstore(i, max_blobs_per_block) |
321 |
| - + cls.blobhash_sstore(i + 1, max_blobs_per_block) |
322 |
| - + cls.blobhash_sstore(i, max_blobs_per_block) |
323 |
| - for i in range(max_blobs_per_block - 1) |
324 |
| - ), |
325 |
| - "invalid_calls": sum( |
326 |
| - cls.blobhash_sstore(i, max_blobs_per_block) |
327 |
| - for i in range(-5, max_blobs_per_block + 5) |
328 |
| - ), |
329 |
| - } |
330 |
| - scenario = scenarios.get(scenario_name) |
331 |
| - if scenario is None: |
332 |
| - raise ValueError(f"Invalid scenario: {scenario_name}") |
333 |
| - return scenario |
0 commit comments