Skip to content

Latest commit

 

History

History
91 lines (44 loc) · 7.86 KB

File metadata and controls

91 lines (44 loc) · 7.86 KB

在之前的 BTC 篇中,介绍了比特币系统中使用的挖矿算法。挖矿这一过程,虽然并没有创造什么实际价值,但挖矿本身维持了比特币系统的稳定。总体来说,比特币系统中的挖矿算法较为成功,并未发现大的漏洞。

当然,比特币系统的挖矿算法也存在一定问题,其中最为突出的就是导致了挖矿设备的专业化,普通计算机用户难以参与进去,导致了挖矿中心化的局面产生,而这与“去中心化”这一理念相违背。

因此,在比特币之后包括以太坊在内的许多加密货币针对该缺陷进行改进,希图做到 ASIC Resistance(抗拒 ASIC 专用矿机)。由于 ASIC 芯片相对普通计算机来说,算力强但访问内存性能差距不大,因此常用的方法为 Memory Hard Mining Puzzle,即增加对内存访问的需求。

LiteCoin (莱特币)

莱特币的 puzzle 基于 Scrypt,Scrypt 为一个对内存性能要求较高的哈希函数,之前多用于计算机安全密码学领域。

莱特币挖矿算法基本思想

  1. 设置一个很大的数组,按照顺序填充伪随机数。Seed 为种子节点,通过 Seed 进行一些运算获得第一个数,==之后每个数字都是通过前一个位置的值取哈希得到的。可以看到,这样的数组中取值存在前后依赖关系==。

    图片说明

  2. 在需要求解 Puzzle 的时候,按照伪随机顺序,从数组中读取一些数,每次读取位置与前一个数相关。例如:第一次从 A 位置读取其中数据,根据 A 中数据计算获得下一次读取位置 B;第二次从 B 位置读取其中数据,根据 B 中数据计算获得下一次读取位置 C;

    图片说明

分析

==如果数组足够大,对于挖矿矿工来说,必须保存该数组以便查询,否则每次不仅计算位置,还要根据 Seed 计算整个数组数据,才能查询到对应位置的数据。这对于矿工来说,计算复杂度大幅度上升。==

当然,矿工可以选择只保存一部分数据,例如:只保存奇数位置数据,偶数位置需要时再根据前一个奇数位置数据计算即可,从而对内存空间大小减少了一半(计算复杂度提高一点,但内存减少一半)。

==该方法对 Puzzle 验证并不是很友好,想要验证该 Puzzle,也需要存储该数组,因此对于轻节点来说,并不友好。==

因此,莱特币真正应用来说,数组大小不敢设置太大。例如:对于计算机而言,1G 毫无压力,而对于手机 APP 来说,1G 占据空间就过大了。所以,实际中,莱特币系统设计的数组大小仅仅 128K 大小。起初莱特币发行时,不仅希望能够抗拒 ASIC,还希望能抗拒 GPU。但实际中,后来慢慢出现了 GPU 挖矿,再后来,ASIC 芯片挖矿也出现了。实际应用中,莱特币的设计并未起到预期作用,也就是说,128K 对于 ASIC Resistance 来说过小了。

以太坊

以太坊挖矿算法基本思想

以太坊中,设计了两个数据集,一大一小。小的为 16MB 的 cache,大的数据集为 1G 的 dataset(DAG),1G 的数据集是通过 16MB 数据集生成而来的。

为何要设计一大一小两个数据集? 为了便于进行验证,轻节点保存 16MB 的 Cache 进行验证即可,而矿工为了挖矿更快,减少重复计算则需要存储 1GB 大小的大数据集。

以太坊中这两个数组大小并不固定,因为考虑到计算机内存不断增大,因此该两个数组需要定期增大。

  1. 16MB 的小 Cache 数据生成方式与莱特币中生成方式较为类似:通过 Seed 进行一些运算获得第一个数,之后每个数字都是通过前一个位置的值取哈希获得的。
  2. 大的 DAG 生成方式:大的数组中每个元素都是从小数组中按照伪随机顺序读取一些元素,方法同莱特币中相同。如第一次读取 A 位置数据,对当前哈希值更新迭代算出下一次读取位置 B,再进行哈希值更新迭代计算出 C 位置元素。如此来回迭代读取 256 次,最终算出一个数作为 DAG 中第一个元素,如此类推,DAG 中每个元素生成方式都依次类推。

图片说明

  1. 求解 Puzzle:按照伪随机顺序,从 DAG 中读取 128 个数

    图片说明

最后,计算出一个哈希值与挖矿难度目标阈值比较,若不符合就重新更换 nonce,重复以上操作直到最终计算哈希值符合难度要求或当前区块已经被挖出。

分析

轻节点只保存小的 cache,验证时进行计算即可。但对于挖矿来说,如果这样则大部分算力都花费在了通过 Cache 计算 DAG 上面,因此,其必须保存大的数组 DAG 以便于更快挖矿。

伪代码

  1. cache 生成:每隔 30000 个块会重新生成 seed(对原来的 seed 求哈希值),并且利用新的 seed 生成新的 cache。cache 的初始大小为 16M,每隔 30000 个块重新生成时增大初始大小的 1/128 (128K)。

    image-20221030234800204

  2. DAG 生成:DAG初始大小是 1G,也是每隔 30000 个块更新,同时增大初始大小的 1/128 (8M)。

    image-20221030234929780

    image-20221030234941372

  3. puzzle:注意到轻节点是临时计算出用到的 dataset的元素,而矿工是直接访存,也就是必须在内存里存着这个 1G 的 dataset,后边会分析这个的原因。

    image-20221030235124280

  4. 挖矿:我们需要调整 nonce 来使 hashimoto_full 的返回值小于等于 target。这里先随机初始化 nonce,再一个个尝试 nonce,直到得到的值小于 target。

    image-20221030235213618

由于矿工需要验证非常多的 nonce,如果每次都要从 16M 的 cache 中重新生成的话,那挖矿的效率就太低了,而且这里面有大量的重复计算:随机选取的dataset 的元素中有很多是重复的,可能是之前尝试别的 nonce 时用过的。所以,矿工采取以空间换时间的策略,把整个 dataset 保存下来。轻节点由于只验证一个 nonce,验证的时候就直接生成要用到的 dataset 中的元素就行了。

其他观点

本篇中挖矿算法设计一直趋向于让大众参与,这一才是公平的。且由于参与人员的分散,算力分散,也进一步使得系统更安全。

但同样一件事物,从不同观点看就有不同的看法。也有人认为让普通计算机参与挖矿是不安全的,像比特币那样,让中心化矿池参与挖矿才是安全的。为什么呢?

因为要攻击系统,需要购入大量只能进行特定货币挖矿的矿机通过算力进行强行 51% 攻击,而攻击成功后,必然导致该币种的价值跳水,攻击者投入的硬件成本将会全部打水漂。而如果让通用计算机也参与挖矿,发动攻击成本便大幅度降低,目前的大型互联网公司,将其服务器聚集起来进行攻击即可,而攻击完成后这些服务器仍然可以转而运行日常业务。因此,也有人认为,在挖矿上面,ASIC 矿机“一统天下”才是最安全的方式。