比特币挖矿的算法,可以简单地总结为对区块头做两次sha256哈希运算,得到的结果如果小于区块头中规定的难度目标,即挖矿成功。
区块头的结构 如下
那么挖矿的算法可以表达为
block_header = version + previous_block_hash + merkle_root + time + target_bits + nonce
for i in range (0 , 2 **32 ):
if sha256(sha256(block_header)) < target_bits:
break
else:
continue
简单回顾下挖矿的流程。
挖矿节点首先对交易做验证,剔除有问题的,然后通过一套自定义的标准来选择哪些交易希望打包进区块,比如通过交易费与交易占用的字节大小的比值超过某个门槛来判断,这样的交易才被认为有利可图。当然,节点也可以特意选择要加入某条交易,或者故意忽略某些交易,每个挖矿节点有很大的自由裁度权力。
如果是通过矿池挖矿的话,矿池的服务器会去筛选交易,然后分配给每个参与的矿机一个独立的任务。这个任务的难度小于总的挖矿难度,完成了小难度的计算,即确认了自己参与的工作量。每台不同的矿机计算的问题不会重复,当其中一台矿机成功挖矿时,其他矿机依据工作量分配获得的总收益。
一旦筛选好交易数据,按照时间排序,两两哈希,层层约减,通过这些交易就可以计算出一棵Merkle树,可以确定一个唯一的摘要,这就是Merkl树的根。
merkle树中,任何节点的变化,都会导致merkle root发生变化,通过这个值,可以用来验证区块中的交易数据是否被改动过。
然后我们再依次获取挖矿需要的每一项区块头的信息。 区块头只有80个字节,挖矿只需要对区块头进行运算即可。交易数据都通过merkle树固定了下来,不需要再包含进来。而所谓的区块链,其实也是通过区块头而链接在一起的 。下面的示意图比较简单明确地解释了区块链和区块的构成。
比特币区块链示意图
区块头中的信息,在挖矿前大部分已经是固定下来的,或者是可计算的。
版本号
跟随比特币客户端而定,一段时间内不会改变 。即使要改变,也会有比特币的核心开发人员来协调升级策略,这个可以理解为一个静态常数。
前一区块的哈希摘要
一次哈希即可 。前一区块已经是打包好的。
默克尔树的根
刚才已经得到了结果,根据本次交易包含的交易列表得到 。
时间
取打包时的时间 。也不需要很精确,前后几秒,几十秒也都可以。
难度目标
参考上两周产生的区块的平均生成时间而定 。两周内如果平均10分钟产生一个区块的话,两周会产生2016个区块,软件会计算最新的2016个区块生成的时间,然后做对比,随之调整难度,使得接下来产生的区块的预期时间保持在10分钟左右。因为最近的2016个区块已经确定,所以这个数字也是确定的。
随机数nonce
这个就是挖矿的目标 了。这是一个32位的数字。
随机数可以变化,而且要从0试到最大值2^32。直到最后出现的hash结果,其数字低于难度目标值。不过以现在的计算机算力,一台矿机用不了一秒就把全部的变化可能计算完了,所以还需要改变区块内部的创币交易中的附带消息,这样就让merkle root也发生了变化,从而有更多的可能去找到符合要求的nonce。
合格的区块条件如下:
SHA256D(Blockherder) < F(nBits)
其中,SHA256D(Blockherder)就是挖矿结果,F(nBits)是难度对应的目标值 ,两者都是256位,都当成大整数处理,直接对比大小以判断是否符合难度要求。
为了节约区块链存储空间,将256位的目标值通过一定变换无损压缩保存在32位的nBits字段里。具体变换方法为拆分利用nBits的4个字节,第1个字节代表右移的位数,用V1表示,后3个字节记录值,用V3表示,则有:
F(nBits)=V_3 * 2^(8*(V_1-3) )
此外难度有最低限制,也就是说 F(nBits) 有个最大值,比特币最低难度取值nBits=0x1d00ffff,对应的最大目标值为:
0x00000000FFFF0000000000000000000000000000000000000000000000000000
因此挖矿可以形象的类比抛硬币 ,好比有256枚硬币,给定编号1,2,3……256,每进行一次Hash运算,就像抛一次硬币,256枚硬币同时抛出,落地后要求编号前n的所有硬币全部正面向上。
挖矿中,第一笔交易是创币交易。创币交易可以附带一段文字消息,这段信息可以用来提供更多的nonce. 比如中本聪在挖出创世区块时植入的信息。
The Times 03/Jan/2009 Chancellor on brink of second bailout for banks