比特币pow难度验证
何为POW
pow的全称为proof of work,即工作量证明。简单的解释为“做了多少工作”。抛开区块链的背景,pow就是对自己做了多少工作的一种说明:比如做了学习了50个小时的汽车驾驶。而他人很容易验证这个结果:你可能50个小时之后拿到了一本驾照。别人就知道你确实在学习驾驶上使用了50个小时。
Block Header
在区块链的世界里,pow的数据可以体现在区块链的区块头中。当然一般来说,讲解POW的难度离不开挖矿问题。本文因为主要讨论方向的问题,不展开讲挖矿,主要从区块头入手。在阅读下面的内容之前,默认读者已经有了如下前置知识
- 区块链常识
- 比特币基本概念
- 挖矿基本概念
抛开前置知识之后,我们来看区块头的数据结构。
https://en.bitcoin.it/wiki/Protocol_documentation#Block_Headers
可以直接参考以上链接,当然可以可以直接查看比特币的源码,我们现在把数据列出来。
1 | struct header_structure { // BYTES NAME |
现在逐条解释block header中的字段。
nVersion 版本号,主要用来跟踪软件版本(bitcoin core)和协议号 现在固定为2
hashPrevBlock 前一个节点的hash值,我们知道区块链的链,大致指的是数据链式存储。我们可以简单粗暴的理解为它是指向前置节点的链表。
hashMerkleRoot 默克尔根,区块中所有交易组合起来生产成本的默克尔树的根。详情可参考数据结构“默克尔树”
nTime 时间戳,标志块生成的时间
nBits 和难度有关,本文讨论的重点
nNonce 随机值,和难度有关,本文讨论的重点
基本概念
现在介绍基本概念,方便理解:
- 挖矿是矿工之间互相竞争的结果,谁先算出有效区块,谁就可以得到块中的比特币奖励,它叫做coinbase,另外块中有交易,交易中蕴含的手续费也是矿工的奖励
- 有效区块的意思是:区块头的SHA256结果要小于等于一个目标值(target)
- merkleroot是矿工从内存池取出来的“交易”构建的。
- 大致上是先构建,再验证
- 对区块头做
SHA256
运算,如果结果小于等于一个目标值(target),则新块构建成功,广播到全网,随后开始下一次算力竞赛 - 否则,调整区块头部分字段的值(修改
Nonce
或者通过调整交易来修改Merkle Root
),重新做计算
- 对区块头做
目标值target
前一段提到了,区块头hash计算之后小于等于目标值才算有效区块。注意区块头哈希算法SHA256有256位,而bits只有32位。bit转换成target有特定公式:
target = coefficient * 256^(exponent – 3)
随机抽取一个幸运区块来分析一下,我们就选高度为88888的区块。
1 | bits 454,373,987 |
bit值是按照系数+指数的方式存储的,前两位为幂,后六位为系数。
1 | 1b为幂(exponent) 153263为系数(coefficient)注意这是16进制 |
需要注意的有:计算的时候还是转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 | bits: 402,691,653 |
可以看到计算出的难度和区块链浏览器展示的难度一致。大约为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值即可。