白话区块链 之8 - 比特币的发行:挖矿
【编者Peter Ye按】
可以打开如下链接,详细阅读前几篇:
白话区块链 之7 - Bitcoin Core之客户端逻辑结构
下面的段落对应《白话区块链》的第1章的1.4.3节。
比特币的发行:挖矿
很多朋友在第一次看到“挖矿”这个词语时都很疑惑包括本人,比特币不是一个软件吗?通过软件来挖矿是什么意思?从字面上来看,应当是通过投入某种工作,然后能得到一个“宝贝”也就是矿,当然了,“挖矿”自然不是我们通常认为的那个挖矿,它只是一套算法,在介绍算法过程前,我们先来了解下挖矿在比特币软件中主要都有哪些用途:
抢夺区块打包权
验证交易事务
奖励发行新币
广播新区块
我们知道,比特币是一个对等网络,每个节点都可以独立维护自己的数据副本,那么问题就来了,怎么来保证彼此之间的数据一致呢?
既然没有一个中心服务器,自然也就没有一个传统意义上的权威数据来源了,这就得有一个约定的规则,大家共同按照这个规则来进行竞争,谁竞争成功了谁就有数据的打包权也就是记账权,打包完成后广播给别人,别人只要验证一下有无问题即可,没有问题就存入到自己的数据文件中。
这个思路不错,等于就是大家来竞争临时中心服务器的资格,那么比特币中实行了一种什么样的规则呢?那就是被称之为工作量证明(PoW,Proof of Work)的一种算法,其实就是类似于掷骰子的一种游戏,比如说大家约定掷出一个10位长度的数字,前面6位要都是0,后面的四位数得小于某个值,看谁先掷出符合要求的数字出来,谁就抢得了打包权。
我们来看下比特币中具体是怎么来掷这个骰子的:
1. 难度值
首先,既然是大家都在竞争掷骰子,那掷出来的数字必然是要符合一个难度的,这个难度就是一个门槛,在比特币软件中,规定一个256位的整数:
x00000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
为难度1的目标值,在比特币诞生初期,当时的全网算力,大约需要10分钟左右的运算能得到一个符合这个难度1要求的值,这也是我们常常说比特币网络每隔大约10分钟出一个区块的来源,我们在查询创世区块也就是0号区块的信息时,可以看到当时的难度就是1。那么,所谓的符合这个难度为1的要求的值是什么意思呢?就是说通过工作量证明算法也就是比特币中的挖矿算法来计算出一个结果,这个结果要小于这个难度目标值,我们来看下0号区块的难度信息:
"nonce": 2083236893,
"bits": "1d00ffff",
"difficulty": 1,
这些信息可以通过比特币支持的JSON-RPC中的"getblock"命令方法来获得,其中的difficulty就是指难度级别,在0号区块的难度值是1,nonce是一个随机数,是挖矿计算得到的一个数字,这个等会儿再介绍,bits是用来存储难度的十六进制目标值的,这个难度目标值是存储在区块的头部的,在源码中被定义为一个4字节长度的字段,4字节也就是32位,要用来存储256位长度的难度目标值,因此这256位长度的值需要经过一个压缩处理后才能放到这个字段中,以这个难度1的目标值来说,我们查询区块信息后,看到的值是“1d00ffff”,那么,这个值是怎么压缩而来的呢?规则其实很简单,我们一共有4个字节来存储,这4个字节的最高位字节用来存储难度值的有效字节数,什么叫有效字节数?就是从第一个不全为0的字节开始的部分,比如难度1的值有效位是0x00FFFF......(等等,怎么前面有2个0呢?这是因为在压缩规则中,规定了如果难度值有效位的最高位为1(大于0x80),则需要在前面补上一个0x00,这里的最高位是F,也就是二进制的1111,因此是符合这个规则的),难度1的目标值中,有4个字节长度的0,减掉这些0的长度共32bit,剩余256-32=224,也就是28个字节,加上补的0x00,因此,有效位总计29个字节,29的16进制是1D,另外3个字节中存储的是目标值有效位的最高3个字节,此时的目标值有效位前面已经加上了2个0,因此最高3个字节为0x00FFFF,合起来压缩后的值就是0x1d00ffff。对于这样的一个压缩后的十六进制4字节难度目标值,前2位通常称之为幂或者说指数,后面6位称之为系数。
那么,有朋友问了,压缩是可以,那还原出来呢?我们看个公式:目标值=系数2的(8(指数-3))次方。
我们就以这个0x1d00ffff为例来说明,系数是后面6位也就是00ffff,指数是前面2位也就是1d,代入进去就是:0x00ffff2^(8(0x1d-3)),计算后得到的值是:
0x00000000FFFF0000000000000000000000000000000000000000000000000000
有朋友可能疑惑了,不对吧,这个跟规定的那个难度1的值不一样了啊,精度少了很多,确实是的,存储在bits中的值是一个精度截断的近似值。
我们以200000号区块为例,查询一下难度值,得到如下:
"nonce": 4158183488,
"bits": "1a05db8b",
"difficulty": 2864140.507810974,
我们来看看这个difficulty的值是怎么来的,0号区块的难度是1,对应的目标值是0x1d00ffff,200000号区块的难度目标值是0x1a05db8b,将两者的目标值按照上述公式进行转换后然后相除便能得到这个2864140.507810974的难度值,我们发现,200000号区块的difficulty比0号区块的大许多,而bits的大小却比0号区块的小许多,这其实是表明了一个特点,随着全网算力的越来越强,difficulty难度值就会越来越大,而bits表示的目标值是越来越小的,这两者成反比,目标值越小就越难挖矿。
刚才也提到了,难度值并不是一成不变的,比特币差不多每两周会调整一下新的难度值,因为计算的算力是会变化的,为了维持差不多10分钟出一个区块的节奏,难度要跟随算力变化而调整,不得不说比特币的设计还是相当完整的,新难度值的计算公式是这样的:新难度值= 当前难度值 * (最近的2016个区块的实际出块时间 / 20160 分钟),2016个区块的意思是,假设按照理论的10分钟出一个块,2周也就是14天的时间,应该出2016个区块,可以看到实际上就是计算一下实际与理论上的时间差值,弥补上这个差值即可。
2. 挖矿计算
我们了解了难度值的概念,现在来看看挖矿计算具体是怎么个过程,首先,我们说了挖矿是要抢夺区块打包权,那就得收集需要打包进区块的那些交易事务,那这些数据从哪来呢?这里有个概念需要大家注意,打包就像是记账,是把发生的交易事务记录下来存档,但是无论什么时候打包谁打包,在网络中发生的交易是持续不断的,就像企业仓库的进销存业务,无论记账员是一个月还是半个月记一次账,业务是持续进行的,在比特币系统中,每个人通过钱包进行的转账交易数据都会广播到网络中,这些都是属于等待打包的未确认交易数据,这些数据都会放在一个内存池中,总之就是一个缓冲区,当然,这些数据都会被进行基本的验证,用以判断是否是不合法的或者是不符合格式的交易数据。
挖矿程序从内存池中获取用来打包区块的交易数据,接下来就要干活啦,我们来看一下挖矿的计算公式:
SHA256(
SHA256(version + prev_hash +merkle_root + ntime + nbits + nonce )
) < TARGET
SHA256是一种哈希算法,可以通过对一段数据进行计算后输出一个长度为256位的摘要信息,SHA256在比特币中使用很广泛,不但是用于挖矿计算也用于计算区块的哈希值和交易事务的哈希值,比特币对SHA256算法是情有独钟啊,我们看到在这个公式中,是对参数进行两次SHA256计算,如果计算出来的值小于那个TARGET也就是难度目标值那就算是挖矿成功了。那么,这些参数都是由哪些组成的呢?请看下表:
名称 |
含义 |
version |
区块的版本号 |
prev_hash |
前一个区块的哈希值 |
merkle_root |
准备打包的交易事务哈希树的根值,也就是梅克尔根 |
ntime |
区块时间戳 |
nbits |
当前难度 |
nonce |
随机数 |
这些数据字段其实也是区块头的组成部分,将这些参数连接起来,参与SHA256的挖矿计算。在这些参数中,版本号是固定的值,前一个区块的哈希值也是固定的值,当前难度也是一个固定的值,那么要想改变这个公式的计算结果,能改动的参数就只有梅克尔根、区块时间戳和那个随机数了。
1)尔根是通过交易事务计算出来的,具体过程在下面章节中有介绍,挖矿程序从内存池中获取待打包的交易事务,然后计算出梅克尔根,获取交易事务本身也是有一些优先级规则的,比如根据手续费大小之类,这些细节就不赘述了。
2)时间戳是指UNIX时间戳,用于记录区块的产生时间,我们知道比特币系统是分布式的网络,没有固定的时间服务器,因此每个节点获得的时间戳都可能是不一样的,由此,比特币系统中设置了一个规则:首先新产生区块的时间戳要大于之前11个区块的平均时间戳,其次是不超过当前网络时间2个小时。所以我们要注意了,因为这个原因,后一个区块的时间戳比前一个区块的时间戳反而小也是可能的。
3)数是一个可自由取值的数值,取值范围是0~2的32次方。
我们可以看到,要通过这样的参数来计算出符合条件的值,基本上也就只能靠暴力计算匹配了,这种不断的执行SHA256计算的过程很消耗算力,也因此这个过程被形象的称之为是挖矿,简单的说,挖矿就是重复计算区块头的哈希值,不断修改该参数,直到与难度目标值匹配的一个过程。
一旦匹配成功,就可以广播一个新的区块,其他客户端会验证接收到的新区块是否合法,如果验证通过,就会写入到自己的区块链账本数据中。那么,挖矿的奖励在哪儿呢,不是说矿工成功出一个区块就能得到多少多少的比特币奖励的么?那么这里奖励在哪呢?这个奖励其实是作为一条交易事务包含在区块的交易事务中的,相当于系统给矿工转账了一笔比特币,这种交易事务由于特殊性,通常称之为是coinbase交易,这个交易一般是位于区块中的第一条,比特币系统也正是通过这种挖矿奖励的方式发行新的比特币,就像央行发行新钞一样。
这个奖励不是无限的,从2009年1月创建出第一个区块,每个区块奖励50个比特币,然后每21万个区块大约4年产量减半,到2012年11月减半为每个区块奖励25个比特币,然后在2016年7月减半为每个新区块奖励12.5个比特币。基于这个公式,比特币挖矿奖励逐步减少,直到2140年,所有的比特币(20,999,999.98)将全部发行完毕,到那个时候挖矿就只能收入一些交易手续费了,彼时,比特币网络是否还能保持运行,我们目前也只能持保留意见,矿工在没有明显的激励情况下,是否还愿意持续保持挖矿以承担区块打包的责任,现在也很难说。
比特币中的挖矿计算基本就是这个过程了,其实还是很简单的,本质上就是利用了SHA256计算,有朋友可能有疑问,那第一个区块也就是创世区块是怎么挖出来的?呵呵,很简单,创世区块是硬编码直接写进去的,在比特币的源码中,通过CreateGenesisBlock这个方法写入,并且还留下了一段话:"The Times 03/Jan/2009 Chancellor on brink of second bailoutfor banks";当时正是英国的财政大臣达林被迫考虑第二次出手缓解银行危机的时刻,这句话是泰晤士报当天的头版文章标题。
3. 区块广播
矿工挖出区块后,就进行网络广播,传递给相邻的节点,节点接收到新的区块后会进行一系列的验证,比如区块数据格式是否正确;区块头的哈希值小于目标难度;区块时间戳是否在允许范围之内;区块中第一个交易(且只有第一个)是coinbase交易;区块中的交易事务是否有效等,总之就是一连串的检测,全部校验通过就把新的区块数据纳入到自己的区块链账本中。如果是挖矿节点接收到信息,就会立即停止当前的挖矿计算,转而进行下一区块的竞争。
比特币的挖矿过程说到这里,不知道有没有朋友会有个疑惑,那就是挖矿算法虽然能够提供工作量证明,表明矿工确实是投入了相当的算力的,但是却不能保证只能是一个矿工能挖到啊,如果在同一时间内多个矿工都计算出了符合条件的值,都拥有了打包权,那以谁的为准呢?当初在想到这个问题的时候,苦思冥想了良久,在考虑着能有什么样机制来进行选择呢?
当初在想到这个问题的时候,苦思冥想了良久,在考虑着能有什么样机制来进行选择呢?良久过后,无解,看了一下比特币中的解决方案,竟然是那么的简单,人家没用什么复杂的算法,就是让节点自己选择,最终传播最广,处于最长的链中的区块将被保留,因此到底谁的区块会被保留下来,可能还真得看看运气了。这里实际上隐含着一个计算机中的理论的,即FLP原理,先看下定义:在网络可靠,存在节点失效(即使只有一个)的最小化异步模型系统中,不存在一个可以解决一致性问题的确定性算法。这个就是FLP原理了。这个其实也很好理解,比如三个人在不同房间投票,虽然三个人彼此之间是可以通电话沟通的,但是经常会有人时不时的睡着,比如A投票0,B投票1,C收到了然后睡着了(类比节点失效了),则A和B永远无法在有限时间内和C共同获得最终的结果。看到这里,我们也就明白了挖矿的作用了,除了发行新的比特币外,主要就是维持网络共识,让每个节点对区块链的数据保持一个最终一致性。
4. 挖矿方式
比特币的挖矿过程我们已经了解了,现在给大家介绍下挖矿方式,我们知道,挖矿算法在执行过程中,为了抢夺区块打包权,就得拼命的去算出那个符合难度目标的值,大家都在不断的升级自己的算力,难度也就越来越大,挖矿程序本身不复杂,关键是这个过程非常依赖计算机的算力资源,可以说得算力者得天下,也因为这个原因,挖矿的方式在多年来不断的进化,一切都围绕着为了得到更高的算力来进化。
我们先从硬件类型来说,早期的时候,还没多少人挖矿,难度值也还不大,使用普通的个人电脑就能进行挖矿了,这个时期的硬件设施主要是普通CPU挖矿,随着有更多的矿工加入,难度越来越大,使用普通CPU的算力,效率开始不够用,于是出现了GPU挖矿,利用显卡来进行挖矿计算,GPU对于SHA256的计算性能更高,曾经一段时间,市面上的显卡销量猛增,就是被买去搭建显卡挖矿的,2017年上半年,另外一种数字加密货币以太坊价格暴涨,也一度引发了市面上的“一卡难求”,显卡尤其是高端显卡的GPU计算在一些挖矿算法上的性能表现确实相当不错,然而,对于算力的追求是无止境的,接着又出现了FPGA(Field-Programmable Gate Array,现场可编程门阵列)和ASIC(Application Specific IntegratedCircuit,特定应用集成电路)这两种挖矿设备,这两类是属于集成电路的装备了,尤其是ASIC,基本是目前顶级性能的矿机了,专门为了挖矿而设计,只为挖矿而生!
说完了挖矿的装备,我们再来说说挖矿节点的类型,最简单的挖矿节点类型,就是solo挖矿也就是个体矿工,自己搞个挖矿装备然后默默的开挖,守株待兔般等待着挖矿成功,如今,在挖矿难度大幅度提升的时代,个人挖矿几乎是一点机会都没有,那么现在流行的挖矿节点是什么类型的呢?那就是矿池,矿池通过挖矿协议协调众多的矿工,相当于就是大家联合起来,每个人都贡献自己的算力,形成一个整体,大大的增强整个挖矿节点网络的算力,个人矿工也可以加入到矿池,他们的挖矿设备在挖矿时保持和矿池服务器的连接,和其他矿工共同分享挖矿任务,之后分享奖励。
---End---
未完待续……,欢迎持续关注微信公众号“乐生活与爱IT” 。
九存(官网:9Stor.com,微信公众号:九存区块链存储)认为,在区块链基础设施的共享计算领域,比特币矿机已经俨然成为电老虎,消耗了大量的电能,因为比特币的挖掘,靠的是比拼算力取得记账权,矿工的购买成本不断攀升,陷入到“装备竞赛”的恶性循环中,造成极大的资源浪费。下一波将要掀起的热潮是存储矿机(将达到的客观效果是:建设完善的区块链基础设施的共享存储),相比算力矿机,能耗要低得多(例如D28,28块盘,支持14个刀片并行挖矿,磁盘满配时,整个机箱的功耗也才370瓦),而且具有实际的价值,因为除了挖矿之外,还能存放数据。
在这个公众号平台上,之前也分享过和区块链相关的如下文章:
雄文:知耻而后勇,数字代币和区块链技术的未来 (修改版-20180213)
白话区块链 之7 - Bitcoin Core之客户端逻辑结构
诺贝尔物理奖候选人张首晟:区块链技术是互联网世界新的分合转折点
当SDS遇见BlockChain 之二:区块链存储为什么势在必行?(SDS的新赛道 - 暗流涌动的区块链存储)
---
微信公众号平台"乐生活与爱IT"在目前阶段,主要是分享区块链(BlockChain)
、软件定义存储(SDS)和超融合架构(HCI)相关的文章,偶尔也会分享虚拟化、云计算、大数据、人工智能、IoT等IT类文章,甚至生活类的好文章。欢迎投稿,特别是原创文章。如果原创文章属于首次发布,根据质量和阅读量的不同,能获得20~500元的稿费。我的QQ号:9269216。另外,如果还有赞赏收入,作者可获得60%。
欢迎对SDS感兴趣的朋友,加入软件定义存储讨论 QQ群:122295009,可下载原创的一些文章,及其他有参考价值的文档。可直接搜索群号,或者扫描如下二维码:
欢迎您通过扫描关注微信公众号:“乐生活与爱IT”。
关注后,可以通过点击左下角的“文章目录”,通过输入三位数(记住!是三位数,目前第一位是0或者1)详细了解如何查看历史文章。
对软件定义存储与区块链感兴趣的朋友,可以添加如下管理员:
xiaoganggang10101
eric0424
liushuan2008
sdg8848
dts0103
加入到微信群“当SDS遇见BlockChain"。希望大家一起学习和讨论,共同进步。添加时,请自我介绍姓名、公司名、所在城市等信息。
点击左下角“阅读原文”,可以跳转到《当SDS遇见BlockChain 之二:区块链存储为什么势在必行?(SDS的新赛道 - 暗流涌动的区块链存储)》