欢迎光临
我们一直在努力

Symbol账号状态验证

在 Symbol 公共网络上,有一个独特的功能叫做状态证明(state proofs)。这个功能没有足够详细的描述,所以大多数用户不明白这个功能提供了什么。

状态证明(state proofs)允许向第三方证明,在高度X时,您的帐户状态(或马赛克状态、命名空间状态或任何其他状态)等于Y。

这里有一个小问题:目前还没有简单的方式通过API获取给定高度的状态,因此假设状态保存在所需的高度。最好的部分是这种状态可以由验证者以一种不受信任的方式进行验证。

序列化状态

状态内部是什么?简而言之就是:“可能太多了”。但让我们潜入。

让我们在 Symbol 测试网上看看这个帐户:TAKUOCDJH4KUDYP7ZH5HMW43QXYXTLFEDQUR4MI

可以通过请求/accounts/<account-id>获取帐户信息,看起来像这样:

{
 "account": {
    "version": 1,
    "address": "98154708693F1541E1FFC9FA765B9B85F179ACA41C291E31",
    "addressHeight": "119481",
    "publicKey": "13182CF21C0C13BA3FB5401EEED94D274C4305A54017ABCA7CDDEB85A173F765",
    "publicKeyHeight": "119490",
    "accountType": 0,
    "supplementalPublicKeys": {},
    "activityBuckets": [],
 "mosaics": [
  {
    "id": "091F837E059AE13C",
    "amount": "8539426394"
  }
 ],
    "importance": "0",
    "importanceHeight": "0"
 },
 "id": "<node-based, not important>"
}

目前(symbol python core-sdk)不允许账户状态的序列化,但是账户状态在里面有它的定义(catbuffer-schemas)。所以让我们做一些手动数据序列化

上面的帐户的重要性为0,这意味着这不是一个高价值的帐户,这使事情更容易。

在检查帐户状态之前要做的最后一件事是计算序列化数据的 sha3 哈希值。

010098154708693f1541e1ffc9fa765b9b85f179aca41c291e31b9d2010000000000
13182cf21c0c13ba3fb5401eeed94d274c4305a54017abca7cddeb85a173f765c2d2
0100000000000000000001003ce19a057e831f095a4efdfc01000000

sha3 帐户状态的结果哈希值是:

9532475d9217848ca629e690c89470f18c95497d8913233e74fa32b802b3c5d5

检验哈希树的状态

在Symbol(Catapult)白皮书的第4章中,对 Merkle 树进行了详细的描述,本文不再赘述。

让我们查询这个账户的当前 Merkle 树路径。REST API 端点(传递视图状态):/accounts/<account-id>/merkle,反之如下:

View State Transfer (REST API) 以“原始格式”返回 Merkle 树,因此您需要使用更易于处理的解析器来处理此问题。

Merkle 树的反向路径从树的顶部到底部。检查可以在任何方向 – 从下到上或从上到下。渲染后,Merkle 树将如下所示:

让我们从一条路径开始。路径只是一个密钥的哈希值。在帐户状态缓存的情况下,密钥只是帐户地址。因此,对于账户TAKUOCDJH4KUDYP7ZH5HMW43QXYXTLFEDQUR4MI,路径是:

>>> sha3_256(unhexlify('98154708693F1541E1FFC9FA765B9B85F179ACA41C291E31')).hexdigest()
E220E4E4BCF533F0E0082F28E65B8EA5A278D255DB22D61D097A2F9008676F3A

树中的每个分支可能都包含非空路径,但在上面的示例中,它总是空的,因此从上到下,必须从帐户路径中获取适当的半字节(半字节称为半字节)。按顺序:E,2,2,0,所以“剩余”路径是:

E4E4BCF533F0E0082F28E65B8EA5A278D255DB22D61D097A2F9008676F3A

注意:如果无法使用正确的分支从上到下遍历树,则表示树已被修改。

现在您可以很容易地看到,具有所需哈希值(“type”:255)的叶子的值等于之前计算的 sha3 散列。这意味着已经进行了一次检查。

{
 "type": 255,
 "path": "E4E4BCF533F0E0082F28E65B8EA5A278D255DB22D61D097A2F9008676F3A",
 "encodedPath": "20E4E4BCF533F0E0082F28E65B8EA5A278D255DB22D61D097A2F9008676F3A",
 "nibbleCount": 60,
 "value": "9532475D9217848CA629E690C89470F18C95497D8913233E74FA32B802B3C5D5",
 "leafHash": "39D61E874BE3A301D1FEE4DDA1D2F6D53030004A51E6399BFB6F58EE35218EC4"
}

现在,验证器需要做的是检查所有的哈希值。让我们从头开始,因为这样会更容易。

leafHash是级联的encodedPath(*)和value的哈希值,因此:

* 如何摆脱编码路径超出了本文的范围,好奇的读者应该看看Symbol 白皮书中的第 4 章。

>>> sha3_256(unhexlify('20E4E4BCF533F0E0082F28E65B8EA5A278D255DB22D61D097A2F9008676F3A') + 
unhexlify('9532475D9217848CA629E690C89470F18C95497D8913233E74FA32B802B3C5D5')).hexdigest()
39D61E874BE3A301D1FEE4DDA1D2F6D53030004A51E6399BFB6F58EE35218EC4

耶!匹配。
将我们带到此叶的路径半字节的值为0。这意味着第4级第0个元素的“link”必须等于该哈希值,而且确实是这样。

以类似的方式,branchHash-是给定级别的concated encodedPath和所有链接的哈希值。如前所述,缺少的元素必须用00哈希填充。所以对于第4级,encodedPath等于’00’,这给了我们:

>>> zero = unhexlify('00000000000000000000000000000000000000000000000000000000000000')
>>> sha3_256(unhexlify('00') + u('39D61E874BE3A301D1FEE4DDA1D2F6D53030004A51E6399BFB6F58EE35218EC4') + 
zero * 3 + unhexlify('6A69ADA0538FC9582D813619288B400038286522206FEA14D231F0D9775900E3') + zero * 11)
.hexdigest()B1508023DFF34155479B81C93EE43926F590E59E0CEA66F4633D5929B809AC34

您也可以在此处查看。您可以检查它是否与级别 4 的分支哈希匹配。

导致我们得到这个结果的路径是在第 2 级,第 3 级的链接位置 2 对应于计算出的哈希值。

现在我们需要重复这个过程,我将插入一个工具来计算 BranchHash 的正确哈希:

计算出的根哈希值(Root Hash):

B6B9F48079B27914FFE030B8CBBE6C81ED30FEB4E007946962C4283CBD99C581

最后,验证程序可以检查计算出的哈希是否与该具体高度处的状态树哈希匹配,对于该具体高度,可以获得merkle树路径:

http://explorer.testnet.symboldev.network/blocks/173056

现在,使用快捷方式,我们链接到 Symbol 区块浏览器,但为了不信任链接,验证器必须收集所有区块头,只有头本身,您不需要实际检查它们的内容。因此,检查这个区块中账户状态的哈希值是否真的与计算出的哈希值匹配就足够了。

总结

证明提供:

  • 账户状态
  • 到给定高度的 Merkle 树的路径

验证器:

  • 序列化帐户的状态,
  • 沿着 Merkle 树的路径检查序列化状态
  • 根据块头检查状态根的哈希值

原文链接:

https://ncosigimcitynre.medium.com/verifying-symbol-account-state-proofs-for-fun-and-profit-part-1-3dfedfc19cb4

评论 抢沙发