In this challenge, you need to understand the complex inner workings of blocks to form some data with the same hash as a block.
The contract has two main functions:
preMintFlag()
: Registers your intent to mint and stores the current block numbermintFlag(bytes memory rlpBytes)
: Verifies thatkeccak256(rlpBytes)
is the same as a block hash before minting the flag
Hint 1
mintFlag(bytes memory rlpBytes)
requires keccak256(rlpBytes)
to be the same as blockhash(registeredBlock)
. It's virtually impossible to find data that hashes to the same value. How else can you get some data that has the same hash?
Hint 2
Under the hood,blockhash()
has a keccak256()
operation. If we figure out the parameters to this hash, we can pass that into the mintFlag()
function!
Hint 3
A block hash is the Keccak-256 hash of the block header encoded in RLP. Note that this is Optimism, so the block header will be different!Specifically, here is the structure of the Optimism block header:
[
parentBlockHash,
sha3Uncles,
miner,
stateRoot,
transactionsRoot,
receiptsRoot,
logsBloom,
number,
gasLimit,
gasUsed,
timestamp,
extraData,
mixHash,
nonce, // <- after PoW, 8 bytes of zeros
baseFeePerGas,
withdrawalsRoot,
blobGasUsed,
excessBlobGas,
parentBeaconBlockRoot
]
Click to reveal solution
- First, register for minting:
challenge12.preMintFlag();
uint256 targetBlock = block.number + challenge12.futureBlocks();
-
Get the block data for
targetBlock
. This can be obtained by aneth_getBlockByNumber
call to an RPC. -
After converting to a list (see hint #3), RLP encode it.
-
Submit the proof:
challenge12.mintFlag(rlpEncoded);
The contract will:
- Verify the block number matches
- Check that the RLP-encoded header matches the block hash
- Mint your flag if everything is correct
Congratulations! You've mastered block header verification and RLP encoding! 🎉