|
| 1 | +# Optimism Bedrock |
| 2 | + |
| 3 | +> by @paco0x |
| 4 | +
|
| 5 | +## Addresses |
| 6 | + |
| 7 | +### Goerli |
| 8 | + |
| 9 | +| Name | Type | Address | |
| 10 | +| ---------------------------- | --------- | ----------------------------------------------------------------------------------- | |
| 11 | +| Batcher Submitter | EOA | https://goerli.etherscan.io/address/0x7431310e026b69bfc676c0013e12a1a11411eec9 | |
| 12 | +| BatchInbox | EOA | https://goerli.etherscan.io/address/0xff00000000000000000000000000000000000420 | |
| 13 | +| Proposer | EOA | https://goerli.etherscan.io/address/0x02b1786A85Ec3f71fBbBa46507780dB7cF9014f6 | |
| 14 | +| Challenger | Multi-sig | https://goerli.etherscan.io/address/0xBc1233d0C3e6B5d53Ab455cF65A6623F6dCd7e4f | |
| 15 | +| L2OutputOracle | Contract | https://goerli.etherscan.io/address/0xE6Dfba0953616Bacab0c9A8ecb3a9BBa77FC15c0 | |
| 16 | +| OptimismPortal | Contract | https://goerli.etherscan.io/address/0x5b47E1A08Ea6d985D6649300584e6722Ec4B1383 | |
| 17 | +| L1CrossDomainMessenger | Contract | https://goerli.etherscan.io/address/0x5086d1eef304eb5284a0f6720f79403b4e9be294 | |
| 18 | +| L1StandardBridge | Contract | https://goerli.etherscan.io/address/0x636af16bf2f682dd3109e60102b8e1a089fedaa8#code | |
| 19 | +| L1ERC721Bridge | Contract | https://goerli.etherscan.io/address/0x8DD330DdE8D9898d43b4dc840Da27A07dF91b3c9 | |
| 20 | +| OptimismMintableERC20Factory | Contract | https://goerli.etherscan.io/address/0x883dcF8B05364083D849D8bD226bC8Cb4c42F9C5 | |
| 21 | +| SystemConfig | Contract | https://goerli.etherscan.io/address/0xAe851f927Ee40dE99aaBb7461C00f9622ab91d60 | |
| 22 | +| SystemDictator | Contract | https://goerli.etherscan.io/address/0x1f0613A44c9a8ECE7B3A2e0CdBdF0F5B47A50971#code | |
| 23 | +| SystemDictator Owner | Multi-sig | https://goerli.etherscan.io/address/0xBc1233d0C3e6B5d53Ab455cF65A6623F6dCd7e4f | |
| 24 | + |
| 25 | +### OP Bedrock on Goerli |
| 26 | + |
| 27 | +| Name | Type | Address | |
| 28 | +| ----------------------------- | ---------- | --------------------------------------------------------------------------------------- | |
| 29 | +| L1 Attribute Depositor | EOA | https://goerli-optimism.etherscan.io/address/0xdeaddeaddeaddeaddeaddeaddeaddeaddead0001 | |
| 30 | +| L1Block | Pre-deploy | https://goerli-optimism.etherscan.io/address/0x4200000000000000000000000000000000000015 | |
| 31 | +| L2ToL1MessagePasser | Pre-deploy | https://goerli-optimism.etherscan.io/address/0x4200000000000000000000000000000000000016 | |
| 32 | +| L2CrossDomainMessenger | Pre-deploy | https://goerli-optimism.etherscan.io/address/0x4200000000000000000000000000000000000007 | |
| 33 | +| L2StandardBridge | Pre-deploy | https://goerli-optimism.etherscan.io/address/0x4200000000000000000000000000000000000010 | |
| 34 | +| L2ERC721Bridge | Pre-deploy | https://goerli-optimism.etherscan.io/address/0x4200000000000000000000000000000000000014 | |
| 35 | +| OptimismMintableERC20Factory | Pre-deploy | https://goerli-optimism.etherscan.io/address/0x4200000000000000000000000000000000000012 | |
| 36 | +| OptimismMintableERC721Factory | Pre-deploy | https://goerli-optimism.etherscan.io/address/0x4200000000000000000000000000000000000017 | |
| 37 | + |
| 38 | +Pre-deployed contracts are deployed in genesis block by directly setting the state DB: [https://github.com/ethereum-optimism/optimism/blob/c21476c1874702da8c0817d5c7c9de5b8066eb4b/op-chain-ops/genesis/setters.go#L226](https://github.com/ethereum-optimism/optimism/blob/c21476c1874702da8c0817d5c7c9de5b8066eb4b/op-chain-ops/genesis/setters.go#L226) |
| 39 | + |
| 40 | +## Component |
| 41 | + |
| 42 | +- **op-geth** is a slightly modified version of **geth**, the Execution Engine in Optimism Bedrock, used to produce L2 blocks. You can find all the changes at [https://op-geth.optimism.io/](https://op-geth.optimism.io/). |
| 43 | +- **op-node** is the rollup node, which is a standalone stateless binary. |
| 44 | + - It receives L2 user transactions and converts the deposit data into payload attributes for the Engine API. |
| 45 | + - It submits the payload attributes to the Engine API, where they are converted into blocks and added to the canonical chain. |
| 46 | + - It can also derive the L2 chain from L1 deposits & batchInbox. |
| 47 | + - It generates L2 outputRoots for submission or verification. |
| 48 | +- **op-batcher** submits the L2 transactions to DA (currently, L1 calldata) through batcher transactions. |
| 49 | +- **op-proposer** periodically submits the L2 state root to the L1 contract for verification and withdrawal proving. |
| 50 | + |
| 51 | +## L2 Blocks |
| 52 | + |
| 53 | +Before Bedrock, the blockchain had a variable block time and one transaction per block. |
| 54 | + |
| 55 | +With Bedrock, the block time is fixed at 2 seconds and can contain multiple transactions. |
| 56 | + |
| 57 | +Advantages of this change include: |
| 58 | + |
| 59 | +- Consistency with the Ethereum mainnet after POS. |
| 60 | +- Convenience for contracts that use block numbers rather than timestamps to keep track of time; for example, the `MasterChef` contract. Block numbers are harder to manipulate than block timestamps. |
| 61 | +- Reduced overhead for storing the blockchain. |
| 62 | +- No need to update the state trie root after each transaction. |
| 63 | + |
| 64 | +#### Epochs and the Sequencing Window |
| 65 | + |
| 66 | +The rollup chain is subdivided into epochs. There is a 1:1 correspondence between L1 block numbers and epoch numbers. |
| 67 | + |
| 68 | +L2 block timestamp can be 10 minutes (**sequencer drift parameter**) ahead of L1. This parameter is meant to ensure liveness of the L2 chain during temporary loss of connection to L1. |
| 69 | + |
| 70 | +## Transaction Types |
| 71 | + |
| 72 | +On L2, Optimism adds a new type of transaction in op-geth called deposit transaction. |
| 73 | + |
| 74 | +There are 2 types of deposit transactions: |
| 75 | + |
| 76 | +- System transactions, the first transaction of every L2 block, setting the attributes from L1 |
| 77 | +- Deposit transactions, transactions sent by users on L1 to L2 |
| 78 | + |
| 79 | +Other transactions are sent by users on L2 directly |
| 80 | + |
| 81 | +## Deposit |
| 82 | + |
| 83 | +- Call `OptimismPortal.depositTransaction(to, value, gasLimit, isCreation, data)` on L1. |
| 84 | +- Emit the `TransactionDeposited(from, to, version, opaqueData)` event in the contract. |
| 85 | + - If `from` is a contract, address aliasing will be performed. For more information, see the [address aliasing documentation](https://community.optimism.io/docs/developers/build/differences/#using-eth-in-contracts). |
| 86 | +- The sequencer uses these events to generate deposited transactions on L2 and build the block. |
| 87 | +- Deposit transactions are not retryable. |
| 88 | +- It's invalid to have an L2 block without including the deposits of its L1 origin. (anti censorship) |
| 89 | + |
| 90 | +The L2 execution gas is paid by the user on L1. |
| 91 | + |
| 92 | +## Withdrawal |
| 93 | + |
| 94 | +- Call `L2ToL1MessagePasser.initiateWithdrawal(target, gasLimit, data)` on L2. |
| 95 | +- Set the contract storage for `sentMessages[withdrawalHash]` to `true`. |
| 96 | +- The proposer should set the L2 state root and storage root of `L2ToL1MessagePasser` on L1 (`L2OutputOracle`). |
| 97 | +- Prove the state on L1 by calling `OptimismPortal.proveWithdrawalTransaction()`. |
| 98 | + - Prove the `withdrawalHash -> true` key pair exists in the contract’s storage(**_Merkle Patricia Trie_**) |
| 99 | +- Wait for the finalization period. |
| 100 | +- Finalize the withdrawal transaction by calling `OptimismPortal.finalizeWithdrawalTransaction()`. |
| 101 | +- Withdrawal transactions are not retryable. |
| 102 | + |
| 103 | +They use `Safecall.call()` to ignore the return data to avoid the potential return data bomb. |
| 104 | + |
| 105 | +[https://www.notonlyowner.com/research/message-traps-in-the-arbitrum-bridge](https://www.notonlyowner.com/research/message-traps-in-the-arbitrum-bridge) |
| 106 | + |
| 107 | +## Message Passing |
| 108 | + |
| 109 | +Optimism constructed a pair of messaging contracts for message passing by utilizing the low-level deposit and withdraw transactions. The contracts used for message passing are `L1CrossDomainMessenger.sol` and `L2CrossDomainMessenger.sol`. |
| 110 | + |
| 111 | +The messages are retryable, unlike the raw deposits/withdrawals. Developers should use messenger contracts instead of low-level deposits/withdrawals. |
| 112 | + |
| 113 | +- To pass a message to the other chain, users need to call `CrossDomainMessenger.sendMessage(target, message, minGasLimit)`. |
| 114 | +- To obtain the caller on the other chain, users can use `CrossDomainMessenger.xDomainMsgSender()`. |
| 115 | + - If it is an L1 → L2 message, remember to undo the address alias. |
| 116 | + |
| 117 | +### L1 → L2 message |
| 118 | + |
| 119 | +#### on L1 |
| 120 | + |
| 121 | +- user call `L1CrossDomainMessenger.sendMessage()` |
| 122 | +- gas is charged and computed on L1 |
| 123 | + - gas usage: `gasLimit = minGasLimit * 1.016 + _message.length * 16 + 200,000` |
| 124 | +- call `OptimismPortal.depositTransaction()` |
| 125 | + |
| 126 | +```solidity |
| 127 | +portal.depositTransaction{value: msg.value}( |
| 128 | + L2CrossDomainMessenger, // The pre-deplyed CrossDomainMessenger on L2 |
| 129 | + msg.value, |
| 130 | + gasLimit, |
| 131 | + false, |
| 132 | + abi.encodeWithSelector( |
| 133 | + this.relayMessage.selector, |
| 134 | + messageNonce(), |
| 135 | + msg.sender, |
| 136 | + _target, |
| 137 | + msg.value, |
| 138 | + _minGasLimit, |
| 139 | + _message |
| 140 | + ) |
| 141 | +) |
| 142 | +
|
| 143 | +``` |
| 144 | + |
| 145 | +- emit the `TransactionDeposited()` event in the `OptimismPortal` contract on L1 |
| 146 | + |
| 147 | +#### on L2 |
| 148 | + |
| 149 | +- op-node generate a deposit transaction by reading the `TransactionDeposited` events |
| 150 | +- the deposited transaction calls the `L2CrossDomainMessager.relayMessage()` on L2 |
| 151 | +- call the target address in `L2CrossDomainMessager.relayMessage()` and record the result |
| 152 | +- call the target address with the message |
| 153 | +- If the replay transaction failed, user can replay it manually |
| 154 | + |
| 155 | +### L2 → L1 message |
| 156 | + |
| 157 | +#### on L2 |
| 158 | + |
| 159 | +- user call `L2CrossDomainMessenger.sendMessage()` |
| 160 | +- call `L2ToL1MessagePasser.intializeWithdraw()` |
| 161 | +- set `sentMessages[withdrawalHash] = true;` in the `L2ToL1MessagePasser` |
| 162 | + |
| 163 | +#### on L1 |
| 164 | + |
| 165 | +- wait for the proposer submit the state root on L1 `L2OutputOracle` |
| 166 | +- prove the tx hash is already written to `L2ToL1MessagePasser` on L2 |
| 167 | +- wait for the finalization period |
| 168 | +- finalize the withdrawal transaction by calling `OptimismPortal.finalizeWithdrawalTransaction()` |
| 169 | +- call `L1CrossDomainMessenger.relayMessage()` |
| 170 | +- call the target address with the message |
| 171 | + |
| 172 | +## Bridges |
| 173 | + |
| 174 | +Optimism built the following bridges for ERC20 and ERC721 |
| 175 | + |
| 176 | +- `L1StandardBridge` & `L2StandardBridge` |
| 177 | +- `L1ERC721Bridge` & `L2ERC721Bridge` |
| 178 | + |
| 179 | +Under the hood, Optimism uses the message-passing mechanism provided by `CrossDomainMessenger` contracts. |
| 180 | + |
| 181 | +### Bridging from L1 to L2 |
| 182 | + |
| 183 | +Before bridging from L1 to L2, users need to create a remote ERC20 contract on L2 by using the `OptimismMintableERC20Factory` contract. |
| 184 | + |
| 185 | +#### On L1 |
| 186 | + |
| 187 | +- Lock the token/ETH and record the amount on L1's `L1StandardBridge`. |
| 188 | +- Send a message to L2's `L2StandardBridge`. |
| 189 | + |
| 190 | +#### On L2 |
| 191 | + |
| 192 | +- Receive the message call in `L2StandardBridge`. |
| 193 | +- Mint the remote token with the specified amount. |
| 194 | + |
| 195 | +### Bridging from L2 to L1 |
| 196 | + |
| 197 | +The process is very similar to the above. |
| 198 | + |
| 199 | +## L2OutputOracle |
| 200 | + |
| 201 | +### State Verification |
| 202 | + |
| 203 | +`L2OutputOracle` is a contract on L1 that saves the L2 state roots for verification. Verifiers can challenge the result through a disputing system. |
| 204 | + |
| 205 | +Currently, only an EOA address operated by Optimism can write to this contract. |
| 206 | + |
| 207 | +The challenger address is set to a multi-sig wallet controlled by Optimism. |
| 208 | + |
| 209 | +### Withdrawal proving |
| 210 | + |
| 211 | +`L2OutputOracle` also saves the storage root of the `L2ToL1MessagePasser` contract on L2 for proving the withdrawal transactions on L1. |
| 212 | + |
| 213 | +## Batcher |
| 214 | + |
| 215 | +**op-batcher** submits the L2 data as calldata to `BatchInbox` address. |
| 216 | + |
| 217 | +- op-node can read these calldata to rebuild the entire L2 chain. |
| 218 | +- Verifiers can use these data to verify the state root in `L2OutputOracle` contract. |
| 219 | + |
| 220 | +### Data format |
| 221 | + |
| 222 | +**Batches**, \***\*a batch \*\***contains all the txs of an L2 block |
| 223 | + |
| 224 | +**Channels**, Batches are aggregated into **channel** |
| 225 | + |
| 226 | +**Channel Frames**, channels are compressed and split into **channel frames** |
| 227 | + |
| 228 | +Batcher submits those frames in the [batcher transactions](https://github.com/ethereum-optimism/optimism/blob/f30376825c82f62b846590487fe46b7435213d37/specs/glossary.md#batcher-transaction). |
| 229 | + |
| 230 | +## Proposer |
| 231 | + |
| 232 | +**op-proposer** submits the L2 state root and the storage trie root hash of the `L2ToL1MessagePasser` contract on L2 to L1 `L2OutputOracle`. |
| 233 | + |
| 234 | +Proposer queries these data through op-node’s `optimism_outputAtBlock` RPC API. Inside `optimism_outputAtBlock`: |
| 235 | + |
| 236 | +- fetch the L2 block header through `eth_getBlockByNumber` RPC in op-geth |
| 237 | +- fetch the storage root of `L2ToL1MessagePasser` contract through `eth_getProof` RPC in op-geth |
| 238 | +- return the state root of the L2 block and the storage root of `L2ToL1MessagePasser` contract |
| 239 | + - before returning, verify the storage root is contained in the state trie |
| 240 | + |
| 241 | +Test account: |
| 242 | + |
| 243 | +- Address: `0x3bb843cf8e26FF1Fdbdb6B2eC1B0dD5B37082B64` |
| 244 | +- Private Key: `0x8567689e64d90470cf9e30ed5d59d495e7a27de4fbe964620e45ecbe050018d7` |
| 245 | + |
| 246 | +## Reference |
| 247 | + |
| 248 | +- <https://paco0x.notion.site/Optimism-Bedrock-a546537289864e2dad5eca77e7386b96> |
| 249 | +- <https://community.optimism.io/docs/developers/bedrock/how-is-bedrock-different/> |
0 commit comments