区块难度详解

1 难度及相关概念

1.1 哈希运算

简单的说,哈希运算可以看出是输入不同输出不同的函数(免碰撞),该函数没有反函数,即不可以通过输出推导出输入(隐匿性)。哈希运算有很多种算法,不同的算法可能有位数不同的输出,比特币用了其中的一种,SHA256(Secure Hashing Algorithm 256),顾名思义,该算法的哈希输出结果是256位,可以看作是256位的整数。严格来说免碰撞这个特性并不成立,例如比特币使用的SHA256算法,总共会有2^256种输出,如果我们进行2^256+1次输入,那么必然会产生一次碰撞,甚至从概率的角度看,进行2^130次输入就会有99%的可能发生一次碰撞。不过我们可以计算一下,假设一台计算机以每秒10000次的速度进行哈希运算,要经过10^27年才能完成2^128次哈希!甚至可以这么说,即便是人类制造的所有计算机自宇宙诞生开始一直运算到今天,发现碰撞的几率也是极其小的。

1.2 目标值

 在比特币中所谓的“挖矿”就是修改区块中特定位置的值,找满足要求的区块,该区块的哈希输出要小于特定的值,该值称作目标值,在比特币中,规定256位整数:
0x00000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
为最大目标值,区块要被比特币网络接受其哈希结果必须要小于最大目标值,把该目标值对应的难度定义1,比特币网络会自动的调整难度值,随着比特币挖矿的进行,区块的目标值会越来越小,哈希结果满足要求的概率越来越低,即找到满足要求的区块会越来越难,难度和目标值有如下对应关系:

当前难度值 = 最大目标值 / 当前目标值

由于哈希的随机性,进行一次哈希运行256位整数任意位置的值要么为0要么为1,以最高位为例,要使最高位为零(其他位不关心)理论上进行2次运算即可出现一次,进而要使最高位和次高位都为零,则理论上要进行2^2才会出现一次,依次类推,要使最高32位都为零则需要进行2^32次运行才行,即找到难度为1的哈希值理论上需要进行2^32次运行,进而要找到难度为D的哈希值,理论上要进行D*2^32次运行,数字货币挖矿时,矿池在对矿工进行算力统计时就是根据该理论进行的。

1.3 nBits

区块中用一个4字节长度的字段来存储当前区块的目标值,4字节也就是32位,要用来存储256位长度的难度目标值,因此这256位长度的值需要经过压缩处理后才能放到这个字段中。压缩规则其实很简单,一共有4个字节来进行存储,最高字节用来存储目标值的有效字节数,即目标值转换成16进制后去除前导零的字节数,另外如果最高字节值大于0x7F,则是在最高字节前添加00后字节个数,3个字节中存储的是目标值有效位的最高3个字节,例如对于最大目标值,有效字节的个数是28,因为最高字节是0xFF所以还需在之前添加00,即有效字节数是29(十六进制0x1D),所以压缩后的nBits的最高字节为0x1D,剩余3个字节为00FFFF,即最大目标值对应的nBits为0x1D00FFFF。对于这样的一个压缩后的十六进制4字节难度目标值,前2位通常称为幂者指数,后面6位称为系数。nBits可通过如下公式获得目标值:

目标值=系数*2^(8*(指数-3))次方

以0x1D00FFFF为例,系数是00FFFF,指数是1D,带入公式就是0x00FFFF*2^(8*(0x1D-3)),计算后得到的值是:

0x00000000FFFF0000000000000000000000000000000000000000000000000000

 读者可以已经发现,相比原始的目标值,还原后的目标值,精度少了很多位,确实如此,存储在nBits中的值是一个精度截断后的近似值,但是该值已经很接近原始值,通过计算:
0xFFFF0000000000000000000000000000000000000000000000000000*1.0/0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF=0.9999847412109375
可知该近似的精度很高了。

 1 /* Calculate the difficulty for a given block index.
 2  */
 3 double GetDifficulty(const CBlockIndex* blockindex)
 4 {
 5     CHECK_NONFATAL(blockindex);
 6 
 7     int nShift = (blockindex->nBits >> 24) & 0xff;
 8     double dDiff =
 9         (double)0x0000ffff / (double)(blockindex->nBits & 0x00ffffff);
10 
11     while (nShift < 29)
12     {
13         dDiff *= 256.0;
14         nShift++;
15     }
16     while (nShift > 29)
17     {
18         dDiff /= 256.0;
19         nShift--;
20     }
21 
22     return dDiff;
23 }
GetDifficulty

1.4 难度调整

比特币网络的难度值并不是一成不变的,差不多每两周会调整一下难度值,因为计算的算力是变化的,为了维持差不多10分钟出一个区块的节奏,难度要跟随算力变化而调整。新难度值的计算公式是这样的新难度值=当前难度值×(最近的2016个区块的实际出块时间/20160分钟)2016个区块的意思是,假设按照理论的10分钟出一个块,2周也就是14天的时间,应该出2016个区块,可以看到实际上就是计算一下实际与理论上的时间差值,弥补上这个差值即可。

2 实例分析

我们以比特币57043(00000000152340ca42227603908689183edc47355204e7aca59383b0aaac1fd8)块为例,通过查询可知:

该区块的难度是11.85,nBits是0x1c159c24,转换成256整数后为0x159c24<<(8*(0x1c-3))=0x159c2400000000000000000000000000000000000000000000000000,用原始最大目标值计算可知:

0x00000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF*1.0/0x159c2400000000000000000000000000000000000000000000000000=11.846408911559438

用压缩后的最大目标值计算:

0x00000000FFFF0000000000000000000000000000000000000000000000000000*1.0/0x159c2400000000000000000000000000000000000000000000000000=11.846228149704709

可知难度的近似值都是11.85。

 3 工作量证明

工作量证明系统主要特征是客户端需要做一定难度的工作得出一个结果,验证方却很容易通过结果来检查出客户端是不是做了相应的工作。这种方案的一个核心特征是不对称性:工作对于请求方是适中的,对于验证方则是易于验证的。举个例子,给定的一个基本的字符串"Hello, world!",我们给出的工作量要求是,可以在这个字符串后面添加一个叫做nonce的整数值,对变更后(添加nonce)的字符串进行SHA256哈希运算,如果得到的哈希结果(以16进制的形式表示)是以"0000"开头的,则验证通过。为了达到这个工作量证明的目标。我们需要不停的递增nonce值,对得到的新字符串进行SHA256哈希运算。按照这个规则,我们需要经过4251次计算才能找到恰好前4位为0的哈希散列。

"Hello, world!0" => 1312af178c253f84028d480a6adc1e25e81caa44c749ec81976192e2ec934c64

"Hello, world!1" => e9afc424b79e4f6ab42d99c81156d3a17228d6e1eef4139be78e948a9332a7d8

"Hello, world!2" => ae37343a357a8297591625e7134cbea22f5928be8ca2a32aa475cf05fd4266b7

...

"Hello, world!4248" => 6e110d98b388e77e9c6f042ac6b497cec46660deef75a55ebc7cfdf65cc0b965

"Hello, world!4249" => c004190b822f1669cac8dc37e761cb73652e7832fb814565702245cf26ebb9e6

"Hello, world!4250" => 0000c3af42fc31103f1fdc0151fa747ff87349a4714df7cc52ea464e12dcd4e9

实际上,通过概率学址事可知,预期大概要进行2^16次尝试,才能得到4个前导0的哈希散列。这里数学期望的计算次数,就是我们要求的“工作量”,重复多次进行的工作量证明会是一个符合统计学规律的概率事件。比特币中所谓的“工作量”证明就是不断变化nonce进行哈希计算,使得两次SHA256计算结果小于目标值:

SHA256(SHA256(version + prev_hash + merkle_root + ntime + nbits + nonce )) < TARGET

由哈希函数的特性可以认为,每个矿工要找出满足条件的nonce所需要运行哈希运算的次数从概率上来说是一样的,只要矿工给出了满足条件的nonce值,就可以认为它完成了特定的“工作量”。正是比特系统的工作量证明机制保证了挖矿过程没有投机取巧的可能性,从而保证了比特币网络的公平及安全性。

posted @ 2018-09-02 21:51  weiwei22844  阅读(1719)  评论(1编辑  收藏  举报