Merkle Patricia Tree (MPT) 以太坊中的默克尔树
本篇博文是自己学习mpt的过程,边学边记录,很多原理性内容非自己原创,好的博文将会以链接形式进行共享。
一、什么是mpt
MPT是以太坊中的merkle改进树,基于基数树,即前缀树改进而来,大大提高了查找效率。
二、前缀树
MPT中的P,就是前缀树,也叫trie或字典树。trie每个节点是一个确定长度的数组,每个节点的值指向子节点的指针,最后还有一组标志位,用来标志到此是否是一个完整的字符串,并且有几个这样的字符串。
如下图是一个常见的用来存英文单词的trie:(图转自http://blog.csdn.net/zslomo/article/details/53434883)
传统trie树也存在一些不足:
1.当某一字符串很长或者与其他字符串没有相同前缀,构造的树会极其不平衡;
2.传统trie是由内存指针链接,且字符串的值没有编码,明文直接显示,安全系数低。
三、以太坊的改进
针对传统trie的不足,以太坊进行了一些改进,http://www.cnblogs.com/fengzhiwu/p/5584809.html 这篇博文对于原理的讲解详细易懂,GitHub的文章https://github.com/ethereum/wiki/wiki/Patricia-Tree也很好,该篇文章的翻译http://me.tryblockchain.org/Ethereum-MerklePatriciaTree.html
下文进行简单的阐述:
1.以太坊增加了两个节点,叶子结点和扩展节点,所以MPT中共存在四类节点:空节点、叶子节点、扩展节点和分支节点。
标准的叶子结点,形式为[key,value]的列表,其中key是key的一种十六进制编码,value是value的RLP编码(RLP编码将在下文解释)。
扩展节点,也是[key,value]的形式,但不同于叶子节点,这里的value是可以链接到其他节点的hash,可以被用来查询数据库中的节点。
分支节点,MPT树中的key被编码成一种特殊的16进制,再加上value,所以分支节点长度为17,前16个元素对应着key中16个十六进制字符,如果有一个[key,value]对在这个分支节点终止,最后一个元素代表一个值,即分支节点既可以搜索路径的终止也可以是路径的中间节点。
MPT还有一个重要的概念是特殊的十六进制前缀编码(GitHub文中有提到),十六进制序列的带可选结束标记的压缩编码。传统的编码十六进制字符串的方式,是将他们转为了十进制。比如0f1248表示的是三个字节的[15,18,72]。然而,这个方式有点小小的问题,如果16进制的字符长度为奇数呢。在这种情况下,就没有办法知道如何将十六进制字符对转为十进制了。额外的,MPT需要一个额外的特性,十六进制字符串,在结束节点上,可以有一个特殊的结束标记(一般用T表示)。结束标记仅在最后出现,且只出现一次。或者说,并不存在一个结束标记,而是存在一个标记位,标记当前节点是否是一个最终结点,存着我们要查找的值。如果不含结束标记,则是表明还需指向下一个节点继续查找。
为了解决上述的这些问题。我们强制使用最终字节流第一个半字节(半个字节,4位,也叫nibble),编码两个标记位。标记是否是结束标记和当前字节流的奇偶性(不算结束标记),分别存储在第一个半字节的低两位。如果数据是偶数长,我们引入一个0值的半字节,来保证最终是偶数长,由此可以使用字节来表示整个字节流。
一个例子:
> [ 1, 2, 3, 4, 5 ]
'\x11\x23\x45' ( Here in python, '\x11#E' because of its displaying unicodes. )
//不含结束,所以没有结束标记,由于字节流是奇数,标记位取值1,不补位,所以前面只补一个半字节就好。
> [ 0, 1, 2, 3, 4, 5 ]
'\x00\x01\x23\x45'
//不含结束标记的偶数,且由于是偶数第一个nibble是0,由于是偶数位,需要补一个值为零的nibble,所以是00。紧跟后面的值。
> [ 0, 15, 1, 12, 11, 8, T ]
'\x20\x0f\x1c\xb8'
//由于有结束标记,除结束标记的长度为偶数,所以第一个nibblie是2,由于是偶数长补位一个值为0的nibble,所以最后加20。
> [ 15, 1, 12, 11, 8, T ]
'\x3f\x1c\xb8'
//由于有结束标记,且为奇数,第一个值为3,又由于是奇数不需要补位,值是3加后面的值。
python编码:
def compact_encode(hexarray):
term = 1 if hexarray[-1] == 16 else 0
if term: hexarray = hexarray[:-1]
oddlen = len(hexarray) % 2
flags = 2 * term + oddlen
if oddlen:
hexarray = [flags] + hexarray
else:
hexarray = [flags] + [0] + hexarray
// hexarray now has an even length whose first nibble is the flags.
o = ''
for i in range(0,len(hexarray),2):
o += chr(16 * hexarray[i] + hexarray[i+1])
return o
2.安全性
首先,为了保证树的加密安全,每个节点通过他的hash被引用,而非32bit或64bit的内存地址,即树的Merkle部分是一个节点的确定性加密的hash。一个非叶节点存储在leveldb关系型数据库中,数据库中的key是节点的RLP编码的sha3哈希,value是节点的RLP编码。想要获得一个非叶节点的子节点,只需要根据子节点的hash访问数据库获得节点的RLP编码,然后解码就行了。通过这种模式,根节点就成为了整个树的加密签名,如果一颗给定trie的跟hash是公开的,那么所有人都可以提供一种证明,通过提供每步向上的路径证明特定的key是否含有给定的值。
MPT例子:
假设我们有一个树有这样一些值('dog', 'puppy'), ('horse', 'stallion'), ('do', 'verb'), ('doge', 'coin')。首先,我们将它们转为十六进制格式:
<64 6f> : 'verb'
<64 6f 67> : 'puppy'
<64 6f 67 65> : 'coin'
<68 6f 72 73 65> : 'stallion'
构造树:
rootHash: [ <16>, hashA ]
hashA: [ <>, <>, <>, <>, hashB, <>, <>, <>, hashC, <>, <>, <>, <>, <>, <>, <>, <> ]
hashC: [ <20 6f 72 73 65>, 'stallion' ]
hashB: [ <00 6f>, hashD ]
hashD: [ <>, <>, <>, <>, <>, <>, hashE, <>, <>, <>, <>, <>, <>, <>, <>, <>, 'verb' ]
hashE: [ <17>, hashF ]
hashF: [ <>, <>, <>, <>, <>, <>, hashG, <>, <>, <>, <>, <>, <>, <>, <>, <>, 'puppy' ]
hashG: [ <35>, 'coin' ]
树的构造逻辑是root结点,要构造一个指向下一个结点的kv节点。先对键编码,由于当前节点不是结束结点,存值的键为奇数字符数,所以前导值为1,又由于奇数不补位,最终存键为0x16。它指向的是一个全节点A。下一层级,要编码的是d和h的第二个半字节,4和8。所以在A节点的第五个位置(从零开始)和第九个位置,我们可以看到分别被指向到了B和C两个节点。对于B节点往后do,dog,doge来说。他们紧接着的都是一个编码为6f的o字符。所以这里,B节点被编码为指向D的kv结点,数据是指向D节点的。其中键值存6f,由于是指向另一个节点的kv节点,不包含结束标记,且是偶数,需要补位0,得到00,最终的编码结果是006f。后续节点也以此类推。
附上GitHub的python代码:
def get_helper(node,path):
if path == []: return node
if node = '': return ''
curnode = rlp.decode(node if len(node) < 32 else db.get(node))
if len(curnode) == 2:
(k2, v2) = curnode
k2 = compact_decode(k2)
if k2 == path[:len(k2)]:
return get(v2, path[len(k2):])
else:
return ''
elif len(curnode) == 17:
return get_helper(curnode[path[0]],path[1:]) def get(node,path):
path2 = []
for i in range(len(path)):
path2.push(int(ord(path[i]) / 16))
path2.push(ord(path[i]) % 16)
path2.push(16)
return get_helper(node,path2)
Merkle Patricia Tree (MPT) 以太坊中的默克尔树的更多相关文章
- 区块链~Merkle Tree(默克尔树)算法解析~转载
转载~Merkle Tree(默克尔树)算法解析 /*最近在看Ethereum,其中一个重要的概念是Merkle Tree,以前从来没有听说过,所以查了些资料,学习了Merkle Tree的知识,因为 ...
- 区块链 - 默克尔树(Merkle Tree)
章节 区块链 – 介绍 区块链 – 发展历史 区块链 – 比特币 区块链 – 应用发展阶段 区块链 – 非对称加密 区块链 – 哈希(Hash) 区块链 – 挖矿 区块链 – 链接区块 区块链 – 工 ...
- 区块链入门到实战(12)之区块链 – 默克尔树(Merkle Tree)
目的:解决由于区块链过长,导致节点硬盘存不下的问题. 方法:只需保留交易的哈希值. 区块链作为分布式账本,原则上网络中的每个节点都应包含整个区块链中全部区块,随着区块链越来越长,节点的硬盘有可能放不下 ...
- 区块链学习1:Merkle树(默克尔树)和Merkle根
☞ ░ 前往老猿Python博文目录 ░ 一.简介 默克尔树(Merkle tree,MT)又翻译为梅克尔树,是一种哈希二叉树,树的根就是Merkle根. 关于Merkle树老猿推荐大家阅读<M ...
- Merkle Patricia Tree (MPT) 树详解
1. 介绍 Merkle Patricia Tree(简称MPT树,实际上是一种trie前缀树)是以太坊中的一种加密认证的数据结构,可以用来存储所有的(key,value)对.以太坊区块的头部包 ...
- 014-数据结构-树形结构-基数树、Patricia树、默克尔树、梅克尔帕特里夏树( Merkle Patricia Tree, MPT)
一.基数树 Radix树,即基数树,也称压缩前缀树,是一种提供key-value存储查找的数据结构.与Trie不同的是,它对Trie树进行了空间优化,只有一个子节点的中间节点将被压缩.同样的,Radi ...
- Merkle Tree(默克尔树)算法解析
Merkle Tree概念 Merkle Tree,通常也被称作Hash Tree,顾名思义,就是存储hash值的一棵树.Merkle树的叶子是数据块(例如,文件或者文件的集合)的hash值.非叶节点 ...
- 转 Merkle Tree(默克尔树)算法解析
Merkle Tree概念 Merkle Tree,通常也被称作Hash Tree,顾名思义,就是存储hash值的一棵树.Merkle树的叶子是数据块(例如,文件或者文件的集合)的hash值.非叶节 ...
- 以太坊中的Ghost协议
https://blog.csdn.net/t46414704152abc/article/details/81191804 写得超好,终于弄懂了什么是叔块,怎么确定哪条链最长,以太坊与比特币出块的差 ...
随机推荐
- 有了SSL证书,如何在IIS环境下部署https?
昨天各位小伙伴都很开心的领取了自己的SSL证书,但是大部分小伙伴却不知道如何部署,也许是因为第一次接触SSL这种高端的东西吧,不过个人觉得就是懒懒懒...本来小编也挺懒的,但是答应了各位小伙伴的,那么 ...
- Spring的jar包不同版本的下载地址
http://repo.spring.io/release/org/springframework/spring/ 可以直接下载不同版本的spring jar包
- centos7中nginx的搭建
./nginx 启动服务./nginx -s stop 关闭服务./nginx -s reload 重新加载配置文件 首先我们应当安装一个依赖的软件包: yum install gcc-c++yum ...
- js扩展String.prototype.format字符串拼接的功能
1.题外话,有关概念理解:String.prototype 属性表示 String原型对象.所有 String 的实例都继承自 String.prototype. 任何String.prototype ...
- vue 图片压缩 基于cli3 配置
chainWebpack: config => { const imagesRule = config.module.rule('images') imagesRule .use('image- ...
- Python-知识点小计
1.python赋值.浅拷贝.深拷贝区别:https://www.cnblogs.com/xueli/p/4952063.html: 2.python的hasattr(),getattr(),sett ...
- flask第三方插件DBUtils
django中有强大的ORM支持我们来操作数据库, 但是flask没有提供对数据库的操作, 依然还是需要第三方的支持, 来提高我们的开发效率. 下载DBUtils 使用DBUtils 使用DBUtil ...
- Drill-On-YARN
1. Drill-On-YARN介绍 功能 启动 停止 扩容 缩容 failover 启动流程 下载drill的社区包,进行必要的配置,执行drill-on-yarn.sh start命令,启动dri ...
- kubernetes基础使用
查看节点详细信息 kubectl describe node vm2 显示版本号 kubectl version Client Version: version.Info{Major:"1& ...
- 如何在VMware Fusion中导入windows下的虚拟机
最近换了新款的mbp,因为偷懒,便将之前在windows台式机上的虚拟机搬了过来. 特此记录下搬运过程,方便以后查看. 一 操作过程 安装激活VMware 常规操作,无需赘言 拷贝windows下虚拟 ...