第五期测试活动在 10 月 30 日结束,我们与 34 个外部验证者节点共同参与了此次活动。我们这次测试的目标是建立一个稳定的测试网,并开始逐步发送交易到集群,完成对其交易处理能力的首次测试。不幸的是,由于共识和网络稳定的一些问题,我们并没有成功进行这些交易测试。在共识模块失效前,整个测试运行了大约 2.5 小时。本次测试期间发生的事件概括如下:
集群于上午 8 时启动成功,并且 38 个验证节点也很快同步上线。
RPC 端口 tds.solana.com1[1]在上午 9:30 PST 失效掉线。该集群上的大多数节点也同时遇到了类似的问题。集群继续运行良好(根据计量服务器的返回信息)。我们手动重置了 tds.solana.com1 端口。
上午 10 时 28 分 07 点 PST,共识模块失效掉线。
我们调查了两个节点,发现他们最终的 stake 分布情况相同:
slot 34617: votes: 22, stake: 22.5 SOL (63.2%)
slot 34611: votes: 7, stake: 7.1 SOL (19.9%)
slot 34614: votes: 1, stake: 1.0 SOL (2.8%)
Absent: votes: 5, stake: 5.0 SOL 14.0%
Slot 34617 没有成功获得 66.7%的投票,并因此导致集群宕机。
我们共获得了 34 个外部验证者节点的参与。
得益于社区的帮助,我们成功发现了一些之前未知的问题——而这这是测试的目的所在。通过查看一些在该次尝试中输出的日志,我们发现这次系统崩溃是由两个状态调节相关的故障引起的。以下是这两个故障相关的详细信息:
故障 #1
在我们深入探讨这个故障的细节之前,我们首先需要解释 Solana 的网络结构。在 Solana 中,我们有一个 gossip 网络。一般来说,它会像区块链协议中的任何传统的 gossip 网络一样运作(每个节点都会相互对话,并确保所有其他人都会收到这些信息), 目标是确保所有的投票信息都能传播到网络中的其余验证者节点处。
让我以下面这个场景为例。在某个 gossip 网络中有三个节点:Alice,Bob 和 Charlie。每一个验证者都总是会存储最新的投票,并且每一个验证者的公钥都会指向它最近的投票。同时每 400 毫秒会由 leader 产生新的投票。
基于上述背景,现在我们假设 Alice 是区块生产者,并且她刚刚进行了投票(11 号区块),并且引用了最新的区块(10 号区块),同时该投票正在被传播到全网其他节点处。这个时候,如果作为新一轮的出块者的 Bob 还尚未接收到 Alice 发送过来的投票信息,Bob 就不会他提出的新块中引用 Alice 投票的区块,此时网络就会出现分叉,而问题就在于此。Alice 的投票实际上从网络中丢失了。
产生这种情况是因为验证者正在储存选票,而他们的公钥只会引用他们视角中最近的投票。但由于 Bob 生产的新块(12 号区块)是在一个单独的叉上, 它不能被包含在 10 号区块的子块里。而 10 号区块将会跳过 12 号区块,直接连接到 13 号区块上。因此,我们实际上会丢失这个投票信息,并且无法就一个共同的父区块达成一致,从而导致分叉现象产生。
故障 #2
当验证者节点们察看整个网络的投票池时,他们将保留上次察看此投票数据集时的时间戳(比如:100 毫秒前)。在他们下次查看该数据集时,他们将使用该时间戳作为参考来从中提取所有新的投票,并将他们放进一个新的分叉中然后再重复此过程。而当一个分叉使用了另一个没有引用其投票的分叉所提供的时间戳作为参考时,问题就出现了。
换句话说,当整个网络试图使用一个统一的时间戳来同步来自几个拥有不同状态的分叉的投票信息时,故障就会发生。
故障 #3
在我们的内部测试中我们还发现了另一个共识错误。我们共识协议使用了一个基于贪心算法的实现,这种算法总是会给权重最高的有效区块投票。虽然节点永远不会向一个拥有少数节点的网络分区提交投票,但这条规则同时也造成了少数节点的网络分区更可能为自己所在的分区投票,因为在投票时,这些节点是被封锁在多数节点所在的分区之外的。
这些故障需要进行多处修复:
计算一个分叉的权重,即其包含的所有区块的权重。等待找到权重最大的区块,而不是继续在一个拥有少数节点的分叉上出块。
其他问题
在查看本次测试的输出日志时,我们注意到网络中出现了意外的丢包事件。所以我们正在使用 netem 来进行内部测试以模拟不利的网络条件(即 15%的丢包率的情况下),以此来保证我们的网络能在最恶劣的条件下生存。这应该会解决导致分叉产生的一些问题。
新的工具!
为了对共识和网络活动进行压测,我们增加了一些新的工具,可以用来引起任意的网络分区和数据包丢失。
./net/net.sh netem –config-file topology.txt
在连续的网络分区测试中我们发现了更多的问题,经过艰苦卓绝的工作后,我们现在可以在高 TPS 负载的情况下运行网络,同时每隔 10 分钟引发一个网络分区,并保证不会有任何的宕机或内存泄漏情况发生。
Tour de SOL 的相关法律文件
在进行活动的过程中,我们收到了一些来自社区的反馈。这其中有一部分是关于在注册参与 Tour de SOL 所需要进行的全面登记,包括 KYC/AML,W8-BEN,W9 以及一些参与者同意书等。
我们完全理解一份 12 页的法律文件相当令人生畏。因此我们想要针对此进行一下解释,说明为什么它会是这样做的。
为了激励参与者参与测试网的测试,我们基本上会像这些服务提供者们分发代币。这些服务提供者们会作为验证者节点来帮助我们对我们的测试网络进行压测。更具体地说,我们正在使用一个 701 豁免权,这在某种程度上类似于公司的期权发放。而这些法律文件就是为了清楚的界定这种关系。对于任何对于条款细节感兴趣的人,我们都很乐意为其进行解读。
虽然这可能会造成一些障碍,但考虑到我们是一家美国公司,我们倾向于走一条保守的路线来保证我们的合规,并同时允许参与者们可以获得 SOL 通证来获得一些补偿。
100% 惩罚机制
加入我们在论坛上的讨论[2]
我们主张 100%惩罚机制,因为我们认为这样的机制可能会成为一种为去中心化和安全性做出贡献的强权机制。例如,如果您是已经启用了抵押的交易所,并且产生了一次 100%惩罚, 您不想作为唯一的一个验证者节点来对所有交易所用户的币负责对吗?您会更倾向于去分担您的风险。
同样,如果您是一位想要将您的代币委托出去的投资者, 您会想要以类似的方式确保你的投票代币在一堆验证者节点间平均分配,而不仅仅是一个。关于安全性问题,网络的安全性取决于处于风险中的资本的数量,即被抵押的币的比例。因此,如果惩罚增加,那么处于风险中的资本的数量也会相应增加,从而提供更有力的安全性保障。
需要注意的是,我们完全清楚被惩罚的风险不仅仅来源于验证者节点,它也有可能是来自于实现协议的客户端软件中的漏洞。基于这一点,我们打算随着网络的成熟以及代码安全性和鲁棒性的增加,来慢慢的增加惩罚率。
我们欢迎更多来自社区的思考/评论/讨论。我们想要实现的显然将是一个长期目标,所以与社区的共同理解与和谐共处将成为重中之重!