协议演进 / BIP/比特币改进提案 / BIP-14
BIP-14
把协议版本与客户端版本拆开:version 字段只表示协议版本,客户端身份改用结构化的 user agent 字符串按软件栈逐层标明。本 BIP 目前处于已部署状态。
一、档案卡
| 编号 | BIP-14 |
|---|---|
| 标题 | Protocol Version and User Agent |
| 作者 | Amir Taaki <[email protected]>, Patrick Strateman <[email protected]> |
| 指定日期 | 2011-11-10 |
| 讨论日期 | 2011-11-02 |
| 层级 | Peer Services(对等服务) |
| 类型 | Specification(规范类) |
| 状态 | Deployed(已部署) |
| 阅读版 | https://bips.dev/14 |
| 官方原文 | https://github.com/bitcoin/bips/blob/master/bip-0014.mediawiki |
二、放在哪一族
对等服务层的身份与版本这一族,管的是节点在网络上如何报家门:我说的协议是哪个版本、我跑的是什么实现。
文中用词先作区分:bitcoin 指协议本身,Satoshi 指当时的客户端(后称 Bitcoin Core 一脉)。这份 BIP 处理的正是“协议”与“某一个实现”从最初混为一体、到必须分家的问题——今天在节点连接信息里看到的 user agent 字符串(如 /Satoshi:x.y.z/ 的形态),源头就在这里。
三、它要解决什么
比特币起步时只有一个 Satoshi 客户端,协议即客户端,版本号只有一个。但社区开始分化:用 Java、Python、Javascript、C++ 等不同语言写的替代客户端快速出现,各有自己的功能集。
当时协议里内嵌的版本号——主要出现在 “version” 与 “getblocks” 消息中,“block” 消息里也用它表示产出该块的软件版本——与客户端版本号是同一个数。这带来两个问题:
- 绑架其他实现:Satoshi 客户端每次发版都抬高这个数,其他所有客户端被迫追赶它的版本编号节奏,这与比特币的去中心化性质相悖——网络健康要求把“协议”这一共享协作过程从“协议的实现”中拆出来。
- 版本抬升可致不兼容与网络分裂:靠一个共享编号区分彼此,本就容易出问题。
拆法是:协议有自己的版本号,所有实现对齐到同一标准;客户端的身份与版本则降格为一条信息性的 user agent 字符串,像车牌一样只用于区分彼此。原文也承认,把协议开发改为多方协商有“难以达成一致时”的民主代价,需要强沟通渠道与快发布节奏来缓解,但这属于流程类 BIP 的范围,不是本文的事。
四、规则本身
4.1 字段分工
- “version” 与 “getblocks” 数据包中的 version 字段,改为协议版本号;“block” 中的版本号表示该块创建时的协议版本。
- “version” 数据包中原先未使用的 sub_version_num 字段,改为新的 user agent 字符串。
原文为两者的用途划了一条明确的界线:
- 协议版本:用来区分节点、并据此采取不同行为的依据。
- User agent:只是简单的信息工具。协议不得因 user agent 不同而被修改或区别对待——若客户端针对不同实现采取不同行为,将导致协议分裂。user agent 的正当用途是统计网络数据(如各实现的分布、常见架构与操作系统),极端情况下甚至能帮助识别威胁网络健康的故障客户端,但原文明确说以此屏蔽对方是强烈不推荐、极坏的做法。
4.2 User agent 格式
格式借鉴浏览器 user agent(RFC 1945)但加以结构化,因为浏览器的空格分隔格式不利于机器解析、也没有层次。比特币软件通常是从核心代码库到图形界面的一个软件栈,user agent 就按这个栈逐层编码:
基本格式:
/Name:Version/Name:Version/.../
示例:
/Satoshi:5.64/bitcoin-qt:0.4/
/Satoshi:5.12/Spesmilo:0.8/
即同一种核心代码可以有不同版本的上层界面(如 bitcoin-qt 与 Spesmilo 可同用协议版本 5.0、而各自代码库版本不同)。
细节规则:
- 版本号无严格格式,但推荐 Major.Minor.Revision 形式(如 2.6.41);仓库构建推荐用 YYYYMMDD 日期形式(如 20110128),git 构建也可用 commit 标识,但原文轻度推荐日期,因为脱离仓库时 commit 先后不易判断。版本号后可附加 -r1、-r2 等(同为轻度推荐,非强制)。版本号中不得包含
( ) : /这几个字符,以免干扰语法。 - 版本号之后可带可选注释,用括号
(...)界定,内容完全由实现自定,推荐用分号;分隔多条信息,如/BitcoinJ:0.2(iPad; U; CPU OS 3_2_1)/AndroidBuild:0.8/。 - 保留符号共四个:
/分隔软件栈层级,:标明该层的实现版本,(与)界定注释,不得挪作他用。
4.3 时间线
文档发表时,协议与 Satoshi 客户端版本同为 0.5 且正在变动。为减少扰动、让在途改动完成,原文安排:到下一版 0.6 时把协议版本(同为 0.6)从客户端版本中剥离;自那时(2012 年 1 月)起,协议版本号与实现版本号彼此独立。
五、谁必须动
普通持币人:无直接变化。钱包连接网络时附带的身份字符串变了,收发币不受影响。
客户端开发者:按新分工填两个字段——version 报协议版本,sub_version_num 按 /Name:Version/ 的栈式格式报自己的实现身份;版本号与注释不得使用保留符号。
全节点与网络观察者:可以解析 user agent 做网络构成统计;但不得按 user agent 对连接方区别对待协议行为,更不应以此屏蔽节点。
共识层:无变化。改的是对等服务层消息字段的含义,不涉及区块与交易有效性。
六、现在算不算数,以及一个常见误读
状态为 Deployed:协议版本与实现版本分家、user agent 按栈式格式自我标明,早已是比特币网络的日常形态——节点软件在 version 握手消息里报出的正是这类字符串,网络统计中看到的实现分布即来自于此。本 BIP 不定义任何具体协议版本的内容,只定义“版本号归谁、身份怎么写”。
常见误读:
“节点应该看 user agent 决定怎么对待对方,比如屏蔽某个有问题的客户端版本。”
恰恰相反。BIP-14 明确把区别对待的依据限定为协议版本,并写明 user agent 只是信息工具,协议不应因它而被修改;拿它去屏蔽故障客户端被原文称为强烈不推荐、极坏的做法,因为按实现身份区别对待正是协议分裂的源头。
