本文详细探讨了以太坊协议的未来发展方向,特别是关于Verge(冯格)的概念,即提高以太坊验证节点的可行性和灵活性。通过实现无状态验证和使用先进的证明技术(如Verkle树和STARK),希望降低节点运行的存储要求,并使移动设备等资源受限的设备能够参与到以太坊网络中,不仅增强了验证的分散化,还推动了以太坊的普及与可持续性。
特别感谢 Justin Drake、Hsiao-wei Wang、Guillaume Ballet、Ignacio、Josh Rudolf、Lev Soukhanov、Ryan Sean Adams 和 Uma Roy 的反馈和审阅 。
区块链最强大的功能之一是 任何人都可以在他们的计算机上运行一个节点并验证链是否正确。即便链共识运行的95%节点(如PoW,PoS……)立即同意改变规则,并开始根据新规则生成区块,所有运行完全验证节点的用户都会拒绝接受该链。那些不属于这样卡巴尔的质押者将自动聚合,并继续构建符合旧规则的链,而完全验证的用户将跟随那条链。
这就是区块链与集中系统之间的关键区别。然而,要实现这个特性,运行一个完全验证的节点必须对一批人来说是切实可行的。这适用于质押者(如果质押者不验证链,他们实际上并没有为执行协议规则做出贡献)和普通用户。如今,在消费型笔记本电脑上运行节点是可能的(包括用于撰写此帖子所用的那一台),但这很困难。The Verge的目标是改变这一现状,使得完全验证链的计算成本低到每个移动钱包、浏览器钱包甚至智能手表都能默认执行。
最初,“The Verge”指的是将以太坊状态存储移动到 Verkle trees 的想法——一种允许更紧凑证明的树状结构,从而实现对以太坊区块的无状态验证。节点可以在硬盘上没有任何以太坊状态(账户余额、合约代码、存储……)的情况下验证一个以太坊区块,代价是消耗几百千字节的证明数据和几百毫秒来验证该证明。目前,The Verge指的是一个更大的愿景,专注于实现以太坊链的最大资源效率验证,这不仅包括无状态验证技术,还包括使用 SNARKs 验证所有以太坊执行。
除了对整个链进行 SNARK 验证的长期关注外,另一个新问题是 Verkle trees 是否就是最好的技术。Verkle trees 对量子计算机是脆弱的,因此如果我们将目前的 KECCAK Merkle Patricia tree 替换为 Verkle trees,我们将来还需要再次替换树。Merkle trees 的自然替代方案是直接使用 STARK 将 Merkle 分支应用于 二叉树。从历史上看,由于开销和技术复杂性,这被认为是不可行的。然而,最近我们看到 Polygon 在笔记本电脑上证明每秒 1.7 百万 Poseidon 哈希,并且更“传统”的哈希的证明时间也由于像 GKR 之类的技术而迅速改善。
因此,在过去一年中,The Verge变得更加开放,目前有几种可能性。
无状态验证:Verkle 还是 STARKs 我们在解决什么问题?
如今,一个以太坊客户端需要存储 数百 GB 的状态数据 来验证区块,这个数量每年继续增加。原始状态数据每年大约增加 ~30 GB,各个客户端必须在顶部存储一些额外数据以有效更新 trie。
这减少了可以运行完全验证以太坊节点的用户数量:即使可以存储所有以太坊状态和多年历史的硬盘 已随处可见,但人们默认购买的计算机通常只拥有几百 GB 的存储。状态大小同样为首次设置节点的过程引入了巨大的摩擦:节点需要下载整个状态,这可能需要数小时或数天。这会带来各种连锁反应。例如,这使得质押者升级其质押设置变得显著困难。技术上,可以在没有停机的情况下完成此操作——启动一个新客户端,等待其同步,然后关闭旧客户端并转移密钥,但在实践中技术上却很复杂。
无状态验证是一种允许节点在没有整个状态的情况下验证区块的技术。相反,每个区块都有一个 见证,其中包括 (i) 在状态中块将访问的特定位置的 值(例如代码、余额、存储),以及 (ii) 一份证明这些值正确性的 加密证明。
实际上实现无状态验证需要改变以太坊状态树结构。这是因为当前的 Merkle Patricia tree 在实现任何加密证明方案时是 极其 不友好的,特别是在最坏情况下。这对于 "原始" Merkle 分支,以及将 Merkle 分支“包装”到 STARK 中的可能性都是如此。关键难点源于 MPT 的两个缺点:
32 * (16 - 1) * log16(N) = 120 * log2(N)
字节,在 232 项树中约为 3840 字节。而在二叉树中,你只需 32 * (2 - 1) * log2(N) = 32 * log2(N)
字节,约为 1024 字节。我们可以计算一个最坏情况场景如下:
30,000,000 gas / 2,400 ("cold" account read cost) * (5 * 480 + 24,000) = 330,000,000
字节
由于当许多支路存在时,支路的顶部部分会被重复,这使得支路成本略有减少( 5 * 480
而不是 8 * 480
)。但是,即便如此,这也导致下载的数据量在一个槽中完全不切实际。如果我们尝试将其包装在 STARK 中,则会出现两个问题:(i)KECCAK 相对不适合 STARK ,而(ii)330 MB 的数据意味着我们必须证明 500 万次调用 KECCAK 轮函数,这对于绝大多数消费硬件来说是 过于庞大 的证明,即便我们能够让 STARK 证明 KECCAK 更加高效。
如果我们只用二叉树替换十叉树,并且我们也用 Merkelize 代码,则最坏情况大约变为 30,000,000 / 2,400 * 32 * (32 - 14 + 8) = 10,400,000
字节(14 是冗余位 ~214 个分支的减法,而 8 是进入块中某个叶子证明的长度)。请注意,这需要更改 gas 成本,以便对访问每个单独的代码块收费; EIP-4762 正是这样做的。10.4 MB 要比以前好得多,但仍然对于许多节点而言,在一个槽中下载数据仍然过多。因此我们需要引入更强大的技术。为此,有两个主要解决方案:Verkle trees 和 STARKed binary hash trees。
Verkle trees 使用基于椭圆曲线的向量承诺来生成更短的证明。关键在于 与每个父子关系有关的证明片段仅为32字节,无论树的宽度如何。树的宽度唯一的限制是如果树变得太宽,证明将变得计算效率低下。为以太坊提议的实施宽度为256。
因此,证明中单个分支的大小变为 32 * log256(N) = 4 * log2(N)
字节。因此,理论最大证明大小为 30,000,000 / 2,400 * 32 * (32 - 14 + 8) / 8 = 1,300,000
字节(因为状态快照的分布不均匀,因此在实践中的数学结果略有不同,但这可以作为第一近似)。
作为额外的注意事项,请注意,在以上所有示例中,这种"最坏情况"并不 完全 是最坏情况:当攻击者故意“挖掘”两个地址以在树中具有较长的公共前缀并从其中一个地址读取时,这可能会使最坏情况下的分支长度增加大约 ~2 倍。但即便有这一点,Verkle trees 仍然能够让我们达到 ~2.6 MB 的最坏情况证明,这大致匹配了今日的最坏情况 calldata。
我们还利用这一点做了另一件事:使访问“相邻”存储变得非常便宜:无论是相同合约的许多代码块,还是相邻的存储槽。EIP-4762 提供了相邻的定义,仅收取200的 gas 作为相邻访问。如果我们想让这个值出于安全原因降低,我们可以适度增加相邻访问的成本。
这里的技术非常自明:你做一个二叉树,拿到证明你需要证明区块中值的最大10.4MB的证明,并用该证明的 STARK 替换它。这样我们就可以使证明本身仅由待证明的数据组成,外加 ~100-300 kB 的实际 STARK 固定开销。
这里的主要挑战是证明时间。我们可以基本上跟上面的计算相同,只是我们计数哈希而不是字节。一个 10.4 MB 的区块意味着 330,000 个哈希。如果我们加入攻击者在树中“挖掘”具有长公共前缀地址的可能性,真正 的最坏情况变为大约 660,000 个哈希。所以,如果我们可以每秒证明 ~200,000 个哈希,那就没问题。
这些数字已经在使用 Poseidon hash function 的消费级笔记本电脑上达到,该函数特别设计为适合 STARK。然而,Poseidon 相对不成熟,因此许多开发者尚未对此完全信任以保证安全。因此,有两个切实可行的前进道路:
Starkware 在本写作时的循环 STARK 证明器只有在证明保守哈希函数的情况下,每秒能证明 ~10-30k 哈希。然而,STARK 技术正在快速改进。即便是今天,基于 GKR 的技术也显现出将在未来提供约达到 ~100-200k 的潜力。
除了验证区块,还有三个更高效无状态验证的关键用例:
这些用例都有一个共同点,即它们需要大量的证明,但每个证明都很小。因此,STARK 证明实际上并不适合它们;相反,最现实的选择是直接使用 Merkle 分支。Merker 分支的另一个优点是它们是可更新的:给定一个以块 B 为根的状态对象 X 的证明,如果你收到带有其见证的子块 B2,则可以更新证明,使其根植于块 B2。Verkle 证明也可以本地更新。
剩下的主要工作是:
我们还将很快面临一个决策点,选择三种选项之一:(i)Verkle trees, (ii) 面向 STARK 的哈希函数,以及 (iii) 保守的哈希函数。它们的属性可以通过下表进行大致总结:
Verkle | Data plus ~100-2,000 kB | Elliptic curve (not quantum-resistant) | < 1s |
---|---|---|---|
STARK over conservative hash functions (eg. SHA256, BLAKE) | Data plus ~100-300 kB | Conservative hash functions | > 10 s |
STARK over aggressive hash functions (Poseidon, Ajtai) | Data plus ~100-300 kB | Relatively new and less-tested hash functions | 1-2s |
除了这些“重点数字”,还有一些其他重要考虑:
如果我们希望以量子安全的方式获得 Verkle 见证可更新属性,同时又足够高效,另一条可能的路径是使用基于晶格的 Merkle trees。
如果在最坏情况下证明系统效率不足,另一种我们可以使用的“托出兔子”的方法是 多维 gas:为 (i) calldata, (ii) 计算, (iii) 状态访问以及可能的其他不同资源设置独立的 gas 限制。多维 gas 增加复杂性,但作为交换,这可以更紧密地限制平均情况与最坏情况之间的比例。使用多维 gas,理论上需要证明的最大分支数可能会降低,从 30,000,000 / 2400 = 12,500
降至例如 3000。 这甚至在没有改进证明器的情况下使BLAKE3(刚好)足够。
另一种“托出兔子”的方法是 这个提议,可以 延迟状态根计算直到一个区块之后的槽。这样我们将有完整的 12 秒来计算状态根,这意味着即使在最极端的情况下,仅需 ~60,000 个哈希/秒的证明时间也是足够的——使我们又回到 BLAKE3 恰好够用的范围。
这种方法的缺点是这将增加轻客户端延迟一个槽,尽管该技术的更智能变体会将此延迟减少到 仅 证明生成延迟。例如,证明可以在任何节点生成后立即广播到网络,而无需等待下一个区块。
解决无状态性大大提高了单独质押的便利性。如果能够降低单独质押的最低余额的技术(例如 Orbit SSF 或应用层策略如 squad staking)可用,这将变得更有价值。
如果同时引入 EOF,则多维 gas 将变得更容易。这是因为多维 gas 的 一个关键复杂性 与处理子调用有关,这些子调用不会将父调用的完整 gas 传递下去,而 EOF 通过简单地使此类子调用非法来解决了该问题(原生账户抽象将为当前主要使用的部分 gas 子调用提供协议内替代方法)。
另一个重要的协同作用是在无状态验证和历史过期之间。如今,各客户端需要存储近一 TB 的历史数据;这些数据的大小是状态的数倍。即便客户端是 无状态 ,几乎免除存储客户端的梦想也无法实现,除非我们能够解除客户端存储 历史 的责任。在这方面的第一步是 EIP-4444,这也意味着将历史数据存储在 torrents 或门户网络中。
EVM 执行的有效性证明 我们在解决什么问题?以太坊区块验证的长期目标是明确的:你应该能够通过(i) 下载区块 或者甚至只是对数据可用性抽样的小部分(ii) 验证一个小证明 来验证一个以太坊区块。这将是一个极低资源消耗的操作,并且可以在移动设备、浏览器钱包中,甚至(无数据可用性部分)在其他链中完成。达到这一点需要对 (i) 共识层(即权益证明)和 (ii) 执行层(即 EVM)有 SNARK 或 STARK 证明。前者本身就是一个挑战,它应该在对共识层进行进一步改进的过程中进行解决(例如单槽确认)。后者需要 EVM 执行证明。 什么是它,它是如何工作的?在以太坊规范中,EVM 被定义为状态转换函数:你有一些前状态 S
、一个区块 B
,然后计算一个 后状态 S' = STF(S, B)
。如果用户使用轻客户端,他们没有 S
和 S'
或者 B
的完整信息;相反,他们有一个 前状态根 R
、一个 后状态根 R'
和一个 区块哈希 H。需要证明的完整声明大致如下:
R
、后状态根 R'
,区块哈希 H
B
、区块访问的状态对象 Q
、在执行区块后的相同对象 Q'
、状态证明(例如 Merkle 分支) P
P
是一个有效证明,证明 Q
包含由 R
表示的状态的一部分Q
上运行 STF,就会 (i) 执行只访问 Q
内的对象,(ii) 区块是有效的,并且 (iii) 结果是 Q'
Q'
和 P
的信息重新计算新的状态根,你将获得 R'
如果这存在,则你可以拥有一个全面验证以太坊 EVM 执行的轻客户端。这允许客户端以相当低的资源进行操作。要实现 真正 全面验证的以太坊客户端,还需要在共识方面做到这一点。对于 EVM 计算的有效性证明的实现已经存在,并且正在被Layer2大量使用。然而,提高 EVM 有效性证明以在 L1 上可行还需要做大量的工作。 现有研究的链接是什么?
如今,EVM 的有效性证明在两个维度上是不足的:安全性 和 证明时间。
安全有效的证明涉及对 SNARK 的保障,确保它实际验证 EVM 计算,并且没有漏洞。提高安全性的两种主要技术是 多证明器 和 正式验证。多证明器意味着要有多个独立编写的有效性证明实现,就像有多个客户端一样,当区块通过这些实现中的一个足够大的子集证明时,客户端就接受该区块。正式验证涉及使用通常用于证明数学定理的工具,例如 Lean4,以证明有效性证明仅接受作为底层 EVM 规范的正确执行的输入(例如 EVM K Semantics 或使用 Python 编写的 Ethereum execution layer specifications (EELS))。
足够快的证明时间意味着任何以太坊区块都可以在不足 ~4 秒内证明。目前离这一目标仍然远,但我们比两年前想象的任何情况都要接近。要实现这一目标,我们需要在三个方向上取得进展:
在实现这一点时面临挑战。如果计算无法在最坏情况下有效,即当非常大交易占用整个区块时,计算的分割不能按交易进行,应以 opcode(EVM 或基于 RISC-V 的底层虚拟机的 opcode 可用)作为分割标准。然而,一个关键实现挑战使这一过程并不 完全 简单,那就是必须确保 VM 的“内存”在证明的不同部分之间保持一致。但是,如果我们 能够 实现这种类型的递归证明,那么我们知道至少证明延迟问题是解决的,即使在其他领域没有任何改善。
证明寄存器系统优化——新证明系统例如 Orion、Binius、GKR、以及更多,可能会在通用计算方面进一步大幅减少证明时间。
EVM gas 成本的其他变更——EVM 中的许多内容可以优化,使其更加友好于证明,尤其是在 最坏情况下。即使攻击者能构造一个区块,将造成证明者花费十分钟的时间来解决的问题,能够在 4 秒内证明平均以太坊区块也不够。所需的 EVM 更改在很大程度上分为两类:
此外,前面一节提到的两种“托出兔子”的方法(多维 gas 和 延迟状态根)也可以帮助这里。然而,值得注意的是,与无状态验证不同,使用任何一个托出兔子意味着我们必须具备足够的技术才能实现我们今天所需的功能,但即使使用这些技术,全 ZK-EVM 验证仍需更多的工作 - 只是在未来需要的工作相应减少了。
上面没有提到的一点是 证明器硬件:通过使用 GPUs、FPGAs 和 ASICs 更快速地生成证明。Fabric Cryptography、Cysic 和 Accseal 是三家公司正在推动进展。这对于Layer2来说是极其有价值的,但对于Layer1 来说,这似乎不太可能成为决定性的考虑,因为强烈希望维持Layer1 的高度去中心化,这意味着证明生成必须在 reasonably large subset of 以太坊用户的能力范围内,且不应被单一公司的硬件所制约。Layer2可以进行更激进的权衡。
在这些领域仍需做工作:
在这里可能产生的权衡包括:
实现 EVM 有效性证明的核心技术与两个其他领域密切相关:
在Layer1 成功实现有效性证明,可以为独立质押提供最终的便利:即便是最弱的计算机(包括手机或智能手表)也能够质押。这进一步增加了解决独立质押其他限制的价值(例如 32 ETH 的最低金额)。
此外,Layer1 的 EVM 有效性证明也可以实现显著的 L1 gas 限制增加。
共识的有效性证明 我们在解决什么问题?如果我们希望能够通过 SNARK 完全验证以太坊区块,那么 EVM 执行不仅是我们需要证明的唯一部分。我们还需要证明 共识 : 处理存款、取款、签名、验证者余额更新和其他元素的以太坊权益证明部分。共识比 EVM 简单得多,但面临的挑战是,我们没有Layer2 EVM rollups 作为许多工作本来就会完成的理由。因此,任何以太坊共识证明的实现都需要“从头开始”完成,尽管证明系统本身是可以在这方面建立的共享工作。 什么是它,它是如何工作的?
信标链被定义为状态转换函数,和 EVM 一样。状态转换函数主要由三部分主导:
在每个区块中,我们需要验证 1-16 个 BLS12-381 ECADD 每个验证者(可能有多个,因为多个签名可能会包含在多个聚合中)。可以通过子集预计算技术来补偿,所以总的来说我们可以说每个验证者需要一个 BLS12-381 ECADD。目前,每个槽约有 ~30,000 个验证者在签名。未来,通过单槽最终确认,这可能在任一方向上变动(参见 此处的说明): 如果我们采取“暴力”途径,这可能在每个槽中增加到 100 万个验证者;与此同时,若采用 Orbit SSF 可能仍保持在 32,768,甚至减至 8,192。
至于配对,目前每个槽的最大集体指标为 128 个验证,这就意味着需要验证 128 个 配对。通过 EIP-7549 及其他修改,这可以合理地减少到每槽16个。配对的数量并不多,但成本极高:每个配对的运算要求验证时间是 ECADD 的几千倍。
证明 BLS12-381 操作的一个重大挑战是,当前并没有方便的曲线可用来绝对等于 BLS12-381 的域大小,这为任何证明系统增加了相当大的开销。而针对以太坊提出的 Verkle trees,则使用了 Bandersnatch curve,这使得 BLS12-381 自身成为证明一个 Verkle 分支于 SNARK 系统时的自然曲线。相当简单的实现每秒可以证明 ~100 G1 加法;但知道像 GKR 这样的聪明技术会是必需品,确保证明过程快得足够。对于 SHA256 哈希,今天最坏的情况是时代过渡区块,其中整个验证者短余额树,以及大量验证者余额,都会进行更新。验证者短余额树为每个验证者分配一个字节,因此大约 1 MB 的数据需要被重新哈希。这对应于 32,768 次 SHA256 调用。如果有一千个验证者的余额超过或低于需要更新验证者记录中的 有效余额 的阈值,那么这对应于一千个 Merkle 分支,因此可能还有另一万次哈希。洗牌机制每个验证者需要 90 位(因此,11 MB 的数据),但这可以在一个时代的任何时间计算完成。对于单槽最终性,这些数字可能根据细节再次增加或减少。不过,洗牌就变得不必要了,但 Orbit 可能会重新带回来某种程度的需求。
另一个挑战是需要 读取 所有验证者状态,包括公钥,以验证一个区块。仅读取公钥就需要 4800 万字节,对于 100 万个验证者,加上 Merkle 分支。这需要每个时代数百万次哈希。如果我们今天必须证明权益证明的有效性,一个现实的方案将是一种增量可验证计算:在证明系统内存储一个优化过的单独数据结构,以便进行高效查找,并证明对此结构的更新。
总之,有很多挑战。
有效解决这些挑战可能需要对信标链进行深度重设计,这可能会在转向单槽最终性时进行。这个重设计的特点可能包括:
实际上,我们要花费几年时间才能获得 Ethereum 共识的有效性证明。这大致与我们需要实施单槽最终性、Orbit、对签名算法的更改以及可能的安全性分析的时间线相同,以在使用“激进”的哈希函数(如 Poseidon)时变得足够自信。因此,解决这些其他问题是最明智的,同时在进行这些工作时,保持 STARK 友好性。
主要的权衡可能在于操作顺序,在对 Ethereum 共识层进行更增量的方法和更激进的“同时进行多项更改”方法之间。对于 EVM,一个增量的方法是合理的,因为它最大限度减少了对向后兼容性的干扰。对于共识层,向后兼容性的问题较小,在重思信标链构造的各种细节上有好处,以最好地优化 SNARK 友好性。
STARK 友好性需要成为 Ethereum 权益证明共识的长期重设计中的主要关注点,特别是单槽最终性、Orbit、对签名方案的更改以及签名聚合。
- 原文链接: vitalik.eth.limo/general...
- 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!