Skip to content

Latest commit

 

History

History
54 lines (36 loc) · 3.55 KB

Puzzle7.md

File metadata and controls

54 lines (36 loc) · 3.55 KB

Analysis

Let's break down the bytecode and understand the flow of execution to find the answer:

  1. CALLDATASIZE (36): This opcode pushes the size of the calldata (in bytes) onto the stack.

  2. PUSH1 00: Pushes the value 00 (0 in decimal) onto the stack.

  3. DUP1 (80): Duplicates the top value of the stack.

  4. CALLDATACOPY (37): Copies the calldata into memory. The arguments (from the stack) are destination offset (0), source offset (0), and length (calldata size).

  5. CREATE (F0): Creates a new contract. The stack top is endowment (0), next is memory start (0), and third is memory size (calldata size). The calldata itself is used as the initialization code for the new contract.

  6. EXTCODESIZE (3B): Gets the size of the code of the newly created contract and pushes it onto the stack.

  7. EQ (14): Compares the top two values on the stack for equality. If equals, it pushes 1 (true) onto the stack; otherwise, it pushes 0 (false).

  8. JUMPI (57): If the top value of the stack is true (1), it alters the program counter to the value beneath it (in this case, 0C), performing a conditional jump to the JUMPDEST at byte 0C.

  9. JUMPDEST (5B): Marks a valid destination for jumps.

  10. STOP (00): Halts execution.

Execution

  • CALLDATASIZE (36), Pushes the size of the calldata onto the stack. Stack: [calldataSize]
  • PUSH1 00 (6000), Pushes 00 onto the stack. Stack: [00, calldataSize]
  • DUP1 (80), Duplicates the top value of the stack. Stack: [00, 00, calldataSize]
  • CALLDATACOPY (37), Copies the calldata to memory. Parameters are destination offset (0), source offset (0), length (calldataSize). Stack: [calldataSize]
  • CALLDATASIZE (36), Pushes the size of the calldata onto the stack. Stack: [calldataSize, calldataSize]
  • PUSH1 00 (6000), Pushes 00 onto the stack. Stack: [00, calldataSize, calldataSize]
  • PUSH1 00 (6000), Pushes another 00 onto the stack. Stack: [00, 00, calldataSize, calldataSize]
  • CREATE (F0), Creates a new contract. Parameters are value (0), memory start (0), and memory size (calldataSize). The calldata is used as the initialization code. Stack: [contractAddress]
  • EXTCODESIZE (3B), Gets the size of the code at the contract address. Stack: [extCodeSize]
  • PUSH1 01 (6001), Pushes 01 onto the stack. Stack: [01, extCodeSize]
  • EQ (14), Compares the top two stack items for equality. Stack: [isEqual]
  • PUSH1 13 (6013), Pushes 13 onto the stack. Stack: [13, isEqual]
  • JUMPI (57), Conditional jump to the position specified by 13 if isEqual is true. Stack: [contractAddress] (if jump is not taken)
  • JUMPDEST (5B) at 13, Marks a valid destination for jumps. Stack: [contractAddress]
  • STOP (00): Halts execution. Stack: [contractAddress]

Solution

To ensure that the JUMPI instruction at byte 11 performs a jump to the JUMPDEST at byte 13, the EXTCODESIZE of the contract created by CREATE must be exactly 1 byte. This means the calldata, when used as initialization code, must result in a contract with a bytecode size of 1 byte.

The calldata must be such that, as construction bytecode, it returns exactly 1 byte of runtime bytecode using the RETURN opcode. A valid solution is the calldata 0x60016000F3, which is a sequence of opcodes:

6001: PUSH1 01 - pushes 01 onto the stack (size of the data to return). 6000: PUSH1 00 - pushes 00 onto the stack (offset in memory). F3: RETURN - returns 1 byte of data from the specified offset in memory.

This sequence returns 1 byte of memory as the runtime bytecode of the created contract, ensuring that EXTCODESIZE is 1, and thus the JUMPI instruction jumps to the JUMPDEST at byte 13.