区块链学习笔记15——ETH状态树

区块链学习笔记15——ETH状态树

学习视频:北京大学肖臻老师《区块链技术与应用》
笔记参考:北京大学肖臻老师《区块链技术与应用》公开课系列笔记——目录导航页

在以太坊中,有三棵树的说法,分别是状态树、收据树和交易树。了解了这三棵树,就弄清楚了以太坊的基础数据结构设计。

引入

要实现的功能:地址到状态的映射
ETH的账户地址是160位的,一般表示成40个十六进制数
状态就是外部账户和合约账户的状态,包括余额、交易次数,合约账户还有代码和存储。

数据结构的组织形式

  1. 直观上地址到状态的映射用哈希表存储比较简单,为什么不用哈希表存储呢?
    用哈希表如何提供Merkle Proof?将哈希表内容组织为一颗Merkle tree像比特币一样提供Merkle Proof,但是当新区块发布时,哈希表内容会改变,我们需要再次将其组织为新的Merkle Tree,这样的话,每当产生新区块(ETH中新区块产生时间为10s左右),都要重新组织Merkle Tree,这样的代价是很大的,实际上发生变化的账户只有新交易所关联的那一部分。
    需要注意的是,比特币系统中没有账户概念,交易由区块管理,而区块包含上限为4000个交易左右,每次发布一个区块对应一棵新的Merkle tree,一旦发布是不会改变的,所以Merkle Tree不是无限增大的。而ETH中,Merkle Tree用来组织账户信息,是要把所有的以太坊账户一起构建一个Merkle tree,这个数目比BTC中的Merkle tree会大好几个数量级。
    实际中,发生变化的仅仅为很少一部分数据,我们每次重新构建Merkle Tree代价很大

  2. 能不能不用哈希表,直接用Merkle tree,改的时候直接在Merkle tree里改?
    Merkle tree没有提供一个高效的查找和更新的方法。为了保证所有节点的一致性和查找速度,必须进行排序。如果以太坊不排序的话,每个全节点维护的账户顺序不一样那么计算的Merkle tree的根哈希也是不一样的,比特币系统中虽然没有进行排序,但是交易的顺序是由发布区块的结点确定的,顺序是唯一的。如果以太坊要想实现的话必须把所有账户的状态也发布到区块上,数量级很大是不可行的。

  3. 如果用排序的Merkle tree会有什么问题?
    插入账户的话代价很大

综上所述,以上两种简单的数据结构均是不可行的,实际中以太坊采取的数据结构是MPT。

简单的数据结构——trie

trie:字典树,边代表字母,从根结点到树上某一结点的路径就代表了一个字符串

在这里插入图片描述

特点:

  • 每个结点的分支数目取决于Key值中每个元素的取值范围
    图例中的分支数目为27(最多26个小写的英文字母+一个结束标志位);以太坊中的地址为40个十六进制数,所以分支数目为17(16个十六进制数+一个结束标志符)
  • 查找效率取决于key值的长度,以太坊中所有的键值是相同长度,都是40位16进制数
    Ps:比特币和以太坊的地址是不通用的,格式长度均不同,以太坊的地址是公钥取哈希从前面截取一段(160bit)得来的
  • 哈希表存储理论上是会出现哈希碰撞的,trie是不会出现碰撞的
  • 给定一组输入构成的trie是相同的,与顺序无关
  • 更新的局部性比较好,只需要更改元素所属的分支即可

缺点

  • 存储浪费,很多中间节点都只有一个子节点,如果能将其合并,可以减少存储的开销,同时提高了查找的效率。因此,为了解决这一问题,我们引入Patricia tree/Patricia trie。

Patricia tree

经过了路径压缩的前缀树

在这里插入图片描述

需要注意的是,如果新插入单词,原本压缩的路径可能需要扩展开来。
路径压缩在什么情况下效果比较好:键值分布比较稀疏

Trie:
在这里插入图片描述
Patricia tree:
在这里插入图片描述

以太坊的地址是160bit的,共有2160种,是非常稀疏的,这样可以避免产生碰撞,这是去中心化系统防止产生碰撞的唯一办法。

MPT——Merkle Patricia tree

Merkle tree与binary tree的区别:把普通指针转为哈希指针

Merkle Patricia tree:所有账户组织成一棵Patricia tree,用路径压缩提高效率,然后把普通指针换成哈希指针,这样就可以计算出一个根哈希值。(比特币的block header中只有一个根哈希值,就是区块中包含的交易组成的Merkle tree的根哈希值;以太坊中有三个)

这个根哈希值的作用:

  • 防篡改
  • Merkle proof,证明账户余额
  • 证明账户不存在,如果存在的话应该存在哪个分支上,将这个分支作为Merkle proof发送,可证明其不存在

实际用到的MPT——Modified MPT

在这里插入图片描述
每次发布新区块,状态树中部分节点状态会改变。**但改变并非在原地修改,而是新建一些分支,保留原本状态。**如下图中,仅仅有新发生改变的节点才需要修改,其他未修改节点直接指向前一个区块中的对应节点。
合约账户的存储也是MPT形式保存,也是用一棵MPT,以太坊的结构是一棵大的MPT包含很多小的MPT,每一个合约账户的存储都是一个小的MPT
在这里插入图片描述
所以,系统中全节点并非维护一棵MPT,而是每次发布新区块都要新建MPT。只不过大部分节点共享。

为什么要保留历史状态?
系统中有时会出现分叉,出块时间降到十几秒,临时性的分叉是很普遍的。
保留历史状态为了便于回滚。
如下图1中产生分叉,而后上面节点胜出,变为2中状态。那么下面节点中状态的修改便需要进行回滚,将这个结点的状态取消掉,退回到上一个区块,然后沿着上一个链向后推进。
因此,需要维护这些历史记录。
在这里插入图片描述
比特币中的交易可以通过简单的反向交易退回到之前的状态,但是以太坊中有智能合约的存在,一旦执行完后就无法推算出之前的状态,所以要想回滚必须保存历史状态。

以太坊中代码的数据结构

区块头的结构:
在这里插入图片描述
区块的结构:
在这里插入图片描述
区块在网上真正发布时的信息:
在这里插入图片描述

value的存储

状态树中保存的是(key,value)
key就是地址,value是经过RLP(Recursive Length Prefix)编码做序列化之后再存储
RLP的特点:简单,只支持一种类型——nested array of bytes

  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值