Puzzle 2

CALL, RETURNDATASIZE

Puzzle

############
# Puzzle 2 #
############

00      36        CALLDATASIZE
01      6000      PUSH1 00
03      6000      PUSH1 00
05      37        CALLDATACOPY
06      36        CALLDATASIZE
07      6000      PUSH1 00
09      6000      PUSH1 00
0B      F0        CREATE
0C      6000      PUSH1 00
0E      80        DUP1
0F      80        DUP1
10      80        DUP1
11      80        DUP1
12      94        SWAP5
13      5A        GAS
14      F1        CALL
15      3D        RETURNDATASIZE
16      600A      PUSH1 0A
18      14        EQ
19      601F      PUSH1 1F
1B      57        JUMPI
1C      FE        INVALID
1D      FE        INVALID
1E      FE        INVALID
1F      5B        JUMPDEST
20      00        STOP

? Enter the calldata: 

Solution

Pseudocode:

// Copy calldata to memory offset 0
calldatacopy(0, 0, calldata_size);

// Create a new contract based on that calldata stored in memory, deposit 0 wei into it.
// Return the new contract's address back to the stack.
contract_address = create(0, 0, calldata_size);

// Call the new contract with remaining gas.
// Return success status (0 or 1) back to the stack.
returndata = call(gas, contract_address, 0, 0, 0, 0, 0)

if (returndata_size == 0x0A) {
    jump(0x1F);
}

Basically we need to build a contract that returns 10 bytes of data, any data suffices, such as 0x00's. That means our runtime code can simply return 10 bytes of stuff without writing anything to the memory:

// Return that 10 bytes
PUSH1 0x0A
PUSH1 0x00
RETURN

Compile it in Playground:

600a6000f3

Next let's build creation code:

// Store 0x600a6000f3 in memory offset 0
PUSH5 0x600a6000f3
PUSH1 0x00
MSTORE

// Return it, but skipping all the leading zeros
PUSH1 0x05
PUSH1 0x1B
RETURN

Compile:

64600a6000f36000526005601bf3

Last updated