比特币区块头的扩展空间:时间戳、版本号滚动与额外随机数 图 1
比特币区块头的扩展空间:时间戳、版本号滚动与额外随机数 · 图 1

区块头里真正在变的字段

一台矿机每秒钟要尝试几十万亿次哈希,但它能改动的东西其实非常少。比特币的区块头固定八十字节:四字节版本号、三十二字节父区块哈希、三十二字节默克尔根、四字节时间戳、四字节难度目标(nBits)和四字节随机数。除了父块哈希和难度目标在挖矿期间基本不动,其余字段都在以不同节奏变化。大多数人知道 nonce 是挖矿的核心变量,但对矿机来说,nonce 恰恰是最先被用完的那个。 四字节 nonce 只有四十二亿多种取值。一台算力较高的矿机在几秒到几十秒内就能把这四十二亿个数扫完一遍。扫完之后如果哈希仍不达标,就必须改变区块头的内容,否则一切重复计算都是徒劳。于是矿工和矿池软件依次动用三个补充空间:先更新时间戳,再改版本号低位,最后动 coinbase 交易里的额外随机数。

第一层空间:时间戳

更新 nTime 是最自然的第二步。时间戳是 Unix 秒级计数,正常情况下每过一秒就产生一个新的合法取值,等于每秒钟免费多出四十二亿个哈希位置。区块时间戳并非随便填写:规则要求它必须大于前十一块时间戳的中位数,又不能比节点自己的时钟快太多,各矿池实现通常允许在正常值附近做有限的向前或向后偏移。这也是为什么区块浏览器里的出块时间看起来总比真实时刻滞后若干秒:矿机往往要把一个时间戳对应的全部 nonce 空间耗尽,才会切换到下一秒。

第二层空间:版本号滚动

更早的矿机曾通过往 coinbase 交易追加垃圾数据来制造变化,效率很低。后来 Stratum 协议出现了版本滚动(version rolling)的协商机制:矿池告诉矿机一段可以随意翻转的版本号位掩码,矿机在提交份额时附上自己改过的 version_bits,由矿池还原出完整的 nVersion。BIP 310 曾为这一做法写过正式规范(在 BIP 仓库中的状态至今仍是草案),但矿池实现里的 mining.configure 与 mining.set_version_mask 扩展沿用至今。BIP 320 则进一步把版本号第十三位到第二十八位共十六个位划为通用用途,明确它们不再用于软分叉信号,钱包和节点看到这些位被翻转也不应报警。 版本滚动有一个著名的争议名字:AsicBoost。哈希函数的特性决定了,只要版本号某些位按特定方式变化,矿机可以复用前一阶段的中间计算结果,理论上有机会提升效率。把它公开用在版本号上的做法称为显式(overt)AsicBoost,块里能看出来;如果转而操纵交易排序去制造同样的哈希碰撞空间,则称为隐式(covert)做法,从区块表面看不出来。2017 年开发者格雷格·马克斯韦尔在比特币开发邮件列表公开了这一发现,指出某款主流挖矿芯片经逆向工程确认内置了该能力,此后围绕哪些矿池实际使用了隐式做法,社区长期只有间接证据,没有公认结论。

第三层空间:额外随机数

当时间戳和版本号都用尽,就要改变默克尔根。矿池把 coinbase 交易拆成 coinbase1 与 coinbase2 两段下发,中间的 extranonce2 由矿机自由递增,coinbase2 里还有一段 extranonce1 由矿池分配给每个连接。每换一个额外随机数,coinbase 就不同,默克尔根随之改变,四字节 nonce 又获得了全新的四十二亿次机会。不同矿工、不同矿池的 extranonce 互不相同,这也是同一笔交易中不同区块哈希互不重复的原因之一。

普通用户怎么用这些知识

如果你运行节点或用 RPC 观察网络,getblockheader 返回的 version、time、bits、nonce 就是上面这些字段的原样。看到相邻区块版本号略有差异属于正常现象,不代表异常分叉信号;出块时间戳与真实时间差十几秒也属常见。至于某个矿池是否使用显式版本滚动,可以从区块版本号的非典型取值的统计分布推断,但这属于研究性观察,单个区块不足以下结论。

风险提示

本文只解释挖矿工作空间的构造原理,不构成任何挖矿收益预期或投资建议。矿机宣传的算力、功耗与价格请以厂商官方参数为准,二手与预购矿机存在交付与收益风险。