以太坊之PMT

参考

官网解释
https://github.com/ethereum/wiki/wiki/Patricia-Tree

牛逼啊,一文讲清楚了以太坊的MPT
https://blog.csdn.net/itleaks/article/details/79992072

概述

MPT,全称Merkle Patricia Trie,以太坊中用来存储用户账户的状态及其变更、交易信息、交易的收据信息。
看其全称便大概知道MPT融合了MerkleTree,Trie,Patricia Trie这三种数据结构的有点,从而最大限度地快速实现查找功能并节省空间。

  • Trie:单词查找树,根据前缀匹配,比如输入法的前缀模糊匹配,都用这种树做数据结构,快速匹配
  • Patricia Trie:紧凑前缀树,是一种空间使用率经过优化的 Trie
  • Merkle Patricia Trie: 把每个Node都做Hash计算获取Node.Hash,然后键值对的方式存储在数据库当中

PMT在以太坊中的运用

https://github.com/ethereum/wiki/wiki/Patricia-Tree
以太坊的MPT实际上是一种key/value键值对存储的树形版本,因为如果不做特殊处理,1w个不同的key,会有1w个value,每次操作数据时,都要遍历,这样查询的效率很低。
所以按照前缀匹配的法则,在key/value的基础上,引入了树的概念(类似于 JDK1.8的 hashmap的数据结构,引入了红黑树),这样大大提升了查询的速度,就像查字典一样。

以太坊里面有4个Root,分别存储了不同的信息

  1. stateRoot:存储了当前区块的所有用户的最终状态:地址、余额、合约等信息,path:sha3(ethereumAddress)
  2. transactionsRoot:存储了当前区块的所有的交易的信息,path: rlp(transactionIndex)
  3. receiptsRoot:存储了当前区块的所有的交易收入的信息,path: rlp(transactionIndex)
  4. storageRoot: 存储了当前Account的所有相关的合约信息

以太坊比比特币做了一个更多内容的压缩存储,比特币的root仅仅是该区块的所有的交易的merkle Tree,而以太坊不仅仅有交易树,还有收款人树,还有全局的账户树和用户的智能合约树,从而开放更多的功能。

代码展示

Block.Header里面的部分代码 (状态树、交易树、收据树)

    Root        common.Hash    `json:"stateRoot"    /    
    TxHash      common.Hash    `json:"transactionsRoot" 
    ReceiptHash common.Hash    `json:"receiptsRoot"     

state_object.go Line98

type Account struct {
    Nonce    uint64
    Balance  *big.Int
    Root     common.Hash // merkle root of the storage trie
    CodeHash []byte
}

Trie结构

树其实就是一个根节点,因为根据根节点就可以找到整个树

type Trie struct {
    root         node   //根节点
    db           Database   //数据库相关,在下面再仔细介绍
    originalRoot common.Hash    //初次创建trie时候需要用到
    cachegen, cachelimit uint16 //cache次数的计数器,每次Trie的变动提交后自增
}

节点的结构

以太坊中按照业务功能分,有4种类型的结点:

  • 叶子节点(leaf),表示为[key,value]的一个键值对。和前面的英文字母key不一样,这里的key都是16编码出来的字符串,每个字符只有0-f 16种,value是RLP编码的数据
  • 扩展节点(extension),也是[key,value]的一个键值对,但是这里的value是其他节点的hash值,通过hash链接到其他节点
  • 分支节点(branch),因为MPT树中的key被编码成一种特殊的16进制的表示,再加上最后的value,所以分支节点是一个长度为17的list,前16个元素对应着key中的16个可能的十六进制字符,如果有一个[key,value]对在这个分支节点终止,最后一个元素代表一个值,即分支节点既可以搜索路径的终止也可以是路径的中间节点。分支节点的父亲必然是extension node
  • 空节点,代码中用null表示
  1. 分支Node
    Node:[i0, i1 ... in, value]
    每个slot要么为null,要么有一个指针指向下一个Node,一个fullNode有 [17]node,因为采用16进制+value值
    branch的value值,表示的是上一个节点的RLP编码的数据,也就是父节点最终的值,当然value也可以为空,说明并没有存储到父节点截止的数据
  1. 叶子节点:叶子节点的value值是RLP编码的数据,也就是最终的值


    image
  1. 扩展节点:体现了Patricia的特征,可以合并一起的前缀就不分开,可以减少查询的深度。另外扩展节点下面一定是分支节点,不然就不需要扩展了,直接叶子节点了。所以扩展节点的value值,指向的是下一个分支节点的地址


    image

在以太坊的系统当中,其实分为2大类的节点的数据结构:

  • shortNode key/value的结构(叶子节点、扩展节点)
  • FullNode 数组节点(分支节点)
    fullNode struct {
        Children [17]node 
        flags    nodeFlag
    }
    shortNode struct {
        Key   []byte
        Val   node
        flags nodeFlag
    }

type nodeFlag struct {
    hash  hashNode // cached hash of the node (may be nil)
    gen   uint16   // cache generation counter
    dirty bool     // whether the node has changes that must be written to the database
}

    hashNode  []byte
    valueNode []byte

分析

  1. 不管是fullNode还是shortNode,在以太坊中,都是通过指针引用直接获取的,比如shortNode.Val 就直接指向下一级的Node,并不是通过hashNode查询的,所以一次加载,必须加载一个完整的树到内存中,但是存储的最终的value对象是一个RPL格式的数组valueNode []byte

  2. 不管是 fullNode还是shortNode都有一个flags属性,flags又有一个hashNode的属性,所以每个节点都有hashNode的属性值

  3. 叶子节点,携带数据部分的RLP哈希值,数据的RLP编码值作为valueNode的匹配项存储在数据库里,也就是叶子节点的shortNode.Val --> 指向valueNode []byte

  4. 分支节点之所以是17个slot,并且依次 0、1、2...f是因为把key压缩成了16进制,这样key的长度就不长了。

  5. MPT的优点:

  • 查询快,因为是Patricia Trie,前缀相同会压缩
  • 更新变动小,可以快速定位位置,且一个节点的改动,不会影响太多不关联的节点,改动小

举个简单的例子

根据Address,查询该用户的余额

  1. 先获取最新的Block.Root,这个就是stateRoot的rootHash,根据这个rootHash去内存中查询对应的root节点(节点启动的时候,必须加载一棵完整的内存树出来)
  2. Sha3(Address)获取到path,然后根据path去rootNode中根据MPT规则去找到对应的valueNode,也就是rpl(Account) 的值
  3. 根据 valueNode然后decodeRpl(Account),得到Account,读取Account.balance

以太坊的存储

以太坊中使用的数据库是levelDB

注意事项

MTP中,key = Sha3(Account.address),所以是安全的,即使你拥有一颗完整的Tree,你不知道 address,你也是无法推测出来,哪个账户里面有多少钱,而一个address是uint160的整数,穷举的话,基数也很大,所以具有一定的私密性。

MTP就像一个公共密码箱,谁都可以去尝试打开,但是只有拥有钥匙的人才能打开自己的柜子。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 151,511评论 1 330
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 64,495评论 1 273
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 101,595评论 0 225
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 42,558评论 0 190
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 50,715评论 3 270
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 39,672评论 1 192
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,112评论 2 291
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 29,837评论 0 181
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 33,417评论 0 228
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 29,928评论 2 232
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,316评论 1 242
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 27,773评论 2 234
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,253评论 3 220
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 25,827评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,440评论 0 180
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 34,523评论 2 249
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 34,583评论 2 249

推荐阅读更多精彩内容