okex欧易交易所封面图

okex欧易交易所

全区最顶尖的数字货币交易所之一,现在注册享受永久20%交易手续费减免+新人盲盒大礼包!限时优惠!

APP下载 官网注册

愿原力包容与你同在。这篇文章将介绍 Rollup 的交易抗审查机制 — Force Inclusion,并以几个著名 Rollup 的设计与实际作为示例。

Rollup的Force Inclusion机制介绍  第1张
照片由 Artur TumasjanUnsplash上拍摄

先备知识:

  • 知道 Rollup 的运作以及为什么 Rollup 需要把交易上传到 L1 上

交易的抗审查能力

交易抗审查(审查抵抗)的能力对一条区块链来说非常重要,如果一条区块链能够为任何审查用户交易,那么这条区块链就和一个Web2服务器没有两样。以太坊目前的交易抗审查能力来自于为数众多的验证者们,如果Alice想要审查Bob的交易、不让他的交易上链,那Alice要不得尝试买通网路中的每一个验证者,要不得垃圾邮件整个网路、不断发送出比Bob交易高的垃圾交易来塞满区块。无论是哪一种方式,她的成本都会非常高。

注:在以太坊目前的 PBS 架构中,审查的成本确实降低明显,可以参考OFAC 审查 Tornado Cash 交易的区块比例。当前的抗审查能力仰赖于 OFAC 及政府管辖范围之外的独立验证者及中继。

但 Rollup 呢? Rollup 不需要一大堆的验证者来保证它的安全性,补充 Rollup 只有一个中心化的角色(Sequencer,称为排序器或排序器)来批量区块,它也和 L1 一样安全。但安全和抗审查能力是两回事,构建了一个 Rollup 和以太坊一样安全,但却只有一个中心化的 Sequencer,那该 Sequencer 想要审查任何用户的交易都行。

Rollup的Force Inclusion机制介绍  第2张
Sequencer 可以拒绝收入用户交易,导致用户无法使用也无法离开 Rollup

强制包容机制

同时要求 Rollup 和 L1 一样多的验证者来确保抗审查能力,还不如直接利用 L1 的抗审查能力:测序仪也将交易数据压缩到 L1 的 Rollup 契约上,不如在 Rollup 契约里加入一个让监控用户也可以插入交易到排序,这样的办法就叫强制包含。只要Sequencer无法审查监控用户的「L1交易」,它并不能阻止用户通过L1强制插入Rollup交易,而Rollup 的运行及安全性基础正是基于 L1 的抗审查能力。

Rollup的Force Inclusion机制介绍  第3张
排序器无法审查用户的 L1 交易,除非有很复杂的成本

注:强制包含是要该 Rollup 有设计才会有,用户一定可以突破 L1 强制插入 Rollup 交易。如果 Rollup 没有提供强制包含机制,那用户就只能祈祷 Sequencer 审查不会自己交易。

交易立即生效 vs. 延迟生效

如果我们允许透过 Force Inclusion 插入的交易可以直接写入到 Rollup 的交易历史中(突然立即生效),那 Rollup 的状态就会立刻被改变,例如 Bob 通过 Force Inclusion 机制插入笔「他转 1000 DAI 给」 Carol」的交易,如果此时交易立即生效,那最新的状态中 Bob 的余额就会少 1000 DAI 而 Carol 会多 1000 DAI(当然前提是 Bob 余额超过 1000 DAI)。

Rollup的Force Inclusion机制介绍  第4张
如果Bob交易能直接被写进交易历史中,立即生效,那Rollup的状态就会立刻改变

如果此时Sequencer正在链下集合交易,等到把下一笔交易发送到Rollup合约上,那么就有可能被Bob强制插入并立即生效的交易给影响到。例如Bob只需事先发送了付款「他」转 1000 DAI 给 Alice」的交易到 Sequencer 那,Sequencer 相当于验证没问题并承诺会收入,Alice 和 Bob 都可以向 Sequencer 查询交易是否会被收入并计算出最新状态(Alice 多 1000 DAI,Bob 少 1000 DAI )。但等到 Sequencer 发现 Bob 抢先去强制插入交易后,它手上的交易的执行状态都改变了,知道那笔已「Bob 转 1000 DAI 给 Alice」的交易已经变成会执行失败,Alice 也拿不下来到1000 DAI。

Rollup的Force Inclusion机制介绍  第5张
Sequencer 收入 Bob 的交易,Alice 因此相信自己会收到 1000 DAI

Rollup的Force Inclusion机制介绍  第6张
结果Bob直接在L1上强制收入另一笔冲突的交易,导致Sequencer手上的交易无法被收入,Alice也拿不到DAI

这可能不是一个好的用户体验,因此 Rollup 一般会使强制包含交易立即生效,而是让交易高级到一个「准备中」的状态。Sequencer 可以在预算交易发送上来时选择是否要顺便塞进入这些「准备中」状态的交易到批次的最后面,如果 Sequencer 一直都不想处理这些「准备中」的状态,那么这些交易在过了一段时间后就可以被强制插入到交易历史中。

Rollup的Force Inclusion机制介绍  第7张

Rollup的Force Inclusion机制介绍  第8张
鲍勃想通过强制收入交易来骗爱丽丝,但实际上交易会先进到等待队列

Rollup的Force Inclusion机制介绍  第9张
Sequencer 可以自己决定在什么时候「顺便收入」队列等待中交易,所以 Bob 给 Alice DAI 的交易会先执行

如果Sequencer一直没有等待队列中的交易,在一段时间内后用户(或者任何人)就可以自己去强制收入。

Rollup的Force Inclusion机制介绍  第10张
Sequencer 拒绝收入 Bob 交易,所以 Bob 从 L1 将交易等待队列中

Rollup的Force Inclusion机制介绍  第11张
排序器仍然可以持续拒绝队列中的交易一段时间

Rollup的Force Inclusion机制介绍  第12张
但 Sequencer 无法永远拒绝等待队列中的交易,一段时间后任何人都可以触发强制收入接下来将依次介绍 Optimism、Arbitrum、StarkNet 及 zkSync 等较有名的 Rollup 的原力包容机制实作。

乐观的力量包容机制

首先先介绍 Optimism 的 Deposit 流程,这个 Deposit 不单是指把存钱进 Optimism 的意思,而相当于更一般的「把给 L2 的消息」存入 L2。L2 节点在接收到新存入的消息后就传送消息转换成端口 L2 交易去执行,传送消息指定的接收方。

Rollup的Force Inclusion机制介绍  第13张
用户从 L1 存款给 L2 的消息

L1CrossDomainMessenger 合约

当一个用户决定 ETH 或 ERC-20 代币存进乐观时,他会(交叉网页)与 L1 上的 L1StandardBridge 合约交互,指定要存多少数量以及由地址哪个接收等等。接着 L1StandardBridge 连接消息传递至下一层的L1CrossDomainMessenger合约,这个合约主要是作为一般通用的L1与L2之间相互通讯的合约,L1StandardBridge就是使用这个通用的通讯合约来和L2上的L2StandardBridge沟通,决定谁可以从L2铸造代币或可以从L1提领代币开始。如果开发者需要开发一个L1与L2之间互通、同步状态的合约,那他就可以搭建在L1CrossDomainMessenger之上。

Rollup的Force Inclusion机制介绍  第14张
用户的消息传递 CrossChainMessenger 合约从 L1 传递到 L2

OptimismPortal 合约

L1CrossDomainMessenger 契约会再将消息发送至最底层的 OptimismPortal 契约,OptimismPortal 契约处理完成后会发出一个TransactionDeposited事件,事件参数包含「发送消息的人」、「接收消息的人」,以及相关的执行参数。

然后 L2 的 Optimism 节点会监听 OptimismPortal 约定所发出的TransactionDeposited事件,并把事件里的参数转换为记下 L2 的交易,这个 L2 交易的发起者可能是TransactionDeposited事件里的「送消息的人」、交易的接收者就会是事件里的「接收消息的人」,其他执行参数也是由事件参数传来。

Rollup的Force Inclusion机制介绍  第15张
L2 节点插入 OptimismPortal 发出的 TransactionDeposited 事件转换成注释 L2 交易

例如这一笔是某个用户透过 L1StandardBridge 契约存款 0.01 ETH 的交易,这个消息及 ETH 一路传到 OptimismPortal 契约(地址是0xbEb5…06Ed),四十后转换成L2 交易然后消息发起者是 L1CrossDomainMessenger 契约;接收者是L2上的L2CrossDomainMessenger合约;附带0.01 ETH。

强制包容

当用户想要强制收入他的交易进乐观执行时,他不需要从L1发送消息到L2,所以他不会去使用L1CrossDomainMessenger合约。他要达到的效果是让账单具体「他从他的」 L2地址在L2上送出并要执行的交易」能够顺利执行,所以他会直接去和OptimismPortal合约互动,并且让他L2地址去呼叫OptimismPortal合约,这样到时候TransactionDeposited事件转换成L2交易的「交易发起」者将会是他的L2地址”,才能重新看见那笔交易。

Rollup的Force Inclusion机制介绍  第16张
从 TransactionDeposited 事件转换而成的 L2 交易中,发起人会是 Bob 自己;接收人是 Uniswap 合约;而且会附带指定的 ETH,就像 Bob 自己发起 L2 交易一样

Rollup的Force Inclusion机制介绍  第17张
用L2地址呼叫OptimismPortal签约的 depositTransaction函式,记清楚L2交易的参数一一填入

我做了一个简单的强制包含交易:以我L2的地址(0xeDc1…6909)转钱给我自己,并附带一个“强制包含”的文字信息。这是我透过OptimismPortal契约执行depositTransaction函式的L1交易,可以看到在发射的TransactionDeposited事件中,from和to都是我自己,剩余的opaqueData栏位里的值(000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000015BE000000000000C35000666F72636520696E636C7573696F6E)多少编码了「呼叫 DepositTransaction 的人附带了多少 ETH」、「L2 交易发起者要附带 ETH 给 L2 接收者」、「L2 交易 Gas Limit」及「给 L2 接收者的数据」等等资讯

Rollup的Force Inclusion机制介绍  第18张
L1 交易发出的 TransactionDeposited 事件

将这opaqueData几个资讯的数值解读后分别会得到:

  • 「呼叫 DepositTransaction 的人附带了多少 ETH」:,0因为我没有要从 L1 充值 ETH 进到 L2
  • 「L2 交易发起者要附带多少 ETH 给 L2 接收者」:5566(wei),因为我要转钱给我自己
  • 「L2交易Gas限额」:50000
  • 「给L2接收者的数据」:0x666f72636520696e636c7573696f6e,清晰“强制包含”这个字串的十六进制编码

接下来没多久就出现转换后的L2 交易:记下我转钱给自己的 L2 交易,金额是5566,数据是“强制包含”字串。并且可以注意到在图中倒数第二行的Other Attributes中Txn Type(交易类型)是系统交易126(System),表示不是我自己在L2发起的交易,是由L1TransactionDeposited事件转换而来。

Rollup的Force Inclusion机制介绍  第19张
转换完成的 L2 交易

如果用户要召集其他合约、带不同的数据,那同样就是将参数一一填写入depositTransaction函,只要记住是用L2地址来去L1上执行,这样到时候L2交易发起者就会是该L2地址。

音序器窗口

前面提到的 Optimism L2 节点将TransactionDeposited事件转换成 L2 交易,其实这个 Optimism 节点指的是 Sequencer 节点,毕竟这关乎交易排序,所以只有 Sequencer 可以决定什么时候要转换成 L2 交易。监听到TransactionDeposited事件时,Sequencer不一定会立即将事件转换成 L2 交易,但是可以一段时间决定要进行转换,这段时间称为音序器窗口,目前 Optimism 主网上的音序器窗口为 24 小时,那么当用户从 L1 开始时存款补钱或者一个提示,或者强制包含补款交易时,最糟糕的情况会是24小时后才被正式收入进L2交易历史中,不过至少这胜过交易永远没办法被收入的结果。

Arbitrum的强制包容机制

在乐观中 L1 的存款操作会发出一个TransactionDeposited事件,剩余的就是等待 Sequencer 收入这个存款操作;但在任意中 L1 的操作(存钱或传消息给 L2 等等)会被存在 L1 约定的一个队列里,而不是仅仅发出事件。而定序器会被给予一段时间来将这个队列里的L1操作交易历史中,如果时间到了定序器都作为,那任何人都没有去替换定序器就可以完成。

Rollup的Force Inclusion机制介绍  第20张
仲裁会在 L1 合约维护一个队列,如果 Sequencer 没有主动收入队列里的交易,时间到了任何人都可以强制收入队列里的交易进交易历史中

L1操作全部都是Delayed Inbox的合约,顾名思义这里的操作会延迟失效;另一个合约是Sequencer Inbox,是给Sequencer上传L2交易的介面。Sequencer上传的交易会直接写进交易历史中,而另外Sequencer上传时都可以选择要顺便从Delayed Inbox拿多少个L1操作一起写入交易历史中,让这些L1操作生效。

Rollup的Force Inclusion机制介绍  第21张
SequencerInbox 里是交易历史,一般只有 Sequencer 可以直接写入新交易;DelayedInbox 里等待被收入的交易

Rollup的Force Inclusion机制介绍  第22张
Sequencer 写入新交易时可以顺便从 DelayedInbox 发起交易一起写入

复杂的设计以及凡善可陈的文件

如果读者直接参考 Arbitrum 官方关于 Sequencer 及 Force Inclusion 的章节,会看到里面提到的 Force Inclusion 如何兼容,以及一些参数名称和函式名称:用户先去 Inbox 约定呼叫sendUnsignedTransaction函式,如果 Sequencer 未在约24小时内收入,那用户就可以去呼叫Sequencer Inbox签约的forceInclusion函式。就这样,连链接也没有附在里面,只能自己去约定方案码里相对应的函式。

当找到sendUnsignedTransaction函式后,你发现其实要自己填nonce值还有maxFeePerGas值。是哪个地址的nonce?是哪个网路上的maxFeePerGas值?要怎么填比较好?没有文件记录,连 Natpsec 都没有。然后你还顺便发现一个堆积皮肤的函式:sendL1FundedUnsignedTransactionsendUnsignedTransactionToForksendContractTransactionsendL1FundedContractTransaction,一样没有文件告诉你这些函式的区别、如何使用、参数如何填写,连 Natpsec 都没有。

你综合考虑并试一试的心态来试填参数并送出交易,想用反复试验的方式看能不能找出正确的方法,但发现这些函式全都会把你的L1地址做地址别名,导致最终L2上的交易发起人根本上是不一样的地址,所以你的L2地址一动也不动。

发送L2消息

后来偶然点开 Google 搜索页面中的某个链接才发现 Arbitrum 自己原来有一个教程程序库,里面有脚本示范怎么从 L1 送 L2 交易(或者 Force Inclusion 的意思),然后它的函式完全不是上面提到的任何一个,不过是一个叫的sendL2Message函式而且消息参数要带入的居然是签名的 Arbitrum L2 交易???谁会知道要「传送 L2 的消息」其实会是备注「签完名的 L2 交易”??而且再一次,没有任何文件及 Natspec 解释什么时候用及如何使用这个函式。

结论:要手动产生一个 Arbitrum 的强制收入交易比较麻烦,建议就照着官方教程跑 Arbitrum SDK 呗。Arbitrum 不像其他 Rollup 清楚有的开发者文件及计划码附注,许多函式的用途和参数缺乏说明,导致开发者需要花费比预期更多的时间来接入和使用。我同时 Arbitrum Discord 上询问 Arbitrum 的人,但并没有得到令人满意的答案。

注:在 Discord 上询问,对方也只是让我听sendL2Message,不需要解释其他函式(甚至是强制包含文件里提到的sendUnsignedTransaction)是什么用途、怎么用、什么时候用。

很遗憾,StarkNet 目前还没有强制收录。只有两篇在官方论坛上讨论到审查强制收录机制的文章。

无法证明交易失败

到底是因为 StarkNet 的零知识证明系统没办法证明记账失败的交易,所以不能允许强制记入。因为如果有人恶意(或无意)强制记入记失败、无法被证明的交易,那 StarkNet 就会直接卡住:因为交易被强制收入后,Prover就必须证明该笔失败交易,但它却没办法证明。

而StarkNet预期在v0.15.0版本引入证明失败交易的功能,之后应该就可以进一步实现强制包含机制。

zkSync 的强制包含机制

zkSync 的 L1->L2 消息传递以及强制包含机制都穿透 MailBox 合约的requestL2Transaction函式进行,用户指定要呼叫的 L2 地址、通话数据、带上的 ETH 数量、L2 Gas Limit 值等,分割requestL2Transaction这些参数组合成一个L2交易然后模拟优先伫列(Priority Queue)中,Sequencer会在交易备份上传到L1时(commitBatches函式)指定要顺便从优先伫列中拿出多少笔交易一起收入

zkSync 在强制包含介面和乐观方面很像,都是以用户的 L2 地址去呼叫,并填入相关数据(被呼叫者、通话数据等),而不是像 Arbitrum 一样是填记签完名的L2 交易;但在设计上交易和 Arbitrum 一样都在 L1 维护一个实体的队列,并由 Sequencer 从队列中取出交易写入交易历史中。

Rollup的Force Inclusion机制介绍  第23张
用户通过 requestL2Transaction 插入 L2 交易到优先伫列中,Sequencer 在 commitBatches 时可以从优先伫列中顺便对话交易

如果你通过 zkSync 的官方桥去充值 ETH,相当于此时交易,它就是去呼叫 MailBox 契约的requestL2Transaction函式,它会保留这个充值 ETH 的 L2 交易优先伫列中并发出一个NewPriorityRequest事件。因为契约把 L2 交易数据编码成一串字节字串所以不易读,改成看一下 L1 交易的参数的话,会看到参数中 L2 的接收方也是交易的发起人因为(是 Deposit 给自己),所以过一阵子兑换L2交易被序列器从优先伫列支出并收入进交易历史中时,它会在L2上被转换成记下自己转帐给自己的交易,而转帐的金额就是交易发起人在L1的存款ETH交易所带上的 ETH 金额。

Rollup的Force Inclusion机制介绍  第24张
L1充值交易中,交易发起者和接收者均为0xeDc1…6909,金额为0.03 ETH,调用数据为空

Rollup的Force Inclusion机制介绍  第25张
L2 上会出现记账 0xeDc1…6909 自己转帐给自己的交易,交易类型(Txn Type)是 255,玄系统交易

接下来我直接照本宣科呼叫requestL2Transaction函,发送了记下自己呼叫自己的交易:不带任何ETH,调用数据带入「强制包含」字串的十六进制编码。随后的式子被转换成L2上记下自己呼叫自己的交易,调用数据里是「强制包含」字串:0x666f72636520696e636c7573696f6e。

Rollup的Force Inclusion机制介绍  第26张
当排序器把交易从优先队列拿出来并写进交易历史中时,在 L2 上就可以转换成相对应的 L2 交易

通过requestL2Transaction 函式,用户可以以L2地址在L1请求L2交易,指定L2接收方、带上的ETH金额以及通话数据。如果用户要调用其他合约、带不同数据,那同样就是将参数一一填入requestL2Transaction函式,只要记得是用L2地址来去L1上执行,这样到时候L2交易发起者就会是该L2地址。

还没有让用户强制收入的功能

虽然L2交易放在优先伫列中会顺便计算出L2交易要被Sequencer收入的期限,但目前zkSync设计中并没有让用户能够自己执行的强制包含相关函式,相当于做半套。那么虽然有「收入有效期限」,但实际上还是「看 Sequencer 要不要收入」:Sequencer 可以等到过渡后才收入,也可以永远不再收入优先伫列中任何交易。未来 zkSync 应该要加入相关函式上,让用户可以在收入已经过了但还没有被Sequencer收入时,能够强制收入,这样才是真正有效的强制包容机制。

总结

  • L1 靠为数群的人来保证网路的「安全性」及「抗审查能力」,而 Rollup 靠「L1 的抗审查能力」来获得「和 L1 同样的安全性」,但不包含Rollup的抗审查能力
  • 相反地​​,Rollup 因为都是由少数或什至单一的 Sequencer 来写入交易,抗审查能力反而更弱。因此 Rollup 需要有 Force Inclusion 机制来让用户绕过 Sequencer,将交易写入历史中,避免被 Sequencer 审查而无法使用也无法离开 Rollup
  • 强制包含让用户可以强制将交易写入历史中,但在设计上需在「交易是否能立即插入历史、立即生效」上做选择。如果允许交易立即生效的话,会造成排序器的麻烦和使用体验上的困难,因为L2上等待被收入的交易都可能会被L1强制收入的交易所影响
  • 因此目前 Rollup 的强制包含机制都会先让 L1 上插入的交易先进到一个等待状态中,并让 Sequencer 有一段时间窗口来反应、来选择要不要收入这些等待中的交易
  • zkSync 和 Arbitrum 都是在 L1 维护一个实体的队列,用于管理用户从 L1 送出的 L2 交易或给 L2 的消息。Arbitrum 称为延迟收件箱;zkSync 称为优先队列
  • 但 zkSync 发送 L2 交易的方式和 Optimism 比较像,都是以 L2 地址去 L1 上发送,所以 L2 交易的发起人会是该 L2 地址。Optimism 发送 L2 交易的函式称为depositTransaction;zkSync 称为requestL2Transaction。而 Arbitrum制作填写完整的L2交易并签名,然后透sendL2Message函的方式送出,Arbitrum在L2上会透签名还原签章者来作为L2交易的发起人
  • StarkNet 目前还没有强制包含机制;zkSync 撕像做了半套的强制包含 — 有优先队列且每个队列里的 L2 交易都有收入有效期限,但这个有效期限目前只是装饰用,实际上 Sequencer 可以选择完全不再收入任何优先队列里的L2交易
FORCE LOGO图 FORCE +0.00%
The End

文章声明:以上内容(如有图片或视频亦包括在内)除非注明,否则均为谈天说币原创文章,转载或复制请以超链接形式并注明出处。

上一篇 下一篇

相关阅读