状态树:区块链如何记录当前世界状态

状态树是区块链系统中用来表示“当前账本状态”的核心数据结构。它不是记录过去发生了哪些交易,而是记录交易执行之后,系统现在变成了什么样。
在比特币里,账本主要围绕 UTXO 运行;在以太坊里,账本则更像一个全球共享的状态机。每个区块都会让系统从一个状态转移到另一个状态。
上一个状态 + 本区块交易 = 新状态
状态树的作用,就是把这个“新状态”用一种可验证、可追踪、可证明的方式组织起来。
一、什么是状态?
在区块链语境里,“状态”指的是某个时刻系统里的当前结果。
例如在以太坊中,状态包括:
| 状态类型 | 示例 |
|---|---|
| 账户余额 | Alice 有 3 ETH |
| 账户 nonce | Alice 已经发起过 7 笔交易 |
| 合约代码 | 某个地址部署了一段智能合约代码 |
| 合约存储 | 某个合约变量 x 的值为 100 |
| 代币余额 | ERC20 合约记录 Bob 有 200 个代币 |
这些不是单笔交易,而是交易执行后的结果。
比如 Alice 向 Bob 转账 1 ETH:
转账前:Alice 3 ETH,Bob 5 ETH
转账后:Alice 2 ETH,Bob 6 ETH
状态树关心的是转账后的当前状态。
二、为什么需要状态树?
如果系统里只有几个账户,直接用表格记录余额就可以。但区块链是全球共享账本,可能包含海量账户、合约和存储项。
节点需要解决几个问题:
- 如何高效查找某个账户的当前状态?
- 如何证明某个账户状态确实属于当前账本?
- 如何发现状态被篡改?
- 如何让区块头用一个很小的字段承诺整个系统状态?
- 如何支持轻客户端验证某个账户或合约变量?
状态树就是为了解决这些问题而设计的。
三、状态树的基本结构
简化来看,状态树把所有账户组织成一棵树,树根是一个哈希值,称为 状态根 State Root。
真实以太坊使用的不是普通二叉树,而是一种叫 Merkle Patricia Trie 的结构,中文常译为 默克尔帕特里夏树 或 默克尔前缀树。
它结合了两类思想:
| 结构 | 作用 |
|---|---|
| Merkle Tree | 通过哈希保证数据不可篡改,并支持证明 |
| Patricia Trie | 通过键路径组织数据,便于查找和压缩 |
四、状态根:用一个哈希承诺整个世界状态
状态树最重要的产物是状态根。
状态根的意义是:
用一个很短的哈希值,代表整个区块执行完成后的全局状态。
如果任何账户余额、nonce、合约代码哈希或合约存储发生变化,相关节点哈希会变化,最终状态根也会变化。
这使得区块链可以做到:
小小一个 stateRoot,承诺整个世界状态。
五、状态树在区块中的位置
以太坊每个区块头中都会包含状态根。可以把它理解为:
这个区块里所有交易执行完以后,系统状态的最终摘要。
简化流程如下:
当一个节点收到新区块时,它会:
- 从上一区块的状态开始;
- 按顺序执行新区块中的交易;
- 更新账户余额、nonce 和合约存储;
- 重新计算状态根;
- 检查计算结果是否等于区块头里的状态根。
如果不一致,区块就是无效的。
六、账户状态里有什么?
以太坊账户大致分为两类:
| 账户类型 | 说明 |
|---|---|
| 外部账户 EOA | 由私钥控制的普通账户 |
| 合约账户 | 由智能合约代码控制的账户 |
每个账户状态通常包含四类核心信息:
| 字段 | 含义 |
|---|---|
| nonce | 外部账户发起交易次数,或合约创建计数 |
| balance | ETH 余额 |
| storageRoot | 合约存储树根 |
| codeHash | 合约代码哈希 |
外部账户没有合约代码,合约账户则会通过 codeHash 指向合约代码,并通过 storageRoot 指向自己的存储树。
七、存储树:合约自己的小账本
状态树记录所有账户;但每个智能合约还有自己的内部存储。
例如一个 ERC20 代币合约可能记录:
Alice 有 200 个代币
Bob 有 500 个代币
总供应量为 1000000
这些变量不会直接平铺在全局状态树里,而是放在该合约账户自己的 存储树 Storage Trie 中。
因此,以太坊状态可以理解为两层结构:
全局状态树:管理所有账户
合约存储树:管理单个合约内部变量
八、状态树和交易树、收据树的区别
以太坊中常见的树不止状态树。
| 树 | 记录什么 | 根哈希写在哪里 |
|---|---|---|
| 状态树 State Trie | 区块执行后的账户和合约状态 | 区块头 stateRoot |
| 交易树 Transaction Trie | 本区块包含的交易 | 区块头 transactionsRoot |
| 收据树 Receipt Trie | 交易执行结果、日志、gas 使用等 | 区块头 receiptsRoot |
三者的区别可以简单概括:
交易树记录发生了什么;
收据树记录执行结果如何;
状态树记录世界变成了什么。
九、状态树如何支持轻客户端证明?
状态树的 Merkle 属性让它可以提供状态证明。
假设轻客户端想知道:
Alice 在某个区块高度的 ETH 余额是不是 3 ETH?
它不必下载完整状态树,只需要获得:
- 区块头中的 stateRoot;
- Alice 账户数据;
- 从 Alice 账户节点到 stateRoot 的证明路径。
轻客户端可以沿着证明路径重新计算哈希。如果最终得到的根等于区块头里的 stateRoot,就可以确认:
Alice 的账户状态确实被这个区块的状态根所承诺。
这类证明常被称为 Merkle Proof 或 状态证明。
十、状态树和比特币 UTXO 模型的区别
状态树常见于账户模型区块链,而比特币采用 UTXO 模型。
| 对比项 | 比特币 | 以太坊 |
|---|---|---|
| 账本模型 | UTXO 模型 | 账户模型 |
| 当前状态 | 未花费交易输出集合 | 账户和合约状态 |
| 余额来源 | 汇总可用 UTXO | 直接读取账户余额 |
| 主要树结构 | 区块内交易 Merkle 树 | 状态树、交易树、收据树 |
| 合约存储 | 非主要设计目标 | 通过存储树管理 |
比特币更像现金零钱:
你有哪些还没有花掉的纸币?
以太坊更像账户系统:
每个账户现在有多少钱?每个合约变量现在是多少?
十一、状态树的优点
状态树带来几个重要优势:
| 优点 | 说明 |
|---|---|
| 可验证 | 任意状态变化都会影响状态根 |
| 可证明 | 可以证明某个账户或变量属于某个状态根 |
| 可同步 | 节点可以围绕状态根检查一致性 |
| 可追踪 | 每个区块都有执行后的状态承诺 |
| 适合智能合约 | 能表达复杂合约存储 |
状态树使区块链不仅能记录“转账历史”,还能记录复杂应用的当前状态。
十二、状态树的成本和挑战
状态树也不是没有代价。
| 挑战 | 说明 |
|---|---|
| 存储压力 | 大量账户和合约状态会持续膨胀 |
| 访问成本 | 合约频繁读写状态会增加节点负担 |
| 状态膨胀 | 无用或长期不用的数据仍可能占用状态 |
| 实现复杂 | Merkle Patricia Trie 比普通树复杂 |
| 同步复杂 | 新节点同步和验证状态需要额外机制 |
这也是为什么以太坊生态长期关注状态租金、状态过期、Verkle Tree、无状态客户端等方向。
十三、一个完整例子:转账如何改变状态树
假设 Alice 向 Bob 转账 1 ETH。
初始状态:
| 账户 | 余额 | nonce |
|---|---|---|
| Alice | 3 ETH | 7 |
| Bob | 5 ETH | 2 |
交易执行后:
| 账户 | 余额 | nonce |
|---|---|---|
| Alice | 2 ETH | 8 |
| Bob | 6 ETH | 2 |
状态树中的变化路径如下:
新区块头会保存这个新的状态根。其他节点只要重新执行交易,也应该得到同一个状态根。
十四、总结
状态树是账户模型区块链中的核心结构。它的本质是:
用一棵带哈希的树组织全局账户和合约状态,并用状态根代表整个系统当前状态。
它解决了三个关键问题:
- 表示问题:如何表示当前全局状态;
- 验证问题:如何发现状态是否被篡改;
- 证明问题:如何向轻客户端证明某个账户或变量的值。
一句话概括:
交易树说明区块里发生了什么,收据树说明执行结果如何,状态树说明世界现在变成了什么。
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐



所有评论(0)