(1)以太坊把出块时间降到了十几秒,这有利于提高系统的througput以及降低了系统反应时间。和比特币的10分钟出块时间相比,以太坊的出快速度相当于提高了40倍。但是这样大幅度降低出块时间后,也带来了一些新的问题。
(2)前面我们介绍到,比特币和以太坊都是运行在应用层的共识协议,它底层是一个peer to peer 的over network。over network本身传输协议是比较长的,因为它的拓扑协议做flooding时候没有考虑实际的拓扑结构。
(3)这就带来一个问题,你发布一个区块后,区块在网络上传到其他节点,可能需要十几秒的时间。对于比特币来说,10分钟的出块时间相当于600秒,那么这个足够让新发布的区块传播到网络上的其他节点。
(4)但是即使这样,因为挖矿是一个概率的过程,所以仍然有可能是由两个矿工同时获得记账权,同时发布区块。前面介绍过这个情况,这会带来临时性的分叉。那么对于以太坊来说,这种临时性的分叉就会变成了常态,而且分岔的数目也会更多。因为十几秒的出块时间,很有可能别的节点其实还没来得及收到你发布的区块,还在沿着原来的区块链往下挖,等到他收到你发布的区块时候,可能他自己已经挖出来一个新的区块。那么这对共识协议来说有什么样的挑战呢?
(5)比特币的情况是这样的:只有在最长合法链上的那些区块里面所包含的出块奖励才是真正有用的。其他的一些分叉的链上的出块奖励,其实最后是作废的。下面我们画一个例子如下:
上图中的区块链,在第三个块出现了分叉,分了三个叉,这三个差不多是同一时间取得了记账权,那么最后有一个会胜出,成为最长合法链。如果中间这个胜出了,那么像上面和下面这个区块我们称为orphan block或者 stale block。而挖到这个区块的矿工,在这个区块里面有一个铸币交易coinbase transaction,能够获得一定数量的比特币,但实际上最后是没用的,因为他不在最长合法链上,所以这里得到的出块奖励等于是作废了。对于比特币来说,因为出现这种临时性的分叉的情况不是很多,所以这么规定还是可以接受的。但是对于以太坊来说,如果也这样处理的话,那么这就意味着矿工挖到的区块有很大概率是白挖了。
你辛辛苦苦挖出一个区块,因为系统中有很多分叉,所以很有可能你挖出的这个区块,他最后没有成为最长合法链,这样你就白忙活了。这样对挖到矿的矿工来说,不是很公平,尤其是对于这种个体矿工,这种情况更为严重。我们前面介绍过,挖矿呈现出两个趋势,一个是挖矿设备的专业化,现在已经很少有人用我们的普通桌面机挖矿,服务器都很少,一般都是用的专门的设备,像ASIC芯片,或者对于以太坊来说用GPU挖矿。第二个趋势就是大型矿池的出现,个体矿工算力有限,有很多是组成了大型矿池,资本的运作下,有很多算力实际上是集中在大型矿池。不光是前面我们了解的比特币是这样,下面我们说的以太坊也如此,叫做mining pool。
这对个体矿工尤其是不公平的,正常情况下,我们希望的是,你矿池能够得到的收益应该和你的算力比例是一致的。比如,你矿池的算力占整个系统算力的30%。假设你是一个大矿池,那么你得到的挖矿收益也应该是整个系统的30%,这样才算公平。
(6)但是如果我们的共识协议设计不好的话,有可能大矿池得到了收益超过它的算力的比例。比如说,我们刚出现分叉的时候,假设上下两个区块是个体矿工挖出来的,中间区块是某个大型矿池挖出来的,那么下面怎么变化呢。大矿池肯定是沿着它自己的分叉往下面挖,因为他的算力很强,所以它挖出下一个区块的概率是比较大的,而上下这两个分叉,他们个体矿工的,他们主要寄希望于别的矿工会沿着他们这两个分叉往下挖,因为他自己的算力是微不足道的。他就是一个个体矿工,光靠他自己沿着这条链往下挖是比不过别人的。但是对于别的矿工,他其实没有什么理由倾向于这两个个体矿工的分叉去挖。换句话说你个体矿工,如果是作为一个整体的话,出现分叉后它的算力是分散的。这样就会造成一个结果。假设这个矿池挖到区块的概率是30%,但是他挖到区块后,成为最长合法链的概率很高。这样就会造成mining centralization(挖矿的集中化)。
(7)实际情况可能比这个更加糟糕,一般来说,大型矿池在这个区块链网络中占得位置是比较好的,有的可能是在网络中多个地方都有接口,所以大型矿池发布出去的区块,有可能更早的被其他节点所接收。所以说,就算这三个区块是同时被挖出来,那么中间的大型矿石发布的区块可能是别的节点最先收到的区块。而且从过去的历史经验来看,大型矿池所在的分叉更有可能成为最长合法链,这个也就促使别的矿工会沿着它的分叉去继续挖,因为你沿着其他分叉去挖的话,很有可能就白挖了。这就使得大型矿池出现了一个恶性循环,越是大型矿池得到的收益也就越大,mining centralization也就更加严重。有时候我们称作它centralization bias,即中心化带来的不成比例的优势。
(8)如果我们什么都不改,以太坊沿用比特币共识机制就会出现问题。为了解决这些问题,以太坊中采用了基于Ghost协议的共识机制。Ghost协议并不是以太坊发明的,就在以太坊以前就已经有了Ghost协议了。以太坊对这个协议做一些修改。这个协议的核心思想就是,你挖到了矿,发布了一个区块,最后这个区块作废了,你就很难受,我们给你一些出块奖励作为安慰。比如我们上图中的情况,上面那条链没有成为最长合法链,变成了orphan block或stale block,以太坊给他去了一个名字叫做uncle block,就是这个区块相对于最长合法链上的当前区块来说,它是它的叔父区块,它和它的父亲是一个辈分。这就得到了Ghost协议的最初版本如下。
(1)如图,假定以太坊系统存在以下情况,A、B、C、D在四个分支上,最后,随着时间推移B所在链成为最长合法链,因此A、C、D区块都作废,但为了补偿这些区块所属矿工所作的工作,给这些区块一些“补偿”,并称其为"Uncle Block"(叔父区块)。
(2)规定E区块在发布时可以将A、C、D叔父区块包含进来,A、C、D叔父区块可以得到出块奖励的7/8,而为了激励E包含叔父区块,规定E每包含一个叔父区块可以额外得到1/32的出块奖励。为了防止E大量包含叔父区块,规定一个区块只能最多包含两个叔父区块,因此E在A、C、D中最多只能包含两个区块作为自己的出块奖励。
(3)假定一个矿工挖出了B,此时他沿着其所在链继续挖,而他知道A是和自己“同辈”,则可以将A包含进区块挖矿,若挖矿过程中又听到C也是“同辈”,则可以停止挖矿,将C包含进来重新组织成一个新区块重新挖矿,实际中,由于挖矿过程的无记忆性,这样并不会降低成功挖到矿的概率。
(4)最初版本缺陷:
(1)下图为对上面例子的补充,F为E后面一个新的区块。因为规定E最多只能包含两个叔父区块,所以假定E包含了C和D。此时,F也可以将A认为自己的的叔父区块(实际上并非叔父辈的,而是爷爷辈的)。如果继续往下挖,F后的新区块仍然可以包含B同辈的区块(假定E、F未包含完)。这样,就有效地解决了上面提到的最初Ghost协议版本存在的缺陷。但这样仍然存在一定的问题。
(2)我们将“叔父”这个概念进行扩展,但问题在于,“叔父”这一定义隔多少代才好呢?
如下图所示,M为该区块链上一个区块,F为其严格意义上的叔父,E为其严格意义上的“爷爷辈”。以太坊中规定,如果M包含F辈区块,则F获得7/8出块奖励;如果M包含E辈区块,则F获得6/8出块奖励,以此类推向前。直到包含A辈区块,A获得2/8出块奖励,再往前的“叔父区块”,对于M来说就不再认可其为M的"叔父"了。对于M来说,无论包含哪个辈分的“叔父”,得到的出块奖励都是1/32出块奖励。也就是说,叔父区块的定义是和当前区块在七代之内有共同祖先才可(合法的叔父只有6辈)。
(3)这样,就方便了全节点进行记录,此外,也从协议上鼓励一旦出现分叉马上进行合并。对于区块链当前状态产生了临时性的意见分歧,我们想办法把它合并。如果是别的原因,像我们前面说的比特币脚本时候,CHECKMULTISIG(这个操作是检查多重签名的合法性),这个操作的实现上有一个bug,它检查的时候会从堆栈里面多弹出一个元素,所以实际上如果你正常操作的话是检查不通过的,你得先往里面压一个多余的元素,就为了应付这个bug。为什么不能把这个bug改掉呢,这是因为你改完后版本不一样了,会出现硬分叉(这里不同于中心化的系统)。两条链如果不是因为对当前状态有意见分歧而是互相认为对方是非法的(认为对方的区块包含非法交易),那么用这种方法是合并不了的。
(4)以太坊中的奖励,如下
(5)以太坊中包含了叔父区块,要不要包含叔父区块中的交易?
答:不应该,叔父区块和同辈的主链上区块有可能包含有冲突的交易。而且我们前文也提到,叔父区块是没有动态奖励的。因此,一个节点在收到一个叔父区块的时候,只检查区块合法性(是否合法发布,是否符合挖矿难度)而不检查其中交易的合法性。假设我的一个交易被叔父区块包含了,也就是说我的交易并没有得到执行。这个问题中,矿工不吃亏,拿到了交易费,但是我的交易没有执行。主链节点收到你的交易后还会继续执行的,可能你要再等一个区块,但是还是会执行的,最终flooding到所有节点。
(6)它是怎么检测它前面链上有多少个叔父区块?
每个已发布的区块,你得说明你的父区块是哪个区块,所以可以检查你的父区块和当前区块是不是有共同祖先。
(7)那么对于分叉后的堂哥区块怎么办?
例如下图所示,A->F该链并非一个最长合法链,所以B->F这些区块怎么办?该给挖矿补偿吗?
如果规定将下面整条链作为一个整体,给予出块奖励,这一定程度上鼓励了分叉攻击(降低了分叉攻击的成本,因为即使攻击失败也有奖励获得)。因此,ETH系统中规定,只认可A区块为叔父区块,给予其补偿,而其后的区块全部作废。
(8)我们设计这个协议的主要目的是为了解决系统中出现的临时性分叉,包括我们说的比特币也好,以太坊也好,为什么规定最长合法链,为了防止篡改,使得交易不容易被篡改,其实也是为了解决临时性分叉。最长合法链提供了一个出现临时性分叉后进行运行合并的一种机制。
(9)我们一起看看以太坊的一些真实数据
上图显示的是叔父区块的几种情况,这里每一行对应一个叔父区块,第一列的block height就是区块的序号也就是block number像第一行(第一个红框)的叔父区块的序号比这个区块本身要小两个,这个说明是一个距离为2的叔父区块,应该得到6/8的奖励也就是6/8 * 3 = 2.25个以太币。接下来·两行都属于这种情况的叔父区块。再往下面一行(第二个红框),叔父区块的序号只比它小一个,说明是当代叔父,应该得到7/8的奖励也就是7/8 * 3 =2.625个以太币,后面的可以此类推。说明系统中大多数分叉都很快得到了合并,最下面这一行的叔父区块的序号比这个区块小三个,那么应给得到5/8的奖励。下面表格给出的不同辈分的叔父得到的uncle reward的数。
我们再看看下面两个区块的例子,左边这个区块包含了一个叔父区块,我们可以看到倒数第二行的uncle reward 是2.25,可以判断这是一个距离为2的叔父。这个区块得到的奖励,就是他本身得到的reward(倒数第三行这部分内容),是由三块内容组成,出块奖励+汽油费+包含叔父区块得到的奖励。
我们再看一下右边的区块,包含了两个叔父区块,一个距离为1的当代叔父另一个是距离为2的上一代叔父。所以这里它倒数第二的uncle reward为2.25+2.625=4.875,这个区块的reward也是三部分内容。大家可以通过第一行的height来查一下,比如左边这个区块,它的height就是5695161,第一个红框对应点这一行。右边区块类似。
(1)对于基于工作量证明的区块链系统来说,挖矿是保障区块链安全的一个重要手段。所以有一句话叫做,block is secured by mining。比特币中用的挖矿算法,总体来说是比较成功的。经受了时间的检验,到目前为止没有人发现里面有什么大的漏洞。
(2)bug bounty(公司悬赏找软件漏洞,找到了就可以得到一笔赏金),比特币的挖矿算法是一个天然的bug bounty。如果你能找到里面的漏洞,或者是某一个挖矿的捷径,就能取得很大的利益。但是到目前为止,还没有人发现有什么捷径可以走,所以说比特币的挖矿算法总的来说是比较成功的,是经受了时间考验的。但是比特币的挖矿算法也有一些值得改进的的地方。其中一个饱受争议的问题就是挖矿设备的专业化,用普通计算机挖不到矿,只能用专门的设备,专门的ASIC芯片来挖矿很多人认为这种做法与去中心化的理念背道而驰。中本聪最早的比特币论文中提到了一个说法叫做,one CPU one vote。理想情况下,应该让普通人也能够参与挖矿的过程,就用自家的桌面机,笔记本电脑甚至手机来挖矿,这样也更安全。因为算力分散后,有恶意攻击者想要聚集到51%的算力发动攻击,难度也会大得多。
(3)所以比特币之后出现的很多加密货币,包括以太坊设计mining puzzle,一个目标就是要做到ASIC resistance。那么怎么才能够设计出一个队ASIC芯片不友好的mining puzzle呢?一个常用的做法就是增加这个puzzle对内存访问的需求,也就是所谓的memory hard mining puzzle。这是因为,ASIC芯片相对于普通计算机来说,它的主要优势就是算力强,但是在内存访问的性能上并没有那么大优势。ASIC矿机的计算能力可能是普通计算机的几千倍,因为它里面有很多核,能进行大量的并行计算,但是在内存访问上,性能差距并没有那么大。所以说,如果我们能设计出一个对内存要求很高的puzzle,那么就能够起到遏制ASIC芯片的作用。那么该如何设计呢?
(1)在这方面一个早期的例子,LiteCoin(莱特币)。莱特币曾一度成为市值仅次于比特币的第二大货币。莱特币的puzzle基于Scrypt。Scrypt为一个对内存性能要求较高的哈希函数,之前多用于计算机安全密码学领域。
(2)莱特币挖矿算法基本思想:
1.设置一个很大的数组,按照顺序填充一些伪随机数。因为哈希函数的输出我们并不能提前预料,所以看上去就像是一大堆随机的数据,因此称其为“伪随机数”。实际上,我们不可能真的用随机数,真的用随机数的话,没办法验证。
Seed为种子节点,通过Seed进行一些运算获得一个数,放在数组第一个位置,之后每个数字都是通过前一个位置的值取哈希得到的。可以看到,这样的数组中取值存在前后依赖关系。
2.在需要求解Puzzle的时候,按照伪随机顺序,从数组中读取一些数,每次读取位置与前一个数相关。例如:第一次,从A位置读取其中数据,然后对A中的数值进行一些运算,获得下一次读取位置B;第二次,从B位置读取其中数据,根据B中数据计算获得下一次读取位置C;
(3)分析:
如果数组足够大,对于挖矿矿工来说,必须保存该数组以便查询。如果你没有这个数组的话,你还得从第一个数,依次算出A这个数的值。然后要读取第二个位置的数,你没有保存,那么得再算一遍,算到B这个位置的值,然后后面的C也一样。这对于矿工来说,计算复杂度大幅度上升。所以要想高效的挖矿,内存区域是需要保存的。当然,矿工可以选择只保存一部分数据,例如:只保存奇数位置数据,偶数位置需要时再根据前一个奇数位置数据计算即可,从而对内存空间大小减少了一半(计算复杂度提高一点,但内存减少一半),也称作time memory trade off。
(4)这个设计有问题吗?
(5)因此,莱特币真正应用来说,数组大小不敢设置太大。例如:对于计算机而言,1G毫无压力,而对于手机APP来说,1G占据空间就过大了。所以,实际中,莱特币系统设计的数组大小仅仅128K大小。起初莱特币发行时,不仅希望能够抗拒ASIC,还希望能抗拒GPU。但实际中,后来慢慢出现了GPU挖矿,再后来,ASIC芯片挖矿也出现了。实际应用中,莱特币的设计并未起到预期作用,也就是说,128k对于ASIC Resistance来说过小了。
(6)莱特币的这一设计是好事还是坏事?
(7)能启动问题:任何一个加密货币都存在能启动问题,包括比特币一开始的时候,没有人知道这个加密货币。这就有一个问题,对于基于工作量证明的加密货币来说,挖矿人太少,是不安全的,因为发动恶意攻击难度太低了。
(1)让我们看看以太坊的设计,以太坊的理念与莱特币相同,都是Memory Hard Mining Puzzle,但具体设计上与莱特币不同。
(2)以太坊挖矿算法基本思想:
以太坊中,设计了两个数据集,一大一小。小的为16MB的cache,大的数据集为1G的dataset(DAG)。其关系为,1G的数据集是通过16MB数据集生成而来的。
(3)思考为何要设计一大一小两个数据集?
为了便于进行验证,轻节点保存16MB的Cache进行验证即可,而矿工为了挖矿更快,减少重复计算则需要存储1GB大小的大数据集。
(4)16MB的小Cache数据生成方式与莱特币中数组的生成方式较为类似,大致如下:
1.通过Seed进行一些运算获得第一个数,之后每个数字都是通过前一个位置的值取哈希获得的。这样把整个数组从前往后填充这些伪随机数就得到了一个cache。
2.区别如下:
莱特币:直接从数组中按照伪随机顺序读取一些数据进行运算。
以太坊:先生成一个更大的数组,这个大数组比小数组要大得多。(注:以太坊中这两个数组大小并不固定,因为考虑到计算机内存容量不断增大,因此该两个数组需要定期增大)
3.大的DAG生成方式:
大的数组中每个元素都是从小数组中按照伪随机顺序读取一些元素,方法同莱特币中相同。如第一次读取A位置数据,对当前哈希值更新迭代算出下一次读取位置B,再进行哈希值更新迭代计算出C位置元素。如此来回迭代读取256次,最终算出一个数作为DAG中第一个元素,如此类推,DAG中每个元素生成方式都依次类推。
(5)分析:
轻节点只保存小的cache,验证时进行计算即可。但对于挖矿来说,如果这样则大部分算力都花费在了通过Cache计算DAG上面,因此,其必须保存大的数组DAG以便于更快挖矿。
(6)以太坊挖矿过程(求解puzzle过程):
根据区块block header和其中的Nonce值计算一个初始哈希,根据这个哈希映射到大数据集某个,例如位置A,读取A位置的数及其相邻的后一个位置A’上的数,根据该两个数进行运算,算得下一个位置B,读取B和B’位置上的数,依次类推,迭代读取64次,共读取128个数。最后,计算出一个哈希值与挖矿难度目标阈值比较,是否符合难度要求。若不符合就重新更换Nonce,重复以上操作直到最终计算哈希值符合难度要求或当前区块已经被挖出。
(7)从伪代码理解以太坊挖矿算法
上面这两个函数分别是矿工用来挖矿的函数和轻节点用来验证的函数。我们来看一下第一个函数,第一个参数header是当前要生成的区块的块头,以太坊和比特币一样,挖矿只用到块头信息。第二个参数nonce是当前尝试的nonce值。第三个参数full_size,这是大数据集中元素的个数,这个元素的个数每3万个区块会增加一次,增加原大小的1/128。
挖矿过程如下:先通过header和当前nonce求出一个初始的哈希值,然后要经过64轮的循环,每一轮循环读取大数据集中两个相邻的数,读取的位置是由当前哈希值计算出来的,再根据这个位置上的数值来更新当前的哈希值,这个前面生成大数据集的方法是类似的。循环64次最后返回一个哈希值,用于和挖矿难度的目标阈值相比较。
思考题:这两个值相关吗?
答:是没有关系的,这两个值虽然位置上相邻,但是生成过程是独立的,都是由前面的16M的cache生成。
上图第二个函数是轻节点用来验证的函数,也是四个参数,但是含义和上面矿工用的函数有所不同。轻节点是不挖矿的,当它收到某个矿工发布的一个区块时,这里用来验证的这个函数的第一个参数header是这个区块的块头,第二个参数nonce是包含在块头里面的nonce,是发布区块的矿工选好的。轻节点的任务是验证nonce是否符合要求,验证用的是16M的cache,也就是最后一个参数cache。第三个参数full_size,和上面挖矿用到的函数里面的full_size含义相同,它并不是cache中元素个数,验证过程也是64轮循环,看上去和挖矿过程类似。
那么这两个函数有什么区别呢?
每次需要从大数据集中读取元素的时候,因为轻节点没有保存大数据集,所以要从cache中重新生成,其他地方的代码逻辑是一样的。大数据集中这个位置的元素,前面提到过,每个位置的元素都可以独立生成出来。
(8)目前以太坊挖矿以GPU为主,用ASIC矿机的很少,从这点来看它比莱特币要成功,起到了ASIC resistance的作用。这与以太坊设计的挖矿算法(Ethash)所需要的大内存具有很大关系。
(9)初识权益证明(POS: Proof of Stake),这个下文有一节专门讲这个,
(10)预挖矿(Pre-Mining)
(11)下面我们一起看看以太坊的一些统计数据
(12)其他观点:
(1)前面文章中介绍了比特币难度调整是每隔2016个区块调整难度,从而达到维持出块时间10min的目标。而以太坊则与之不同,每个区块都有可能会进行难度调整。
(2)以太坊难度调整较为复杂,修改过好几个版本,网络上关于这方面介绍存在诸多不一致,包括以太坊的黄皮书和实际代码也有一些出入,我们这里遵循以代码为准的原则,从以太坊的代码中来分析以太坊难度调整算法。以太坊中区块难度调整公式如下图所示:
(3)我们先看看第一部分,第一部分的调整方法是在父区块的难度基础上加上一些自调整的部分,P(H)hd就是父区块的难度。所谓的父区块就是当前区块链的最后一个区块,对于我们正在挖的区块来说,它是这个区块的父区块。第一部分的难度调整有一个下限,就这个D0=131072这部分,不论你怎么去调整,最小不能低于这个难度,这是为了保证挖矿有一个最低的难度。后面这个ε(epsilon)部分就是难度炸弹部分。
(4)继续观察第一部分,如上图,这里的x是调整力度,是父区块的难度除以2048,所以调整难度的时候,不论是上调还是下调,都是按照力度的整数倍进行调整,按照父区块的难度的1/2048作为一个调整单位。x后面那个符号是σ(sigma),它的计算如上图。σ的取值和两个因素有关,一个是出块时间,另一个是有没有叔父区块,就是父区块有没有叔父区块。那么问题来了,为什么要和叔父区块相关呢?
(5)我们仔细看一下上图的公式,这个y就是取决于有没有叔父区块,有叔父区块的话y=2,没有叔父区块的话y=1。不论哪种情况,它都是个常数,所以它实际上就是一个常数减去后面一个项,如果后面这个项比这个常数大的话,减出来是个负数,说明这个难度是要下调的;相反,如果后面一项比前面要小的话,减出来是正数,说明难度要上调。这个Hs是当前区块的时间戳,这个P(H)是父区块的时间戳,那么两项相减就是当前区块的出块间隔,然后出块间隔除以9再向下取整。那么为什么要这么设计?
(6)讲完了基础部分,下面我们介绍一下难度炸弹。
(7)我们来看看难度炸弹有什么特点,如上图,当初设计难度炸弹时候没有这个第二行(就是减300万那一行),第一行直接用的Hi(当前区块的序号),没有Hi’这一项。观察一下这个公式有什么特点,很显然一个指数模型。也就是说难度炸弹这部分的取值是呈指数形式增长的。
(8)观察下图,可以看到,在以太坊早期时,区块号较小,难度炸弹计算所得值较小,基本可以忽略不计,难度调整主要还是上通过前面介绍的第一部分(基础部分)来决定,而随着越来越多区块被挖出,区块号变得越来越大,难度炸弹的威力开始显露出来,指数函数增长到后期速度是非常恐怖的。
(1)以太坊发展被分为四个阶段如下图,其中的metropolis又分为两个阶段,我们正处于第一个阶段,叫做拜占庭阶段。难度炸弹的回调就是在拜占庭阶段进行的。EIP叫做Ethereum Improvement Proposal。
(2)在难度回调的同时,把出块奖励从5个以太币降到了3个以太币。那么为什么会做出如此调整呢。因为如果不这么调的话,对于回调之前的矿工是不公平的。因为回调是突然进行的,比如昨天我辛辛苦苦挖矿得到了5个以太币,今天一夜之间难度降低了,另一个人挖矿也得到了5个以太币,这就对我很不公平。而且从这个系统中货币的总供应量来说,也要维护总供应量的稳定。现在挖矿容易了,相应的就把出块奖励减少一些。
(3)注意:比特币中那个每隔一段时间就把出块奖励减半的做法,以太坊中是没有的,像这种把5个以太币的出块奖励降为3个,这是一次性的,并非以后定期都会这么做。
(4)下面我们看一下具体的代码实现。如下图这是拜占庭阶段计算挖矿难度调整的代码,它的输入是父区块的时间戳和父区块的难度,从而计算出当前正在挖的这个区块难度。图中的注释给出了难度计算公式,和前面我们说的是一样的。它也是分成两部分,
(5)基础部分计算,如下图,这段代码主要是计算基础部分的难度调整。
(6)难度炸弹计算
如下图为fake block number,也就是假的区块号,我们前面说的Hi’。
先看这个if判断,和2999999比较,比它大的话就要减掉2999999。
那么问题来了,为什么不减3000000,之前说的那个公式不应该减300万吗?
因为判断的是父区块的序号,而我当前挖的区块要比父区块的序号多一个,所以你得按照父区块的序号算的话,正好差一个。
再下面是把假的区块号除以expDiffPeriod,也就是除以10万,然后向下取整,再减去2,然后把这个结果当做2的指数部分,算出来的就是难度炸弹的取值。最后加到x上面,x就是前面代码中算出的基础部分难度x。
(7)下面我们一起来看看以太坊中的实际情况
之前的文章中,我们一直在提到权益证明(POS),本章节便专门讲述权益证明。
(1)比特币和以太坊目前采用的都是POW(工作量证明)机制,但这种方式受到一个普遍的批评,就是浪费电。如下图,我们这个图上显示了比特币能耗随时间变化的情况,y轴是TWh(Tera Watt Hour)是10的12次方。我们比较熟悉的是KWh(kiloWatt-hour),它是10的三次方,叫做千瓦时一度电。下图中,我们可以看出比特币的能耗随时间是不断增长的。
(2)下图给出了一些具体的统计数据。比特币每年的总能耗大概是70个TWh,相当于647万多个美国家庭的能耗,占世界总能耗的0.31%。具体到每个交易上来说,平均每个交易的能耗是1014千瓦时,相当于34.26个美国家庭一天的能耗,这是相当大的。一个交易要花1000度电,这听起来很吓人。信用卡公司处理一个交易的能耗,远远没这么大。比特币挖矿的每年总收入是60多亿美元,将近61亿美元,然后费用差不多35亿美元,占总收入的57.48%。说明挖矿的利润空间还是很大的。
(3)下面我们一起看看以太坊的数据,如下图。以太坊的能耗也是随时间增长的,中间有一些波动。
(4)如果我们把比特币和以太坊能耗加在一起当做一个国家来算的话,那么它在国家中的排行榜是这样的,如下图:
(1)让我们一个思考以下几个问题:
显而易见,“挖矿”过程消耗了大量的电力资源,这些能耗是必须的吗?
1.矿工挖矿是为了取得出块奖励,获取收益。而系统给予出块奖励的目的是激励矿工参与区块链系统维护,进行记账,而挖矿本质上是看矿工投入资金来决定的(投入资金买设备->设备决定算力->算力比例决定收益)。
2.所以说白了,挖矿的收益是靠拼钱决定的。那么,为什么不直接拼“钱”呢?我们直接把钱拿出来比一比不就行了吗。现在是矿工通过竞争算力来决定挖矿的收益如何分配,我们能不能把它改成直接靠比钱的多少来决定收益分配。比如,我出100万,你出50万。目前的做法是咱两都用这个钱去买矿机,然后大家的矿机开始挖矿比拼算力,看谁挖的区块多。
3.与其这样,还不如我们把这些钱投入到区块链的开发,将来就按照每个人投入的资金多少来决定收益的分配,就别挖矿了,直接拼钱就行。这就是权益证明的基本思想。有时候管这种方法叫做virtual mining(虚拟挖矿)。采用权益证明的加密货币,一般在正式发行前,会先预留一些货币给开发者,也会出售一些货币换取开发所需要的资金。那么将来按照权益证明的共识机制是按每个人持有的货币数量来进行投票的。
(2)这种方法和工作量证明相比有如下特点:
(3)下面解释一下具体意思
(4)首先,我们思考一下权益证明是如何工作的。
(5)权益证明和工作量证明并不是互斥的,有的加密货币采用的就是一种混合模型。它仍然是要挖矿的,但是挖矿难度和你占有的权益(或者说你持有的币的数量)是相关的。
(6)当然,权益证明这么好,为什么实际中并未得到大规模应用呢?原因是其中仍然存在很多挑战。
(7)以太坊拟采用的权益证明
以太坊中,准备采用的权益证明协议为Casper the Friendly Finality Gadget(FFG),该协议在过渡阶段是要和POW结合使用的。为工作量证明提供finanlity。finanlity是一种最终的状态,包含在finanlity中的交易不会被取消。单纯基于工作量证明(或者说基于挖矿)的交易是有可能被回滚的。
比如说某个交易被写到区块链里了,然后有人从前面开始分叉,挖出一条更长的分叉链。这时候你原来写入区块链的交易有可能就无效了。像比特币当中规定要等六个确认区块,这只是说你等六个确认区块后,发生回滚的可能性已经非常小了。但是如果有某个有恶意的攻击者,从前面开始分叉,只要他算力足够强,比如说占到了半数以上的算力,那么仍然有可能让分叉链比原来的链更长。所以单纯基于挖矿的区块链是缺乏这种finanlity。
(8)那么Casper协议具体是怎么做的呢?
(9)矿工挖矿会获得出块奖励,而验证者做的工作也会得到相应奖励。
(10)Casper 协议可以给挖矿挖出来的区块链的某种状态做一个检查点(checkpoint),这是不是绝对安全的,或者说通过验证者投票达成的finanlity有没有可能被推翻?我们之前说包含在finanlity中的交易是不会被推翻的,这个是否绝对呢?
(11)所以我们可以看到基于权益证明的共识机制和基于工作量证明的共识机制是很不一样的。以太坊系统设想是要逐步从工作量证明过渡到权益证明。随着时间的推移,挖矿得到的奖励逐渐减少而权益证明得到的奖励逐渐增多,最后达到完全不用挖矿。既然权益证明这么好,为什么以太坊不从一开始就用权益证明。这是因为权益证明不是很成熟,工作量证明是比较成熟的,是经过时间检验的。前面我们说过bug bounty,比特币和以太坊的挖矿算法都经历了bug bounty的检验,没有人发现有什么漏洞。很多人认为权益证明是未来的方向,但是目前主流的加密货币用的还是工作量证明,像以太坊一直到现在用的还是工作量证明。
(12)其他观点:前面的基本观点都是基于“挖矿消耗大量电能,这是不好的”,但也有人持有相反观点。
五一假期结束前终于更完了以太坊相关的基础知识,如发现错误欢迎联系博主,本人会马上修改。另外下一次博客会介绍几个以太坊智能合约的相关项目。假期结束了,各位加油学习。另外博客更新不易,感觉本人写的不错的话,麻烦给个三连支持一下,谢谢。