图1
2014年初前后,我们还根据其他人的建议作了一些修改。在安德鲁·米勒(Andrew Miller)等人提出回到基于栈的架构这一想法以后,我们最终还是回去了(图2)。
图2
查尔斯·霍斯金森(Charles Hoskinson)建议我们从比特币的SHA256转换为更新的SHA3(或者更准确地说,是keccak256)。尽管有过一段时间争议,但通过与加文、安德鲁以及其他人进行讨论,我们还是确立了栈中的值的大小应该被限制在32 Byte。而另一种替代方案——无限制整数——则仍在考虑当中,因为该方案存在一个问题,即我们很难计算出执行家加法、乘法以及其他操作到底需要多少燃料。
回到2014年1月,我们最初想到的挖矿算法是一个叫匕首 (Dagger) 的东西:
匕首是根据有向无环图 (Directed Acyclic Graph, DAG) 命名的。DAG是一种用在算法中的数学结构,其思想是每隔N个区块,就会有一个新的DAG由种子伪随机生成。并且,DAG的底层将会是一个需要用几十亿字节来存储的节点的集合。然而,在DAG中,生成任意一个独立的值只需要计算计算几千个条目。一次匕首计算包含在这种底层的数据集中的任意位置获得一定数量的值,然后将这些值一起进行哈希运算。这意味着存在一种快速的方式可以进行匕首计算——已经将数据存储在内存中,然后以一种缓慢但不会导致内存紧张的方式——重新从DAG中生成你需要从头开始获取的每一个值。
这个算法的目的就是和当时流行的算法一样拥有相同的内存受限属性,就像Scrypt算法,但是仍然对轻客户端友好。矿工会使用快速的方法,所以他们的挖矿将受限于内存带宽 (理论上,消费者级别内存的优化程度已经足够高了,因此用ASIC对其进行进一步优化十分困难),但轻客户端可以使用内存宽松且缓慢的方式进行验证。快速方法可能只需几微秒,而慢速且内存宽松的方法可能需要几毫秒,所以这对轻客户端依然是可行的。
从这里开始,这个算法伴随着以太坊的发展历程发生了几次变化。接下来的想法是自适应工作量证明。在这个方案中,工作量证明将会涉及执行被随机选出的以太坊合约,并且这里面包含了一个很巧妙的做法去抵抗ASIC:如果ASIC被开发出来了,那么竞争矿工就会有动机去创建并发布该ASIC不擅长执行的合约。没有一种ASIC能够用于通用计算,因为它仅仅是一个CPU。因此,我们可以利用这类对抗激励机制来实现本质上在执行通用计算的工作量证明。
由于一个简单的原因,这个想法后来破碎了。这个原因是长程攻击。攻击者可以从区块 1 开始构建一条链,并且只用简单的合约对这条链进行填充。需要注意的是,攻击者可以为这种简单的合约设计出专门的硬件,从而使攻击链迅速赶超主链。所以......又回到了原点。
下一个算法被称为“随机电路”,具体的描述可以查看其Google文件。这个算法是我和弗拉德·赞菲尔 (Vlad Zamfir) 提出的,并由马修·万普勒·多蒂 (Matthew Wampler-Doty) 和其他人进行分析。这个算法的思路是通过执行伪随机生成电路来模拟挖矿算法中的通用计算。这一次,没有任何确凿的证据表明基于这些原则的东西是行不通的。但我们在2014年接触的计算机硬件专家都对此表示非常悲观。马修·万普勒·多蒂提出了一种基于SAT解决方案的工作量证明,但最终也被拒绝了。
最后,兜兜转转,我们还是提出了Dagger Hashimoto算法,有时简称为Dashimoto。这种算法借鉴了Hashimoto的很多想法。Hashimoto是萨帝厄斯·追亚 (Thaddeus Dryja) 提出的工作量证明机制,它开创了“I/O约束工作量证明”概念。在该机制中,挖矿速度的主要限制因素不是每秒钟哈希运算的速度,而是RAM每秒可访问的兆字节数。然而,Dagger Hashimoto将这种工作量证明机制与匕首算法中对轻客户端友好的DAG所生成的数据集结合了起来。经过我、马修、蒂姆和其他人多次调整以后,这些想法终于融入了我们现在称为“Ethash”的算法中。
到2014年夏天,除了工作量证明大概需要到2015年初才能到达Ethash阶段,这个协议已经相当稳定,并且其半正式规范已经以加文的黄皮书形式面世了。
2014年8月,我开发并引入了叔区块机制。该机制可以使以太坊的区块链具备更短的区块时间以及更高的处理能力,同时减少了中心化的风险。关于叔区块机制的介绍,可以参见PoC6。
在与比特股团队讨论之后,我们考虑使用堆作为头等数据结构——尽管最后由于时间不够没有这样做,并且后来的安全审计和DoS攻击让我们明白:在当时安全地实现这一功能远比想象中更难。
9月,我和加文计划对协议设计进行两处重大的变更。首先,除了状态树和交易树,每一个区块还将包含一颗收据树。收据树将包含由每一笔交易创建的日志的哈希以及中间的状态根。日志将会允许交易创建可以保存在区块链中的输出,并且可被轻客户端访问。然而,未来的状态计算无法访问这些日志。这种方法使得去中心化应用能够很容易地查询时间,如代币转账、购买、正在被创建和被撮合的交易所订单,以及正在进行的拍卖等。
我们还考虑了其他想法,如把默克尔树从一笔交易的完整执行轨迹中抽取出来,以允许任意内容得到证明。在对简单性和完整性进行折中以后,我们选择了使用日志。
其次就是预编译的想法。预编译解决了允许复杂的加密计算在EVM中可用而不必处理EVM开销的问题。我们还提出过许多关于本地合约的雄心勃勃的想法。在这些想法中,如果矿工拥有关于某些合于的更优的实施方法,那么他们就会投票下调这些合约的燃料价格。如此一来,那些大多数矿工都能快速执行的合约自然就拥有更低的燃料价格了。然而,所有这些想法都被拒绝了,因为我们无法提出一种在加密经济学角度足够安全的方式来实现它。攻击者总是可以创建一些合约来执行带有活动门的加密操作,然后将活动门分发给自己和他们的朋友,从而能够更快地执行这个合约。随后,攻击者投票下调燃料价格并利用这一点对网络进行DoS攻击。相反,我们选择了一个不那么雄心勃勃的方法,即在协议中简单地指定较小的预编译数量,用于哈希和签名方案等常用操作。
加文也是最初支持开发协议抽象这一想法的关键人物。所谓协议抽象,就是将协议的众多部分,如以太币余额、交易签名算法、随机数等,作为合约迁移到协议本身中。其理论上的最终目标是要达到整个以太坊协议能够被描述为将函数调用加入到具有特定预初始化状态的虚拟机中的目标。我们没有足够的时间把这些想法都加入到最初的前沿版本中,不过预计这些原则将通过“君士坦丁堡”的一些变化、Casper合约和分片规范慢慢开始被整合。
这些内容都在PoC 7 中实现了。在 PoC 7 之后,该协议并没有真正发生太大的变化,除了一些轻微但在某些情况下十分重要的变动。这些细节将会在通过安全审计后公布。
到2015年初,尤塔·斯坦纳 (Jutta Steiner) 和其他人组织了发布前的安全审计,包括软件代码审计和学术审计。软件代码审计主要是在分别由加文和杰夫瑞主导的C++和Go语言实现上。尽管我的Pyethereum实现也进行了一次简单的审计。在这两次学术审计中,一次由尤塔·埃雅尔 (Ittay Eyal) (因提出“自私挖矿”而成名) 负责进行的,另一次由安德鲁·米勒和Least Authority的其他成员进行。埃雅尔的审计导致了一个轻微的协议变更,即链的总难度值不会包含叔区块。由Least Authority负责的审计更侧重于智能合约、燃料经济学以及帕特里夏树。这次审计也导致了几处的协议变更。其中,比较小的一处变更是使用sha3(addr) 和 sha3(key) 作为树的键值,而不是直接使用地址和键值。这将使得攻击者更难对树发起最坏攻击。
我们讨论的另一个重要的问题是燃料限制投票机制。那时候,我们已经对关于比特币区块大小的争论缺乏进展感到担忧,并希望在以太坊中拥有一个灵活的设计:该设计能够根据需要随时间调整。但面临的挑战是, 的限制是什么?我最初的想法是制定一个动态的限制,该限制是实际燃料使用量的长期指数移动平均值的1.5倍。因此,从长远来看,平均区块都会被占用2/3的容量。然而,安德鲁证明了这种限制在某些方面是可以被利用的——具体来说就是,想要提高限制的矿工仅需要把消耗大量燃料却只花费很少处理时间的交易都包含在他们自己的区块中,从而创建出满载区块且不会亏损成本。因此,至少从最终的结果来看,这个机制的安全模型相当于只是让矿工对燃料限制进行投票。
我们没能提出一个更好的燃料限制策略,安德鲁推荐的方案是让矿工明确地对燃料限制进行投票,而且默认的投票策略是1.5倍的EMA。其原因在于,我们还没有想出设置最大燃料限制的正确方法,并且任何具体方法失败的风险都似乎远远高于矿工滥用投票权的风险。因此,不妨简单地让矿工对燃料限制进行投票,并接受燃料限制过高或过低的风险,从而换取灵活性以及矿工联合起来根据需要快速调整燃料限制高低的好处。
在我和加文、杰夫进行了一场迷你黑客松之后,PoC 9终于在3月份推出了。其旨在成为概念证明的最终版本。我们将一个叫作“奥林匹克”的测试网运行了4个月。该测试网用的是将要用在主网中的协议。与此同时,我们还建立了以太坊的长期计划。维纳·古普塔 (Vinay Gupta) 写了一篇文章——《以太坊的发布过程》。这篇文章描述了以太坊主网开发的4个阶段,并相应给出了如今大家耳熟能详的名字:“前沿”、“家园”、“大都会”和“宁静”。
“奥林匹克”测试网运行了4个月。前2个月,我们在各种实施版本中发现了很多漏洞,也发生了共识失败等其他问题。不过在6月前后,网络已经显著稳定下来了。到了7月,我们决定冻结代码;7月30日以太坊主网正式发布。
来自以太坊基金会的庆生
以太坊5岁啦!