同步中的节点日志里偶尔会闪过一行拒绝记录,或者你用 submitblock 提交一个区块时拿到一句短语。比特币核心给无效区块准备的这套短代号不是随手写的日志文本,而是一份分类明确的诊断词汇表:每个代号都指向校验流水线上的一个具体环节,看到哪个词,就知道问题卡在哪一层。理解这条流水线,比记住全部词汇更重要。
v31.0 的校验顺序大体从便宜到昂贵。第一步只看区块头:工作量证明是否真的低于目标值,代号 high-hash,调试信息是 proof of work failed;版本号是否在允许范围,代号形如 bad-version 加十六进制值。这一层花几个字节就能判死一个块,所以永远排在最前。第二步是结构检查,仍然不需要执行任何脚本:整块体积是否越界记 bad-blk-length;第一笔交易不是币基交易记 bad-cb-missing;出现第二笔币基交易记 bad-cb-multiple;交易列表里有重复交易记 bad-txns-duplicate;默克尔根与交易列表对不上记 bad-txnmrklroot;见证数据的结构问题另有 bad-witness-nonce-size 与 bad-witness-merkle-match。全部通过后,才轮到需要查历史状态的上下文检查:这个块的父块在不在活动链上(bad-prevblk)、币基交易里写的块高对不对(bad-cb-height)、币基交易的产出是否超过补贴加手续费(bad-cb-amount)、整块的签名操作预算是否越界(bad-blk-sigops)、非最终交易是否被塞进来了(bad-txns-nonfinal)、整块权重是否超限(bad-blk-weight),以及在启用 signet 的网络上,区块携带的出块证据是否满足这条网的脚本——它有自己的专属代号 bad-signet-blksig。
从这些代号反推,能看出比特币校验设计的三条原则。第一,先验形式后验语义:high-hash、bad-blk-length、bad-txnmrklroot 都只依赖区块自身的内容,一个无状态的人拿着块和规则就能判断,不需要知道链的历史。这让坏块在传播早期就被拦下,不用消耗全网的 UTXO 查询。第二,共识错误与政策错误分开:bad-cb-amount 这类是记账违规,任何诚实节点都必须拒绝;而节点因为自己的策略(比如内存池配置)不欢迎某笔交易时,不会也不能用这些代号,那是交易侧的事。第三,代号一旦公开就倾向于保持稳定——它们出现在日志、测试断言和第三方工具的解析逻辑里,改动等于破坏别人的自动化,因此多年几乎只增不改。
对运营者,这套词汇表的实用价值在三类场景。第一类,同步卡住或反复断开某对端:先看被拒代号属于哪层。头部层(high-hash、bad-diffbits)通常是对方在测试或广播畸形数据,节点按规则丢弃即可;bad-prevblk 则说明你的节点缺一段历史,往往随同步推进自愈;bad-cb-height 与 bad-txnmrklroot 若频繁出现在同一条链上,那是真实的共识分歧信号,需要立刻核对软件版本与部署参数,而不是继续观望。第二类,用 regtest 或自建 signet 搭测试链时 submitblock 失败:bad-signet-blksig 指向出块脚本与签名密钥不匹配,bad-cb-height 多半是生成工具的链上下文过期,重新导入或重挖即可。第三类,写监控时按代号族分类计数,比按原始文本计数稳定得多——头部族、结构族、上下文族各自的增速对应完全不同的处置剧本。
需要提醒的边界是:这些代号描述“这台节点为什么拒绝”,不等于“全网为什么拒绝”。同一份块,若你的节点版本落后或参数被改,可能拒掉别人接受的块,反过来也一样——2013 年那次因为库版本不一致导致的短暂分裂就是极端教材。因此代号只用于定位本机视角的失败原因,判断链的健康度仍然要看节点的部署参数与版本一致性,不能拿一句短语下全网结论。
风险提示:本文为协议与软件机制说明,不构成任何投资建议;文中代号与顺序以比特币核心 v31.0 源码为准,后续版本可能调整。

发表评论
还没有评论,来说两句吧。
评论区为展示样式,提交不会被处理。