@

MPT树定义

一种经过改良的、融合了默克尔树和前缀树两种树结构优点的数据结构,以太坊中,MPT是一个非常重要的数据结构,在以太坊中,帐户的交易信息、状态以及相应的状态变更,还有相关的交易信息等都使用MPT来进行管理,其是整个数据存储的重要一环。交易树,收据树,状态树都是采用的MPT结构。

ps:

  1. 交易树:记录交易的状态和变化。每个块都有各自的交易树,且不可更改 
  2. 收据树(交易收据):交易收据的存储
  3. 状态树(账户信息):帐户中各种状态的保存。如余额等。
  4. Storage Trie 存储树 :存储只能合约状态 ,每个账号有自己的Storage Trie 。

回想我们我们上一次所讲的RLP:
在网络节点的本地以trie树的形式存储,发送给客户端的时候序列化成列表。这不就是RLP的作用嘛,用来对trie树种所有的条目进行编码
这个树,在以太坊,指的就MPT树

MPT树的作用是什么?

  1. 存储任意长度的key-value键值对数据;
  2. 提供了一种快速计算所维护数据集哈希标识的机制;
  3. 提供了快速状态回滚的机制;
  4. 提供了一种称为默克尔证明的证明方法,进行轻节点的扩展,实现简单支付验证;

前缀树与默克尔树

前缀树

前缀树(又称字典树),用于保存关联数组,其键(key)的内容通常为字符串。前缀树节点在树中的位置是由其键的内容所决定的,即前缀树的key值被编码在根节点到该节点的路径中。


如下图所示,图中共有6个叶子节点,其key的值分别为(1)to(2)tea(3)ted(4)ten(5)A(6)inn。

默克尔树

merkle树是自底向上构建的。在下图的例子中,首先将L1-L4四个单元数据哈希化,然后将哈希值存储至相应的叶子节点。

将相邻两个节点的哈希值合并成一个字符串,然后计算这个字符串的哈希,得到的就是这两个节点的父节点的哈希值。

重要结论:
若两棵树的根哈希一致,则这两棵树的结构、节点的内容必然相同。

分析:

在p2p网络下载网络之前,先从可信的源获得文件的Merkle Tree树根。一旦获得了树根,就可以从其他从不可信的源获取Merkle tree。通过可信的树根来检查接受到的MerkleTree。如果Merkle Tree是损坏的或者虚假的,就从其他源获得另一个Merkle Tree,直到获得一个与可信树根匹配的MerkleTree。

三种节点类型

知道了Merkle Tree,知道了Patricia Tree,MPT(Merkle Patricia Tree)就是这两者混合后的产物。下面我们介绍一下MPT树的三种节点类型

  • 分支结点(branch node):包含16个分支,以及1个value
  • 扩展结点(extension node):只有1个子结点
  • 叶子结点(leaf node):没有子结点,包含一个value

    需要注意的是:Key-value 这里的value存储的是key,key存储在路径上
    详细解释:

    叶子节点,表示为[key,value]的一个键值对,其中key是key的一种特殊十六进制编码。
    扩展节点,也是[key,value]的一个键值对,但是这里的value是其他节点的hash值,这个hash可以被用来查询数据库中的节点。也就是说通过hash链接到其他节点。
    分支节点,因为MPT树中的key被编码成一种特殊的16进制的表示,再加上最后的value,所以分支节点是一个长度为17的list,前16个元素对应着key中的16个可能的十六进制字符,如果有一个[key,value]对在这个分支节点终止,最后一个元素代表一个值,即分支节点既可以搜索路径的终止也可以是路径的中间节点。
    叶子节点和扩展节点是新增加的!(对比于前缀树来说)

MPT中的Merkle

即指向下一级节点的指针是使用 节点的确定性加密hash,而不是传统意义上下一级节点地址的指针

如果给定的trie的根哈希是公开的,则任何人都可以 通过给出给定path上的所有节点, 来证明在给定path上存在一个给定值 ,对于攻击者,不可能提供一个不存在的(key,value)对的证明, 因为根哈希最终基于它下面的所有哈希,所以任何修改都会改变根哈希。

HP编码

HP-编码:特殊的十六进制前缀编码

引入:对nibble和节点奇偶性进行编码

Nibble是什么?
引进一种特殊的终止符标识来标识key所对应的是值是真实的值,还是其他节点的hash。如果终止符标记被打开,那么key对应的是叶节点,对应的值是真实的value。如果终止符标记被关闭,那么值就是用于在数据块中查询对应的节点的hash。
为什么需要对节点奇偶性进行编码?
数据最小的表示单位为一位16进制,如1、a等,但在编程实现中,数据的最小表示单位往往是byte(8bit,2位16进制数),这样在用byte来表示一串奇数长度的16进制串时会出现问题。
例如"5b3"和"5b30",直接转成byte都是5b30。

举例:
对"0x5b3ed"编码(奇数位)
"0x5b3ed" = "0005 1011 0003 1110 1101"t=0 时, "0001"+"0005 1011 0003 1110 1101"->"00010005 10110003 11101101"->"0x15b3ed"
t !=0时 "0011"+"0005 1011 0003 1110 1101"->"00110005 10110003 11101101"->"0x35b3ed“

对"0x5b3e"编码(偶数位)
"0x5b3e" = "0005 1011 0003 1110"t=0 时, "0000"+"0005 1011 0003 1110 1101"->"00000005 10110003 11101101"->"0x005b3e"
t !=0时 "0010"+"0005 1011 0003 1110 1101"->"00100005 10110003 11101101"->"0x205b3e"

这里的t就是是否结束的标志位
最低位表示奇偶性,第二低位编码终止符状态。
最低位为0的时候表示偶数位置,反之奇数。
第二低位为1的时候表示结束,反之不结束。

官方表示形式

这里的prefix就是HP编码!对终止符的状态和奇偶性进行编码。最低位表示奇偶性,第二低位编码终止符状态。
总共有2个扩展节点,2个分支节点,4个叶子节点。 右边是叶子节点的情况,左边代表的是节点的prefix(HP编码)
这就是一个状态树的存储形式,其实他应当长的样子,我们可以细细想一下,他的key被编码成一种特殊的16进制的表示,value是一些rlp后的数据,而且比上图要大的多的多。

相关MPT树

现在,我们来回看一下,状态、存储以及交易树使用的MPT树。
首先说,全局状态树,这个全局状态树包含了以太坊网络中每一个账户的一组键值对。
对全局状态树的几点说明:

  1. 状态前缀树包含了以太坊网络中每一个账户的一组键值对。
  2. 他的Key是一个 160 位的标识符(以太坊账户的地址)。
  3. 全局状态树中的 “值” 是通过编码以太坊账户中的如下细节来得到的(使用RLP的方法):
  • nonce 值
  • 余额
  • 存储前缀树根节点哈希
  • 代码哈希
    我们可以从下图很清晰的了解:

存储树是智能合约数据存储的位置,每一个以太坊账户都有自己的存储树。
本图接上图;

参考目录

[1]. 深入浅出以太坊MPT(Merkle Patricia Tree)
[2]. 以太坊学习(2)MPT树--白话版
[3]. Merkle Patricia Tree 梅克尔帕特里夏树(MPT)规范
[4]. merkle树、Trie树、MPT树、以太坊中的那些树

MPT树详解的更多相关文章

  1. Merkle Patricia Tree (MPT) 树详解

    1.    介绍 Merkle Patricia Tree(简称MPT树,实际上是一种trie前缀树)是以太坊中的一种加密认证的数据结构,可以用来存储所有的(key,value)对.以太坊区块的头部包 ...

  2. 数据结构图文解析之:AVL树详解及C++模板实现

    0. 数据结构图文解析系列 数据结构系列文章 数据结构图文解析之:数组.单链表.双链表介绍及C++模板实现 数据结构图文解析之:栈的简介及C++模板实现 数据结构图文解析之:队列详解与C++模板实现 ...

  3. trie字典树详解及应用

    原文链接    http://www.cnblogs.com/freewater/archive/2012/09/11/2680480.html Trie树详解及其应用   一.知识简介        ...

  4. Linux DTS(Device Tree Source)设备树详解之二(dts匹配及发挥作用的流程篇)【转】

    转自:https://blog.csdn.net/radianceblau/article/details/74722395 版权声明:本文为博主原创文章,未经博主允许不得转载.如本文对您有帮助,欢迎 ...

  5. JavaScript---Dom树详解,节点查找方式(直接(id,class,tag),间接(父子,兄弟)),节点操作(增删改查,赋值节点,替换节点,),节点属性操作(增删改查),节点文本的操作(增删改查),事件

    JavaScript---Dom树详解,节点查找方式(直接(id,class,tag),间接(父子,兄弟)),节点操作(增删改查,赋值节点,替换节点,),节点属性操作(增删改查),节点文本的操作(增删 ...

  6. 线段树详解 (原理,实现与应用)(转载自:http://blog.csdn.net/zearot/article/details/48299459)

    原文地址:http://blog.csdn.net/zearot/article/details/48299459(如有侵权,请联系博主,立即删除.) 线段树详解    By 岩之痕 目录: 一:综述 ...

  7. Linux dts 设备树详解(二) 动手编写设备树dts

    Linux dts 设备树详解(一) 基础知识 Linux dts 设备树详解(二) 动手编写设备树dts 文章目录 前言 硬件结构 设备树dts文件 前言 在简单了解概念之后,我们可以开始尝试写一个 ...

  8. Linux dts 设备树详解(一) 基础知识

    Linux dts 设备树详解(一) 基础知识 Linux dts 设备树详解(二) 动手编写设备树dts 文章目录 1 前言 2 概念 2.1 什么是设备树 dts(device tree)? 2. ...

  9. AVL树详解

    AVL树 参考了:http://www.cppblog.com/cxiaojia/archive/2012/08/20/187776.html 修改了其中的错误,代码实现并亲自验证过. 平衡二叉树(B ...

随机推荐

  1. 使用HtmlAgilityPack抓取Ethereum Tokens信息

    使用HtmlAgilityPack抓取Ethereum Tokens信息 class Program { static void Main(string[] args) { try { for (in ...

  2. jquery完成界面无刷新加载登陆注册

    昨天公司说官网的登陆注册每次要跳转到另一个界面,能不能做一个简单的,在界面弹出一个框框登陆,我想了想做了这么一个案例,大家来看看成不成 贴上代码,实现了在同一个弹出窗上加载了登陆注册功能!可自由点击! ...

  3. SQL Server ——用 join on 连接多个表

    select * from table1 inner join table2 on table1.id=table2.id 其实 INNER JOIN ……ON的语法格式可以概括为: FROM ((( ...

  4. VMware12创建新的虚拟机及设置硬件环境

    一.安装VMware虚拟机 http://jingyan.baidu.com/article/215817f78879c21edb142379.html?qq-pf-to=pcqq.group 二.创 ...

  5. 在微信小程序中引入 Iconfont 阿里巴巴图标库

    小程序的代码包不能超过4M,为了压缩代码包的大小,可以通过第三方链接引入图标资源 Iconfont 无疑是最常用的第三方图标库,这里介绍一下在微信小程序引入 Iconfont 的方法 一.下载图标 首 ...

  6. 为JavaScript正名--读你不知道的JavaScript(持续更新..)

    你不知道的JavaScript上卷 JavaScript和Java的关系就像Carnival和Car的关系一样,八竿子打不着. JavaScript易上手,但由于其本身的特殊性,相比其他语言能真正掌握 ...

  7. Python3.6下的Requests登录及利用Cookies登录

    利用Python中的Requests模块可以实现Post,Get等发送功能,我以登录某网站为例,记录使用Post发送用户名.密码及图形验证码,以及通过Cookies直接登录的内容. 1.利用POST发 ...

  8. mysql数据库操作指令

    数据库相关 查询所有数据库 show databases; 创建数据库 create database 数据库名: 创建数据库指定字符集 create database 数据库名 character ...

  9. webpack中mainifest.js vendor.js app.js 三者的区别

    场景: 大家在利用构建工具进行应用最后的打包过程中,我们希望做到的是将业务代码和第三方引用模块代码分开打包. 因为第三方引用模块代码通常很大,而且在不引入新的模块之前基本上是不会变动的.所以我们需要将 ...

  10. php递归获取无限分类菜单

    从数据库获取所有菜单信息,需要根据id,pid字段获取主菜单及其子菜单,以及子菜单下的子菜单,可以通过函数递归来实现. <?php class Menu { public $menu = arr ...