零零客微文大全00ke.net

  • 经典回顾 | 以太坊1.0的设计依据(中)
  • 来源:Unitimes
点击上方“Unitimes”可以订阅哦!


unitimes.io

全球视角,独到见解



尽管以太坊借用了许多已经在诸如比特币这样的旧加密货币中试用并测试了五年的想法,但是以太坊中也有许多地方不同于当前处理特定协议特性的常见方式。此外,以太坊不得不开发一种全新的经济方法,以提供其它现有系统无法提供的特性。本文档旨在详细说明在构建以太坊协议的过程中所产生的细微甚至被忽视又或者是在某些情况下有争议的决策,并揭示这些方法和潜在的替代方案所涉及的风险。


11日,Unitimes 发布了此篇文章的上部分:《经典回顾 | 以太坊1.0的设计依据(上)》


01

叔区块激励


“贪婪的最重观察子树(Greedy Heaviest Observed Subtree,GHOST)”协议是Yonatan Sompolinsky和Aviv Zohar于2013年12月首次提出的创新性协议 [5],该协议旨在解决阻碍出块时间缩减的一系列问题。GHOST所提出的动机是,当前具有快速确认时间的区块链会由于过高的陈旧率而导致安全性降低——因为区块在网络中广播需要花费一定的时间,如果矿工A挖出一个区块,恰巧在这时,矿工B在矿工A的区块传播给自己之前挖出了另一个区块,那么矿工B的区块将会被废弃(即成为“陈旧”区块)并且对网络安全性没有任何贡献。此外,这里还存在一个中心化的问题:如果矿工A是一个拥有30%哈希算力的矿池,而B只拥有10%算力,那么A将面临有70%的时间都在产生陈旧区块的风险(因为在另外30%的时间里,A生成最新的区块,并因此立即获得挖矿数据),而B将面临有90%的时间都在产生陈旧区块的风险。因此,如果出块间隔足够短以至于陈旧率变得特别高,那么A依靠自身的规模优势所获得的挖矿效率将会更高。综合这两种情况,我们不难得出:出块时间更快的区块链很可能导致单一矿池因为拥有足够大的网络哈希算力百分比,最终实际控制了整个挖矿过程的结果。


正如Sompolinsky和Zohar所述,GHOST通过在计算“最长”链时包含陈旧区块来解决网络安全性降低的问题。也就是说,不仅仅是区块的父代以及更久远的祖先代,就连区块的祖先的陈旧后代(用以太坊的术语来说,就是“叔区块”)也被用于计算哪个区块拥有最大的工作量证明支撑。


为了解决中心化倾向这一问题,我们采用了不同的策略:我们为陈旧区块提供区块奖励:陈旧区块将获得其基本奖励的7/8(即87.5%),并且包含陈旧区块的侄区块将获得1/32 (即3.125%)的基本奖励作为包含奖励。需要注意的是,叔区块或侄区块不会获得交易费用作为奖励。


在以太坊中,陈旧区块最多只能作为叔区块被其亲兄弟区块七代以内的后代包含,关系更远的区块就爱莫能助了。这么做有几个原因:首先,无限GHOST将在计算特定区块的叔区块的有效性时引入过多复杂性。其次,在以太坊中使用无限叔区块激励会削弱矿工在主链而不是在公共攻击者的链条上挖矿的动力。最后,计算表明,限制在七代以内在满足众多需求的同时,负面后果最少。


  • 你可以通过这个网址获取测量中心化风险的模拟程序: 

    https://github.com/ethereum/economic-modeling/blob/master/ghost.py 

  • 更近一步的讨论请参考:

    https://blog.ethereum.org/2014/07/11/toward-a-12-second-block-time/


关于出块时间算法的设计决策包括:


  • 12秒出块时间:选择12秒一来是希望时间尽可能快,二来这个时间显着长于网络延迟。由Decker和Wattenhofer2013年在苏黎世所撰写的论文[6]对比特币的网络延迟进行了测量,并确定新区块传播到95%节点所需的时间为12.6秒。然而,该论文还指出,传播时间中的大部分时长与区块大小成正比。因此,在更快的货币实现中,我们预期传播时间将大幅缩减。传播间隔当中的恒定时长约为2秒。但是,为了安全起见,在我们的分析中,我们假设区块需要12秒来传播。


  • 关于7个祖先区块的限制:这是设计目标的一部分,我们希望区块历史能够在经历少量区块以后便能“被遗忘”。此外,我们已经证明7个区块足以提供绝大部分所需效果。


  • 关于1个后代区块的限制(例如 c(c(p(p(p(head))))))是无效的,其中,c 表示子代和 p 表示父代):这是为了满足设计目标中的简单性,上述模拟程序表明这种方案不会导致过高中心化风险的出现。


  • 叔区块有效性要求:叔区块必须是有效的头部,而不是有效的区块。这么做是基于简单性考量,并将区块链模型保持为线性数据结构(而不是像Sompolinsky和Zohar所提出的区块-DAG结构那样)。不过要求叔区块必须为有效区块其实也是一种有效的方案。


  • 奖励分配:叔区块将获得基础挖矿奖励的7/8,侄区块获得基础奖励的1/32,二者都不会获得交易费用作为奖励。如果费用占主导地位的话,那么从中心话的角度来看,这将使得叔区块的激励失效。然而,这也是导致“只要我们继续使用PoW,以太坊就要继续发行以太币”的原因之一。


02

难度更新算法


以太坊的难度目前根据以下规则进行更新:


diff(genesis) = 2^32


diff(block) = diff.block.parent + floor(diff.block.parent / 1024) `

    1 if block.timestamp - block.parent.timestamp < 9 else

    -1 if block.timestamp - block.parent.timestamp >= 9


难度更新规则的根本设计目标是:


  • 快速更新:出块间隔应该根据哈希算力增减情况快速重新调整

  • 低波动性:如果哈希算力恒定,那么难度不应过度跃跳

  • 简单性:算法实现应该相对简单

  • 低内存性:算法不应依赖于超过特定数量的历史区块,并且应该尽可能包含最少的“内存变量”。假设最新的十个区块以及放置在这十个区块的区块头中的所有内存变量,都可用于算法中

  • 不可利用性:算法不应过度鼓励矿工调整时间戳,或者让矿池反复增减哈希算力,以使其自身收益最大化


当前的算法在低波动性和不可利用性方面的效果非常不理想,并且我们希望将时间戳对照切换为父代和祖父代关系。如此一来,矿工只有在连续挖出两个区块时,才有动机去修改时间戳。另一个更强大的模拟方案请访问(这一模拟方案采用的是比特币的日均挖矿算力,并且能够模拟在某一天内95%算力崩溃的状况):https://github.com/ethereum/economic-modeling/blob/master/diffadjust/blkdiff.py 


03

gas 和费用


比特币中的所有交易大致相同,因此它们的网络成本可以建模为单个单元;但在以太坊中,交易变得更加复杂,因此交易费用系统需要考虑众多因素,包括带宽成本,存储成本和计算成本。特别重要的是,以太坊编程语言是图灵完备的,因此,交易可以消耗任意数量的带宽、存储和计算。然而,计算成本可能会因为停机问题的存在导致无法被可靠地提前预测。我们的关键目标是,防止攻击者以无限循环的形式来发起拒绝服务攻击。


交易费用的基本机制如下:


  • 每笔交易必须指明其愿意消耗的“gas”数量(即startgas的值),以及它愿意为每单位gas支付的费用(即gasprice)。在交易执行开始时,交易发送方的帐户中将扣除价值startgas`gasprice的以太币。


  • 交易执行期间的所有操作,包括数据库读取和写入,消息传递以及虚拟机所采取的每一个计算步骤都会消耗一定量的gas。


  • 如果交易执行成功被完整处理,并且执行过程所消耗的gas少于交易发送方一开始指明的数量(假设剩余gas_remgas),那么该交易不但正常执行,并且在执行结束时,交易发送方将收到价值gas_rem ` gasprice的以太币退款,同时将该笔交易打包进区块的矿工也将得到价值(startgas - gas_rem) ` gasprice的以太币作为奖励。


  • 如果一笔交易在执行期间“耗尽gas”,那么期间所发生的执行结果都会恢复,但该交易仍然有效。该笔交易的唯一影响是将总价值为startgas ` gasprice的以太币转移给矿工。


  • 当一个合约向另一个合约发送消息时,它还可以选择设置由该消息产生的子执行的gas数量限制。如果子执行耗尽gas,那么该子执行将被还原,但被消耗gas同样无法退还。


这里所强调的每一个要素都是缺一不可的,举个例子:


  • 如果一笔交易不需要指明gas的数量限制,那么恶意用户便可以发送一笔产生数十亿次循环的交易,并且没有人能够处理这笔交易,因为处理这样的交易需要花费远高于区块间隔的时间。但矿工无法预知每一笔交易所包含的内容,这将隐藏拒绝服务攻击的风险。


  • 相比起严格的gas计数,另一个替代方案是进行时间限制,但这个方案意义不大,因为时间这个因素太主观(总有机器比其它机器更快,哪怕在相同的机器中,误差问题始终存在)。


  •  价值startgas ` gasprice的以太币必须在一开始时便作为保证金被整体取出。如此一来,就不会出现账户在执行过程中“突发破产”并且无法支付gas费用的情况。这里需要强调的是,光执行余额检查也不行,因为帐户可以向其它地方转移余额。


  •  如果在发生gas不足的情况下,交易执行没有被恢复。那么合约需要采取强有力的安全措施,以防止自己中途被曾经提供足够gas的交易或消息所利用,从而导致某些正在执行的合约过程发生更改,但其它部分没有发生变化的境况。


  •   如果不存在子限制,恶意帐户同样可以发起拒绝服务攻击。它可以通过与其它合约签订协议,然后在计算开头插入一个无限循环,从而使得受害合约在补偿攻击合约或者其向受害合约发送消息时因交易执行竭尽资源。


  •  对于开发者来说,要求交易发送方而不是合约支付gas能够极大地提高可用性。非常早期的以太坊版本里包含让合约支付gas的功能,但这导致了一个相当丑陋的问题,那就是每个合约都必须实施“守卫”代码,以确保每一条传入的消息都有足够的以太币来支付其所消耗的gas。


关于gas成本,以下几个特性需要我们注意:


  •  任何交易最起码需要支付21000 gas作为“基本费用”。这一费用包含通过椭圆曲线根据签名恢复发送方地址的操作成本,以及存储交易的磁盘和带宽成本。


  • 一笔交易可以包括无限量的“数据”,并且虚拟机中存在特定的操作码,以允许接收交易的合约访问该数据。数据的“固定gas”费用是“每个零字节 4 gas和每个非零字节 68 gas”。之所以这么定价是因为我们看到在用户编写的合约中,大多数交易数据都以一系列32字节的参数呈现,其中,大多数参数都带有许多前导零字节。这样的结构咋看效率很低,但由于压缩算法的存在,其实际效率非常高。我们希望鼓励用户使用这种参数机制来代替其它尝试根据预期字节数来紧密打包参数的复杂机制,而不是使用一套复杂的机制来增加编译器层面的复杂性。尽管这一点有悖于多层次复杂性模型的理念,但考虑到成本收益比,这是一个合理的模型。


  • 用于设置帐户存储中的值的SSTORE操作码的成本有几种:(i)将零值改为非零值时需要20000 gas,(ii)将零值改为零值,或将非零值改为非零值需要5000gas,或(iii)将非零值改为零值时的5000gas,加上在交易成功执行结束时退回的15000gas(即该执行没有导致“耗尽gas”异常)。这一方案将会激励用户清理存储。我们注意到,正是缺乏这样的激励措施,许多合约的存储空间并没有得到有效使用,从而导致存储快速膨胀。而为存储收取费用带来了许多好处,同时不会失去合约一旦部署就可以永久存在的保证。此外,延迟退款机制是很有必要的,因为这样可以阻止拒绝服务攻击:比如,攻击者发送一笔含有少量gas的交易,该交易循环清除大量的存储直至耗尽gas。这种交易执行尽管消耗了验证者大量的算力,但实际上并没有真正清除存储或消耗大量gas。50%上限的设定是为了确保矿工在获得一笔包含一定数量gas的交易后,依然能够确定执行该笔交易的计算时间上限。


  • 合约所提供的消息中的数据没有gas成本。因为在消息调用期间,我们不需要实际“复制”任何数据——被调用的数据可以被简单地看作是一个指向父合约内存的指针,该内存在子执行进行期间不会发生改变。


  •  内存是一个无限可扩展的数组。但是,每32字节内存扩展需要消耗1 gas,不足32字节的按32字节算。


  •  对于某些计算时间高度依赖于参数的操作码来说,其gas成本是变化的。比方说,在指数中,EXP的gas成本为每字节10 + 10(即x^0 = 1 gas, x^1 ... x^255 = 2 gas, x^256 ... x^65535 = 3 gas,依此类推),而复制操作码(CALLDATACOPY, CODECOPY, EXTCODECOPY)的gas成本为每复制32字节消耗1 + 1,不足32字节按32字节计算(LOG也有类似的规则)。内存扩展的gas成本并未包含在内,因为它开启了二次攻击(50000次消耗50000 gas的CALLDATACOPY大约消耗 50000^2 计算工作量,但在引入可变gas成本前,只有约50000gas)


  •  如果值非零,那么CALL操作码(为了对称起见,也可以叫CALLCODE)将额外消耗 9000 gas。这是因为任何值的传输都会导致存档节点的历史存储明显膨胀。需要注意的是,这里面实际收取的费用是 6700 gas。此外,我们还添加了一个强制性的2300 gas的最小值,这一笔 gas 会自动提供给接收者,以确保接收交易的钱包至少有足够的gas来记录交易。


关于 gas 机制,另一个重要的部分是关于 gas 价格本身的经济学问题。在比特币中,其所使用的默认方式是纯粹自愿收费,并依靠矿工充当看守者来设定动态最小值。在以太坊中,其所采用的等价手段是允许交易发送方设定任意的gas成本。这种方式在比特币社区中得到了广泛支持,因为它是“市场导向的”,价格仅由矿工和交易发送方之间的供需来决定。然而,这种方案实现逻辑中所存在的问题在于,交易处理不是一个市场。尽管直观上而言,我们将交易处理描述为矿工向发送方提供服务更具有吸引力,但实际上,矿工所包含的每一笔交易都需要经由网络中的每一个节点进行处理。为此,绝大部分的交易处理成本都由第三方承担,而不是决定是否包含这笔交易的矿工。因此,这里很可能会发生公地悲剧问题。


当前,由于缺乏矿工在现实中如何表现的明确信息,我们采用了一种相当简单的方式,即投票制度。矿工有权将当前区块的 gas 限制设置为最新一个区块的 gas 限制的约0.0975%(1/1024)之内。由此,最终的 gas 限制应该会是矿工们所偏好的中位数。我们希望将来能够通过软分叉的方式将这一方案升级为更加精确的算法。


由于文章较长,本文分为上中下三部分发出。敬请期待下篇~


相关阅读:

Vitalik:以太坊 Serenity 设计依据综述

经典回顾 | 以太坊1.0的设计依据(上)


参考注释:

[5] GHOST:https://eprint.iacr.org/2013/881.pdf

[6] Decker和Wattenhofer 2013年在苏黎世所撰写的论文见:https:// www.tik.ee.ethz.ch/f`ile/49318d3f56c1d525aabf7fda78b23fc0/P2P2013_041.pdf


本文翻译:喏呗尔

原文作者:Vitalik Buterin

原文链接:https://github.com/ethereum/wiki/wiki/Design-Rationale


【文章版权归原作者所有,其内容与观点不代表Unitimes立 场。转载文章仅为传播更有价值的信息,合作或授权联系请发邮件至 editor@unitimes.media或添加微信unitimes2017】

区块

1 2 3 4 5 >> 

公众号 • Unitimes

Flag Counter