闪电网络的可复用收款码:BOLT 12 报价的完整收发流程 图 1
闪电网络的可复用收款码:BOLT 12 报价的完整收发流程 · 图 1

一码收天下:BOLT 12 想解决什么

用过闪电收款码的人都有体会:BOLT 11 发票基本是一次性的。它把金额、描述、有效期全部焊死在一段 Bech32 字符串里,签名覆盖整张发票——改一个字符就作废。于是商家要么给每个顾客现开一张票,要么把同一张票贴出去给所有人重复用,后者会带来付款串扰和隐私问题。BOLT 12 规范把这些痛点逐条列在了文档开头,并给出一个完全不同的模型:收款方发布一个可以长期挂着的“报价”,付款方在自己的钱包里针对这次购买现生成一张只属于自己的发票。

三条消息的对话

BOLT 12 把一次收款拆成 offer、invoice_request 和 invoice 三种结构化消息。商家把一份 offer 发布在网页或静态二维码上,里面写明这是卖什么、可以固定金额也可以留空、支持哪些特性。用户扫码后,钱包在闪电网络里向商家发一条 invoice_request,带上本次的金额、描述和新鲜随机数;商家节点据此签发一张全新的 invoice 发回;用户再按这张发票完成付款。整个来回对用户是透明的,屏幕上仍然是“扫码、确认、成功”。规范同时支持反向流程:商家先发 invoice_request 说明想给用户退多少钱,用户回一张发票让商家付款,自动取款和退款场景由此而来。

为什么静态码可以不换

同一份 offer 可以服务无限多次购买,每次的 invoice 都是独立签发的,支付哈希、支付密文各不相同,彼此无法关联。这对商家是运营解放,对双方隐私也更友好。地址隐藏方面,BOLT 12 大量使用盲路(blinded path):offer 里可以只挂一串经混淆的路由路径,付款方通过路径末端与商家通信,拿不到商家的真实节点身份;发票里同样为每条盲路配一份付款信息,付款方必须按票行事。签名格式改用通用 TLV 结构,字段可以被单独抽取和出示——这也是付款证明的基础:付款完成后,双方可以各自生成一份可验证的收据,证明“这笔钱因为这份报价而支付”,事后可举证而无需公开整张发票内容。

使用前的现实检查

BOLT 12 依赖洋葱消息基础设施把请求送达对方,收款节点必须持续在线,网络路径也比 BOLT 11 多两个来回,小额首刷的延迟会略高。静态二维码长期有效,意味着二维码本身成为被攻击目标:物理贴纸可能被覆盖成攻击者的 offer,网页上的 offer 可能被跨站脚本替换。防御方法是把核对重心从“码”挪到“钱包显示的发票描述与金额”上:每一次付款前,钱包展示的 invoice 描述应与当前订单页一致,对不上就停。付款证明可以留存作为纠纷凭证,但它是密码学收据,不替代商家售后政策。本文描述协议机制,不涉及任何交易时机建议。

与 LNURL 静态码的分岔

静态闪电收款码目前有两条主流路线,用户看到的是同一张二维码,机制却不同。LNURL 路线的做法是在二维码里放一个 HTTPS 地址,钱包扫码后向服务器请求一张现开的发票——好处是复用现有网页基础设施、接入快,代价是收款方服务器在流程中处于可见位置,用户必须信任这台服务器给出的发票描述与金额,且对网络封锁的抗性较弱。BOLT 12 路线把这套交互搬进闪电网络本身:报价消息经洋葱消息送达,可用盲路隐藏节点身份,签名与字段抽取由协议保证,服务器可见性被削弱。两者都能实现“一码长期有效”,差别在信任落点:LNURL 把信任交给一个域名与它的实现,BOLT 12 把信任交给密钥与协议规则。选型判断可以直接照这个差别问:你的收款方服务器是否值得用户信任,若不值得,就更该选把信任压回密码学的路线。

落地前的三条现实检查

一是钱包支持面:收发双方都要有实现才能走通,报价能力上线较晚,先确认自己钱包的行为再决定推广,别把兼容性赌在顾客端。二是运营语义:一份报价的有效期语义、多次购买之间的对账标识、退款流程都由报价字段与商家逻辑约定,规范给了结构但没有替你定业务规则,报价文本改动需要重新发布而静态二维码不会自动更新。三是失败重试体验:报价模式下同一份报价重复请求是常态,若商家侧对重复请求缺少幂等处理,会出现顾客连点两次被生成两张实际发票的怪事,用户视角就是“付了两次”,需要靠商家侧对账与钱包提示共同兜住。