MPT tree

MPT(Merkle Patricia Tries) 树是一种融合Merkle树和前缀树的数据结构。以太坊的世界状态树、交易树、收据树就是以MPT树的结构存在。主要以下功能:

存储key-value键值对;

根据节点key,可以快速查找到节点;

提供快速回滚机制;

提供Merkle证明方法,实现轻节点SPV验证。

1.前缀树

前缀树,又称为字典树,节点在树中的位置为 key 决定,即 key 编码根节点到该节点的路径.前缀树对查询操作比较高效,但对于较⻓的key, 容易造成空间浪费。

图1 前缀树示例

2.Merkle树


Merkle树通常是一种二叉树, 能够允许在公链环境下实现轻点节验证.

图2 Merkle树示例

3.MPT树

图3:MPT树示例

从图中可以看出, MPT树中主要有3种类型的节点:

叶子节点,为 [key, value] 的键值对, key 为16进制编码的字符串, 每个字符范围为0~16, value 为叶子节点的值;
扩展节点,为 [key, value] 的键值对, value 为其它节点的hash值,链接到其到节点;

分支节点,为⻓度为17的list, 前16个元素对应着key中16个可能的路径的中间节点, 分支节点的父节点为扩 展节点;

注:

1.扩展节点的value以及分支节点的个分支位置中存放的都是下一个节点的哈希(也是下一个节点在数据库中存储的key),具体如下:

value = hash(RLP(HP(key_child), value_child))

2.编码

在以太坊中,MPT树的key值共有三种不同的编码方式,以满足不同场景的不同需求。

三种编码方式分别为:

  • 1.Raw编码(原生的字符):

Raw编码就是原生的key值,不做任何改变。这种编码方式的key,是MPT对外提供接口的默认编码方式

例如一条key为“cat”,value为“dog”的数据项,其key的Raw编码就是[‘c’, ‘a’, ‘t’]

  • 2.Hex编码(扩展16进制编码)

Hex编码就是把一个8位的字节数据用两个十六进制数展示出来,编码时,将8位二进制码重新分组成两个4位的字节,其中一个字节的低4位是原字节的高四位,另一个字节的低4位是原数据的低4位,高4位都补0,然后输出这两个字节对应十六进制数字作为编码。Hex编码后的长度是源数据的2倍。

如:字符a(ASCII编码为65),进行hex编码后得到(4,1)(65=16*4 + 1)

  • 3.Hex-Prefix编码(16进制前缀编码)

编码目的有以下两点:

3.1) 区分leaf和extension

3.2)把奇数路径变成偶数路径,同时标记真实key的奇偶

编码原则是:1.如果key长度为奇数,则在key前面增加半个字节,若为偶数则增加1个字节;

2.若key长度为奇数,则在增加的最高半字节的最低位置1,否则置0,

若节点为叶子节点,则在增加的最高半字节的次低位置1,否则置0

3.1 MPT树构建示例

我们以世界状态树为例进行展示,世界状态树的中:

key: 账户地址的哈希;

value: ( Nonce, Balance, StorageHash,CodeHash)的RLP编码

其中:StorageHash 是合约的存储数据的merkle root.对于账户来说StorageHash 是固定值0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421(=hash(RLP(Bytes.EMPTY))), 即空树的root

CodeHash 是合约代码的哈希,对于账户来说,是固定值0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470

=hash(Bytes.EMPTY)),即空字符串的哈希。

3.1.1创建树

以包含2个节点的世界状态树为例,我们在本章演示世界状态树的构建过程和证明过程

账户1:(24264ae01b1abbc9a91e18926818ad5cbf39017b, {Nonce: 1, Balance: 1ETH})

账户2:(3a844bb6252b584f76febb40c941ec898df9bc23, {Nonce: 3, Balance: 2ETH})

对账户进行hash后,两个账户在世界状态树中的key如下:

账户1:1ee3017a85544556ea847c203623a9c84efdb77fa4951a5b01296d9aacefc5f7

账户2:1eeced8d7a011c27d9aed60517c8e596509852f1d208a8a6d6f16d17ea5da204

下面我们将展示先将账户1插入到树中,然后再将账户2插入到树中的过程:

1.首先创建一个空树,此时,树的root是固定值(root值存放位置可由开发人员自行定义)0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421

2.插入账户1 (key=1ee3017a85544556ea847c203623a9c84efdb77fa4951a5b01296d9aacefc5f7):

1)从数据库中拿到树的Root

2) 对比root发现本树为空,则新建账户1的节点node1,

key = 1ee3017a85544556ea847c203623a9c84efdb77fa4951a5b01296d9aacefc5f7,

value = RLP(1,1ETH,Empty StorageHash,Empty CodeHash),

3)计算node1的哈希得到hash0,将节点存入数据库key为hash0的位置

4)更新树的root为hash0

结果如下:

3.插入账户2 (key=1eeced8d7a011c27d9aed60517c8e596509852f1d208a8a6d6f16d17ea5da204)

1)从数据库中拿到树的Root

2)根据root拿到第一个节点(即上图的node1), 发现该节点的key和我们欲插入的节点的key拥有共同前缀1ee,则:

2.1)新增key为1ee的前缀节点node4;

2.2) 新增node4的子节点,即分支节点node3;

2.2) 原节点node1变为分支节点node3的分支3的子节点,并且key更新为017a85544556ea847c203623a9c84efdb77fa4951a5b01296d9aacefc5f7,value不变。我们称之为node1‘;

2.2)新建账户2的节点node2,作为分支节点node3的分支c的子节点

key = ed8d7a011c27d9aed60517c8e596509852f1d208a8a6d6f16d17ea5da204,

value = RLP(3,2ETH,Empty StorageHash,Empty CodeHash)

3)

计算node1的哈希得到hash1,将node1存入数据库key为hash1的位置,并将hash1放在node3的分支3的位置,

计算node2的哈希得到hash2,将node2存入数据库key为hash2的位置,并将hash2放在node3的分支c的位置,

计算node3的哈希得到hash3,将node3存入数据库key为hash3的位置,并将hash3放在node4的value位置,

计算node4的哈希得到hash4,将扩展节点存入数据库key为hash4的位置;

4)更新树的root为hash4

3.1.2 验证节点

由于轻节点并不保存树的结构,所以如果轻节点想要验证一个账户的balance,需要从全节点请求该账户节点的全路径,并从链上获取状态树的根哈希并进行验证。

假如轻节点要验证账户1的balance,那么需要从全节点的数据库中获得key为hash4, hash3,hash1对应的3个节点node4、node3、node1‘。轻节点分别计算这3个节点的哈希,并存入DB。然后借助于获得的可靠stateRoot和账户1的key,从自己的数据库中查找,如果确实找到了账户1对应的节点,且节点的value确实记录了账户的balance为1,那么就完成了账户余额的证明。

3.1.3 作恶全节点

如果全节点作恶,把账户的balance改成了1000,也就是全节点发过来的路径中的叶子节点的value设成了1000,则会验证失败。原因在于node1'的value变了,则该节点的hash变为hash1‘ != hash1,从而node3的位置3的值也由hash1变为了hash1', 从而node3的hash变成了hash3'!=hash3,进而node4的hash值也变为了hash4' != hash4. 那轻节点根据stateRoot找不到扩展节点node4,进而找不到账户1的叶子节点,证明失败。

状态快速回滚

MPT树就提供了一种机制,可以零延迟地完成世界状态的回滚。这种优势的代价就是需要浪费存储空间去冗余地存 储每个节点的历史状态。

在以太坊中,发生分叉而进行世界状态回滚时,仅需要用旧的MPT根节点作为入口,即可完成“状态回滚”

参考文档:

https://medium.com/@chiqing/verify-ethereum-account-balance-with-state-proof-83b51ceb15cf

以太坊 Merkle Patricia Tree 全解析 - 知乎

详解以太坊默克尔压缩前缀树-MPT :: 以太坊技术与实现

  • 26
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值