跳转到正文
buybitcoinsmart

术语表 /挖矿与共识

nBits

又称 Compact target、难度位。

nBits 是什么?
nBits 是每个区块头中长度为四字节的字段,它以一个指数和一个三字节系数组成的紧凑、类浮点编码方式,对挖矿目标值进行打包。

比特币需要在区块头中使用一个256位的目标值,而区块头无法为此腾出32字节,因此它用四个字节存储该值的一个取整版本。第一个字节是指数,其余三个字节是系数,目标值等于系数乘以256的(指数减三)次方。每个节点都会重新计算自己预期的值,因此声称目标值比规则允许的更容易的区块头会被直接拒绝。

运作方式

nBits 被解读为一个指数字节加上一个三字节系数,二者合并成一个完整的256位数字。

以创世区块携带的值0x1d00ffff 为例。指数是0x1d,即29,系数是0x00ffff,即65,535。因此目标值等于65,535乘以2的208次方,写成十六进制是八个零,随后是 ffff,再用零补足到64位。这是主网允许的最容易的目标值,也是难度1的定义。

有两个特殊之处容易让人困惑。第一是精度。仅有24位的系数无法表示任意的256位数字,因此编码后的目标值始终是取整后的值,从目标值转换为 nBits 再转换回来,并不总能得到最初的值。第二是符号位。如果系数的最高位被置位,该值会被视为负数,因此编码器会将系数下移一个字节,并相应增大指数。这就是创世区块的值写作0x1d00ffff,而不是看上去更直观的0x1cffff00 的原因,也是系数内部出现前导零字节属于正常现象而非错误的原因。

在序列化的区块头中,该字段位于字节偏移量72处,并以小端序写入,因此这四个字节在磁盘和网络上显示为 ff ff 00 1d。

在哪里会遇到它

nBits 以多个不同的名称出现,围绕它的大多数困惑由此而来。

区块浏览器将其标为"bits",并在更易读的难度数字旁显示该十六进制值。Bitcoin Core 的 RPC 命令 getblock 将其作为"bits"返回,getblocktemplate 则将其作为候选区块头必须满足的要求交给挖矿软件。在源代码中,它是 CBlockHeader 的 nBits 成员,由 arith_uint256::SetCompact 和 GetCompact 进行转换。矿池几乎不会将其展示出来:Stratum 在任务通知中把这四个字节发送给矿机,固件无需理会其含义。

该字段的变化也是按周期进行,而非连续变化。它在整个2,016个区块的窗口内保持不变,只在难度调整时才取新值,因此相隔一小时挖出的两个区块,其 nBits 字段相同,除非两者之间发生了难度调整。

nBits vs 目标阈值

nBits 是编码,目标阈值是它所编码的数字。节点从不直接将区块头哈希与 nBits 比较,而是先把这四个字节展开成完整的256位目标值,再检查哈希是否小于或等于该值。在交谈中把 nBits 当作目标值本身无妨,但在代码中是错误的,因为相差一个单位的两个 nBits 值,解码后得到的目标值在绝对数值上相差极大。

请勿混淆

常见问题

nBits 与难度相同吗?

不相同。nBits 对目标值进行编码,难度是由目标值推导出的比值:允许的最容易目标值除以当前目标值。区块浏览器显示难度,是因为十进制数字比十六进制字段更便于比较。

创世区块为什么使用0x1d00ffff?

因为这是比特币主网允许的最容易的目标值,其编码使系数的最高位保持为零。解码后,它等于65,535乘以2的208次方,这就是难度1的含义。

相关术语

挖矿与共识中的更多术语

阅读本页英文版