我们看到的是最新的等级库,它没有太多的背景信息或关于SSZ试图实现的目标的解释。SSZ的主要目标是什么?
它的序列化和Merkleization优势的示例将非常有用,因为这可能是一个典型的问题。
发布于 2020-04-01 06:14:13
SimpleSerialize (SSZ)是Eth2中使用的标准序列化格式。SSZ规范指导读者如何执行两个不同的任务:
BeaconBlock或BeaconState)编码为可以通过网络发送或存储在数据库中的字节字符串。对于每一项任务,我都将说明目标(或我对它们的理解),并为其中的每一项任务树立榜样。
据我所知,从来没有关于SSZ目标的规范声明。然而,我认为公平地说,这些是其中的一些目标:
BeaconBlock。使用此属性,SSZ编码为该实例形成一个“标识”。我将提供一个简单的示例,并将读者推荐给@protolambda的SSZ编码图。
让我们假设这个虚构的数据结构,因为Eth2规范中没有一个结构适合这个示例:
class Example
id: uint64,
bytes: List[uint8, 64]
next: uint64Example有两个64位整数字段(id和next)和一个可以容纳0-64字节的bytes字段。让我们实例化它:
my_example = Example(id=42, bytes=List[0, 1, 2], next=43)现在,让我们看看serialize(my_example)的输出:
# serialize(my_example)
#
# Note: this is a single byte-array split over four lines for readability.
[
42, 0, 0, 0, # The little-endian encoding of `id`, 42.
12, 0, 0, 0, # The "offset" that indicates where the variable-length value of `bytes` starts (little-endian 12).
43, 0, 0, 0, # The little-endian encoding of `next`, 43.
0, 1, 2 # The value of the `bytes` field.
]正如我们所看到的,字段按照定义的顺序进行编码。“固定尺寸”项直接序列化到缓冲区中,而“变尺寸”项首先作为指向项目实际值开始的“偏移量”序列化。变量大小项的实际值(而不是偏移)是在所有固定大小的项和偏移量附加后追加的。
Eth2不只是使用块编码的简单SHA256哈希来标识它(例如,sha256(serialize(block)) )。相反,Eth2中的所有散列都是Merkle根。
决定在所有散列中使用Merkle是为了让轻量级客户端和执行环境可以使用Merkel-保护法来了解Eth2状态的部分内容。例如,如果轻型客户端具有某个块根的可信的32字节散列,我可以向该轻型客户端提供一个简洁的密码证明,即验证器n具有x的平衡。
然而,将Merkle用作规范散列的决定有很大的计算开销。灯塔中的同步瓶颈(我工作的客户端)正在执行这些Merkle。当一个简单的sha256(serialize(block))花费微秒时,其中一些例程需要几十毫秒(即慢数百万倍)。
因此,我认为Merkleization方案的目标是确保受限环境(轻型客户端、执行环境、eth1等)可以获得轻量级的证据,他们可以用来做重要的决定。
让我们使用前面的Example类型以及my_example实例化。同样,我建议使用@protolambda:SSZ散列树根与合并的图表。
为了帮助这个示例,我们定义了hash_concat(a, b),它返回a和b连接的SHA256散列。例如,hash_concat([1], [2]) == hash([1, 2])。
首先,我们确定了Example梅克尔树的叶子:
# id: little-endian 42, right-0-padded to 32 bytes.
leaf_0 = [42, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
# bytes: when a list is hashed, you first hash the list values (right-0-padded to the next multiple of 32) along with the little-endian encoding of the list length (aka., "mixing in the length").
leaf_1 = hash_concat(
[0, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[3, 0, 0, 0]
)
# id: little-endian 43, right-0-padded to 32 bytes.
leaf_2 = [43, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] 现在,我们将叶子散到Merkle树的中间层:
# Hash the concatenation of `id` and `bytes`.
node_1 = hash_concat(leaf_0, leaf_1);
# Hash the concatentation of `next` and a "zero leaf" (32 zero-bytes), since there is no fourth element.
node_2 = hash_concat(leaf_2, [0; 32])最后,我们可以用root = hash_concat(node_1, node_2)找到这棵梅克尔树的根。
最终,我们创建了一个嵌套的Merkle树,如下所示:
root
|
-----------------
/ \
node_1 node_2
| |
------ -----------
/ \ / \
id bytes_root next ZERO_LEAF
|
-------
/ \
bytes len(bytes) https://ethereum.stackexchange.com/questions/74005
复制相似问题