ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

以太坊的挖矿算法

2021-02-19 23:59:29  阅读:237  来源: 互联网

标签:这个 读取 比特 以太 算法 哈希 挖矿


十八、以太坊的挖矿算法

对于基于工作量证明的系统来说,挖矿是保障区块链安全的重要手段,有时候说Block chaim is secured by mining,比特币里面的挖矿算法总的来说是比较成功的,经受了时间的检验,到目前为止,没有人发现,也没有什么大的漏洞。

bug bounty:bounty(赏金)

美国电影有一个叫bounty hunter(赏金猎人),专门去抓那些政府悬赏捉拿的逃犯

bug bounty:有的公司悬赏来找软件中的漏洞,如果能找到软件中的安全漏洞就可以得到一笔赏金。

比特币的挖矿算法是一个天然的bug bounty,如果你能找到里面的漏洞,或者是某一个挖矿的捷径就能取得很大的利益。但是到目前为止还没有人发现有什么捷径可走,所以比特币的挖矿算法总的来说是比较成功的,是经受住时间检验的,但是比特币的挖矿算法也有一些值得改进得地方,其中有一个保守争议得问题就是挖矿设备得专业化,有普通的计算机挖不倒矿,只能用专门的设备,专用的ASIC芯片来挖矿,那么很多人认为这种去中心化的做法和去中心化的理念是背道而驰的,也跟比特币的设计初衷相违背的,中本聪最早的一篇论文,提出One cpu,one vote,理想状况下,应该让普通老百姓也能参与挖矿过程,就用家里的桌面机,笔记本电脑,甚至手机来挖矿,这样也更安全,因为算力分散之后,有恶意的攻击者想要聚集到51%的算力发动攻击,这个难度就会大得多。所以比特币之后出现的加密货币包括以太坊设计mining puzzle的时候,一个目标就是要做到ASIC resistance,那么怎么才能设计出对ASIC芯片不友好的mining puzzle呢?

一个常用的做法就是增加mining puzzle对内存访问的需求,也就是所谓的memory hard mining puzzle,ASIC芯片相对于普通计算机而言,主要优势是算力强,但是在内存访问的性能上没有那么大的优势,同样的价格买一个ASIC矿机和买一个普通的计算机,这个ASIC矿机的计算能力是普通计算机的几千倍,但是内存访问方面的性能差距远远没有这么大,所以能设计出一个对内存要求很高的puzzle,就能起到遏制芯片的作用。

怎么设计呢?

一个早期的例子是莱特币,曾经是市值仅次于比特币的第二大加密货币,他用的Puzzle是基于Scrypt,这个是对内存要求很高的哈希函数,以前用于计算机安全领域,跟密码相关,那么他的具体设计思想是说,开一个很大的数组,然后按照顺序填充一些伪随机数,比如说有一个种子节点,seed的值通过一些运算,算出一个数来,填在第一个位置,然后后面每个位置都是前一个位置的值取哈希得到的,伪随机数是说取哈希值后的值你也不知道,看上去就是乱七八糟的数一样,就好像随机数,但我们不可能真的用随机数,真的用随机数没法验证。填充完之后,里面的数值是有前后依赖关系的,是从第一个数依次算出来的,然后需要求解这个puzzle的时候,按照伪随机数的顺序从数组当中读取一些数,每次读取的位置跟前一个数相关,比如说要解puzzle了,一开始读取A这个位置的数,把A位置的值读取出来之后,根据他的取值进行一些运算,算出下次要读取的位置,比如说是B这个位置,然后把B这个位置的数读出来,再进行一些运算得到下一个读取的位置,比如说C这个位置,这个也是一种伪随机数的顺序,因为经过哈希运算之后得到下一个读取的位置。

在这里插入图片描述

这样做的好处:
如果这个数组开的足够大的时候,挖矿的矿工就是memory hard,因为如果不保存数组,那么挖矿的计算复杂度会大幅度上升,比如说,在读取数组里面这些数的时候,你没有保存数组,那要怎么办,比如说求解puzzle的时候,一开始在A这个位置,如果没有数组的话,还得从第一个数,依次算出这个值,然后要读取第二个位置的数,这些没有存起来,再算一遍算到B位置的值,下面是C,也一样,要算到C位置的值,这个计算复杂度会大幅度上升。

所以要想高效地挖矿,这个内存区域是需要保存的,有的矿工可能保存一部分内存区的内容,比如说,这个数组当中只保留奇数位置地元素,偶数位置地元素就不存了,这样数组可以少一半,那用到偶数位置的数怎么办呢,要根据另外一半去算一下,计算复杂度会提高一点,但是内存量可以减小一半,管它叫做time-memory trade off。

这个设计的核心思想是不能像比特币那样主要进行哈希运算,比特币其实也不是取一次哈希,他是取两次哈希,但这个不够,要增加他的运算过程中对内存访问的需求,要设计一个对ASIC芯片不友好的,对普通计算机能参与的。设计的任务更像是普通计算机干的事情,而不是像一个挖矿专用的ASIC芯片干的事情,普通计算机内存很大,就要利用这个特性,设计puzzle对资源的需求,特别像是普通计算机对资源的配备比例。

这个puzzle好的地方:对于矿工挖矿的时候是memory hard。

坏的地方:对轻节点来说也是memory hard。

前面讲过设计puzzle的一个原则:difficult to solve,but easy to verify,这个问题就在于验证这个puzzle需要的内存区域跟求解这个puzzle需要的区域几乎是一样大的,轻节点验证的时候也得保存这个数组,要不然他的计算复杂度也是大幅度提高,对于scrypt早期计算机的安全领域,这个密码方面的话他不是一个问题,他没有轻节点验证这个问题,但对于我们这个来说是不行的,这样造成一个结果就是莱特币在真正使用的时候,这个内存区域不敢设置的太大,比如说你设一个1G的数组,这对于计算机来说是不大的,但是如果是一个手机上的app,1G的内存可能就太大了,因为这个原因,实际莱特币在使用的时候,这个数组只有128Ks,这个是非常小的,连1M都不到,就是为了照顾轻节点,那么最后的效果怎么样呢

当初莱特币在发行的时候,目标不仅仅是ASIC resistance,还是GPU resistance,就是挖矿最好连GPU都不要用,都用普通的CPU挖矿就行了,结果后来就出现GPU挖矿的,再后来就出现用ASIC芯片挖矿的,实践证明莱特币要求的128k内存不足以对ASIC芯片的生产和设计带来实际上的障碍,所以从这一点来说,莱特币的设计目标没有达到,但是他早期宣传的设计目标对于解决能启动问题是很有帮助的,任何一个加密货币,都存在能启动问题,包括比特币,一开始的时候,没有人知道这个加密货币,你就发行一个货币,也没有人理你,那怎么办呢,没有人参与,这是一个问题,而且对于基于工作量证明的加密货币来说,挖矿人太少是不安全的,因为发动恶意攻击难度太低,比特币早期也是不安全的,一开始只有中本聪一个人在用,后来变成少数几个人在挖矿,那个时候,如果想对比特币发动恶意攻击是很容易的,那么比特币是怎么解决这个能启动的问题呢,现在谁也说不清楚了,但总的来说是一个循坏迭代的过程,中本聪宣传的多了,对比特币感兴趣的人就多了,然后参与挖矿人就多了,变得更安全,价值也提高了,然后对比特币感兴趣的人就更多了,挖矿的人也更多了,然后比特币变得更安全了,价值就更进一步提高了,形成一个良性循坏。莱特币虽然没有达到当初的设计目标,但是他早期的宣传,更民主,让更多人参与的理念对于聚集人气来说是很重要的,所以莱特币一直到现在也是一个比较主流的加密货币,除了这个mining puzzle之外,莱特币跟比特币的另一个区别是来特比的出块速度是比特币的4倍,他的出块间隔是两分半,而不是十分钟,除此之外,这两种加密货币基本上是一样的。

以太坊也是用一种memory hard mining puzzle,但是在设计上,跟莱特币有很大的不同

以太坊用的是两个数据集,一大一小,小的是16M cache,大的数据集是一个1G dataset,DAG,这1G的数据集是从16M的cache生成出来的,为什么要设计成一大一小的两个数据集呢,就是为了便于验证,轻节点只要保存16M cache就行了,只有需要挖矿的矿工才需要保存1G的dataset。

基本思想:
小的数据集的生成方式跟前面讲的数组的生成方式是比较类似的,首先从一个种子节点seed,进行一些运算,算出数组的第一个元素,然后依次取哈希,第一个元素取哈希得到第二个元素,第二个元素取哈希得到第三个元素,这样从前往后,把这个数组从前往后,填充一些伪随机数得到一个cache,下面和莱特币就不一样了,莱特币是直接从数组当中按照伪随机数的顺序读取一些数,然后进行运算,以太坊是要先生成一个更大的数组,这里没有按比例画,就这个大数组应该比下面的小数组要大得多,下图看就大了一点,因为黑板画不下了,就意思意思,而且小的cache和大的dataset都是定期增长的,每隔一段时间,大小要增大,因为计算机的内存容量也是定期增长的,比如说这个大的dataset涨到了2.5G,就已经不是一个G了,那大的dataset是怎么生成的呢,他的每个元素小的cache里按照伪随机数的顺序读取一些元素,方法和刚才讲的莱特币里面求解puzzle的过程是类似的,比如说,第一次读取A位置的元素,读取完之后,对当前的哈希值进行一些更新迭代,算出下一个要读取的位置,比如说B这个位置,然后把B位置的数再进行一些哈希值的更新,算出C这个位置,那么从这个cache里面这么来回读,一共读256次,读256个数,最后算出来一个数放在大的dataset的第一个元素,然后第二个元素也是一样的,dataset的每个元素都是从这个cache里面按照伪随机数的顺序,不断进行迭代更新,最后得到一个值存在里面,然后求解puzzle的时候,用的是大数据集中的数,这个cache是不用的,按照伪随机数的顺序在大的数据集中读取128个数,就是一开始的时候根据区块的块头,包括里面的nonce值算出一个初始的哈希,根据这个哈希,映射到大数据集里面的某个位置,把这个数读取出来,然后进行一些运算,算出下一个要读取的位置,比如说又在大数据集里面的另一个位置,又把这个数读取出来,这里有一个区别:他每次读取的时候除了计算出这个元素的位置之外,还要把相邻元素也要读取出来,这个例子当中每次读取的时候是读取两个相邻元素,这样循环64次,每次读两个元素,所以一共是符合难度要求128个数,最后算出一个哈希值来,跟挖矿难度的目标域值比较是不是符合难度要求,如果不是,把block header 里面的nonce替换一下,换另外一个nonce,因为换了nonce之后,第一次算的那个哈希值就变了,然后重复这个过程,根据这个哈希值找到数组中的元素,读取两个相邻的元素,反复循环64次,再得到一个哈希值,然后再去比较。

在这里插入图片描述

上面讲的比较抽象,下面是写的一个伪代码,没有直接用以太坊中的源代码,这个伪代码省略了源代码中的一些实现的细节,更有利于理解。

ethash算法伪代码

第一步首先生成16M cache,cache中每个元素都是64个字节的哈希值,生成的方法与莱特币类似,第一个元素是种子的哈希,就是这个seed的哈希,后面每个元素是前一个的哈希,这个哈希的内容每隔3万个区块会变化一次,这个seed每隔3万个区块会发生变化,然后重新生成cache中的内容,同时cache的容量要增加原始大小的1/128,也就是16M的1/128=128K。

在这里插入图片描述

第二步是从这个cache生成1G的大数据集,这个函数的功能是通过cache来生成dataset中的第i个元素,基本思想是按照伪随机数的顺序读取cache中的256个数,每次读取的位置是由上一个位置的数值经过计算得到的,这里用的两个函数get_int_from_item和make_item,是自己定义的,源代码中是没有的,把源代码中一些相关的内容总结成了这两个函数,可以避免源代码中不是很重要的细节,这个get_int_from_item函数就是用当前算出来的哈希值求出下一个要读取的位置,然后make_item函数用cache中这个位置的数和当前的哈希值计算出下一个哈希值,这样迭代256轮,最后得到一个64字节的哈希值,作为大数据集中的第i个元素。

在这里插入图片描述

这个calc_dataset是生成整个1G数据集的过程,就是不断调用前的函数来依次生成大数据集中的每个元素

在这里插入图片描述

这一页的两个函数,分别是矿工用来挖矿的函数,和轻节点用来验证的函数,先看一下上面这个函数,这个矿工用来挖矿的函数,他有四个参数,header是当前要生成的区块的块头,以太坊和比特币一样,挖矿只用到块头的信息,这样设计的原因,是轻节点只下载块头,就可以验证这个区块是否符合挖矿的难度要求,第二个参数nonce就是当前尝试的nonce值,以太坊就像比特币一样,挖矿的时候,也是要尝试大量的nonce才能找到一个符合要求的,第三个参数full_size是大数据集中元素的个数,元素的个数每3万个区块会增加一次,增加原始大小的1/128也就是1G的1/128=8M,最后参数dataset就是前面生成的大数据集,挖矿的过程是这样的,首先根据块头的信息,和当前Nonce算出一个初始哈希值,然后要经过64轮的循环,每一轮循环读取大数据集中两个相邻的数,读取的位置是由当前哈希值计算出来的,然后再根据这个位置上的数值来更新当前的哈希值,这跟前面生成大数据集的方法是类似的,循环64次,最后返回一个哈希值,跟挖矿难度目标域值相比较。

这里提个小问题,每次读取大数据集中两个相邻位置的哈希值,这两个哈希值有什么联系吗?

其实是没有联系的,他们虽然位置相邻,但是生成的过程是独立的,每个都是由前面那个16M的cache中的256个数生成的,而且256个数的位置是按照伪随机数的顺序产生的,这个是构造大数据集的一个特点,每个元素独立生成,这才给轻节点的验证提供了方便,所以每次读取的相邻两个位置的哈希值是没有什么联系的。

下面这个函数是轻节点用来验证的函数,也是有四个参数,但是含义跟上面那个矿工用的函数有所不同,轻节点不挖矿,当他收到某个矿工发的区块的时候,这里用来验证的函数的第一个参数header是这个区块的块头,第二参数是包含在这个块头里的Nonce,是发布这个区块的矿工选好的,轻节点的任务是验证这个nonce是否符合要求,验证用的是16M的cache,也就是最后的参数cache,注意,第三个参数full_size仍然是大数据集的元素个数,跟上面那个挖矿的那个full_size含义是一样的,并不是cache中的元素个数,验证的过程也是64轮循环,看上去与挖矿的过程类似,只有一个地方有区别,比较这一页的上下两个函数,有什么区别?

每次需要从大数据集中读取元素的时候,因为轻节点没有保留大数据集,所以要从cache中重新生成其他地方的代码逻辑是一样的,每次从当前的哈希值算出要读取的元素的位置,这个位置是指在在大数据集中的位置,但是轻节点并没有这个大数据集,所以要从cache中生成大数据集中这个位置的元素,我们前面说过大数据集中每个元素都可以独立生成出来。

在这里插入图片描述

最后这个函数,是矿工挖矿的主循环,其实是不断尝试nonce的过程,这里的target就是挖矿的难度目标,跟比特币类似,也是可以动态调整的,nonce的可能取值是从0-2的64次方,对每个nonce用前面讲的那个函数算出一个哈希值,看看是不是小于难度目标,如果不行的话,就再试下一个nonce。

在这里插入图片描述

最后这一页是前面讲过的所有函数的一个汇总,同时解释了为什么轻节点可以只保存cache,而矿工要保存整个大数据集。其实轻节点做一次验证的计算量也不算少,同样要经过64轮循环,每次循环用到大数据集中的两个数,所以是128个数,每个数是从cache里的256个数计算得到的,跟比特币相比,以太坊中验证一个nonce的计算量要大很多,但是仍然在可以接受的范围内,相比之下,如果矿工每次都这么折腾的话,代价就太大了,因为要尝试的nonce就太多了。

在这里插入图片描述

那以太坊设计的这个puzzle实际效果怎么样呢?

到目前为止,以太坊挖矿主要还是以GPU为主,用ASIC矿机的很少,所以从这一点来说,他比莱特币来说要成功,起到了ASIC resistance的作用,这个跟以太坊的挖矿算法需要的大内存是很有关系的,这个挖矿算法就是ethash,这个起的很有意思,前三个字母eth是以太坊的代码,后面这个hash,h用了两遍,矿工挖矿需要1G的内存,跟莱特币的128K比,差了有八千多倍,即使是16M的cache跟128K比,也要大了一百多倍,所以这个差距是很大的,而且还是按照这两个数据集的最初的大小算的,因为定期会增长嘛,如果按照现在这个2.5G差距就更大了,以太坊没有出现ASIC矿机还有另外一个原因,以太坊从很早就计划要从工作量证明转移到权益证明,所谓的PoW->PoS(Proof of Stake),所谓的权益证明,就是按照所占的权益进行投票来形成共识,就不用挖矿了,权益证明是不挖矿,就类似于股份公司按照股票多少来进行投票,这个对于ASIC矿机的厂商来说是个威胁,因为ASIC芯片的研发周期是很长的,一款芯片从设计研发流片到最后生产出来,一年的周期就已经算是很快的了,而且研发的成本也很高,将来以太坊转入权益证明之后,就不挖矿,那些投入的研发费用就白费了,其实到目前为止,以太坊是基于工作量证明,以太坊很早就说要转入权益证明,但是转移的时间点一再往后推迟,到现在也没转过来,但是他不停的宣称要这么做,所以要想达到ASIC resistance一个简单的办法就是不断地吓唬大家:大家注意哦,下面要搞权益证明就不挖矿了,所以你就不要设计ASIC矿机了,你设计出来到时候也没用了,因为要设计一年嘛,一年以后,我们就不挖矿了。

等过了一年,不行,还是得继续挖矿,那怎么办呢,再吓唬一次:我们真的再挖一年,然后就再也不挖了,所以你还是不要再设计了。

从历史看,以太坊成为一个主流的加密货币,其实就是最近两年的事情(2018),以前市值很小的时候,没有人会去设计ASIC芯片,因为划不来啊,无利可图,等到市值上来之后呢,你这么吓唬他几次,就能起到ASIC resistance的作用,这也是另外一方面的原因。

关于以太坊的挖矿还有一个要说明的

以太坊中采用了预挖矿,叫pre-mining,所谓预挖矿并不是说真的去挖矿,而是说,在当初发行货币的时候,预留一部分货币给以太坊的开发者,有点像创业公司会留一部分股票给创始人和早期员工一样,将来这个加密货币成功了的话,这些预留的币就变得是很值钱了。

像以太坊的早期开发者,现在就都很有钱,比北大教授要有钱多了,跟这个比特币相比呢,比特币就没有采用pre-mining的模式,所有的比特币都是挖出来的,只不过早期的时候,挖矿的难度,要容易的多,与pre-mining相关的一个概念叫pre-sale(就是把pre-mining预留的那些币通过出售的方法来换取一些资产用于加密货币的开发工作),有点类似于众筹,如果你看好这个加密货币的未来,可以在pre-sale的时候买入,将来这个加密货币成功之后呢,同样可以赚很大一笔钱

下面看一下以太坊上的一些统计数据

下面这个图显示了以太坊中货币供应量的分布情况,总共有大约一亿个以太币,每个以太币的市场价格是五百多美元,这里的数据是以前的,现在以太币的价格没有了解,整个以太坊的市值大概是五百多亿美元,下面这个图显示了这一亿的来源,绝大部分是通过pre-mining方法产生的,这个蓝色部分Genesis是指创世纪块中就已经包含了这些以太币,上线以后,再挖出来的以太币中Block Rewrad占了绝大多数,Uncle Reward就是前面讲的叔父区块得到的奖励只占很少一部分。有没有觉得毁三观,挖矿挖的再努力,关键还是不能输在起跑线上。

在这里插入图片描述

下图显示的是最大的以太坊矿池所占的算力比重,可以看出挖矿集中化的程度也是很高的,尤其是最大的几个矿池所占的比例很高,与比特币的情况类似

在这里插入图片描述

下图显示的是以太币的价格随时间变化的情况,可以看到在以太坊早期的那几年价格基本没怎么涨,真正的大涨是2017年,这一年的价格涨得非常猛,直到2018年初达到了顶峰,然后开始走下坡路,这个图显示的是以太坊的市值,叫Market Capitalization,这个跟价格的走势基本上是符合的

在这里插入图片描述

下图显示的是以太坊HashRate的变化情况,HashRate是指系统中所有的矿工加在一起,每秒钟计算的哈希次数,可以看到HashRate从总体来说是处于上升趋势的,而且也是从2017年开始大幅度上升的,2018年以太币的价格下跌了不少,HashRate总体上趋于平稳,并没有出现明显的下降,不同的货币入宫采用的mining puzzle不一样的话,那么它们的HashRate是不可比的,比特币和以太坊的HashRate就不能直接比较,因为以太坊中尝试一个nonce的工作量要比比特币大得多。

在这里插入图片描述

这篇文章讲的是挖矿的算法设计要尽可能让通用的设备也能参加,参加的人越多,挖矿的过程越民主,那么区块链就越安全,这也是为什么莱特币,以太坊要设计memory hard mining puzzle,但是也有一些人有不同的观点,认为让通用设备参加反而是不安全的,像比特币那样只能用专门的ASIC芯片挖矿才是更安全的,假设要对比特币系统发动攻击,需要投入大量资金买入ASIC矿机,才能聚集到发动攻击所需要的算力,而这些矿机除了挖矿之外,干不了别的任何事情,而且是为某一个加密货币设计的加密芯片,只能挖这一种加密货币,像比特币的ASIC芯片去挖莱特币就不行,所以呢,发动这个攻击的成本是很高的,早期需要投入大量的硬件资源,而且一旦攻击成功比特币系统的安全性被证明存在安全问题,大家对比特币的信心会大幅度下跌,然后比特币的价格也会跳水,这样早期投入的硬件成本就收不回来了,因为比特币本身就不值钱了,你买的那些比特币的矿机当然也不值钱了。相反如果让通用设别参与挖矿的话,发动攻击的成本就大幅度下降。所以有些人认为让通用设备参与挖矿是不安全的,让ASIC矿机一统天下才是安全的

标签:这个,读取,比特,以太,算法,哈希,挖矿
来源: https://blog.csdn.net/qq_44293330/article/details/113874105

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有