背景
阅读我关于共享定序器的文章。
许多共享定序器已经允许原子包含事务。然而,这需要对所有组件汇总进行协议更改。这些协议的改变是未经指定的,而且这些想法是毛茸茸的和奇怪的。
我怀疑共享定序器的人们只是将其过于复杂化,使其看起来很神秘。所以我决定坐下来设计一个基本的交叉汇总捆绑方案。
幸运的是,我们拥有关于任意捆绑方案的现有技术,因此我们知道要避免什么,以及通常如何构建它们。事实证明,修改每个Rollup的过滤功能很容易。
目标
它应该允许来自多个 EOA 的多个交易。
应该不可能破坏捆绑(包括组件交易而不包括同一序列中的所有其他交易)。
不需要共享 TX 格式。
签名应该很便宜(在最坏的情况下,交易数量为
O(n),参见 二次叹息问题)
修改组件RollupTX 格式
在所有情况下均省略签名。
在 tx 中包含链 ID 或其他域绑定。
没有其他修改
捆绑
对于每个组件Rollup,都有一个数据结构,将 EOA 地址映射到该地址的交易列表。事务应该被序列化并表示为不透明字节。签名者无需理解内容。
struct Bundle {arbitrum: Map<Address, Vec<OpaqueBytes>>,optimism: Map<Address, Vec<OpaqueBytes>>,}签约
我们迭代所有交易,为Rollup和发送者插入分隔符。这确保了 txn 绑定到特定的Rollup和特定的 EOA,并且不会被误解。它还确保将Rollup和 EOA 信息公开给所有观察者,而不要求观察者了解 tx 结构。
以这种方式签名还可以确保所有签名都提交给所有交易。这使得捆绑包不可修改。它既不能扩展也不能分拆。
fn signing_hash(&self) -> [u8;32] {let mut hasher = Keccak::new();hasher.update(b"arb");for (from, txns) in self.arbitrum.iter() {hasher.update(&from);txns.for_each(|tx| hasher.update(tx.hash()));}hasher.update(b"opt");for (from, txns) in self.optimism.iter() {hasher.update(&from);txns.for_each(|tx| hasher.update(tx.hash()));}hasher.finalize()}fn sign(&self, key: &SigningKey) -> Signature {key.sign_raw(self.signing_hash())}如果需要,也可以使用一些额外的域绑定,idc。
正在验证
验证可以在不了解交易内容的情况下完成。
我们通过以下方式验证:
计算捆绑包的签名哈希值
检查该捆绑包的每个声明的 EOA 是否在签名哈希上都有签名
struct SignedBundle {bundle: Bundle,signatures: Vec<Signature>,}fn verify(bundle: &SignedBundle) -> Result<()> {let signing_hash = bundle.bundle.signing_hash();// Collect the signers whose signatures are includedlet addresses = bundle.signatures.map(|sig| sig.recover_raw(signing_hash)).collect::<Result<HashSet<_>>>();// collect the stated EOA senderslet eoas = bundle.arb.keys().chain(bundle.opt.keys()).collect::<HashSet<_>>>();// Check that those sets are equalif eoas != addresses {return Err("missing sig or extra sig or whatever")}Ok(())}通过这种方式,我们确保所有签名覆盖所有交易(并且如果添加、删除或替换交易将无效),并且签名不会覆盖任何交易。进行额外检查也不是很昂贵。
序列化
谁在乎这都是小事。就做事吧。
过滤
组件汇总必须过滤验证失败的包。请注意,过滤不需要了解交易的内容,只需检查交易的签名即可。
这意味着签名不正确或不足的包将包含在主机历史记录中,但会从Rollup历史记录中过滤掉。它们对Rollup链没有任何影响。今天,ofc 在主网的汇总中对排序器输出中的无效交易做了同样的事情。
结论
这实现了多方捆绑包的原子包含。多个 EOA 可以包含事务。捆绑包无法拆分,因为所有签名都提交给所有交易。签名交易次数为O(n) 。验证的时间复杂度为O(n + s)其中s是签名者的数量。如果需要,您可以使用可聚合的签名方案来稍微调整这种权衡。
繁荣。目标已实现。
那么这对我们没有什么好处呢?阅读过我过去的博客文章和恼火的推文线程的精明读者可能会意识到,这种捆绑方式无法让您获得原子执行。是的。因此,如果没有进一步的机制/协议更改来处理执行部分,您实际上无法使用它来构建任何互操作性方案。 MEV 提取块构建器通过位于块顶部来获得执行。但你,最终用户,不提取东西。你被提取了。
所以,是的,构建一个捆绑方案是微不足道的,但这只是因为我们将问题缩小到几乎无用的程度。
总而言之,原子包含是令人讨厌的,而且很容易,除了 MEV 提取之外,对任何事情都没有什么好处。别小题大做了。


