Skip to main content

涡轮(Turbine)区块传播

Solana 集群使用一个叫做 Turbine 的多层区块传播机制来广播所有节点的交易,该过程只产生少量的重复信息。 群集将自身分成小的节点集合,叫做 neighborhoods(邻居)。 每个节点负责与其附近的其他节点分享它收到的任何数据,同时将数据传播到其他邻居的小节点。 这样,每个节点只需要与少数节点通信。

在其插槽中,领导人节点会在第一个邻居的验证节点(层 0) 之间分配碎片。 每个验证节点在其邻居之间共享各自的数据,但也在下一层(层 1) 中将碎片转化为某个邻居的一个节点。 每个 1 层节点与邻居节点共享数据, 并在下一层重新传输到节点,以此类推,直到集群中的所有节点都收到了所有碎片。

邻居分配 - 权重选择#

为了使数据扩散发挥作用,整个集群必须就如何将划分邻居达成一致。 为了实现这一点,所有公认的验证节点 (TVU 节点) 都按质押权重排列并存储在一个列表中。 然后以不同的方式索引这该列表,来查明邻居边界并相互重新传送。 例如,领导者只需选择第一个节点来构建层 0。 最高权重的质押持有者会让得票最多的节点优先成为领导者。 0 层和下层节点使用相同的逻辑来找到他们的邻居和下一个层节点。

为了减少攻击向量的可能性,每个碎片都向邻居发送一个随机树。 每个节点使用代表集群的同一批节点。 随机树是通过碎片集生成的,它使用领导者ID、插槽和碎片索引来生成种子。

层和邻居结构#

当前领导者将其初始广播到最多 DATA_PLANE_FANOUT 的节点。 如果该层 0 小于集群中的节点数,则数据平面扫描机制在下面添加图层。 随后的图层遵循这些约束来决定图层容量:每个邻居包含的 DATA_PLANE_FANOUT 节点。 0 层从带有扩散节点的 1 个邻居开始计算。 每个附加层中的节点数量增加了一个扩散因素。

如上文所述, 图层中的每个节点只能向邻居广播它的碎片,并且在某些下层邻居中只能播放一个节点, 不适用于集群中的每个 TVU 节点。 有一个理解该问题的好方法:0 层从带有扩散节点的 1 个邻居开始计算,1 层增加扩散邻居, 每个带有扩散节点和 2 层的节点都会有 扩散 * 在 1 层的节点数量,以此类推。

这样,每个节点进行通信最大只能达到 2 * DATA_PLANE_FANOUT - 1 个节点。

下面的图表显示了领导人如何在 0 层向 0 令居发送两个扩散的碎片,以及 0 邻居的节点如何彼此分享他们的数据。

领导者向 0 层中的 0 号邻居发送碎片

下面的图表显示了 Neighborhood 0 如何向 Neighborhood 1和2 进行扩散。

Neighborhood 0 向Neighborhood 1 和 2 号散播

最后,下图显示两个层集群都有 2 个扩散。

具有两个扩散的两层集群

设置值#

DATA_PLANE_FANOUT - 确定层 0 的大小。 后续的层由 DATA_PLANE_FANOUT 系数生成。 邻居的节点数量等于扩散值。 某个邻居要在添加新邻居之前被填满,即如果某个邻居没有满,它必须是最后一个。

目前,集群启动的时候就进行了配置。 未来这些参数可能会托管在链上,从而能够随着群组大小的变化而自行调整。

计算所需的 FEC 比率#

Turbine 依赖于验证器之间数据包的再传输。 由于重新传输,任何网络宽包丢失都会加重, 同时每次访问的数据包未能到达目的地的概率也会增加。 FEC 比率需要考虑网络宽数据包丢失和传播深度。

碎片组是可以使用重建彼此的数据和编码数据集。 每个碎片组都有失败的可能性,其概率大致相当于数据包错误率超过 FEC。 如果验证节点无法重建碎片组,那就无法构建区块,它就必须先修复区块。

碎片组失败的概率可以通过二项分布计算。 如果 FEC 率是 16:4, 那么群组大小则为 20,而且至少要有 4 个碎片失败才会导致整个组失败。 这等于 20 个碎片中的四条或更多个体失败的概率之和。

涡轮区块成功的概率为:

  • 数据包失败的概率为: P = 1 - (1 - network_packet_loss_rate)^2
  • FEC 率: K:M
  • 尝试次数: N = K + M
  • 碎片组失败率: S = SUM of i=0 -> M for binomial(prob_failure = P, trials = N, failures = i)
  • 每个区块的碎片: G
  • 区块成功率: B = (1 - S) ^(G / N)
  • i 的精确结果的双向分布被定义为 (N choose i) * P^i * (1 - P)^(N-i)

例如:

  • 网络丢包率为 15%。
  • 50k Tps 的网络每秒产生 6400个碎片。
  • FEC 率增加了每个块按 FEC 笔录的总碎片数。

其中 FEC 率为: 16:4

  • G = 8000
  • P=1 - 0.85 * 0.85 = 1 - 0.7225 = 0.2775
  • S = i 的总和 =0 -> 4 为二项分布(prob_fail= 0.2775, trials = 20, fails = i) = 0.689414
  • B = (1 - 0.689) ^(8000 / 20) = 10^-203

其中 FEC 率为: 16:16

  • G = 12800
  • S = i 的总和 =0 -> 32 为二项分布(prob_fail= 0.2775, trials = 64, fails = i) = 0.002132
  • B = (1 - 0.002132) ^(12800 / 32) = 0.42583

其中 FEC 率为: 32:32

  • G = 12800
  • S = i 的总和 =0 -> 32 为二项分布(prob_fail= 0.2775, trials = 64, fails = i) = 0.000048
  • B = (1 - 0.000048) ^(12800 / 64) = 0.99045

邻居(Neighborhoods)#

以下图表显示不同层中两个邻居之间的相互作用。 若要使邻居瘫痪,就需要从上面的邻居建立足够的节点(擦除代码+1)。 由于每个邻居都会从上层一个邻居的多个节点收到碎片, 因此上层网络出现大规模故障,才会产生不完整的数据。

邻居的内部工作