记录 | 以太坊协议的发展史

zzzhang   |     |   1441 次阅读

虽然当前以太坊协议背后的思想已经很大程度上稳定了两年了,但是以太坊当前的构想和形式并不是一次性完成的。在区块链推出之前,该协议经历了一些重大的演变和设计决策。本文的目的是讨论协议从开始到发布的演变过程;但是我不会一一提及例如Geth,cppethereum,pyethereum以及EthereumJ这些在协议的实现上做出的无数工作以及以太坊生态系统中应用和企业的历史。

同样在本文中不会提及的还有Casper以及分片研究的历史。我们当然可以写更多的博客来讨论Vlad,Gavin,我自己以及其他人提出并最终舍弃的各种各样的观点,其中包括“工作量证明之证明”,轮辐式链(hub-and-spoke chains), “hypercubes”, 影链(shadow chains)(可以说是Plasma的前身),链纤维( chain fibers),以及Casper的各种迭代,还有Vlad的在推理共识协议的激励机制及其性质的快速演变思想。在一篇博客中讨论这些将是一个太过复杂的事情,所以我们在此就不进一步讨论这些。

让我们从最早的版本开始,这个版本最终成为了以太坊但是当时它甚至还不叫以太坊。当我在2013年10月访问以色列的时候,我花了很多时间与Mastercoin团队在一起,甚至还给他们推荐了一些功能。在花了一些时间思考他们所做的事情后,我向该团队提出了一个建议,那就是让他们的协议更加的通用化,能够支持更多类型的合同而不需要增加同样庞大而复杂的功能集:
https://web.archive.org/web/20150627031414/http://vbuterin.com/ultimatescripting.html

请注意,该版本与之后范围更广的以太坊版本大不相同:它单纯地专注于Mastercoin当时尝试的方向,即双方合约,该合约是指A方和B方都会投入资金,之后根据合同中规定的一些公式他们可以将钱取出来(例如,赌注内容为“如果X发生了,则所有的钱都给A,反之都给B”)。该脚本语言不是图灵完备的。
Mastercoin 团队对此印象深刻,但是他们并没有兴趣放弃他们所作的一切事情并朝着这个方向发展,我越发觉得这是一个正确的选择。接着,大约在12月,我更新了第二个版本:
https://web.archive.org/web/20131219030753/http://vitalik.ca/ethereum.html

在这里,你可以看到进行了大量重构的结果,这很大程度上是11月份我在旧金山一次散步的结果,那时,我意识到智能合约有完全通用化的潜力。合同本身就是完全成熟的账户而不是像脚本语言那样只是单纯的描述双方关系的方式,合同具有持有,发送和接收资产的能力,甚至可以保持永久性储存(当时,永久性储存被称作“内存”,并且这仅有的临时“内存”是256个寄存器)。这种语言从基于堆栈的机器转变成自我意志为基础的基于注册的机器;我对此几乎没有异议,除了它看起来似乎更加复杂。
此外,可以注意到,该版本还有一个内置的收费机制:

在这个阶段,以太(Ether)按照字面意思是气;在每一个计算步骤之后,一个交易调用的合约的余额将会减少一些,如果合约余额耗尽,则停止执行。请注意,这个“接收者支付”机制意味着合约本身要求发送者必须向合约支付一笔费用,否则立即退出执行;该协议分配了16个免费执行步骤的许可,以允许合约拒绝不支付费用的交易。

以上所述阶段的以太坊协议完全是由我自己创造的。然而,从这里开始,新的参与者开始加入。到目前为止,协议方面最突出的是Gavin Wood,他2013年12月在about.me用站内私信开始与我联系。

Jeffrey Wilcke,Go 客户端(那时被称作“ethereal”)的首席开发者也在同一时期联系了我并开始进行编程。他的贡献更多的是在客户端开发方面而不是协议研究方面。

“嗨 Jeremy,很高兴看到你对以太坊感兴趣”

Gavin的早期贡献是双重的,首先,你可能会注意到在初始设计中的合同调用模型是异步的:虽然合同A可以创建一个“内部交易(internal transaction)”给合同B(“内部交易“是以太坊的行话;最初他们仅仅被称为“交易”,之后又被叫做“消息调用”或者“调用””),但第一个交易完全完成之前,内部交易是不会启动执行的。这意味着交易不能使用内部交易作为从其他合约获取信息的方式;唯一实现该功能的方法就是EXTRO 操作码(类似于你可以用于阅读其他合约存储内容的SLOAD),这随后在Gavin和其他人的支持下被删除了。

在实现我最初的规范时,Gavin自然地实现了内部交易的同步化,他甚至没有意识到这与最初的设计是不同的-也就是说,在Gavin的实现中,当一个合约调用另一个合约时,内部交易会立即执行,一旦该执行完成,虚拟机将返回到创建内部交易的合约并转到下一个操作码。这种方法似乎对我们双方都有优势,所以我们决定把它当作规范的一部分。

接着,我和他之间的一次讨论(那发生在一次旧金山漫步中,因此具体的细节将在历史的洪流中湮没,但也可能会存在于NSA的深层档案中的一两份文件中)开启了对交易费模式的重构,从“合同支付”方式转向“发送方支付”方式,并且切换到“gas”的架构。交易发起者支付并被分配到一些“gas”(大致是一个计算步骤的计数器)而不是在每个独立的交易步骤执行后立刻消耗一点以太,同时计算步骤来源于gas的允许量。如果进行某笔交易时gas不足,所剩的gas还是会被没收的,但整个执行将被复原;这似乎是最安全的做法,因为它删除了之前需要担心的整个“部分执行”的攻击类型。当交易执行完成时,任何未使用的gas费用将被退还。

Gavin也对以太坊逐渐成为一个用于构建可编程资金的平台做出了巨大贡献,该平台有基于区块链的合约,能持有数字资产并将其按照预设规则转移到通用计算平台上。这种变化从重点和术语的微妙变化开始,后来随着对“Web3”集成的日益强调,这一影响也而逐渐变强,它将以太坊视为一套分布式技术的一部分,另外两部分则是耳语协议以及蜂群协议。

2014年初,还有一些根据其他人提出的建议做出的改变。在Andrew Miller等人提出这个想法后,我们最终又回到了基于堆栈的架构。

Charles Hoskinson 建议从比特币的SHA256转换成较新的SHA3(或者更准确的说,keccak256)。虽然有过一段时间争议,但是通过Gavin,Andrew等人的讨论决定,建立了堆栈里值的大小应该限制为32字节的方案;另一种被考虑的替代方案是无限制的整数,该方案有一个问题那就是很难计算出加法,乘法和其他操作所需的gas的量。

我们最初想到的挖矿算法,要回溯到2014年2月,是一个叫Dagger的玩意儿:
https://github.com/ethereum/wiki/blob/master/Dagger.md

Dagger是以“有向无环图”(DAG)命名的,DAG是算法中用到的一种数学结构。Dagger的思想就是对于每N个区块,由种子值生成一个伪随机的DAG。DAG的底层将会是一个需要用几个千兆字节来存储的节点的集合。不过,DAG中生成任何一个独立的值只需要计算几千个条目,一个“计算Dagger”包括在这种最底层的数据集中生成一系列随机数,然后求他们的哈希。这就意味着有一个迅速的方式进行Dagger计算——内存中已经有了数据,然后用一个虽然慢却不会引起内存紧张的方式——重新从DAG中得到每个数据,而不是从其他节点下载。

这个算法的目的就是要和当时流行的算法一样具有相同的“内存难解”属性,就像Scrypt算法,并且要求是轻客户端友好的。矿工会采用快速的方法,所以他们的挖矿速度就会受到内存带宽的约束(理论上认为普通的内存已经是非常优化的了,所以在ASIC上对它进一步优化是非常困难的),但是轻客户端会在无内存限制的慢CPU环境中进行哈希验证。快速的方式可能就用几微秒,但是这种慢速无内存限制的方式可能用上几毫秒,所以这对于轻客户端来说也是可行的。

从此开始,在以太坊发展的过程中这个算法做出了几次重大的改变。我们接下来的想法就是“自适应工作量证明”,这里的工作量证明包括执行随机选出的以太坊合约,而且它为什么能抵抗ASIC的原因是非常高明的:如果应用了某ASIC,竞争矿工就有创建和发行那个ASIC并不擅长计算的合约的动机。没有一种ASIC能用于通用计算。故事接着说下去,因为它只是一个CPU,所以我们可以用这种对抗激励机制来进行实质上是使用通用计算的工作量证明。

这个想法由于一个简单的原因而被否了:远程攻击。攻击者可以从块1开始一个链,只用简单的合约来填充它,而且这种合约是比较特殊的,可以为它创建专门的硬件,使得这条链迅速超过主链。所以。。。。又回到起点。

下一个算法被称为随机电路,在这个Google文件中有详细的描述,它是由我和Vlad Zamfir提出,Matthew Wampler-Doty和其他几个人分析的。这里我们的想法就是模拟挖矿算法中的普通计算,模拟的方法是执行随机生成的一些电路。这里没有任何基于这些原则不能工作的硬性证明,但是我们2014年咨询过的电脑硬件专家对此都不表示看好。Matthew Wampler-Doty 提出了一种基于SAT的POW机制,但最终也不行。

最后,我们全身心的投入到了“Dagger Hashimoto”算法中,简称“Dashimoto”,这种算法从Hashimoto中借鉴了很多,这是Thaddeus Dryja首创的工作量证明机制,它开创了“I/O绑定的工作证明”的概念,其中挖矿速度的主要限制因素不是哈希散列的速度,而是RAM每秒可访问的兆字节数。然而,Dagger Hashimoto将上述工作量证明机制与Dagger的轻客户端友好的DAG生成的数据集的概念结合了起来。经过了我、Matthew、Tim和其他人的多次调整之后,这些想法终于融合进了我们现在称之为“Ethash”的算法中。

到2014年的夏天,这个协议已经相当稳定,除了到2015年初才能完成的Ethash工作量证明算法之外,以Gavin黄皮书形式存在的半正式规范已经面世了。

在2014年8月,我开发并介绍了叔伯机制,它可以使以太坊的区块链有一个更短的区块时间和更高的容量,同时降低了集中化的风险。叔伯机制的介绍发布在PoC6中。

与Bitshare团队讨论后,我们考虑使用堆作为主要数据结构,但我们最后还是没有这样做,因为我们时间不够,而且后来的安全审计和DoS攻击表明在安全这方面它实际上比我们当时想象的更难。

9月,我和Gavin计划对协议设计做出以下两大重要的改变。首先,除了状态树和交易树,每一个区块将包含一个“收据树”。收据树将包含每次交易的所有交易日志的哈希值,以及中间状态根。交易日志允许交易创建可以保存在区块链上的输出,并且轻客户端是可以访问的,不过将来的状态计算是不可以访问的。这可以用于分布式应用程序很容易的查询交易,例如token的传输、购买、正在创建和进行的交易单据和正在进行的拍卖等。

我们还有一些其他的想法,例如把merkle树从整个交易执行中提取出来,以便进行任意事物的证明。在对简单性和完备性的权衡之后,我们选择了日志,。

第二个就是预编译的思想,解决了允许复杂加密计算在以太坊虚拟机中可用而不必处理虚拟机开销的问题。我们还经历了许多关于“本地合约”的雄心勃勃的想法,如果矿工有一些合约的更优化的执行方法,他们就会“投票”下调gas费用,因此,对于那些大多数矿工都能快速执行的合约,自然就有较低的gas费用;不过,所有的这些想法都被否绝了,因为,我们无法提出一种在密码经济学看来安全的方式来实现它。攻击者总是可以创建一些合约,去执行活动的加密操作,然后将活动门分发给自己和朋友,这样就能更快的执行这个合约,如此一来,gas价格就会降低,就能进行DoS攻击。相反,我们选择了一个没有那么大的野心的方法,即在协议中简单指定的少量的预编译器,例如用于哈希散列和签名方案等常用操作。

Gavin也是支持“协议抽象”的最初的关键人员。协议抽象就是将协议的许多部分,例如以太币余额、交易签名算法、Nounce(一次性随机数)等,作为合约迁移到协议本身中,并且理论上要实现的最终目标是要达到一个状态:整个以太坊协议能够被描述为将功能调用函数加入到具有一些预初始化状态的虚拟机中的状态。我们没有足够的时间把这些想法都在最初的Frontier中实现,不过这些原则预计将会随着君士坦丁堡分叉、Casper合约和分片规范而慢慢整合到其中去。

这一切都在PoC7中实现了,在PoC7之后,除了一些较小的,尽管在某些情况下是比较重要的,协议没有太大的变化。这些细节将会在通过安全审计后呈现给大家。

在2015年初,Jutta Steiner等人组织了发布前的安全审计,包括软件代码审计和学术审计。软件代码审计主要是在C++和Go的实现上,分别由Gavin Wood和Jeffrey Wilcke主导的,其实还有我的Pyethereum实现的一次简单审计。在两次学术审计中,一次由Ittay Eyal(因提出“自私挖矿”攻击成名)执行,另一次由Andrew Miller和 Least Authority的其他成员进行。通过Eyal审计我们做了一个小小的协议变更,链的难度值不包含叔伯节点。第二次审计侧重于智能合约、合约费用以及Patricia树。通过这次审计我们也进行了几处协议的变更。一个是使用sha3(addr)和sha3(key)作为键值,而不是直接使用地址和键值;这将使得更难对树进行最坏的攻击。

有一个可能有点超前的警告。。。。。。

我们讨论的另一个比较重要的问题就是gas限制投票机制。当时,我们已经对没有任何进展的比特币块大小讨论感到担心,并希望在以太坊中有一个灵活的能够按需调整的设计。但这其中的挑战就是:什么是最佳的限制?我最初的想法是做一个动态的限制,是实际gas使用量长期指数移动平均值(EMA)的1.5倍,所以长来看区块平均都是2/3满的。然而,Andrew证明了这种限制在某些方面是可以被利用的,具体来说就是:想要提高限制的矿工们,他们只需要把需要花费大量的gas却只需很少的处理时间的交易都包括在自己的块中,从而创建出完全块且不会对自己造成损失。因此,这个机制的安全模式相当于只是让矿工对gas限制进行投票,可能还不如矿工投票。

我们没有想出来一个更好的gas限制的策略,Andrew的建议是明确地让矿工对gas限制进行投票,而且默认的是1.5倍的EMA投票规则。原因在于我们还没有认识到设定最大gas限制的具体的方法,而且任何具体做法的风险都似乎都远远高于矿工滥用投票权的风险。因此,我们还不如直接让矿工对gas限制进行投票,接受gas限制过高或过低的风险,这样一来,能够更加灵活,矿工也可联合,迅速按需调整gas限制的高低。

在我和Gavin、Jeff进行了一个小型黑客松之后,3月份推出了PoC9,旨在成为概念证明的终稿。我们运行了一个测试网,Olympic,跑了四个月,用的是将要用在真实网络中的协议,并且建立了以太坊的长期计划。Vinay Gupta写了一篇博客,“以太坊的开展过程”,描述了以太坊开发的四个预期阶段,并把它们命名为:Frontier(前线)、Homestead(家园)、Metropolis(大都会)和Serenity(宁静)。

Olympic运行了4个月。前两个月,在各种实现中发现了许多错误,发生了共识失败等问题,不过到6月左右网络已经显著的稳定了。我们在7月份做出了冻结代码的决定,随后7月30日发布了最初版本。


原文链接:http://vitalik.ca/general/2017/09/14/prehistory.html
作者: Vitalk Buterin
翻译&校对: Aisling 、刘艳安 & Elisa

 
0 人喜欢