斑点流
由@QED 、 @fradamt 、 @Julian撰写,特别感谢@soispoke 、 @aelowsson和@casparschwa的宝贵意见。
我们提出blob 流式传输:将 blob 数据的连续采样预传播作为协议内一级机制,与现有的关键路径 blob 通道并列。预传播目前已通过 blob 池实现,但由于缺乏数据可用性采样且保证较弱,因此无法安全地扩展吞吐量。Blob 流式传输引入了一种票据机制来限制预传播的速率,从而允许在不扩展关键路径的情况下可靠地将采样扩展到整个时隙——因此缓解了自由选项问题。除了扩展性之外,该机制还实现了 blob 交易的完全抗审查性。
介绍
定义:JIT 和 AOT 数据块
如果一个数据块在需要其可用性的时隙的关键路径上传播,我们就称该数据块为JIT (即时)数据块;否则,我们就称该数据块为AOT (提前)数据块。
以太坊的数据可用性机制最初是围绕即时数据块(JIT blob)设计的,并在共识层(CL)的关键路径上进行传播。该机制已通过PeerDAS进行了升级,以支持数据可用性采样。然而,执行层(EL)的数据池实际上通过提供预传播途径,实现了实时数据块(AOT blob)的实现。
尽管 JIT blob 原则上能够实现 AOT blob 无法提供的功能——例如,为了与 L1 层实现同步组合,需要同时创建数据块和 blob——但实际上,目前所有 blob 的使用都是 AOT 的。因此,blobpool 使得工作能够脱离关键路径,从而分散带宽使用。然而,这种预传播缺乏可靠的保证,也没有数据可用性采样,因此其带来的扩展性优势有限。
图 1.时隙时间线可视化 JIT/AOT 定义。AOT 数据块(橙色)在关键路径之前传播;JIT 数据块(黄色)在需要其可用性的时隙的关键路径内传播。无论传播何时以及如何发生,验证人员都会验证所有数据块的可用性。
本文提出了一种名为Blob 流式传输的机制:将 AOT Blob 作为一级通道,采用基于票证的机制——用户可以提前购买 Blob 的传播权——与按现货价格计费的 JIT 通道并存,后者可以被视为当前的私有 Blob。流式传输通道采用叠加式设计:AOT Blob 在关键路径之前进行预传播,而 JIT Blob 在关键路径内进行传播。至关重要的是,基于票证的速率限制机制能够有效控制传播负载,从而确保预传播的可靠性——一致的节点视图和清晰的 DoS 防护能力。此外,由于传播权与可用性判定相分离(与 Blob 池不同),因此可以安全地在其上叠加数据可用性采样,将采样窗口扩展到整个时隙,从而实现 Blob 吞吐量的扩展。因此,所提出的机制可以被视为 Blob 池采样机制(例如垂直分片、水平分片)的替代方案,能够在实现相同吞吐量扩展的同时,提供以下优势:
- 对用户而言:强大的抗审查保证、提前获取 blob 空间的可能性、放宽 blob 交易的内存池限制。
- 协议:明确的负载界限和更小的关键路径传播窗口,从而缓解自由期权问题。
图 2.时隙的双通道视图。AOT 数据块在关键路径之前预先传播,并随时间推移而扩散;JIT 数据块与有效载荷一起在关键路径内传播。验证器会验证所有数据块的可用性。
基于票证的设计可以同时支持 JIT 和 AOT blob。但是,我们选择保留现有的 JIT 路径,其中容量按现货价格定价,而不是通过票证分配,以适应不涉及提前容量规划的用例,例如(纯粹的) 基于 blob 的汇总,以及最终 L1 本身对 blob 的使用( blobs 中的块, 原生汇总)。
在深入探讨机制的具体细节之前,让我们通过分析 AOT 和 JIT 数据块的供需情况,来阐述引入 AOT 通道的必要性。
协议视角(供应方)
系统提供的 AOT 数据块吞吐量明显高于纯 JIT 吞吐量,因为 JIT 数据块必须在受以下因素限制的狭窄时间窗口内传播:
- 下一个提案方和建设方需要在采取行动前确定可用性。
- 自由选择权问题,随着我们延长这个窗口期,这个问题会变得越来越严重。
这会在传播窗口期间造成带宽激增,而在该时隙的其余时间里带宽则基本处于闲置状态。通过AOT数据块的预传播,传播会扩展到更大的时间窗口(见图2),从而平滑带宽消耗并避免瓶颈。有效的预传播可以实现带宽在容量范围内的稳定使用,进而提高吞吐量。
图 3. JIT 数据块与 AOT 数据块在不同时隙内的带宽变化示意图。JIT 数据块需要在较短的时间段内消耗带宽,导致带宽消耗波动较大;而 AOT 数据块的传播时间较长,带宽消耗较为平滑。
用户视角(需求方)
JIT blob 的主要应用场景是与 L1 实现同步组合,这需要 基于序列的验证以及实时证明。相比之下,外部序列化的 rollup 以及带有预确认的基于序列的 rollup (例如Taiko )可以使用 AOT blob。
也可能存在一种基于混合的汇总设计,它结合了预确认和同步可组合性,其主要方式是在 L1 时隙的大部分时间里使用预确认,但在 L1 区块生成期间切换到基于模式,从而实现该期间的同步交互。这种汇总可能混合使用 JIT 和 AOT 数据块,其中在 L1 区块生成期间需要使用 JIT 数据块,以实现与 L1 的同步交互。
至关重要的是,JIT blob 对于 L1 也变得非常重要,因为我们正迅速迈向未来,届时 zkEVM + DAS 将通过把有效载荷放入 blob 中来扩展 L1 本身,本质上是将 EL 变成有效性汇总。
即使考虑到这些用例,也很难准确预测未来 JIT 与 AOT 数据块的需求将如何变化。我们知道同步可组合性是有益的,但究竟有多大益处?我们知道它成本很高,但究竟有多高?我们知道 L1 需要 JIT 数据块,但它会占用总数据块吞吐量的多少比例?
我们认为,无需精确预测这两种数据块类型未来的需求,即可确定是否值得在协议中引入更多用于处理 AOT 数据块的机制。只要对 AOT 数据块存在显著需求(这似乎很有可能,因为并非所有汇总都希望完全基于数据块,即使是超大规模的 L1 层也不太可能消耗掉所有数据块吞吐量),所有数据块用户都能从将 AOT 数据块吞吐量转移到其专属通道中受益。如上所述,AOT 数据块可以利用当前未使用的关键路径之外的带宽。允许它们使用这些资源可以释放关键路径,供 JIT 数据块使用。这意味着引入 AOT 数据块不仅有利于使用它们的用户,也有利于 JIT 数据块的用户,因为他们可以获得更多受限的关键路径资源。
设计
现在我们从现有的 blobpool 开始,逐步构建完整的双车道架构,来描述该设计。
回顾:blobpool 门票
目前,预传播是通过EL blobpool进行的,但协议内部没有任何机制来分配传播带宽。随着blob吞吐量的增长,blobpool必然会分片——它没有全局方法来限制流入,因此只能在节点层面进行局部控制。此外,blobpool无法从数据可用性采样中获益,而且引入采样也极具挑战性:blobpool的安全模型依赖于仅传播有效且可包含的事务,而采样节点无法独立完全验证blob的可用性,因此在采样时很难确保这一点。
图 4.当前 blob 池中的预传播。请注意,blob 事务必须与完整的 blob 数据同步传播,因为后者的可用性是前者有效性的前提条件。
关于 blob 票务机制已有大量文献(参见此处、此处、此处),这些机制旨在拍卖 blob 传播的权利。最近,有人提出了blobpool 票务机制,作为朝着这个方向迈出的一步,它增强了 blobpool,以确保 blob 在 blobpool 中预先传播时能够抵御拒绝服务攻击,并且即使与 blobpool 采样机制一起实现,也能保持这种保证(参见垂直分片内存池和EIP-8070:稀疏 Blobpool )。
为了在 Blob 池中提交和传播 Blob,提交者需要持有有效的票据,该票据可通过与指定的票据合约交互获得(例如,通过实施第一价格拍卖)。这将确保通过 Blob 池传播的 Blob 数量受到限制,并公平地分配有限的空间。由于 Blob 池的准入现在由预付费票据控制,而不是通过有效性检查,因此也可以安全地引入抽样机制——节点不再需要验证 Blob 的完全可用性来决定是否传播交易。
图 5.使用 blobpool 票证扩充 blobpool。
Blob 票
Blob 票证进一步扩展了票证概念,将预传播移至变更列表 (CL),并将其更深入地集成到数据可用性管道中。这与 Blob 池票证主要有两点不同:
- 对于 AOT blob,用户只需一张票券即可将 blob 添加到链上。特别地,AOT blob 交易在被添加到链上时无需支付 blob 基本费用,只需支付常规 gas 费用。因此,票券被称为blob票券而非blobpool票券——您购买的实际上是 blob 空间,而不仅仅是 blobpool 空间。从协议的角度来看,这是因为传播过程才是真正消耗稀缺带宽资源的地方。(JIT blob 将在后面讨论,并且仍然采用现货价格。)
- 传播过程转移到 CL ,重用其已开发的用于 DA 采样的基础设施,否则需要在 EL 上重复开发。此外,DA 采样是共识机制的根本组成部分,因为 DA 是将区块导入 fork-choice 的前提条件。目前,我们通过
getBlobs引擎 API 调用将 EL 预传播和 CL 可用性强制执行整合在一起。
工单工作流程如下:
- 购买门票:通过向门票合约发送交易,用户可以获得在未来某个时间传播 blob 的权利。
- 传播:
- Blob :用户使用票据(在指定时间)通过 CL 采样基础架构推送 blob 数据。
- Blob tx :同样使用票据,blob tx(不带 blob 数据)会进入常规内存池。
- 包含性和可用性强制执行:当包含 blob 事务时,证明者会强制执行关联的 blob(由
blob_tx.versioned_hashes标识)的可用性,就像今天一样。
图 6.用户使用 blob 票据的工作流程。用户获取票据,在 CL 上传播 blob,并将 blob 事务提交到 EL 内存池。一旦 blob 事务被包含在数据块中,其功能与现在完全相同,数据块的有效性取决于相关 blob 的可用性,从而为用户提供严格的可用性保证。
每张票都赋予传播权:
- CL 上的一个斑点(传播方向右侧)
- 在EL上可以进行多笔blob交易。例如,最多可以进行16笔交易,这与Geth blobpool当前允许的最大blob交易数(
maxTxsPerAccount)以及Geth mempool中常规交易的默认最大保证mempool槽位数(AccountSlots)相匹配。但需要注意的是,这里的限制是针对每张票券的,而不是针对每个账户的。
这两项权限是独立的——CL 和 EL 各自独立跟踪票据的使用情况。这意味着票据持有者可以并行地在 CL 上传播其 blob 数据,并在 EL 上传播其 blob 交易,而无需各层之间进行协调。允许使用同一张票据在 EL 内存池中传播多笔 blob 交易,使得用户无需购买新票据即可重新提交交易,例如,当基础费用变更导致交易失效时。
用户须知:将 blob 交易的传播与票据(而非其有效性)挂钩,可以让内存池摆脱目前对其施加的严格规则。具体来说,同一个地址可以并行排队多个 blob 交易,因为一个交易导致其他交易失效的情况并不重要——再次强调,传播权限取决于票据,而非有效性!这对 blob 提交者来说是一个切实的痛点,如果不加以解决,随着各个 L2 交换机吞吐量的增加,这个问题只会愈演愈烈,因为每个交易的 blob 数量上限会导致每个 L2 交换机的交易速率增加。
混合设计:AOT + JIT
根据我们目前讨论的内容,AOT 和 JIT 在结构上原则上可以相同:我们可以设计一个系统,使所有容量(包括关键路径容量)都通过票券出售。在这种系统中,JIT 和 AOT 的区别仅仅在于传播时间。
这种仅使用票券的设计对于能够提前规划吞吐量并购买票券的参与者(例如外部排序汇总的运营商)的 blob 需求来说非常有效。然而,一旦需求包含没有规范票券管理器的开放式用户流,这种设计就会失效:用户不能被期望提前获取票券,而默认将构建者设置为中间票券会造成库存、资金和中心化方面的压力。在需求高峰期,即使网络仍然具备关键路径传播能力,票券库存也可能成为瓶颈。这不仅适用于最终使用 blob( blob 中的 blob )的 L1 本身,也适用于基于 blob 的汇总。
因此,本文最终提出的架构明确采用了混合架构,引入了基于票证的AOT blob以及按现货价格计费的JIT通道。最终用户可以通过交易直接支付关键路径blob资源(JIT blob,通过blob基础费用),而计划流程(AOT blob)可以使用票证(并从中受益)。在有效负载中,这种分离通过引入两个版本化哈希列表来明确体现:
-
jit_versioned_hashes:用于构建者即时提交的 blob。它们与有效负载一起传播(采样),并立即支付其资源费用(通过设置为等于\text{bf}^{AOT} bf A O T的 JIT blob 基本费用 - 有关更多详细信息,请参阅票据合同部分),就像今天的 blob lane 一样。 -
aot_versioned_hashes:已预先随票证传播的 blob,现在被声明为可用。购买票证时已支付 blob 资源费用,无需立即付款。
这两个列表都将有效载荷的有效性取决于可用性:所有与jit_versioned_hashes和aot_versioned_hashes对应的 blob 都必须可用,有效载荷才能成为规范有效载荷。区别仅在于传播资源的付费和使用方式。
总而言之,网络传播资源被明确地分为两类:关键路径和非关键路径。不同的市场分别管理这两类资源的分配:预先进行的链上门票拍卖用于传播前的容量分配,而关键路径传播则采用即时现货市场,在该市场中,构建者拥有最终的分配权。
JIT 机制与当前的 blob 通道本质上相同:关键路径传播、构建者驱动的包含,以及在包含时通过 blob 基本费用进行即时支付。但需要注意的是,由于 JIT blob 没有 blob 池预传播,用户必须直接将他们的 blob 发送给构建者。因此, JIT blob 对应于当前的私有 blob。AOT机制是新增的,它提供了一条具有不同特性的额外路径:提前购票、预传播(因此容量更高),以及我们将看到的抗审查性 (CR) 保证。对于任何可以预传播的 blob,此路径都将成为默认路径。
JIT 与 AOT 产能对比
混合设计中出现的一个根本问题是资源分配:我们应该将多少网络容量用于传播 Blob 数据,多少用于 AOT Blob?我们提出了一种设计方案,其中容量约束由三个参数控制,这些参数的设置方式与目前 Blob Gas 目标和限制的设置方式非常相似:
- B_1 B 1 ( JIT max ):每个时隙的 JIT 代码块最大数量。这是一个上限,取决于我们愿意完成关键路径的时间长短——以及我们相应地可以容忍的自由选择窗口的大小。
- B_2 B 2 ( blob (JIT + AOT) max ): 每个时隙的最大 blob 总数,是 JIT + AOT 的聚合限制。该值由网络在一个时隙内的总传播吞吐量决定。
- R \leq B_1 R ≤ B 1 (保留的 JIT 容量):JIT 容量的一部分,受到保护,免受 AOT 使用。
这些参数对给定的时隙n导出以下规则:
- AOT 门票销售:最多可售出B_2 - R B 2 − R个未来时段的门票。由于R R已预留给 JIT,因此最多只能提前安排B_2 - R B 2 − R个区块。
- JIT 容量:如果已为时隙n调度了a \leq B_2 - R a ≤ B 2 − R AOT blobs,则最多\min(B_1,\, B_2 - a) min ( B 1 , B 2 − a )可以包含 JIT 块。这保证了至少R R JIT 容量,并允许 JIT 在 AOT 需求较低时扩展到B_1 B 1 。
B_2纯粹是一个技术约束,反映了网络在一个时隙内的总传播预算。B_1则需要更大的灵活性:它受时隙结构的限制,但可以设置得更低以限制空闲选项窗口。然而, B_1对 JIT与AOT并没有预设要求——所有超出R R 的容量都是共享的,因此较高的B_1值只是允许 JIT 在 AOT 需求较低时进一步扩展到共享池中。
最有趣的设计选择是R R。未预留容量B_2 - R B 2 − R是一个共享池,可供 AOT(通过票券)和 JIT(如果 AOT 需求有余量)使用。将R R设置得太低可能会导致 JIT 需求无法得到满足,尤其是在 L1 本身依赖于 JIT 数据块的情况下,这个问题更为突出。将R R设置得太高会将原本可以作为票券出售的容量转移到仅限 JIT 使用的路径中;预留容量永远不会完全丢失——原则上任何 AOT 活动都可以使用 JIT 数据块——但用户将被迫直接通过构建者进行操作,并失去协议的抗审查保证。
基准定价
作为基准,现有的二进制大容量费用更新机制可以照常应用。在规定的限制条件下, \min(B_1,\, B_2 - a) + B_2 - R min ( B 1 , B 2 − a ) + B 2 − R个斑点可以在槽位中出售, \min(B_1,\, B_2 - a) min ( B 1 , B_2 − a )作为当前时隙的 JIT blobs , B_2 - R作为未来时隙的票证。因此,如果时隙中调度的 AOT blobs 数量较少,则最多可以售出B_1 + B_2 - R ( B_1 + B_2 − R )个blobSchedule.target可以位于B_2\times2/3 ( B_2 × 2 / 3) , blob_gas_used由时隙中售出的 JIT blobs 和 AOT 票证总数乘以GAS_PER_BLOB计算得出。实际上,我们还会向blobSchedule添加新变量B_1 (B_1 ) 、 B_2 (B_2 )和R ( R) ,这些变量施加了整体机制所需的更细粒度的容量约束。
提高吞吐量的票务合同和定价机制
如前所述,购买车票时,需要向专用车票合约发送交易信息。该合约有两个主要功能:输出新车票以及更新已使用或过期的旧车票。车票合约根据上述容量限制输出 AOT 车票。车票价格根据 AOT 基本费用\text{bf}^{AOT} bf A O T设定,该基本费用由目标 AOT blob 容量通过 EIP-1559 类型的控制器机制设定。如前所述,JIT 的基本费用等于\text{bf}^{AOT} bf A O T。
具体而言,这意味着如果售出的票数超过或少于目标票数,则从时隙i到时隙i+ 1的bf ^{AOT}会增加或减少。其中,目标票数是 AOT 区块容量的函数,即B_2 - R , AOT_target = B_2 - R。基本费用的更新规则可以与EIP -1559 中使用的规则完全相同:
$$\text{bf}^{AOT} {i+1} = \text{bf}^{AOT} {i} \times \Big(1 + \frac{1}{8} \times \frac{\text{AOT} {i} - \text{AOT} {\text{target}}}{\text{AOT}_{\text{target}}}\Big)$$
其中\text{AOT}_{i} AOT i是在i i号售票处售出的票数。
每笔票务交易需要指定四个变量: base_fee 、 auction_bid 、 number of tickets (合约可从中扣除auction_bid_per_ticket = auction_bid / number of tickets 、 base_fee_per_ticket = base_fee / number of tickets )以及sender_adress指定接收票务的地址)。票务交易要获得票务,必须满足条件base_fee_per_ticket ≥ bf^{AOT} ≥ bf A O T。交易按auction_bid_per_ticket降序排列,并分配票务,最多分配2×(B_2 - R) 2 × ( B 2 − R ) 。
如果出现超额需求(即,如果用户在给定时段内尝试购买的票数总数超过2 × ( B₂ - R )的限制),则成功获取票券的交易的base_fee和auction_bid将被销毁,而未能获取票券的交易的相应值将被退回给发送方地址。回想一下,AOT blob 的吞吐量容量为B₂ - R。因此,所有票券(由于我们将限制设置为容量的两倍,因此数量不超过B₂ - R )对应于有序交易列表底部的交易,在下一个时段内都将有效。例如,假设B₂ - R = 5 ,且时段N中竞标者的顺序如下:Alice: 3张票,Bob: 4张票,Charlie: 3张票。那么,Alice 将在时段N+1收到3张票,Bob 将在时段N + 1收到2张票。对于N+1 N + 1和2 2 号槽位N+2 N + 2 ,查理将收到3 3 张N+2 N + 2 号槽位的票。在需求不超过2\times(B_2 - R) 2 × ( B 2 − R )的情况下,每次交易都会销毁\text{bf}^{AOT}\times bf A O T × number of tickets对应的值。
最后,需要注意的是,没有理由只出售下一个时段的门票。我们也可以考虑出售在时段N中有效的门票,这些门票适用于时段N+ k 。能够提前获取门票对 L2 系统来说意义重大,因为 L2 系统可以利用这一点,在预先了解特定数据块价格的情况下,更准确地为自己的交易定价。至于具体细节——例如 k应该多大?用户是否应该能够从一系列选项中指定他们想要的时段门票?——等等,目前仍是一个开放性问题。
抵制审查
AOT通道的一项关键承诺是确保blob交易的抗审查性。票证允许我们识别一组受限的blob,其可用性可由委员会确定,从而确保它们能够被纳入协议——每张票证都可以被视为授予单个blob的纳入列表提议者角色。然而,仅靠blob票证的基础系统并不能完全实现这一目标。接下来,我们将指出这一差距,展示如何通过DA合约在链上记录可用性来解决这个问题,并在此基础上构建端到端的纳入保证。
blob票据的局限性
Blob 票据是一项意义重大的改进,但在抗审查方面仍存在缺陷。FOCIL 是一种抗审查机制,它允许委员会保证某些交易(例如从内存池中提取的交易)被纳入链表。然而,Blob 交易的有效性取决于其可用性。由于可用性没有记录,因此无法强制执行 Blob 交易的纳入。根本原因在于可用性只能在 Blob 交易被纳入链表的那一刻确定:即使 Blob 已经传播开来,并且所有人都对其进行了采样,也没有记录表明哪些 Blob 可用,而验证可用性的唯一方法是将 Blob 交易纳入链表。
录音权限:DA合同
一种简洁的解决方法是独立于 blob 事务包含情况来记录可用性。我们引入两项更改:
- 有效载荷可以包含独立于 blob 交易的版本化哈希值。构建器可以包含一个 blob 版本化哈希值列表,用于声明其可用性,即使同一区块中没有相应的 blob 交易。
- 可用性记录在 DA 合约中。在每个区块开始时,系统调用会将有效载荷中的版本化哈希值记录到 DA 合约中。这样就创建了一个记录,显示哪些 blob 可用,节点(作为 mempool 和 FOCIL 参与的一部分)以及 EVM 内部都可以查询该记录。
强制可用性机制与现在完全相同:认证者只会对数据块可用的区块进行投票。如果构建者为不可用数据添加了版本化哈希值,则该区块将无法获得认证。唯一的区别在于,版本化哈希值现在可以直接来自有效负载,而不仅仅是来自数据块交易。
此外,我们调整了链上 blob 交易的行为以使其与合约兼容。Blob 交易的有效性仍然取决于相应 blob 的可用性,但为了确保这一点,我们现在会在验证blob_tx时检查 DA 合约中blob_tx.versioned_hashes的可用性。特别地,如果blob_tx.versioned_hashes已在之前的区块中记录为可用,则我们不再要求将其包含在payload.versioned_hashes中。可用性只需确认一次。
注意:由于 DA 合约可在 EVM 内查询,常规交易也可以检查 blob 的可用性,例如,合约可以根据特定 blob 是否可用来调整其逻辑。Blob 交易可以继续作为主要接口,但 DA 合约为与可用性进行更灵活的交互打开了大门。
图 7.可用性记录与强制执行,以及 blob 交易有效性。构建器包含一个版本化哈希列表,该列表指向可用的 blob,其可用性通过证明来强制执行。版本化哈希记录在一个专用的 DA 合约中,blob 交易验证会检查该合约中的可用性。
此外,我们调整了内存池中 blob 交易的处理方式,以便内存池能够利用合约中的可用性信息。现在,如果满足特定条件,blob 交易就可以在内存池中传播。
任何一个:
1.可用性已记录:所引用 Blob 的可用性已记录在 DA 合约中,或者
2.发送方持有未使用的票据:发送方拥有尚未在 EL 上使用的有效票据(节点在本地可以看到)。
换句话说,只有当 blob 交易在可用性记录之前传播时(例如与 blob 本身并行传播),才需要票证。可用性记录后,blob 交易可以像普通交易一样,按照正常的内存池规则进行传播。这也解决了基础票证系统的一个实际限制:如果没有 DA 合约,一张票证只能提交有限的 blob 交易,并且内存池必须将 blob 交易的传播限制在票证持有者范围内。可用性记录后,这些限制就消失了——例如,重新提交不再需要特殊处理。
图 8.基于 DA 合约的 blob 和 blob tx 传播全貌。一张票据授予两项独立的传播权限:CL 上的一个 blob 和 EL 上的几个 blob tx。在 DA 合约中记录可用性后,blob tx 无需票据即可自由传播,从而实现无限次重新提交。
blob txs 的完整包容性故事
由于可用性记录独立于 blob 交易,我们现在可以通过首先确保 blob 的包含(可用性确定)来为 blob 交易提供抗审查性。我们通过基于 blob 票据的机制来实现这一点,并将类似 FOCIL 的 fork 选择强制执行机制应用于 blob:
- 有效载荷及时性委员会 (PTC) 的每个成员都会观察哪些数据块已在区块生成前的截止时间前传播。他们会对这些数据块进行抽样,并形成本地可用性视图。
- 成员们会发送他们观察到的可用版本化哈希列表。
- 多数投票决定提案人必须在有效载荷中包含哪些版本化的哈希值(从而记录在 DA 合约中)。
- 提案人可以添加额外的二进制数据块,但不能排除 PTC 要求的数据块。
- 验证者强制执行此规则:他们只对包含 PTC 要求的版本化哈希值的区块进行投票,除非验证者在本地看不到这些 blob 可用(安全始终优先)。
请注意,现在提案者在 blob 包含方面受到双向约束:他们必须包含 PTC 要求的内容(活性),而不能包含不可用的内容(安全性)。
至关重要的是,一旦记录了 blob 的可用性,引用该 blob 的 blob 交易就等同于常规交易,因为其附加的有效性条件保证得到满足:
- 如前所述,根据正常的内存池规则,它可以在没有票据的情况下传播。
- 它可以通过常规的FOCIL接口包含进来。
此外,票据交易本身也是常规交易,共享相同的内存池和FOCIL基础设施。因此,我们获得了针对blob交易的端到端抗审查机制。
图 9. blob 交易的端到端包含保证。PTC 强制包含传播的 blob(作为 DA 合约中记录的版本化哈希),而 FOCIL 为购票和 blob 交易提供包含保证。
请注意,这种端到端的抗审查机制适用于使用 AOT blob 的 blob 交易。即使 AOT blob 在给定区块的 PTC 截止时间之后传播,只要它仍然可用,仍然可以从下一个区块开始获得包含保证——这与常规的 FOCIL 行为类似,即在 IL(包含列表)截止时间之前不在内存池中的交易不能被强制包含在当前区块中,但可以包含在下一个区块中。
另一方面,JIT blob 的定义是,只有当它被包含在区块中时才会传播——没有预先包含的传播路径,因此无法提前确定其可用性并保证其被包含。当 JIT blob 被允许传播时,它实际上已经被包含在区块中了。我们可以将 JIT 容量理解为将一部分工单(“关键路径”部分)分配给提案者,提案者再将这些工单转售给构建者:构建者完全可以自行决定是否包含这些 blob(但会收取优先费用作为激励)。对于真正需要 JIT blob 的用例——例如为了实现同步组合而进行的区块和 blob 的共同创建——除了让构建者执行此操作之外别无他法,因此缺乏包含保证是其固有特性。对于并非严格需要共同创建的用例,未能作为 JIT 包含的 blob 可以始终作为 AOT 重新提交,从而获得上述完整的抗审查保证。
最后,我们将全面介绍该设计,并将其与当今的系统进行对比。
图 10.当前模式(上)与 Blob 流式传输模式(下)。当前模式下,blob 数据、可用性判定和执行在一个模块中耦合。而采用 Blob 流式传输模式后,AOT blob 通过票据预先传播,并根据 DA 合约进行验证;JIT blob 则像当前模式一样在关键路径上传播。DA 合约通过系统调用记录可用性,之后 blob 事务会根据该记录进行验证并正常执行。
附录
DA系统合同
设计考虑因素
- 写入模式:在每个块的开头,系统调用会记录该块中要断言可用性的 blob 的版本化哈希值。
- 读取模式:合约通过版本化哈希查询来检查数据块是否可用。这应该既简单又高效。
- 存储管理:必须定期删除条目以限制存储空间的增长。如果每个存储槽存储 128 个数据块,则无限制的存储空间每年将增长约 10 GB。
- 当前区块访问:与可用性记录在同一区块中的交易必须能够在没有外部证明的情况下检查可用性,因为它们无法为刚刚记录的数据生成证明。
合同设计
该合约通过环形缓冲区维护一个最近窗口(约 128 个区块),从而实现 O(1) 的无证明查询。这涵盖了当前区块访问和典型的汇总用例。
此外,用户还可以通过存储在每个区块头中的versioned_hashes_root来验证合约是否包含在内。这既能最大限度地减少合约存储空间,又能长时间地进行可用性查询,足以确保用户在 blob 可用性确定后仍能将交易上链。
请注意,当versioned_hashes包含在当前有效负载中时,验证 DA 合约作为 blob 交易验证的一部分,其开销非常低,因为这是一次热读——版本化哈希在区块开始时已写入 DA 合约。因此,当前可用性确定与执行同时进行的模式基本不受影响。
# Constants BLOCK_WINDOW = 128 MAX_BLOBS_PER_BLOCK = 128 RECENT_RING_SIZE = BLOCK_WINDOW * MAX_BLOBS_PER_BLOCK # Storage recent_vhs_buffer: list [ Optional [ bytes ]] = [ None ] * RECENT_RING_SIZErecent_availability: dict [ bytes , int ] = {} # vh => 1 if in recent window recent_write_cursor: int = 0 def record_availability ( versioned_hashes: list [ bytes ] ): """Called via system call at block start.""" global recent_write_cursor for vh in versioned_hashes: # Clear old entry at current position old_vh = recent_vhs_buffer[recent_write_cursor] if old_vh is not None : del recent_availability[old_vh] # Record new entry recent_vhs_buffer[recent_write_cursor] = vhrecent_availability[vh] = 1 recent_write_cursor = (recent_write_cursor + 1 ) % RECENT_RING_SIZE def is_available ( versioned_hash: bytes ) -> bool : """Check availability in recent window (no proof needed).""" return recent_availability.get(versioned_hash) == 1














