织梦CMS - 轻松建站从此开始!

我的网站

当前位置: 主页 > 竞争币 > 以太坊

五分钟简述以太坊 Geth 客户端快照加速机制

时间:2020-07-23 17:03来源:未知 作者:admin 点击:
Geth 的快照加速结构将状态读取的复杂性降低了一个数量级,代价是参与主网的节点需要 9~10 小时来建构初始快照。 原文标题:《干货 | 了解 Geth 客户端:快照加速机制》 撰文:Pét
Geth 的快照加速结构将状态读取的复杂性降低了一个数量级,代价是参与主网的节点需要 9~10 小时来建构初始快照。

原文标题:《干货 | 了解 Geth 客户端:快照加速机制》
撰文:Péter Szilágyi
翻译:阿剑

本文为 Geth 客户端有问必答系列的第一篇文章,大家可以就 Geth 客户端的问题踊跃提问,我会每周用一篇小文章回答得票最高的问题。本周呼声最高的问题是:你能说说 flat 数据库结构与 legacy 结构的主要区别吗?

以太坊的状态

在深入了解加速结构(acceleration structure)之前,我们先回顾一下以太坊的 「状态」 概念、状态在涉及到不同层次的抽象时又是如何存储的。

以太坊有两种不同类型的状态:账户的集合;每一合约账户存储槽的集合。从 完全抽象的角度 来看,两种数据都是 键-值 对。账户集合把地址映射到该地址的 nonce、余额,等等。而一个合约的存储领域把任意的值(由该合约定义并使用)映射到某个值。

但糟糕的是,虽然把这些键值对存储成扁平数据(flat data)可以非常高效,但验证它们的正确性在计算上就会变得很难。每当对数据修改时,我们都要自下而上对所有数据做哈希运算。

为免去总是对整个数据库做哈希运算的需要,我们可以把数据库分割成连续的小片,然后建立出一种树状结构!最原始、最有用的数据就放在叶子节点上,然后树上每一个内部节点都是该节点以下内容的哈希值。如此一来,当我们要修改某些值时,就只需做对数次的哈希运算。这种数据结构其实有一个路人皆知的名字,就是 「默克尔树」。

但还没完,这种办法在计算复杂性上还是有所欠缺。默克尔树结构虽然在修改现有数据时非常高效,但是,如果插入数据和删除数据会更改底层小数据块的边界,那就会让所有已经算好的哈希值全都变为无效。

这时候,与其盲目地对数据库分组,我们可以使用键本身来组织数据、基于共同前缀将数据都安排到树状格式中!这样插入和删除操作都不会影响到所有节点,只会影响到从树根到叶子路径上的(对数个)节点。这种数据结构就叫 「帕特里夏树」。

把上面两种办法合在一起 —— 帕特里夏树的树状分层和默克尔树的哈希算法 —— 就是所谓的 「默克尔-帕特里夏树」,也是实践中用于代表以太坊状态的数据结构。无论是修改、插入、删除还是验证,都只有对数复杂度!唯一的小小例外是,有些键会在插入前做哈希运算(存入树中),以平衡整棵树(A tiny extra is that keys are hashed before insertion to balance the tries)。

以太坊的状态存储

上文解释了为什么以太坊要用默克尔帕特里夏树结构来存储其状态。遗憾的是,虽然所需操作的速度都很快,但每一种选择都有所牺牲。更新操作和验证操作的对数复杂性 意味着对 每一个单独的密钥 的读取和存储都是对数复杂的(logarithmic reads and logarithmic storage)。这是因为树状结构的每一个内部节点都要单独保存在硬盘上。

此时此刻,账户树的深度确切是多少我不知道,但在大约一年以前,账户状态就已填满了 7 层高的树。这就意味着,每一次树操作(例如读取余额、写入 nonce)都要触达至少 7~8 个内部节点,因此会做至少 7~8 次持久数据库访问(persistent database accesses)。LevelDB 组织数据时最多也是 7 层,所以还有一个额外的乘数。最终的结果是,单次 状态访问预计会放大为 25~50 次随机的 硬盘访问。你再乘上一个区块中的所有交易的所有状态读取和写入,你会得到一个 吓人 的数字。

[当然,所有客户端实现都在尽力降低开销。Geth 使用更大的内存区域来缓存数节点;还使用了内存内的修剪机制、避免将几个块之后就会删除的数据写入硬盘。不过这需要另外一篇文章才能讲清楚。]

可怕之处还在于,这个数字就是运行一个以太坊节点、保证能全时验证所有状态的成本。

我们能做得更好一点吗?

并不是所有访问都要一视同仁

以太坊的运行依赖于对状态的密码学证明。只要我们还想保持对所有数据的验证能力,就绕不开硬盘读写放大问题。也就是说,我们 ——可以并且也事实上 —— 相信我们已经验证过的数据。

不断重复验证每一个状态物是没有意义的,但如果每次从硬盘中拉取数据都要验证一次的话,就是在做这样没有意义的事。默克尔帕特里夏树结构本质上是为写入操作设计的,但反过来就成了读取操作的负担。我们摆脱不了它,也无法让它瘦身,但 这绝不意味着 我们在每一个场合都必须使用它。

以太坊节点访问状态的场景可大致分为以下三类:

  • 在导入一个新区块的时候,EVM 代码的执行会产生或多或少基本平衡的状态读取和写入次数。不过,一个用于拒绝服务式攻击的区块可能会产生远多于写入操作的读取操作次数。
  • 当节点运营者检索状态的时候(例如调用 ethcall 及类似操作),EVM 代码执行仅产生读取操作(当然也可能有写入操作,但这些操作产生的数据最终会丢弃掉,不会持久化到硬盘里面)。
  • 当节点在同步区块链的时候,同步者会向远程节点请求状态,被请求者会将数据挖掘出来并通过网络传播给同步者。
  • (责任编辑:admin1)
织梦二维码生成器
顶一下
(0)
0%
踩一下
(0)
0%
------分隔线----------------------------
发表评论
请自觉遵守互联网相关的政策法规,严禁发布色情、暴力、反动的言论。
评价:
表情:
用户名: 验证码:点击我更换图片
栏目列表
推荐内容