引介 | 二叉状态树的结构, Part-1
摘要: 二进制状态树如何解决 RLP 编码带来的复杂性
过去几个月来,我一直致力于将 trie 从十六进制树结构过渡到二进制树结构。我已经写了一篇关于如何转换状态树格式的文章(中文译本),但是没有完全说明状态树的结构。我将撰写一系列文章来探讨设计新结构时需要做出哪些权衡。本文是该系列的第一篇。
在设计十六进制 trie 时,一些设计选择在当时听起来很棒,但是经过 5 年的实践,被证明带来了很多复杂性。鉴于 ETH 1.x 想要转向二进制 trie,我们正好可以借此机会研究一下状态的存储方式。
问题的根源
在重新设计存储格式时,我们至少可以从 5 个方面进行改进。
-
将账户 trie 和存储 trie 合并:维护多个结构会增加复杂性,典型的例子就是节点必须先遍历账户 trie,得到存储 trie 的根,然后再到存储 trie 上获取数据。 -
扩展节点(extension nodes):这是一种特殊的节点,负责给特定子树上的所有 key 加上前缀。这些节点的作用是能够限制需要被哈希的节点数量,但是也引入了复杂性,因为它们所涉及的 key 必须以特定方式打包。 -
RLP 编码格式旨在高效地对任意结构进行编码。由于其复杂性,它也带来了很多麻烦:必须费尽千辛万苦打包 key 块(pack key chunk)。另外,由于每个节点的结构相当固定,可以使用更简单的序列化方法来代替 RLP。 -
与前两个问题相关的是,十六进制的前缀也会带来复杂性和混乱。 -
十六进制 trie 的证明【即,“见证数据(witness)”】比二进制 trie 的证明大 4 倍左右。(欲知详情,请阅读这篇文章。(中文译本))
RLP —— Ramble, Lose yourself and Pester?
size + data
格式。这就是复杂性的由来。首先,size 可以是任何整数(实际上,它不可能超过 2 字节,但是从原则上来说是可以的,因此你必须确保能够支持超过 2 字节的 size)。我们如何知道 size 部分在哪里结束,data 部分在哪里开始?-
在大多数情况下,开头会加上一个 header。这个 header 是一个值 h
,然后再加上 size 值:因此,RLP 编码是[length(data)+h] [data]
-
如果 length(data)+h < 256
,则 RLP 编码如上所示。如果数据太大,加上h
值后超过一个字节,该怎么办?没错,你还需要再增加一个字节,即,引入h'
值来表示你正在使用第二种存储方案。在这种情况下,RLP 编码是[h'+length(length(data))] [length(data)] [data]
。为 “方便” 起见,h'
被选定为 56。 -
如果数据大小为一个字节,你发现自己必须在这个字节前再增加一个字节。有没有可能不这样做?部分情况下可以,但是会另外增加复杂程度!如果 data[0]< h
,那就不需要增加 header。相应地,任何以小于h
的值作为开头的字节负载必定只有一个字节。
-
字节数组:header=128,overflow_header=183 -
结构列表:header=192,overflow_header=247
默克尔化规则(Merkelization rule)
叶子节点及其十六进制前缀
(key, value)
,这就是一个包含两个元素的列表,包含了 key
和 value
,两个数据都是字节数组(byte array)。RLP 理论上应该能帮助我们编码这两个数据吧?不那么见得。


RLP(HP(key_chunk), value)
的形式来编码的。分支节点和太小的子节点
128
来标注一个长度为 0 的数组)。世界上,列表中还有第 17 个条目,就是分支节点本身的值,但因为实践中都不使用它,所以列表的最后一个条目总是 128
。128
),反而常常找到另一个列表开始的标记(192
),又给开发者出了很多难题。延伸节点
我们真的需要 RLP 吗?
rlp < 32 bytes
这条规则,需要多占用多少存储空间呢?
二进制 trie:送 RLP 入土为安
-
左子节点哈希值,用作指针; -
右子节点哈希值,用作指针; -
值(可选),即存储在用于寻得此节点的键中(stored at the key used to get to this node)的值 -
前缀(可选),目的是替换十六进制 trie 中的延伸节点


-
如果 #7 bit 为有,则此 header 后面所跟随的数据的前 32 个字节即是左子节点的哈希值。如果该比特为空,则左子节点的哈希值也为空。 -
如果 #6 bit 为有,则跟着的 32 个字节表示右子节点的哈希值。如果该比特为空,则右子节点的哈希值也为空。 -
如果 #4 bit 为有,则该 header 会有一个额外的字节来给出前缀比特中的数字;前缀比特则跟着 左/右 子节点哈希值放置; -
如果 #5 bit 为有,则 header 后载荷剩下的字节就用来表示该值
结论
(完)
(文内有许多超链接,可点击左下 ”阅读原文“ 从 EthFans 网站上获取)
原文链接:
https://medium.com/@gballet/structure-of-a-binary-state-tree-part-1-48c587836d2f
作者: Guillaume Ballet
作者:以太坊爱好者;来自链得得内容开放平台“得得号”,本文仅代表作者观点,不代表链得得官方立场凡“得得号”文章,原创性和内容的真实性由投稿人保证,如果稿件因抄袭、作假等行为导致的法律后果,由投稿人本人负责得得号平台发布文章,如有侵权、违规及其他不当言论内容,请广大读者监督,一经证实,平台会立即下线。如遇文章内容问题,请发送至邮箱:linggeqi@chaindd.com
链得得仅提供相关信息展示,不构成任何投资建议
评论(0)
Oh! no
您是否确认要删除该条评论吗?