12-ETH中的数据结构
简介
账户地址到 账户状态的映射
eth的addr是160b的数,一般表示为 40个 16进制的数;
trie
我们先介绍一下 trie 结构:
trie 结构,只要地址不一样,就一定会映射到trie 树的两个不同的分支,
它不会碰撞;
给定的单词不变,顺序打乱,不影响树的结构;
更新如果是局部性的,只需要改变一条分支即可;
patricia tree
patricia tree路径压缩的trie,会如下:
以上这样密集的情况路径压缩比较好;
但是eth地址是160位,也就是2**160 是一个非常大的数,所以地址在这个地址空间中,其实非常稀疏(为了防碰撞),不需要压缩;
state tree 状态树
merkle Patricia tree (MPT)
右上角是四个账户,假设只有7位的地址,账户状态只显示了余额;
第一个账户是 45个 eth;第二个是 1 wei;第三个 1.1eth;第四个 0.12 eth。
如果有路径压缩就会有 extension node;
可以看见他们 root 结点 a7 ,后面就分支了;就是一个 树的结构。
最后,这个 root 结点取hash 得到了一个hash 值写在block header 中。
都是 一个结点算hash 值,这个值放进上一个结点中作值,来实现指针。
这个value的实现是靠 RLP 序列化。
上图是 两个 block 相连的例子;
state root 在block header中,但是 每一个block 中的 状态树state tree 下的结点,都共用了很多个结点, 看见右边的block state tree中大部分结点都指向了左边状态树的结点,只有那些发生改变的结点需要新建分支;
上面图片的例子中只有一个结点 的值 ,从29变成 45,这就是上图表达的意思;
对于全结点而言,每新建一个block ,就需要在本地维护一个新的 merkle Patricia tree,只不过大部分结点是重复利用上的。
回滚困境
淘汰掉的一条链,想要直接回滚是不可能的,因为eth 中有智能合约,智能合约 可能非常复杂,合约执行完之后想要回滚实现不了。
所以想要回滚必须要 保存历史状态;
header 块结构
前一个 block header的 hash 值;
叔叔区块hash值;
coinbase 矿工地址 ;
Root 是 状态树的根hash;
TxHash 是交易树的根hash;
receipthHash 是收据树的根hash;
bloom 查询某种交易的执行结果;
Gas 消耗的汽油费用;
Time 是block 的产生时间;
Nonce 也是 挖矿时候的随机数;
transaction是这个block 中交易的列表;
这个区块真正发布出去在网上 就是上面external的这些信息;
交易树、收据树
bloom filter 布隆过滤器
就是一个 hash表的结构,看一个元素是不是真的在 abc 这个集合中,就对这个元素 hash,算出来的值看看在不在hash 表中,有冲突可能性,也就是可能错报,但是不可能漏报。
删除的操作,只存0和1的基础情况下,bloom filter 不支持删除操作,因为理论上可能多个 集合内的元素落在hash 表的一个位置上,你想改0,可能会破坏 整体存储情况。
每一笔交易执行完之后,会形成一个收据,收据内就会包含一个bloom filter ,记录交易的地址、类型 等七七八八的信息。
发布的区块在 block header中 也有一个 总的 bloom filter,这个总的 bloom filter 是这个block 中所有交易的bloom filter的并集。
查找过去十天 和这个智能合约相关的所有交易:
1、查哪个区块的 block header 中的 总bloom filter 中有我要的交易的类型。如果 block header 中没有的话,这个block 就不是我们想要的;
2、如果block filter中总 bloom filter 中有,就从这个 block 所对应的交易所对应的收据树里面的bloom filter里面找;
transaction-driven state machine
交易驱动状态机
state 指的是eth 所有账户的状态,每次发布的 block 中 包含的交易,通过执行这些交易,让eth 系统的状态从一个状态到下一个状态;
为什么要有状态树?
eth 和 btc 一样 创建一个账户是可以私下完成的,只有当这个账户第一次收到钱的时候,才能被记录进链中;
状态树 是保留全部账户 状态信息的,而不是 交易树、收据树 仅仅包含交易相关的账户的信息,这样的好处在于 当 A->B 转账时,B 是新建账户时,不用一路回溯 全部结点找一遍来确认 B 是一个新建的账户,而有状态树 可以快速发现B不在状态树中,快速确认了B是一个新建账户,而将其纳入状态树。
代码中数据结构
以上是交易树和收据树的创建过程。
bloom 就是 前面说的 bloom filter ,散列表。
block header 中的bloom 是由 bloom 汇总来的。
bloomlookup 是查看 bloom filter 中有没有我们感兴趣的topic;