https://github.com/ethereum/wiki/wiki/Patricia-Tree
网络上有很多对帕特里夏默克尔树的介绍。此文谨做英文翻译,以加深自己对以太坊世界状态树的理解。
Merkle Patricia尝试提供一个经过密码验证的数据结构,该结构可用于存储所有(键、值)对,尽管在本文的范围内,我们将键和值限制为字符串(要删除此限制,只需对其他数据类型使用任何序列化格式)。
序文:basic Radix tries
在basic Radix tries中,她所存储的每个节点表示为:
[i0,i1,...in,value]
其中i0,i1...in代表不同的字母(通常为二进制或者十六进制),在树中分别标记着从根到叶子节点,value表示最终值,其中i0,..in之间的间隙的值要么为NULL,要么为一个指向其他节点的指针(在咱们的例子中,“指针”是指其他节点的hash值)。从而,她能够作为最基本的键值存储单元。咱们用她来举个简单的例子,假设咱们想要用她存储dog这个单词。咱们首先要把dog分解成字母并用十六进制表示,也就是64 6f 67.用她表示的话就是[root,6,4,6,f,6,7,dog]。所以咱们可以利用这棵树所表示的一条路径很快找到需要的值。所以咱们用path这个变量来表示路径。
下面是更新和删除节点的代码:
def update(node_hash, path, value):
if path == '':
curnode = db.get(node_hash) if node else [ NULL ] * 17
newnode = curnode.copy()
newnode[-1] = value
else:
curnode = db.get(node_hash) if node else [ NULL ] * 17
newnode = curnode.copy()
newindex = update(curnode[path[0]], path[1:], value)
newnode[path[0]] = newindex
db.put(hash(newnode), newnode)
return hash(newnode)
def delete(node_hash, path):
if node_hash is NULL:
return NULL
else:
curnode = db.get(node_hash)
newnode = curnode.copy()
if path == '':
newnode[-1] = NULL
else:
newindex = delete(curnode[path[0]],path[1:])
newnode[path[0]] = newindex
if len(filter(x -> x is not NULL, newnode)) == 0:
return NULL
else:
db.put(hash(newnode), newnode)
return hash(newnode)
传统c语言中的树结构中,一个节点指向下一个节点使用的指针,然而在以太坊中,需要把状态树的节点持久化到硬盘中,所以不能够使用指针来指向节点,树中使用的是key = sha3(rlp(value)),以这种方式得到key,作为leveldbd的键值对存储于硬盘中。
merkle partricia tree 的构造是为了解决默克尔树中存储浪费的问题,该方案可以压缩大量树中的节点。通过以下结构
NULL
(代表空字符串)branch
A 17-item node[ v0 ... v15, vt ]
leaf
A 2-item node[ encodedPath, value ]
extension
A 2-item node[ encodedPath, key ]
。。。。写不下去了。翻译果然还是一件很无聊的事。
说说自己论文里面看到的吧。
2017-2018年的一篇论文,《EDRAX:A Cryptocurrency with Stateless Transaction Validation》里面提到比特币的区块数据已经达到150GB,以太坊的已经超过400GB。每个机器节点中保存的区块链状态,比特币的UTXO大约在2.7GB,以太坊的状态树达到14GB,并且每天都在以86000的速度增加新账户。状态树的不断增大,导致默克尔帕特里夏树也在不断增高,这使得这种树的好处也在不断失去。同时每个区块产生大量的状态树节点更新,使得机械硬盘已经完全跟不上区块链的同步速度。