Skip to content

testinprod-io/optimism-state-export

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

5 Commits
 
 
 
 

Repository files navigation

optimism-state-export

A gentle guide to prepare storage for new execution client for OP stack. Preliminary info: goerli bedrock transition was done at block 4061224.

TL;DR: Jump to Game Plan

Historical data

To build new execution client for OP stack, we must import historical data of optimism. Lets break down what exactly the history data means. The historical data consists of below segments.

  1. Block header
    • state root, transaction trie root, transaction receipt trie root is included
  2. Transaction trie
    • Transactions are stored at leaves
  3. Transaction receipt trie
    • Transaction receipts are stored at leaves
  4. World state trie
    • Account states(balance, nonce, code, storage trie root) is stored at leaves

Prebedrock Block Execution is Impossible

Simply thinking, you may claim that new client may start with genesis, and by only knowing the block header and the transaction trie, it can execute the transactions and advance the block state, contructing transaction receipt trie and world state trie.

However, new client has no functionality of executing the pre-bedrock transactions. This is because pre-bedrock state transition was only done via l2geth, which does not have EVM equivalence.

World State Trie Dump to the Rescue

Therefore we need to extract the entire world state trie, starting from bedrock block(block number 4061224). As you can see in etherscan, this block does not contain transactions not to make ambiguity during bedrock transition. Bedrock supports EVM equivalence, so every transactions included in bedrock era can be natively executed in your new execution client, with some tweaks. The tweaks will be the diff introduced between geth and op-geth. Here are the detailed diff explanation.

You may create the state dump using public info:

  • Bedrock Data Directory
    • 7.5G. This tarball contains the following info
      • Block header until block 4061224
      • Transaction until block 4061224
      • Transaction receipt until block 4061224
      • World state trie only for genesis and 4061224
  • Legacy Geth Data Directory
    • 62G. This tarball contains the following info
      • Block header until block 4061223
      • Transaction until block 4061223
      • Transaction receipt until block 4061223
      • Every world state trie until block 4061223

By using upper info, you must construct file which contains state trie to reconstruct world state trie for block 4061224, starting from bedrock.

Luckily, here is the 1.39G json file which captures every info for recontructing world state trie for block 4061224. alloc_everything_4061224_final.json. It was super painful to derive all the preimages! In theory, every data to create this world state trie is included in bedrock data directory. However, we had some problems with state dump, so we also used legacy geth data directory to create the full world state trie. The given json file follows the genesis file structure. Detailed steps to create this json will be added in this repo in the future.

Data Export

All the data export artifacts will be shared asap. You do not have to follow steps. You can use files that we provided in the game plan. We followed below steps because op-geth dump functionality is not working at the moment.

  1. Initialize your new OP stack execution engine's storage with the optimism-goerli genesis file.
  2. Dump block headers and transactions from block number 1 to 4061224 from the archive. This can be done via l2geth's export command. RLP encoded file will be created.
  3. Dump transaction receipts from block 1 to 4061224 from the archive. I wrote the custom geth command export-receipts to do this. See here for details. RLP encoded file will be created.
  4. Dump world state trie at block 4061224. alloc_everything_4061224_final.json

Game Plan

  1. Import optimism-goerli genesis file to your new client
  2. Import block headers and transactions to your new client.
  3. Import transaction receipts to your new client
    • RLP encoded receipt: export_receipt_0_4061223
    • There is no receipt for block 4061224 because no transaction at block 4061224.
  4. Import world state trie at block 4061224: alloc_everything_4061224_final.json to your new client. I wrote custom import functionality for op-erigon to achieve this.

You may ask that is it okay not to have world state trie for prebedrock block. You may simply relay the requests to l2geth node. Daisy chain will handle these prebedrock jobs.

Wait, How can I trust your huge json?

Here is the huge json: alloc_everything_4061224_final.json. You can check the validity of this json by recontructing the world state trie, and check the merkle root. Query block 4061224, get the world state trie's root included at block header and compare it by yourself. You may refer to the creation/validation script written by me.