---
title: 涡轮（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 号邻居发送碎片](/img/data-plane-seeding.svg)

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

![Neighborhood 0 向Neighborhood 1 和 2 号散播](/img/data-plane-fanout.svg)

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

![具有两个扩散的两层集群](/img/data-plane.svg)

### 设置值

`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\)。 由于每个邻居都会从上层一个邻居的多个节点收到碎片， 因此上层网络出现大规模故障，才会产生不完整的数据。

![邻居的内部工作](/img/data-plane-neighborhood.svg)
