前一篇介绍了比特币挖矿是一个算术比赛,获胜者能得到相应的奖励。比特币网络用这个机制来确定每一个新的区块由谁来发布,术语叫“工作量证明”,俗话“挖矿”,这是中本聪用来解决去中心化的关键一招。挖矿有许多细节值得玩味,我已经介绍了比特币如何选择谜题,也顺便聊了一下比特币网络恐怖的算力资源。今天我来科普一下比特币网络是如何通过控制挖矿难度来整定新区块产生的间隔时间,这也是理解比特币网络特别重要的知识。
一、为什么比特币网络的新区块产生需要大约十分钟?
在《比特币网络的运行过程原理》中我提到了交易确认这个概念。关注比特币的人大概都知道(没关注的现在也应该知道了),比特币的每一个区块产生的间隔时间为大约十分钟。为什么是十分钟而不是五分钟或者二十分钟,并没有特别精确的原因,最早出现关于十分钟的讨论,还是中本聪在他的比特币白皮书中举例说的。他提到这个十分钟是为了计算区块头部信息的大小会不会造成存储问题1。
除了与存储问题相关,确定十分钟间隔也与比特币网络处理交易效率、区块链安全性和复杂的全球网络环境有关。由于全球网络信息传输有一定的滞后时间,那么在新区块产生后,到所有节点都接受到这个信息一定会有一个时延,而在这个时延内消耗大量的电能和计算机资源去做的计算显然是没有用的,有人经过计算,间隔时间越短,浪费资源的比例越高2。
另外这个时延内可能会出现的同等级别区块也会干扰最长区块链共识的形成。如果区块产生的频率很高,例如一秒一个区块或者一分钟一个区块,可能因为新区块还没有被全网都接受和认可,就会有其他节点产生了同级别新区块,或者有更新的区块发布了,这样会使全网达成最长链的共识受到眼花缭乱的干扰,反而造成最长链的共识形成需要花费更多的时间。另外如果区块链产生的频率很低,那么新区块发布的时间间隔会很长,那么交易确认的效率就会大大降低。
用大约十分钟作为区块发布的时间间隔是中本聪在开发比特币时,在比特币网络软件的代码里用一个常数来确定的。而之所以这么确定那个常数,并没有特别的原因资料,以上分析都是事后诸葛亮根据结果以及比特币网络成功运行的情况进行分析的。
二、飞镖游戏来理解挖矿的计算比赛难度
大家都应该知道飞镖游戏,对面是一个大圆盘(我们假设半径为R),靶心处有个红色圆圈就是靶心区域(半径用r来表示),我们的目标就是尽可能的把飞镖扔进靶心。这里有一个假设,就是投掷飞镖的人每一次投出去都是随机乱扔的,这样飞镖的落点也是随机的分布在大圆盘上。我们把投掷到圆盘上的位置离圆心的距离记作d,那么显然当d小于或等于r时,就成功的投中靶心了。可见这个飞镖游戏的难度与靶心半径直接相关,半径越大,难度就越低。我们只要调整靶心半径r,就可以调整飞镖游戏的难度。
比特币是采用计算哈希值来进行计算比赛的,哈希值的输出有2256个数字,这个数字我们在介绍哈希函数特性说过非常巨大,我们把这个数字用一个非常大的飞镖大圆盘半径R来表示。而比赛就是要不断的计算哈希值,想办法找到一个计算结果小于等于某一个目标值(target),就算成功。而这个目标值(target)就相当于靶心半径r,每一次计算结果出来的哈希值就相当于每次投掷到圆盘上位置到圆心的距离d。
如此投掷方法投到靶心的概率其实就是靶心面积与大圆盘总面积的比值。现在有一个关键细节需要各位理解,就是每次投掷到靶心的概率假如是1%,那么也可以说投100次会有1次投中靶心。后一种说法并不是指在第100次会投中,而是有时会第1次就投中,有时会到第200次也没有投中,但是经过无数次后的统计来看,会是100次里有1次投中。这个细节很关键,理解这个就能比较容易理解挖矿计算的随机性3与新区块以一个大致均等的速度产生的原理了。
三、用挖矿难度来调节新区块产生速度
我们通过一个飞镖游戏来理解挖矿比赛的大致情况以及如何调整难度。飞镖游戏调整的是靶心半径r,当r增大时,难度就降低,反之亦然,那么对于挖矿比赛,调整的是目标值(target),当目标值(target)越大,难度就越低,反之亦然。因此调整难度其实是调整计算成功的概率,挖矿难度调整高了(也就是目标值调整小了),就需要计算更多次哈希计算才能成功找到小于或等于目标值(target)的计算结果。
计算哈希值是要消耗时间的,全网计算资源需要花费十分钟左右的时间才能计算出一个成功的哈希值,这个概率对应的目标值(target)就是我们需要的。随着计算资源的不断投入或者退出,那么十分钟的哈希计算次数也会随之增加或者减少,这就需要不断能调整目标值(target)来调整计算成功的概率,只有如此才能尽可能的维持十分钟产生一个区块的速度。
在这里我来复习一下,挖矿难度是怎么成为调节新区块产生速度的工具:
1、首先是十分钟产生一个区块是一个确定的目标,这是中本聪在发明比特币时确定下来的;
2、然后我们需要找到一个机制能够维持新区块按照十分钟的速度来产生,同时还要保证去中心化;
3、中本聪在设计用工作量证明(挖矿)来进行竞争新区块发布权的同时,也确定了调整目标值(target)的方式来调整挖矿难度,从而调整了挖矿比赛成功的概率;
4、这个概率最终保证了比特币网络的新区块都在十分钟左右产生,实现了新区块产生速度稳定的目标。
四、挖矿难度是怎么自动调整的?
现在我们把注意力集中到比特币网络是如何让所有节点协调一致的自动调整挖矿难度的。首先要告诉大家的是,挖矿难度调节是每个节点自己做的决定,不过是根据一定规则来做的决定。
规则是这样确定挖矿难度的程序的:
1、每个区块都有编号,从第0个区块,然后是第1个区块一直排下去,目前我写到这里的时候,最新的区块号是#523663;
2、每个节点在准备新的区块时,首先计算这个新区块的区块号能不能被2016整除,如果不能整除,则这个区块不需要调整挖矿难度,直接使用上一个区块的目标值(target)就可以了;
3、如果能被整除,再计算一下前2016个区块的总时间,看看是不是正好是两周;
4、如果偏离两周,则说明比特币网络算力变化了,就根据一个公式,按照上2016个区块的时间与两周的比例,来调整上一个区块的目标值(target)就可以了4;
5、新区块就采用调整后的目标值(target)来进行挖矿计算。
我先把这个程序摆出来,相信大家只能看得似懂非懂,这里面有两点小细节我要说明一下。
(一)那个“2016”数字是怎么回事?
首先是那个“2016”数字是怎么回事?中本聪在确定十分钟产生一个区块后,就要考虑如何调整难度让比特币网络能够在计算资源变化的情况下维持住这个十分钟,这一点我们前面已经介绍了。这里面有一个细节,就是多久来调整一下挖矿难度比较合适呢?
是每个区块都根据上一个区块产生的时间来调整吗?这显然不行,因为十分钟能计算成功只是一个概率统计的结果,有可能某个矿工运气好,一分钟就挖出来也有可能,运气差的话,可能全网二十分钟也不能出来一个区块,这样就调整的话其实并不是依据算力资源变化调整,而是跟据运气变化在调整。
那么就拉长时间,例如一个月或一年,那么就可能会在某类新型计算设备出来的情况下,会有时间在难度调整周期内形成超强的算力,影响比特币网络的安全。可见这个调整难度的时间和区块产生的速度一样,也是一个需要权衡的事情。最终中本聪选择了两周为一个难度调整周期,而两周里总共有2016个十分钟,这就是“2016”这个数字的来历。
每个节点首先看区块编号是不是能被2016整除,如果能,则需要计算新的目标值(target)了;如果不能整除,则没到调整难度周期,就不用管它了。
(二)目标值(target)存放在哪里?
我们在前面说过,目标值(target)就相当于飞镖游戏的靶心半径r,调整这个数字,就相当于增大靶心或缩小靶心,挖矿难度自然也随着变化。在比特币网络区块链中,目标值(target)存放在所有区块的头部信息里5。
每个节点都可以得到上一个区块的目标值(target),以及前2016个区块的产生时间,相信所有小学毕业的人都很容易就能算出来要把未来2016个区块整定到两周时间,如何算出新的目标值(target)来吧?
五、比特币网络里“难度(difficulty)”是指什么?
其实本篇任务到前一段应该已经完成了,如果小白们大致明白了,可以不继续看下去。如果好奇,我想再稍微深入介绍一个比较重要的概念。许多人看其他资料时一定会被一个“难度(difficulty)”概念搞糊涂,我就是这样的笨蛋,废了九牛二虎之力才搞清楚是怎么回事。
我们在本小节之前提到的“难度”这个词,是一个定性的概念,而在比特币网络里,“难度(difficulty)”这个词是一个专有名词,指向一个定量描述挖矿难度的概念。现在开始我们为了防止搞混淆,“难度”这个词如果不加双引号和英文,就表示普通定性的概念,加了双引号和英文的表示定量的概念。
“难度(difficulty)”这个概念是在比特币网络运行一段时间后引入的。其实用目标值(target)就已经能够说明挖矿难度了,而且这个值在每个区块里都有,只是这个数字实在太大,在区块里记录的是一种经过处理过的数字,要想看明白是什么数字,还真不是掐指算算就能搞定的。所以,专门引入了一个量化的概念来描述比特币网络的挖矿难度,用“难度(difficulty)”来表示。这个表示难度的数值并不保存在每个区块里面,但是现在几乎所有提供区块内容展示的网站都把这个数值专门列出来,看上去就跟区块里保存的一样。现在我把比特币的第一个区块,编号为0(著名的创世区块)和写作时最近的一个区块拿出来给大家解释一下“难度(difficulty)”的意思。
上面是两个区块头部信息,我把跟我们这期相关的部分都红框标注出来了。现在我来分别解释一下:
1、区块的哈希值,就是挖矿比赛成功算出来小于等于目标值的那个结果,同时也是本区块的标志,区块链之间的指针,也是用的这个哈希值。我们可以看到这两个区块的哈希值分别是6:
创世区块哈希值:0000 0000 0019 d668 9c08 5ae1 6583 1e93 4ff7 63ae 46a2 a6c1 72b3 f1b6 0a8c e26f
最近区块哈希值:0000 0000 0000 0000 0008 fdd5 5c63 d532 0363 b76a 2a10 ec29 cd23 8475 936f e517
2、目标值(target)在区块链里用字段“Bits”来表示,这是一个8个字节固定长度的16进制数字,我们前面说过,这是用了一些特殊办法处理过保存在区块中的样子,我们这里不深入细节。我直接算好给出两个区块的目标值(target):
创世区块目标值(target):0000 0000 ffff 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000
最近区块目标值(target):0000 0000 0000 0000 0043 eca9 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000
我们可以看到每个区块的哈希值都小于那个区块的目标值,就相当于飞镖落点与圆心的距离d,小于靶心半径一样。
我们还可以看到创世区块的目标值(target),那其实是中本聪自己指定的,所以当定义“难度(difficulty)”概念是,就以创世区块的难度为1来定义,以后的区块的“难度(difficulty)”都是用创世区块的目标值/当前区块的目标值来计算的。因此“难度(difficulty)”概念可以理解为当前区块的挖矿难度比创世区块增大了多少倍来理解。
那么我们再看一眼最近的那个区块的“难度(difficulty)”,是4,143,878,474,754.19。4万多亿倍,是不是一个恐怖的数字?从这里也可以看出比特币网络近十年来算力的恐怖增长。
注释:
1、中本聪在白皮书中写道:“一个没有转账交易的区块头大概有80个字节。如果我们假设每十分钟产生一个区块,那么一年产生的所有区块头就有4.2MB的大小。以2008年计算机系统典型配置为2GB内存,以及摩尔定律预测每年内存增长1.2GB来看,如果必须把所有区块头都读进内存,也没啥问题。”
2、其他密码货币后来采用了其他技术,实现了区块之间的间隔时间缩短到秒级。
3、计算结果的随机性是去中心化的要求,在这里提醒一下。
4、我觉得这么介绍是小白应该能看明白的程度,具体细节公式甚至代码,就不说了,专业选手不用看我的文章,网上说得更专业的文章非常多。
5、目标值在区块里存放的形式还是挺有意思的,因为这个数字非常大,没办法直接放,就采取了一种固定长度的方法。不过这涉及到代码层面的细节,我这里就不深入介绍了,感兴趣的朋友可以自己找资料看,也可以留言与我交流。
6、这里表示的数字全都是二进制数字,每4位用一个十六进制数来表示,估计许多小白对不同进制的数高不清楚,我这里简单做一个对应表: