以太坊数据结构的批量增加(一)

我们先了解一下以太坊MPT树的基本节点。


可以看到有四种节点,代码目录结构在/tire.node.go中

1,fullnode 有17个子节点,叫做分支节点。

2,shortNode对应了黄皮书里面的扩展节点和叶子节点(通过shortNode.Val的类型来判断当前节点是叶子节点(shortNode.Val为valueNode)还是拓展节点(通过shortNode.Val指向下一个node))。

3,hashNode用于指向下一个节点

4,valueNode存储value

然后我们再看看树的结构

可以看到,结构比较简单。db是数据库,每个节点的内容都是保存在数据库里。

root 也就是根部的node   node是一个接口 接口中的两个方达

 fstring(string)string   

cache() (hashNode,bool)

我们知道,以太坊和比特币的最大区别有两个。一个是数据结构,第二个是虚拟机。

比特币词用utxo模型,在此不展开来讲。以太坊是账户余额模型。

因为每个地址一旦转账就发生余额改变。mpt地址余额账户就会从叶子更新到根hash

这样对比一个根部hash的改变就可以知道两个账本是否一致。shortnode是为了防止树过深。影响查找效率。



为了了解树的数据结构,我们先来了解一下字典树

字典树是这个样子的

 例如我们需要查找节点7我们只需要输入to就可以了,节点9就是inn

这里面的to 和inn 就是以太坊说的key

那么Key是怎么来的呢。比如说我要寻找一个账户余额。那么先得得到这个账户的key。沿着树往下找。

通过源码知道,以太坊的key是经过keccak256计算而来的结果

keccak256计算是256位。换成十六进制就是64位字符

于是这64位支付就成为以太坊的key

但是字典树有个缺陷,就是高度不可控。如图


如果是64位Key,那么他的最高高度可以达到64位。所以我们还得了解一下Patricia树


如果它没有更多的子节点,是可以把多个字符合并成一个节点的。比如说ulus。这样就可以显著的减少高度。

mpt树还兼具另外一种数据结构。merkel树


事实上,merkel树的特性是为了方便维持各个节点之间的数据一致性,更改状态的。

一旦某个节点的值改变或者删除,都会影响到值根节点的所有hash值。


以上的预备工作就结束了。让我来画一个mpt树吧


在网上找了个图


叶子节点(leaf),存储的是真实的数据,

扩展节点(extension),扩展节点合并相同的前缀,扩展节点下面是分支节点,上图中共享"d3"

分支节点(branch),因为在以太坊协议中,不管是地址还是hash,都是一个16进制串,所以是数字,16进制一共16个数字表示0~9,还有a,b,c,d,e,f;不会出现其他字母,MPT树中的key被编码成一种特殊的16进制的表示,再加上最后的value,所以分支节点是一个长度为17的list,前16个元素对应着key中的16个可能的十六进制字符,如果有一个[key,value]对在这个分支节点终止,最后一个元素代表一个值,即分支节点既可以搜索路径的终止也可以是路径的中间节点。分支节点的父亲必然是extension node。由于分支节点是16长度数组,故该节点减少了层高和存储空间

空节点,代码中用null表示


知道了树的结构。下面我们就来看增删改查

首先我们新建一个mpt树,Trie树的初始化调用New函数,函数接受一个hash值和一个Database参数,如果hash值不是空值的话,就说明是从数据库加载一个已经存在的Trie树, 就调用trei.resolveHash方法来加载整颗Trie树,这个方法后续会介绍。 如果root是空,那么就新建一颗Trie树返回。

树的查找,采用递归的查找方法

树的更新,修改

树的插入,这个就是下一篇文章中我们要改的点。

树的插入是递归查找,然后插入一条数据。然后从叶子节点到根节点的hash更新一遍。而这个函数每次只能更新一条数据。然后从叶子到hash会花费大量机器时间。如果是一批数据,时间就成批增长。不巧的是,以太坊每时每刻都有交易在发生。

能不能有一种方式,减少hash的次数

©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容