├── .gitignore ├── EnglishReadme.md ├── LICENSE ├── README.md ├── architecture ├── EnglishReadme.md ├── ReadMe.md └── images │ ├── Readme.md │ └── architecture.png ├── cdmsg-bridge ├── EnglishReadme.md ├── images │ ├── a.png │ ├── erc20cliam.png │ ├── erc20deposit.png │ ├── erc20withdraw.png │ ├── erc721deposit.png │ ├── ethcliam.png │ ├── ethdeposit.png │ └── ethwithdraw.png └── readme.md ├── derive ├── EnglishReadme.md └── readme.md ├── optimistim-api ├── EnglishReadme.md ├── README.md └── op-node-api1.png └── rollup ├── EnglishReadme.md ├── README.md ├── op-batcher ├── EnglishReadme.md ├── Readme.md └── op-batcher.png ├── op-proposer ├── EnglishReadme.md ├── op-proposer.png └── readme.md └── rollup_art.png /.gitignore: -------------------------------------------------------------------------------- 1 | # If you prefer the allow list template instead of the deny list, see community template: 2 | # https://github.com/github/gitignore/blob/main/community/Golang/Go.AllowList.gitignore 3 | # 4 | # Binaries for programs and plugins 5 | *.exe 6 | *.exe~ 7 | *.dll 8 | *.so 9 | *.dylib 10 | 11 | # Test binary, built with `go test -c` 12 | *.test 13 | 14 | # Output of the go coverage tool, specifically when used with LiteIDE 15 | *.out 16 | 17 | # Dependency directories (remove the comment below to include it) 18 | # vendor/ 19 | 20 | # Go workspace file 21 | go.work 22 | -------------------------------------------------------------------------------- /EnglishReadme.md: -------------------------------------------------------------------------------- 1 | [![Chinese](https://img.shields.io/badge/Chinese-README-blue)](README.md) 2 | 3 | 4 | # how-dose-op-stack-work 5 | 6 | ## Tutorial directory 7 | 8 | ### Basics 9 | 10 | #### 1.Op-Stack Architecture - [Tutorial](https://github.com/guoshijiang/how-dose-op-stack-work/blob/main/architecture/ReadMe.md) 11 | 12 | #### 2. Deeply understand the Op-stack cross-chain calling process and the deposit and withdrawal analysis of ETH and ERC20 - [Tutorial](https://github.com/guoshijiang/how-dose-op-stack-work/blob/main/cdmsg-bridge/readme.md) 13 | 14 | #### 3. Detailed explanation of Op-stack rollup process - [Tutorial](https://github.com/guoshijiang/how-dose-op-stack-work/blob/main/rollup/README.md) 15 | 16 | #### 4.Optimistim op-node json rpc - [Tutorial](https://github.com/guoshijiang/how-dose-op-stack-work/blob/main/optimistim-api/README.md) 17 | 18 | #### 5. Detailed explanation of Optimistim block derivation process - [Tutorial]() 19 | 20 | ### Practical combat 21 | 22 | #### 6. How to start op-stack devnet network locally - [Tutorial]() 23 | 24 | #### 7. How to use op-stack sdk for deposit and withdrawal testing - [Tutorial]() 25 | 26 | #### 8.op-stack l1->l2, l2->l1, rollup transaction data, transaction status synchronization practice - [Tutorial]() 27 | 28 | #### 9. How to develop your own Layer2 chain based on op-stack - [Tutorial]() 29 | 30 | ### Advanced 31 | 32 | #### 10. Detailed explanation of Op-stack configuration items - [Tutorial]() 33 | 34 | #### 11.Op-stack service running status monitoring - [Tutorial]() 35 | 36 | #### 12. Deploy a Layer2 network based on sepolia - [Tutorial]() 37 | 38 | #### 13. Conclusion 39 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 seek 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![English](https://img.shields.io/badge/English-README-blue)](EnglishReadme.md) 2 | 3 | 4 | # how-dose-op-stack-work 5 | 6 | ## 教程目录 7 | 8 | ### 基础篇 9 | 10 | #### 1.Op-Stack 架构 - [教程](https://github.com/guoshijiang/how-dose-op-stack-work/blob/main/architecture/ReadMe.md) 11 | 12 | #### 2.深入理解 Op-stack 跨链调用过程及 ETH 和 ERC20 的充值提现解析 - [教程](https://github.com/guoshijiang/how-dose-op-stack-work/blob/main/cdmsg-bridge/readme.md) 13 | 14 | #### 3.Op-stack rollup 流程详解 - [教程](https://github.com/guoshijiang/how-dose-op-stack-work/blob/main/rollup/README.md) 15 | 16 | #### 4.Optimistim op-node json rpc - [教程](https://github.com/guoshijiang/how-dose-op-stack-work/blob/main/optimistim-api/README.md) 17 | 18 | #### 5.Optimistim 区块推导过程详解 - [教程]() 19 | 20 | ### 实战篇 21 | 22 | #### 6.如何在本地启动 op-stack devnet 网络 - [教程]() 23 | 24 | #### 7.如何使用 op-stack sdk 进行充值提现测试 - [教程]() 25 | 26 | #### 8.op-stack l1->l2, l2->l1, rollup 交易数据, 交易状态同步实战 - [教程]() 27 | 28 | #### 9.如何基于 op-stack 开发自己的 Layer2 链 - [教程]() 29 | 30 | ### 高级篇 31 | 32 | #### 10.Op-stack 配置项详解- [教程]() 33 | 34 | #### 11.Op-stack 服务运行状态监控- [教程]() 35 | 36 | #### 12.基于 sepolia 部署一个 Layer2 网络 - [教程]() 37 | 38 | #### 13.结语 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /architecture/EnglishReadme.md: -------------------------------------------------------------------------------- 1 | [![Chinese](https://img.shields.io/badge/Chinese-README-blue)](ReadMe.md) 2 | 3 | 4 | # architecture 5 | 6 | [![architecture](https://github.com/guoshijiang/how-dose-op-stack-work/blob/main/architecture/images/architecture.png)](https://github.com/guoshijiang/how-dose-op-stack-work) 7 | 8 | 9 | - Op-stack is mainly composed of op-node, op-geth, op-batcher, op-proposer, CrossDomainMessenger, OptimismPortal, Bridge contracts and L2OutputOracle contract. 10 | - op-node and op-geth (Seqeuencer & Verifier): responsible for transaction packaging and block dropping, transaction status derivation, data transmission synchronization, etc. 11 | - op-batcher: Submit transaction data to the EOA address of L1 12 | - op-proposer submits the block state to the L2OutputOracle contract of L1 13 | - CrossDomainMessenger cross-chain messenger contract, its main functions are sendMessage and relyMessage, responsible for the communication contracts of L1->L2, L2->L1; 14 | - Bridge contracts: Bridge contracts, the main function is to carry deposits and withdrawals, L1->L2: L1 locks the funds in the bridge, L2 Mint the corresponding funds; L2->L1: L2 Burn the corresponding funds; L1 unlocks the corresponding funds. 15 | -------------------------------------------------------------------------------- /architecture/ReadMe.md: -------------------------------------------------------------------------------- 1 | [![English](https://img.shields.io/badge/English-README-blue)](EnglishReadme.md) 2 | 3 | 4 | # architecture 5 | 6 | [![architecture](https://github.com/guoshijiang/how-dose-op-stack-work/blob/main/architecture/images/architecture.png)](https://github.com/guoshijiang/how-dose-op-stack-work) 7 | 8 | 9 | - Op-stack 主要由 op-node, op-geth, op-batcher, op-proposer, CrossDomainMessenger, OptimismPortal, Bridge contracts 和 L2OutputOracle contract 等角色组成 10 | - op-node 加 op-geth(Seqeuencer & Verifier):负责交易打包落块,交易的状态推导, 数据传输同步等 11 | - op-batcher: 提交交易数据到 L1 的 EOA 地址 12 | - op-proposer 提交区块状态到 L1 的 L2OutputOracle 合约 13 | - CrossDomainMessenger 跨链信使合约,主要功能是 sendMessage 和 relyMessage, 负责 L1->L2, L2->L1 的通信合约; 14 | - Bridge contracts:桥合约,主要功能是承载充值提现,L1->L2: L1 将资金锁定在桥中,L2 Mint 相应的资金;L2->L1: L2 Burn 相应的资金; L1 解锁对应的资金。 15 | 16 | -------------------------------------------------------------------------------- /architecture/images/Readme.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /architecture/images/architecture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/the-web3-chain/how-dose-op-stack-work/c40bf36d058337b4c12bfd301103457ae10a7fda/architecture/images/architecture.png -------------------------------------------------------------------------------- /cdmsg-bridge/EnglishReadme.md: -------------------------------------------------------------------------------- 1 | [![Chinese](https://img.shields.io/badge/Chinese-README-blue)](readme.md) 2 | 3 | 4 | # Deeply understand the Op-stack cross-chain calling process and the deposit and withdrawal of ETH and ERC20 5 | 6 | # 1. Messenger Contract 7 | The main function of the messenger contract is cross-chain communication, and the core methods are sendMessage and relayMessage; 8 | - sendMessage: Send packaged messages from the source chain to the target chain, maintain the incremented msgNonce, and ensure the uniqueness and security of cross-chain messages. 9 | - relayMessage: Construct a MsgHash comparison of the message sent from the source chain on the target chain to ensure the consistency of the message and then schedule and execute the message on the current chain. 10 | In op-stack, there are respectively in L1 and L2 layers 11 | - L1CrossDomainMessenger 12 | - L2CrossDomainMessenger 13 | Inherited from the CrossDomainMessenger contract to carry cross-chain communication. How the cross-chain message contract is called will be explained in detail in the recharge and withdrawal chapters. 14 | 15 | # 2. OptimismPortal 16 | The OptimismPortal contract is the deposit and withdrawal contract of op-stack. 17 | 18 | ## 2.1 Recharge 19 | The recharge transaction will call depositTransaction; depositTransaction will throw the TransactionDeposited event, which contains the following information: 20 | emit TransactionDeposited(from, _to, DEPOSIT_VERSION, opaqueData); 21 | After the op-node monitors the contract event, it will execute the recharge transaction on the second layer. We will talk about the detailed introduction of the op-node later. 22 | 23 | ## 2.2 Withdrawal 24 | 25 | For cash withdrawals, OptimismPortal will do two things: 26 | - The first is the transaction proof proveWithdrawalTransaction, which updates the transaction proven to pass to 27 | mapping(bytes32 => ProvenWithdrawal) public provenWithdrawals 28 | As long as you enter it, the transaction means that it has been proven. 29 | 30 | - The other is the operation of relay transaction. The finalizeWithdrawalTransaction function will put the relay transaction into 31 | mapping(bytes32 => bool) public finalizedWithdrawals 32 | As long as the transaction enters the finalizedWithdrawals Map, it is proven that it has been relayed. 33 | 34 | # 3. Bridge Contract 35 | In this section, we will draw a detailed flowchart of the recharge and withdrawal on the entire bridge. 36 | 37 | # 4. L1->L2 recharge 38 | 39 | ## 4.1 ETH Deposit 40 | 41 | [![ethdeposit](https://github.com/guoshijiang/how-dose-op-stack-work/blob/main/cdmsg-bridge/images/ethdeposit.png)](https://github.com/guoshijiang/how-dose-op-stack-work) 42 | 43 | 44 | -User 45 | - The user calls depositETH to recharge his own address, or calls depositETHTo to recharge the specified to address; 46 | - L1StandardBridge 47 | - Whether you call depositETH or depositETHTo, you will eventually enter a function _initiateETHDeposit; no operation is done in _initiateETHDeposit, and _initiateBridgeETH is called directly 48 | - In the _initiateBridgeETH function, there will be the following operations 49 | - Determine whether msg.sender has enough funds for recharge 50 | - Throws an _emitETHBridgeInitiated event 51 | - Call the sendMessage method of the CrossDomainMessenger contract 52 | - CrossDomainMessenger 53 | - In CrossDomainMessenger, the _sendMessage function of L1CrossDomainMessenger will be called. After successful execution, msgNonce will be added. 54 | - L1CrossDomainMessenger 55 | - The _sendMessage of the L1CrossDomainMessenger contract will call the depositTransaction function of OptimismPortal 56 | - depositTransaction will throw TransactionDeposited event 57 | - Op-node and op-geth 58 | - Op-node listens to TransactionDeposited, constructs the Attrs of the recharge transaction, and points op-geth to execute the recharge transaction in L2 59 | - Op-geth will call finalizeDeposit of the L2StandardBridge contract 60 | - L2StandardBridge 61 | - The finalizeBridgeETH function will execute SafeCall.call, causing the position and the recharge process to be completed. 62 | 63 | Note: For ETH recharge, since there is a receive method in OptimismPortal and L1StandardBridge 64 | 65 | -OptimismPortal 66 | ``` 67 | receive() external payable { 68 | depositTransaction(msg.sender, msg.value, RECEIVE_DEFAULT_GAS_LIMIT, false, bytes("")); 69 | } 70 | ``` 71 | 72 | - L1StandardBridge 73 | ``` 74 | receive() external payable override onlyEOA { 75 | _initiateETHDeposit(msg.sender, msg.sender, RECEIVE_DEFAULT_GAS_LIMIT, bytes("")); 76 | } 77 | ``` 78 | 79 | Therefore, directly transferring ETH to OptimismPortal and L1StandardBridge is also an ETH recharge transaction. 80 | 81 | 82 | ## 4.2 ERC20 Deposit 83 | 84 | [![ethdeposit](https://github.com/guoshijiang/how-dose-op-stack-work/blob/main/cdmsg-bridge/images/erc20deposit.png)](https://github.com/guoshijiang/how-dose-op-stack-work) 85 | 86 | -User 87 | - The user calls depositERC20 to recharge his own address, or calls depositERC20To to recharge the specified to address; 88 | - L1StandardBridge 89 | - Whether you call depositERC20 or depositERC20To, you will eventually enter a function _initiateBridgeERC20; 90 | - Determine whether it is OptimismMintableERC20. If so, call the burn method to destroy the token; if not, transfer the token to the bridge and record the funds into the ledger; the ledger code is as follows: 91 | ``` 92 | mapping(address => mapping(address => uint256)) public deposits; 93 | deposits[_localToken][_remoteToken] = deposits[_localToken][_remoteToken] + _amount; 94 | ``` 95 | - Next, call sendMessage of CrossDomainMessenger to send a cross-chain message. After successfully calling the _sendMessage method of L1CrossDomainMessenger, the nonce will be automatically incremented by 1. 96 | - L1CrossDomainMessenger 97 | - _sendMessage will call depositTransaction of OptimismPortal, 98 | - depositTransaction will throw TransactionDeposited event 99 | - Op-node and op-geth 100 | - Op-node listens to TransactionDeposited, constructs the Attrs of the recharge transaction, and points op-geth to execute the recharge transaction in L2 101 | - Op-geth will call finalizeDeposit of the L2StandardBridge contract 102 | - L2StandardBridge 103 | - The finalizeBridgeERC20 function will perform mint Token or token Transfer operations. 104 | - If it is OptimismMintableERC20, perform mint operation 105 | - If it is not OptimismMintableERC20, update the ledger with the following code: 106 | 107 | ``` 108 | mapping(address => mapping(address => uint256)) public deposits; 109 | deposits[_localToken][_remoteToken] = deposits[_localToken][_remoteToken] - _amount; 110 | ``` 111 | 112 | ## 4.3 ERC721 Deposit 113 | 114 | [![ethdeposit](https://github.com/guoshijiang/how-dose-op-stack-work/blob/main/cdmsg-bridge/images/erc721deposit.png)](https://github.com/guoshijiang/how-dose-op-stack-work) 115 | 116 | Regarding the recharge of ERC721, the current logic is fragmented and not completely connected, so I won’t go into details here. 117 | 118 | # 5. L2->L1 withdrawal 119 | 120 | ## 5.1 ETH Withdrawal 121 | 122 | ### 5.1.1 ETH withdrawal transaction to L1 123 | 124 | [![ethdeposit](https://github.com/guoshijiang/how-dose-op-stack-work/blob/main/cdmsg-bridge/images/ethwithdraw.png)](https://github.com/guoshijiang/how-dose-op-stack-work) 125 | 126 | -User 127 | - The user calls withdraw to withdraw coins to his own address, or calls withdrawTo to withdraw money to the specified to address; 128 | - L2StandardBridge 129 | - Both withdraw and withdrawTo will call _initiateWithdrawal; this method will determine whether it is an ETH withdrawal or an ERC20 withdrawal. 130 | - CrossDomainMessenger & L2CrossDomainMessenger 131 | - For ETH withdrawal, enter the _initiateBridgeETH function, which will call the sendMessage method of the CrossDomainMessenger contract. After the logic in the sendMessage method is successful, msgNonce will be incremented by 1, and then the _sendMessage method of the L2CrossDomainMessenger will be called. 132 | -L2ToL1MessagePasser 133 | - After calling the _sendMessage of the L2CrossDomainMessenger contract to the initiateWithdrawal of the L2ToL1MessagePasser, the withdrawal transaction data will be constructed to calculate the withdrawalHash, and the Hash will be set to true in the map data structure. 134 | - msgNonce of maintained L2 is incremented by 1 135 | - Op-node & Op-geth 136 | - The second layer generates withdrawal transactions 137 | - Op-batcher & Op-proposer, the detailed process of Op-batcher and Op-proposer will be introduced later, here is a simple overview 138 | - Op-batch rolls up the withdrawal transaction data to L1 139 | - Op-proposer submits the stateroot of a batch of data related to withdrawal transactions to L1 140 | 141 | ### 5.1.2 ETH Cliam transaction process 142 | 143 | [![ethdeposit](https://github.com/guoshijiang/how-dose-op-stack-work/blob/main/cdmsg-bridge/images/ethcliam.png)](https://github.com/guoshijiang/how-dose-op-stack-work) 144 | 145 | - The user calls the SDK to obtain the status of the withdrawal transaction. If the status is READY_TO_PROVE, it means that the transaction can be proved; the user can call the proveMessage of the SDK to prove the transaction, or directly call the proveWithdrawalTransaction method of the OptimismPortal contract to prove the transaction. When the proof transaction is generated , when the transaction passes the challenge period, the transaction status will change to READY_FOR_RELAY; at this time, the user can call the finalizeMessage method of the SDK to claim funds, or directly call the finalizeWithdrawalTransaction method of the OptimismPortal contract to claim funds. 146 | - Directly calling the contract requires various combination calls, which is more troublesome. It is recommended to use SDK for transaction proof and cliam. 147 | - The picture above is the complete call flow chart using SDK cliam 148 | 149 | ## 5.2 ERC20 Withdrawal 150 | 151 | ### 5.2.1 ERC20 withdrawal transaction to L1 152 | 153 | [![ethdeposit](https://github.com/guoshijiang/how-dose-op-stack-work/blob/main/cdmsg-bridge/images/erc20withdraw.png)](https://github.com/guoshijiang/how-dose-op-stack-work) 154 | 155 | - The difference between the above process and ETH withdrawal is that 156 | - If it is OptimismMintableERC20 contract Token burn 157 | - Otherwise, add the corresponding amount in the deposits ledger and perform token safeTransfer 158 | 159 | ### 5.2.2 ERC20 Cliam transaction process 160 | 161 | [![ethdeposit](https://github.com/guoshijiang/how-dose-op-stack-work/blob/main/cdmsg-bridge/images/erc20cliam.png)](https://github.com/guoshijiang/how-dose-op-stack-work) 162 | 163 | - The difference between the above process and the ETH client is that finalize is changed from finalizeERC20Withdrawal to finalize and the logic in finalizeBridgeERC20 is also inconsistent. 164 | - finalizeBridgeERC20 165 | - If token of type OptimismMintableERC20, mint 166 | - Otherwise, subtract the corresponding amount from the deposits ledger and perform token safeTransfer. 167 | 168 | # 6. Summary 169 | 170 | This section mainly explains the cross-chain calling process of op-stack and the recharge process of ETH and ERC20 Token. In the next lecture, we will explain the rollup process of op-stack in detail. 171 | -------------------------------------------------------------------------------- /cdmsg-bridge/images/a.png: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /cdmsg-bridge/images/erc20cliam.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/the-web3-chain/how-dose-op-stack-work/c40bf36d058337b4c12bfd301103457ae10a7fda/cdmsg-bridge/images/erc20cliam.png -------------------------------------------------------------------------------- /cdmsg-bridge/images/erc20deposit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/the-web3-chain/how-dose-op-stack-work/c40bf36d058337b4c12bfd301103457ae10a7fda/cdmsg-bridge/images/erc20deposit.png -------------------------------------------------------------------------------- /cdmsg-bridge/images/erc20withdraw.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/the-web3-chain/how-dose-op-stack-work/c40bf36d058337b4c12bfd301103457ae10a7fda/cdmsg-bridge/images/erc20withdraw.png -------------------------------------------------------------------------------- /cdmsg-bridge/images/erc721deposit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/the-web3-chain/how-dose-op-stack-work/c40bf36d058337b4c12bfd301103457ae10a7fda/cdmsg-bridge/images/erc721deposit.png -------------------------------------------------------------------------------- /cdmsg-bridge/images/ethcliam.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/the-web3-chain/how-dose-op-stack-work/c40bf36d058337b4c12bfd301103457ae10a7fda/cdmsg-bridge/images/ethcliam.png -------------------------------------------------------------------------------- /cdmsg-bridge/images/ethdeposit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/the-web3-chain/how-dose-op-stack-work/c40bf36d058337b4c12bfd301103457ae10a7fda/cdmsg-bridge/images/ethdeposit.png -------------------------------------------------------------------------------- /cdmsg-bridge/images/ethwithdraw.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/the-web3-chain/how-dose-op-stack-work/c40bf36d058337b4c12bfd301103457ae10a7fda/cdmsg-bridge/images/ethwithdraw.png -------------------------------------------------------------------------------- /cdmsg-bridge/readme.md: -------------------------------------------------------------------------------- 1 | [![English](https://img.shields.io/badge/English-README-blue)](EnglishReadme.md) 2 | 3 | # 深入理解 Op-stack 跨链调用过程及 ETH 和 ERC20 的充值提现 4 | 5 | # 1. 信使合约 6 | 7 | 信使合约的主要功能是跨链通信,核心方法位 sendMessage 与 relayMessage; 8 | 9 | - sendMessage: 将包裹的消息从源链发送到目标链上,维护自增的 msgNonce, 确报跨链消息的唯一性和安全性 10 | - relayMessage: 将源链发过来的消息在目标链上构建 MsgHash 对比,确保消息的一致性之后在目前链上调度执行该消息 11 | 在 op-stack 中在 L1 和 L2 层分别有 12 | - L1CrossDomainMessenger 13 | - L2CrossDomainMessenger 14 | 继承自 CrossDomainMessenger 合约,来承载跨链通信,关于跨链消息合约如何被调用的,在充值,提现章节会有详细的解释。 15 | 16 | # 2. OptimismPortal 17 | 18 | OptimismPortal 合约是 op-stack 的充值提现纽带合约 19 | 20 | ## 2.1 充值 21 | 22 | 充值交易会调用到 depositTransaction; depositTransaction 会抛出 TransactionDeposited 事件,事件里面携带信息如下 23 | emit TransactionDeposited(from, _to, DEPOSIT_VERSION, opaqueData); 24 | op-node 监听到该合约事件之后,会在二层去执行充值交易,关于 op-node 的详细介绍,我们后面会讲到 25 | 26 | ## 2.2 提现 27 | 28 | 对于提现来说,OptimismPortal 会做两件事儿 29 | 30 | - 一是交易证明proveWithdrawalTransaction,将证明通过的交易更新到 31 | mapping(bytes32 => ProvenWithdrawal) public provenWithdrawals 32 | 只要进入到里面都交易表示都是已经经过证明的 33 | 34 | - 另一个是交易 relay transaction 的操作,finalizeWithdrawalTransaction 函数会将 relay 的交易放到 35 | mapping(bytes32 => bool) public finalizedWithdrawals 36 | 只要进入到 finalizedWithdrawals Map里面的交易都证明已经被 relay。 37 | 38 | # 3. Bridge 合约 39 | 40 | 在本节中,我们会把整个桥的上的充值,提现详细的流程图画出来。 41 | 42 | # 4. L1->L2 充值 43 | 44 | ## 4.1 ETH 充值 45 | 46 | [![ethdeposit](https://github.com/guoshijiang/how-dose-op-stack-work/blob/main/cdmsg-bridge/images/ethdeposit.png)](https://github.com/guoshijiang/how-dose-op-stack-work) 47 | 48 | - User 49 | - 用户调用 depositETH 给自己的地址充值,或者调用 depositETHTo 给指定的 to 地址充值; 50 | - L1StandardBridge 51 | - 不管是调用 depositETH 还是 depositETHTo,最终都会进入到一个函数 _initiateETHDeposit;_initiateETHDeposit 里面没有做任何操作,直接调用 _initiateBridgeETH 52 | - 在 _initiateBridgeETH 函数中,会有如下操作 53 | - 判断 msg.sender 是否有足够的资金以供充值 54 | - 抛出一个 _emitETHBridgeInitiated 事件 55 | - 调用 CrossDomainMessenger合约的 sendMessage 方法 56 | - CrossDomainMessenger 57 | - 在 CrossDomainMessenger 里面会去调用 L1CrossDomainMessenger 的 _sendMessage 函数,执行成功之后,msgNonce 会加一下 58 | - L1CrossDomainMessenger 59 | - L1CrossDomainMessenger 合约的 _sendMessage 会去调用 OptimismPortal 的 depositTransaction 函数 60 | - depositTransaction 会抛出 TransactionDeposited 事件 61 | - Op-node 和 op-geth 62 | - Op-node 监听到 TransactionDeposited,会去构建充值交易的 Attrs, 指到 op-geth 在 L2 执行该充值交易 63 | - Op-geth 会去调用 L2StandardBridge 合约的 finalizeDeposit 64 | - L2StandardBridge 65 | - finalizeBridgeETH 函数会去执行 SafeCall.call,导致位置,充值流程就完事儿 66 | 67 | 注意:对于 ETH 充值来说,由于 OptimismPortal 和 L1StandardBridge 里面存在 receive 方法 68 | 69 | - OptimismPortal 70 | 71 | ``` 72 | receive() external payable { 73 | depositTransaction(msg.sender, msg.value, RECEIVE_DEFAULT_GAS_LIMIT, false, bytes("")); 74 | } 75 | ``` 76 | 77 | - L1StandardBridge 78 | 79 | ``` 80 | receive() external payable override onlyEOA { 81 | _initiateETHDeposit(msg.sender, msg.sender, RECEIVE_DEFAULT_GAS_LIMIT, bytes("")); 82 | } 83 | ``` 84 | 85 | 因此,直接把 ETH 转入到 OptimismPortal 和 L1StandardBridge 里面,也属于 ETH 的充值交易 86 | 87 | ## 4.2 ERC20 充值 88 | 89 | [![ethdeposit](https://github.com/guoshijiang/how-dose-op-stack-work/blob/main/cdmsg-bridge/images/erc20deposit.png)](https://github.com/guoshijiang/how-dose-op-stack-work) 90 | 91 | - User 92 | - 用户调用 depositERC20 给自己的地址充值,或者调用 depositERC20To 给指定的 to 地址充值; 93 | - L1StandardBridge 94 | - 不管是调用 depositERC20 还是 depositERC20To,最终都会进入到一个函数 _initiateBridgeERC20; 95 | - 判断是否为 OptimismMintableERC20 ,如果是, 调用 burn 方法销毁 token; 如果不是,将 token 转到桥里面,并将资金记录到账本中;账本代码如下: 96 | 97 | ``` 98 | mapping(address => mapping(address => uint256)) public deposits; 99 | deposits[_localToken][_remoteToken] = deposits[_localToken][_remoteToken] + _amount; 100 | ``` 101 | 102 | - 接下来调用 CrossDomainMessenger 的 sendMessage 发送跨链消息,调用 L1CrossDomainMessenger 的 _sendMessage 方法成功之后,会对 nonce 进行自增加 1 103 | - L1CrossDomainMessenger 104 | - _sendMessage 会去调用 OptimismPortal 的 depositTransaction, 105 | - depositTransaction 会抛出 TransactionDeposited 事件 106 | - Op-node 和 op-geth 107 | - Op-node 监听到 TransactionDeposited,会去构建充值交易的 Attrs, 指到 op-geth 在 L2 执行该充值交易 108 | - Op-geth 会去调用 L2StandardBridge 合约的 finalizeDeposit 109 | - L2StandardBridge 110 | - finalizeBridgeERC20 函数会去执行 mint Token 或者 token Transfer 的操作 111 | - 若是 OptimismMintableERC20,执行 mint 操作 112 | - 若不是 OptimismMintableERC20,更新账本,代码如下: 113 | 114 | ``` 115 | mapping(address => mapping(address => uint256)) public deposits; 116 | deposits[_localToken][_remoteToken] = deposits[_localToken][_remoteToken] - _amount; 117 | ``` 118 | 119 | ## 4.3 ERC721 充值 120 | 121 | [![ethdeposit](https://github.com/guoshijiang/how-dose-op-stack-work/blob/main/cdmsg-bridge/images/erc721deposit.png)](https://github.com/guoshijiang/how-dose-op-stack-work) 122 | 123 | 关于 ERC721 的充值,目前逻辑是断层的,并没有完全关联起来,这里不再做过多的赘述。 124 | 125 | # 5. L2->L1 提现 126 | 127 | ## 5.1 ETH 提现 128 | 129 | ### 5.1.1 ETH 提现交易到 L1 130 | 131 | [![ethdeposit](https://github.com/guoshijiang/how-dose-op-stack-work/blob/main/cdmsg-bridge/images/ethwithdraw.png)](https://github.com/guoshijiang/how-dose-op-stack-work) 132 | 133 | - User 134 | - 用户调用 withdraw 给自己的地址提币,或者调用 withdrawTo 给指定的 to 地址提现; 135 | - L2StandardBridge 136 | - withdraw 和 withdrawTo 都会去 call _initiateWithdrawal; 该方法里面会去判断是 ETH 的提现还是 ERC20 的提现 137 | - CrossDomainMessenger & L2CrossDomainMessenger 138 | - 若是 ETH 提现, 进入 _initiateBridgeETH 函数,该函数会去调用 CrossDomainMessenger 合约的sendMessage 方法,sendMessage 方法里面的逻辑成功后会对 msgNonce 自增 1,然后调用进入到了 L2CrossDomainMessenger 的_sendMessage 方法。 139 | - L2ToL1MessagePasser 140 | - 从 L2CrossDomainMessenger 合约的 _sendMessage 调入到 L2ToL1MessagePasser 的 initiateWithdrawal 之后,会进行提现交易的 data 的构造计算出 withdrawalHash,并将该 Hash 在 map 数据结构设置为 true 141 | - 维护的 L2 的 msgNonce 自增 1 142 | - Op-node & Op-geth 143 | - 二层生成提现交易 144 | - Op-batcher & Op-proposer, 关于 Op-batcher 和 Op-proposer 的详细流程,后面会有介绍,这里就是简单的概述 145 | - Op-batch 把提现交易的数据 rollup 到 L1 146 | - Op-proposer 把提现交易相关的一批次数据的 stateroot 提交到 L1 147 | 148 | ### 5.1.2 ETH Claim 交易流程 149 | 150 | [![ethdeposit](https://github.com/guoshijiang/how-dose-op-stack-work/blob/main/cdmsg-bridge/images/ethcliam.png)](https://github.com/guoshijiang/how-dose-op-stack-work) 151 | 152 | - 用户调用 SDK 获取提现交易的状态,若状态为 READY_TO_PROVE, 说明交易可以进行证明; 用户可以调用 SDK 的 proveMessage 去进行交易的证明,或者直接 call OptimismPortal 合约 proveWithdrawalTransaction 方法进行交易的证明,当证明交易产生之后,等到交易过了挑战期,交易状态会变成 READY_FOR_RELAY;这个时候用户可以调用 SDK 的 finalizeMessage 方法进行资金的 Claim, 也可以直接调用 OptimismPortal 合约的 finalizeWithdrawalTransaction 方法进行资金的 Claim。 153 | - 直接调用合约要进行各种组合调用,比较麻烦,建议用 sdk 进行交易的证明和 Claim 154 | - 上图是使用 SDK Claim 的完整调用流程图 155 | 156 | ## 5.2 ERC20 提现 157 | 158 | ### 5.2.1 ERC20 提现交易到 L1 159 | 160 | [![ethdeposit](https://github.com/guoshijiang/how-dose-op-stack-work/blob/main/cdmsg-bridge/images/erc20withdraw.png)](https://github.com/guoshijiang/how-dose-op-stack-work) 161 | 162 | - 上面流程和 ETH 提现不一样的点是 163 | - 如果是 OptimismMintableERC20 合约 Token burn 164 | - 否则 deposits 账本里面的加上对应的金额,并做 token safeTransfer 165 | 166 | ### 5.2.2 ERC20 Claim 交易流程 167 | 168 | [![ethdeposit](https://github.com/guoshijiang/how-dose-op-stack-work/blob/main/cdmsg-bridge/images/erc20cliam.png)](https://github.com/guoshijiang/how-dose-op-stack-work) 169 | 170 | - 上述流程和 ETH Claim 不一致的就是 finalize 的时将 finalizeERC20Withdrawal 变成了并且 finalizeBridgeERC20 里面的逻辑也不一致 171 | - finalizeBridgeERC20 172 | - 如果 OptimismMintableERC20 类型的 token, mint 173 | - 否则 deposits 账本里面的减去对应的金额,并做 token safeTransfer 174 | 175 | # 6. 小结 176 | 177 | 本节主要讲解了 op-stack 的跨链调用过程以及 ETH 和 ERC20 Token 的充值过程,下一讲我们将详细讲 op-stack 的 rollup 流程。 178 | -------------------------------------------------------------------------------- /derive/EnglishReadme.md: -------------------------------------------------------------------------------- 1 | [![Chinese](https://img.shields.io/badge/Chinese-README-blue)](readme.md) 2 | 3 | 4 | # op-stack derivation process -------------------------------------------------------------------------------- /derive/readme.md: -------------------------------------------------------------------------------- 1 | [![English](https://img.shields.io/badge/English-README-blue)](EnglishReadme.md) 2 | 3 | 4 | # op-stack 推导过程 5 | -------------------------------------------------------------------------------- /optimistim-api/EnglishReadme.md: -------------------------------------------------------------------------------- 1 | [![Chinese](https://img.shields.io/badge/Chinese-README-blue)](README.md) 2 | 3 | 4 | # Optimistim op-node json rpc 5 | 6 | ## 1. Overview 7 | - The default interface after starting the service baseUrl: http://127.0.0.1:7545 8 | 9 | ## 2. Optimism 10 | ### 2.1 Get op-stack version information 11 | #### 2.1.1 optimism_version interface call 12 | - Interface name: optimization_version 13 | - Request method: post 14 | - Request a demonstration: 15 | ``` 16 | { 17 | "jsonrpc":"2.0", 18 | "method":"optimism_syncStatus", 19 | "id":1 20 | } 21 | ``` 22 | - Response demonstration: 23 | ``` 24 | { 25 | "jsonrpc": "2.0", 26 | "id": 1, 27 | "result": "v0.0.0-" 28 | } 29 | ``` 30 | ### 2.1.2 Detailed explanation of optimism_version code process 31 | 32 | Return version directly after calling 33 | 34 | ``` 35 | func (n *nodeAPI) Version(ctx context.Context) (string, error) { 36 | recordDur := n.m.RecordRPCServerRequest("optimism_version") 37 | defer recordDur() 38 | return version.Version + "-" + version.Meta, nil 39 | } 40 | ``` 41 | ``` 42 | var ( 43 | Version = "v0.10.14" 44 | Meta = "dev" 45 | ) 46 | ``` 47 | 48 | ### 2.2 Obtain op-stack rollup configuration information 49 | #### 2.2.1 optimism_rollupConfig interface call 50 | - Interface name: optimization_rollupConfig 51 | - Request method: post 52 | - Request a demonstration: 53 | ``` 54 | { 55 | "jsonrpc":"2.0", 56 | "method":"optimism_rollupConfig", 57 | "id":1 58 | } 59 | ``` 60 | - Response demonstration 61 | ``` 62 | { 63 | "jsonrpc": "2.0", 64 | "id": 1, 65 | "result": { 66 | "genesis": { 67 | "l1": { 68 | "hash": "0xc73a8389a5aaa20922df51c2847cd9385b1b5e0ba679b775f8a2630cd015cd51", 69 | "number": 0 70 | }, 71 | "l2": { 72 | "hash": "0xce549f8a96ab878b17b7f19f770844044d188e5bba6d2ea3a63bae3360745b9c", 73 | "number": 0 74 | }, 75 | "l2_time": 1695096865, 76 | "system_config": { 77 | "batcherAddr": "0x3c44cdddb6a900fa2b585dd299e03d12fa4293bc", 78 | "overhead": "0x000000000000000000000000000000000000000000000000000000000000834", 79 | "scalar": "0x0000000000000000000000000000000000000000000000000000000000f4240", 80 | "gasLimit": 30000000 81 | } 82 | }, 83 | "block_time": 2, 84 | "max_sequencer_drift": 300, 85 | "seq_window_size": 20000, 86 | "channel_timeout": 120, 87 | "l1_chain_id": 900, 88 | "l2_chain_id": 901, 89 | "regolith_time": 0, 90 | "batch_inbox_address": "0xff00000000000000000000000000000000000000", 91 | "deposit_contract_address": "0x6900000000000000000000000000000000000001", 92 | "l1_system_config_address": "0x6900000000000000000000000000000000000009" 93 | } 94 | } 95 | ``` 96 | #### 2.2.2 Detailed explanation of optimism_rollupConfig code process 97 | 98 | `RollupConfig(op-node/node/api.go)`->`n.config(op-node/node/api.go)` 99 | 100 | -The return structure is as follows 101 | ``` 102 | type nodeAPI struct { 103 | config *rollup.Config 104 | client l2EthClient 105 | dr driverClient 106 | log log.Logger 107 | mrpcMetrics 108 | } 109 | ``` 110 | ``` 111 | type Config struct { 112 | // Genesis anchor point of the rollup 113 | Genesis Genesis `json:"genesis"` 114 | // Seconds per L2 block 115 | BlockTime uint64 `json:"block_time"` 116 | // Sequencer batches may not be more than MaxSequencerDrift seconds after 117 | // the L1 timestamp of the sequencing window end. 118 | // 119 | // Note: When L1 has many 1 second consecutive blocks, and L2 grows at fixed 2 seconds, 120 | // the L2 time may still grow beyond this difference. 121 | MaxSequencerDrift uint64 `json:"max_sequencer_drift"` 122 | // Number of epochs (L1 blocks) per sequencing window, including the epoch L1 origin block itself 123 | SeqWindowSize uint64 `json:"seq_window_size"` 124 | // Number of L1 blocks between when a channel can be opened and when it must be closed by. 125 | ChannelTimeout uint64 `json:"channel_timeout"` 126 | // Required to verify L1 signatures 127 | L1ChainID *big.Int `json:"l1_chain_id"` 128 | // Required to identify the L2 network and create p2p signatures unique for this chain. 129 | L2ChainID *big.Int `json:"l2_chain_id"` 130 | 131 | // RegolithTime sets the activation time of the Regolith network-upgrade: 132 | // a pre-mainnet Bedrock change that addresses findings of the Sherlock contest related to deposit attributes. 133 | // "Regolith" is the loose deposited rock that sits on top of Bedrock. 134 | // Active if RegolithTime != nil && L2 block timestamp >= *RegolithTime, inactive otherwise. 135 | RegolithTime *uint64 `json:"regolith_time,omitempty"` 136 | 137 | // Note: below addresses are part of the block-derivation process, 138 | // and required to be the same network-wide to stay in consensus. 139 | 140 | // L1 address that batches are sent to. 141 | BatchInboxAddress common.Address `json:"batch_inbox_address"` 142 | // L1 Deposit Contract Address 143 | DepositContractAddress common.Address `json:"deposit_contract_address"` 144 | // L1 System Config Address 145 | L1SystemConfigAddress common.Address `json:"l1_system_config_address"` 146 | } 147 | ``` 148 | 149 | Note: op-batcher and op-preposer use the information here when they start up. Once the configuration changes, you need to restart op-node, and then restart op-batcher and op-preposer to take effect. 150 | 151 | ### 2.3 Synchronize op-stack Status information 152 | #### 2.3.1 optimism_syncStatus interface call 153 | - Interface name: optimization_syncStatus 154 | - Request method: post 155 | - Request a demonstration: 156 | 157 | ``` 158 | { 159 | "jsonrpc":"2.0", 160 | "method":"optimism_syncStatus", 161 | "id":1 162 | } 163 | ``` 164 | - Response demonstration: 165 | 166 | ``` 167 | { 168 | "jsonrpc": "2.0", 169 | "id": 1, 170 | "result": { 171 | "current_l1": { 172 | "hash": "0x47db9d8d2a9d752dff26e645a8c42108cccc6b778df51253a5d3bad7cbe171b9", 173 | "number": 1622, 174 | "parentHash": "0x589f1d15637dc0f99266e1d3b2d4f21b4672c805c71fc1cae6320dd88c80fcf9", 175 | "timestamp": 1695098493 176 | }, 177 | "current_l1_finalized": { 178 | "hash": "0x0000000000000000000000000000000000000000000000000000000000000000", 179 | "number": 0, 180 | "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", 181 | "timestamp": 0 182 | }, 183 | "head_l1": { 184 | "hash": "0x5f02518f5fcf132eab01f55fee17353b2466eccf26dea5976b56219df9186203", 185 | "number": 7424, 186 | "parentHash": "0x966526a64be988d15a6df49acbfb2b879202616a7c102500bf081598eda9bc53", 187 | "timestamp": 1695109106 188 | }, 189 | "safe_l1": { 190 | "hash": "0x0000000000000000000000000000000000000000000000000000000000000000", 191 | "number": 0, 192 | "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", 193 | "timestamp": 0 194 | }, 195 | "finalized_l1": { 196 | "hash": "0x0000000000000000000000000000000000000000000000000000000000000000", 197 | "number": 0, 198 | "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", 199 | "timestamp": 0 200 | }, 201 | "unsafe_l2": { 202 | "hash": "0x7c6be4624192eee80ede3f4b51206477e9a93b15cb289561744818e39037470a", 203 | "number": 6087, 204 | "parentHash": "0xce518c72d0d02d3e160ec26e698342ce7bf8e5bbf8de84f2e61d01a63b04080c", 205 | "timestamp": 1695109039, 206 | "l1origin": { 207 | "hash": "0xe11512ebdc88d836efd750a51ace6b404966af90c34ef19759aaa1bee700568a", 208 | "number": 5268 209 | }, 210 | "sequenceNumber": 0 211 | }, 212 | "safe_l2": { 213 | "hash": "0xaa8fb7e1b2d871d56e935eeaa78eb8039646fde50b500a3f315b14f900f8280b", 214 | "number": 807, 215 | "parentHash": "0xaa8b6ba2420fdb8568ce9eccf76e46dd45ab186e050be294051cbb25e553cc9c", 216 | "timestamp": 1695098479, 217 | "l1origin": { 218 | "hash": "0x9b1ca8527f379c863639eb524f048e6fdae259c932fee5021853af05c2288256", 219 | "number": 804 220 | }, 221 | "sequenceNumber": 0 222 | }, 223 | "finalized_l2": { 224 | "hash": "0xce549f8a96ab878b17b7f19f770844044d188e5bba6d2ea3a63bae3360745b9c", 225 | "number": 0, 226 | "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", 227 | "timestamp": 1695096865, 228 | "l1origin": { 229 | "hash": "0xc73a8389a5aaa20922df51c2847cd9385b1b5e0ba679b775f8a2630cd015cd51", 230 | "number": 0 231 | }, 232 | "sequenceNumber": 0 233 | }, 234 | "queued_unsafe_l2": { 235 | "hash": "0x0000000000000000000000000000000000000000000000000000000000000000", 236 | "number": 0, 237 | "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", 238 | "timestamp": 0, 239 | "l1origin": { 240 | "hash": "0x0000000000000000000000000000000000000000000000000000000000000000", 241 | "number": 0 242 | }, 243 | "sequenceNumber": 0 244 | } 245 | } 246 | } 247 | ``` 248 | 249 | #### 2.3.2 Detailed explanation of optimism_syncStatus code flow 250 | `SyncStatus(op-node/node/api.go)`-> `SyncStatus(op-node/rollup/driver/state.go)`->`syncStatus(op-node/rollup/driver/state.go)` 251 | 252 | The code return structure is as follows: 253 | 254 | ``` 255 | return ð.SyncStatus{ 256 | CurrentL1: s.derivation.Origin(), 257 | CurrentL1Finalized: s.derivation.FinalizedL1(), 258 | HeadL1: s.l1State.L1Head(), 259 | SafeL1: s.l1State.L1Safe(), 260 | FinalizedL1: s.l1State.L1Finalized(), 261 | UnsafeL2: s.derivation.UnsafeL2Head(), 262 | SafeL2: s.derivation.SafeL2Head(), 263 | FinalizedL2: s.derivation.Finalized(), 264 | UnsafeL2SyncTarget: s.derivation.UnsafeL2SyncTarget(), 265 | } 266 | ``` 267 | We can see that the return value contains the current unsafe, safe and finalized block information of L1 and L2. This interface is also used in the rollup service to obtain the currently submitted blocks (safe status) and L2 Block information that has been generated but not submitted (unSafe status). 268 | 269 | ### 2.4 Get op-stack state root output information 270 | #### 2.4.1 optimism_outputAtBlock interface call 271 | - Interface name: optimization_outputAtBlock 272 | - Request method: post 273 | - Request a demonstration: 274 | ``` 275 | { 276 | "jsonrpc":"2.0", 277 | "method":"optimism_outputAtBlock", 278 | "params":["0xa"], 279 | "id":1 280 | } 281 | ``` 282 | - Response demonstration: 283 | 284 | ``` 285 | { 286 | "jsonrpc": "2.0", 287 | "id": 1, 288 | "result": { 289 | "version": "0x0000000000000000000000000000000000000000000000000000000000000000", 290 | "outputRoot": "0xa320665d67f71b761f7e65ef065a71e7b2015772f24ac959107b31b540b5c79e", 291 | "blockRef": { 292 | "hash": "0x364cd42fe675acc76f5acee58ec3d05422036078025ae7edf387736fa2fc4c77", 293 | "number": 10, 294 | "parentHash": "0x5dad8149226b0468e6a9f4e676e448e9f0f0cf7ed904f18456635d8dda5ba126", 295 | "timestamp": 1695096885, 296 | "l1origin": { 297 | "hash": "0xff0ea2db97724942684bcac3323a7f816a46b36ef81d912308a11362ef1c65d5", 298 | "number": 7 299 | }, 300 | "sequenceNumber": 0 301 | }, 302 | "withdrawalStorageRoot": "0x8ed4baae3a927be3dea54996b4d5899f8c01e7594bf50b17dc1e741388ce3d12", 303 | "stateRoot": "0x5c0b4a5eca962019c26d35de246af89e6f4c5ae84f1e1ea7322b378d07356c52", 304 | "syncStatus": { 305 | "current_l1": { 306 | "hash": "0xbd057f40bc82e5a36c488034921aefe69cf99ee2277b57cdc4bb0c7fe719e010", 307 | "number": 18194, 308 | "parentHash": "0x80cb8a14f8616f9300a3ef3e6a9b330693106d29e0289928f47d69b8a29de583", 309 | "timestamp": 1695120804 310 | }, 311 | "current_l1_finalized": { 312 | "hash": "0x0000000000000000000000000000000000000000000000000000000000000000", 313 | "number": 0, 314 | "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", 315 | "timestamp": 0 316 | }, 317 | "head_l1": { 318 | "hash": "0xe2dd477086d7abac9c3a0a4cb89c14935111ae6fd244a6fabe1a343bd8fb0b4a", 319 | "number": 18206, 320 | "parentHash": "0x1d54677e3ce73e4fdba1197479bcd6ac325b91bbbc1dec16a868f3d86564048e", 321 | "timestamp": 1695120816 322 | }, 323 | "safe_l1": { 324 | "hash": "0x0000000000000000000000000000000000000000000000000000000000000000", 325 | "number": 0, 326 | "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", 327 | "timestamp": 0 328 | }, 329 | "finalized_l1": { 330 | "hash": "0x0000000000000000000000000000000000000000000000000000000000000000", 331 | "number": 0, 332 | "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", 333 | "timestamp": 0 334 | }, 335 | "unsafe_l2": { 336 | "hash": "0x168541a09e0c3cd04b5fef3e5857461fe5d4b861c7266a9b8a560f2ff6380d7c", 337 | "number": 11975, 338 | "parentHash": "0xf5cb4a16f0dc3c60b4f79fe03e2c6be71db708fc3a1053cbf66c981389a8e12c", 339 | "timestamp": 1695120815, 340 | "l1origin": { 341 | "hash": "0x6c6d3ea564dc2ac69b506da8f11349347a897431ae52d43f4dd65c0912dc6455", 342 | "number": 11156 343 | }, 344 | "sequenceNumber": 0 345 | }, 346 | "safe_l2": { 347 | "hash": "0xb7091f5916ada4302b3c3bbdc2df423ef26a134c54d0e96a22e7e79fe15dab20", 348 | "number": 10414, 349 | "parentHash": "0x08b2c1921606afba1e7d1b35f75638018947e9f5caa5f513c076c78be02fb7e1", 350 | "timestamp": 1695117693, 351 | "l1origin": { 352 | "hash": "0xd27bee73396cdf7dd5d107b9833bd4986943b1604e978e866022fd7ebb285431", 353 | "number": 9595 354 | }, 355 | "sequenceNumber": 0 356 | }, 357 | "finalized_l2": { 358 | "hash": "0xce549f8a96ab878b17b7f19f770844044d188e5bba6d2ea3a63bae3360745b9c", 359 | "number": 0, 360 | "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", 361 | "timestamp": 1695096865, 362 | "l1origin": { 363 | "hash": "0xc73a8389a5aaa20922df51c2847cd9385b1b5e0ba679b775f8a2630cd015cd51", 364 | "number": 0 365 | }, 366 | "sequenceNumber": 0 367 | }, 368 | "queued_unsafe_l2": { 369 | "hash": "0x0000000000000000000000000000000000000000000000000000000000000000", 370 | "number": 0, 371 | "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", 372 | "timestamp": 0, 373 | "l1origin": { 374 | "hash": "0x0000000000000000000000000000000000000000000000000000000000000000", 375 | "number": 0 376 | }, 377 | "sequenceNumber": 0 378 | } 379 | } 380 | } 381 | } 382 | ``` 383 | 384 | #### 2.4.2 optimism_outputAtBlock 代码流程详解 385 | 386 | [![ethdeposit](https://github.com/guoshijiang/how-dose-op-stack-work/blob/main/optimistim-api/op-node-api1.png)](https://github.com/guoshijiang/how-dose-op-stack-work) 387 | 388 | Op-stack wrote the following code in the GetProof method of op-geth 389 | 390 | ``` 391 | if s.b.ChainConfig().IsOptimismPreBedrock(header.Number) { 392 | if s.b.HistoricalRPCService() != nil { 393 | var res AccountResult 394 | err := s.b.HistoricalRPCService().CallContext(ctx, &res, "eth_getProof", address, storageKeys, blockNrOrHash) 395 | if err != nil { 396 | return nil, fmt.Errorf("historical backend error: %w", err) 397 | } 398 | return &res, nil 399 | } else { 400 | return nil, rpc.ErrNoHistoricalFallback 401 | } 402 | } 403 | ``` 404 | 405 | Here, the passed address will eventually be returned to the Proof of the account of the corresponding block. The code is as follows: 406 | 407 | ``` 408 | // Result structs for GetProof 409 | type AccountResult struct { 410 | Address common.Address `json:"address"` 411 | AccountProof []string `json:"accountProof"` 412 | Balance *hexutil.Big `json:"balance"` 413 | CodeHash common.Hash `json:"codeHash"` 414 | Nonce hexutil.Uint64 `json:"nonce"` 415 | StorageHash common.Hash `json:"storageHash"` 416 | StorageProof []StorageResult `json:"storageProof"` 417 | } 418 | ``` 419 | 420 | When we trace the code process, we can find that the address passed here is the address of the L2ToL1MessagePasserAddr pre-deployment contract, which means that the final generated stateroot is the state root based on an Account proof of L2ToL1MessagePasserAddr. 421 | 422 | op-proposer Fetching the submitted stateroot is implemented through this interface. 423 | 424 | ## 3.Admin 425 | ### 3.1 Start seqeuencer 426 | #### 3.1.1 admin_startSequencer interface call 427 | - Interface name: admin_startSequencer 428 | - Request method: post 429 | - Request a demonstration: 430 | ``` 431 | ``` 432 | - Response demonstration: 433 | ``` 434 | ``` 435 | 436 | #### 3.1.2 Detailed explanation of admin_startSequencer code process 437 | 438 | ### 3.2 Stop seqeuencer 439 | #### 3.2.1 admin_stopSequencer interface call 440 | - Interface name: admin_stopSequencer 441 | - Request method: post 442 | - Request a demonstration: 443 | ``` 444 | ``` 445 | 446 | - Response demonstration: 447 | ``` 448 | ``` 449 | 450 | #### 3.2.2 Detailed explanation of admin_stopSequencer code flow 451 | 452 | ### 3.3 Reset the derivation process 453 | #### 3.3.1 admin_resetDerivationPipeline interface call 454 | - Interface name: admin_resetDerivationPipeline 455 | - Request method: post 456 | - Request a demonstration: 457 | ``` 458 | ``` 459 | 460 | - Response demonstration: 461 | ``` 462 | ``` 463 | 464 | #### 3.3.2 Detailed explanation of admin_resetDerivationPipeline code process -------------------------------------------------------------------------------- /optimistim-api/README.md: -------------------------------------------------------------------------------- 1 | [![English](https://img.shields.io/badge/English-README-blue)](EnglishReadme.md) 2 | 3 | 4 | # Optimistim op-node json rpc 5 | 6 | ## 1. 概述 7 | - 启动服务之后默认接口 baseUrl: http://127.0.0.1:7545 8 | 9 | ## 2. Optimism 10 | ### 2.1 获取 op-stack 版本信息 11 | #### 2.1.1 optimism_version 接口调用 12 | - 接口名称:optimism_version 13 | - 请求方式:post 14 | - 请求示范: 15 | ``` 16 | { 17 | "jsonrpc":"2.0", 18 | "method":"optimism_syncStatus", 19 | "id":1 20 | } 21 | ``` 22 | - 响应示范: 23 | ``` 24 | { 25 | "jsonrpc": "2.0", 26 | "id": 1, 27 | "result": "v0.0.0-" 28 | } 29 | ``` 30 | ### 2.1.2 optimism_version 代码流程详解 31 | 32 | 调用之后直接返回 version 33 | 34 | ``` 35 | func (n *nodeAPI) Version(ctx context.Context) (string, error) { 36 | recordDur := n.m.RecordRPCServerRequest("optimism_version") 37 | defer recordDur() 38 | return version.Version + "-" + version.Meta, nil 39 | } 40 | ``` 41 | ``` 42 | var ( 43 | Version = "v0.10.14" 44 | Meta = "dev" 45 | ) 46 | ``` 47 | 48 | ### 2.2 获取 op-stack rollup 配置信息 49 | #### 2.2.1 optimism_rollupConfig 接口调用 50 | - 接口名称:optimism_rollupConfig 51 | - 请求方式:post 52 | - 请求示范: 53 | ``` 54 | { 55 | "jsonrpc":"2.0", 56 | "method":"optimism_rollupConfig", 57 | "id":1 58 | } 59 | ``` 60 | - 响应示范 61 | ``` 62 | { 63 | "jsonrpc": "2.0", 64 | "id": 1, 65 | "result": { 66 | "genesis": { 67 | "l1": { 68 | "hash": "0xc73a8389a5aaa20922df51c2847cd9385b1b5e0ba679b775f8a2630cd015cd51", 69 | "number": 0 70 | }, 71 | "l2": { 72 | "hash": "0xce549f8a96ab878b17b7f19f770844044d188e5bba6d2ea3a63bae3360745b9c", 73 | "number": 0 74 | }, 75 | "l2_time": 1695096865, 76 | "system_config": { 77 | "batcherAddr": "0x3c44cdddb6a900fa2b585dd299e03d12fa4293bc", 78 | "overhead": "0x0000000000000000000000000000000000000000000000000000000000000834", 79 | "scalar": "0x00000000000000000000000000000000000000000000000000000000000f4240", 80 | "gasLimit": 30000000 81 | } 82 | }, 83 | "block_time": 2, 84 | "max_sequencer_drift": 300, 85 | "seq_window_size": 20000, 86 | "channel_timeout": 120, 87 | "l1_chain_id": 900, 88 | "l2_chain_id": 901, 89 | "regolith_time": 0, 90 | "batch_inbox_address": "0xff00000000000000000000000000000000000000", 91 | "deposit_contract_address": "0x6900000000000000000000000000000000000001", 92 | "l1_system_config_address": "0x6900000000000000000000000000000000000009" 93 | } 94 | } 95 | ``` 96 | #### 2.2.2 optimism_rollupConfig 代码流程详解 97 | 98 | `RollupConfig(op-node/node/api.go)`->`n.config(op-node/node/api.go)` 99 | 100 | - 返回结构如下 101 | ``` 102 | type nodeAPI struct { 103 | config *rollup.Config 104 | client l2EthClient 105 | dr driverClient 106 | log log.Logger 107 | m rpcMetrics 108 | } 109 | ``` 110 | ``` 111 | type Config struct { 112 | // Genesis anchor point of the rollup 113 | Genesis Genesis `json:"genesis"` 114 | // Seconds per L2 block 115 | BlockTime uint64 `json:"block_time"` 116 | // Sequencer batches may not be more than MaxSequencerDrift seconds after 117 | // the L1 timestamp of the sequencing window end. 118 | // 119 | // Note: When L1 has many 1 second consecutive blocks, and L2 grows at fixed 2 seconds, 120 | // the L2 time may still grow beyond this difference. 121 | MaxSequencerDrift uint64 `json:"max_sequencer_drift"` 122 | // Number of epochs (L1 blocks) per sequencing window, including the epoch L1 origin block itself 123 | SeqWindowSize uint64 `json:"seq_window_size"` 124 | // Number of L1 blocks between when a channel can be opened and when it must be closed by. 125 | ChannelTimeout uint64 `json:"channel_timeout"` 126 | // Required to verify L1 signatures 127 | L1ChainID *big.Int `json:"l1_chain_id"` 128 | // Required to identify the L2 network and create p2p signatures unique for this chain. 129 | L2ChainID *big.Int `json:"l2_chain_id"` 130 | 131 | // RegolithTime sets the activation time of the Regolith network-upgrade: 132 | // a pre-mainnet Bedrock change that addresses findings of the Sherlock contest related to deposit attributes. 133 | // "Regolith" is the loose deposited rock that sits on top of Bedrock. 134 | // Active if RegolithTime != nil && L2 block timestamp >= *RegolithTime, inactive otherwise. 135 | RegolithTime *uint64 `json:"regolith_time,omitempty"` 136 | 137 | // Note: below addresses are part of the block-derivation process, 138 | // and required to be the same network-wide to stay in consensus. 139 | 140 | // L1 address that batches are sent to. 141 | BatchInboxAddress common.Address `json:"batch_inbox_address"` 142 | // L1 Deposit Contract Address 143 | DepositContractAddress common.Address `json:"deposit_contract_address"` 144 | // L1 System Config Address 145 | L1SystemConfigAddress common.Address `json:"l1_system_config_address"` 146 | } 147 | ``` 148 | 149 | 注意:op-batcher 和 op-preposer 启动的时候使用到这里面的信息,一旦配置发生改变,需要重新启动 op-node, 然后再重启 op-batcher 和 op-preposer 之后才能生效。 150 | 151 | ### 2.3 同步 op-stack Status 信息 152 | #### 2.3.1 optimism_syncStatus 接口调用 153 | - 接口名称:optimism_syncStatus 154 | - 请求方式:post 155 | - 请求示范: 156 | 157 | ``` 158 | { 159 | "jsonrpc":"2.0", 160 | "method":"optimism_syncStatus", 161 | "id":1 162 | } 163 | ``` 164 | - 响应示范: 165 | 166 | ``` 167 | { 168 | "jsonrpc": "2.0", 169 | "id": 1, 170 | "result": { 171 | "current_l1": { 172 | "hash": "0x47db9d8d2a9d752dff26e645a8c42108cccc6b778df51253a5d3bad7cbe171b9", 173 | "number": 1622, 174 | "parentHash": "0x589f1d15637dc0f99266e1d3b2d4f21b4672c805c71fc1cae6320dd88c80fcf9", 175 | "timestamp": 1695098493 176 | }, 177 | "current_l1_finalized": { 178 | "hash": "0x0000000000000000000000000000000000000000000000000000000000000000", 179 | "number": 0, 180 | "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", 181 | "timestamp": 0 182 | }, 183 | "head_l1": { 184 | "hash": "0x5f02518f5fcf132eab01f55fee17353b2466eccf26dea5976b56219df9186203", 185 | "number": 7424, 186 | "parentHash": "0x966526a64be988d15a6df49acbfb2b879202616a7c102500bf081598eda9bc53", 187 | "timestamp": 1695109106 188 | }, 189 | "safe_l1": { 190 | "hash": "0x0000000000000000000000000000000000000000000000000000000000000000", 191 | "number": 0, 192 | "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", 193 | "timestamp": 0 194 | }, 195 | "finalized_l1": { 196 | "hash": "0x0000000000000000000000000000000000000000000000000000000000000000", 197 | "number": 0, 198 | "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", 199 | "timestamp": 0 200 | }, 201 | "unsafe_l2": { 202 | "hash": "0x7c6be4624192eee80ede3f4b51206477e9a93b15cb289561744818e39037470a", 203 | "number": 6087, 204 | "parentHash": "0xce518c72d0d02d3e160ec26e698342ce7bf8e5bbf8de84f2e61d01a63b04080c", 205 | "timestamp": 1695109039, 206 | "l1origin": { 207 | "hash": "0xe11512ebdc88d836efd750a51ace6b404966af90c34ef19759aaa1bee700568a", 208 | "number": 5268 209 | }, 210 | "sequenceNumber": 0 211 | }, 212 | "safe_l2": { 213 | "hash": "0xaa8fb7e1b2d871d56e935eeaa78eb8039646fde50b500a3f315b14f900f8280b", 214 | "number": 807, 215 | "parentHash": "0xaa8b6ba2420fdb8568ce9eccf76e46dd45ab186e050be294051cbb25e553cc9c", 216 | "timestamp": 1695098479, 217 | "l1origin": { 218 | "hash": "0x9b1ca8527f379c863639eb524f048e6fdae259c932fee5021853af05c2288256", 219 | "number": 804 220 | }, 221 | "sequenceNumber": 0 222 | }, 223 | "finalized_l2": { 224 | "hash": "0xce549f8a96ab878b17b7f19f770844044d188e5bba6d2ea3a63bae3360745b9c", 225 | "number": 0, 226 | "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", 227 | "timestamp": 1695096865, 228 | "l1origin": { 229 | "hash": "0xc73a8389a5aaa20922df51c2847cd9385b1b5e0ba679b775f8a2630cd015cd51", 230 | "number": 0 231 | }, 232 | "sequenceNumber": 0 233 | }, 234 | "queued_unsafe_l2": { 235 | "hash": "0x0000000000000000000000000000000000000000000000000000000000000000", 236 | "number": 0, 237 | "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", 238 | "timestamp": 0, 239 | "l1origin": { 240 | "hash": "0x0000000000000000000000000000000000000000000000000000000000000000", 241 | "number": 0 242 | }, 243 | "sequenceNumber": 0 244 | } 245 | } 246 | } 247 | ``` 248 | 249 | #### 2.3.2 optimism_syncStatus 代码流程详解 250 | `SyncStatus(op-node/node/api.go)`-> `SyncStatus(op-node/rollup/driver/state.go)`->`syncStatus(op-node/rollup/driver/state.go)` 251 | 252 | 代码返回结构如下: 253 | 254 | ``` 255 | return ð.SyncStatus{ 256 | CurrentL1: s.derivation.Origin(), 257 | CurrentL1Finalized: s.derivation.FinalizedL1(), 258 | HeadL1: s.l1State.L1Head(), 259 | SafeL1: s.l1State.L1Safe(), 260 | FinalizedL1: s.l1State.L1Finalized(), 261 | UnsafeL2: s.derivation.UnsafeL2Head(), 262 | SafeL2: s.derivation.SafeL2Head(), 263 | FinalizedL2: s.derivation.Finalized(), 264 | UnsafeL2SyncTarget: s.derivation.UnsafeL2SyncTarget(), 265 | } 266 | ``` 267 | 268 | 我们可以看到返回值里面包含了 L1 和 L2 当前的 unsafe, safe 和 finalized 的区块信息,这个接口也在 rollup 服务中被用到,用于获取目前已提交的区块(safe 状态) 和 L2 已出块未提交(unSafe 状态)的区块信息。 269 | 270 | ### 2.4 获取 op-stack state root 输出信息 271 | #### 2.4.1 optimism_outputAtBlock 接口调用 272 | - 接口名称:optimism_outputAtBlock 273 | - 请求方式:post 274 | - 请求示范: 275 | ``` 276 | { 277 | "jsonrpc":"2.0", 278 | "method":"optimism_outputAtBlock", 279 | "params":["0xa"], 280 | "id":1 281 | } 282 | ``` 283 | - 响应示范: 284 | 285 | ``` 286 | { 287 | "jsonrpc": "2.0", 288 | "id": 1, 289 | "result": { 290 | "version": "0x0000000000000000000000000000000000000000000000000000000000000000", 291 | "outputRoot": "0xa320665d67f71b761f7e65ef065a71e7b2015772f24ac959107b31b540b5c79e", 292 | "blockRef": { 293 | "hash": "0x364cd42fe675acc76f5acee58ec3d05422036078025ae7edf387736fa2fc4c77", 294 | "number": 10, 295 | "parentHash": "0x5dad8149226b0468e6a9f4e676e448e9f0f0cf7ed904f18456635d8dda5ba126", 296 | "timestamp": 1695096885, 297 | "l1origin": { 298 | "hash": "0xff0ea2db97724942684bcac3323a7f816a46b36ef81d912308a11362ef1c65d5", 299 | "number": 7 300 | }, 301 | "sequenceNumber": 0 302 | }, 303 | "withdrawalStorageRoot": "0x8ed4baae3a927be3dea54996b4d5899f8c01e7594bf50b17dc1e741388ce3d12", 304 | "stateRoot": "0x5c0b4a5eca962019c26d35de246af89e6f4c5ae84f1e1ea7322b378d07356c52", 305 | "syncStatus": { 306 | "current_l1": { 307 | "hash": "0xbd057f40bc82e5a36c488034921aefe69cf99ee2277b57cdc4bb0c7fe719e010", 308 | "number": 18194, 309 | "parentHash": "0x80cb8a14f8616f9300a3ef3e6a9b330693106d29e0289928f47d69b8a29de583", 310 | "timestamp": 1695120804 311 | }, 312 | "current_l1_finalized": { 313 | "hash": "0x0000000000000000000000000000000000000000000000000000000000000000", 314 | "number": 0, 315 | "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", 316 | "timestamp": 0 317 | }, 318 | "head_l1": { 319 | "hash": "0xe2dd477086d7abac9c3a0a4cb89c14935111ae6fd244a6fabe1a343bd8fb0b4a", 320 | "number": 18206, 321 | "parentHash": "0x1d54677e3ce73e4fdba1197479bcd6ac325b91bbbc1dec16a868f3d86564048e", 322 | "timestamp": 1695120816 323 | }, 324 | "safe_l1": { 325 | "hash": "0x0000000000000000000000000000000000000000000000000000000000000000", 326 | "number": 0, 327 | "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", 328 | "timestamp": 0 329 | }, 330 | "finalized_l1": { 331 | "hash": "0x0000000000000000000000000000000000000000000000000000000000000000", 332 | "number": 0, 333 | "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", 334 | "timestamp": 0 335 | }, 336 | "unsafe_l2": { 337 | "hash": "0x168541a09e0c3cd04b5fef3e5857461fe5d4b861c7266a9b8a560f2ff6380d7c", 338 | "number": 11975, 339 | "parentHash": "0xf5cb4a16f0dc3c60b4f79fe03e2c6be71db708fc3a1053cbf66c981389a8e12c", 340 | "timestamp": 1695120815, 341 | "l1origin": { 342 | "hash": "0x6c6d3ea564dc2ac69b506da8f11349347a897431ae52d43f4dd65c0912dc6455", 343 | "number": 11156 344 | }, 345 | "sequenceNumber": 0 346 | }, 347 | "safe_l2": { 348 | "hash": "0xb7091f5916ada4302b3c3bbdc2df423ef26a134c54d0e96a22e7e79fe15dab20", 349 | "number": 10414, 350 | "parentHash": "0x08b2c1921606afba1e7d1b35f75638018947e9f5caa5f513c076c78be02fb7e1", 351 | "timestamp": 1695117693, 352 | "l1origin": { 353 | "hash": "0xd27bee73396cdf7dd5d107b9833bd4986943b1604e978e866022fd7ebb285431", 354 | "number": 9595 355 | }, 356 | "sequenceNumber": 0 357 | }, 358 | "finalized_l2": { 359 | "hash": "0xce549f8a96ab878b17b7f19f770844044d188e5bba6d2ea3a63bae3360745b9c", 360 | "number": 0, 361 | "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", 362 | "timestamp": 1695096865, 363 | "l1origin": { 364 | "hash": "0xc73a8389a5aaa20922df51c2847cd9385b1b5e0ba679b775f8a2630cd015cd51", 365 | "number": 0 366 | }, 367 | "sequenceNumber": 0 368 | }, 369 | "queued_unsafe_l2": { 370 | "hash": "0x0000000000000000000000000000000000000000000000000000000000000000", 371 | "number": 0, 372 | "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", 373 | "timestamp": 0, 374 | "l1origin": { 375 | "hash": "0x0000000000000000000000000000000000000000000000000000000000000000", 376 | "number": 0 377 | }, 378 | "sequenceNumber": 0 379 | } 380 | } 381 | } 382 | } 383 | ``` 384 | 385 | #### 2.4.2 optimism_outputAtBlock 代码流程详解 386 | 387 | [![ethdeposit](https://github.com/guoshijiang/how-dose-op-stack-work/blob/main/optimistim-api/op-node-api1.png)](https://github.com/guoshijiang/how-dose-op-stack-work) 388 | 389 | Op-stack 在 op-geth 的 GetProof 方法里面 写了如下代码 390 | 391 | ``` 392 | if s.b.ChainConfig().IsOptimismPreBedrock(header.Number) { 393 | if s.b.HistoricalRPCService() != nil { 394 | var res AccountResult 395 | err := s.b.HistoricalRPCService().CallContext(ctx, &res, "eth_getProof", address, storageKeys, blockNrOrHash) 396 | if err != nil { 397 | return nil, fmt.Errorf("historical backend error: %w", err) 398 | } 399 | return &res, nil 400 | } else { 401 | return nil, rpc.ErrNoHistoricalFallback 402 | } 403 | } 404 | ``` 405 | 406 | 这里最终会返回传人的地址到对应块的 account 的 Proof, 代码如下: 407 | 408 | ``` 409 | // Result structs for GetProof 410 | type AccountResult struct { 411 | Address common.Address `json:"address"` 412 | AccountProof []string `json:"accountProof"` 413 | Balance *hexutil.Big `json:"balance"` 414 | CodeHash common.Hash `json:"codeHash"` 415 | Nonce hexutil.Uint64 `json:"nonce"` 416 | StorageHash common.Hash `json:"storageHash"` 417 | StorageProof []StorageResult `json:"storageProof"` 418 | } 419 | ``` 420 | 421 | 我们追踪代码流程可以发现这里传入的地址是 L2ToL1MessagePasserAddr 预部署合约的地址,也就是是最终生成出来的 stateroot 是基于 L2ToL1MessagePasserAddr 一个 Account proof 的 state root。 422 | 423 | op-proposer 抓取提交的 stateroot 就是通过该接口实现的。 424 | 425 | ## 3. Admin 426 | ### 3.1 启动 seqeuencer 427 | #### 3.1.1 admin_startSequencer 接口调用 428 | - 接口名称:admin_startSequencer 429 | - 请求方式:post 430 | - 请求示范: 431 | ``` 432 | ``` 433 | - 响应示范: 434 | ``` 435 | ``` 436 | 437 | #### 3.1.2 admin_startSequencer 代码流程详解 438 | 439 | ### 3.2 停止 seqeuencer 440 | #### 3.2.1 admin_stopSequencer 接口调用 441 | - 接口名称:admin_stopSequencer 442 | - 请求方式:post 443 | - 请求示范: 444 | ``` 445 | ``` 446 | 447 | - 响应示范: 448 | ``` 449 | ``` 450 | 451 | #### 3.2.2 admin_stopSequencer 代码流程详解 452 | 453 | ### 3.3 重置推导流程 454 | #### 3.3.1 admin_resetDerivationPipeline 接口调用 455 | - 接口名称:admin_resetDerivationPipeline 456 | - 请求方式:post 457 | - 请求示范: 458 | ``` 459 | ``` 460 | 461 | - 响应示范: 462 | ``` 463 | ``` 464 | 465 | #### 3.3.2 admin_resetDerivationPipeline 代码流程详解 466 | 467 | -------------------------------------------------------------------------------- /optimistim-api/op-node-api1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/the-web3-chain/how-dose-op-stack-work/c40bf36d058337b4c12bfd301103457ae10a7fda/optimistim-api/op-node-api1.png -------------------------------------------------------------------------------- /rollup/EnglishReadme.md: -------------------------------------------------------------------------------- 1 | [![Chinese](https://img.shields.io/badge/Chinese-README-blue)](README.md) 2 | 3 | 4 | # Detailed explanation of Op-stack rollup process 5 | 6 | ## 1. Overview 7 | 8 | The rollup of Op-stack is undertaken by two services 9 | - op-batcher service: its main responsibility is to submit transaction data to the EOA address of Layer1 10 | - op-proposer service: its main responsibility is to submit the transaction status to the L2OutputOracle contract of Layer1 11 | 12 | ## 2.Rollup architecture 13 | 14 | [![rollup_art](https://github.com/guoshijiang/how-dose-op-stack-work/blob/main/rollup/rollup_art.png)](https://github.com/guoshijiang/how-dose-op-stack-work) 15 | 16 | ## 3.op-batcher 17 | 18 | ### 3.1 Execution flow chart 19 | 20 | [![op-batcher](https://github.com/guoshijiang/how-dose-op-stack-work/blob/main/rollup/op-batcher/op-batcher.png)](https://github.com/guoshijiang/how-dose-op-stack-work) 21 | 22 | ### 3.2 Detailed execution process 23 | - loadBlocksIntoState will execute the following logic 24 | - calculateL2BlockRangeToStore obtains and determines the start and end block numbers of the latest L2 that need to be submitted. The starting block is the highest current safe block of L2; the end block is the highest current unsafe block of L2. 25 | - After getting the submitted start block and end block, get the block information starting from the start block, and call the AddL2Block function to add the block to blocks []*types.Block of channelManager. 26 | - Call the block returned by the loadBlockIntoState function to verify whether the block needs to be resubmitted. If necessary, set l.lastStoredBlock to eth.BlockID{}; otherwise, set l.lastStoredBlock to eth.ToBlockID(block); set latestBlock into block; 27 | - L2BlockToBlockRef extracts basic L2BlockRef information from the L2 block reference source, and falls back to the creation information if necessary based on the block number. 28 | - The publishStateToL1 method will perform some logic 29 | - The publishTxToL1 method obtains the data to be submitted, constructs a transaction and sends it to the Layer1 network, and throws the sent transaction into the receiptCh chan TxReceipt[T] channel. 30 | - l1Tip: Get the current L1 tip as L1BlockRef. The passed context is assumed to be a lifecycle context, so it is wrapped internally with a network timeout. 31 | - recordL1Tip: Replace the previous L1BlockRef with the latest L1BlockRef obtained by l1Tip 32 | - TxData: Collect transaction data that requires rollup; TxData returns the next tx data that should be submitted to L1. Currently, only one frame is used per transaction. If a pending channel is full, only the remaining frames for that channel are returned until successfully fully transmitted to L1. If there are no pending frames, it returns io.EOF. 33 | - nextTxData: If there are pending frames or the channel manager is closed, collect the submitted data from the channel and return it 34 | - NextTxData: Read transaction data from channel, record transaction data to pendingTransactions and return 35 | - NextFrame: Returns the next available frame. HasFrame must be called before checking if the next frame is available. If called when there is no next frame, a panic will occur. 36 | - processBlocks: Add blocks from the block queue to the pending channel until the queue is exhausted or the channel is full. 37 | - AddBlock: Add the block to channelBuilder 38 | - AddBlock: Adds a block to the channel compression pipeline. IsFull should then be called to test whether the channel is full. If it is full, a new channel must be started. If AddBlock is called, a ChannelFullError is returned even if the channel is full. AddBlock also returns the L1BlockInfo extracted from the first transaction of the block for subsequent use by the caller. Then call OutputFrames() to create the frame. 39 | - BlockToBatch: Convert blocks into batch objects that can be easily RLP encoded 40 | - AddBatch: AddBatch adds a batch to a channel. If there is a problem adding the batch, it returns the RLP encoded byte size and an error. The only tagged error it returns is ErrTooManyRLPBytes. If this error is returned, the channel should be closed and a new one created. AddBatch should be used with BlockToBatch if you need to access the BatchData before adding the block to the channel. Unable to access batch data using AddBlock. The encoded data is compressed and written to ChannelOut. 41 | - registerL1Block: Register the given block on the pending channel, registering the current L1 header only after all pending blocks have been processed. Even though a timeout will now be triggered, it is better to have all pending blocks submitted in this channel. 42 | - outputFrames: read frames from currentChannel 43 | - OutputFrames: read frames from channelBuilder 44 | - OutputFrames: Create new frames using channel outputs. It should be called after AddBlock and before iterating through the available frames using HasFrame and NextFrame. If the channel is not already full, it will conservatively only extract available frames from the compressed output. If it is full, the channel will be closed and all remaining frames will be created, possibly with a small remaining frame. 45 | - outputReadyFrames: outputReadyFrames creates new frames as long as there is enough data in the channel output compression pipeline. This is part of the optimization, already generating frames and sending them out as transactions while still collecting blocks in the channel builder. 46 | - outputFrame: Creates a new frame and adds it to the frame queue. Note that compressed output data must be available on the underlying ChannelOut, otherwise empty frames will be generated. This is actually adding the frame data to the frames []frameData structure so that nextTxData can read the corresponding frame data. 47 | - sendTransaction sends the transaction to one layer and updates the transaction sending status into the receiptCh chan TxReceipt[T] channel; sendTransaction creates a transaction using the given "data" and submits it to the batch inbox address. It currently uses the underlying "txmgr" to handle transaction routing and price management. This is a blocking method. It should not be called simultaneously. 48 | - Send: Send will wait until the number of pending transactions is below the maximum number of pending transactions, then send the next transaction. The actual tx send is non-blocking and the receipt is returned on the provided receipt channel. If the channel is unbuffered, the goroutine will be blocked from completing until data is read from the channel. 49 | - sendTx: Call the txMgr send method to send the transaction and write the transaction status to the receiptCh chan TxReceipt[T] channel 50 | - handleReceipt gets the status of transactions processed from the channel and removes successfully processed transactions from the channel 51 | - handleReceipt gets the status of transactions processed from the channel and removes successfully processed transactions from the channel 52 | 53 | 54 | ## 4.op-proposer 55 | ### 4.1 Execution flow chart 56 | 57 | [![op-batcher](https://github.com/guoshijiang/how-dose-op-stack-work/blob/main/rollup/op-proposer/op-proposer.png)](https://github.com/guoshijiang/how-dose-op-stack-work) 58 | 59 | ### 4.2. Detailed execution process 60 | - FetchNextOutputInfo: Get the output of the block on L2 to facilitate subsequent assembly and submission. The output structure is as follows 61 | ``` 62 | typeOutputResponse struct { 63 | Version Bytes32 `json:"version"` 64 | OutputRoot Bytes32 `json:"outputRoot"` 65 | BlockRef L2BlockRef `json:"blockRef"` 66 | WithdrawalStorageRoot common.Hash `json:"withdrawalStorageRoot"` 67 | StateRoot common.Hash `json:"stateRoot"` 68 | Status *SyncStatus `json:"syncStatus"` 69 | } 70 | ``` 71 | 72 | - NextBlockNumber: Get the block interval that needs to be submitted in the next batch. The interval is calculated as latestBlockNumber() + SUBMISSION_INTERVAL. The value of SUBMISSION_INTERVAL can be specified when deploying the L2OutputOracle contract. 73 | - SyncStatus: Get the status and block information of SafeL2 and FinalizedL2 of L2 block, 74 | - fetchOutput: After checking that nextCheckpointBlock complies with the rules, go to L2 to get the stateRoot that needs to be submitted. 75 | - OutputAtBlock: Get the output based on the block height, which contains stateRoot. Here, eth_getProof is finally called to calculate and obtain stateRoot. The code calling process can refer to the figure above. 76 | Tip: This is not to submit stateRoot once for each block, but to calculate the stateRoot of a batch of blocks based on the value configured in SUBMISSION_INTERVAL, and finally submit the stateRoot to the L2OutputOracle contract 77 | - sendTransaction: Use output to construct stateRoot to submit the transaction and submit the transaction to a layer of chain. The following are the data details of the transaction packaging. 78 | 79 | ``` 80 | return abi.Pack( 81 | "proposeL2Output", 82 | output.OutputRoot, 83 | new(big.Int).SetUint64(output.BlockRef.Number), 84 | output.Status.CurrentL1.Hash, 85 | new(big.Int).SetUint64(output.Status.CurrentL1.Number)) 86 | ``` 87 | 88 | ## 5. Summary 89 | 90 | In this section, we mainly explain the detailed process of rollup transaction data and stateRoot. After studying this section, I believe everyone will have a better understanding of the stateRoot submission process. In the next lecture, we will explain the function and code of the new optimization_xxx interface in the op. . -------------------------------------------------------------------------------- /rollup/README.md: -------------------------------------------------------------------------------- 1 | [![English](https://img.shields.io/badge/English-README-blue)](EnglishReadme.md) 2 | 3 | 4 | # Op-stack rollup 流程详解 5 | 6 | ## 1.概述 7 | 8 | Op-stack 的 rollup 由两个服务来承担 9 | - op-batcher 服务:主要职责是负责将交易数据提交到 Layer1 的 EOA 地址 10 | - op-proposer 服务:主要职责是负责将交易状态提交到 Layer1 的 L2OutputOracle 合约 11 | 12 | ## 2.Rollup 架构 13 | 14 | [![rollup_art](https://github.com/guoshijiang/how-dose-op-stack-work/blob/main/rollup/rollup_art.png)](https://github.com/guoshijiang/how-dose-op-stack-work) 15 | 16 | ## 3.op-batcher 17 | 18 | ### 3.1 执行流程图 19 | 20 | [![op-batcher](https://github.com/guoshijiang/how-dose-op-stack-work/blob/main/rollup/op-batcher/op-batcher.png)](https://github.com/guoshijiang/how-dose-op-stack-work) 21 | 22 | ### 3.2 详细执行流程 23 | - loadBlocksIntoState 会执行以下逻辑 24 | - calculateL2BlockRangeToStore 获取并判断需要提交的最新 L2 的 start 和 end 块号,起始的区块为 L2 当前安全的最高块;结束区块为 L2 当前最高的不安全的区块。 25 | - 拿到提交的开始块和结束区块之后,从起始区块开始获取区块信息,并调用 AddL2Block 函数将区块加到 channelManager 的 blocks []*types.Block 中。 26 | - 调用 loadBlockIntoState 函数返回的区块,校验区块是否需要重新提交,若需要,将 l.lastStoredBlock 置成 eth.BlockID{};否则就将 l.lastStoredBlock 置成 eth.ToBlockID(block);latestBlock 置成 block; 27 | - L2BlockToBlockRef 从 L2 块引用源中提取基本的 L2BlockRef 信息,根据区块号判断必要时回退到创世信息 28 | - publishStateToL1 方法会执行一下逻辑 29 | - publishTxToL1 方法获取要提交的数据数据构建交易发送到 Layer1 网络,并将发送出去的交易扔到 receiptCh chan TxReceipt[T] channel 里面。 30 | - l1Tip:获取当前 L1 提示作为 L1BlockRef。 假定传递的上下文是生命周期上下文,因此它在内部使用网络超时进行包装。 31 | - recordL1Tip:将上一个 L1BlockRef 更换成 l1Tip 获取到的最新的 L1BlockRef 32 | - TxData:收集需要 rollup 的交易数据;TxData 返回应提交给 L1 的下一个 tx 数据。 目前,每个事务仅使用一帧。 如果待处理的通道已满,则仅返回该通道的剩余帧,直到成功完全发送到 L1。 如果没有挂起的帧,它将返回 io.EOF。 33 | - nextTxData: 如果有待处理帧或通道管理器关闭,从 channel 里面收集提交的数据并返回 34 | - NextTxData:从 channel 里面读取交易数据,将交易数据记录到 pendingTransactions 并返回 35 | - NextFrame:返回下一个可用帧。 在检查是否有下一帧可用之前,必须调用 HasFrame。 如果在没有下一帧时调用,则会发生恐慌。 36 | - processBlocks: 将块从块队列添加到待处理通道,直到队列耗尽或通道已满。 37 | - AddBlock: 将块加入到 channelBuilder 里面 38 | - AddBlock:向通道压缩管道添加一个块。 之后应该调用 IsFull 来测试通道是否已满。 如果已满,则必须启动新通道。如果调用 AddBlock,即使通道已满,也会返回 ChannelFullError。 AddBlock 还返回从区块的第一个交易中提取的 L1BlockInfo,以供调用者后续使用。 之后调用 OutputFrames() 创建帧。 39 | - BlockToBatch:将块转换为可以轻松进行 RLP 编码的批处理对象 40 | - AddBatch:AddBatch 将批次添加到通道。 如果添加批次出现问题,它会返回 RLP 编码的字节大小和错误。 它返回的唯一标记错误是 ErrTooManyRLPBytes。 如果返回此错误,则应关闭该通道并创建一个新通道。如果您需要在将块添加到通道之前访问 BatchData,则 AddBatch 应与 BlockToBatch 一起使用。 无法使用 AddBlock 访问批次数据。编码完成的数据压缩之后写到了 ChannelOut 里面 41 | - registerL1Block: 在挂起的通道上注册给定的块,仅在处理完所有待处理块后才注册当前 L1 头。 即使现在会触发超时,最好还是让所有待处理的区块都包含在这个通道中提交。 42 | - outputFrames: 从 currentChannel 读取 frames 43 | - OutputFrames: 从 channelBuilder 读取 frames 44 | - OutputFrames: 使用通道输出创建新帧。 它应该在 AddBlock 之后、使用 HasFrame 和 NextFrame 迭代可用帧之前调用。 如果通道尚未满,它将保守地仅从压缩输出中提取可用的帧。 如果已满,则通道将关闭,并且将创建所有剩余的帧,可能还有一个小的剩余帧。 45 | - outputReadyFrames: 只要通道输出压缩管道中有足够的数据,outputReadyFrames 就会创建新帧。 这是优化的一部分,已经生成帧并将它们作为交易发送出去,同时仍在通道构建器中收集块。 46 | - outputFrame: 创建一个新帧并将其添加到帧队列中。 请注意,压缩的输出数据必须在底层 ChannelOut 上可用,否则将生成空帧。这里其实就是将 frame 数据添加到 frames []frameData 结构中,以供 nextTxData 读取对应的 frame 数据。 47 | - sendTransaction 将交易发送到一层,并把交易发送状态更新到 receiptCh chan TxReceipt[T] channel 里面;sendTransaction 使用给定的“数据”创建交易并将其提交到批处理收件箱地址。 它目前使用底层的“txmgr”来处理交易发送和价格管理。 这是一种阻塞方法。 不应同时调用它。 48 | - Send: 发送将等待,直到挂起的交易数量低于最大挂起数量,然后发送下一个交易。 实际的 tx 发送是非阻塞的,收据在提供的收据通道上返回。 如果通道未缓冲,则 goroutine 将被阻止完成,直到从通道读取数据为止。 49 | - sendTx:调用 txMgr send 方法发送交易,将交易的状态写到 receiptCh chan TxReceipt[T] channel 里面 50 | - handleReceipt 获取从 channel 处理交易的状态,并将成功处理的交易从 channel 里面移除 51 | - handleReceipt 获取从 channel 处理交易的状态,并将成功处理的交易从 channel 里面移除 52 | 53 | 54 | ## 4.op-proposer 55 | ### 4.1 执行流程图 56 | 57 | [![op-batcher](https://github.com/guoshijiang/how-dose-op-stack-work/blob/main/rollup/op-proposer/op-proposer.png)](https://github.com/guoshijiang/how-dose-op-stack-work) 58 | 59 | ### 4.2.详细执行流程 60 | - FetchNextOutputInfo: 获取 L2 上的区块的 output,方便后续组装提交,output 结构如下 61 | ``` 62 | type OutputResponse struct { 63 | Version Bytes32 `json:"version"` 64 | OutputRoot Bytes32 `json:"outputRoot"` 65 | BlockRef L2BlockRef `json:"blockRef"` 66 | WithdrawalStorageRoot common.Hash `json:"withdrawalStorageRoot"` 67 | StateRoot common.Hash `json:"stateRoot"` 68 | Status *SyncStatus `json:"syncStatus"` 69 | } 70 | ``` 71 | 72 | - NextBlockNumber:获取下一批次需要提交的区块区间,区间计算为 latestBlockNumber() + SUBMISSION_INTERVAL SUBMISSION_INTERVAL 的值可以在部署L2OutputOracle 合约的时候指定。 73 | - SyncStatus:获取 L2 块的 SafeL2 和 FinalizedL2 的状态和块信息, 74 | - fetchOutput:上面检查完 nextCheckpointBlock 符合规则之后,去 L2 上获取需要提交的 stateRoot 75 | - OutputAtBlock: 根据块高获取 output, 里面包含 stateRoot,这里最终是调用 eth_getProof 去计算并获取 stateRoot,代码调用流程可以参考上图。 76 | 提示: 这里并不是一个块提交一次 stateRoot, 而是根据 SUBMISSION_INTERVAL 配置的值来计算一批块的 stateRoot,最终将 stateRoot 提交到 L2OutputOracle 合约 77 | - sendTransaction:使用 output 构建 stateRoot 提交交易,将交易提交到一层链, 下面是交易打包的数据细节 78 | 79 | ``` 80 | return abi.Pack( 81 | "proposeL2Output", 82 | output.OutputRoot, 83 | new(big.Int).SetUint64(output.BlockRef.Number), 84 | output.Status.CurrentL1.Hash, 85 | new(big.Int).SetUint64(output.Status.CurrentL1.Number)) 86 | ``` 87 | 88 | ## 5.小结 89 | 90 | 本节我们主要是讲解了 rollup 交易数据和 stateRoot 的详细流程,通过本节的学习,相信大家对 stateRoot 的提交流程会更了解,下一讲我们将讲解 op 新增 optimism_xxx 这组接口的作用与代码。 91 | -------------------------------------------------------------------------------- /rollup/op-batcher/EnglishReadme.md: -------------------------------------------------------------------------------- 1 | [![Chinese](https://img.shields.io/badge/Chinese-README-blue)](Readme.md) 2 | 3 | 4 | # op-batcher 5 | -------------------------------------------------------------------------------- /rollup/op-batcher/Readme.md: -------------------------------------------------------------------------------- 1 | [![English](https://img.shields.io/badge/English-README-blue)](EnglishReadme.md) 2 | 3 | 4 | # op-batcher 5 | -------------------------------------------------------------------------------- /rollup/op-batcher/op-batcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/the-web3-chain/how-dose-op-stack-work/c40bf36d058337b4c12bfd301103457ae10a7fda/rollup/op-batcher/op-batcher.png -------------------------------------------------------------------------------- /rollup/op-proposer/EnglishReadme.md: -------------------------------------------------------------------------------- 1 | [![Chinese](https://img.shields.io/badge/Chinese-README-blue)](readme.md) 2 | 3 | 4 | # op-proposer 5 | -------------------------------------------------------------------------------- /rollup/op-proposer/op-proposer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/the-web3-chain/how-dose-op-stack-work/c40bf36d058337b4c12bfd301103457ae10a7fda/rollup/op-proposer/op-proposer.png -------------------------------------------------------------------------------- /rollup/op-proposer/readme.md: -------------------------------------------------------------------------------- 1 | [![English](https://img.shields.io/badge/English-README-blue)](EnglishReadme.md) 2 | 3 | 4 | # op-proposer 5 | -------------------------------------------------------------------------------- /rollup/rollup_art.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/the-web3-chain/how-dose-op-stack-work/c40bf36d058337b4c12bfd301103457ae10a7fda/rollup/rollup_art.png --------------------------------------------------------------------------------