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

BIP-321 URI 方案

更新 bitcoin: URI 方案:用统一的链接描述链上地址与闪电发票、静默支付等多种支付指令,让点击链接或扫码即可发起付款。本 BIP 目前处于已完成状态。

一、档案卡

档案卡
编号BIP-321
标题URI Scheme
作者Matt Corallo <[email protected]>
指定日期2024-11-15
层级Applications(应用)
类型Specification(规范类)
状态Complete(已完成)
取代文档Replaces: BIP-21
阅读版https://bips.dev/321
官方原文https://github.com/bitcoin/bips/blob/master/bip-0321.mediawiki

二、放在哪一族

支付链接与发票族。这一族的源头是 BIP-20 与 BIP-21 定义的 bitcoin: URI 方案:把收款地址、金额等信息编码成一条链接或一个二维码,用户点击或扫码即可付款。BIP-321 是 BIP-21 的修改版与指定接替者,档案上以 Replaces 标记取代 BIP-21。

同一族中还有几份近亲:

BIP-72:支付协议的 bitcoin: URI 扩展

BIP-351:Private Payments;其地址经本 BIP 的 pay 参数承载

BIP-352:Silent Payments(静默支付);其地址经本 BIP 的 sp 参数承载

理解 BIP-321 的关键,是看清它如何把“一条 URI 只能装一个链上地址”的老格式,升级为“一条 URI 可以同时装多种支付指令、付款方自选其一”的统一发票格式。

三、它要解决什么

3.1 让付款像点链接一样简单

原文动机的第一句就是 URI 方案的总目的:让用户只需点击网页上的链接或扫描二维码,就能轻松完成付款。bitcoin: URI 是操作系统、浏览器与钱包之间传递“付款指令”的通用语言。

3.2 老格式装不下现代支付方式

BIP-21 写于只有链上地址的年代。如今收款方常常同时希望提供闪电发票、静默支付地址等多种收款方式,新地址类型也不断出现。若每种方式都另造一套链接格式,钱包与商户系统就要反复适配;若把新地址硬塞进 URI 的地址位置,老钱包又会无法识别。

BIP-321 的修法是结构性的:地址部分保留给经典链上地址,新的支付指令一律放进查询参数。这样旧付款方至少还能走链上回退路径,新付款方则能挑更现代的方式。

3.3 付款发起方需要拿到付款凭证

原文还新增了一个老格式没有的环节:发起付款的应用(如在手机上唤起钱包的另一个应用)可能需要知道付款已完成的结果。链上付款尚可自行监控区块链,但闪电等支付没有全局账本可查。为此本 BIP 定义了可选的付款证明(Proof of Payment)回传机制。

四、规则本身

4.1 通用格式与处理纪律

Bitcoin URI 遵循 RFC 3986 的通用 URI 格式:路径部分是比特币地址,查询部分提供附加支付选项;查询元素中超出有效范围的字符须先按 UTF-8 编码,再逐字节做百分号编码。

两条处理纪律原文置于规范之首:

形式文法(ABNF)要点:方案名 “bitcoin:” 大小写不敏感,查询参数的键同样大小写不敏感(原文指出,用全大写 URI 的二维码已是常见做法,把握这一点才兼容);参数值与地址字段是否大小写敏感取决于其内容。同一键可出现多次的情形有明确区分:代表支付指令的参数可以重复,label、message、pop 不得重复,其他未知参数则必须允许重复。

4.2 地址部分放什么

URI 的 bitcoinaddress 主体必须是 base58 的 P2SH 或 P2PKH 地址、bech32 的 SegWit v0 地址、bech32m 的 SegWit 地址,或者干脆为空。原文强调:未来的地址格式应当改放查询参数作为可选支付指令,以保证升级周期的向后兼容;地址部分也可以留空——前提是查询参数中至少提供了一条支付指令,适合不想提供标准链上回退的收款方。

4.3 查询参数

通用键(适用于任何 URI):

支付指令键(原文列出的现行定义):

原文还给了一条命名约定:使用 bech32 或 bech32m 编码的新支付指令,应复用其地址格式的人类可读前缀(HRP)作为参数键。测试网的 SegWit 地址因此要放进 tb 参数而不是 bc 参数:一串 URI 可同时携带多个 bc 参数,分别给出不同 SegWit 版本的地址。

金额参数 amount 必须以十进制 BTC 表示:不得有逗号,小数点用 “.” 分隔。例如 amount=50.00 与 amount=50 都表示 50 BTC,而 amount=50,000.00 是无效的。

4.4 必填参数与前向兼容

带 req- 前缀的查询参数被视为必填:客户端若不理解某个 req- 参数,必须把整条 URI 视为无效;不带前缀的未知参数则可以安全忽略。原文举例:带 req-somethingyoudontunderstand 的 URI 对老客户端是无效的,而同样的未知键不带前缀时 URI 仍有效。地址类型今后一律经查询参数添加,老付款方只需支持经典指令,就能付给提供更现代格式的新收款方。

4.5 付款证明(pop)

URI 可带 pop(或 req-pop)参数,其值是一个经百分号编码的 URI 前缀。付款完成后,支持回传的钱包解码该前缀,拼上实际所用的支付指令键名、一个 “=” 与付款信息,再用系统默认处理程序打开拼成的 URI,把结果交回发起付款的应用。链上付款的付款信息是已广播交易的完整十六进制(含见证数据);经 lightning 参数完成的 BOLT 11 付款,付款信息是支付原像的十六进制编码;其他支付方式各自定义格式。

安全约束有三条:

4.6 设计理由与兼容性说明

原文专门申明“支付标识符,而非个人标识符”:链上地址的最佳实践是每笔交易使用唯一地址,因此含链上地址的 URI 必须被当作一次性付款指令,而不是个人信息的交换;只有由可复用、且不复用地址的指令(如 BOLT 12 offer、静默支付)构成的 URI,才可以按钱包意愿复用。

与 BIP-21 相比,本 BIP 的变化包括:把承载支付指令的标准查询参数写成规范、查询参数改为大小写不敏感、允许 bech32/bech32m 地址进入地址字段、允许地址字段为空。原文指出:bech32/bech32m 地址用法与 lightning 参数在 2024 年的数年前已成常见做法;任何既有 BIP-21 实现原则上自动符合本 BIP,唯一可能的例外是查询参数大小写不敏感这一点。参考实现指向 rust-bitcoin 的 bitcoin-payment-instructions 库。

五、谁必须动

普通持币人:付款体验不变——点链接或扫码、在钱包里核对金额与收款方、批准。需要知道的是:一条链接现在可能同时给出链上与闪电等多种收款方式,由钱包代为选择;批准前核对的习惯不变。

钱包开发者:这是主要的行动方。要按新文法解析 URI(包括大小写不敏感、重复键规则与 req- 语义),支持查询参数中的多种支付指令与空地址 URI,未经用户授权不得自动付款;实现 pop 的,还须落实方案白名单式的安全校验与 req-pop 的拒绝付款规则。

商户与收款方:生成 URI 时应把链上地址只当一次性指令使用;想同时提供闪电、静默支付等方式时,按参数键规范拼装,并可借助 pop 让发起付款的应用拿到完成凭证。

全节点与矿工:无需改动。URI 是应用层约定,不进入共识与网络协议。

共识层:本 BIP 不修改共识规则。

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

状态为 Complete(已完成),且档案上正式取代 BIP-21。它的“完成”指规范文本已经完备、可供实现;在应用层标准里,实际效力取决于钱包与商户系统的采用程度——原文亦承认,其中若干做法(bech32 地址入 URI、lightning 参数)在成文之前已是通行实践,本 BIP 做的是把实践固定为标准,并为今后的支付指令留好扩展位。

常见误读:

“BIP-321 是一套全新的付款链接格式,老二维码全要作废。”

不对。原文明确:既有 BIP-21 实现原则上自动符合本 BIP,新格式是老格式的超集——经典地址链接照常可用,新增的只是查询参数里的现代支付指令与付款证明回传。作废之说与原文的向后兼容结论正相反。

七、延伸

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