本文详细探讨了区块链虚拟机的存储层及其面临的挑战,特别是以太坊的Merkle Patricia Trie结构带来的高昂存储成本和状态膨胀问题。通过分析各种区块链(如Solana、Sui、Sei)在存储和检索数据方面的优化策略,本文旨在提出有效的解决方案来实现更高的性能和可扩展性。作者呼吁社区参与协作,共同推动更美好的区块链基础设施的发展。
特别感谢 Philippe Dumonet、Lefteris Kokoris-Kogias、Patryk Krasnicki、dcbuilder.eth、Evan Pappas、Rishin Sharma、Anastasios Andronidis 的反馈和讨论。
区块链虚拟机的存储层至关重要,因为它管理持久数据,如智能合约和帐户,以及它们的内部状态和变量。在以太坊虚拟机(EVM)上进行的存储操作是资源密集型且耗费气体的操作之一,直接与 EVM 处理存储操作的效率相关。在以太坊上存储数据的成本很高,因为 EVM 从叶节点重新计算哈希,一直计算到根节点。随着 MPT 的大小和深度增加,读取和写入操作的计算复杂性也随之增加。
随着更多智能合约的部署和更多数据的存储,区块链状态持续增长,导致“状态膨胀”。这个问题增加了节点的存储需求,特别是全节点,它们必须存储整个状态以验证交易,这使得使用消费级硬件参与网络变得越来越资源密集型。
状态膨胀造成的读/写操作低效限制了开发者的设计空间,提高了消费者的成本。本文将探讨缓解这些限制的方法。
EVM 存储层负责维护持久但可变的数据,这些数据在智能合约执行完成后仍然存在。这与 EVM 的内存不同,后者用于合同执行过程中的短期临时数据。
EVM 的持久存储组件:
EVM 使用修改版的帕特里夏梅克尔树(Patricia Merkle Tree)。Trie 是一种树状数据结构,允许高效地存储和检索键值对。
以太坊有:
这些 trie 的根哈希只存储在块头中,确保数据完整性,同时防止块头变得过大。
以太坊的修改梅克尔-帕特里夏树结构
以太坊维持多客户端方法,并且故意没有参考客户端,所有人 必须 运行,以提高冗余、安全性、技术和政治的去中心化,并促进实验改进。目标确保没有一个共识或执行客户端占据网络的 ⅔ 以上。
以太坊客户端分布 - 2024年11月
每个客户端变体遵循规范,但采用不同的实现方式,导致不同的性能指标。
Geth
第一个以太坊客户端是用 Go 编写的,它使用 LevelDB,这是一个优化用于快速读取和写入的键值存储库。它实现了黄皮书中指定的 Merkle Patricia Trie,并使用快照来优化状态访问,提高同步时间。
Besu
它用 Java 编写,使用 RocksDB,这是一个针对快速存储优化的可嵌入持久键值存储,是 LevelDB 的一个分支,优化了 SSD。它实现了 Merkle Patricia Trie,并具有先进的缓存机制以提高性能。
Nethermind
用 C# 编写,使用 .NET Core 框架,采用 LMDB(闪电内存映射数据库)进行高效的数据存储,并进行了内存缓存的优化,以支持频繁访问的节点和写入缓存以批量处理数据库操作。
Erigon
它是用 Go 编写的,使用基于 MDBX(内存映射数据库极限)的自定义存储层。它在很大程度上消除了运行时 MPT 结构,同时通过在需要时计算状态根来保持 MPT 兼容性。相反,状态 trie 被扁平化为一个键值数据库,以减少复杂性。这消除了 MPT 所需的多个数据库查找,提供了更好的存储效率、减少了磁盘空间需求,并降低了与 MPT 基于客户端相比的磁盘 I/O。
Silkworm,也称为 Erigon++,是基于 Erigon 架构的以太坊协议的 C++ 实现。它同样使用 libmdbx 作为数据库引擎,并寻求进一步优化客户端性能和资源利用。当前正在开发中,尚未进入 alpha 阶段。
Reth
Reth 采取模块化、以库为先的方法进行以太坊客户端开发。用 Rust 编写以提高性能,它采用 Erigon 的分阶段同步架构,同时强调组件的可重用性。Reth 正在实现并行区块处理,采用表分区以改进数据组织,并实施高效的修剪策略。
尽管有各种客户端,但一些核心局限性依然存在。
存储操作的高Gas费用
状态膨胀
梅克尔·帕特里夏树的复杂性与低效的数据检索
我们可以对存储收费,但这并不能解决这些局限性。开发者和用户会被激励更加谨慎地处理他们的存储需求,但历史上这并未奏效,例如 C 语言与垃圾回收之间的对比。存储租赁是一个经济解决方案,而不是技术解决方案。
更有效的解决方案可能涉及替代数据结构,和/或优化的数据库。让我们探讨一些区块链为优化读取、写入和梅克尔化所采取的不同方法。
读取
以太坊的状态检索过程从每个区块头中的 stateRoot 开始,该状态根是处理该区块交易后的状态 trie 的根哈希。为了访问当前状态数据,节点从最新块的 stateRoot 开始。帐户信息的检索通过首先用 Keccak-256 哈希帐户地址,创建一个状态 trie 的键。节点然后遍历这个 trie,沿着由键的小字节(nibbles)定义的路径从根到叶,通常涉及对每个节点的数据库查找。
对于任何类型的帐户,包括外部拥有帐户(EOA),检索的数据包括余额和随机数。对于合约帐户,还存储以下附加字段:
为了执行合约,EVM 必须检索实际的字节码。codeHash 用于定位和验证存储在节点代码存储中的字节码(通常是一个单独的键值存储)。这涉及使用 codeHash 作为键来访问代码存储,以获取字节码。要访问特定的合约存储变量,类似的过程也会发生。存储键(通常是变量的插槽索引)使用 Keccak-256 哈希。所得到的键用于遍历合约的存储 trie,从 storageRoot 开始,检索相关值。
提高数据读取效率的优化
以太坊采用多种优化措施来应对状态管理和检索的挑战。在数据库层面,以太坊客户端使用了像 LevelDB 或 RocksDB 这样的键值存储,这些存储都针对快速读取和写入进行了优化。这些客户端还实现了批量操作,以最小化磁盘访问。缓存策略起着至关重要的作用,频繁访问的节点保存在内存中以减少磁盘 I/O,同时通过修剪 trie 节点来节省空间。快速同步模式,如快照同步和急速同步,使得节点可以下载最新的状态数据,或依赖区块头获得历史信息,从而显著减少同步时间。
协议改进,如 EIP-1052、EIP-2929 和 EIP-2930,旨在优化状态访问模式和更精确的Gas费用计算。对无状态以太坊的持续研究探讨了客户无需存储整个状态,而是依赖于证明进行验证的设计。此外,像 Verkle Trees 这样的替代数据结构也在研究中,以提供更小的证明确认和更快的验证。
写入
写操作始于用户或智能合约提交事务。事务进入内存池,等待被验证者提议包含在块中。验证者通过验证事务的签名、随机数和执行所需的气体来验证事务。这个过程与以太坊的存储结构进行交互,主要是帐户的状态 trie 和合约的存储 tries。在事务执行过程中任何值的变化都需要更新相应的 trie 节点并重新计算哈希直到根,确保加密数据的完整性。
以太坊所采用的写入优化
1. Gas费用调整
2. 无状态以太坊研究
3. 数据库和存储改进
4. 协议层的增强
以太坊社区探讨的梅克尔化优化
为了应对上述 MPT 限制,以太坊社区正在探索 Verkle trees,
这是一种多项式承诺梅克尔树,允许更小的证明大小和更高效的验证。
Verkle 证明的大小远小于梅克尔证明,减少了轻客户端和无状态客户端所需的带宽。更小的证明和更高效的验证使更好的可扩展性成为可能,并为无状态以太坊铺平道路。EIP-4844(Proto-Danksharding)引入了数据可用性抽样,为实施 Verkle trees 奠定基础。通过减少加密证明(见证)的大小,Verkle trees 使无状态客户端能够验证事务,而无需维护整个状态数据库。这一效率是以太坊可扩展性路线图的一个重要组成部分,促进了更轻节点和更广泛的网络参与。
Solana 的数据存储模型
1. 扁平账户模型
2. 内存映射账户存储
提高 Solana 数据读取效率的优化
1. 避免复杂的数据结构
2. 使用 Sealevel 进行并行交易处理
3. 高效的数据序列化
4. 缓存和数据位置
5. 用于状态同步的快照机制
6. 乐观并发控制
7. 账户版本和垃圾回收
写入
Solana 的写操作采用账户模型,分离程序和数据,使用扁平命名空间实现直接访问。系统采用乐观并发控制和 Sealevel 运行时进行并行交易处理,写锁确保数据一致性。Solana 的历史证明和塔 BFT 共识加快交易确认,而内存映射存储实现零复制写入。事务流水线和 GPU 加速提高处理速度。该平台通过持久存储、定期快照和有效的数据压缩保持数据完整性。
提高 Solana 写入操作效率的优化
1. 并行化
2. 乐观并发控制
3. 高性能运行环境
4. 直接账户访问
5. 减少磁盘 I/O
6. 精简的共识
7. 交易费用机制
Solana 对状态管理与梅克尔化的处理
与以太坊 MPT 相比,Solana 在梅克尔化方面采取了不同的方法,优先考虑性能和简单性。它没有采用 trie 结构,而是只使用简单的梅克尔树进行块验证,每个块包含从所有账户状态计算的状态根哈希。该系统直接使用 SHA-256 对账户状态进行哈希,结合诸如 lamports(余额)、拥有者信息、可执行标志、租赁时代和账户数据等元素。
这种简化的梅克尔化策略与 Solana 的扁平账户模型和高度吞吐的重视相一致。状态验证主要通过交易执行期间的运行时验证进行,而不是通过加密证明。通过消除复杂的树遍历和中间节点,它实现了更快的状态访问和更新,同时减少了存储开销。然而,这种方法具有权衡——验证者必须在内存中维护完整的当前状态,且证明生成的粒度不如以太坊的 MPT 系统。这种设计以性能为最大化,要求验证者具有更高的内存占用。
Sui 的数据存储模型
Sui 的数据存储模型围绕对象优先的方法展开,其中对象作为存储和计算的基本单元。这些对象封装状态和行为,表示用户数据和智能合约。Sui 维护一个全局对象存储,每个对象在扁平命名空间中唯一标识,通过对象 ID 实现直接和高效的访问。
该平台利用 Move 编程语言,该语言专为安全和可验证的智能合约开发而构建。Move 的资源导向模型与 Sui 的对象优先设计无缝对接,增强了整体系统的完整性和效率。
Sui 实现了所有权和访问控制系统。对象可以由用户账户或其他对象拥有,所有权决定着访问权限和修改能力。共享对象的概念允许多个事务的并发访问和修改。这种所有权模型提供了细粒度的访问控制,通过最小化不必要的争用来优化数据读取。
提高数据读取效率的优化
1. 通过对象 ID 直接访问对象
2. 事务的并行执行
3. 高效的共识机制
Mysticeti:Sui 凭借低延迟和高吞吐量口优化。
4. 对象版本和缓存
5. 高效的数据序列化
6. 数据库和存储优化
7. 处理共享对象
写入
Sui 的写操作围绕以对象为中心的数据模型展开,唯一标识的对象封装数据和行为。这一方法实现了直接访问和通过所有权进行的细粒度控制。Sui 利用并行交易执行来处理独立对象,最小化冲突并最大化吞吐量。Move 编程语言保证了数据的完整性和高效的序列化。Sui 优化的共识机制结合快速的事务传播与 BFT,确保快速和安全的写入确认。内存高效的数据结构,包括内存中存储和有效的垃圾收集,进一步提升写入性能。
Sui 对状态管理和梅克尔化的处理
Sui 采用了一种独特的状态管理和梅克尔化方法,与其以对象为中心的架构一致。它不是使用传统的梅克尔树或 MPT,如以太坊一样,而是实现了一种有向无环图(DAG)结构,用于组织交易及其对对象的影响。该平台的梅克尔化策略主要围绕对象版本控制和认证数据结构,这些结构跟踪对象历史和所有权。
Sui 中的每个对象都有一个唯一的版本号,在修改时单调增加。系统在每个检查点维护对象状态的梅克尔根,结合增量验证和因果顺序跟踪。这一架构使得在保持密码验证的前提下,可以实现并行处理交易。Sui 并未使用全局状态 trie,而是使用每个对象的认证路径,与其 Narwhal-Tusk 共识协议相结合,实现高效的状态验证。这一方法使验证者能够并行处理不重叠的交易,同时保持强一致性保证。
Sui 在梅克尔化中的关键创新在于与 Move 编程语言的资源模型的整合。Move 的所有权系统确保对象只能被其拥有者或指定智能合约所修改,这简化了梅克尔证明的生成和验证。通过在认证数据结构中直接跟踪对象的所有权和版本历史,Sui 在不依赖传统梅克尔树的开销下实现了高效的状态验证。然而,这一设计选择意味着验证者必须维护比仅跟踪当前状态的系统更为详细的对象历史。
在 Sei,我们识别了一些关键挑战:
写入放大:当前的 IAVL 树结构导致高写入放大,导致磁盘上写入的过多元数据超过实际有效数据。这导致存储使用效率低下和磁盘 I/O 增加。
存储增长:由于写入放大和低效压缩,磁盘使用迅速增长。这种指数增长使得运行归档节点变得昂贵且不可持续。
慢速度操作:关键操作,如状态同步、快照创建和数据检索,随着区块链状态的增长而变得日益缓慢,影响节点性能和用户体验。
数据库性能随着时间的推移而下降:随着数据规模的增长,LevelDB 的性能显著下降,尤其影响状态操作。这在处理大型数据集时尤为明显,影响节点的效率。
Sei 中读取的优化
1. 状态承诺与状态存储的分离
2. 采用 MemIAVL 进行状态承诺
Sei 使用 MemIAVL,即 IAVL 树的内存版本,处理状态承诺:
对读取的好处:
3. 优化历史查询的状态存储
对于 SS 层,我们提出一个可插拔接口以允许集成针对读取性能优化的数据库:
潜在的读取优化:
4. 节点特定配置
不同节点有不同需求:
5. 改进的数据结构和存储技术
通过拯救传统 IAVL 树进行状态存储,Sei 可以采用更适合读取优化的数据结构:
EVM 的存储层面临关键挑战:存储操作需要通过 MPT 进行昂贵的哈希重新计算,这使得它们既昂贵又资源密集。随着智能合约的增多,状态规模的增加增加了计算复杂性和存储需求,使得使用消费硬件参与网络变得越来越困难。这些低效限制了开发者的选择,提高了用户的成本。
优化区块链存储的关键在于认识到状态承诺(用于共识和验证)与状态存储(用于数据持久性)具有不同的需求,并且可以独立优化。虽然不同区块链都在探索这一分离的不同方法,但 Sei 使用 MemIAVL 和可插拔存储实现的实现展示了这种架构分离如何实现并行执行和管理状态膨胀,同时保持低硬件需求。该分离允许独立优化共识操作和数据存储与检索,减少状态膨胀的影响,同时支持更高的交易吞吐量。
研究仍然在第一性原理的探索上检讨状态管理,探寻能够进一步优化两个层层的新的数据结构和存储方法,同时保持安全性和去中心化。
我们邀请开发者、研究人员和社区成员加入我们的任务。这是一次开放源代码协作的邀请,旨在建立更可扩展的区块链基础设施。查看 Sei Protocol 的 文档,探索 Sei 基金会资助机会( Sei 创建者基金, 日本生态系统基金)。
- 原文链接: blog.sei.io/research-sca...
- 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!