加载中 ...

干货 | 以太坊无状态客户端初探

2019-05-15 00:46 编辑:btc268.com 来源:区块链资讯

  自从看到了这篇文章,我便一直很想深入了解以太坊的无状态客户端。当然,经过 15 个月的摸索,我对以太坊中的状态、软件、网络的认知都发生了很大的变化,比如说,我现在认为要引入无状态客户端,则硬分叉在所难免;这与我之前的想法不同。但即便如此,我还是很高兴能分享一些学习上的收获,并给出后续发展建议。

无状态客户端的思想

  在阐述无状态客户端之前,我们先来看看在以太坊客户端软件中一般的交易处理过程:

  

  在区块中执行交易需要交易数据(蓝色矩形所示),及当前状态(黄色矩形所示);执行结束后,原本的当前状态变为历史状态,同时产生新的当前状态。处理交易可能还需要一些别的数据(如区块时间戳,或是前个区块哈希值),但我们先忽略这些大小固定且无关紧要的部分。执行交易还会产生明细(receipt)(绿色部分),但在讨论无状态客户端时也可暂时忽略。

  无状态客户端的核心思想是:在区块中执行交易过程时,不访问整个状态。区块创建者以分离的数据结构作为区块补充,里面提取了执行交易所需的所有状态;为了让执行交易的人相信这些额外数据的确来自当前状态,还要附上默克尔证明。这是可以做到的,因为每个区块头都带有 “状态根”,这个默克尔树根凝结了区块内交易执行完成后所有的状态值。有了这些证明,我们能够以下面这种形式执行交易:

  

  值得一提的是,这些区块信息(我们称之为 “区块证明”)对于有状态客户端(那些想要保有全部状态和历史数据的客户端)来说也是非常有用的。当前情况下,所谓的 “全节点” (在接收到区块时)会依凭本地保存的状态执行区块交易,计算新状态的默克尔根并验证是否与区块头的默克尔树根相同(译者注:以此验证新区块的合法性)。计算默克尔树根需要大量的计算资源,包括大量内存以及大量 I/O 读写,详细的描述见此。如果拥有前面的补充信息,全节点验证执行过程的正确性会变得非常容易,大部分情况下将不需要涉及读写操作,就能够基于执行结果更新当前和历史的状态数据库;全节点无需缓存状态树,与当前状态和历史状态数据库的交互转为以写入为主。具体过程如下:

  


区块证明占多大空间?

  无状态客户端最大的缺点是——除了区块,还需要在网路中传输一些额外的数据(区块证明)。究竟这些额外的数据有多少呢?为了计算区块证明的大小,我基于 Turbo-GETH 创建了一个无状态客户端原型,以下是它做的事情:

  从以太坊主网逐一收集区块

  对每一个区块分别抽取出交易需要访问的状态,以及被交易访问的智能合约字节码

  (通过计算状态默克尔树根)选取出足以验证所提取状态确实属于状态的最少哈希值集合

  添加一些结构信息,将上述证明(哈希值集合)和状态抽取物编码为树型结构。可能采用的编码方式不是最好的,不过结果表明编译出来的输出远小于其他部分,所以可接受。

  将区块证明编码为字节数组。

  将字节数组解码出区块证明(即那个树型结构的数据,一些节点来自于状态,一些则是无关状态部分的哈希值)。

  再次执行区块,不过这回不访问当前状态,而是直接与区块证明进行交互。

  验证状态根和所有存储根的正确性。

  整个流程花了不少时间,但我希望得到的数据足够精确。如我所料,虽然这个原型已经能处理许多琐碎的问题(因为 hexary 的默克尔帕特里夏树包含叶节点、扩展节点、嵌入节点等等复杂的结构),还是有一些罕见情况导致我的原型报错(在区块 5340939、5361803、5480357、5480507、5480722、5632299、5707052、5769636 ...... );不过考虑到 670 万个区块中只出现数十个报错,我有信心这些小问题不会影响数据分析的结果(当然,我会尽快 debug)。

  目前我的数据只采集至第 6757045 个区块,但我想很快就能超过这个数字。

  第一张图表表示区块证明的总体量(注:所有图表都经过窗口 = 1024 的移动平均计算)。

  

  在伪龙硬分叉(区块 2675000)之前,少量的 gas 消耗也可能产生非常大的区块证明, 这个缺陷已经在 2016 年秋天被修复。

  下面我们只看伪龙硬分叉后至今的数据表现:

  

  为了清除余额和 nounce 值为零的账户状态,伪龙硬分叉后进行 “状态清理”,导致图表最左侧 “峰值” 的出现。但 2017 年下半年,以及 2018 年的 “区块证明” 的规模已经超过了当时的水平。

分解

  首先,我们将区块证明分解为三个部分:1)所有与 “主” 状态树有关的部分;2)所有与合约存储树有关的部分;3)智能合约字节码。

  

  可能从图上有点看不清楚,不过可以看到 2016 年发生的垃圾攻击造成当时的字节码(红线)和 “主” 状态树的区块证明(黄线)激升。有些人还记得,当时对于智能合约的字节码大小并没有限制(现在限制小于 24k),造成当时能够部署超大的智能合约,并通过 EXTCODESIZE 之类的函数进行查询。

  

  实施伪龙硬分叉后的图表表明,主默克尔树的区块证明在过去大部分时候体量占比较大,不过合约存储证明(蓝线)和字节码随后开始赶上。

分解状态树区块证明

  这里我们会进一步将状态树区块证明分解为四个部分。前两部分是交易需要读取的键值对,或者是为了满足默克尔帕特里夏树的一些特殊需求所需的数据。

  

  看起来状态清除操作对于读取键值对还是造成很大的影响。我们会发现键值对中值的大小(一般是 80 字节)通常比键要大得多( key 一般小于 64 字节,而我刚刚才意识到键可以被压缩,因为我把每个十六进制数都算为一个字节

关键词:比特币新闻 币牛牛

转载自比特币新闻网(www.btc268.com),提供比特币行情走势分析与数字货币投资炒币最新消息。

原文标题:干货 | 以太坊无状态客户端初探

原文地址:http://www.btc268.com/ytf/xw/11484.html

本文来源:区块链资讯编辑:btc268.com

本文仅代表作者个人观点,与本网站立场无关。

本网站转载信息目的在于传递更多信息。请读者仅作参考,投资有风险,入市须谨慎!

'); })();