在区块链技术,尤其是以太坊的世界里,有三个核心的数据结构,它们常被形象地比作“三棵树”,这三棵树——状态树、交易树和收据树——共同构成了以太坊世界状态和交易历史的坚实基础,它们不仅是以太坊高效运行的关键,更是其实现去中心化、安全性和可追溯性的核心,本文将详细介绍这三棵“树”的作用,并配上相应的示意图,帮助您直观理解它们如何协同工作。


想象一下,以太坊网络就像一个庞大的、分布在全球的数字国家,这个国家里的每个“公民”(账户)、每笔“交易记录”和每次“交易结果”都需要被准确、高效地存储和查询,而“三棵树”就是这个数字国家的档案管理系统,确保了每一笔数据都有据可查、井然有序。

第一棵树:状态树 - 世界状态的“总账本”

【示意图】

           ----------------- 
          |    状态树根哈希   |
           ----------------- 
                 /     \
                /       \
               /         \
       -------------    ------------- 
      | 账户A地址... |  | 账户B地址... |
       -------------    ------------- 
          /   \               /   \
         /     \             /     \
 ---------------   -----   ---------------   ----- 
| 账户A: nonce  | | ... | | 账户B: nonce  | | ... |
| 余额: 10 ETH  | | ... | | 余额: 5 ETH   | | ... |
| 代码: ...    | | ... | | 代码: ...    | | ... |
| 存储: ...    | | ... | | 存储: ...    | | ... |
 ---------------   -----   ---------------   ----- 

核心作用: 状态树,全称“世界状态树”(World State Tree),是三棵树中最核心的一棵,它记录了以太坊在任何一个时刻的完整状态,它就是整个以太坊世界的“总账本”,列出了所有账户的实时信息。

  • 账户类型: 主要包括外部账户(由用户私钥控制的EOA)和合约账户(智能代码)。
  • 每个账户在树中都有一个节点,存储着该账户的关键数据,如:
    • nonce:账户发起的交易数量或创建的合约数量。
    • balance:账户的以太币余额。
    • storageRoot:指向该账户自己的“存储树”(Storage Tree)的根哈希,用于存储合约的持久化数据。
    • codeHash:指向该账户智能代码的哈希值。

工作原理: 状态树是一个Merkle Patricia Trie(MPT)数据结构,这意味着:

  1. 高效查询: 任何账户的状态都可以通过其地址快速定位到,就像在字典里查单词一样。
  2. 数据完整性: 树的顶端有一个唯一的“根哈希”,只要树中任何一个微小的数据发生变化(比如A账户转账给B账户0.1个ETH),整个树的根哈希就会彻底改变,这个根哈希被打包在每个区块的头部,成为区块身份的“身份证”,确保了历史状态的不可篡改性。

简单比喻: 状态树就像一个国家的户籍管理系统,实时记录着每个公民(账户)的身份、资产(余额)和房产(合约存储)。


第二棵树:交易树 - 历史交易的“流水账”

【示意图】

           ----------------------- 
          |     交易树根哈希      |
           ----------------------- 
                 /     |     \     \
                /      |      \     \
               /       |       \     \
       --------   --------   --------   -------- 
      | 交易0  | | 交易1  | | 交易2  | | ...   |
       --------   --------   --------   -------- 
      | 发送方  | | 发送方  | | 发送方  | | ...   |
      | 接收方  | | 接收方  | | 接收方  | | ...   |
      | 金额...| | 金额...| | 金额...| | ...   |
      | 签名...| | 签名...| | 签名...| | ...   |
       --------   --------   --------   -------- 

核心作用: 交易树,全称“交易列表树”(Transactions Tree),记录了某个特定区块内包含的所有交易的详细信息,它是对区块内所有交易行为的“流水账”。

  • 每个交易在树中都有一个节点,存储着该交易的全部数据,
    • 发送方地址
    • 接收方地址(或合约代码)
    • 转账金额
    • 交易数据(用于调用合约)
    • 发送方签名

工作原理: 和状态树一样,交易树也是一个Merkle Patricia Trie,当矿工打包一个区块时,会将区块内的所有交易按照一定顺序排列,构建成这棵树,树的根哈希同样被记录在区块头中。

简单比喻: 交易树就像银行一个账单周期(一个区块)内所有的交易记录列表,清楚地记录了每一笔“谁在什么时间向谁转了多少钱”。


第三棵树:收据树 - 交易结果的“回执单”

【示意图】

           ----------------------- 
          |     收据树根哈希      |
           ----------------------- 
                 /     |     \     \
                /      |      \     \
               /       |       \     \
       --------   --------   --------   -------- 
      | 收据0  | | 收据1  | | 收据2  | | ...   |
       --------   --------   --------   -------- 
      | 状态...| | 状态...| | 状态...| | ...   |
      | 消耗Gas| | 消耗Gas| | 消耗Gas| | ...   |
      | 日志...| | 日志...| | 日志...| | ...   |
       --------   --------   --------   -------- 

核心作用: 收据树,全称“收据列表树”(Receipts Tree),记录了区块内每笔交易执行后的结果,它不关心交易本身的内容,只关心交易“办完事之后”的回执。

  • 每个收据对应一笔交易,包含以下关键信息:
    • status:交易执行状态(成功/失败)。
    • cumulativeGasUsed:到该笔交易为止,区块内已消耗的总Gas量。
    • logsBloom:一个布隆过滤器,用于快速判断交易是否产生了特定主题的日志。
    • logs:交易产生的日志数组,这是智能合约与外部世界交互的重要方式,用于事件通知。

工作原理: 收据树同样是一个Merkle Patricia Trie,当一个区块被成功打包后,系统会根据区块内每笔交易的执行结果生成一个收据,然后用这些收据构建收据树。

简单比喻: 收据树就像你去邮局寄一个包裹,交易树记录了你“寄出了包裹”这个动作,而收据树则记录了邮局给你的“回执单”,告诉你包裹是否被成功签收、签收人是谁、有没有留下签收记录等。


三棵树的协同工作

这三棵树并非孤立存在,它们在一个区块的生命周期中紧密协作:

  1. 打包阶段: 矿工收集待处理的交易,准备打包成一个新的区块。
  2. 执行阶段: 矿工按顺序执行这些交易,并在这个过程中更新状态树(改变账户余额)。
  3. 记录阶段: 每笔交易执行完毕后,会生成一个收据,记录其结果。
  4. 构建阶段: 所有原始交易被放入交易树,所有生成的收据被放入收据树
  5. 最终确认: 计算出状态树、交易树、收据树的三个根哈希,连同其他信息(如前一区块的哈希、时间戳、难度等)一起,计算出当前区块头的最终哈希,一个新的区块就此诞生。