03 ETH-状态树
目录地址到状态(balance、nonce、code、storage)的映射。
以太坊地址一般160bits,一般表示为40个16进制的数。
那么如何设计映射?像是 key:value pair?那么,能不能只用一个hash表来实现?(如果不考虑hash碰撞的话),那这样是不是太简单了?
用hash表的话,如果需要提供Merkle Proof,如何提供?
比如:一个人要签合同,需要别人证明一下,他有这么多钱,这个如何提供证明?
一个简单的方法,把hash表中的元素,组织成一颗Merkle tree,算出一个根hash值,根hash值需要保存在block header中,公布出去,根hash值只要是正确的,就能保证数据不被篡改。这个有什么问题吗?
不要一开始就看什么数据结构,而是一步步思考,想想数据结构是如何设计出来的。(多想想别人是为什么这样设计?)
新区块中包含有新的交易,执行交易必然会使hash表的内容发生变化,我们发布下一给区块的时候,难道要把hash表中的数据再重新组织成Merkle tree吗?那这个代价是不是太大了?
实际上,真正发生账户状态变化的只是一小部分。只有新区块中交易所关联的账户才会发生变化,大多数账户的状态是不变的。每次构建一次Merkle tree,代价是很大的。
比特币中不是每出一个区块,也要构建一颗Merkle tree吗,那个为什么没有这个问题?
比特币中的Merkle tree构建完之后,是不会再改了,下次发布新的区块,再重新构建Merkle tree。比特币中构建Merkle tree也仅仅是几百到几千比交易而已,以太坊中如果采用,会是什么结果?
是要把所有的以太坊账户一起构建成一个Merkle tree,这个数目比之前的比特币的交易数目高出好几个数量级。
除了验证账户的数据之外,Merkle tree还有更重要的特性,维护全节点之间数据的一致性。各个全节点之间要保持状态的一致才行。这也是比特币中为什么要把根hash值写在块头中的原因,对于当前区块的状态,所有全节点要有一个共识。
所以,如果每个全节点简单在本地维护一个hash表,然后构建出一个Merkle tree来,这种方法是不行的。(hash表本身查找、更新效率很好,但是构建Merkle tree,效率太低)
我们能不能不要hash表,然后直接构建一个账户的Merkle tree,修改数据直接在Merkle tree中修改(每次只需要改Merkle tree中的一小部分),该方法可行吗?
问题:Merkle tree没有提供一个快速查找、更新的方法。
如果我们把所有的账户放在Merkle tree中,这个Merkle tree要不要排序?Sorted Merkle tree
不排序没有办法证明non-membership。
如果不规定叶结点中的排列顺序,这样构建出来的Merkle tree不是唯一的。相应的,根hash值也是不一样的。
比特币当中不也是不排序吗?比特币中每个全节点收到的交易顺序也是不一样的,但是最后是获得记账权的节点说了算。
希望能够设计出自己的加密货币,设计出更好的数据结构。
如果以太坊中这样做,需要将全节点维护的Merkle tree中发布到区块中,但是包含的发布的是所有账户的状态,不是仅仅是交易的状态。数量级差距。
所以,不排序的Merkle tree是不行的。
如果用Sorted Merkle tree,是不是就没有问题了?
以太坊账户也是随机产生的,如果新产生的账户,刚好在树叶子结点的中间位置,后面的叶子节点数目也会发生改变。又变成了每次产生一个Merkle tree。这样代价也太大了了。
插入和删除代价都太大了。
以太坊采用MPT结构,
数据结构trie(来自retrieval)字典树、前缀树。
特点:
1 trie 中每个节点的分支数目取决于 key 值中每个元素的取值范围。
以太坊地址是40个16进制的树,分叉数目叫做 branding factor,0~f + 1(结束标识符),共17个。
2 trie的查找效率取决于 key 的长度,key的值越长,查找需要访问的内存次数就越多。
以太坊中的地址的键值都是一样长的。(比特币和以太坊的地址是不通用的,格式是不一样的)
3 如果用hash表来进行账户的存储,从理论上说,有可能存在hash碰撞,trie中是不会出现碰撞。
4 不论输入怎么打乱顺序,最后构成的 trie 是同一棵树。
5 更新的局部性(每次一笔交易,只有绝少数账户的信息会发生变化,所以,更新操作的局部性很重要)(注:上图中只画出来key,没有画出value)
缺点:
直观上可以看到,树结构深。
将单个节点进行合并,可以降低存储和查找的开销。
Patricia tree / Paticia trie
经过了路径压缩的前缀树。
访问内存的次数大大减少,效率提高。
但是,如果新插入一个单词,原来的路径可能需要拓展出来。
路径压缩在什么情况下效果比较明显?
键值分布比较稀疏的情况下,效果比较好。
以太坊中键值是地址,以太坊的地址是160位,为 $2^{160}$。
hash碰撞是可能存在的,地址的分布要足够长,分布足够稀疏,这样才不会产生碰撞,这是去中心化系统防止碰撞的唯一办法。
标签:03,hash,状态,以太,tree,Merkle,ETH,区块,节点 From: https://www.cnblogs.com/yangyi215/p/17367677.html