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

以太坊最初存储的核心是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作为默认的持久化存储引擎,用于保存完整的MPT数据,LevelDB是一个键值数据库,其键为MPT节点的哈希(或路径),值为节点的序列化数据(包括节点类型、子节点引用、键值对等)。
世界状态MPT的根哈希0xabc…对应一个序列化的内部节点,该节点包含子节点的哈希引用,通过递归查询LevelDB,最终可还原整棵MPT的结构,这种设计使得节点无需存储全量数据,仅通过哈希索引即可定位任意状态,节省了存储空间。
虽然完整的状态数据存储在节点的LevelDB中,但以太坊通过“状态根”实现了链上轻量化验证,每个区块头包含三个关键哈希:
stateRoot:世界状态的MPT根哈希; transactionsRoot:交易列表的MPT根哈希; receiptsRoot:交易收据的MPT根哈希。 节点无需下载所有状态数据,仅通过验证区块头中的stateRoot,即可确认状态变更的合法性,当用户声称账户A的余额为X时,只需提供从stateRoot到该账户状态路径的Merkle证明,节点即可快速验证其真伪,无需访问完整的状态数据库。
stateRoot对应的全部MPT节点),导致“状态同步”成为早期以太坊节点的痛点;