从上层的视角看看 OP Chain 的架构和工作流程
要理解 OP Chain 的工作流程并不复杂,只需要弄明白几张图即可。这几张图合在一起,共同解释了以下几个关键问题:
网络的参与者有哪些?
用户如何参与到网络中?
L1 的 ETH 如何到 L2 上去?
OP Chain 有哪些模块?
L2 是以什么规则来构建链的?
对这些问题有了一定的了解后,再看源码,才不会云里雾里。
网络参与者有哪些?
那么,让我们先从网络的参与者有哪些开始。
上图展示了 4 个参与者,分别是 Users、Sequencers、Verifiers、ETH L1 Chain。
1)Users
在 OP Chains 中,用户可以通过将交易发送到以太坊主网上的合约,在 L2 上存入或提取任意交易(对应 Bridges 的功能)。
向使用 ETH 一样,使用部署在 L2 上的智能合约,唯一的差别是,交易是发送到 Sequencers上,而不是 ETH 节点。
可以查询交易、区块等信息。
2)Sequencers
接收来自用户的链下交易(相对于 L1 而言)。
监控和收集链上( L1 )的交易信息,主要是质押事件信息。
按特定顺序将上述两种交易合并到 L2 区块中。
向 L1 提交批次信息和断言信息。
Sequencers 是主要的 L2 区块生产者。
3)Verifiers
验证者有两个目的:
为用户提供 Rollup 数据;
验证 Rollup 的完整性并质疑无效的断言。
为了网络保持安全,必须至少有一个诚实的验证者能够验证汇总链的完整性并为用户提供区块链数据。
4)ETH L1 Chain OP Stack 目前只支持 EVM 链。L1 链是 L2 数据有效性和可信任的基石。
从这张图上,我们可以了解到对于 OP Chain 的网络来说,都包含了哪些参与者。用户是网络的交互核心,用户可以向网络发送交易,也可以查询信息。
L1 的 ETH 是如何到 L2 上去的?
上图展示了 OP Chain Sequencer 模块同步用户 Deposits 和接受用户交易的流程。图中为每个行为都标了序号,这些序号基本上代表了逻辑顺序,除了 4.Send Transaction 有一点要注意的外,根据序号观看就好。当然,本文的目的就是为了让大家更轻松的建立直观印象,因此下面会介绍整个流程,也会说明为什么流程 4 需要注意。
一步步来,首先是用户发起了 1.Submit Deposit 的操作。Deposit 操作的其中一种方式是,用户在 L1 发起一笔转账交易,转账给标准桥合约地址,转账金额是你想跨链到 L2 的 ETH 的数额。
流程 2. Get Blocks(including deposit event) ,Rollup Node( op-node 承担) 会按照一定的规则(后面会讲到),获取 L1 区块的信息,并作为 L2 区块的输入信息提供给 L2 区块使用。其中用户在操作 1 发起的 Deposit 交易,会在此时被解析出来。包含用户 Deposit 信息的 L2 Block ,先称为 Deposit Block。
流程 3.Insert deposit block,Rollup Node 通过 Engine API 调用,将 Deposit Block 提交给 Execution Engine( op-geth 承担)。此时,用户在 L1 的 Deposit 信息,就已经被 L2 接收到了,但还没有最终确认。
流程 4.Send Transaction,如果仅从 Deposit L1 ETH 到 L2 的操作的角度来看,流程 4 是不必要的,用户在 L1 发起了 Deposit 交易后,OP Chain 会自动完成剩下的动作,用户不需要额外的再对 L2 发起交易。但它这个图还包含了接收交易的演示,因此他将这个行为作为流程 4 表现了出来。不要把 Submit Deposit 和 Send Transaction 关联起来(当然,必须通过 Deposit 在 L2 有了 ETH,才能在 L2 发起交易,但他们在 OP Chain 系统里不是线性关系),这就是上面说的需要注意的地方。
流程 5.Get latest sequencer blocks,获取最近的排序好的区块,并通过 Engine API 推送到 Execution Engine 中。
流程 6.Submit sequencer blocks(ie. a batch) to the batch inbox,将进行批处理后的 sequencer blocks 提交的 Batch Inbox 上。关于批处理,我们暂时理解为压缩,后面再探讨具体细节。记住它有可以减少 sequencer blocks 的体积(压缩),L2 可以从 L1 上获取之前提交给它的信息,根据该信息可以解析出原来的 sequencer blocks(解压缩),这样的特性即可。
Batch Inbox 是一个 L1 上的常规的 EOA 账户。
流程 7.Get latest assertable block hash,获取最新的区块哈希断言。
流程 8.Verify block hash in the fault proof VM to detect on chain <-> off chain divergence,验证故障证明虚拟机中的块哈希以检测链上 <-> 链下分歧。
流程 9.Submit validated block hash assertion,提交经过验证的区块哈希断言。
流程 7,8,9 涉及到故障证明相关的内容,这一部分较为复杂,暂时不在这里展开。我们先记住它是用来检测和处理 L1 和 L2 链的状态分歧的即可,不影响我们理解 OP Chain 的工作流程。然后,L2 Output Oracle 是一个合约,该合约主要用来存储 L2 output roots(一个 32 字节值,用作对 L2 链当前状态的承诺。由 sequencer 生成和提交)。
以上就是 Sequencer 同步 Deposit 信息和接受用户交易并处理的流程。
OP Chain 有哪些模块?
上图展示了 OP Chain 的核心组件。从 L1 和 L2 两个层级来看, L1 层包含以下组件:
OptimismPortal 一个部署在 L1 上的合约。会将 Deposit 交易存在这个合约中,而不是 token。会抛出 TransactionDeposited 事件,Rollup Driver 会读取事件信息,然后处理质押汇款。
BatchInbox 如前文所述,这是一个常规的 EOA 账户。Batch Submitter 将 batch 信息提交到这个地址上。这种方式,可以通过不执行任何 EVM 代码来节省 Gas 成本。
L2OutputOracle 如前文所述,这是一个存储 L2 output roots 的智能合约,用于提款和故障证明。
L2 层包含以下组件:
Rollup Node
独立、无状态的二进制文件。
接收用户的 L2 交易。
同步并验证 L1 上的 rollup 数据。
应用特定的 rollup 块生成规则来从 L1 合成块。
使用 Engine API 将块追加到 L2 链。
处理 L1 的重组。
将未提交的块分发给其他 Rollup Node。
L2 Execution Engine
一个普通的 Geth 节点,经过少量修改以支持 Optimism。
维持 L2 状态。
将状态同步到其他 L2 节点以实现快速加入。
向 Rollup Node 提供 Engine API。
Batch Submitter 一个专门将 transaction bathes 提交到 BatchInbox 的后台程序。
Output Submitter 将 L2 output commitments 提交到 L2OutputOracle 的后台程序。
此外,上图还可以将 Rollup Node 和 L2 Execution Engine 的关系再展开一下,得到下图:
这个图展示了以下几个关键信息:
执行引擎( EE )之间使用独立于 Rollup Node 的对等网络进行通信。可以同步交易,区块状态等。
Rollup Node 之间也存在一个特有的 P2P 网络,使用这个网络进行通信,而不是 EE 之间的 P2P 网络。
Rollup Node 通过 Engine API 和执行引擎交互。
L2 是以什么规则来构建链的?
给定一条 L1 链,Rollup Chain 可以基于 L1 的区块信息,将 L2 链完全恢复出来。上图展示了 OP Chain 从 L1 恢复 L2 链的基础逻辑。
让我们先了解一下图中各个元素的含义:
Epoch
每个 L1 区块,对应一个 L2 的 Epoch。每个 Epoch 可以包含多个 L2 区块,起始的 L2 区块必须是包含 L1 Deposit 信息的 L2 区块( Deposit Block )。
D1…… D3
表示 Epoch 1 中所有的 Deposit 信息,这些信息是从 OptimismPortal 合约上获得的。
B1…… B7
Transaction Batches。交易 Batch 不仅可以包含一个 L2 区块的交易,还可以包含多个 L2 区块排序好后的交易。每个 Batch 都包含了 parent hash, L1 epoch 的区块哈希和区块编号。
一个 L2 区块中既可以包含 Deposit 交易,也可以包含 Batch 交易。
D1 是在 L1 上发现的第一个 Deposit 信息,以包含该信息的 L1 块为基础,作为 Epoch1。推导出 L2 的第一个区块。B1 作为同一个 L1 区块上的 batch,和 D1 放在同一个 L2 区块中。
以 ETH 作为 L1 和上一个教程中部署的 L2 参数为例,ETH 出块的平均时间为 12s, L2 的平均出块时间为 2s。这些值意味着一个 Epoch 的跨度为 12s, 在这 12s 内,可以包含 6 个区块。这也是上图中,会有 B2, B4, B5, B6, B7 的原因。注意,如果从 L2 的视角来看,B2 不代表只有一个区块,它可能是多个区块,因为一个 Batch 可以从多个排好序的区块中整合交易。
按照同样的逻辑,我们根据在 L1 的第二个区块中的 D2 信息,推导出 L2 上的第二个 Deposit Block,也是 Epoch2 的起始区块。后面的推导都是这样的一个逻辑,一直循环直到达到 L1 的最新的的区块为止。
基础逻辑就是上面说的这样了,现在在这个基础上再补充一个细节,这个细节在上图中没有体现,但非常重要。这个细节就是:SEQUENCING_WINDOW_SIZE。
让我们先反转一下观察角度,之前是 L1 -> L2, 现在我们看 L2 -> L1。假设我们在 D2 追上了 L1 的最高点,后面需要提交 B4,B5,B6…… (从这里开始,不是在解释上图了,只是利用一下,表述的内容并不相同)。OP Stack 协议定义了一个 SEQUENCING_WINDOW_SIZE,在 n(epoch 编号) + SEQUENCING_WINDOW_SIZE 内,指定 epoch 内的 Batch 必须被提交到 L1 上,否则是无效的。另一方面,这也意味着 B4,B5,B6…… 可以提交到后面的 epoch 所对应的 L1 区块上,如 epoch3,4,5…,尽管 Batch 记录的 epoch 为 epoch2,但只要还在 SEQUENCING_WINDOW_SIZE 的范围内,就有效。
再回过来看 L1 -> L2, 也就是说推导 L2 区块时,对于 batches 的检索,需要检索 n + SEQUENCING_WINDOW_SIZE 的区块,才能确保检索出了当前 epoch 中包含的所有的 batches。
还有一张图,对这个过程做了更详细的描述,不过这个图中涉及了更多的代码概念,准备放到后面,在源码阶段再展开讲述。
读者朋友如果感兴趣的话,也可以提前看看,整体逻辑上和前面的简化图是差不多的,只是加入了更多实现上的细节。可以结合 OP Stack 规格书的 derivation[1] 一节来看。
总结
这篇文章,我尝试以上层的视角,来向大家介绍 OP Chain 的整体架构,以及主要的工作流程。让大家建立一个直观的印象,这样后续结合源码时,能够更轻松,更容易理解。
文章中的内容,全部来源于 OP Stack 规格书以及 optimism 仓库的源码。目前我也还处于学习理解的阶段,而系统本身有一定的复杂度,难免有所疏漏,还请海涵指正!
最后,感谢大家的阅读~
找到我们
OP 中文力量是由 GCC、LXDAO、PlanckerDAO,登链社区和 TraDAO 共同发起的 Optimism 中文开发者社区,是一个传播 Optimism 技术和公共物品理念的组织,旨在成为链接华语社区和 Optimism 生态的桥梁,促进 Optimism 生态和华语社区内的双向交流,促进公共物品的繁荣。
OP 中文力量是 GCC 中文力量计划旗下专注 OP 生态的中文社区,由 GCC 捐助孵化成立。
Twitter:https://x.com/Optimismzh
Notion:https://www.notion.so/lxdao/Optimism-99a78f831195451a9f16724342c0c4ed
Telegram:https://t.me/optimism_cn
Mirror: https://mirror.xyz/optimismcn.eth
支持社区
喜欢我的作品吗?别忘了给予支持与赞赏,让我知道在创作的路上有你陪伴,一起延续这份热忱!
- 来自作者
- 相关推荐