|
12 | 12 | from ethereum_test_tools.vm.opcode import Opcodes as Op |
13 | 13 |
|
14 | 14 |
|
| 15 | +@dataclass |
| 16 | +class SpecialAddress: |
| 17 | + """Special values that are re-directed to test generated contracts.""" |
| 18 | + |
| 19 | + GAS_HASH_ADDRESS = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE |
| 20 | + EXTERNAL_ADDRESS = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF |
| 21 | + INVALID_CALL_ADDRESS = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD |
| 22 | + |
| 23 | + |
15 | 24 | @dataclass |
16 | 25 | class ScenarioDebug: |
17 | 26 | """Debug selector for the development.""" |
@@ -172,47 +181,41 @@ def translate_result( |
172 | 181 |
|
173 | 182 |
|
174 | 183 | def replace_special_calls_in_operation( |
175 | | - pre: Alloc, operation: Bytecode, external_address: Address |
| 184 | + pre: Alloc, fork: Fork, operation: Bytecode, external_address: Address |
176 | 185 | ) -> Bytecode: |
177 | 186 | """ |
178 | 187 | Run find replace of some special calls to the contracts that we don't know at compile time |
179 | 188 | replace 0xfff..fff address to external_address |
180 | 189 | replace special call to 0xfff..ffe address to gas_hash_address contract. |
181 | 190 | """ |
182 | 191 | gas_hash_address = make_gas_hash_contract(pre) |
183 | | - invalid_opcode_contract = make_invalid_opcode_contract(pre) |
184 | | - |
185 | | - """Replace Op.CALL(Op.GAS, 0xfff..ffe, 0, 64, 32, 0, 0) to gas_hash_address""" |
186 | | - """Replace Op.CALL(1000, 0xfff..ffd, 0, 64, 32, 0, 0) to invalid_opcode_contract""" |
187 | | - """Replace BALANCE(0xfff..fff) to BALANCE(external_address) in operation""" |
188 | | - """Replace EXTCODESIZE(0xfff..fff) to EXTCODESIZE(external_address) in operation""" |
189 | | - """Replace EXTCODEHASH(0xfff..fff) to EXTCODEHASH(external_address) in operation""" |
190 | | - """Replace EXTCODECOPY(0xfff..fff, ...) to EXTCODECOPY(external_address, ...)""" |
| 192 | + invalid_opcode_contract = make_invalid_opcode_contract(pre, fork) |
| 193 | + |
191 | 194 | replace_list: List[Tuple[str, str]] = [ |
192 | 195 | ( |
193 | | - "600060006020604060007ffffffffffffffffffffffffffffffffffffffffffffffff" |
194 | | - "ffffffffffffffffd620186a0f1", |
195 | | - Op.CALL(10000, invalid_opcode_contract, 0, 64, 32, 0, 0).hex(), |
| 196 | + "602060646020604060007f" |
| 197 | + + hex(SpecialAddress.INVALID_CALL_ADDRESS)[2:].lower() |
| 198 | + + "611388f1", |
| 199 | + Op.CALL(Op.SUB(Op.GAS, 200000), invalid_opcode_contract, 0, 64, 32, 100, 32).hex(), |
196 | 200 | ), |
197 | 201 | ( |
198 | | - "600060006020604060007ffffffffffffffffffffffffffffffffffffffffffffffff" |
199 | | - "ffffffffffffffffe5af1", |
| 202 | + "600060006020604060007f" + hex(SpecialAddress.GAS_HASH_ADDRESS)[2:].lower() + "5af1", |
200 | 203 | Op.CALL(Op.SUB(Op.GAS, 200000), gas_hash_address, 0, 64, 32, 0, 0).hex(), |
201 | 204 | ), |
202 | 205 | ( |
203 | | - "7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff31", |
| 206 | + "7f" + hex(SpecialAddress.EXTERNAL_ADDRESS)[2:].lower() + "31", |
204 | 207 | Op.BALANCE(external_address).hex(), |
205 | 208 | ), |
206 | 209 | ( |
207 | | - "7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff3b", |
| 210 | + "7f" + hex(SpecialAddress.EXTERNAL_ADDRESS)[2:].lower() + "3b", |
208 | 211 | Op.EXTCODESIZE(external_address).hex(), |
209 | 212 | ), |
210 | 213 | ( |
211 | | - "7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff3f", |
| 214 | + "7f" + hex(SpecialAddress.EXTERNAL_ADDRESS)[2:].lower() + "3f", |
212 | 215 | Op.EXTCODEHASH(external_address).hex(), |
213 | 216 | ), |
214 | 217 | ( |
215 | | - "7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff3c", |
| 218 | + "7f" + hex(SpecialAddress.EXTERNAL_ADDRESS)[2:].lower() + "3c", |
216 | 219 | "3c".join(Op.BALANCE(external_address).hex().rsplit("31", 1)), |
217 | 220 | ), |
218 | 221 | ] |
@@ -256,20 +259,44 @@ def make_gas_hash_contract(pre: Alloc) -> Address: |
256 | 259 | return gas_hash_address |
257 | 260 |
|
258 | 261 |
|
259 | | -def make_invalid_opcode_contract(pre: Alloc) -> Address: |
| 262 | +def make_invalid_opcode_contract(pre: Alloc, fork: Fork) -> Address: |
260 | 263 | """ |
261 | 264 | Deploy a contract that will execute any asked byte as an opcode from calldataload |
262 | | - With 0-ed input stack of 10 elements, valid for opcodes starting at 0x0C. |
| 265 | + Deploy 20 empty stack elements. Jump to opcode instruction. if worked, return 0. |
263 | 266 | """ |
264 | 267 | invalid_opcode_caller = pre.deploy_contract( |
265 | | - code=Op.PUSH0 * 10 |
266 | | - + Op.JUMP(Op.SUB(Op.MUL(2, Op.CALLDATALOAD(0)), 1)) # here pc is 19 |
267 | | - + Op.JUMPDEST * 4 |
| 268 | + code=Op.PUSH1(0) * 20 |
| 269 | + + Op.JUMP(Op.ADD(Op.MUL(7, Op.CALLDATALOAD(0)), 20 * 2 + 10)) |
268 | 270 | + sum( |
269 | 271 | [ |
270 | | - Bytecode(bytes([opcode]), popped_stack_items=0, pushed_stack_items=0) + Op.JUMPDEST |
271 | | - for opcode in range(0x0C, 0xFF) |
| 272 | + Op.JUMPDEST |
| 273 | + + Bytecode(bytes([opcode]), popped_stack_items=0, pushed_stack_items=0) |
| 274 | + + Op.RETURN(0, 0) |
| 275 | + for opcode in range(0x00, 0xFF) |
272 | 276 | ], |
273 | 277 | ) |
274 | 278 | ) |
275 | | - return invalid_opcode_caller |
| 279 | + |
| 280 | + invalid_opcodes = [] |
| 281 | + valid_opcode_values = [opcode.int() for opcode in fork.valid_opcodes()] |
| 282 | + |
| 283 | + for op in range(0x00, 0xFF): |
| 284 | + if op not in valid_opcode_values: |
| 285 | + invalid_opcodes.append(op) |
| 286 | + |
| 287 | + code = Bytecode( |
| 288 | + sum( |
| 289 | + Op.MSTORE(64, opcode) |
| 290 | + + Op.MSTORE( |
| 291 | + 32, |
| 292 | + Op.CALL(gas=50000, address=invalid_opcode_caller, args_offset=64, args_size=32), |
| 293 | + ) |
| 294 | + + Op.MSTORE(0, Op.ADD(Op.MLOAD(0), Op.MLOAD(32))) |
| 295 | + for opcode in invalid_opcodes |
| 296 | + ) |
| 297 | + # If any of invalid instructions works, mstore[0] will be > 1 |
| 298 | + + Op.MSTORE(0, Op.ADD(Op.MLOAD(0), 1)) |
| 299 | + + Op.RETURN(0, 32) |
| 300 | + ) |
| 301 | + |
| 302 | + return pre.deploy_contract(code=code) |
0 commit comments