哥白尼开发者:挖矿难度精讲

本文由哥白尼团队何思羽创作,比特币主链上,平均每十分钟会出一个块。随着数字货币的发展,参与的 miner 数量与日俱增,挖矿技术日新月异,全网的算力也是以惊人的速度增长。BTC 中为了保证主链平均的高度增加速度依然维持最初设定,进而设置了挖矿难度调整的功能。深入理解挖矿难度的概念,以及挖矿难度调整的方案,对开发人员以及 miner 都很重要,因为挖矿难度设置不合理可能会导致全网出块速度极不稳定。本文将详细介绍 BTC&BCH 挖矿难度及调整方案,我们先从 PoW 算法讲起。,PoW 算法具有:去中心化,单向,随机性,目标难度易调整等特点,所以现在包括 BTC,BCH 在内的很多币种都采用了 PoW 共识机制。,从实现上来说,PoW 算法的输入为任意长度,输出为固定长度,比如通常使用 SHA256 算法对应输出 256-bit。在挖矿过程中 miner 用 PoW 算法计算整个块头的 hash 值,由于 SHA256 的特性:块头任意一位发生变化,得到的 hash 值会变得完全不一样,而且大小变化方向不确定。于是,我们比较 hash 值是否小于某个值(实际上这个值是保存在块头中的 nBit「解压后」的 current_target 值)来判断是否满足要求;如果小于,则广播这个区块;如果不小于,则按照当前挖矿节点的规则改变块头中可以改变的值,然后再次计算块头 hash 值,以此往复,直到结果小于目标值。,哥白尼开发者:挖矿难度精讲,由此可知,current_target 值越小,满足挖矿要求的概率就越小,挖矿难度就越大。,块头的生成: 当 miner 开始新一轮打包之后,首先会创建一个空的块,块结构分为块头以及块信息两部分。先打包块信息,再根据块信息填充块头。,首先看一下已经成功打包的块。下图是写本文稿时截取最新的 BTC block 详情。,哥白尼开发者:挖矿难度精讲,块信息 存放的是从 mempool 里取出来的一系列交易信息,miner 并以此创建了一个 Merkle Tree,交易信息的 hash 值作为 leaf,最终生成的 Merkle Root 将填到块头里。值得注意的是,交易列表中的第一个是一个非常独特的交易:Coinbase Transaction。Coinbase Transaction 与普通交易主要的区别有:,1) Coinbase Transaction 不消耗 UTXO,2) input 只有一个,叫做 Coinbase,3) output 的 addresss 为 miner 的 btc/bch 地址,4) value 由挖矿奖励和交易费组成,5)更值得注意的是 input 中没有 Unlocking-script,取而代之的是 Coinbase Data (这部分数据包含 Extra Nonce,在挖矿难度非常高时,将起非常重要的作用),Coinbase 交易 input 的结构如下:,哥白尼开发者:挖矿难度精讲,哥白尼开发者:挖矿难度精讲,Coinbase data,该字段数据长度范围为 2-byte~100-byte:,在交易信息聚合完毕得到了 MerkleRoot 之后,接下来填充区块头。块头结构如下(其中 nBit 就是 PoW 小节提到的 current-target 的压缩版):,哥白尼开发者:挖矿难度精讲,区块头 80-byte,一共 6 个字段:,块头中 80 bytes 任意一个值发生改变,PoW 的 Hash 结果就会发生改变。,理解了 PoW 运算以及运算结果可能受哪些个因素影响,接下来了解一下我们要满足的难度要求是什么。,挖矿难度的描述可以认为有三种形式,difficulty (难度值,浮点数),current_target (当前目标值,256-bit),nbits (32-bit);形式不同其实实质是表达的同一个难度要求,而且这个难度要求在每个块打包前就确定了。,difficulty 不写在区块中,而是以浮点数的形式展现,给人直观的感受难度程度。 difficulty = difficulty_1 / current_target;,difficulty_1 为常数:0x00000000ffff0000000000000000000000000000000000000000000000000000,nbits 就是区块头 nBits 字段的值,用长度为 32-bit 的数值表示 256-bit 的数值,是需要牺牲一定精度的 , 可以理解它为「压缩」后的 current_target。,在计算 current_target 时,我们先转换为二进制然后用公式(a)来计算 256-bit 的 current_target。(值得注意的是:current_target 是一个无符号 256-bit 的值,之所以设置一个 Sign 字段,是为了与 bitcoind 代码保持一致,保留符号位参考的是 IEEE 浮点型表示法,其实是无用的),哥白尼开发者:挖矿难度精讲,计算 current_target 的公式为:,哥白尼开发者:挖矿难度精讲,哥白尼开发者:挖矿难度精讲,(最高 16 位为零),哥白尼开发者:挖矿难度精讲,为了维持平均每十分钟生成一个块的频率,BTC 中 current_target 设计为了一个动态值,current_target 根据全网算力的改变而做一些相应的调整,这就是挖矿难度调整。,在 BTC 中,挖矿难度调整 idea 为:以 2016 个块(两周)为一个周期,每个周期根据前一个周期的实际耗时与理论耗时之间的差别进行调整。,方案具体逻辑是:,计算过程,Go 代码如下 :,哥白尼开发者:挖矿难度精讲,BCH 诞生于区块高度 478558,两条链都采用相同 PoW 共识算法(平均 10 分钟生成一个块),所以 miner 可以任意在 BTC 与 BCH 间切换,但由于通常 BCH 全网算力只占有 BTC 的 7% 左右,当 BCH 获利大于 BTC 的时候,大量原 BTC miner (尤其是大的矿场)会切入 BCH,一段时间后随着算力提升,难度值也会提升,miner 会纷纷离开切回 BTC,算力降低,难度居高不下将导致接下来出块十分困难。倘若继续沿用 BTC 的难度调整方案,BCH 将无法保证出块速率稳定在平均 10mins/block,事实上 BCH 的难度值调整算法已经先后经历了两种,第一种是紧急难度调整规则(EDA),目前使用的是难度调整规则(DAA)。,紧急难度调整规则(EDA),EDA 是在沿用 BTC 难度调整算法的基础上,增加了一个 Emergency Difficulty Adjustment 处理方案,主要是针对于出块缓慢情况及时降低难度。算法具体逻辑是:对于高度为 2016 倍数的就拿到此高度前 2016 块的 blocktime,沿用 BTC 难度调整方案;对于高度非 2016 倍数的块,则计算生成前六块的块总共耗时是否超过 12h,如果超过则降低挖矿难度 20%。 具体实现代码如下:,哥白尼开发者:挖矿难度精讲

哥白尼开发者:挖矿难度精讲,难度调整规则(DAA),然而在运行三个多月中,EDA 表现不尽如人意(非常差),由于其应对出块速率过高并没有做相应及时调整而依赖于 BTC 原有的 2016 块一次的调整机制,所以在面对算力波动时表现并不是很好。,哥白尼开发者:挖矿难度精讲,本人分别截取了三段「典型」数据,为了对上述观点进行说明:,哥白尼开发者:挖矿难度精讲,哥白尼开发者:挖矿难度精讲,哥白尼开发者:挖矿难度精讲,所以优化 BCH 的难度调整方案刻不容缓,在得到几大矿池的稳定算力支持后,17 年 11 月 13 日,BCH 再次升级,就是为了优化 EDA。BCH 开发团队(并非社区)收到几份 DAA,最终采用了 BTCABC 开发团队 Amaury Sechet 的 DAA 提案。 这份 proposal 的 ieda 可以用一句俗语来形容「魔高一尺,道高一尺,魔有天花板」,根据前一天的算力为基准从而预测需要设置多少工作量才能耗掉十分钟。 其实现逻辑如下:,哥白尼开发者:挖矿难度精讲,具体实现代码如下:,哥白尼开发者:挖矿难度精讲,计算新 Target 方法如下:,哥白尼开发者:挖矿难度精讲,总结下来,DAA 算法具有以下特性:,哥白尼开发者:挖矿难度精讲,DAA 应对算力攻击的效果如何呢?,以下是两个算力变化极端场景:算力陡增两倍,算力陡然减半。 poc 代码如下:,哥白尼开发者:挖矿难度精讲

哥白尼开发者:挖矿难度精讲

哥白尼开发者:挖矿难度精讲,目前,BTC 挖矿难度设置到了 7184404942701.792( 0x17272d92 对应的 current_target 为 0x000000000000000000272d920000000000000000000000000000000000000000)。 也就是说随机选取的数满足小于 target 的概率是 1/(272),但是块头的 nonce 字段只有 4bytes,也就是 32 位,有可能 232 个随机数都试完来仍然找不到满足 target 的 result。所以允许块头内部分其他的字段改变,用来生成新的 result。允许改变的字段在第二小节块头部分已指明。,试想一下,如果频繁更改 Coinbase Data 里的 Extra Nonce,来改变块头的 Merkle Root 会怎么样?很明显效率会很低,所以实际挖矿中策略是:尽可能减少块头中 Version,TimeStamp,Merkle Root (绿色区域数据)值的改变,而「疯狂」遍历 Nonce (红色区域)的值用于 PoW;当遍历完没找到满足 target 的 result,再改变绿色区域的值,然后继续「疯狂」遍历 Nonce。如此往复直至找到满足 target 的 result 或者这一轮 PoW 竞赛中失败开始新一轮打包。,哥白尼开发者:挖矿难度精讲,5)更值得注意的是 input 中没有 Unlocking-script,取而代之的是 Coinbase Data (这部分数据包含 Extra Nonce,在挖矿难度非常高时,将起非常重要的作用),版本号,允许改变但不推荐,前一个块的 hash 值,不允许改变,MerkleRoot 的 hash 值,用于存块信息里的交易的 Merkle Tree 的 root 节点的值,允许改变(改变 coinbase 中 input 中的值),Coinbase 交易 input 的结构如下:,计算 2016 个块实际使用时长:如果用时低于半周,则按半周计算,防止难度增加 4 倍以上;如果用时高于 8 周,则按 8 周计算。防止难度降低到 4 倍以下。,判断是否需要更新目标值 ( 2016 的整数倍),如果不是则继续使用最后一个区块的目标值,实际使用时长乘以当前难度,再除以 2 周,区块头 80-byte,一共 6 个字段:

原创文章,作者:哈希值,如若转载,请注明出处:http://www.lianchaguan.com/archives/33034

发表评论

电子邮件地址不会被公开。 必填项已用*标注