以太坊作为区块链2.0的代表性项目,其核心设计之一是通过“状态存储”实现去中心化的账户管理,与比特币仅记录UTXO(未花费交易输出)不同,以太坊需要维护全球账户状态(包括账户余额、合约代码、存储数据等),这一机制的最初实现奠定了其智能合约运行的基础,本文将追溯以太坊最初(2015年 Frontier 主网上线时)的存储架构,解析其核心组件与设计逻辑。

以太坊存储的底层载体:Merkle Patricia树

以太坊最初存储的核心是Merkle Patricia树(简称MPT),一种结合了Merkle树和Patricia Trie(前缀树)的数据结构,它通过递归哈希映射,将全局状态、交易数据、收据等全部存储在以太坊的“世界状态”(World State)中,实现了高效验证与数据完整性。

世界状态:全局账户的“总账本”

以太坊的“世界状态”是一个MPT,其每个叶子节点存储一个账户对象(Account Object),账户对象包含四个核心字段:

  • nonce:账户发起的交易数量(防止重放攻击);
  • balance:账户的以太币余额(单位:wei);
  • storageRoot:该账户关联的合约存储树的根哈希(仅合约账户有);
  • codeHash:账户合约代码的哈希(仅合约账户有,普通账户为空哈希)。

所有账户通过地址(address)作为键,在MPT中组织成有序结构,当用户向地址0x123…转账时,以太坊会更新该账户的balance,并重新计算世界状态的根哈希(称为“状态根”),这个根哈希被打包在每个区块的头部,成为区块不可篡改的核心证据之一。

合约存储树:状态数据的“分层管理”

对于智能合约账户,其状态数据(如变量值、数组等)存储在一个独立的MPT中,称为“合约存储树”(Storage Trie),这个树的根哈希就是账户对象中的storageRoot

一个简单的合约存储变量uint256 x = 42,其存储过程为:

  • 将变量x的“键”(通常基于Solidity编译后的内存偏移量,如0x0)和“值”(42的编码)作为叶子节点,插入到合约存储树中;
  • 计算存储树的根哈希,更新到账户对象的storageRoot字段;
  • 当合约状态变更时(如x = 100),仅更新合约存储树中对应的叶子节点,并重新计算根哈希,最终影响世界状态的根哈希。

这种分层设计实现了“全局状态-账户状态-合约存储”的解耦,使得状态更新仅涉及必要的树节点,而非全量数据,大幅提升了效率。

数据持久化:从内存到区块链

以太坊最初的状态存储并非完全“链上”存储,而是结合了内存、数据库与链上索引的混合模式。

内存中的缓存:加速状态访问

为了提升性能,以太坊节点(如Geth客户端)会维护一个内存中的状态缓存(State Cache),当读取账户状态时,优先从缓存中查找;若缓存未命中,再从持久化存储(如LevelDB)中加载并写入缓存,状态更新(如转账、合约调用)也先在缓存中进行,待区块确认后再批量写入持久化存储,减少磁盘IO压力。

持久化存储:LevelDB的底层支撑

以太坊最初使用LevelDB作为默认的持久化存储引擎,用于保存完整的MPT数据,LevelDB是一个键值数据库,其键为MPT节点的哈希(或路径),值为节点的序列化数据(包括节点类型、子节点引用、键值对等)。 随机配图