---
title: 可靠的投票传输
---

验证节点投票是对网络的共识和持续运行具有关键功能的信息。 因此，可靠地传递这些信息并将其编码到账本中是至关重要的。

## 挑战

1. 领导者轮换是由PoH触发的，PoH是具有高漂移的时钟。 所以很多节点很可能对下一个领导者是否实时活跃有一个错误的看法。
2. 下一个领导者可能很容易被淹没。 因此DDOS不仅会阻碍常规事务的传递，也会阻碍共识消息的传递。
3. UDP是不可靠的，我们的异步协议要求任何传输的消息都要重传，直到在账本中观察到它。 重传有可能会对有大量验证节点的领导者造成无意的_过大流量冲击_。 最坏的情况下，冲击量会达到`(num_nodes * num_retransmits)`。
4. 通过账本跟踪投票是否已经传送，并不能保证它将出现在确认块中。 当前观察到的区块可能会被解卷。 验证节点需要为每一次投票和分叉保持状态。

## 设计

1. 通过gossip以推送信息的方式送票。 这样可以保证将票数传递给所有下一届领导，而不仅仅是下一届未来的领导。
2. 领导者将读取Crds表以获取新的投票，并将任何新收到的投票编码到他们提出的区块中。 这样就可以让验证节点的投票被所有未来的领导者纳入回滚分叉中。
3. 在账本中收到投票的验证节点将把它们添加到他们的本地crds表中，而不是作为推送请求，而是简单地将它们添加到表中。 这样就缩短了推送消息协议，所以验证消息不需要在网络上重传两次。
4. 投票的CrdsValue应该是这样的`Votes(<Transaction>)`

每个投票事务都应该在其数据中保持一个`wallclock`。 投票的合并策略将保留本地客户端配置的最后N组投票。 对于push/pull，向量是递归遍历的，每个Transaction被视为一个单独的CrdsValue，有自己的本地wallclock和签名。

Gossip被设计为高效的状态传播。 通过gossip-push发送的消息被分批发送，并以最小的生成树传播到网络的其他部分。 树上的任何部分故障都会通过gossip-pull协议主动修复，同时将任何节点之间的数据传输量降到最低。

## 这种设计如何解决挑战。

1. 因为在领导的 "活跃 "状态，验证节点没有简单的方法与领导同步，所以无论在什么状态下，gossip都可以最终交付。
2. Gossip会将消息传递给所有后续的领导者，所以如果当前领导者被淹没，下一个领导者就会已经收到这些票数，并且能够对其进行编码。
3. Gossip通过维护一个高效的生成树，并使用bloom过滤器来修复状态，从而最大限度地减少通过网络的请求次数。 所以重传回退是没有必要的，消息是分批的。
4. 读取crds表进行投票的领导会对表中出现的所有新的有效投票进行编码。 即使这个领导的区块被取消，下一个领导也会尝试添加同样的票数，而不需要验证节点做任何额外的工作。 因此，不仅保证了最终的交付，也保证了最终编码到账本中。

## 性能

1. 最坏情况下传播到下一个领导者的时间是Log/(N/) 跳，基数取决于fanout。 以我们目前默认的fanout为6，到20k节点约为6跳。
2. 领导者应该收到20k张验证票，通过gossip-push汇总成MTU大小的碎片。 这样可以将20k网络的数据包数量减少到80个碎片。
3. 每个验证节点的票数都会在全网复制。 为了维持5个以前投票的队列，Crds表将增长25兆字节。 `(20000节点*256字节*5)`。

## 两步实施推出

初期网络只需通过网络传输和维护1个投票，就可以可靠地执行当前的投票实施。 对于小型网络，6个fanout就足够了。 对于小型网络，内存和推送开销很小。

### 1k验证节点子网络

1. Crds只是维护验证节点最新的投票。
2. 无论票数是否出现在分类账中，都会被推送和重传。
3. 6的fanout。
4. 最坏情况下每个节点256kb的内存开销。
5. 最坏情况下4跳传播到每个节点。
6. 领导者应该在4个推送消息碎片中收到整个验证节点投票集。

### 20k子网络

在上述子网加上以下几点。

1. CRDS表维护着5个最新验证节点投票的向量。
2. 投票编码一个挂钟。 CrdsValue::Votes是一个类型，它递归到所有Gossip协议的事务向量中。
3. 将fanout增加到20。
4. 最坏情况下每个节点的内存开销为25mb。
5. 在最坏的情况下，用4个跳来传送到整个网络。
6. 领队收到的所有验证机信息80个碎片。
