收款方代付交易矿工费的解决方案

对于 Alice 发送 BSV 给 Bob 这种常见的使用场景,交易的矿工费一般是由 Alice 也就是交易的发送方支付的。而对于 BIP-270 所描述的支付场景,商户也就是收款方可能更愿意承担这部分费用,替用户支付交易的矿工费来尽可能的促成交易或提升用户体验。

本文将针对收款方如何代付 BSV 交易的矿工费,给出可行的解决方案。

显而易见,用户只有用 ANYONECANPAY 标记签名,商户才能为交易添加 gas 输入。问题的核心是怎么限制交易输出,是 SIGHASH_SINGLE,还是 SIGHASH_ALL。

Alice 去店里买咖啡,需要支付 1 BSV,她会将签好名的付款交易直接发给 Bob,然后等待;Bob 收到 Alice 发来的交易后确认交易有效,然后交付商品,流程结束。在整个交互过程中,Bob 会关心自己是否真的收到了钱,所以他会把 Alice 的交易迅速发给矿工来验钞和“结算”;而 Alice 只关心自己是否能尽快取走咖啡,以及自己的支付找零是否安全。

所以对 Alice 来说,使用 SIGHASH_SINGLE 来限制交易找零十分合理。对下面这笔交易,Alice 会使用 SIGHASH_SINGLE | ANYONECAYPAY 标记来签名以放开对交易其它输入输出的限制,同时能保证找零给自己的输出(蓝色)不可修改。她把这个交易直接发给 Bob,意思是我支付了 1 BSV 给你,其它的事情不用我操心,如果你确认交易没问题,那我就可以拿走咖啡。

Bob 收到这笔交易后,会先添加 1 BSV 咖啡钱的输出(绿色)给自己,然后添加 gas 的输入和找零(红色),并使用 SIGHASH_ALL 标记签名。Bob 最终发给矿工的交易如下图所示。

整个方案很简单,但在工程实现上,还有两个细节需要确认:

  • Alice 如果有多个输入要怎么签名
  • Bob 如何提供 gas 输入来避免性能瓶颈

如果 Alice 有多个输入,第一个输入使用 SIGHASH_SINGLE 其它输入使用 SIGHASH_NONE 就可以,因为她只关心给自己的找零是否不可修改。

对第二个问题,因为实际支付可能是并发的,当遇到多人同时付款时,Bob 需要保证给不同交易分配的 gas UTXO 是彼此互斥的,否则整个系统就只能排队执行,每个交易都把前一个交易的 gas 找零当做自己的 gas 输入。要解决这个问题也很简单,提前拆分 UTXO 用一个队列管理起来就可以了。之前我在给 WitnessOnChainBSV 测试网水龙头时就是用的这个方案,实测的效果很不错。

使用 SIGHASH_SINGLE 方案的优势十分明显:Bob 可以很灵活的修改交易。例如,他可以每卖出一杯咖啡就向自己的合伙人 Charles 支付一笔钱。

实际上,Bob 都不需要为这个方案提前准备 gas UTXO,他可以直接从咖啡款里支付矿工费。因为 Alice 发来的交易是确定的,他计划为这个交易添加多少输出也是确定的,所以 Bob 能提前精确的算出最终的交易需要多少矿工费。

基于此,如果 Bob 决定这样支付矿工费,那 ANYONECANPAY 也可以去掉,因为他已经不再需要为交易添加其它输入了。

通过这些讨论你能看到,使用 SIGHASH_SINGLE 的好处就是灵活。不管怎样,Bob 都必须保证一点:Alice 发来的交易不能被他人截获,因为任何拿到这笔交易数据的人都可以添加输出取走里面的 1 BSV。但注意,这个要求对 Bob 来说是合理的,因为他有义务更有动力来采取措施以保证自己的资金安全。实际上要解决这个问题也不复杂,点对点发送交易时选择 HTTPS 或者近场通信,就可以大幅提升 MITM 的攻击成本。

那 Alice 使用 SIGHASH_ALL | ANYONECANPAY 签名行不行?也可以,但会损失一部分灵活性。

使用 SIGHASH_ALL 就意味着 Bob 不能添加输出,因为没有 gas 找零,所以 gas 输入必须是精确的。

所以这个方案要解决的问题,是 Bob 如何在每次收款时都能精确的提供 gas 输入。博泉的 CEO 林哲明给出了这个问题的解决办法:每次都现场构造一个交易。

Bob 还是可以用上文提到的方法提前拆分和管理 gas UTXO,但在每次取队列后,都立即花费拿到的 gas UTXO(红色)新生成一个特定金额的输出(黄色)来作为这次付款交易的 gas 输入。因为 Bob 只会对收到的付款交易添加 1 个输入,所以他同样能提前精确的算出最终交易需要多少矿工费。

这个方案相比 SIGHASH_SINGLE 来说更加“安全”,即使 Alice 发送的交易不小心被他人截获,Bob 也不会有任何经济损失。

总结

针对支付 BSV 时可能出现的收款方代付交易矿工费的场景,本文给出了两种切实可行的解决方案,它们各有优劣,并且工程实现都不复杂,欢迎留言。😊

参考