终探 MPT 树

本文详细介绍了Merkle帕特里夏字典树(MPT)在以太坊中的应用,包括账户数据、智能合约数据和交易/收据树的存储结构。文章讨论了基数树的问题,如效率低下,以及MPT如何通过NULL、BranchNode、LeafNode和ExtensionNode进行优化,以提高存储和查询效率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

简介

鉴于 理解MPT 对于进一步了解 ETH运行原理 的重要性,我们今天再重头完整的梳理一遍MPT(默克尔帕特里夏字典树)树

预备知识

将单个数字或者字母转换成16进制的ASCII

基数树

Patricia原理及应用

  • 基数树其实和 字典树在原理和实现上都很相似,都存储 Key-Value形式的数据,路径中保存的是 KeyValue保存在节点中
  • 不同的是,基数树一般会把 Key都转成 数字

举例:

  1. 我们要存储 dog -> 100, dogKey, 100Value
  2. dog -> 转成16进制表示是 64 6f 67(16进制,每两位占用一个字节)
  3. dog在基数树的路径就是 root -> 6 -> 4 -> 6 -> 15 -> 6 -> 7(15是f的十进制表示)

我们上面的例子中使用的是 1步查找,其中每一步都只检查了数据结构中的 一个元素,以确定所需元素的位置或存在情况

MPT(默克尔帕特里夏树)

半字节

我们把基数树的 原子单位称为 半字节(单个16进制字符 或 4位二进制数)。如上文所述,以 半字节为单位遍历路径时,节点最多可指向 16 个子节点,不过还包含一个 value 元素。 因此,我们把它们表示为具有长度 17个元素的数组

哪些数据使用MPT存储
  1. 以太坊账户数据(World State):path是 keccak256(ethereumAddress), value是 rlp(ethereumAccount)
  • 这里的 path就是上面说的 key,为了区分,我们后面说按 path查找,都是基于MPT查找
  • 一个以太坊账户 是包含 4 个元素的数组:[nonce,balance,storageRoot,codeHash]。关于这一点值得注意的是,storageRoot 是另一个帕特里夏字典树的根
  1. 智能合约数据存储

上面以太坊账户中的 storageRoot就是智能合约数据的根Hash。path是如何计算的,我们之后会用几篇的文章去讲解

  1. 交易树(每个区块都会有)

每个区块都有一个独立的交易字典树,也用于存储 (key, value) 对。 path = rlp(transactionIndex),代表了对应一个值的键,value = TxType | encode(tx)

  1. 收据树(每个区块都会有)

path = rlp(transactionIndex)

  • transactionIndex 是它在挖矿区块中的索引。收据字典树从不更新。 与交易字典树类似,它也有当前和以前的收据。为了在收据字典树中查询特定的收据,需要提供区块中交易的索引、收据有效载荷以及交易类型
  • 返回的收据(就是 value)可以是 Receipt 类型,定义为 TransactionTypeReceiptPayload 的串联;也可以是 LegacyReceipt 类型,定义为 rlp([status, cumulativeGasUsed, logsBloom, logs])
基数树存在的问题

效率低下

通过上面的存储数据可以看到,path的长度一般都等于或者超过 64个半字节keccak256算法生成的是 256位的哈希值)

  • 如果使用基数树每个节点都需要 存储指向下一个节点的指针,占用更多的存储空间
  • 查询,删除时需要执行完整的 64层
MPT做了哪些优化
  1. NULL: 表示空字符串
  2. Branch Node: 一个包含17个元素的节点(能完整表示所有半字节,并且有一个 Value元素),表示为 [ v0 ... v15, vt ]
  3. Leaf Node: 一个双元素节点 [ encodedPath, value ]
  4. Extension Node: 一个双元素节点 [ encodedPath, key ]
  • 64 个半字节path中,遍历前缀树的 前几层后,一定会到达这样的节点:至少部分下游再无分支路径。为了 避免在路径中创建多达 15 个稀疏 NULL 节点,我们通过设置一个形式为 [ encodedPath, key ]extension 节点来精简 向下遍历,其中 encodedPath 包含要跳过的 部分路径key 用于下一次数据库查询
  • 对于 Leaf 节点,encodedPath编码了 path剩余的片段,我们可以直接查询 value

由于 ExtensionLeaf都是用 encodedPath,所有需要制定规则进行区分:

二进制表示node类型path长度奇偶性16进制表示待编码path编码后path
🦀0000Extension偶数0[ 0, 1, 2, 3, 4, 5, …]‘00 01 23 45’
🦞0001Extension奇数1[ 1, 2, 3, 4, 5, …]‘11 23 45’
🦐0010Leaf偶数2[ 0, f, 1, c, b, 8, 10]‘20 0f 1c b8’
🦑0011Leaf奇数3[ f, 1, c, b, 8, 10]‘3f 1c b8’

可以观察到,当 path长度是奇数时,会将 16进制表示的类型待编码path的第一个半字节结合,大家可以思考下为什么这样做,温馨提示:path时基于半字节的

举例说明

pathvalue如下:

    <64 6f> : 'verb'
    <64 6f 67> : 'puppy'
    <64 6f 67 65> : 'coin'
    <68 6f 72 73 65> : 'stallion'

例子

关注我,一起进入Web3的世界

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值