比特币白皮书在工作量证明章节中解释了工作量证明(PoW)的方式:
我们在区块中补增一个随机数(Nonce),这个随机数要使得该给定区块的随机散列值出现了所需的那么多个0。我们通过反复尝试来找到这个随机数,直到找到为止,这样我们就构建了一个工作量证明机制。只要该CPU耗费的工作量能够满足该工作量证明机制,那么除非重新完成相当的工作量,该区块的信息就不可更改。由于之后的区块是链接在该区块之后的,所以想要更改该区块中的信息,就还需要重新完成之后所有区块的全部工作量。
那这个随机数难度值是怎么产生的呢?
原理是简单的,但是细节总是需要穷根究底。
难度值在区块中并不记录,仅仅是为了人类直观感受解题难度而演变出的一个浮点数。难度每2016个区块改变一次,公式如下:
1 | diffculty = difficulty_1_target / currentTarget |
---|
此处的 difficulty_1_target 为一个常数,非常大的一个数字。表示矿池挖矿最大难度。目标值越小,区块生成难度越大。区块中存储的是这个名为target的值。
在区块中存储的是Target,但是将Target经类似于浮点数的一种压缩表示法,字段为nbits。例如,如果区块bits记录为0x1b0404cb,那么他表示的十六进制的Target值为:
1 | 0x0404cb * 2**(8*(0x1b - 3)) = 0x00000000000404CB000000000000000000000000000000000000000000000000 |
---|
1 | 1000 = 0x03 * 256 + 0xe8 * 1 |
---|
那么是由两个数字构成:
1 | 03 e8 |
---|
第一个数未超过0x7f,则不需填0,但长度两位低于三位,在后面补零,最终表示为:0x0203e800
SHA256(SHA256(区块头)) < Target
0x00000000FFFF0000000000000000000000000000000000000000000000000000
,此时难度为1 0x00ffff *256** (0x1d - 3) = ff ff 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
目标值计算公式如下,但在实际计算时有些特别处理,将目标值控制在一定范围内。
1 | 新目标值= 当前目标值 * 实际2016个区块出块时间 / 理论2016个区块出块时间(2周)。 |
---|
代码参考这里:
0x00000000FFFF0000000000000000000000000000000000000000000000000000 / 0x00000000000404CB000000000000000000000000000000000000000000000000 = 16307.420938523983
0xffff * 2^208
(0xffff * 2^208)/D
D * 2^256 / (0xffff * 2^208)
D * 2^48 / 0xffff / 600
可以进一步简化为:
D * 2^32 / 600
1 | 0x00000000FFFF0000000000000000000000000000000000000000000000000000 |
---|
但是在绝大部分矿池里面表示为
1 | 0x00000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF |
---|
这样挖矿的时候,挖矿软件显示的难度和比特币客户端api调用算出来的难度有微小差别,可以忽略。这个其实时早期矿池实现的时候找方便造成的不统一,因为比特币客户端判断HASH合法性的时候用的是nbits来判断,所以不影响最终计算结果
1 | difficulty = [prev_target] * 【前2015个区块生成所用的时间】 / 1209600 (按标准每10分钟出一个块,2016个块所需要的秒数) |
---|
为啥?就是中本聪早期的代码比较糙,他在循环的时候因为还有一个genius block要处理,可能为了代码干净起见就不去特殊处理了,其实也没啥影响