协议演进 / BIP/比特币改进提案 / BIP-9
BIP-9
把区块 version 字段解释为位向量,让多个软分叉以不同 bit 并行部署:每个难度调整周期统计信号,达阈值锁定,超时则失败、bit 可回收再用。本 BIP 目前处于已部署状态。
一、档案卡
| 编号 | BIP-9 |
|---|---|
| 标题 | Version bits with timeout and delay |
| 作者 | Pieter Wuille <[email protected]>, Peter Todd <[email protected]>, Greg Maxwell <[email protected]>, Rusty Russell <[email protected]> |
| 指定日期 | 2015-10-04 |
| 类型 | Informational(信息类) |
| 状态 | Deployed(已部署) |
| 阅读版 | https://bips.dev/9 |
| 官方原文 | https://github.com/bitcoin/bips/blob/master/bip-0009.mediawiki |
二、放在哪一族
软分叉部署机制族的基础文档。在它之前,部署靠比较区块版本号大小(BIP-34 开的头,后被 BIP-66、BIP-65 沿用);BIP-9 把 version 改读为位向量,此后多次软分叉都用这套状态机协调上线。
它的替代设计是 BIP-8:改用区块高度计时,并增加超时强制锁定的参数。对照读两份文档,就能看清“矿工信号部署”这套机制的两种取向。
三、它要解决什么
BIP-34 引入的做法是:不预设旗帜时间戳或旗帜高度,而是用区块头里更高的版本号来计量矿工支持。但原文指出它有两个结构性缺点:
- 一次只能推一个改动:版本号按整数比较,同一时间只能有一个升级在推进,多个提案必须互相排队协调;而且不允许“永久否决”——只要一个软分叉没推完,后面的就排不上。
- 每用一次就永久缩小合法版本空间:BIP-34 在其 95% 阈值达成后把 “nVersion ≥ 2” 写成共识规则,一举排除了 2³¹+2 个取值(nVersion 按有符号整数解释,所有负数以及 0、1 都不再合法);BIP-66、BIP-65 又接连排除了 2 和 3。原文认为这种消耗没有必要。
BIP-9 的答案:把 version 字段的每个 bit 分给一次独立部署并行跟踪,成功或超时之后留一段休耕期(fallow),bit 就能回收给后来的改动用。
四、规则本身
4.1 参数
每次部署由四个逐链参数定义:
- name:部署的简短标识;同一 BIP 描述的部署建议用 “bipN”。任何两次部署(无论是否并发)都不应重名。
- bit:nVersion 中用于信号的位,取 0–28;并发部署不得共用同一 bit。
- starttime:该 bit 开始有意义的最低中位过去时间(median time past);建议设为包含该软分叉的软件发布后约一个月,给发布延迟留余量,也防止预发布软件提前触发。
- timeout:部署被判定失败的时间;建议为 starttime 之后一年(31536000 秒)。
同一 bit 可以被后来的部署复用,前提是其 starttime 在前一次的 timeout 或激活之后;原文不鼓励急着复用,建议中间留一段暂停期以便发现有 bug 的软件。
4.2 状态机
每个区块对每次部署都关联一个状态:
DEFINED(初始状态,创世块按定义处于此态)→ STARTED(越过 starttime)→ LOCKED_IN(某调整周期内至少达到阈值的 STARTED 区块置了该 bit;锁定后再持续一个调整周期)→ ACTIVE(此后所有区块开始执行新共识规则);若越过 timeout 仍未锁定,则 FAILED(超时后再过一个调整周期生效),此后保持终态。
计算要点:
- 同一调整周期(2016 个区块)内所有区块状态相同。
- 某块的状态只取决于其祖先的 nVersion,从不取决于它自己。
- 计时用中位过去时间(区块与其前 10 个前驱的 nTime 中位数)作为单调时钟,而不是单个区块的时间戳。
- STARTED 期的判定顺序:先看是否已越过 timeout——是则直接 FAILED;否则统计上一周期置位区块数。阈值为主网 ≥1916(2016 的 95%,源自 BIP-34),测试网 ≥1512(75%)。超时判定优先,是为了避免同一 bit 上两个不重叠的部署同时分别要求置位而产生歧义。
4.3 位与版本范围
nVersion 按 32 位小端整数解释,bit 位取值为 (1 « N)。信号区块的 nVersion 最高 3 位必须为 001,故可用取值范围是 [0x20000000…0x3FFFFFFF]。受 BIP-34、BIP-66、BIP-65 已有约束所限,原本至多 30 次独立部署;把最高 3 位固定为 001 后,本机制可用其中 29 个,另留最高位组合 010、011 给未来的其他机制。最高 3 位不是 001 的区块,对所有部署按全 0 处理。矿工在 LOCKED_IN 阶段应继续置位以便观察采用情况,但这不影响共识规则。
4.4 警告与挖矿模板
- 未知升级警告:额外跟踪一个“未知升级”,用隐含 bit 掩码 (block.nVersion & ~expectedVersion) != 0 判断是否有意外 bit 被置位;检出未知升级进入 LOCKED_IN 时软件应大声警告,进入 ACTIVE 后警告更强。
- getblocktemplate 变更:模板请求新增 rules(所支持的部署名列表);模板新增 rules(处于 ACTIVE 的部署)、vbavailable(待定且受支持的部署及其 bit)、vbrequired(服务器要求提交时启用的 bit 掩码)。使用 version bits 时,模板的 version 必须落在 [0x20000000…0x3FFFFFFF] 内;矿工可在 vbavailable 范围内自行置位或清位(被 vbrequired 要求的 bit 除外)。rules 中的名字可带 “!” 前缀:无前缀表示规则只是让先前合法的交易变为非法(如 BIP-16、BIP-65),不认识该规则的客户端也可原样使用模板挖矿;带 “!” 表示改动更微妙、涉及区块结构或生成交易(如 BIP-34、BIP-141),不认识的客户端不得处理该模板、更不得拿来挖矿。
4.5 设计理由与后续演化口
超时失败的设计让 bit 在软分叉从未激活时也能最终回收,且回收的时间粒度故意定得很粗,以容纳合理的开发与部署延迟;原文判断失败提案不会多到造成 bit 短缺。结束后的休耕期用来检出有 bug 的客户端,并给成功软分叉留出警告与升级时间。原文还预留了演化方向:阈值不必永远是 1916(但要顾及警告系统的兼容)、互相冲突的软分叉可以把“对方不得锁定”写成共识规则、多阶段软分叉可以把多个 bit 合读为一个整数。
五、谁必须动
普通持币人:无直接动作。部署状态机在节点软件里运行,不改变日常收发方式。
矿工:支持某次部署时,在 STARTED(及 LOCKED_IN)期产出的区块里置上对应的 bit;信号与否直接决定该部署锁定还是超时失败。
全节点与实现开发者:按中位过去时间与调整周期计算并缓存每块的状态(链重组时可能需重算),在 ACTIVE 后执行新规则,实现未知升级警告与 getblocktemplate 扩展。
共识层:本 BIP 是信息类文档,定义的是一套通用部署语义;每次具体软分叉的新规则仍由各自的 BIP 定义,只是借用这套状态机上线。
六、现在算不算数,以及一个常见误读
状态为 Deployed:这套 version bits 机制已被实际用于多次软分叉部署,是理解 2016 年之后比特币升级如何协调上线的必读文档。它的边界也要看清:它负责“何时开始执行新规则”的协调,不负责新规则本身的内容;且信号达不到阈值时部署就是 FAILED,不会强行激活——后来 BIP-8 的 lockinontimeout 正是针对这一点提出的替代设计。
常见误读:
“BIP-9 是矿工投票决定比特币规则,95% 矿工同意就能改协议。”
不准确。按原文,bit 信号统计的是矿工对某次部署的准备与支持情况,用来触发 LOCKED_IN 与随后的 ACTIVE;新规则在 ACTIVE 后由每个全节点按共识规则执行、校验。信号是部署的计时与协调工具,不是把协议决定权交给算力的选举——达不到阈值,部署按规则超时失败,仅此而已。
七、延伸
- 阅读版:https://bips.dev/9
- 官方原文:https://github.com/bitcoin/bips/blob/master/bip-0009.mediawiki
- 相关:BIP-8(按高度计时的替代设计)、BIP-34(前代版本号部署)
- 仓库总目录:https://github.com/bitcoin/bips
