协议演进 / BIP/比特币改进提案 / BIP-70
BIP-70
定义商户与顾客之间的支付协议:商户发出经 X.509 证书签名的 PaymentRequest 给出收款输出与金额,顾客回送 Payment,商户以 PaymentACK 确认收到。本 BIP 目前处于已部署状态。
一、档案卡
| 编号 | BIP-70 |
|---|---|
| 标题 | Payment Protocol |
| 作者 | Gavin Andresen <[email protected]>, Mike Hearn <[email protected]> |
| 指定日期 | 2013-07-29 |
| 层级 | Applications(应用) |
| 类型 | Specification(规范类) |
| 状态 | Deployed(已部署) |
| 阅读版 | https://bips.dev/70 |
| 官方原文 | https://github.com/bitcoin/bips/blob/master/bip-0070.mediawiki |
二、放在哪一族
BIP-70 是支付协议族的主文档,另有两份配套件与它同日指定:
BIP-71:为这三种协议消息定义 MIME 媒体类型,规定消息经 HTTP 或邮件传递时如何标注封装
BIP-72:给 BIP-21 的 bitcoin: URI 增加 r 参数,让用户点一个链接就能启动本协议
三份合起来是一条完整的商户收款链路:链接负责把顾客带进来(72),MIME 类型负责消息在网线上的身份(71),消息本身的含义与流程由本篇定义(70)。
三、它要解决什么
原文先描摹了当时最简的比特币支付流程:顾客把商品放进购物车、决定用比特币付款;商户生成一个唯一收款地址并与订单关联;顾客从网页上复制地址粘进钱包,或点击 bitcoin: 链接让钱包带金额打开;顾客授权付款并经 P2P 网络广播;商户服务器侦测到付款、等足确认数后视为完成。
BIP-70 要在这个流程上扩展五项能力:
- 人类可读且安全的收款目的地:顾客被要求授权付款给 “example.com”,而不是一串 34 字符、无法辨认的比特币地址;
- 安全的付款凭证:顾客日后与商户发生争议时可出示;
- 抗中间人攻击:防止攻击者在硬件钱包授权交易之前,把商户的比特币地址替换成攻击者自己的地址;
- 付款收到消息:顾客立即知道商户已收到并正在处理其付款,而不必等链上确认去猜;
- 退款地址:顾客钱包自动把退款地址给商户,多付或订单无法履约时,商户不必先联系顾客就能退款。
四、规则本身
协议消息用 Google 的 Protocol Buffers 编码,用 X.509 证书认证,经 http / https 传输。原文说明,将来可以有别的 BIP 把它扩展到其他编码、PKI 体系或传输协议。
整场会话只有三条消息:商户发 PaymentRequest,顾客回 Payment,商户回 PaymentACK。
4.1 PaymentRequest:商户开的“账单”
具体内容放在 PaymentDetails 里,外面再套一层 PaymentRequest 装商户身份与签名。PaymentDetails 的主要字段:
- network:
main(生产网络)或test(测试网络);收到不支持的网络,客户端必须拒绝该请求; - outputs:一个或多个收款输出,每个输出含 amount(要付的聪数)与 script(钱应付到的 TxOut 脚本,通常为标准交易脚本之一)。金额合计为零时,由顾客决定付多少、可任选其中输出付款;合计非零时,顾客付该总和,并按非零金额在各输出间拆分;
- time / expires:请求创建的 Unix 时间戳,以及过期时间戳,过期后请求应视为无效;
- memo:给顾客看的纯文本说明,解释这笔请求是为什么;
- payment_url:顾客回送 Payment 消息的(通常为 https 的)地址;它至少应在请求过期前保持有效——哪怕订单已取消也不能提前失效,因为商户服务器需要记录误付以便退款;
- merchant_data:商户用来把付款与请求对应起来的任意数据,可省略。
外层 PaymentRequest 则含版本号、pki_type(实现须支持 none、x509+sha256、x509+sha1)、pki_data(X.509 时为证书链)、序列化后的 PaymentDetails,以及对整条消息所作的数字签名。
钱包收到 PaymentRequest 后必须依次:按 PKI 验证商户身份与签名(pki_type 非 none 时);确认本机时间未过 expires,过期必须拒绝;向顾客展示商户身份(例如第一张 X.509 证书的 Common Name)并请其确认是否付款。大于 50,000 字节的 PaymentRequest 应被钱包拒绝,以防拒绝服务攻击。
4.2 Payment:顾客的回执与付款
顾客授权付款后,客户端构造并签名一笔或多笔付清 outputs 的交易,再次确认未过期,随后把交易广播到比特币 P2P 网络;若指定了 payment_url,再向该地址 POST 一条 Payment 消息,其中含:
- merchant_data:从 PaymentDetails 原样复制回来,供商户对应订单(原文提醒:恶意客户端可篡改它,商户应另行设法认证,例如用商户专有密钥签名);
- transactions:一笔或多笔付清该请求的、有效的已签名交易;
- refund_to:一个或多个退款输出,商户在需要时可把钱退到这里;商户在付款请求时间之后 2 个月内可使用它们退款,过期后要退必须另行协商;
- memo:顾客给商户的纯文本留言。
发 Payment 消息时须按 BIP-71 设置 Content-Type: application/bitcoin-payment 与 Accept: application/bitcoin-paymentack。payment_url 必须能防中间人篡改 refund_to(用 HTTP 时须有 TLS 保护)。商户服务器收到 Payment 后,须判定交易是否满足付款条件,当且仅当满足时才把交易广播到 P2P 网络;大于 50,000 字节的 Payment 应被服务器拒绝。若同一请求收到多条相同 Payment,服务器必须逐条确认——顾客端可能因传输失败而重发,确认不能丢。
4.3 PaymentACK:商户的确认
PaymentACK 是流程的最后一条消息,由商户服务器发给钱包,内容是触发它的 Payment 消息的副本,外加一条 memo,向顾客展示交易状态(原文示例:“Payment of 1 BTC for eleven tribbles accepted for processing.”)。大于 60,000 字节的 PaymentACK 应被钱包拒绝;上限比另两条消息大,是因为它内嵌了一整条 Payment。
4.4 证书与扩展
默认 PKI 是 X.509(与认证网站服务器同一套体系)。签名证书必须排在证书链第一位,其后依次为给前一张签名背书的证书,直到(但不含)受信任根;接收方须按 RFC 5280 验证整条链,任一验证失败即拒绝请求。根证书可取自操作系统;没有操作系统的设备推荐用 Mozilla 根证书库。
扩展机制靠 Protocol Buffers 本身:新增可选字段会被旧实现忽略(但会保留并转发);新字段不改变 PaymentDetails 仍为版本 1 的事实。若将来需要“只有新实现能接受”的请求,则定义版本 2 的新 PaymentDetails,旧实现收到时应提示用户升级。需要扩展消息的实现须使用 1000 起始的字段编号,并更新扩展页面以免冲突。
五、谁必须动
普通持币人(顾客):变化在体验层:付款前看到的是经证书认证的商户名而非裸地址;付款后能即时收到商户确认;退款地址由钱包自动提供,无需事后联系商户。
钱包开发者:需实现三条消息的收发:验证证书链与签名、核对过期时间、按 outputs 构造交易、POST Payment 并处理 PaymentACK;同时执行各消息的大小上限。
商户与支付服务器:需生成签名的 PaymentRequest、维护 payment_url、校验回送的 Payment 并广播合格交易、逐条回 PaymentACK。支持多语言的商户应按语言生成对应的 PaymentRequest 与 PaymentACK。
全节点与矿工、共识层:完全不必动。链上最终落地的仍是普通比特币交易,本协议只规范商户与钱包在链下如何商量这笔交易。
六、现在算不算数,以及一个常见误读
状态为 Deployed(已部署)。它是商户收款体验的一层链下协议:认证、账单、回执都在链下完成,结算仍靠链上交易本身。读它要分清两层——协议规定的是消息与流程,不改变任何一笔链上交易的有效性判定。
常见误读:
“用了 BIP-70,收款地址就变成商户域名了,链上记的是域名。”
不对。域名只是经证书认证后展示给顾客看的身份;真正决定钱付到哪里的,仍是 PaymentDetails 里逐条列出的 outputs——金额(聪)与收款脚本。链上交易与此前一样,只认脚本与签名,不认域名。
七、延伸
- 阅读版:https://bips.dev/70
- 官方原文:https://github.com/bitcoin/bips/blob/master/bip-0070.mediawiki
- 相关:BIP-71 支付协议 MIME 类型、BIP-72 bitcoin: URI 扩展、BIP-21 bitcoin: URI
- 仓库总目录:https://github.com/bitcoin/bips
