通告 | Geth v1.10.0
编者注:这篇文章是 Geth 团队撰写的 Geth 1.10.0 大版本更新公告。文章很长,有 9000 多字,但是值得每一个关心以太坊的长期前景的人细细阅读。从中我们可以看到,一个为整个以太坊生态开发最基础的基础设施的工程师,如何理解自己的工程目标、如何发现瓶颈,以及如何理解自身在整个生态中的角色。
Geth v1.9.0 发布已一年半有余。在这期间,我们确实发布过 26 个版本(大约 3 周一次),但是主要版本发布总是更特殊一些。我的心情很微妙:一方面,新功能上线令我兴奋不已,另一方面,我又担心会出现重大失误。无论如何,以太坊正在发展,我们需要突破极限,跟上它的步伐。
言归正传,让我们欢迎 Geth v1.10.0 加入以太坊大家族。
风险提示
在详细介绍最新版本之前,我们有必要强调一下:任何新功能的推出总伴随着新的风险。为了满足风险状况不同的用户和项目的需求,许多重要功能(暂时)可以单独开启或关闭。无论你想要阅读这篇文章的所有内容,还是只阅读你感兴趣的部分,请不要略过文末的 “兼容性” 一节。
接下来,就让我们来看看 Geth v1.10.0 究竟有哪些特性!
柏林硬分叉
首先要声明一点。Geth v1.10.0 尚不可用于柏林硬分叉,因为 Solidity 团队担心 EIP 2315 最后会出现变数。由于v1.10.0 是大版本,我们不想让发布时间太接近柏林分叉。我们很快就会发布 v1.10.1,加入最终的 EIP 及相关区块编号的名单。
快照
我们一直在说快照加速(中文译本),说了很久了,现在终于出现在新发布版本中,我们心中也五味杂陈。本文不会涉及太多细节(见上面的超链接),快照(snapshot)是基于以太坊状态的加速数据结构,可大大加快读取 账户和合约存储项的速度。
具体来说,快照功能可以将访问账户的成本从 O(logN) 降低至 O(1)。乍看之下,这可能不是很多,但是在实际情况下,假设主网上有 1.4 亿个账户,快照可以为每次账户读取节省大约 8 次数据库查询。这几乎将磁盘查询量减少了一个数量级,确保其成为与状态大小无关的常量。
哇偶,这是不是说我们可以将 gas limit 提高 10 倍?很遗憾的是,不能。虽然快照确实能将读取性能提高 10 倍,但是 EVM 执行还需要写入 数据。数据写入需要经过默克尔验证。考虑到默克尔证明,磁盘写入的成本必须是 O(logN)。
既然如此,这又有什么意义呢?!虽然加快账户和合约存储的读取速度并不足以提高 gas limit,但它确实解决了一些棘手的问题:
DoS。在 2016 年,以太坊遭受了有史以来最严重的 DoS 攻击(“上海” 攻击),持续了大约 2 至 3 个月。这次攻击通过以太坊状态膨胀以及滥用各种gas 定价过低的操作码来导致以太坊网络瘫痪。经过无数次客户端优化和硬分叉再定价之后,这次危机才得以平息。但是问题的根源依然存在:状态访问操作码有着固定的 EVM gas消耗量 O(1)
,但是执行成本O(logN)
是缓慢增加的。我们已经通过 “橘子口哨”(Tangerine Whistle)、“伊斯坦布尔”(Istanbul)以及即将到来的 “柏林”(Berlin)分叉状态操作码的 gas 消耗量,让 EVM 成本(名义开销)与运行时成本更加一致,但这些都只是权宜之计。快照可以将状态读取的执行成本降低至O(1)
(使之与 EVM 成本更加一致),从而长期解决基于状态读取的 DoS 问题(请勿在他处引用这句话)。调用。检查以太坊上智能合约的状态需要一次微 EVM 执行。一方面是运行字节码,另一方面是从磁盘中读取状态插槽。如果你运行了一个只供自己使用的以太坊节点,当前的状态访问速度应该绰绰有余。如果你运行一个供多名用户使用的以太坊节点,快照所带来的 10 倍性能提升可以让你以同样的成本完成 10 倍数量的查询。 同步。同步以太坊节点的方法主要有两种。你可以下载区块并执行区块中的所有交易。或者,你可以下载区块,验证其 PoW 证明,并下载与最新区块相关的状态。后者要快得多,但是需要通过其它节点获取最新状态的副本。在当前的 Merkle-Patricia 状态模型中,这些节点需要从磁盘上读取 16TB 的数据,才能满足节点同步需求。有了快照之后,这些节点只需从磁盘中读取 96GB 的数据,就能让新的节点加入网络。欲知更多详细信息,请阅读快照同步 部分。
快照就是 Merkle Patricia trie 的叶节点中已经包含的原始以太坊状态的冗余副本。目前,快照在主网上额外需要大约 20 至 25 GB 的磁盘成本。好在,快照有望让我们进一步实现状态存储优化,并降低当前 Merkle trie 的磁盘成本。 由于目前还没有人在网络中构建快照,节点最初需要自行承担迭代状态 trie 以及创建初始快照的开销。根据你的节点的负载,这可能需要耗时一天至一周,但是(一切顺利的话)每个节点在整个生命周期内只需完成一次。快照创建是在后台运行的,与其它节点操作同时执行。我们的计划是,当全网节点都可获得快照时,就不再要求节点迭代状态 trie 并创建初始快照。预知详情,请阅读快照同步 部分。
--snapshot=false
在 Geth 1.10.0 中禁用该功能,但是请注意,未来我们将强制启用该功能,以保证网络的基准健康度。快照同步
完全同步是信任最小化的,选择执行从创世块到链首块之间的所有事务。虽然这可能是最安全的模式,但是以太坊主网目前有超过 10.3 亿笔事务,而且每天会新增 125 万笔。另外,这也意味着,完全同步的成本永远都在增加。目前,一台性能优秀的计算机也需要 8 到 10 天才能处理完所有事务。 快速同步选择依靠 PoW 的安全性。快速同步无需执行所有事务,而是认为如果某个区块后面跟着 64 个拥有有效 PoW 的区块,那么对于作恶者来说,从这个区块开始分叉的成本太高。因此,下载与 HEAD-64
相关的状态不会有太大问题。快速同步信任较新区块的状态根,可以直接下载状态 trie。如此一来,该模式放低了对 CPU 和磁盘 IO 的需求,提高了对网络带宽和延迟的需求。具体来说,以太坊主网目前有大约 6.75 亿个状态 trie 节点。一台网络连接良好的计算机需要 8 至 10 小时才能下载完成。
你的网络连接高于平均水平 有足够数量的对等节点提供数据 你的对等节点只为你提供数据
无需下载中间的 Merkle trie 节点,即可批量获取状态数据,从而解决因网络延时而导致的延迟问题。 无需下载 Merkle 节点,下行数据减少一半;无需单独处理每单位数据,上行数据变得无关紧要,从而解决因带宽而导致的延迟问题。 无需请求按照随机键值对排序的数据,对等节点仅执行几次连续的磁盘读取来作出响应,从而解决因磁盘 IO 而导致的延迟问题(在对等节点已经以扁平的格式存储数据的情况下)。
压缩同步依赖于每 3 万个区块创建的静态快照。这意味着,作为数据提供方的节点需要每 5 天左右重新生成快照,但是迭代整个状态 trie 实际上可能需要花费更多时间。也就是说,warp sync 不具备长期可持续性。快照同步则依赖于动态快照。无论多慢,动态快照只需生成一次,然后就会随着区块链的增长保持动态更新。 压缩同步的快照格式没有采用 Merkle trie 的结构,因此无法 单独验证每个压缩数据块。同步节点需要先下载整个 20+ GB 数据集,才能对其进行验证。因此,从理论上来说,压缩同步模式对节点来说并不方便。相比之下,快照同步的快照格式是连续的默克尔树叶节点,支持验证任意大小的数据块,因此可以立即发现不良数据。
时间 | 上传 | 下载 | 数据包 | 磁盘读取 | |
---|---|---|---|---|---|
快速同步 | 10 小时 50 分钟 | 20.38GB | 43.8GB | 1607M | 15.68TB |
快照同步 | 2 小时 6 分钟 | 0.15GB | 20.44GB | 0.099M | 0.096TB |
-80.6% | -99.26% | -53.33% | -99.993% | -99.39% |
请注意,Geth v1.10.0 已经上线快照同步功能,但是尚未启用。原因是,快照同步要求节点必须创建快照加速结构,但是目前还没有节点这么做,因为快照加速结构功能也是 Geth v1.10.0 推出的。你可以通过 --syncmode=snap
手动启用快照同步,但是我们预期要等到柏林硬分叉过去几周后才能找到合适的对等节点。等我们觉得有足够多的对等节点采用快照同步功能时,我们将默认启用该功能。
离线 “剪枝”(pruning)
geth snapshot prune-state
。删除事务索引
0xdeadbeef
位于区块 N
。这是很庞大的数据量,而且需要查询很多数据库条目。如果你想查询 6 年前的事务,存储 36 GB 的数据并非难以接受。但是实际上,绝大多数用户都不想。对于他们来说,额外的磁盘使用量和 IO 开销都是在浪费资源。请注意,事务索引并非共识的一部分,也非网络协议的一部分。它们纯粹是在本地创建的加速结构。N
个区块内的事务能被索引到,之前区块内的事务都会被删除。如果有用户想要访问之前的事务,可以设置较高的 --txlookuplimit
值,并重启 Geth,然后原本不在查询范围内的事务将重新被索引(请注意,必须等到下一个区块才会触发)。--txlookuplimit=0
。这样一来,你的节点就会像之前那样保留自创世块以来每笔事务的映射,以便查询。原像丢弃
Keccak256
哈希值。这有助于平衡状态 trie 的分支深度。使用哈希值作为键是可行的,因为以太坊用户只会引用原地址,这些原地址可以随时进行哈希计算。--cache.preimages
保留之前的设置。请注意,事后无法再生成原像。如果你在禁用原像采集功能的情况下运行 Geth,却又改变了主意,你需要重新导入区块。ETH/66 协议
eth/66
协议是很小的改动,但是带了很多好处。简而言之,该协议为所有双向数据包引入了请求与应答 ID。这些 ID 的目标是,降低响应与请求之间的配对难度,以便将响应传递给发出原始请求的子系统。eth/66
协议的重要性并不在于它能解决某个特定问题,而在于它是在柏林分叉前引入的。由于所有节点都将在分叉时进行升级,这就意味着 Geth 可以在分叉后开始弃用旧协议。只有等到所有旧协议弃用后,我们才能重写 Geth 的内部结构,以利用请求 ID。按照我们的协议弃用计划表,我们将很快弃用eth/64
,并在今年夏末弃用eth65
。eth/xy
协议,其它客户端要求将该功能加入旧的协议版本(译者注:此处应指 eth/66 之前的此类协议,如 eth/64),以免不得不将全部精力集中在联网组件上。最终达成的协议是,Geth 将 typed transaction 功能向后移植到之前协议的代码中,为其他开发者争取时间,但是作为交换条件,Geth 将在 6 个月内淘汰旧版本,以免停滞不前。ChainID 执行措施
abigen
生成的代码,我们已经在 go-ethereum
代码库中加入了额外的签名建构器,可以容易地创建锁定了链 ID 的事务。遗存的那个开箱即用的签名器是在 EIP155 实施之前编写的,所以现在你要自己构筑受保护的签名。这很容易出错,而且用户会假设我们能在内部预测好链 ID,所以我们决定引入直接的 API。我们会在未来弃用并移除当前遗存的签名器。--rpc.allow-unprotected-txs
来接收非 EIP-155 的事务。请注意,这只是暂时的。最终我们会移除这个机制。标签弃用
--rpc
->--http
,开启 HTTP-RPC 服务器--rpcaddr
->--http.addr
,HTTP-RPC 服务器监听接口(listeninginterface)--rpcport
->--http.port
,HTTP-RPC 服务器监听端口(listeningport)--rpccorsdomain
->--http.corsdomain
,接受请求的域--rpcvhosts
->--http.vhosts
,接受请求的虚拟主机名--rpcapi
->--http.api
,通过 HTTP-RPC 接口提供的 API--wsaddr
->--ws.addr
,WS-RPC 服务器监听接口--wsport
->--ws.port
,WS-RPC 服务器监听端口--wsorigins
->--ws.origins
,接受 websockets 请求的 Origins--wsapi
->--ws.api
,通过 WS-RPC 接口提供的 API--gpoblocks
->--gpo.blocks
,检查相应区块号区块的 gas price(Number of blocks to check for gas prices)--gpopercentile
->--gpo.percentile
,按近期事务的百分比提供 gas 建议--graphql.addr
->--graphql
,在 HTTP-RPC 服务器上开启 GraphQL--graphql.port
->--graphql
,在 HTTP-RPC 服务器上开启 GraphQL--pprofport
->--pprof.port
,分析器的 HTTP 服务器监听端口--pprofaddr
->--pprof.addr
,分析器的 HTTP 服务器监听接口--memprofilerate
->--pprof.memprofilerate
,按给定比率开启内存分析--blockprofilerate
->--pprof.blockprofilerate
,按给定比率开启区块分析--cpuprofile
->--pprof.cpuprofile
,向给定文件写入 CPU 分析
--nousb
来关闭 USB 功能。为迎合大部分人的默认需求,Geth v1.10.0 会默认禁用 USB 钱包支持,并取消 --nousb
标签。你仍然可以使用 USB 钱包,只不过要手动使用 --usb
。跟踪突然关闭
WARN [03-03|06:36:38.734] Unclean shutdown detected booted=2021-02-03T06:47:28+0000 age=3w6d23h
兼容性
--snapshot=false
,禁用快照加速结构和快照同步功能--txlookuplimit=0
,确保为主链上所有的交易建立索引(而不是仅为过去一年的交易建立索引)--cache.preimages
,保持生成及保存账户的原象--rpc.allow-unprotected-txs
,以允许非重放保护的签名(non-replay-protected signatures)--usb
,以重新启用 USB 钱包支持
eth_protocolVersion
API 调用已经删除,因为没有用处。如果你能充分说明为什么需要这个功能,请联系我们。结语
源代码、git 标签等,见 GitHub 软件版本发行页 适用于所有平台的、预构建的二进制文件,见下载页 Docker 镜像,见 ethereum/client-go
Ubuntu 安装包,见 Launchpad PPA repository OSX 安装包,见 Homebrew Tap repository
原文链接: https://blog.ethereum.org/2021/03/03/geth-v1-10-0/
作者: Péter Szilágyi
翻译&校对: 闵敏 & 阿剑