区块链与密码学全民课堂第1-5讲:如何优雅地比特币挖矿

【本课堂内容全部选编自PlatON首席密码学家、武汉大学国家网络安全学院教授、博士生导师何德彪教授的《区块链与密码学》授课讲义及互联网,版权归属其原作者所有,如有侵权请立即与我们联系,我们将及时处理。】
1.5比特币的挖矿
如何优雅地获得你人生中第一枚比特币?这是一个值得思考的问题。我们在第二堂课的时候简单讲过挖矿对于比特币价格和走势的影响,以及挖矿周边衍生出的各行各业。今天我们详细说说挖矿原理。
“挖矿”成功即是该节点成功获得当前区块记账权,也就是说其他节点就“照抄”该挖矿成功的节点的当前区块。获得记账权的节点会获取一定数量的比特币奖励,以此激励比特币网络中的所有积极参与记账工作。该奖励包含系统奖励和交易手续费两部分,系统奖励则作为比特币发行的手段。
最初每生产一个“交易记录区块”可以获得50比特币的系统奖励,为控制比特币发行数量,该奖励每4年就会减半,到2140年会基本发放完毕,最终整个系统中最多的只能有2100万个比特币。如果按照目前比特币的价格计算,比特币的总价值将在2000亿美金左右。
注:价格取自2020年5月30日13:35
比特币系统大约每10分钟会记录一个数据块,这个数据块里包含了这10分钟内全网待确认的部分或全部交易。所谓的“挖矿”,就是争夺将这些交易打包成“交易记录区块”的权利。比特币系统会随机生成一道数学难题,后续会详细描述该数学难题,所有参与挖矿的节点一起参与计算这道数学难题。首先算出结果的节点奖获得记账权。
每个节点会将过去一段时间内发生的、尚未经过网络公认的交易信息进行收集、检验、确认,最后打包并加签名为一个无法被篡改的“交易记录区块”,并在获得记账权后将该区块进行广播,从而让这个区块被全部节点认可,让区块中的交易成为比特币网络上公认已经完成的交易记录,永久保存。
挖矿最主要的工作就是计算上文提到的数学难题,最先求出解的矿工即可获得该块的记账权。在介绍这个数学难题前,先简单介绍一下哈希算法。哈希算法的基本功能概括来说,就是把任意长度的输入值通过一定的计算,生成一个固定长度的字符串,输出的字符串即为该输入的哈希值。比特币系统中采用SHA-256算法,该算法最终输出的哈希值长度为256bit。
1.5.1 挖矿的原理

讲到挖矿原理,首先我们要了解一种“植物”——Merkle树

比特币科普之Merkle树是什么树?
Merkle树通常称为Merkle Hash Tree,是数据结构中所说的树,常用于高效汇总和验证大数据集的完整性.具有以下特点:
① 默克尔树常见的结构是二叉树,但它也可以是多叉树,它具有树结构的全部特点。
② 默克尔树的基础数据不是固定的,因为它只要数据经过哈希运算得到的hash值。
③ 默克尔树是从下往上逐层计算的,就是说每个中间节点是根据相邻的两个叶子节点组合计算得出的,而根节点是根据两个中间节点组合计算得出的,所以叶子节点是基础。

比特币中每个区块生成时,需要把上一个区块的哈希值、本区块的交易信息的默克尔树根、一个未知的随机数(nonce)拼在一起计算一个新的哈希值。为了保证10分钟产生一个区块,该工作必须具有一定难度,即哈希值必须以若干个0开头。哈希算法中,输入信息的任何微小改动即可引起哈希值的巨大变动,且这个变动不具有规律性。因为哈希值的位数是有限的,通过不断尝试随机数nonce,总可以计算出一个符合要求的哈希值,且该随机数无法通过寻找规律计算出来。这意味着,该随机数只能通过暴力枚举的方式获得。挖矿中计算数学难题即为寻找该随机数的过程。
哈希值由16进制数字表示,即每一位有16种可能。根据哈希算法的特性,出现任何一个数字的概率是均等的,即每一位为“0”的概率为1/16.要求某一位为“0”平均需要16次哈希运算,要求前n位为“0”,则需要进行哈希计算的平均次数为16的n次方。矿工为了计算出该随机数,需要花费一定的时间进行大量的哈希运算。某个矿工成功计算出该随机数后,则会进行区块打包并全网广播。
其他节点收到广播后,只需对包含随机数的区块按照同样的方法进行一次哈希运算即可,若哈希值以“0”开头的个数满足要求,且通过其他合法性校验,则接受这个区块,停止本地对当前区块随机数的寻找,开始下个区块随机数的计算。
随着技术的发展,进行一次哈希计算速度越来越快,同时随着矿工的逐渐增多,算出满足哈希值以一定数量“0”开头的随机数的时间越来越短。为保证比特币始终按照平均每10分钟一个区块的速度出块,必须不断调整计算出随机哈希计算的平均次数,即调整哈希值以“0”开头的数量要求,以此调整难度。比特币中,每生成2016个区块就会调整一次难度,即调整周期大约为两周(2016x10min=14天)。也就是说,对比生成最新2016个区块花费的实际时间和按照每10分钟出一个块生成2016个块的期望时间,若实际时间大于期望时间则降低难度,若实际时间小于期望时间则增加难度。
同时,为防止难度变化波动太大,每个周期调整幅度必须小于一个因子(当前为4倍)。若幅度大于4倍,则按照4倍调整。由于按照该幅度调整,出块速度仍然不满足预期,因此会在下一个周期继续调整。
1.5.2 矿池的原理
随着区块链的日渐火爆,参与挖矿的人越来越多,按照比特币原本的设计模式,只有成功打包一个区块的人才能获取奖励。如果每个矿工都独立挖矿,在如此庞大的基数下,挖矿成功的概率几乎为0,只有一个幸运儿可以获取一大笔财富,其他矿工投入的算力、电力资源就会白白亏损。或许投入一台矿机,持续挖矿好几年甚至更久才能挖到一个区块。
为了降低这种不确定性,矿池应运而生。假如有10万矿工参与挖矿工作,这10万矿工的算力和占这个网络的10%,则这10万个矿工中的某个矿工成功挖到下个块的概率即为1/10。即平均每个矿工成功挖到下个区块的概率为1/1000000,即平均每个矿工要花费19年可以成功挖到一个区块,然后获得相应的比特币奖励。这种挖矿模式风险过大,几乎没人可以承受。但是假设这10万个矿工共同协作参与挖矿,则平均每100分钟即可成功挖到一个区块,然后按照每个矿工提供的算力分配该次收益。这10万个矿工的收益也会趋于稳定。
协调矿工进行计算的思路也非常简单,矿池将打包区块需要的交易等信息验证完成后发送给矿工,然后降低矿工的挖矿难度。比如某个时段比特币系统需要哈希值“0”开头的个数大于50个,矿池可以将难度降低到40个“0”开头,矿工找到一个40个“0”开头哈希值的方案后,即可提交给矿池。矿池收到一个满足哈希值“0”开头个数大于50个的方案时,即可提交至比特币网络。
当然,你也许会想:如果矿工计算得到一个“0”开头个数大于50的哈希值后,则直接提交给比特币网络,独享该区块的收益;如果计算得到一个“0”开头数在40到50之间的则提交到矿池,享受整个矿池分配的收益。该方案当然是行不通的,因为区块内容是由矿池发送给矿工的,即受益者地址已经包含在该区块中了,即使直接提交,最终受益的也是矿池。如果修改该地址,即意味着区块内容改变,则前面计算的哈希值也无效了。最后矿池按照矿工提交方案数量计算贡献的算力,最后根据算力分配收益。
当前的主流挖矿协议是stratum,以前还有GBT(getblocktemplate)、getwork等几种协议,它们都过时了。可以用免费的Cpuminer软件把协议调通。
软件地址为:
https://sourceforge.net/projects/cpuminer/files