Ethereum学习之路 —— 状态树

状态树

要设计一种什么数据结构呢?要完成账户地址到账户状态的映射。
以太坊的账户地址是160位的,也就是20个字节,一般表示成40个16进制的数。
状态时指外部账户和合约账户的balance、nonce等。

MPT

了解MPT之前,先了解下trie。

trie: 字典树。假设有如下几个单词:General,Genesis,Go,God,Good,使用 trie 这种数据结构产生的树如下:
Ethereum学习之路 —— 状态树_第1张图片
trie的特点

  • 优点
    • 由于以太坊的地址是40个16进制的数组成,所以头节点有0~f加上结束标志位总共17个
    • 因为地址都是40个16进制的数,所以纵向的长度是40。
    • 两个地址映射到哈希表中,可能会出现哈希碰撞,但trie中,两个不同的地址必定映射到两个不同的路径。
    • 给定一组输入,不论什么顺序,最后构造出的数都是一样的。
    • 更新操作时,局部性很好,只需访问输入地址所映射的节点即可
  • 缺点
    • 中间节点(如E、N、E)存储浪费

如何解决 trie 中的缺点呢?这里用到了 Patricia tree(压缩前缀树)。上面的例子进行路径压缩后,得到的数据结构如下:
Ethereum学习之路 —— 状态树_第2张图片
压缩之后,访问内存的次数会减少,效率明显提高。
如果新加一个单词,压缩的路径可能会展开。

以太坊中的地址分布是否是稀疏的?
是。以太坊中的地址是160位,所以地址空间是2^160。这个数值是非常非常非常大的。为什么要这么稀疏呢?为了避免哈希碰撞。

MPT (Merkle Patricial tree) 将 Patricial Tree中的普通指针换成了哈希指针,并将状态树的根哈希值保存在区块头中。
这个根哈希值又什么作用?

  • 验证账户数据是否被篡改。
  • 将整个MPT发送给轻节点,轻节点就可以验证账户中有多少钱。
  • 可以证明某个key值在MPT中不存在。

以太坊中所使用的MPT 是 Modify MPT.
Ethereum学习之路 —— 状态树_第3张图片
如果一个node 不是 leaf node ,则会有一个Branch Node

每一个合约账户都有一颗小的MPT

以太坊中如果一个账户的状态发生了改变,会新建一个新的分支,原来的状态会保留在区块链中。下图是两个相邻的区块,大部分的账户的状态没有发生改变,只有状态发生了改变的账户会创建新的分支发布在新的区块中。在下图的例子中,只有45新建了一个新的分支。
Ethereum学习之路 —— 状态树_第4张图片
以太坊系统中每个全节点需要维护的不是一颗MPT,而是系统中每次出现一个区块,就要新建一个MPT,只不过其中大部分的节点是共享的,只有少数发生改变的节点需要新建分支。

  • 为什么要保留历史状态,而要新建分支?
    • 如果链上出现了分叉,未胜出的那个节点需要将其包含的状态回滚到上一个版本。如何回滚?这时就需要历史状态了。

状态树中的状态要如何存储在树上呢?
将value 通过RLP进行序列化后保存到value中

问题:

  • 比特币中的merket tree为什么不需要排序?
    • 比特币的矿机需要再本地维护一个全节点,但是会被发布到区块链中的区块只能是取得记账权的那个区块,所以merket tree的顺 序是由获得记账权的节点所确定的。
  • 以太坊的状态树为什么不能采用比特币的方式?
    • 如果采用这种方式,每次发布新区块都需要将所有的账户状态打包发布到区块链中,而发布一个交易只需要几百或几千个交易,这和账户数量差了好多个数量级。而且交易必须得发布,账户状态有很多是没有变化的,变化的只是那些发生了交易的账户。
  • 为什么不采用sort merket tree ?
    • 如果新增加了一个账户,该账户的地址是随机的,有可能出现在树的中间,导致后面的树的结构都发生了改变,相当于重新生成了一棵merket tree。而且新增账户其他节点是不需要知道的,只有当该账户发生了交易,才会通知其他节点。
  • 什么时候采用路径压缩比较好?
    • 如果输入很长,但又没有几个输入,采用路径压缩比较好。
      Ethereum学习之路 —— 状态树_第5张图片

你可能感兴趣的:(Ethereum)