作者:林冠宏 / 指尖下的幽灵。转载者,请: 务必标明出处。
掘金:https://juejin.im/user/1785262612681997
博客:http://www.cnblogs.com/linguanh/
GitHub : https://github.com/af913337456/
出版的书籍:
前序: 对于区块链每个阶段的风口产品,我都会挑选其中某个研究其源码,当作学习并增加经验。早前看的是
zkSync
,难度巨大而能力有限,遂转于Optimism
。
本次是系列文章,这是第一篇。
这里就不说什么是 Layer2 了,可以去网络搜索其它文章来阅读。在 Layer2 的扩容方案中目前有 3 种,Rollups
是其中一种,称为打包
。打包又分两大派别:
这两派的风格各异,特点突出。Optimistic rollups
对智能合约
的支持可以说是完全兼容,而 ZK rollups
目前对智能合约支持不友好,但是在交易提款
上链这块非常快、更安全却计算量巨大,技术难度复杂。关于它们的对比
,我后续再写篇文章详细说说
Layer2 是公链下的第二层。比如安卓系统下的底层软件。
Optimism,下面简称 Op,是基于 Optimistic rollups
方案所实现的 Layer2 应用,下面简称 L2。作用是帮助 以太坊
扩容以及加速交易。
特点如下:
欺诈证明
;虽说 Op 是个 L2 应用,但它的组成程序组件非常多。我这里列出会和我本文内容相关的组件:
合约
,这些会被部署在 L1 公链上面,由 L2 组件或用户来调用,包含不限于有: L2 侧链
,基于 geth 源码改造的链,运行在 Op 生态里;L1StandardBridge.sol
垮链桥合约,用来处理充值 Token 到 Op 地址或从 Op 地址提现到 L1 地址 所用;CanonicalTransactionChain.sol
规范处理 L2 --> L1
的交易,下面简称 CTC
;L1CrossDomainMessenger.sol
跨链信使合约,里面主要编写进行了各种要触发跨链事件的函数。DataTransportLayer
,定时扫描 L1 区块,从中获取到 TransactionEnqueued
事件,并存储到 LevelDB
数据库;Sequencer
: DataTransportLayer
存储的 TransactionEnqueued
事件数据,并把交易在 L2 链中执行,使之正常被打包到 L2 区块中;Batch-Submitter
,定期从 L2 区块中将交易数据以打包的形式组装到交易: txBatch
提交到 L1 的 CTC
合约;stateBatch
提交到 L1 的StateCommitmentChain.sol
等待挑战
窗口,挑战方式就是欺诈证明
;Relayer
,定时从 L2 区块中过滤交易中的 SentMessage
事件数据: L1CrossDomainMessenger.relayMessage
函数,使之完成合约检查
然后在内部调用目标合约,最终在 L1 完成 L2 交易的最终目的;它们的组合通讯流程图如下:
注: 目前所有的 Op 组建,都由官方运行着,欺诈证明还在完善。用户必须要相信官方不会做恶。
使用 Op 网络分两种情况:
L1StandardBridge.sol
进行充值到 Op;L1StandardBridge.sol
充值 Token 到 L2 地址;按照流程,用户需要调用 L1 上的 L1StandardBridge.sol
智能合约充值,如下图所示:
注意,payable
就是 solidity 语法中标明可以接收 ETH 的语法糖。此时充值 ETH 到了 Op 的 L1StandardBridge 跨链桥合约中。
上图,函数走完了,都没有痕迹告诉我们如何在为 L2 的地址充值了 ETH,我们只需要留意其中的 IL2ERC20Bridge.finalizeDeposit.selector
这一行。这里设置了一个 L2 到时需要调用的函数。
上图,结合我们前面的结论 DataTransportLayer
,会定时扫描 L1 区块,从中获取到 TransactionEnqueued
事件,并存储到 LevelDB
数据库。
所以在 _sendXDomainMessag
内部,最终会触发 emit TransactionEnqueued
事件。L1 层面的闭环结束
ERC-20 的充值也是一样的,只是函数不一样。如下图:
// TransactionEnqueued 事件在 enqueue 内发生
function _sendXDomainMessage(
address _canonicalTransactionChain,
bytes memory _message,
uint256 _gasLimit
) internal {
// slither-disable-next-line reentrancy-events
ICanonicalTransactionChain(_canonicalTransactionChain).enqueue(
Lib_PredeployAddresses.L2_CROSS_DOMAIN_MESSENGER,
_gasLimit,
_message
);
}
在这里我们主要看 Sequencer
的是如何执行 TransactionEnqueued
中的交易到 L2 的。
在 Sequencer
的启动中,首先是它会进入一个定时从数据库中获取交易的函数,如下图所示:
接下来的调用链是: s.sequnece --> syncQueueToTip --> syncQueue --> syncQueneTransaction
如下图所示,在 syncQueneTransaction
中,调用 GetEnqueue
从远程接口即 DataTransportLayer
服务中获取目标交易数据。最后执行 applyTransaction
执行交易
回到前面合约层的 IL2ERC20Bridge.finalizeDeposit.selector
这一句,最后交易的执行会走到 L2 合约层的 L2ERC20Bridge
合约的 finalizeDeposit
函数,如下图所示,最终 mint 操作完成充值流程,至此闭环。