0%

比特币pow难度验证

比特币pow难度验证

何为POW

pow的全称为proof of work,即工作量证明。简单的解释为“做了多少工作”。抛开区块链的背景,pow就是对自己做了多少工作的一种说明:比如做了学习了50个小时的汽车驾驶。而他人很容易验证这个结果:你可能50个小时之后拿到了一本驾照。别人就知道你确实在学习驾驶上使用了50个小时。

Block Header

在区块链的世界里,pow的数据可以体现在区块链的区块头中。当然一般来说,讲解POW的难度离不开挖矿问题。本文因为主要讨论方向的问题,不展开讲挖矿,主要从区块头入手。在阅读下面的内容之前,默认读者已经有了如下前置知识

  1. 区块链常识
  2. 比特币基本概念
  3. 挖矿基本概念

抛开前置知识之后,我们来看区块头的数据结构。

https://en.bitcoin.it/wiki/Protocol_documentation#Block_Headers

可以直接参考以上链接,当然可以可以直接查看比特币的源码,我们现在把数据列出来。

1
2
3
4
5
6
7
8
struct header_structure {      // BYTES   NAME
uint32_t nVersion; // 4 version
uint8_t hashPrevBlock[32]; // 32 previous block header hash
uint8_t hashMerkleRoot[32]; // 32 merkle root hash
uint32_t nTime; // 4 time
uint32_t nBits; // 4 target
uint32_t nNonce; // 4 nonce
};

现在逐条解释block header中的字段。

nVersion 版本号,主要用来跟踪软件版本(bitcoin core)和协议号 现在固定为2

hashPrevBlock 前一个节点的hash值,我们知道区块链的链,大致指的是数据链式存储。我们可以简单粗暴的理解为它是指向前置节点的链表。

hashMerkleRoot 默克尔根,区块中所有交易组合起来生产成本的默克尔树的根。详情可参考数据结构“默克尔树”

nTime 时间戳,标志块生成的时间

nBits 和难度有关,本文讨论的重点

nNonce 随机值,和难度有关,本文讨论的重点

基本概念

现在介绍基本概念,方便理解:

  1. 挖矿是矿工之间互相竞争的结果,谁先算出有效区块,谁就可以得到块中的比特币奖励,它叫做coinbase,另外块中有交易,交易中蕴含的手续费也是矿工的奖励
  2. 有效区块的意思是:区块头的SHA256结果要小于等于一个目标值(target)
  3. merkleroot是矿工从内存池取出来的“交易”构建的。
  4. 大致上是先构建,再验证
    • 区块头SHA256运算,如果结果小于等于一个目标值(target),则新块构建成功,广播到全网,随后开始下一次算力竞赛
    • 否则,调整区块头部分字段的值(修改Nonce或者通过调整交易来修改Merkle Root),重新做计算

目标值target

前一段提到了,区块头hash计算之后小于等于目标值才算有效区块。注意区块头哈希算法SHA256有256位,而bits只有32位。bit转换成target有特定公式:

target = coefficient * 256^(exponent – 3)

随机抽取一个幸运区块来分析一下,我们就选高度为88888的区块。

1
2
bits 454,373,987
注意:这个bits是10进制,我们分析时候需要转16进制 对应为 0x1b153263

bit值是按照系数+指数的方式存储的,前两位为幂,后六位为系数。

1
2
3
4
5
6
1b为幂(exponent) 153263为系数(coefficient)注意这是16进制
根据公式
target = (0x153263)* 256^(1b - 3)
target = 1389155 * 256^(27 - 3
= 8719867261221084516486306056196045840260667577454435863762042880
= 00 00 00 00 00 15 32 63 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

需要注意的有:计算的时候还是转10进制,计算完之后要转16进制,不够64位的要在高位补零。

实际上我们发现,实际的hash

000000000013a2a3a8f1aaec4690f55fdcb4067d812521a6d55239d8ea1a4dd3

比目标target确实是小的。

难度

查看创世区块 我们发现 bits为0x1d00ffff (486604799)。我们把这个难度定为1

根据上面的公式,我们可以很简单的计算出target 0x00ffff * 256^26

0x00000000ffff0000000000000000000000000000000000000000000000000000

也就是说下一个区块头的sha256哈希值要小于这个值(前三十二位为0)。

target用16进制表示,每两个十六进制位表示一个字节bytes,前面有8个0,相当于4个字节,为4*8 = 32位(2进制位bit)

这里有个重要结论:

SHA256运算的结果被认为是 一致的随机序列 。换个说法:SHA256的结果中的某一位的值,为0或为1的概率相同。所以做一次计算,满足上述条件(前32位的值均为0)的概率为1 / (2^32),也就是平均要做2^32次运算,才能找到这个值

关于一致的随机序列:可以看这个

在此之上,我们定义:“使区块头的SHA256结果小于某个目标值(target),平均要尝试的计算次数,这个次数为难度(difficulty)”。创世区块的难度为1!

比特币有这样一个公式

difficulty—current = target-genesis / target-current

随机选取一个幸运高度算一个 选择500000

1
2
3
4
5
6
7
8
9
10
11
12
13
bits: 402,691,653
Difficulty: 1,873,105,475,221.61

bit转16进制 18 009645
target = (0x009654) * 256^(18-3)
= 38484 * 256^(24-3)

创世块的target = (0x00ffff * 256 ^ 26)

两者相除 = 65535/38484 * 256^5
= 1.70291549735 * 2 ^ 40
= 1,873,105,475,221.61
= 1.87 * 10^12

可以看到计算出的难度和区块链浏览器展示的难度一致。大约为1.87T。

此外,还有一个计算公式

出块时间(单位:秒) ≈ difficulty_当前 * 2^32 / 全网算力

有兴趣的话可以去区块链浏览器上计算一下,在当前的难度下,出块时间是不是保持在10分钟左右。

难度的调整

由上述计算得知,区块链难度取决于target值。target值和bits值相关。根据区块链的设计,要保证在10分钟左右出块。实际上,在难度不变的情况下,出块速度和全网算力相关,全网算力越大,则出块时间越短。为了保证出块时间的基本恒定,比特币在代码中内置了一个调整难度的算法。实际上这个算法很简单:

每产生2016个块,期望时间为2016*10min,大约两周。全网实际出2016个块的时间和期望时间做对比(times对比),小于期望就增加难度,大于期望值就减小难度。总体保持恒定。

根据比特币的源码,调整难度也是有限度的,如果调整的倍数超过4倍,按照4倍或者四分之一来调整。再次强调一遍,区块中的难度不是直接写入区块头的,是调整bits值得到的。有兴趣可以看这里

注意:实际代码中2015个块就会调整,因为当初写代码写错了。。。

关于难度验证的闲话

区块链pow难度验证如何保证数据的正确性

这里面有两个问题:交换数据的时候如何保证这个块是正常的块,不是伪造的?

答:区块链像链表一样,要指向前一个块。本区块中的的prvehash要和前一个区块的哈希一致。另外就是要计算pow难度,大致相当于之前的target计算过程,target要满足要求说明才是正常的块。

再进一步:如果难度满足要求,就是正常的块,有没有可能同时有两个以上有效块产生?

完全可能,因为coinbase不一样,merkle树不一样,nonce值也不一样,计算出来hash也不一样,是存在两个不一样的块都满足要求都 被接受的。但是,总有一个块会更快得到其他块,链接上。所以最长的链才是有效链。

安全广播的问题?

答:所谓安全广播,就是指如何应对别人窃取你的工作量,别人是否可以拿你打包的那些交易?答案是不可以,打包的时候,要从交易池获取对应的交易,其中第一个交易是自己的coinbase交易,如果你先成功,相当于矿工已经锁定了交易,锁定了merkletree。别的矿工只好开始下一轮竞争。换句话说:你打包了就是你的,别人只能放弃。这里有个常见的误解,因为交易是从内存池取过来的,交易不一样得到的merkler树不一样,会影响块hash计算,那我岂不是永远无法的的计算出合适的hash?实际在挖矿过程中,矿工会按照交易费高低排序,优先高交易费的交易打包进块。他为了快,选取什么交易(先算好),times是什么都是固定的(只要比上一个大就行),专心寻找nonce值即可。