协议演进 / BIP/比特币改进提案 / BIP-21
BIP-21
今天通用的 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 留下的两个麻烦:
- 金额写法太多:十进制、十六进制、X 指数并存,同一金额有多种表达,解析与显示都容易出错、出歧义。简化为单一写法,才能让不同钱包对同一条链接算出同一个数。
- 扩展参数的进退没有规矩:将来必然要加新参数。老客户端遇到不认识的参数,是该整单拒绝还是忽略?若一律拒绝,新功能永远推不开;若一律忽略,关键参数被无声丢弃又会出事。需要一条事先约好的规则——这就是 4.4 的
req-前缀机制。
同 BIP-20 一样,它坚持 URI 是“支付标识,不是个人标识”:每笔交易应使用唯一地址,链接表达一次付款,而不是某人的身份;方案名 “bitcoin:” 本身也要让路人看得懂、搜得到。
四、规则本身
4.1 通用处理规则(原文标为“重要”)
- 客户端不得在未取得用户授权时对 URI 采取行动;
- 客户端应要求用户逐笔手动批准付款;某些情形下,可允许用户预先设定自动批准。
图形客户端应默认把自己注册为 “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 表示;
- 不得含逗号,必须用句点(.)分隔整数与小数部分;
amount=50.00或amount=50都是 50 BTC;amount=50,000.00是无效的。
客户端可以用任何不欺骗用户的格式显示金额,应首选最不易混淆的格式,其次才是对该数额最合理的格式;原文举例:在多数用户以 BTC 计价时,即使 mBTC 或 TBC 读起来更“顺”,也应默认按 BTC 显示。原文示例中的地址是刻意写成无效的,以免有人误转资金。
4.4 前向兼容:req- 前缀规则
- 以
req-开头的参数视为必填扩展:客户端若不实现任何一个带req-前缀的参数,必须把整条 URI 视为无效; - 不带
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 无效;不带前缀的未知参数应被安全忽略。把两者混为一谈,要么会误拒正常付款,要么会在该拒绝时误付——这正是本提案要事先立规矩的原因。
七、延伸
- 阅读版:https://bips.dev/21
- 官方原文:https://github.com/bitcoin/bips/blob/master/bip-0021.mediawiki
- 相关:BIP-20 URI 方案(本页所替代)、BIP-321(接替本页的现行文档)
- 仓库总目录:https://github.com/bitcoin/bips
