文章提出了一种基于随机线性网络编码(RLNC)的以太坊区块和blob传播方案,旨在优化P2P网络中的广播和传输效率。通过将区块分割成小块并进行编码,该方案理论上可以在降低带宽消耗和减少网络跳数的同时,实现更快的区块分发。初步的实验数据表明,该方法能够显著提升传播速度,尤其是在处理较大的区块或blob时。
感谢 @n1shantd、@ppopth 和 Ben Berger 对本文的讨论和反馈,以及 @dankrad (https://ethresear.ch/u/dankrad) 的许多有用的讨论。
我们提出了一种通过使用随机线性网络编码来广播和传输 P2P 网络中的区块和 blob 的方式的变更。我们证明了从理论上讲,我们可以以当前 gossipsub 实现所需时间的 5% 的带宽和 57% 的网络跳数(因此每个消息的延迟减半)来分发区块。我们提供了计算开销的具体基准。
当前用于分发区块的 gossipsub 机制大致如下。提议者在其所有 peer 中选取一个随机子集(称为其 Mesh),大小为 D=8
,并将区块广播给它们。每个收到区块的 peer 都会执行一些非常快的初步验证:主要是签名验证,但最重要的是不包括状态转换或事务执行。经过这种快速验证后,该 peer 将其区块重新广播给另外 D
个 peer。这种设计有两个直接的后果:
我们建议在广播级别使用 随机线性网络编码 (RLNC)。通过这种编码,提议者会将区块拆分成 N
个块(例如,对于下面的所有模拟,N=10
),而不是将完整区块发送给大约 8 个 peer,而是将单个块发送给大约 40 个 peer(不是原始块之一,而是它们的随机线性组合,有关隐私注意事项,请参见下文)。Peer 仍然需要下载一个完整区块,或者更确切地说 N
个块,但它们可以从不同的 peer 并行获取它们。在收到这 N
个块后,每个块都是组成原始区块的原始块的随机线性组合,peer 需要求解一个线性方程组以恢复完整区块。
一个概念验证 实现 突出了以下数字
10
个块和 D=40
,每个节点发送的数据是当前 gossipsub 的一半,并且网络以一半的时间广播一个 100KB 的区块,并且好处随着区块大小的增加而增加。有关网络编码的深入介绍,我们请读者参考 op. cit. 和 这本教科书。我们在此处提及上述概念验证基准的最低实现细节。在区块传播(约 110KB)的情况下,延迟或网络跳数决定了传播时间,而在完整 DAS 中像 blob 这样的大消息的情况下,带宽决定了传播时间。
我们考虑一个具有素数特征的有限域 \mathbb{F}_p。在上面的示例中,我们选择 Ristretto 标量基础域,如 curve25519-dalek rust crate 所实现的那样。提议者获取一个区块,它是一个不透明的字节切片,并将其解释为 \mathbb{F}_p 中的元素向量。在撰写本文时,一个典型的以太坊区块约为 B = 110KB,鉴于每个 Ristretto 标量需要略小于 32 字节来编码,一个区块大约需要 B/32 = 3520 个 \mathbb{F}_p 元素。分成 N=10
个块,每个块可以看作是 \mathbb{F}_p^{M} 中的一个向量,其中 M \sim 352。因此,该区块被视为 N 个向量 v_i \in \mathbb{F}^M_p, i=1,...,N。提议者随机选择 D\sim 40 个 peer 的子集。对于每个这样的 peer,它将发送一个 \mathbb{F}_p^M 向量,以及一些额外的信息来验证消息并防止网络上的 DOS。我们解释一下提议者
我们将使用 Pedersen 对 Ristretto 椭圆曲线 E 的承诺,如上面提到的 rust crate 所实现的那样。我们假设我们已经随机选择了一个足够元素的受信任设置 G_j \in E, j = 1, ..., K,其中 K \gg M。我们为 \mathbb{F}_p^M 选择一个标准基 \{e_j\}_{j=1}^M。因此,每个向量 v_i 都可以唯一地写成
v_i = \sum_{j=1}^M a_{ij} e_j,
对于一些标量 a_{ij} \in \mathbb{F}_p。对于每个向量 v_i,我们都有一个 Pedersen 承诺
C_i = \sum_{j=1}^M a_{ij}G_j \in E.
最后,对于大小为 D \sim 40 的子集中的每个 peer,提议者均匀随机地选择一组标量 b_i, i=1, ...,N 并将以下信息发送给该 peer
一个 已签名消息 是以上 1-4 的元素的集合。我们看到每个消息作为 sidecar 发送了 64N \sim 640 个额外的字节。
当一个 peer 收到上一节中的消息时,验证过程如下
Peer 跟踪他们收到的消息,假设它们是向量 w_i, i = 1,...,L,其中 L < N。它们生成一个子空间 W \subset \mathbb{F}_p^M。当他们收到 v 时,他们首先检查该向量是否在 W 中。如果它在 W 中,那么他们会丢弃它,因为该向量已经是之前向量的线性组合。该协议的关键是这种情况发生的可能性非常小(对于上面的数字,这种情况发生的概率远小于 2^{-256})。作为其结果,当节点收到 N 个消息时,它知道它可以从消息 w_i, i=1,...,N 中恢复原始的 v_i,从而恢复区块。
另请注意,只需要一个签名验证,所有传入的消息都具有相同的承诺 C_i 并且对同一组承诺具有相同的签名,因此该 peer 可能会缓存第一次有效验证的结果。
Peer 可以在收到一个块后立即将块发送给其他 peer。假设一个节点持有 w_i, i=1,...,L,其中 L \leq N,如上一节所述。一个节点还会跟踪他们收到的标量系数,因此他们知道他们持有的块满足
w_i = \sum_{j=1}^N b_{ij} v_j \quad \forall i,
对于他们在内部状态中保存的一些标量 b_{ij} \in \mathbb{F}_p。最后,节点还会保留完整的承诺 C_i 和提议者的签名,他们在验证他们收到的第一个块时已经验证了该签名。
节点发送消息的过程如下。
a_j = \sum_{i=1}^L \alpha_i b_{ij}, \quad \forall j=1,...,N.
他们发送的消息包含块 w、系数 a_j 和承诺 C_i 以及提议者的签名。
该协议有一些与 gossipsub 相同的组件,例如,提议者需要创建一个 BLS 签名,而验证者必须检查一个 BLS 签名。我们在此记录执行通常的 gossipsub 操作之外还需要执行的操作的基准。这些是协议在节点上具有的 CPU 开销。基准是在 Macbook M4 Pro 笔记本电脑和 Intel i7-8550U CPU @ 1.80GHz 上进行的。
这些基准的参数为 N=10,表示块的数量,总块大小被认为是 118.75KB。所有基准都是单线程的,并且都可以并行化
提议者需要执行 N 个 Pedersen 承诺。该基准测试结果为
时间 | 型号 |
---|---|
[25.588 ms 25.646 ms 25.715 ms] | Apple |
[46.7ms 47.640 ms 48.667 ms] | Intel |
接收节点需要为每个块计算 1 个 Pedersen 承诺,并执行由提议者提供的承诺的相应线性组合。这些时间如下
时间 | 型号 |
---|---|
[2.6817 ms 2.6983 ms 2.7193 ms] | Apple |
[4.9479 ms 5.1023 ms 5.2832 ms] | Intel |
发送新块时,节点需要执行它可用的块的线性组合。这些时间如下
时间 | 型号 |
---|---|
[246.67 µs 247.85 µs 249.46 µs] | Apple |
[616.97 µs 627.94 µs 640.59 µs] | Intel |
在收到 N 个块后解码完整块时,节点需要求解一个线性方程组。时间如下
时间 | 型号 |
---|---|
[2.5280 ms 2.5328 ms 2.5382 ms] | Apple |
[5.1208 ms 5.1421 ms 5.1705 ms] | Intel |
Apple M4 上提议者的总体开销是 26 毫秒单线程,而对于接收节点是 29.6 毫秒单线程。这两个过程都是完全可并行化的。在提议者的情况下,它可以并行计算每个承诺,而在接收节点的情况下,这些是自然并行事件,因为节点正在从不同的 peer 并行接收块。在 Apple M4 上并行运行这些过程会导致提议者端为 2.6 毫秒,接收 peer 为 2.7 毫秒。对于实际应用,与涉及的网络延迟相比,可以合理地将这些开销视为零。
一些尚未实现的过早优化包括在块到达时反转线性系统,尽管上面引用的概念验证确实将传入的系数矩阵保持为 Echelon 形式。最重要的是,消息的随机系数不需要像 Ristretto 字段那样大的字段。像 \mathbb{F}_{257} 这样的小素数域就足够了。但是,由于 Pedersen 承诺发生在 Ristretto 曲线中,因此我们被迫在更大的字段中执行标量运算。这些基准的实现为线性组合选择了小系数,并且这些系数在每次跳转时都会增长。通过正确控制和选择随机系数,我们也许可以将线性系统的系数(以及因此在发送块中的带宽开销)限制为以 4 字节而不是 32 字节进行编码。
执行这种优化的最简单方法是在 \mathbb{F}_q 上定义的椭圆曲线上工作,其中 q = p^r 对于某个小素数 p。这样,系数可以在子域 \mathbb{F}_p \subset \mathbb{F}_q 上选择。
隐私注意事项 上面链接的 PoC 中的实现认为每个节点,包括提议者,都选择小系数来复合其线性变换。这允许接收具有小系数的块的 peer 识别该块的提议者。要么采用上述优化来通过执行像 Bareiss' 扩展这样的算法来保持所有系数都小,要么我们应该允许提议者从字段 \mathbb{F}_p 中选择随机系数。
我们在一些简化假设下进行了块传播的模拟,如下所示。
我们使用发送消息的 peer 数 D=6。我们获得网络平均需要 7 跳才能将完整块传播到 99% 的网络,从而导致总传播时间为
T_{\mathrm{gossipsub, D=6}} = 7 \cdot (L + B/X),
以毫秒为单位。
\
gossipsub-total-theorical1712×982 70.6 KB
使用 D=8 的结果类似
T_{\mathrm{gossipsub, D=8}} = 6 \cdot (L + B/X),
浪费的带宽对于 D=6 为 94,060 \cdot B,对于 D=8 为 100,297 \cdot B。
对于 B 的低值,如当前的以太坊区块,延迟决定了传播,而对于较大的值,例如在 peer-DAS 之后传播 blob,带宽成为主要因素。
使用随机线性网络编码,我们可以使用不同的策略。我们模拟了一个系统,其中每个节点只会将一个块发送到其大小为 D 的 mesh 中的所有 peer,这样我们保证了产生的延迟与 gossipsub 中的延迟相同:每次跳转的单个延迟成本 L 毫秒。这要求 mesh 大小要明显大于 N,即块的数量。请注意,对于 gossipsub mesh 大小为 D_{gossipsub}(例如,当前以太坊中为 8),我们需要设置 D_{RLNC} = D_{gossipsub} \cdot N 才能消耗每个节点相同的带宽,对于当前值,这将是 80。
使用带宽的一半的更保守的值,即 D=40,我们获得
T_{RLNC, D=40} = 4 \cdot \left(L + \frac{B}{10 X} \right),
浪费的带宽为 29,917\cdot B。假设与今天相同的带宽,我们使用 D=80 得到令人印象深刻的
T_{RLNC, D=80} = 3 \cdot \left(L + \frac{B}{10 X} \right),
浪费的带宽为 28,124\cdot B,这是 gossipsub 中相应浪费带宽的 28%。
对于每个节点发送的相同带宽,我们看到传播时间的不同之处在于将延迟除以 2(有 3 跳与 6 跳),以及通过消耗每单位时间十分之一的带宽更快地传播块。此外,通过多余消息浪费的带宽被削减到 gossipsub 浪费消息的 28%。对于传播时间和浪费的带宽,也获得了类似的结果,但每个节点发送的带宽减少了一半。
在较低的块大小端,延迟占主导地位,而 3 跳与 gossipsub 上的 6 跳起到了最大的作用,在较高的块大小端,带宽性能占主导地位。对于更大的块大小,RLNC 中的 CPU 开销会变得更糟,但是考虑到传输时间的数量级,这些可以忽略不计。
\
rlnc-gossipsub1712×982 87.7 KB
在生产中,每个 peer 发送单个块的方法中,具有更高带宽的节点可以选择广播到更多 peer。在节点级别,这可以通过简单地广播到所有当前 peer 来实现,并且节点运营商只需通过配置标志来选择 peer 的数量。另一种方法是允许节点依次将多个块发送给单个 peer。这些模拟的结果与上述完全相同,但 D 明显更低,正如预期的那样。例如,对于 D=6,在每个 peer 发送单个块的情况下,永远不会广播完整块。模拟需要 10 跳才能广播完整块。使用 D=10,跳数减少到 9。
我们的结果表明,如果我们使用 RLNC 而不是当前的路由协议,那么预计在块传播时间和每个节点的带宽使用方面都会有相当大的改进。这些好处在块/blob 大小越大或每次跳转的延迟成本越短时越明显。实施此协议需要对当前架构进行重大更改,并且可能需要一种全新的 pubsub 机制。为了证明这一点是合理的,我们可能需要实施完整的网络堆栈以在 Shadow 下进行模拟。另一种方法是实施 Reed-Solomon 纠删码和路由,类似于我们对 Peer-DAS 所做的那样。将上述模拟扩展到这种情况应该很简单,但是 op. cit 已经包含许多这样的比较。
- 原文链接: ethresear.ch/t/faster-bl...
- 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!