比特币开发指南——交易支付

96
通若
2017.11.28 11:16 字数 6945

支付过程包括消费者和收钱者为了交换服务或产品发起和接受支付。自商业开始以来,步骤从未改变。但是技术在不断变化。本章将解释消费者和收钱者怎么使用比特币发起和请求支付——以及如何处理退款和重复消费的问题。


image.png

上面的图总结了新订单开始,从接收者角度使用比特币的支付过程。下面的子章节将分别介绍这三个基本的步骤和三个可选的步骤。

值得注意的是这些步骤的每一个都能通过第三方API和服务查到。

商品价格

因为聪和国际货币(法定货币)之间的汇率变化,许多比特币订单以法币定价但是用聪支付,所以需要价格转换。

汇率数据可以通过货币兑换处提供的基于HTTP的API获得。一些组织还汇总了来自多个交易所的数据以便创建指数价格,这些数据使用基于HTTP的API也可以获取到。

任何使用汇率数据自动计算交易总额的应用必须采取措施确保引用的价格反映了当前聪的一般市场价值,或者应用能够接受产品或服务只售出了非常少的聪。或者他们可以要求非常多的聪,赶走潜在的消费者。

为了问题最小化,应用可以从至少两个独立的源头收集数据并比较他们的差值。如果差值太大,应用可以进入安全模式直到人能够评估环境。

如果汇率剧增或骤降,你或许想要应用进入安全模式。汇率的变化反应了比特币市场出现了问题,导致了今天很难花费出收到的聪。

汇率不受比特币和相关技术的控制,所以没有技术能够使得程序正确地把法定货币转换成聪。

因为汇率随着时间波动,锚定到法定货币的交易总额必须防止消费者怀着聪将会降价的希望推迟支付。最广泛使用的付款处理系统在10到20分钟后终止发票。

更短的截止周期增加了接收到付款之前截止发票的机会,可能需要手动干预请求额外的支付或退款。更长的截止周期增加了接收到支付以前汇率大幅波动的机会。

请求支付

在请求支付之前,应用必须创建一个比特币地址,或者从另一个程序如比特币核心请求一个地址。在交易章节已详细描述过比特币地址。正如描述过的避免复用地址的两个重要的原因——第三种原因尤其应用到支付请求中。

针对每笔收入付款使用一个独立的地址,使得决定哪个消费者支付了他们的付款请求变得微不足道。应用只需要跟踪一个特定的支付请求和使用的地址,然后扫描区块链查找匹配这些地址的交易。

下一子章节将详细描述将地址和数量发给花费者的四种兼容方式。为了加强便利和兼容性,建议在付款请求中提供所有选项。

  1. 所有的钱包软件都让用户粘贴或手动输入地址和数量到付款屏幕中。这当然非常不方便——但它是一个有效的后备选择。

  2. 几乎所有的桌面软件都能联合使用bitcoin: URI,所以花费者可以点击链接到预填充付款界面。许多移动钱包也是这样工作,但是对于基于Web的钱包来说是无效的,除非花费者按照浏览器扩展或手动配置URI处理器。

  3. 大部分移动钱包支持浏览被编码到二维码中的bitcoin:URI,而且几乎所有钱包都能展示它们用于收款。而且对于线上交易也很方便,二维码对个人商户尤其有用。

  4. 近期的钱包更新增加了对新支付协议的支持,提高了安全性,接收者使用X.509数字证书认证身份,而且另一个重要的特性就是退款。

必须对收入付款盗窃高度关注。尤其是,私钥不应保存到Web服务器,而且支付请求应该以HTTPS或其他的安全手段发送,避免中间人攻击使用攻击者的地址代替你的地址。

纯文本

为了指定要直接复制或粘贴的数量,必须提供地址、数量和面额。交易的有效时间也要指定。例如:

Pay: mjSk1Ny9spzU2fouzYgLqGUD8U41iR35QN
Amount: 100 BTC
You must pay by: 2014-04-01 at 23:00 UTC

表明面额是很关键的,从这篇文章起,流行的比特币钱包软件默认以BTC、毫BTC或微BTC微单位。也支持单位选择,但是其他的软件也让用户从下面的一些或全部选项中选择面额数量。


image.png

bitcoin:URI

在BIP21中定义的bitcoin:URI方案消除了面额困惑,节省了花费者复制和粘贴两个独立的值。也让支付请求给花费者提供一些额外的信息。例子如下:

bitcoin:mjSk1Ny9spzU2fouzYgLqGUD8U41iR35QN?amount=100

只要求地址,如果地址是唯一要求指定的,钱包将使用它预填充一个支付请求并让花费者输入数量。总是以十进制的比特币(BTC)指定数量。

另外两个参数也被广泛支持。label参数一般用于和收件人名称一起提供钱包软件。message参数一般用于描述花费者的付款请求。label和message都是保存在花费者的钱包软件中——但是都没添加到实际的交易中,所以其他的比特币用户看不到它。label和message都必须被URI编码。

四个参数一起使用,使用相应的URI编码,如下例所示:

bitcoin:mjSk1Ny9spzU2fouzYgLqGUD8U41iR35QN\
?amount=0.10\
&label=Example+Merchant\
&message=Order+of+flowers+%26+chocolates

URI方案可被扩展,正如下面付款协议章节将会看到的一样,同时使用新的选项和要求的参数。截止本文更新之日,除了四个上面描述的参数之外,唯一广泛使用的就是付款协议的r参数。

在支付之前,程序以任意形式接受URI必须请求用户的许可,除非用户明确禁用提示(微型支付或许如此)

二维码

二维码是一种很流行的替换bitcoin:的方式,大部分移动比特币钱包app和一些桌面钱包,都支持扫描二维码预填充到支付界面。

下面的表格展示了相同的bitcoin:URI码以四种不同的错误校正级别,被编码成四种不同的比特币二维码。二维码可以包括labelmessage参数——和任意其他的参数——但是为了保持二维码足够小而且容易被不稳定或分辨率较低的移动摄像机扫描,他们都被省略了。

image.png

错误纠正使用校验和确保比特币二维码无法被解码,由于数据丢失或意外改变,所以应用应当基于可使用用于展示二维码的空间选择相应的错误校正级别。当空间被限制时,低级别的破坏校正工作非常好,四分级别破坏校正帮助确保在高分辨率屏幕上快速扫描。

支付协议

比特币核心0.9支持新的支付协议。支付协议在支付请求中添加了许多重要的特性:

  1. 支持X.509认证和SSL加密验证接收者的身份和帮助防止中间人攻击。
  2. 给花费者提供更详细的关于请求付款的信息
  3. 允许花费者直接提交交易给接收者,不用经过P2P网络。可以加快支付处理,并使用计划的功能如孩子支付给家长交易费和线下NFC或基于蓝牙的支付。

代替被询问支付给一个无效的地址,例如“mjSk1Ny9spzU2fouzYgLqGUD8U41iR35QN”,花费者被要求支付接收者的X.509证书中的通用名,例如www.bitcoin.org

为了使用支付协议请求支付,使用给一个扩展的(但是向后兼容)bitcoin:URI.例如:

bitcoin:mjSk1Ny9spzU2fouzYgLqGUD8U41iR35QN\
?amount=0.10\
&label=Example+Merchant\
&message=Order+of+flowers+%26+chocolates\
&r=https://example.com/pay/mjSk1Ny9spzU2fouzYgLqGUD8U41iR35QN

上面提供的参数除了r之外,并不被支付协议强制要求——但是应用或许为了向后兼容把他们加到尚未处理支付协议的钱包程序上。
r参数告诉支付协议识别钱包程序忽略其他的参数,从URL捕获支付请求。浏览器,二维码阅读器、或其他的程序处理URI打开花费者的比特币钱包程序。

image.png

支付协议在BIP70、BIP71、BIP72中描述。一个例子CGI程序和可能在支付协议中使用的所有参数的描述都在开发者例子支付协议子段落里提供。在这个子章节,我们将简单地以故事的形式描述支付协议是如何典型地被使用的。

查理——客户端,在一个被Bob运行的网站上购物。查理添加商品到购物篮并点击“使用比特币结账”按钮。

Bob的服务器自动添加下列信息到发票数据库中:

  1. 查理订单详情,包括商品顺序和购物地址
  2. 以聪计算的订单总额,可能由法币转换到聪创建
  3. 交易截止时间
  4. 查理应该发送付款的公钥脚本。典型的是P2PKH或P2SH公钥脚本,包含一个唯一的secp256k1 公钥

添加所有信息到数据库后,Bob的服务器展示给查理一个bitcoin:URI点击支付。

查理点击在浏览器中点击bitcoin:URI。他的服务器URI处理器发送URI到他的钱包程序。钱包识别支付协议,所以解析r参数并发送HTTP GET到URL查询一个支付请求信息。

返回的支付请求信息可能包括私有信息,例如查理的邮寄地址,但是钱包必须能够访问而不用使用有限的认证,例如HTTP cookies,所以一个公开访问的HTTPS URL是典型地被使用。为支付请求创建的唯一的公钥可用于创建一个唯一标识符。这是为什么在上面的URI例子中,支付请求URL包含P2PKH 地址。

上面的例子中,URL接收到HTTP GET请求之后,Bob的网页服务器上的支付请求生成CGI程序利用URL中的唯一标识符,并查询数据库中的相应细节。然后使用下面的信息创建一个支付细节信息:

  1. 要支付的钱数和公钥脚本(地址)
  2. 包含商品列表的备忘录,所以查理知道为何而付款。或许包括查理的邮寄地址,所以他可以对之双重校验
  3. 支付详细信息被创建的时间和有效时间
  4. 查理钱包应该发送以完成交易的URL

支付详情信息被放到支付请求信息中。支付请求要求Bob的服务器使用X.509 SSL整数签署请求。(支付协议被设计成允许将来的其他签名方法)Bob的服务器发送支付请求到查理的钱包,在HTTP GET响应之后。


image.png

查理的钱包接受到支付请求信息,校验签名,然后展示支付详情信息给查理。查理同意支付,所以钱包构建支付给Bob的服务器创建的公钥脚本。不像额外的比特币支付,查理的钱包不一定自动广播该付款到网络中。相反,钱包构建付款信息并发送到支付详情信息提供的作为HTTP POST使用的URL中。在其他的事物中,支付信息包含:

  • 查理支付给Bob的签名了的交易
  • 查理发送给Bob的额外的备忘录(无法保证Bob将会阅读它)
  • 退款地址(公钥脚本),Bob如果需要返回给查理一些或全部的聪,支付的地址

Bob的服务器接收支付信息,验证支付特定数量给被提供地址的交易,然后广播交易到网络中。它也使用支付确认信息作为HTTP POST付款信息的响应,支付确认信息包括一个源于Bob服务器的可选的被网络,处于感谢查理对他的支持和提供关于交易的其他信息,例如预期抵达时间。

查理的钱包看到支付确认旧告诉查理支付已被发送。支付确认并不意味着Bob已经验证了查理的支付——看下面的验证支付子章节——但是意味着查理能做一些其它的事当交易确认的时候。Bob的服务器从区块链中验证了查理的交易已经被适度确认了之后,授权运送查理的订单。

在纠纷情况下,在几种签名或其他验证信息之外,查理可以生成一个密码验证收据

  • Bob的网页服务器签名的支付详情信息证明查理接收到一个发票——为了备忘录中指定的商品,支付给特定的公钥脚本特定数量的聪。

  • 比特币区块链能证明Bob指定的公钥脚本是被特定数量的聪支付。

如果需要处理退款,Bob的服务器可以安全的支付给查理提供的退款公钥脚本。更多详情请看下面的退款章节。

验证支付

正如在交易和区块链章节所解释的,广播交易到网络中并不确保接收者会被支付。恶意的花费者可以创建一笔支付给接收者的交易和一个把相同的输入返回给自己的交易。这些交易只有一个会被添加到区块链中,而没人能确保会是哪一个。两个或多个交易花费相同的输入叫做双花。

一旦交易被加入到区块中,双花就不可能了,除非修改区块链交易记录替换该交易,但是这非常困难。使用该系统,基于替换交易需要修改的区块数量,比特币协议可以给每笔交易一个不断更新的信心分数。对于每个区块链,交易获得一个确认。因为修改区块相当困,更高的确认分数表明更大的保护。

0确认:交易已被广播但仍未加入到任何区块中。0确认交易(未被确认交易)在没有风险分析的情况下,一般不应相信。虽然矿工通常确认接收到的第一笔交易,骗子有可能操纵网络添加他们自己版本的交易。

1确认:交易被加入到最新的区块中而且双花风险被戏剧性的降低。支付足够交易费用的交易一般需要10分钟接收确认。然而,最新的区块仍有可能被替换,所以双花仍然具有可能性。

2确认:最新的区块被链加到包含交易的区块上。从2014年5月起,双区块替换是极度稀少的,而且双区块替换攻击没有昂贵的挖矿设备是不切实际的。

6确认:网络花费了1个小时左右保护交易免遭双花,而且交易被埋到留个区块下面。
一个合理的幸运的攻击者可能获取网络中的大部分算力替换六个区块。虽然数量有点随意,软件处理高值交易,应该等待至少6个确认在视作交易为已接受之前。

比特币核心提供几种RPC,可以提供钱包中交易或任意交易的确认分。例如,listunspentRPC 提供可花费的聪的列表和确认分。

虽然确认大部分时间里提供优秀的双花保护,至少三种情况下需要双花风险分析:

  1. 程序或用户不能等待确认而想要接受未确认的支付的情况下
  2. 程序或用户正在接受高值交易而且不能等到至少6个或更多确认的情况下
  3. 实现的bug或者持续攻击比特币,使得系统比预期的更欠可靠性。

一个有趣的双花风险分析根源可以通过连接到大量的比特币节点跟踪交易和区块如何不同于其他的交易和区块得到。一些第三方的API可以提供这类服务。

例如,未确认的交易可以在所有连接的节点间比较,如果UTXO是被用到多笔未确认交易中,表明存在双花尝试,这种情况下支付可被拒绝直到确认。交易可按照交易费用排列评估被加入到区块中的时间。

另一个例子可能检测到分叉,当多个节点在相同的区块高度报告不同的区块头部hash值时,如果分叉扩展到超过两个区块,程序会进入安全模式,表明区块链可能出现了问题。更多细节,请看监测分支子章节。

另一个双花保护的来源就是人类的智力。例如,恶意者可能和合法的消费者行为不同,让见多识广的商人把他们标上高危标签。程序可以提供安全模式,阻止全球或个人消费者的自动支付可接受性。

办理退款

偶尔使用应用的接收者需要退款。有种很明显方式就是简单地把聪返回到公钥脚本,但是这是很不安全的。例如:

  • Alice想从Bob那里购买一个装饰品,所以Bob把价格和比特币地址发给Alice
  • Alice打开她的钱包程序并发送一些聪到该地址。她的钱包程序自动从UTXO中选择花费这些聪,一个输出对应到比特币地址mjSk1Ny9spzU2fouzYgLqGUD8U41iR35QN.
  • Bob发现Alice支付了太多的聪,是一个诚实的伙伴,Bob把多余的聪退到mjSK...地址。

看起来似乎没问题,但是Alice使用了一个集中式多用户网页钱包,并没有给每个用户一个唯一的地址,所以无法知道Bob的退款是属于Alice的。现在退款相当于是无意捐赠给集中式钱包背后的公司,除非Alice打开一个支持票并证明这些聪是属于她的。

这使得接收者只有两种正确的方式发起退款:

  • 如果使用的地址时复制和粘贴或一个基础的bitcoin:URI,直接联系花费者并让他们提供一个退款地址
  • 如果使用了支付协议,发送退款到支付信息中的refund_to字段列举的输出。

注:如果退款在交易之后拖延了很长时间,直接联系花费者是个不错的想法。允许你确保用户仍然能够访问refund_to地址的秘钥或秘钥对

支付收入(限制外汇风险)

许多接收者担心将来聪会贬值,叫做外汇风险。为了限制外汇风险,许多接收者选择支付最新要求的付款在收到之后。

如果应用提供业务逻辑,需要选择首先花费哪笔输出。这有几种可能导致不同结果的算法。

  • 合并无效算法使得外人很难通过看区块链数据计算出接收者挣、花费和保存了多少聪。
  • 后进先出算法花费最新获取的聪,虽然仍然存在双花风险,可能会把风险推向别人。这对于接收者的余额流动可能是好的,但是对他们的名声有坏的影响。
  • 先进先出算法首先花费最早的聪,会帮助确保接收者的付款总被确认,虽然这只适用于一些边缘情况。

当接收者在输出中接收到聪,花费者可以跟踪(以一种简陋的方式)接收者如何花费这些聪。但是花费者无法自动看到其他的花费者支付给接收者的聪,只要接收者在每笔交易都使用一个唯一的地址。

然而,如果接收者在一笔交易中花费来自两个不同花费者的聪,这两个花费者任意一个都能看到对方的支付。这叫做合并,接受者合并越多的输出,外人也就更容易跟踪接受者赚、花费和保存了多少聪。

合并空缺意味着尽量避免在同一笔交易中花费不相干的输出。对于那些想要保持交易数据隐私的个人和商人,是一个非常重要策略。

一个简单的合并空缺策略是使用比要支付的数量大的最小的输出。例如,如果有四个输出,分别是100、200、和900聪,将使用500聪输出支付300聪。也就是说,只要有比账单大的输出,就应避免合并。

更多现金的合并空缺策略极大地依赖于增强支付协议,该协议允许支付者避免合并,通过在接收者提供的多个输出中智力分发他们的付款。

后进,先出(LIFO)

只要接收到输出就能花费——甚至尚未确认。因为最新的输出处于极大地双花风险中,在旧的输出前花费它们使得花费者可以继续持有更少成为双花的确定了的交易。

后进先出有两个紧密相连的缺点:

  • 如果在第二笔交易中花费一笔未确认交易的输出,第二笔交易将变得无效如果交易延展性改变了第一笔交易。
  • 如果在第二笔交易花费了来自未确认交易的输出,而且第一笔交易的输出成功的双花给了另一笔输出,第二笔交易将无效。

上面的任一情况中,第二笔交易的接收者将看到收入交易提示消失或变成错误信息。

因为后进先出把第二笔交易的接收者置于和第一笔交易接收者相同的双花风险中,当第二个接收者不关心风险——例如交互或其他的服务将要等到六个确认,最好使用它们,不管是否花费了旧的输出或新的输出。

当主交易接收者的名声濒临危境时,后进先出不应使用,例如当支付给员工。这些情况下,在使用它们做支付之前最好等到交易完全验证。

先进先出(FIFO)

旧的输出时最可靠的,接收至今时间越长,双花需要修改的区块数量越多。然而,在几个区块之后,就会迅速递减到某一个点。中本聪白皮书预测攻击者能够修改旧区块的可能性,假设攻击者有全网的30%算力:

image.png

对于交易费用这块,先入先出具有些微优势,旧的输出可能有资格放到预留的5000个字节中,该字节主要针对免费、高优先级的交易。然而,因为交易费很低,所以不是一个非常有意义的优势。

先进先出唯一的实际用处是在几个区块中花费所有或大部分收入,以及想要减少支付意外无效的几率。例如,一个持有每笔交易六个确认的接收者,花费100%验证过的交易给卖主和按时计算的储蓄账户。

重复支付

对于去中心化的比特币钱包来说,自动重复支付是不可能的。虽然钱包支持自动化定期发送不可逆的交易,用户仍需要在特定时间启动程序,或使之在未被加密保护的期间一直运行 。

这意味着自动重复花费只可能出现在集中服务器上,该服务器站在花费者的角度处理聪。实际上,想要以法币设定价格的接收者必须让相同的集中式服务器选择相应的兑换率。

非自动化重复支付可被相同的机制管理,该机制在之间的信用卡重复支付中使用:联系花费者并让他们重复支付——例如,给他们发送一个包含支付请求bitcoin:URI的HTML邮件。

在将来,支付协议的扩展和新钱包特性或许允许一些钱包程序管理重复支付交易列表,花费者将仍需要在固定的基础上启动程序和认证支付——但是可能比点击邮寄的法币更容易和安全,增加了接收者及时被支付的可能性。

随想录
Web note ad 1