Pectra Holesky 事件

本文详细分析了以太坊 Holesky 测试网在 Pectra 升级后发生的非最终性事件,深入探讨了事件原因、非最终性的影响以及 Lighthouse 客户端为应对此类问题所做的优化和改进,并提出了未来提高以太坊网络韧性的建议。

The Pectra Holesky Incident关于 Holesky 事件的详细事后分析可以在这里找到。

关于 dapplion 阐述的非最终性对以太坊网络构成的危险的非常有见地的演讲可以在这里找到。

2025 年 2 月 24 日,在 Holesky 上的 Pectra 升级后不久,用户开始报告无效的 execution payload 错误。多个团队的执行层(EL)和共识层(CL)开发人员立即开始调查这些错误报告。在一小时内,发现 Geth、Nethermind 和 Besu 由于配置错误的 depositContractAddress 值错误地接受了一个无效区块。

An invalid block is attested to at slot 371066在 slot 3711006 提出了一个无效区块(红色阴影的区块 3419724)。Geth、Nethermind 和 Besu 错误地接受了这个无效区块,创建了一个分叉。因此,所有源自原始无效区块的链(也以红色阴影显示)都是无效的。

相关的 EL 团队迅速推出了一个补丁来修复这个配置错误的值,但此时对网络的损害已经造成。由于网络中的绝大多数都在运行 Geth、Nethermind 或 Besu,因此网络中的绝大多数已经证明了一个无效的区块。因此,所有 CL 客户端都开始难以构建和证明规范链。这使得 Holesky 网络进入了长期的非最终性状态。

什么是非最终性,为什么它不好?

最终性是以太坊中的一个重要机制。如果有足够多的验证者在足够长的时间内证明链的头部,那么某个检查点之前的所有内容都将变为最终状态。在健康的网络条件下,这个检查点(称为最终检查点)是 current_epoch - 2。除非至少销毁所有以太坊抵押的 2/3,否则无法再回滚最终检查点之前的任何内容。当达到最终性时,共识层客户端可以:

  • 剪枝早于最终检查点的数据。
  • 忽略来自最终检查点之前的 gossipsub 消息。
  • 忽略早于最终检查点的任何与分叉选择相关的数据。
  • 执行其他各种优化。

当最近最终检查点 epoch 小于 current_epoch - 2 时,以太坊被称为处于非最终性时期。由于 CL 客户端无法修剪数据并忽略非最终 epoch 的网络消息,因此长期的非最终性可能会非常混乱。

当以太坊进入大于四个 epoch 的非最终性时期时,将激活一种称为“不活跃泄漏”的特殊模式。这种紧急模式允许网络惩罚那些没有履行其预定职责的验证者。这些惩罚随时间呈平方增长。如果经过足够的时间,未履行其预定职责的验证者将被处罚到被迫退出网络的地步。在非最终性期间,当不活跃泄漏惩罚飙升时,预计 Beacon State 的大小会增加。

什么是 Beacon State,为什么它这么大?

Beacon State 是一种数据结构,是以太坊共识层的核心。它存储了任何给定时间链的完整状态。诸如历史区块根、创世时间、当前分叉、验证者余额和不活跃惩罚之类的数据只是存储在 Beacon State 中的值的子集。

处理新区块、强制执行分叉选择规则和其他关键共识层操作需要最新的状态(高级 Beacon State)。其中许多任务对时间敏感,因此将这些最近的状态存储在缓存中对于 CL 客户端性能至关重要。

Cache: 一种存储区域,用于保存内存中经常访问的数据,与存储在磁盘上相比,可以实现更快的检索。如果你是澳大利亚人,你可能会错误地发音这个词。

可能需要旧状态来处理点对点网络请求或提供有关链的历史数据。缓存这些旧状态可能并不总是理想的。

Beacon State 的查找成本很高,部分原因是它们非常大。在健康的网络条件下,Holesky 上的单个状态大约为 200MB。Lighthouse 在信标状态对象上使用内存优化技术,以结构化的方式“回收”内存。例如,如果我们要查看某个范围的 slot 的一组信标状态对象,则这些单个状态的许多数据将是相似的。使用内存优化技术,Lighthouse 可以让这些信标状态对象在这些相似的值之间共享内存。这有助于减少由频繁的内存分配/释放引起的开销,并减少整体内存使用量。

在 Holesky 非最终性事件期间,不活跃泄漏惩罚在每个 epoch 边界向信标状态添加了大约 70MB 的新数据。Lighthouse 内存优化技术未应用于信标状态的 inactivity_score 字段,该字段跟踪每个验证者的这些惩罚。因此,信标状态消耗的内存比正常网络条件下消耗的内存多得多。

Lighthouse、非最终性、同步、磁盘空间和 OOM

同步

共识层客户端依赖于一个称为乐观同步 (Optimistic Sync) 的过程来追赶链的头部。在乐观同步期间,不验证 execution payload。相反,CL 依赖于分叉选择来同步链。具有最重证明权重的链被认为是分叉选择标准的规范链。此外,一旦分叉选择看到一个被证明是合理的检查点,它将忽略不是该被证明是合理的检查点的后代的区块。

引发 Holesky 非最终性事件的坏区块已被网络中的绝大多数证明,并且已成为一个被证明是合理的检查点的一部分。因此,Lighthouse 节点实际上变得卡住,无法同步到好链上。为了解决这个问题,该团队引入了一个 invalid-block-root CLI 标志,允许节点运营商忽略特定的区块根及其后代。通过此更改,来自无效链的服务区块的对等方会自动被禁止,并且分叉选择会忽略错误的证明。这使得 Lighthouse 节点更容易找到好的对等方并同步到好链上。

但这并没有完全解决 Holesky 上的同步问题。尽管 Lighthouse 节点能够忽略无效区块及其后代,但找到好的对等方仍然是一项挑战。添加了两个新的同步工具,以便更快、更可靠地进行同步。第一个是一个名为 http-sync 的 Lighthouse CLI 程序,允许 Lighthouse 节点连接并与已同步的共识客户端同步。尽管非常有用,但从 UX 的角度来看,此方法有点复杂,并且还需要直接访问已同步的节点。第二个更友好的同步工具以新端点 add_peers 的形式添加。通过 add_peers,节点运营商可以手动添加一个受信任的对等方,通过其以太坊节点记录 (ENR),该运营商知道该对等方正在服务于规范链。通过使用此端点并禁用对等方发现(使用 --disable-discovery 标志),在混乱的网络条件下,同步变得更加快速和可靠。

对等方发现: 以太坊节点在网络上查找其他对等方以与其交换数据的过程。

未来,我们希望引入一种非最终检查点同步机制,该机制可以在长时间的非最终性期间帮助救援节点。这将允许节点运营商同步到未最终确定的 epoch,从而为他们提供更多方式来在不利的网络条件下保持其节点运行。

如果在 Holesky 非最终性事件期间可以使用此功能,则节点运营商可以检查点同步到比包含坏区块的 epoch 更靠前的非最终 epoch。这将允许运营商快速同步到好链,并禁止为他们提供坏链的对等方。此外,如果网络保持未最终确定状态超过几周,则需要此功能才能安全地救援网络。这是因为转发比数据可用性窗口旧的同步区块是不安全的。

数据可用性窗口: Deneb 分叉向以太坊网络引入了 blob。节点必须存储 blob 18 天,即数据可用性窗口,然后才能修剪它们。

在长时间的非最终性期间,如果没有非最终检查点同步,节点将被迫转发同步,而无法独立验证它们正在同步的区块的内容。这对于单个节点和整个网络都是不安全的。

磁盘空间

Lighthouse 将其数据存储在磁盘上的两个数据库中,分别是热 DB 和 冷冻 DB。热 DB 管理非最终数据。在健康的网络条件下,它存储 current_epochcurrent_epoch - 2 之间的数据。冷冻 DB 管理最终数据。冷冻 DB 使用一种复杂的基于差异的存储策略(称为 Tree-States)来优化磁盘使用率。

当区块链的一部分最终确定时,Lighthouse 会启动数据库迁移,将最近最终确定的数据从热 DB 传输到冷冻 DB。在这些迁移期间,将修剪任何不是新最终状态的子链。

在非最终性事件期间,Lighthouse 节点无法执行数据库迁移和侧链修剪。磁盘使用率迅速从大约 20GB 膨胀到 100 多 GB,最终超过 1TB!由于热 DB 缺少基于差异的存储策略,因此单个信标状态以完整形式存储。热数据库中还存储了数千个侧链,进一步加剧了磁盘空间问题。Lighthouse DB 严格执行一个不变式,该不变式要求存储跳过的 slot 的中间状态。这些侧链主要由跳过的 slot 组成。因此,Lighthouse 正在为数千个侧链中的许多跳过的 slot 存储中间状态。

跳过的 slot:一个没有区块的 slot。如果区块提议者提出无效区块,或者该 slot 的区块提议者离线,通常会发生这种情况。在 Holesky 事件中,提议者在其当前同步的链上提议区块。即使区块提议者已同步到规范链并成功提出有效区块,其他侧链也可能将该 slot 注册为跳过的 slot。

为了解决这个问题,该团队引入了一个新端点,该端点允许节点运营商在数据库中触发伪最终确定。该端点要求运营商提供来自 epoch 边界的 epoch、区块根和状态根。修剪任何不是提供的 epoch 边界区块的后代的侧链。此外,早于提供的 epoch 的数据将从热 DB 迁移到更节省磁盘空间的冷冻 DB。

我们还在努力向热 DB 添加一种基于差异的存储策略。这个功能被命名为 Hot Tree-States,将有助于减少健康和不利网络条件下的磁盘空间使用率。我们已经在 Holesky 非最终性事件期间测试了此功能,并且与常规 Lighthouse 节点相比,磁盘空间使用率大幅降低。

内存不足 (OOM)

Lighthouse 利用多个内存缓存来提供快速数据访问,同时最大限度地减少读取延迟和磁盘 I/O。状态缓存用于存储有用的/最近访问的状态。默认情况下,此缓存最多只能存储 256 个状态,并且会经常进行修剪以删除过时的数据。

当通过网络向对等方提供数据时(例如,在提供非最终区块、blob 和状态请求时),Lighthouse 会触发状态查找。当触发状态查找时,如果状态在状态缓存中不存在,则将从数据库中获取该状态并将其插入到状态缓存中。状态查找是代价高昂的计算,特别是当从热 DB 中获取时。

在 Holesky 非最终性期间,大多数对等方都在请求非最终区块和 blob,因为他们试图同步他们对链的本地视图。由于提供此数据需要 Lighthouse 执行状态查找,因此 Lighthouse 节点很快变得不堪重负,并出现 OOM 错误。

OOM:内存不足异常。当计算机没有剩余内存可供程序分配使用时,会发生这种情况。

当向对等方提供非最终区块和 blob 时,Lighthouse 会执行状态查找,因为它需要一种方法来计算哪些区块根与对等方请求的 slot 范围相关。对于最终数据,区块根存储为 slot/区块根映射。确定哪些区块根与哪些 slot 相关联是微不足道的,不需要状态查找。对于非最终数据,这有点棘手,因为重组和其他侧链可能会与我们对该 slot/区块根映射的看法相冲突。相反,我们使用信标状态来计算给定 slot 范围的区块根范围。在健康的网络条件下,这是一个不错的选择。但是在非最终性期间,对等方几乎总是从链的未最终部分请求区块,从而迅速压垮了 Lighthouse 节点并导致与 OOM 相关的崩溃。

为了消除这些低效的状态查找,我们更改了 Lighthouse 向对等方提供非最终区块和 blob 的方式。我们没有获取信标状态来计算给定 slot 范围的区块根范围,而是使用分叉选择。分叉选择包含一个 DAG,用于存储 slot 及其关联的区块根。

DAG: 有向无环图。它是一种数据结构,由永远不会形成闭环的顶点和边组成。

通过通过分叉选择访问这些非最终区块根,我们完全消除了在向对等方提供区块和 blob 数据时执行任何状态查找的需要。这减少了内存消耗并有助于防止 Lighthouse 崩溃。

在非最终性期间,不活跃泄漏惩罚在每个 epoch 边界向信标状态添加了大约 70MB 的新数据。通过将内存优化技术应用于信标状态上的 inactivity_scores 字段,我们能够将内存使用量减少到 4MB。

我们为状态缓存添加了更精细的控制,优化了何时将获取的状态存储在缓存中,并改进了我们的状态缓存剔除算法。此外,我们将默认状态缓存大小从 256 减少到 32,以进一步减少内存使用量。将来,我们希望向状态缓存添加更好的启发式方法,以便它可以根据其内存使用情况和其他因素动态调整自身大小。

我们会再见 ♪♪

不知道在哪里,不知道什么时候。

We'll meet again Ethereum non-finality强烈建议在阅读本节时收听 Vera Lynn 的歌曲《We'll Meet Again》。

假设我们永远不会再看到另一次非最终性事件是不现实的。随着我们不断改进协议,我们一定会看到影响以太坊测试网或主网的运行状况的错误和其他问题。构建安全措施、恢复机制和优化客户端以处理非最终性对于以太坊的长期愿景至关重要。最近看来,我们选择专注于协议升级,而不是对最坏情况的弹性。继续改进协议非常重要,尤其是在我们继续寻求巩固以太坊作为世界计算机的地位时。但同样重要的是为意外情况和灾难性网络条件做好准备。那么我们该如何准备呢?

非最终性测试网

非最终性测试网的维护成本高昂且复杂。从计算角度来看,它们的资源密集型,并且需要工程师花费宝贵的时间来调试和维护这些网络。这种类型的工作非常重要,但托管长期存在的非最终性测试网是不现实的。相反,我们应该以半定期的节奏启动短期的非最终性网络,以帮助在不利的网络条件下对客户端进行压力测试。这些非最终性网络可以按季度、年度或在计划的网络升级之前进行安排。

非最终性互操作日

以太坊的年度互操作活动是将所有客户端团队聚集在一个房间中以处理协议的重要升级的好方法。在肯尼亚举行的上次互操作活动中,客户端团队能够在短短一周内完成第一个 Pectra 测试网的最终确定。让所有客户端团队在一个房间里带来的生产力提升是无价的。如果我们要将一两天的时间专门用于关注客户端在不利的网络条件下的弹性,我们或许能够在构建更具弹性的以太坊方面取得重大进展。

客户端团队优先级

致力于以太坊协议的创新前沿功能令人兴奋。它很有趣、性感,并且“满足了”许多工程师在构建酷炫新事物方面的需求。在不忽视可以帮助客户端在不稳定网络条件下进行保存的关键工作的情况下,继续将时间投入到这些努力中非常重要。我看到许多以太坊最好的客户端工程师花费大量时间致力于可能甚至无法进入下一个计划的以太坊分叉的升级。作为一个整体,我们必须重新确定优先级,并留出我们工程时间的一部分用于可以确保以太坊持续 100 年的工作。

结论

Lighthouse 团队正在努力确保我们的软件能够处理非最终性和其他不利的网络条件。我们在 Holesky 事件期间的许多优化已经极大地提高了稳定性和可恢复性。这些包括:

  • 减少在向对等方提供非最终数据时不必要的状态查找。
  • 添加更好的状态缓存剔除逻辑,确保我们将优质状态保留在缓存中。
  • 引入关于我们如何/何时将状态插入状态缓存的更精细的控制。
  • 添加伪最终确定数据库的能力,以便 Lighthouse 可以修剪坏侧链并减少磁盘空间使用率。
  • 包括将某些区块根列入黑名单的能力,以便节点可以在同步时忽略坏链和对等方。
  • 更多同步工具,以便节点运营商可以在不利的网络条件下将其节点保留在规范链上。
  • 将内存优化技术扩展到其他信标状态字段(如 inactivity_scores),这些字段在网络运行状况不佳时会占用大量内存。

我们还有一些令人兴奋的即将推出的功能,这些功能将使 Lighthouse 更加有弹性

  • 向热 DB 引入一种基于差异的存储机制,又名 Hot Tree-States,这将使磁盘使用率在健康和不健康的网络条件下都成为一个非问题。
  • 添加用户检查点同步到非最终状态的功能。这允许节点运营商在正确的硬分叉周围进行社交协调。如果非最终性周期超过 14 天,则这是一项必需的功能。
  • 更好和更频繁地使用测试工具,我们可以使用这些工具来探索 Lighthouse 在不利网络条件下的行为方式。
  • 探索防止并行化状态缓存未命中的方法,并添加更好的状态缓存启发式方法。
  • 改进我们的任务调度机制,并添加更精细的控制,以便我们可以动态地确定重要任务的优先级,并降低重要性较低的任务的优先级,尤其是在非最终性期间。

这些只是 Lighthouse 寻求构建更强大的以太坊的一些方法。如果你有任何问题、反馈或想要了解更多信息,请通过我们的 discord 与我们联系。

  • 原文链接: blog.sigmaprime.io/pectr...
  • 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
点赞 0
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
sigmaprime
sigmaprime
江湖只有他的大名,没有他的介绍。