协议演进 / BIP/比特币改进提案 / BIP-36

BIP-36 自定义服务

想给 version 消息加一份自定义服务清单,让实验性扩展不必抢占 64 位 services 位域;方案最终关闭,未被采用。本 BIP 目前处于已关闭状态。

一、档案卡

档案卡
编号BIP-36
标题Custom Services
作者Stefan Thomas <[email protected]>
指定日期2012-08-03
层级Peer Services(对等服务)
类型Specification(规范类)
状态Closed(已关闭)
阅读版https://bips.dev/36
官方原文https://github.com/bitcoin/bips/blob/master/bip-0036.mediawiki

二、放在哪一族

BIP-36 属于对等服务层的“节点能力宣告”这一族。节点在握手时用 version 消息里的 64 位 services 位域告诉对方自己能做什么,每一项标准服务占一位,如 NODE_NETWORK、NODE_BLOOM 等。

与它相关的文档包括 BIP-14(协议版本与用户代理)、BIP-33(分层节点,同样动过 services 位的主意)、BIP-37(其服务后来以 NODE_BLOOM 服务位宣告,见 BIP-111)与 BIP-159(NODE_NETWORK_LIMITED 服务位)。

BIP-36 问的是另一个问题:位域只有 64 位,实验性的、还没标准化的扩展服务,该到哪里去登记自己?

三、它要解决什么

原文希望鼓励开发者实验各种扩展比特币协议的自定义服务,并举了例子:分布式哈希表(DHT)、分布式矿池、轻客户端支持协议、定向消息路由、自定义传输支持等。

但没有通用框架时,这些实验很容易互相撞车:名字撞、命令撞、位域乱占。每个实验都往有限的 64 位 services 字段里塞自己的标志,字段会被污染、耗尽,彼此也无法共存。

BIP-36 要提供的正是这个框架:让客户端在 version 消息里以结构化的清单宣告自定义服务,既不占用标准位域,又给日后“转正”留好升级路径;同时附上一些不具约束力的实现建议。

四、规则本身

4.1 version 消息新增两个字段

在 version 消息的 extra_height 之后新增:

一个节点不得宣告两个同名服务;若对方发来这样的 version 消息,客户端可以断开连接。

service_data 的建议用法是:一般应传空字符串,改用自定义握手去初始化协议、交换能力等信息;打算转正为标准服务的服务不得依赖 service_data,因为标准服务的 services 字段没有对应机制。不打算转正的服务则可用它传少量初始化数据,例如自定义传输(UDP、WebSocket)服务把端口号放进去。格式由服务自定,可以是二进制或 ASCII,原文建议用便于调试的人类可读格式。

4.2 服务标识符的命名规则

每个服务应选一个未被他人使用的新标识,并登记到原文指定的 Service identifiers 维基页面,附维护者姓名与联系方式;没有真在用的标识不要登记。已被接受的 BIP 保留或使用的标识,他人不得挪用。

标识长度必须在 5 到 11 个字符之间,只能用 ASCII 字符,且不得含 /、*、_、: 四个字符。原文给的合规例子包括 MySampleSvc、smartserv、P-Pool;太短、太长或含非法字符的则不合规。

4.3 自定义命令的推荐格式(可选)

比特币命令名最长 12 个字符,塞不下“服务标识 + 命令名”。因此原文建议:一个服务在比特币网络上只占一个命令名,即下划线加服务标识(如 _MySampleSvc),以同时避免与别的服务和与现行、未来的协议消息撞名。

真正的子命令放在载荷开头的额外头部里:12 字节的 subcommand(ASCII,空字节填充,填充非空则数据包被拒),其后是实际数据 subpayload。文档中引用这种消息的写法是“服务标识:子命令”,如 MySampleSvc:search。不理解的服务或子命令,客户端应当直接忽略。

4.4 从自定义到标准的转正路径

想进入比特币协议的自定义服务必须满足:不使用 service_data;使用与 services 字段相同的“每节点一位”的对等发现机制;子命令不得与现行或计划中的协议命令冲突。

转正流程大致是:先实现并测试;API 相对稳定后写成 BIP 正式提交;被接受后分配一个 NODE_* 常量,进入过渡期——过渡期内客户端必须同时认两种宣告方式、同时收两种形式的命令,但只发包装形式的消息,且 API 不得变更;过渡期结束后只用 services 字段宣告、只发未包装消息,此后 API 再变就需要新的 BIP 并提升协议版本。原文同时强调,这条转正通道只应留给有强理由的服务;也可以只把服务以自定义形式标准化,而不转成标准服务。

4.5 设计取舍

原文列的目标包括:最小化命名空间冲突风险、给自定义服务留平滑的转正路径、对服务作者施加最少限制、让创建与同时支持多个自定义服务的成本尽量低。

为什么不另发一条新消息、非要改 version?原文的理由是:让标准服务与自定义服务的宣告待在同一条消息里,两类服务的生命周期才能保持一致,也便于识别正处在“两种方式同时宣告”的转正过渡期服务。此外,原文还顺带固定了 subcommand、subpayload、service identifier 等一套讨论自定义服务时的通用名词。

五、谁必须动

普通持币人:无直接变化。本方案不涉及地址、交易与余额。

实验性服务的开发者:若采用本框架,要按规则命名与登记标识、在 version 中宣告服务,并按推荐格式组织命令;不认识的服务与子命令要学会忽略。

全节点实现者:要解析扩展后的 version 消息,处理重名服务等异常情形;是否真去实现某个自定义服务,仍由各自决定。

共识层:完全不动。改动只在握手消息与节点能力宣告层面。

六、现在算不算数,以及一个常见误读

状态为 Closed(已关闭)。BIP-36 的宣告框架没有被网络采用:今天的 version 消息里没有 service_list 字段,新服务进入协议的实际做法,仍是逐个 BIP 论证、逐个分配 NODE_* 服务位(如后来的 NODE_BLOOM、NODE_NETWORK_LIMITED、NODE_COMPACT_FILTERS 等各自的文档)。本页的价值在于留档:它记录了社区曾认真考虑过“给实验留一个通用登记处”,最后没有走这条路。

常见误读:

“services 位域里没给我的功能留位子,我就可以按 BIP-36 的格式自己宣告一个自定义服务,全网节点都得认。”

不对。BIP-36 本身已经关闭,从未成为生效标准;而且即便在它自己的设计里,自定义宣告也只是实验框架,别的客户端对不理解的服务应当忽略,而不是必须支持。想让一项能力成为全网通用的服务,至今仍要走单独 BIP 并分配标准服务位的老路。

七、延伸

本页内容整理自 bitcoin/bips 仓库与 bips.dev,事实已与仓库核对;解读仅供学习参考。