组块前先扣四百个签名预算:DEFAULT_COINBASE_OUTPUT_MAX_ADDITIONAL_SIGOPS 的预留逻辑 图 1
组块前先扣四百个签名预算:DEFAULT_COINBASE_OUTPUT_MAX_ADDITIONAL_SIGOPS 的预留逻辑 · 图 1

组块前先在签名预算里扣四百:coinbase 输出的保留额度 DEFAULT_COINBASE_OUTPUT_MAX_ADDITIONAL_SIGOPS

比特币核心替矿工组一个新区块时,账本上有一笔不太显眼的预支:区块的签名操作总预算是八万计价单位,而组装器从第一笔交易还没挑之前,就先扣掉 400 留给未来那条 coinbase 交易的输出。这 400 来自策略层常量 DEFAULT_COINBASE_OUTPUT_MAX_ADDITIONAL_SIGOPS。为什么凭空预留?扣多了还是扣少了会怎样?本文全部以 Bitcoin Core v31.0 源码为准。

区块的签名预算是稀缺资源

共识规则给每个区块的签名操作成本设了硬上限:MAX_BLOCK_SIGOPS_COST,八万计价单位。交易在被选中进块模板时,各自的脚本签名成本会累计进这个预算,接近用尽就不能再塞。但有一个时序问题:组装器开始挑交易的时候,coinbase 交易还不存在——它是最后按矿池要求生成的,其输出脚本(收款锁定脚本)的形状在组装开始时并不完全可知。如果最后生成的 coinbase 输出碰巧用了很重的脚本,而区块预算已经被普通交易填到只剩零头,整块就可能因为超了签名预算而无效。

预留四百,从记账起点就生效

策略层的处理办法是”先扣再花”。src/policy/policy.h 中定义 DEFAULT_COINBASE_OUTPUT_MAX_ADDITIONAL_SIGOPS 为 400,注释写明:创建区块模板时,为 coinbase 交易输出预留的默认签名成本。落到组装器 src/node/miner.cpp 里,每轮重置区块状态时,区块的签名成本计数器 nBlockSigOpsCost 不是从零开始,而是直接被设成这个预留值——也就是说,后续所有交易共享的可用预算天然是”八万减四百”。四百对八万只有半个百分点的损耗,换来的是:无论矿池最终把收益锁成什么常见脚本,coinbase 都不会成为压垮预算的最后一根稻草。

这个额度是可调的内部选项

值得强调的是这一层的性质。组装选项结构体里的字段(src/node/types.h)默认取上述 400,并会被钳制在零到八万之间——传负数按零处理、传超预算按整块预算封顶,防止把普通交易的预算挤光。在进程内接口(IPC)的挖矿选项定义里,这个字段有正式的参数名 coinbase_output_max_additional_sigops,供外部挖矿组件在建模板时显式调整。也就是说,它是”组装这台节点”的策略参数:它改变的是本节点生成的模板如何预留,不改变八万这个全网共识上限,也管不着别人组出来的块。

现场观察

普通 RPC 面(如 getblocktemplate)不会把这 400 单独印成一个返回字段,但它的影响可以在数字里看到:模板返回的 sigoplimit 是八万,把模板内各交易的 sigops 逐项加总,离上限留出的那个小缺口里就有 coinbase 预留的份额。真把预算用满又塞了重脚本 coinbase 的矿池,会收到什么后果?组装期它自己的模板无效,只能重来——共识节点对超预算区块的态度是整块拒绝,没有商量。

常见误区

一是把这 400 当成共识规则:共识只有区块总预算八万,预留多少是各实现保护自己的策略选择。二是把它和区块”预留权重”(blockreservedweight,默认八千权重单位)混为一谈:那个管体积、这个管签名成本,两本账互相独立。三是以为预留越大越安全:预留到接近八万,普通交易就没预算可花,模板反而空转;400 是对常见输出脚本的一次性买断,够用且不浪费。四是以为这 400 只对隔离见证时代的脚本有意义:多签、锚定输出乃至未来新脚本类型都在同一预算下竞争,预留逻辑跟着计价单位走,不跟着脚本流派走。

风险提示:本文为区块组装机制科普,常量与接口字段以 Bitcoin Core 当前版本源码为准,可能随版本调整;不构成矿池收益承诺或投资建议。