IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> 以太坊源码阅读3——MPT原理 -> 正文阅读

[数据结构与算法]以太坊源码阅读3——MPT原理

以太坊源码阅读3——MPT原理

介绍

  • MPT(Merkel-Patricia Tree),翻译为梅克尔-帕特里夏树
  • MPT提供了一个基于密码学验证的底层数据结构,用来存储键值对( key-value)关系
  • MPT是完全确定性的,这是指在一颗MPT上一-组键值对
    是唯一确定的,相同内容的键可以保证找到同样的值,并
    且有同样的根哈希( root hash)
  • MPT的插入、查找、删除操作的事件复杂度都是0(log(n)),
    相对于其它基于复杂比较的树结构(比如红黑树),MPT
    更容易理解,也更易于编码实现

字典树(Trie)

image-20220314154231567

  • 字典树(Trie) 也称前缀树( prefix tree),属于搜索树,是一种有序的树数据结构
  • 字典树用于存储动态的集合或映射,其中的键通常是字符串

字典树在非根节点存储数据,在叶子节点存储最终的value,CRUD的时候只需要依据数据的每个字符遍历节点向下查询,缺点就是存储空间消耗大

基数树(Radix Tree)

为了解决字典树存储空间消耗大的问题而产生

基数树又叫压缩前缀树( compact prefix tree)是一种空间优化后的字典树,其中如果一个节点只有唯一的子节点,那么这个子节点就会与父节点合并存储

image-20220314154844151

简单的说就是,如果有多个字符分支,那就分叉,否则就压缩合并

基数树的问题:

  • 数据校验: 基数树节点之间的连接方式是指针,一般是用32位或64位的内存地址作为指针的值,比如C语言就是这么做的。但这种直接存
    地址的方式无法提供对数据内容的校验,而这在区块链这样的
    分布式系统中非常重要。

  • 访问效率:基数树的另一个问题是低效。如果我们只想存-一个bytes32类型的键值对,访问路径长度就是64(在以太坊定义的Hex字符集下) ;每一级访问的节点都至少需要存储16个字节,这样就需要至少1k字节的额外空间,而且每次查找和删除都必须完整地执行64次下探访问。

梅克尔树(Merkel Tree)

解决数据校验问题

也被称作哈希树(Hash Tree),以数据块的hash值作为叶子节点存储值。梅克尔树的非叶子节点存储其子节点内容串联拼接后的hash.值。

image-20220314164241574

在梅克尔树中,使用rlp(value)再做hash,hash会作为地址(key)

帕特里夏树(Patricia Tree)

解决访问效率问题

  • 如果一个基数树的“基数”(radix) 为2或2的整数次幂,就被称为“帕特里夏树”,有时也直接认为帕特里夏树就是基数树
  • 以太坊中采用Hex字符作为key的字符集,也就是基数为16的帕特里夏树
  • 以太坊中的树结构,每个节点可以有最多16个子节点,再加上value,所以共有17个“插槽”(slot) 位置
  • 以太坊中的帕特里夏树加入了一些额外的数据结构,主要是为了解决效率问题

MPT (Merkel Patricia Tree)

详情

  • 梅克尔-帕特里夏树是梅克尔树和帕特里夏树的结合
  • 以太坊中的实现,对key采用Hex编码,每个Hex字符就是一.
    个nibble (半字节)
  • 遍历路径时对-一个节点只访问它的一一个nibble,大多数节点是.一个包含17个元素的数组:其中16个分别以hex字符作为索引值,存储路径中下一个nibble的指针;另–个存储如果路径到此已遍历结束,需要返回的最终值。这样的节点叫做“分支节点”( branch node)
  • 分支节点的每个元素存储的是指向下一-级节点的指针。与传统做法不同,MPT是用所指向节点的hash来代表这个指针的;每个节点将下个节点的hash作为自己存储内容的一部分,这样就实现了Merkel树结构,保证了数据校验的有效性

节点分类

  • 空节点(NULL)
    • 表示空字符串
  • 分支节点(branch )
    • 17个元素的节点,结构为[v0… v15, vt]
  • 叶子节点(leaf)
    • 拥有两个元素,编码路径encodedPath和值value
  • 扩展节点( extension)
    • 拥有两个元素,编码路径encodedPath和键key
    • 用于压缩前缀,encodedPath存储压缩后的数据,key用于指向下一个节点

MPT中数据结构的优化

  • 对于64个字符的路径长度,很有可能在某个节点处会发现,下面至少有一段路径没有分叉;这很难避免
  • 我们当然可以依然用标准的分支节点来表示,强制要求这个节点必须有完整的16个索引,并给没有用到的那15个位置全部赋空值;但这样有点蠢.
  • 通过设置“扩展节点”,就可以有效地缩短访问路径,将冗长的层级关系压缩成一个键值对,避免不必要的空间浪费
  • 扩展节点(extension node)的内容形式是[encodedPath, key],其中encodedPath包含了下面不分叉的那部分路径,key 是指向下一个节点的指针(hash,也即在底层db中的存储位置)
  • 叶子节点(leafnode) :如果在某节点后就没有了分叉路径,那这是一个叶子节点,它的第二个元素就是自己的value

image-20220314170158090

紧凑编码(compact coding)

16进制前缀编码

它能够存储一个额外的标志,当在trie的上下文(使用它的唯一上下文)中使用时,可以消除节点类型之间的歧义。

详情

  • 路径压缩的处理相当于实现了压缩前缀树的功能;不过路径表示是Hex字符串( nibbles),而存储却是以字节(byte)为单位的,这相当浪费了一倍的存储空间
  • 我们可以采用一种紧凑编码(compact coding)方式,将两个nibble整合在个字节中保存,这就避免了不必要的浪费
  • 这里就会带来一个问题:有可能nibble总数是一个奇数,而数据总是以字节形式存储的,所以无法区分nibble1和nibbles01;这就使我们必须分别处理奇偶两种情况
  • 为了区分路径长度的奇偶性,我们在encodedPath中引入标识位

Hex序列的压缩编码规则

image-20220314113005312

  • 我们在encodedPath中,加入一个nibble作为前缀,它的后两
    位用来标识节点类型和路径长度的奇偶性

image-20220314170617720

  • MPT中还有一一个可选的“结束标记”(用T表示) ,值为0x10(十进制的16),它仅能在路径末尾出现,代表节点是一一个最终节点(叶子节点)
  • 如果路径是奇数,就与前缀nibble凑成整字节;如果是偶数,则前缀nibble后补0000构成整字节

编码示例:

原始数据条件(路径长度)节点类型HP前缀HP编码结果
0x12345奇数个 nibbleextension(扩展)0x1 (0001)0x112345
0xf1cb8奇数个 nibbleleaf(叶子)0x3 (0011)0x3f1cb8
0x012345偶数个 nibbleextension0x00 (0000 0000)0x00012345
0x0f1cb8偶数个 nibbleleaf0x20 (0010 0000)0x200f1cb8

MPT树结构示例

image-20220314181330072

以查询45.0ETH为例,右上角指明keys为 a711355 ,root 的nibbles为a7,下一个key为1,则root的next node 指向branch node的branch node[1],keys a711355 已经查询完a71 ,左节点的key-end正好为剩下的1355,则该节点的value即为45.2ETH。由于抵达该路径的距离为2,且是叶子节点,根据上面的Hex序列的压缩编码规则,可得前缀为2。

以太坊中树结构

以太坊中所有的merkel树都是MPT
在一个区块的头部(block head)中,有三颗MPT的树根:

  • stateRoot
    • 状态树的树根
  • transactionRoot
    • 交易树的树根
  • receiptsRoot
    • 收据树的树根

image-20220314185915181

  • 状态树(state trie)

    • 世界状态树,随时更新;它存储的键值对(path, value)可以表示为(sha3(ethereumAddress), rlp(ethereumAccount))

    • 这里的account是4个元素构成的数组: [nonce,balance,storageRoot,codeHash]

  • 存储树(storage trie )

    • 存储树是保存所有合约数据的地方:每个合约账户都有一个独立隔离的存储空间
  • 交易树(transaction trie )

    • 每个区块都会有单独的交易树;它的路径(path)是rlp(transactionIndex),只有在挖矿时才能确定:一旦出块, 不再更改
  • 收据树(receipts trie)

    • 每个区块也有自己的收据树:路径也表示为rlp(transactionlndex)

image-20220314191120300

参考

尚硅谷区块链全套教程完整版(深入掌握以太坊核心技术)_哔哩哔哩_bilibili

  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2022-03-15 22:50:27  更:2022-03-15 22:55:22 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2025年1日历 -2025/1/9 16:52:01-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码