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

BIP-21 URI 方案

今天通用的 bitcoin: 支付链接写法出自这一版:砍掉 BIP-20 的十六进制与指数金额,只留十进制 BTC,并用 req- 前缀解决“不认识的参数该拒绝还是忽略”。本 BIP 目前处于已关闭状态。

一、档案卡

档案卡
编号BIP-21
标题URI Scheme
作者Nils Schneider <[email protected]>, Matt Corallo <[email protected]>
指定日期2012-01-29
层级Applications(应用)
类型Specification(规范类)
状态Closed(已关闭)
替代BIP-20
接替文档Proposed-Replacement: BIP-321
阅读版https://bips.dev/21
官方原文https://github.com/bitcoin/bips/blob/master/bip-0021.mediawiki

二、放在哪一族

bitcoin: URI(支付链接)族的第二代,也是把这套写法真正定型的版本。

原文开头有两层交代,先看清位置:文件头注明“本 BIP 已被 BIP-321 取代,请改读 BIP-321”;正文则说明它是对 BIP-20 的修改——BIP-20 出自 Luke Dashjr、又基于 Nils Schneider 的更早文档,而本版把 BIP-20 的备选金额写法全部移除。

所以链条是:BIP-20(复杂全语法)→ BIP-21(本页,简化定型)→ BIP-321(现行接替文档)。与 BIP-20 同属应用层:不碰共识与脚本,只约定支付链接的写法与客户端的处理规则。今天扫码、点链接付款时见到的 bitcoin:<地址>?amount=…&label=… 基本形状,就定型于这一版。

三、它要解决什么

目的与 BIP-20 相同:让用户点一下网页链接、或扫一下 QR 码,就能轻松付款。

它要额外解决的是 BIP-20 留下的两个麻烦:

同 BIP-20 一样,它坚持 URI 是“支付标识,不是个人标识”:每笔交易应使用唯一地址,链接表达一次付款,而不是某人的身份;方案名 “bitcoin:” 本身也要让路人看得懂、搜得到。

四、规则本身

4.1 通用处理规则(原文标为“重要”)

图形客户端应默认把自己注册为 “bitcoin:” 方案的处理程序(若尚无其他处理程序);若已有,首次运行时可以提示用户是否改选。

4.2 通用格式

URI 遵循 RFC 3986 的通用格式:路径部分是一个比特币地址,查询部分提供附加付款选项。

查询部分中的字符若超出合法范围,须先按 UTF-8 编码,再对每个字节做百分号编码。细节上有两条大小写规则:方案名 “bitcoin:” 大小写不敏感,实现必须接受任意大小写组合;URI 的其余部分大小写敏感,包括查询参数的键名。

简化语法:

bitcoin:<address>[?amount=<amount>][?label=<label>][?message=<message>]

查询键包括 label(该地址的标签,如收款人名称)、address、message(向用户描述这笔交易的消息),及其他为将来扩展保留的可选参数。

4.3 金额:只准十进制 BTC

这是与 BIP-20 最醒目的分界:

客户端可以用任何不欺骗用户的格式显示金额,应首选最不易混淆的格式,其次才是对该数额最合理的格式;原文举例:在多数用户以 BTC 计价时,即使 mBTC 或 TBC 读起来更“顺”,也应默认按 BTC 显示。原文示例中的地址是刻意写成无效的,以免有人误转资金。

4.4 前向兼容:req- 前缀规则

于是生成方能精确控制语义:“这个参数你不认识,就别付这笔款”(req-),或是“这个参数只是附加信息,不认识也无妨”(普通参数)。原文给的反例正是一条带 req-somethingyoudontunderstand 的链接:对不懂它的客户端整条无效;换成不带 req- 的同名参数,则链接有效、参数忽略。

向后兼容上,原文建议:在本 BIP 定稿后 6 个月的宽限期内,不要把 req- 参数用在性命攸关的地方,给客户端开发者发新版、老用户升级留出时间。当时的参考实现是 Bitcoin-Qt:支持不带 req- 前缀的旧版 URI,含 Windows 与 KDE 集成。

五、谁必须动

普通用户:链接不能自动扣款,客户端必须先取得本人授权、逐笔批准——这是继承自 BIP-20 的安全底线。

钱包 / 客户端开发者:注册 “bitcoin:” 处理程序;严格按十进制规则解析金额(拒绝带逗号的写法);正确处理方案名大小写不敏感、其余大小写敏感;实现 req- 规则——不认识的必填扩展须整单判无效,而非默默忽略。

商户与付款请求生成方:生成链接时只用十进制 BTC 写金额;对新参数慎用 req- 前缀,因为它会使不懂该参数的旧客户端拒绝整条链接。

共识层 / 全节点:无任何关系,URI 是纯应用层约定。

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

本页状态为 Closed,原文已注明被 BIP-321 取代,现行规范以 BIP-321 为准(档案卡中亦标有 Proposed-Replacement: BIP-321)。

但要在档案意义上分清两层:它的“关闭”是因为有了接替文档,而不是因为这套写法被推翻——恰恰相反,BIP-20 的复杂语法被它简化之后,bitcoin: 链接的通行形状就是这一版定下的。读支付链接的历史,BIP-21 是承上启下的定型稿:向上砍掉了 BIP-20 的多余表达,向下给未来扩展留了 req- 这条可进可退的规矩。

常见误读:

“链接里有我钱包不认识的参数,这条付款链接就是坏的、无效的。”

不对。按 4.4 的规则,只有带 req- 前缀的不认识参数才使整条 URI 无效;不带前缀的未知参数应被安全忽略。把两者混为一谈,要么会误拒正常付款,要么会在该拒绝时误付——这正是本提案要事先立规矩的原因。

七、延伸

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