文章提出了FullDAS网络架构,旨在解决Danksharding中32MB大数据块的网络瓶颈问题。FullDAS通过区分数据可用性分散和抽样,设计高效的分散和抽样协议,包括liteDAS抽样协议、Topic Routing和Ephemeral Connect等机制,以及利用2D编码进行网络内修复以增强可用性,从而实现更大的区块数据处理能力。
作者:Csaba Kiraly,与来自 Codex.storage 研究团队的Leonardo Bautista-Gomez和Dmitriy Ryajov合作完成。
注意:本文档描述了我们当前的思考状态,是与其他团队合作努力和多次讨论的结果。如果没有 @dankrad , @djrtwo , @fradamt , @AgeManning , @Nashatyrev , @matt , @pop , 和 @Echo 的贡献和想法,这是不可能的。
最初的 Danksharding 提案 目标是 32 MB 的区块,这个大小主要是由于 DAS 数据结构 中使用的 KZG 承诺的计算约束而选择的。从那时起,网络设计经历了各种迭代,旨在有效地在 P2P 结构中提供区块数据,并允许节点从此结构中进行抽样。然而,这些结构都不能令人信服地支持 32MB 的区块,这使得网络解决方案的性能成为了真正的瓶颈。在这篇文章中,我们研究了这些网络问题并提出了解决方案,目的是使 32 MB(甚至更多)成为可能。
DAS(数据可用性抽样)的目标是高概率地确定给定的数据块是否已提供给任何感兴趣的人,并且在不需要系统中任何单个节点持有 - 甚至暂时接收 - 整个数据块的情况下完成此操作。
也就是说,我们希望将各个节点的带宽需求保持在当前(EIP-4844 之后)以太坊网络的水平,同时处理数量级更大的区块。从网络的角度来看,这是以太坊 DAS 设计的一个重要约束。
对于我们关于网络方面的讨论,重要的是要强调 DAS 有两个不同的部分:“使数据可用”部分和“抽样”部分。
首先,必须使数据可用。可用性意味着系统中的节点获得“足够”的数据,以便能够一起重建原始区块。因此,可用性是一个系统级属性:数据要么可供整个系统使用,要么不可用。至少,这是我们想要实现的。
与一般 P2P 系统一样,数据量最好不要“仅仅足够”,而应该是非常足够,这意味着即使存在流失、网络分区或大部分恶意节点,也可以重建数据。只有到这个时候,我们才能说数据已可用。
换句话说,我们应该设计一个协议,以确保没有临界情况:数据要么不可用(未由源发布),要么具有压倒性的可用性。正如我们稍后将看到的,正是纠错编码和强大且高度冗余的 P2P 网络结构之间的相互作用使这成为可能。
其次,进行抽样。抽样是单个节点对提供给系统的内容的看法。这是一个节点说服自己数据已可用的过程,它使用的技术是检索区块的几个片段。样本是要检索的片段的(通常是随机的)选择,而抽样是检索这些片段的过程。如果此抽样成功,并且在一些独立性假设下,节点可以让自己相信数据确实已可用。
重要的是,在后台,在 概率计算 背后,存在那些令人讨厌的独立性假设。从本质上讲,它假设数据的发布与所选样本无关(过去是,现在是,或者将来是)。不幸的是,这可以被利用,区块生产者及其“同伙”对节点的样本选择了解得越多,引入相关性从而愚弄某人就越容易。因此,样本选择和对选择的有限披露是安全保证的重要组成部分。
请注意,在这篇文章中,我们将区块的片段称为 段 (segments),但在使用 1D 编码时,它们也被称为“列 (column)”,在使用 2D 编码时被称为“单元 (cell)”,或者有时将令人困惑的术语“样本 (sample)”同时用于段以及所选段的列表。
另请注意,抽样不是我们可以用来“说服自己”数据可用的唯一技术。在不试图列出所有可能性的情况下,我们可以使用简洁的证明、可信的朋友等。然而,抽样是无需信任的,并将数据段传播到系统中的所有节点,最终实现额外的冗余层,从而实现恢复。
无论是在使数据可用时,还是在节点进行抽样时,区块的段都会被传递到节点。但是,哪些段传递到哪个节点是由这两个阶段的不同目标驱动的。
我们将应该传递给节点的段称为其兴趣 (interest)。系统中我们有两种类型的兴趣。它们相似,但用途不同且具有一些根本的区别:
兴趣可以随时间变化,例如对于样本选择,从一个 epoch 到另一个 epoch,或者对于托管,以一些其他时间粒度变化。更改它或保持固定对安全性和网络效率都有影响。
数据可用性和抽样的需求之间的根本差异,以及托管和样本的属性之间的根本差异,也反映在网络设计中。我们可以区分段分配的两个阶段:
这两个阶段可以使用不同的 P2P 网络结构。在下文中,我们将重点关注这些网络结构,为分散和抽样推导出快速、强大且带宽高效的协议。
FullDAS - LossyDAS - liteDAS - 数据可用性抽样组件960×720 80 KB
在最初的设计中,计划使用 GossipSub 进行分散,具有许多(列为 512 个,行为 512 个)主题,将列和行分配到所有 staked 节点(具有验证器的信标节点)的托管中。相反,对于抽样,计划从所有完整节点(staked 和非 staked)设置一个单独的 DHT,用于服务所有抽样查询。正如我们在 我们的相关文章和论文中强调的那样,这带来了一些挑战。
因此,在 PeerDAS 和 SubnetDAS 中,我们调整了设计以提供中间解决方案,在功能和可扩展性方面都做出了妥协。
在 PeerDAS 中,我们修改了托管分配和分散,使其基于 NodeID,使所有完整节点(包括 staked 和非 staked 节点)都成为托管系统的一部分。然后,使用节点现有对等方的请求/响应(Req/Resp)协议从此 P2P 结构进行抽样,从而增加了对等方发现(Discv5)的压力以及节点必须维持的对等方数量。
相反,SubnetDAS 修改了设计,以始终使用 GossipSub 分发机制,包括分散和抽样。同样,这限制了我们的可能性,也牺牲了抽样查询的不可链接性。
即使对于几个 MB 的区块,快速且带宽高效的实现也被证明具有挑战性,这就是我们得出主要主题的地方:如何使 DAS 适用于 32 MB 及以上的区块?
在下文中,我们将介绍堆栈的重要部分:
从抽象层面来看,抽样听起来非常简单:
然而,实际上,事情变得更加复杂。在 我们关于 LossyDAS、IncrementalDAS 和 DiDAS 的文章 中,我们已经处理了一些与样本选择相关的复杂性,但我们已经省略了该文章中的所有网络方面。
要设计抽样协议,除了上述草案大纲之外,我们还应该回答以下问题:
此外,我们应该设计一个快速、强大且带宽高效的协议。
对于抽样,我们建议使用 liteDAS,这是一种新的 Req/Resp 协议,旨在提供接近最小的抽样延迟和接近最小的带宽使用,避免在正常情况下和出现问题时过度使用资源。liteDAS 背后的关键观察结果是:
我们提出的消息传递原语是带有显式超时的请求。这个简单的原语允许我们尽早开始抽样(在 slot 开始时),并构建一个漂亮的动态行为,初始阶段处理正常情况,第二个阶段处理潜在问题,如下所述:
在 T_0(slot 开始,或已知公共参数时)
从直觉上讲,这很快(将抽样延迟减少到接近最小值)、带宽高效(在正常情况下每个段仅发送一个 Req/Resp)且稳健(在托管应该存在时探索抽样选项)。
在 slot 开始时发送抽样查询使我们能够将抽样延迟最小化为在分散延迟(我们查询的节点收到段或列的延迟)之上的单个 1 跳延迟。
更详细地说,为了理解为什么这很快,让我们看看最快的情况是什么。最小抽样延迟将是如果节点在知道需要什么样本时立即询问,它可能拥有该样本的所有对等方,即计划托管该段的所有对等方可以实现的延迟。然而,这将意味着我们的节点会收到大量响应,从而增加相当大的额外负载。在 liteDAS 中,我们一次只询问 P 个,作为带宽效率和延迟之间的折衷方案。我们关于 GossipSub 延迟分布的数据 和我们的初始模拟表明,在正常情况下,延迟妥协非常有限。
该协议在正常情况下精确地接收每个样本(或列)一次。在不正常的情况下,我们可以通过遵循具有短超时时间的顺序逻辑,或者通过在稍后阶段更改 P 来允许某种并行性(从而产生重复),从而设置折衷方案。重要的是,如果数据实际上不可用,它仍然会将资源利用率保持在限制范围内。
在第一阶段,上述抽样的稳健性依赖于分散的稳健性。分散已经采用了许多可靠性技术,因此,在正常情况下,对于每个 ID,我们选择的单个节点很可能收到样本。
相反,如果分散存在问题,我们的抽样也会变得不那么对延迟敏感:在通过托管广泛可用之前,无论如何抽样都不应该成功。因此,我们有时间“寻找”段。在初始阶段之后,我们的协议将循环遍历潜在的其他对等方,这些对等方托管同一个段。在那时,我们还可以并行发送更多查询,最终允许一些重复。
除了基本思想之外,还有一些其他的调整可以改善动态行为:
liteDAS 仍然假设我们有所需的对等方来发送请求。如果我们没有这些对等方,并且我们必须搜索托管给定 ID 的对等方怎么办?如果我们在请求该段之前还必须经过一个复杂的连接过程怎么办?
如前所述,我们可以预测对托管对等方的搜索。尽管如此,有时我们需要搜索具有特定 ID 的托管对等方,并且搜索应该相对较快。这是目前在围绕 DAS 的讨论中争论的一个关键点。作为抽样过程的一部分,我们需要在几秒钟内找到并连接到对等方,这似乎是主要的限制因素之一。分散也存在类似的问题,即在构建用于有效基于列(/行)的分发的网格时,尽管在这种情况下,时间安排不太重要。
AgeManning 在 PeerDAS 规范讨论的一部分 中很好地总结了当前协议栈的问题。使用当前堆栈从新对等方获取单个段非常低效。显然,该问题有两个主要的潜在方面:
首先,让我们看看我们可以做些什么来快速查找给定段的托管节点。关键是明智地分配托管。
由于我们需要全系统的可用性,因此必须正确分配托管,以提供良好的覆盖范围。随机本地选择可以提供这一点,但幸运的是,我们可以做得更好。托管的一个很好的属性是我们不需要隐藏谁托管什么。我们可以使用此属性,通过以确定性的方式从 NodeID(最终通过一些轮换方案并使用公共随机性)派生托管兴趣,从而使我们的系统更高效。公开节点的托管兴趣似乎不会影响安全性。而且,我们似乎可以提前 public 地公开兴趣(保持托管在时间上稳定,类似于我们今天对证明所做的那样),并且它仍然不会产生安全问题。
请注意,这里有一个问题:通过使用 NodeID,我们像最初的提案中那样没有将托管绑定到验证器,而是绑定到完整节点(包括非 staked 节点)。因此,我们无法真正强制执行托管。我们目前无论如何都不想强制执行它,但稍后我们可能会引入 托管证明,然后我们必须重新审视这一点。而且,相对容易创建一个大量新的 NodeID,从而有可能将托管暴露于有针对性的女巫攻击。
通过从 NodeID 派生托管,我们可以通过两种方式加速搜索。首先,我们可以从 nodeID 的最左侧位派生托管。这允许我们使用 Discv5 Kademlia 搜索而不是随机游走,因为 Kademlia 是基于前缀的。其次,如果使用托管轮换方案(节点在某个周期内更改它们托管的列/行),我们可以从 NodeID 计算出这一点,而无需联系对等方或从 Discv5 获取更新的 ENR 记录。
我们已经在 PeerDAS 中使用了这种基于 NodeID 的确定性托管分配技巧:它使我们能够提高分散效率,并且还允许抽样对等方更容易地找到托管节点,只需基于 NodeID 和与 ENR 中的 NodeID 一起发布的一小部分元数据。
请注意,对于 样本(sample) 来说并非如此,我们确实关心使其相对难以弄清楚给定节点将要抽取的内容,否则我们将很容易攻击单个节点。因此,我们无法从 NodeID 派生样本(段 ID 列表),而且我们最好避免将整个样本(再次,ID 列表,而不是数据)发送到单个节点。因此,我们更希望节点按需请求样本,最好选择性地向不同的对等方公开兴趣,从而限制单个节点的暴露。
我们掌握的另一个选择是将托管节点搜索直接引入到我们的协议中,从而规避 Discv5 的困难。
在当前提案中,列是使用 GossipSub 分发的,不同的列 ID 映射到不同的 GossipSub 主题。列 ID 空间被视为一个平面列表,而不考虑主题之间的任何关系。
但是,我们不必将行和列 ID 空间视为平面 ID 空间。我们可以使用几乎任何距离度量,并要求节点保持几个与其列/行 ID 接近的邻居,从而实现更快的搜索。以下是一些解释这可能如何工作的示例:
[C-D, C+D] mod NUM_COLS
的邻居,对于一些选定的 D
和 N
C+2^j mod NUM_COLS
的邻居,对于 j in [0..log2(NUM_COLS}-1]
第一个(循环)实际上不可扩展,最后两个具有良好的可扩展性。但是,如果我们保持列(和行)的数量足够低,那么这些都足以很好地找到任何 C 的潜在邻居。如果我们想扩展得更高,我们可能想为我们的使用选择最好的一个。
请注意,主题 ID 空间是密集的,每个 ID 代表一个主题,并且我们拥有的节点数预计会高于主题数。相比之下,在典型的 DHT 中,密钥和节点 ID 在 ID 空间中是稀疏的。拥有密集的 ID 空间使我们能够简化搜索。
相对容易扩展上述任何技术来处理行和列,可以通过将列和行 ID 空间作为两个单独的 ID 空间处理,或者通过定义一个联合距离函数来处理。
还要注意的是,当在 2D 中抽样时,我们寻找的是列 C 中的节点或行 R 中的节点。这些都足够了,使我们的搜索更快。
连接问题主要是由于协议限制,因为我们是在 libP2P 上运行的,libP2P 最初并非为快速连接而设计的。我们通过对已连接对等方保持严格限制,并且许多节点中都保持满员,从而使我们的生活更加艰难(众所周知,有些对等方不接受连接,因此其他对等方会过载,其对等方计数已满,因此也不接受新连接)。
我们在下面列出了此问题的一些可能解决方案:
我们认为这些可以解决连接问题,使我们能够获得 FullDAS。但是,需要进行更多测试。
最初,我们打算使用 GossipSub 进行分散,原因有几个。它是一个发布-订阅协议,可以很好地映射到纠删码结构,为每列创建单独的主题(如果使用 1D 纠删码),或者为列和行创建单独的主题(如果使用 2D 纠删码)。正如我们在 我们相关的文章中讨论的那样,该协议经过了实战测试,已经在以太坊中用于区块扩散和证明聚合,显示出快速且可靠的运行,该文章测量了区块扩散和证明的延迟分布。
在 PeerDAS 中,我们实际上是将分散问题映射到相对较少数量的 GossipSub 主题。虽然这是一个合理的首要方法,但有些方面是分散问题所特有的,并且可以进行性能优化。
对于 1D 和 2D 纠删码情况,我们都使用 我们的自定义 DAS 模拟器 研究了区块可以多快地分散到托管中。正如在 我们在 EthereumZurich’23 上的演讲 中以及在后来的演讲(EDCON’23、EthPrague’23、EthCC’23)中显示的那样,如果正确填充列和行主题,GossipSub 可以在几秒钟内将区块数据分散到数千个节点。但是,在这些演讲中,我们之所以谈论类似于 GossipSub 的发布-订阅协议是有原因的。GossipSub 本身并不是我们拥有的最佳选择。我们认为我们可以做出一些改变,使其在我们案例中运作良好。最终,我们还可以专门针对分散用例推导出自定义协议。
在下文中,我们将列出通用 GossipSub 主题的使用和分散之间的一些可能区别,从而显示可以进行的一些优化。我们将专门用一篇单独的文章来详细扩展这些内容。
纠删码在 DAS 描述中主要被描述为一种使抽样更稳健的工具。但是,我们应该强调的是,我们可以将纠删码用于设计中的两个目的:
放大抽样 已被很好地理解:使用速率为 R=K/N(例如 1/2)的代码,并假设数据不可用,每个单次抽样的片段都会将未发现数据不可用的可能性降低 2 倍。我们喜欢这种指数属性,它使我们能够仅通过抽样少量片段来实现非常低的假阳性(FP)率。在 2D 情况下,该比率不如在 1D 中好,但我们仍然具有良好的指数属性。
放大可用性 是不同的事情。这意味着如果数据可用,我们使其具有压倒性的可用性。我们通过在分发期间使用 网络内修复 来实现此目的。这是我们的纠删码结构和分发网络结构相遇的地方。通过根据代码将节点组织成列和行,并通过使节点参与行和列,我们在分发期间启用 EC 结构中的本地修复。
然后,正如我们已经在 EthereumZuri.ch’23 演讲 中的模拟中显示的那样,这种网络内修复正在放大可用性。基本上,如果发布的样本不足,则片段计数保持在 75% 以下,而在许多构造中验证者和完整节点使用的基于行/列的抽样(SubnetSampling)仍然非常低。片段抽样也仍然非常低。
相反,如果再发布一个片段,则结果会通过分发结构放大到几乎 100%。
但是,要使这种放大机制起作用,我们需要 2D 代码。我们无法真正在 1D 情况下做到这一点,因为在 1D 情况下,只能在具有 K 个片段(基本上是整个区块)的节点中进行修复。相反,在 2D 情况下,我们可以在任何单个行或列中进行修复,因此单个节点可以修复然后发送。换句话说,我们需要具有本地修复的代码。我们可以使用 2D RS 制作这样的代码(如果需要,还有其他具有本地修复能力的代码构造)。
因此,虽然我们可以通过多种方式将片段 ID 映射到托管,但我们会按列和行进行映射,以在分发期间启用网络内修复和放大可用性。
我们撰写本文的目的是概述 FullDAS 的主要构建块,这是我们为具有 32MB 及以上区块的 DAS 提出的网络堆栈。我们讨论了将区块数据分散到托管的 P2P 结构中的新方法,同时还放大了数据可用性。我们还展示了使用 liteDAS、主题路由和改进的连接机制从该结构实现快速、带宽高效且稳健的抽样所需的工具。
在这一点上,许多人可能已经清楚,我们正在构建类似于 DHT 的东西,这是一个过去被多次提出的观点:分散到托管和抽样之间的区别,以及 DHT 的通用概念并没有那么大。实际上,通过 FullDAS,我们正在构建一个特殊的分布式存储结构,具有自定义播种、修复和检索,每个都针对 DAS 编码和 DAS 目的进行了优化。
以上一些技术已经在模拟中进行了评估,而另一些技术仍在进行中。我们为此目的编写了两个模拟器:
这两个都在进行中,我们计划在 FullDAS 协议的改进和评估进行时发布更多帖子。
我们之前关于采样技术的帖子:LossyDAS、IncrementalDAS 和 DiDAS
在以太坊中启用数据可用性采样时,使用 Kademlia DHT 的可扩展性限制
我们关于测量 GossipSub 延迟分布的帖子,包括用于区块时和用于证明时
我们之前关于 DAS 的演示文稿:
我们的 DAS 模拟器:
具有高抽象级别的 DAS 模拟器,用 Python 编写,用于大规模实验
具有较低抽象级别的 DAS 模拟器,直接在 Shadow 上使用 nim-libP2P 堆栈
- 原文链接: ethresear.ch/t/fulldas-t...
- 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!