问:为什么 Geth 开发团队的压力如此之大,甚至到了超负荷的地步?
通过 etherscan,我们可以看到各个客户端的装机量所占份额的统计数据如下所示:
Geth: 75%
Parity & OpenEthereum: 20%
Nethermind: 1%
剩下 4% 由一些市场份额不到 1% 的客户端组成,因此忽略不计。
重要的是,有超过 51% 的算力都集中在 Geth 客户端上。假设在即将到来的柏林硬分叉中,Geth 在实现其中一个 EIP(以太坊改进提案)时出现了 bug 。即使这个客户端的其它实现都没出 bug ,只要有区块碰上了这个 bug ,就会导致以太坊网络分叉。按理来说,这个区块是无效的,其他客户端也会将其视为无效块。但是,有超过 51% 的挖矿节点都运行的 Geth 客户端,因此整个网络都会被带到错误的分叉链上去。
这就要求 Geth 客户端和开发团队 不能犯错。
因此, 问的答案是:
因为以太坊网络的客户端缺乏足够的多样性。
值得一提的是,客户端多样化不会突然将客户端开发变成一项轻松的工作。但客户端多样性本身依然是一个值得探索的领域,有助于我们找到提高客户端开发的效益,同时减轻开发团队负担的方法。不可否认的一点是,只在 Geth 团队上下功夫不太可能解决这个问题。
第二问:为什么以太坊网络缺乏客户端多样性?
以太坊主网上线时,我们有多个客户端。其中最主要的两个是 Geth 和 CPPEthereum 。之后又出现了 Parity ,CPPEthereum 被淘汰。
从那时起,除了 Parity 之外,没有一个客户端能获得较大的市场份额。去年,Nethermind 异军突起,成为了一颗冉冉上升的新星,但是目前只占据了 1% 的市场份额。最近,由于 Parity 遭遇了一些波折,前途一片黯淡,Parity 的市场份额大幅下降。我们认为,在理想情况下,以太坊网络需要有 3 个及以上的客户端、每个客户端占有的客户端份额都不至于太高、没有任何一个客户端能占据远远超过 51% 市场份额。虽然在理想情况下应该实现客户端多元化,但是我们已经习惯了客户端霸权的局面。
那么,我们为什么需要多个客户端?
从我个人的经验角度来看,构建以太坊客户端难比登天。Geth 之所以能在以太坊网络上稳定运行,是因为它引入了很多复杂的优化。Geth 团队花费了数年时间才达到了如此高的复杂度,目前仍在继续优化中。
有人可能会立即建议我们想办法为落后的客户端提供支持和帮助。我很警惕这种 “人月神话” 式的解决方案 —— 在软件开发过程中,让更多工程师来解决一个难题很少会成功,而且我不指望这种方案会取得成功。
相反,我认为应该将关注点放在复杂性上。
注:人月神话,mythical man-month,指出以大量人员和较短的时间,并不能缩短软件的开发进度。一窝蜂的作业方式无助于软件生产,且会制造麻烦,产生出更差的软件。向进度落后的项目追加人力,只会使进度更加落后。
第三问:为什么构建以太坊客户端会这么难?
现在,我们正越来越接近问题的根源。
事实证明,大部分困难都来自于组网协议(networking protocol),即以太坊客户端软件用于相互连接并分享区块链信息的那一组工具。以太坊的组网规则(定义在 devp2p 代码库中),最终影响甚至决定了以太坊客户端的设计和要求。
一些组网工具指定了未经优化的架构,甚至要求以太坊客户端运行不必要的功能。客户端开发者需要在这些限制下工作。
第四问:为什么网络互联协议提高了客户端实现的难度?
我相信,这个问题的答案基本上可以分为两个部分。
状态管理
整体网络互联要求
就状态管理而言,以太坊客户端必须能够同步网络上的完整状态,并维护该状态的本地副本。这两点都很难做到。对客户端以及读取并处理状态要求的服务器来说,同步状态需要提出数百万个请求,并且会导致磁盘 I/O 饱和。新同步的状态需要经过维护和删减,以便数据库能足够快地执行新区块。从工程上来说,这是一项严峻挑战!
GetNodeData是我们用来同步状态的 网络互联工具,针对特定的状态数据库格式(俗称 “the native layout”)进行了优化。由 Turbo Geth 推广的 “扁平式” 数据库布局在状态维护方面具有极大的性能优势,但是使用这种布局会加大GetNodeData请求的处理难度。
一旦我们将注意力转向网络技术,尤其是 DevP2PETH协议,我们会发现还有其他因素提高了客户端的复杂性。要想加入这个网络,客户端需要具备以下能力:
处理访问最近区块所生成的状态的GetNodeData请求;
处理访问链上数据历史记录的请求,包括区块头、区块体和收据。
从根本上来说,对于许多客户端操作而言,处理这些请求所需的基础数据不是必需的,但是现在却强制它们支持这些功能。这就需要所有客户端在除了满足自己本身的需求之外,还要另外构建大量功能。例如,主要作为交易发送网关的客户端并不需要历史链上数据,可能只需要一个很小的状态子集。但是,就当前的以太坊版本而言,客户端依然需要保存完整的副本。
第五问:为什么……
看来我只问了四个 “为什么” 就找到了根本原因。以太坊协议还没有完全成熟。在设计以太坊协议时,我们并没有意识到现如今发现的大多数问题,或者因为当时状态规模较小、发展历史较短,这些问题还不成问题。