ETH 之 MPT

在ETH的存储结构中,使用了MerklePatriciaTrie(MPT),这种结构为何具有“可验证性”和“前缀压缩”特性?今天就来较详细的了解下。MerklePatriciaTrie=PatriciaTrie+MerkleTree的结合体。以太坊用来存储账户状态、存储数据

在ETH的存储结构中,使用了 Merkle Patricia Trie(MPT),这种结构为何具有“可验证性”和“前缀压缩”特性?今天就来较详细的了解下。

Merkle Patricia Trie = Patricia Trie + Merkle Tree 的结合体。以太坊用来存储账户状态、存储数据和交易数据的核心数据结构。

重温知识

在开始前,先来重温下Merkle Tree 和 Patricia Trie

Step 1:什么是 Trie(前缀树)?

Trie(发音类似“try”)其实就是一种为了节省空间的数据结构,用来存储多个有共同前缀的 key

📦 举个例子

假如有三个键:

  • apple
  • app
  • appricot

Trie 会这样存储它们👇:

        (a)
         |
         p
         |
         p
       /   \
      l     r
      |     |
      e     i
            |
            c
            |
            o
            |
            t

你会发现:

  • app 是所有键的公共前缀 → 只存一遍!
  • 每条路径就表示一个 key。

节省空间,又便于查找

Step 2:什么是 Merkle Tree(默克尔树)?

Merkle Tree 是一种“能验证数据没被篡改”的树结构。

📦 举个例子

假设有 4 个交易:

tx1, tx2, tx3, tx4

Merkle Tree 计算方式:

  1. 把每个 tx 哈希:h1 = hash(tx1) ……
  2. 相邻合并再哈希:h12 = hash(h1 + h2) ……
  3. 一直到最顶端生成根哈希(Merkle Root)。
        root
         /    \
     h12    h34
      /  \      /  \
  h1  h2  h3  h4

要验证tx1是否改动过,只要给 tx1、h2、h34,就能“复原路径”,算出 root,从而得到验证。

→ 就像“发票 + 验证公式”,可验证、难伪造

为何具有「可验证性」?

🔍 原理:哈希可验证路径 + Merkle 证明

MPT 使用了 哈希链结构,可以生成从根节点(Root)到任意叶子节点(Leaf)的路径,每个节点都是通过 哈希加密后的内容指针(Hash pointer) 引用子节点。

  • 每个节点的哈希值由其子节点内容计算而来;

  • 根节点的哈希就是整个状态的唯一表示 —— 即区块头中的 stateRoot

  • 给定某个 key,要证明其值是某个值,只需要:

    • 一条从根到叶的路径(包含分支节点和叶节点);
    • 对这些节点的哈希重新计算 → 对比根哈希是否一致。

结果:

  • 无需访问整个链的数据库,只要有一条路径 + 根哈希,轻节点也能验证数据的合法性;
  • Merkle Proof 可用于轻客户端、ZK Rollup 等场景中

🧵 三、为何具有「前缀压缩」?

🌲 原理:Patricia Trie(压缩前缀树)

普通的 Trie(字典树)为每个字符创建一个节点,比如:

插入 key1: "dog"
插入 key2: "dove"
普通 Trie: d → o → g 和 d → o → v → e 分支

Patricia Trie 采用了路径压缩,合并了唯一路径上的所有节点成一条路径:

        (d)
         |
         o
       /   \
     g    v
            |
            e

在以太坊中:

  • 所有键都转换为十六进制编码,比如地址变为 40 位二进制数;

  • 若多个键有相同前缀,会被压缩成一个 node;

  • 节点分为:

    • 扩展节点(Extension node):只包含中间路径;
    • 分支节点(Branch node):最多有 16 个子项 + 一个 value;
    • 叶子节点(Leaf node):路径 + value。

结果:

  • Trie 更小、存储更高效;
  • 访问路径更短,提升了性能;
  • 对于状态树,可以快速查找、插入、修改账户数据。

结合起来的实际例子

以太坊的状态存储结构包括三个主要 MPT:

Trie 类型 存储内容 根哈希位置
状态树 每个地址的账户信息 stateRoot
存储树 合约存储变量 key→val 合约 storageRoot
交易树 区块内所有交易 transactionsRoot

例如,验证账户地址 0xabc...123 在某个区块中,其余额是 1 ETH,是否真实可信,不是伪造数据

第一步:获取 stateRoot

  • 来自你要验证的那个区块头(如 latest 或某个指定的 block number)。
  • stateRoot 是整棵账户状态树的根哈希。
block = await provider.getBlock(blockNumber);
stateRoot = block.stateRoot;

第二步:获取账户的 Merkle Proof(用 RPC)

eth_getProof(address, [], blockNumber)

这会返回:

  • nonce
  • balance
  • storageHash
  • codeHash
  • accountProof这是验证路径上所有节点的内容

第三步:构造账户状态的 RLP 编码

账户在 MPT 中的值是 RLP 编码的四个字段:

accountRLP = rlp.encode([
  nonce,
  balance,
  storageRoot,
  codeHash
]);

第四步:构造账户的 key(MPT 中的路径)

MPT 中是按地址的 keccak256(address) 存的,所以路径是地址哈希。

accountKey = keccak256(address);

第五步:用 Trie 验证 Proof

使用 Trie.verifyProof 方法来验证:

verifiedValue = Trie.verifyProof(stateRoot, accountKey, accountProof);

这一步会从 stateRoot 开始,走过 accountProof 里包含的每个节点数据,看能否重建出目标账户的值,并最终得到哈希匹配。

第六步:验证是否一致

最后比对 verifiedValue 是否等于之前我们构造的 accountRLP 值。

如果一致,就表示:

✅ 此账户的状态确实存在于该区块的状态树中,数据可信、不可伪造!

轻节点验证数据合法性

什么是轻节点(Light Client)

节点类型 保存区块 保存状态 功能
完整节点 完整同步并验证所有交易
轻节点 只下载区块头,通过 Merkle Proof 验证状态
桥节点 一种混合型,仅用于桥接跨链
点赞 0
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
Henry Wei
Henry Wei
Web3 探索者