引介

Medalla 测试网网络动荡始末,Part-3

Ajian   |     |   345 次阅读

Medalla 测试网网络动荡始末,Part-1
Medalla 测试网网络动荡始末,Part-2


编者注:第五篇材料,是 Prysm 客户端团队的 Raul Jordan 公开发表的事故总结,更清楚地说明了连锁故障发生的先后顺序,也做了透彻的检讨,回应了很多疑问。

Eth2 Medalla 测试网事故

摘要

上周末,Eth2 公开测试网 Medalla 卷入了一系列连锁故障。这些故障暴露出了几个严重的漏洞,以及我们在处理致命情形时的错误方法。这一系列故障始于运行 Prysm 客户端的节点收到了来自 6 台不同时钟服务器的错误响应,这导致绝大多数运行 Prysm 客户端的节点在同一时间掉线。我们团队紧急推出了修复方案,而这一方案又包含了一个重大缺陷 —— 它移除了节点运行需要的所有必要特性。这个问题导致了网络分区,每个节点都在拼命同步区块链,但都无法找到一个健康的对等节点。Medalla 经历了一个命途多舛的周末,也为我们提供了非常宝贵的学习经验,来防止此类故障重演,尤其是在主网上。本文将涵盖此次事故的完整总结、它的结果、经验教训,以及在 eth2 主网启动之前我们进一步的具体行动计划。

问题澄清

Eth2 测试网的失败是因为依赖于 cloudflare.com 的时间服务器么?Eth2 中的时间戳依赖中会出现单点故障么?

当然不会。我们利用 roughtime 云服务器告知用户他们的系统时间可能偏离,并基于这些服务器的响应动态调整他们的时间,我们认为这一做法很好,但其实完全没有必要,反而会招致一些问题。如果我们让 eth2 中像时间戳这样重要的事情出现单点故障,那毫无疑问是个安全风险,且完全没有必要。打这次事故以后,我们只会依赖于系统时间。如果一名验证者的系统时间真的不对,我们会提醒他们,但绝不会强制更改他们的时间。我们会像其它 eth2 客户端实现一样,只使用系统时间

测试网挂掉了?

并没有。只要还能运行节点,只要验证者还可以验证,测试网就永远可以回到完全可控的状态。当前,客户端实现团队已经增强了他们的链同步代码,使得节点的运行更加平稳,此举可以提高验证者的参与率,并使区块链再次实现终局性(finality)。我们还有希望。验证者的参与率已经从 0-5% 攀升到了 40%,当达到 66% 以上时,整条链就可以重新获得终局性了。。

本次事故对主网上线有何影响?会再次跳票么?

我们认为本次事故并不会影响主网的启动事件。Prysmatic Labs 团队建议 ETH2 保持原来的启动日程表,不再推迟。对于很多客户端而言,这周末发生的事故是一次很好的压力测试,并确实测验了一些启动清单上的需求。虽然主网启动的日期尚未明确,但我们认为将目标启动时间定为从 Medalla 创世后 2~3 个月依然是一个理想的时间安排。会有一个 Eth2 启动的公开需求清单,而本次 Medalla 上出现的事故势必会导致清单上添加许多新的条目,包括客户端弹性、安全性以及恰当的版本控制等事项。这就是我们目前已知的所有信息。

事故时间线

故障的初步迹象

1.png

几乎就在事故发生以后不久,用户就注意到他们的 Prysm 节点发出了时钟偏移的报告,并看到了超前的区块。当时,Prysm 使用 roughtime 协议来自动调整客户端时钟,通过查询一组 roughtime 服务器来确定合适的时钟偏移量。Roughtime 协议的工作原理是按顺序查询一组服务器得到一连串经过签名的 请求/响应,然后客户端取这些响应的平均值来调整他们的时钟。

中点 服务器名称
2020 年 8 月 15 日 2:20:23 AM Google-Sandbox-Roughtime
2020 年 8 月 15 日 2:20:23 AM Caesium
2020 年 8 月 15 日 2:20:23 AM Chainpoint-Roughtime
2020 年 8 月 15 日 2:20:23 AM Cloudflare-Roughtime
2020 年 8 月 15 日 2:20:23 AM int08h-Roughtime
2020 年 8 月 16 日 2:20:23 AM ticktock

注意到什么了吗?上表中第 6 台服务器报告的时间比其它 5 台服务器快了整整 24 个小时。因此当 roughtime 客户端计算这些结果的平均值时,会将 2020 年 8 月 15 日 6:20:23 AM 当成正确的时间。Roughtime 协议的一个关键组成是责任制。给定协议中的一条被签了名的时钟链,那么我们可以证明响应出错的是 ticktock 服务器,并有效报告这一问题。不幸的是,Prysm 并没有记录这样一条时钟链,而且在事故发生时,我们也没有将相关信息存储在任何地方。在快速查询日志后我们发现,TickTock 服务器偏移了 24 小时,这就解释了为什么 6 台服务器最终造成了 4 小时的时钟偏移。我们已经与 cloudflare 公司里 roughtime 项目的维护人员取得了联系,他们已决定改进其客户端在服务器故障情况下的稳健性:

问题 #22:针对故障服务器的客户端健壮性

2.png

- 事故发生时候返回的中点(时间戳) -

紧急修复更新(alpha.21)

尽管我们并不知道其中一台 roughtime 服务器报告的时间提前了 24 小时,但我们知道 roughtime 服务器出了问题,因此必须立即关闭。我们并没有完全删除 roughtime 代码,而是将其修改成需要开启一个运行时标签(runtime flag)才能调整时钟,而不再是默认自动调整时钟。测试网已处于水深火热之中,我们希望快速行动起来,于是决定推出一个 “紧急版本”,并要求每个人立即更新新代码。然而,还没等我们这样做,roughtime 服务器已经恢复正常了。

3.png

大规模罚没事件

事故发生前,我们本应对此有所预料,但真当它发生时,仍然震惊了所有人。大约上午 10 点的时候(北京时间),在 roughtime 事故中每一个活跃的验证者都开始主动发出会导致自己被罚没的见证消息。这就变成了一场大屠杀,在极短的时间内发生了超过 3000 次罚没,我们内部的验证者无一幸免。当时我们正忙于改进测试网的用户体验,因此没有及时为我们的内部验证者配置本地的罚没保护措施。

运转中的罚没保护

幸运的是,Prysm 在默认情况下使用了一个简单的罚没保护机制来跟踪见证消息和验证者生产的区块,防止他们对相同的消息重复签名。对许多用户而言,这使得它们免受罚没之灾。

真正的问题:alpha.21 版本中发现了 bug

由于太急于解决原始问题,我们没有考虑到潜在修复的所有影响,把关注点更多地放在了快速发布新版本上,而不是仔细检查新的版本是否会破坏我们节点中的其它东西。我们的队友 Nishant 第一个指出了我们发行的 alpha.21 版本存在严重缺陷。如果我们啥也不干的话,网络本可以自行恢复。

4.png

5.png

在发布这个修复程序时,我们意外地移除了 Eth2 信标链节点得以正常运行的所有关键特性的初始化部分,从而让问题变得一发不可收拾。我们在 discord 服务器和推特上向所有人宣布这个新版本后,质押用户开始快速升级他们的节点,这时我们才意识到问题有多么严重。更糟糕的是,现在 roughtime 的 bug 已经完全恢复了,如果没有我们火急火燎的一通骚操作,网络很可能已经正常。

回滚和同步问题

在意识到错误的范围之后,我们马上建议用户将客户端回滚到以前的版本,因为现在 roughtime 的问题已经解决了。然而这一举动最终变得十分艰难,因为网络已经分区了,而且用户也对短时间内有如此多更新感到一头雾水。由于绝大部分节点停机了一段时间,因此用户频繁重启他们的节点来获取更新,看上去几乎网络中的每个人都在尝试同步区块链,这导致获取最新的区块变得毫无可能。此外,节点想要解决分叉非常困难。也就是说,网络中充斥着无数的不良节点,想要找到一个好的节点犹如大海捞针。而且节点的资源消耗也在不断攀升。其它客户端实现都出现了大量的内存占用, Prysm 节点也受到了 CPU 使用过高的影响,这在解决分叉时毫无帮助。

现状

6.png

本次事故暴露了我们的节点在处理区块链高度分区事故中的分叉区块时所作的几个关键、有缺陷的假设。我们没有处理在某个 slot 时间内可能存在多个区块的多条代码路径,这导致我们的节点经常被卡住。此外,即便我们解决了这个问题,如果节点已经落后了,那么仍然无法重新同步到区块头。基于区块链稳定的假设来写代码并不难,但要让这些代码在充满不良节点、分叉、和网络分区时依然正常运转则完全是另外一回事了。改变假设之后,我们的同步逻辑在处理这类场景时就会变得足够稳健,我们的队友 Victor Farazdagi 可以很快解决这个问题。从那以后,我们又推出了一个修复更新,引导 Prysm 节点同步到区块链顶端并保持同步!在撰写本文时,绝大部分节点正在更新到这个版本。此时,我们只需要更多验证者上线,并使用他们已经同步好的信标链节点开始见证和提议区块就好了。接下来,我们会监视链上的参与情况,并尽可能多地与运行验证者的个人取得联系,去了解他们是否仍然会遇到问题。

如果你正在运行 Prysm,你可以前往我们的发布页面 https://github.com/prysmaticlabs/prysm/release 下载最新的版本,或者遵循我们文档中心 https://docs.prylabs.network/docs/install/install-with-script 发布的详细指南。我们会随着情况的进展不断通过我们的 Discord 更新状态。

经验教训

不要急于合并修复程序

如果我们没有急于修复 roughtime 时钟同步问题,本来可以避免整个事件。这次事件之所以会恶化,是因为我们合并了一个错误的 PR,而这个 PR 清除了节点运行所需的一切关键功能。由于迫切想解决最初的问题,我们没有认真思考修复程序会带来的所有影响,而是一心想着尽快发布,就没有仔细检查修复程序是否会破坏节点的其它功能。我们团队的 Nishant 是第一个指出 alpha 21 版本存在严重缺陷的。如果我们没有采取任何行动,测试网本来是可以自行恢复的。

看到全网运行 Prylabs 客户端的节点都出现故障,我们心急如焚,一心想着尽快缓解用户的担忧。虽然这个修复程序最初是由外部贡献者创建的,但是没有仔细审查是我们的错。这个修复程序中有一行代码将所有运行 Prylabs 客户端的节点还原回全局默认配置。见https://github.com/prysmaticlabs/prysm/pull/6898/files#diff-fb86a5d3c2b85d3e68cad741d5957c29L263。从今往后,在出现故障或危机期间,每一个待发布版本必须

  1. 经过整个团队和一名外部人士(如,以太坊研究员)的审查
  2. 先在模拟环境中经过一段时间的测试,可以是 Prysm ETH 2.0 攻击网,也可以是存在同样漏洞的本地测试网。

我们的团队通常采用金丝雀部署(canary deployment):将新合并的 PR 部署到到生产环境中,以了解一段时间内该 PR(相对于基准)的表现情况。但是,考虑到每个节点都存在问题(包括我们内部运行的节点),没有基准,因此也做不了金丝雀部署。我们急于修复问题,一出新版本就立即向用户发布,没有意识到里面存在巨大漏洞。接下来不会再出现同样的问题了,我们已经从中得到了巨大的教训。如果今后再出现类似情况,即使验证者余额在减少,区块链迟迟得不到确定,我们也要在拥有 100% 信心的情况下再将修复程序对外发布。

在不稳定时期,对外宣布更新必须慎之又慎

7.png

我们的另一个错误是,在对外宣布更新时没有谨慎沟通。在 90% 以上的节点都存在严重问题,无法同步到最新区块的情况下,我们只是通知所有人“快点更新节点!”,造成了极大的混乱。在默认设置下,每个节点可连接的对等节点数量的上限是 30 。对于那些不知道如何修改这个上限的人来说,这就意味着他们的对等节点几乎都在试图同步,通信负担很大。不是所有人都开启了 discord 公告的通知,而且在我们通知所有人更新节点时,其它时区的人可能都在睡觉。从这次事件中,我们学到的主要经验是,要保持清晰的沟通、了解网络状态以及要求所有人更新节点会产生的影响。

让用户能够无缝迁移到其它 ETH 2.0 客户端上,并提供清晰易懂的文档

ETH 2.0 的一大特点是去中心化开发。有 5 个独立的团队在针对 ETH 2.0 构建客户端实现。这 5 个客户端都参与了 Medalla 公共测试网的创世。虽然它们的准备状态不尽相同,但是其中一些自上次测试网实验以来已经有了很大的进步。在故障爆发时,全网有 65% 的节点都在我们的 Prysm 客户端上运行。一旦所有 Prysm 节点出故障,整个网络都会遭殃。从网络抗逆性的角度来看,必须让验证者能够在某个客户端出现严重漏洞的情况下轻松转移到其它客户端上。遗憾的是,Medalla 测试网启动时,客户端团队正在研究如何将客户端管理验证者密钥的方式标准化。也就是说,我们并没有 100% 完成关于如何在 Prysm 和 Lighthouse 之间迁移的文档。接下来,这将成为我们工作的优先项,并将其应用到我们的公共文档门户。我们要让用户能够随时在客户端之间轻松切换,同时遵守我们公布的最佳安全实践。

对质押用户的启示

8.png

这种情况发生在测试网上是最好的

如果 Medalla 公共测试网流畅运行,在主网上线前表现良好,等到 ETH 2.0 主网上线时这个漏洞才暴露出来,这才是真正可怕的事情。对于区块链来说,最坏的情况是,大多数节点都在同一个客户端上运行,而这个客户端包含一个会导致所有节点离线的漏洞。Medalla 已经显示出了这种情况有多可怕。知道在这种情况应该采取什么措施,并且能够在有需要时迁移到另一个客户端上,对于所有质押用户来说都非常重要。

ETH 2.0 Phase 0 的风险

ETH 2.0 Phase 0 是一个拥有宏伟目标的项目,会对那些在创世时加入的质押用户带来技术风险。这是对以太坊协议的全面改进,引入了权益证明。这是自 Casper FFG (确定性小工具)经过多年研究以来的首次实现。虽然客户端实现已经非常成熟,而且经过这次事件的洗礼会比之前更强大,ETH 2.0 是一场实验,对于那些不了解其风险的质押用户会造成严重后果。如果这次故障发生在主网上,导致主网连续几天无法敲定区块,被罚没的验证者的损失加起来即使没有几千万美元,也有几百万美元,这对于所有人(包括那些最积极的支持者们)来说都是极其痛苦的。我们要明确的是,这些风险是真实存在的,技术风险是无法消除的。ETH 2.0 的 launchpad 中阐明了吃螃蟹的风险,我们的建议是请慎重考虑是否要在 ETH 2.0 上质押。

9.png

- “尝鲜者需承担的风险:验证者参与的是新网络的首次上线。就像所有新的软件那样,有可能存在漏洞。虽然可能性不高,但是潜在漏洞会导致罚没” -

10.png

- “我是早期开拓者,我接受因软件和设计存在漏洞而导致被罚没的情况” -

客户端单一化的风险

本文截稿时,超过 78% 的 ETH 2.0 公共信标链节点都在我们的 Prysm 客户端上运行。

11.png

在故障发生前,这个比例就已高达 62% 左右。ETH 2.0 的开发聚焦于多个独立实现,可以让用户在危机关头或某个实现出现漏洞时随意切换。Medalla 测试网目前之所以会出现问题,是因为它过度依赖单个客户端,我们相信应该改变这种情况。其他客户端团队正在努力更新文档,提高抗逆性,并降低其实现的运行难度。很多质押用户之所以会选择我们的 Prysm 客户端,是因为他们可以轻而易举地在个人或云端设置中对 Prysm 客户端进行设置,我们还会继续努力的。但是,一个好的做法是,尝试其它实现并在有需要时进行切换,尤其是对于那些运行多个验证者节点的质押用户而言。

如何让节点保持更新

对于所有客户端实现团队来说,说服用户更新节点是永恒的难题。随着网络的去中心化程度提高,我们缺少一个沟通渠道来通知所有节点运营者更新节点,以修复重要漏洞。团队可以采取的最佳措施就是依靠自己的沟通方式,如,Discord 频道、Github 发布页,甚至是推特账号。尽管我们有通知让所有人“快更新节点!”,但是不同时区的节点运营者可能不在线,还有一些运营者可能不使用社交媒体工具。要求所有人同时更新可能会带来灾难:在节点离线较长一段时间后,所有人都同时开始更新,导致网络中的对等节点都在同一时间同步,造成网络通信量过大。因此,有一个更加详细的发布策略,确保所有用户都知道 “官方” 通信渠道,是很重要的。另外,我们还要确保 ETH 持币大户和多个节点的运营者很容易就能联系到我们的开发团队。我们想要与节点运营者保持更紧密的联系,确保他们知道何时应该更新节点,并告诉他们每次更新时哪些 changelog(更新日志)与他们有关。

如果这次出故障的是主网会怎么样?

不用说,如果发生在主网上,这肯定是最糟糕的情况之一。虽然这一系列事件发生在测试网上是最好的,可以让我们提前预演如何应对危机情况,但是等主网上线后又有可能出现其它状况。尽管我们可以采取安全审核、代码审计和模拟环境等手段,但实际上 ETH 2.0 主网仍有可能会像多年前的 ETH 1.0 那样遭到 DDoS 等攻击,对此我们需要作好准备。 ETH 1.0 背后的团队已经身经百战,积累了很多关于如何应对危机的经验。这次 Medalla 测试网故障同样给我们留下了一些经验。作为客户端开发团队,我们在主网上部署客户端时必须注意以下几点:

  1. 有完整的检查表,包括候选发行版本、模拟环境、外部通信和监控。
  2. 为用户提供在不同 ETH 2.0 客户端之间迁移的详细指南。
  3. 制定一个分步指南并由 ETH 2.0 客户端应急小组执行。Prysmatic Labs 有自己的内部手册,但是如果有一个能够协调所有 ETH 2.0 客户端的总指南,就能省去很多烦恼。
  4. 就如何在关键时刻通知权益者、节点运营者和普通用户更新节点制定详细的计划。

这次事件确实改变了我们的 ETH 2.0 开发方式。我们深知这个项目具有较高的风险,但是现在更加懂得如何应对危机,如何处变不惊,以及当很多用户都依赖我们的客户端时有哪些严禁事项。

总结

总之,由于我们在修复全局故障时决策不当,ETH 2.0 的 Medalla 测试网出现了连锁故障。测试网之所以会出现如此严重的停摆,不只是因为 roughtime 时钟偏移和单点故障问题,而是因为各种网络分区所引发的一系列问题。幸好这一切都发生在测试网上,所有 ETH 2.0 客户端团队现在都做好了完全准备,以防主网出现类似问题。我们将聚焦于如何通过流程、安全性和适当的应急措施来提高 ETH 2.0 的抗逆性,并与所有客户端开发团队合作实现这些目标。

(完)


原文链接: https://medium.com/prysmatic-labs/eth2-medalla-testnet-incident-f7fbc3cc934a
作者: Raul Jordan
翻译&校对: 曾汨, 闵敏 & 阿剑

 
0 人喜欢