比特币 PoW 难度调节机制简析



  • 比特币白皮书在工作量证明章节中解释了工作量证明(PoW)的方式:

    我们在区块中补增一个随机数(Nonce),这个随机数要使得该给定区块的随机散列值出现了所需的那么多个0。我们通过反复尝试来找到这个随机数,直到找到为止,这样我们就构建了一个工作量证明机制。只要该CPU耗费的工作量能够满足该工作量证明机制,那么除非重新完成相当的工作量,该区块的信息就不可更改。由于之后的区块是链接在该区块之后的,所以想要更改该区块中的信息,就还需要重新完成之后所有区块的全部工作量。

    那这个随机数难度值是怎么产生的呢?

    区块哈希值的计算结果是一个随机数,没有人能直接控制计算的结果。打个比方,重复N次(N趋近于无穷大)掷一个六面的骰子,每掷一次就可以掷出一个6(包含6)以下的数字,但是如果要想掷出3以下的数字,取得每个结果时平均雪要掷2次才行;也就是说,掷出“3以下(含3)”比掷出“6以下(含6)”要难一倍,需要多做一倍的“工作量”。

    如果定义“6以下”这个规则的难度系数(困难度)为“1”,那么“3以下”这个规则的难度系数为“2”,意味者要想符合规则要求,需要2倍的工作量;“1以下“的难度系数则为6,意味着该规则需要6倍的工作量。

    比特币协议中,规定一个256位的整数0x00000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF为难度“1”,在当时的全网算力下大约需要10分钟左右的哈希计算工作量才可以满足小于等于这个数这一规则。

    如果想确保10分钟这个工作时间恒定,那么当算力提高n倍时,需要把难度值也调高n倍。2015年10月Bitcoin网络的难度值为608亿,可以推算出现在的全网算力比2009年初增大了608亿倍。

    难度值的计算实际上就是简单的除法。只不过涉及到的整数太大(远远超过内置的整数位数),没法直接用普通数学库的除法来运算,需要借助高精度的算法库(比如GMP)来完成,这就比较麻烦。所以bitcoin wiki中给出了一种借助泰勒级数变体实现的快速对数算法计算难度值的示例。

    区块存储时,block_header中有一个字段是与难度值相对应的,即bits。用一个32位的整数来压缩存储当期256位的目标值。压缩规则很简单,bits字段的最高位字节为指数(little endian中的第4个字节),存储目标值有效的字节数,如果目标值的最高位为1(大于0x80),需要在前面补上一个0x00。(比如难度值1的目标值有效位为0x00FFFF......,补0后共0x1D个字节)。另外3个字节为尾数(mentissa),截取目标值最高3个字节来存储。

    这样,难度值1对应的目标值写成bits格式,就是0x1D00FFFF。以此类推,目标值为 0x00000000000404CB000000000000000000000000000000000000000000000000时,bits的格式为0x1B0404CB

    计算难度值时其实可以采用简易算法:尾数部分相除,再乘以指数部分带来的差异即可。(2 ^ [指数部分相减的结果 * 8]),计算速度比“快速对数法”要快很多(但是如果超出double型所容许的位数会有溢出)。

    现有的算法中,难度值每2016个区块调整一次,但新的难度值不需要与难度“1”进行比较运算,而是根据前2015个块的出块时间来计算。

    (问:为什么是2015?答:因为最初程序员的代码写错了,纠正这个错误会导致分叉,所以只能将就一下了)

    difficulty = [prev_target] * 【前2015个区块生成所用的时间】 / 1209600 (按标准每10分钟出一个块,2016个块所需要的秒数)

    因为算法确定,所以分布计算时也能保证所有节点计算出的难度值都一致,不会出现分歧。区块链同步时,节点或客户端会优先选取累积难度最大的链作为主链,仅有高度(height)的“伪造慢链”很难被认可,除法伪造出的难度值也很高。但是只要伪造了一个块的难度,后续所有的区块必须用相应的难度重新计算一遍,这往往需要攻击者拥有的算力与当前全网的真实算力相当才有可能完成。

    比特币发展的早期,“伪造慢链”攻击应该是很难防的,但是一旦算力达到一定规模,在PoW下这种攻击需要极大的成本和海量的计算时间(不光是金钱,还需要时间),因而一般只需通过优化算法根据累积难度来标识出主链即可。这是PoW下用高额成本的代价换来的成果——算力保护。



  • @jasonD 对POW的理解有点问题,我再看看资料去



  • 区块存储时,block_header中有一个字段是与难度值相对应的,即bits。用一个32位的整数来压缩存储当期256位的目标值。压缩规则很简单,bits字段的最高位字节为指数(little endian中的第4个字节),存储目标值有效的字节数,如果目标值的最高位为1(大于0x80),需要在前面补上一个0x00。(比如难度值1的目标值有效位为0x00FFFF......,补0后共0x1D个字节)。另外3个字节为尾数(mentissa),截取目标值最高3个字节来存储。

    其中 “如果目标值的最高位为1” 什么意思?目标值是难度值,也就是那一串,最高位不是0或者F吗?


登录后回复
 

与 区块链大学 | qkldx.net 的连接断开,我们正在尝试重连,请耐心等待