比特币开发者指南(8)--支付流程

支付流程

支付流程包括消费者和接收者为了交换产品或服务而做出和接受付款的步骤。从商业启蒙开始,基本步骤并没有改变,但技术在改变。本节将介绍接收者和消费者如何分别使用比特币来请求和付款,以及如何处理诸如退款和循环付费等复杂情况。
比特币开发者指南(8)--支付流程
Bitcoin Payment Processing

上图显示了从接收者的角度来看,使用比特币进行支付处理,从新订单开始。以下小节将分别介绍三个常见步骤和三个偶然或可选步骤。

值得一提的是,每个步骤都可以通过使用第三方API和服务进行外包。

价格订单

由于satoshis与本国货币(fiat)之间的汇率变动性,许多Bitcoin订单的价格为fiat,但在satoshis ,需要进行价格转换。

汇率数据可以通过货币兑换提供的广泛使用的基于HTTP的API得到。几个组织还聚合来自多个兑换机构的数据,以创建索引价格,也可以使用基于HTTP的API。

任何使用汇率数据自动计算订单总额的应用程序必须采取措施确保报价的价格反映了目前satoshis的一般市值,或者应用程序对于正在销售的产品或服务可以接受太少的satoshis。或者,他们可以要求更多的satoshis,吓跑潜在的消费者。

为了确保问题最小化,您的应用程序可能希望从至少两个独立的源收集数据,并将其进行比较,以查看它们有多大差异。如果差异很大,您的应用程序可以进入安全模式,直到人们能够评估情况。

如果汇率正在迅速增加或下降,您可能还希望对您的应用程序进行编程,以进入安全模式,这表明在比特币市场可能会出现问题,这可能使得今天难以支付任何satoshis。

汇率不在Bitcoin和相关技术的控制范围之内,因此没有新的或计划中的技术使您的程序更容易将订单总数从fiat转换为satoshis。

由于汇率随时间而波动,与fiat挂钩的订单总额必须有过期时间,以防止消费者拖延付款来希望satoshis将降价。最广泛使用的支付处理系统目前在10到20分钟之后到期。

较短的到期期限会增加发票在收到付款之前到期的机会,可能需要手动干预以要求额外付款或发起退款。更长的到期期限增加汇款在收到付款之前显著波动的机会。

要求付款

在请求付款之前,您的应用程序必须创建比特币地址,或从另一个程序(如Bitcoin Core)获取地址。比特币地址在交易部分中有详细描述。在该部分中也描述了避免多次使用同一个地址的两个重要原因,但第三个原因特别适用于支付请求:

对于每个收到的付款,使用一个单独的地址使得确定哪些客户已经支付了他们的支付请求是不重要的。您的应用程序只需跟踪特定的支付请求和其中使用的地址之间的关联,然后扫描块链以获得匹配的交易的地址。

接下来的小节将详细描述以下四种兼容方式,以便提供给花费者地址并支付金额。为了提高方便性和兼容性,建议您在付款请求中提供所有这些选项。

  1. 所有钱包软件允许用户粘贴或手动输入地址,并将其纳入付款屏幕。这当然是不方便的 - 但是它有有效的回退选项。
  2. 几乎所有桌面钱包可以与比特币:URIs关联,所以消费者可以点击链接预先填写付款屏幕。这也适用于许多移动钱包,但是通常不支持基于Web的钱包,除非消费者安装浏览器扩展或手动配置URI处理程序。
  3. 大多数移动钱包支持以QR码编码的扫描比特币:URI,几乎所有钱包可以显示它们接受付款。虽然在线订单方便,QR码对于个人购买特别有用。
  4. 最近的钱包更新支持新的支付协议,提供更高的安全性,使用X.509证书对接收者的身份进行身份验证,以及其他重要功能例如退款。
Warning icon 警告:必须特别注意避免收到的付款被盗。特别地,私钥不应存储在Web服务器上,支付请求应通过HTTPS或其他安全方法发送,以防止中间人攻击使用攻击者的地址替换比特币地址。

纯文本

要直接指定用于复制和粘贴的金额,您必须提供地址,金额和面额。也可以指定要约的到期时间。例如:

(注:本节中的所有示例都使用testnet 地址)
比特币开发者指南(8)--支付流程
指示面额至关重要。在撰写本文时,流行的比特币钱包软件默认为比特币(BTC),毫比特币(mBTC)或微比特币(uBTC,“bits”)。广泛支持每个单位之间的选择,但是其他软件也可以让用户从以下部分或全部选项中选择面额:
比特币开发者指南(8)--支付流程

比特币:URI

在BIP21中定义的比特币: URI方案消除了面额混淆,使消费者免于复制和粘贴两个单独的值。它还允许支付请求向消费者提供一些附加信息。一个例子:

比特币开发者指南(8)--支付流程
只有地址是必需的,如果它是唯一指定的,钱包将预先填写付款请求,然后让付款人输入金额指定的数量始终为十进制比特币(BTC)。

其他两个参数得到了广泛的支持。label参数通常用于将收款人的姓名提供给钱包软件。message参数通常用于描述花费者的支付请求。标签和消息通常由销售商的钱包软件存储,但是它们不会添加到实际的交易中,因此其他Bitcoin用户看不到它们。标签和消息都必须是URI编码的。

所有四个参数一起使用,具有适当的URI编码,可以在下面的换行示例中看到。
比特币开发者指南(8)--支付流程
可以扩展URI方案,如下面的支付协议部分所示,同时包含新的可选参数和必需的参数。在撰写本文时,除了上述四个之外,唯一广泛使用的参数是支付协议 r参数。

接受任何形式的URI的程序必须在付款之前要求用户获得许可,除非用户明确禁用了提示(对于支付小额支付可能是这样)。

QR码

QR码是个人,图像或视频中交换比特币:URIs的流行方式。大多数移动Bitcoin 钱包应用程序和一些桌面钱包,支持扫描QR码预先填写他们的付款屏幕。

下图显示了在四个不同的纠错水平下,编码为四种不同的比特币QR码的相同的比特币:URI。QR码可以包括label和message参数和任何其他可选参数 - 但是在这里省略了可选参数以便使QR码小,易于不稳定或低分辨率的移动摄像头扫描。
比特币开发者指南(8)--支付流程
Bitcoin QR Codes

错误校正与校验和相结合,以确保比特币QR码在数据丢失或意外更改时无法成功解码,因此您的应用程序应根据您可用的空间选择适当的纠错级别显示QR码。当空间有限时,低级别的损坏修正功能很好,四分位数的损坏修正有助于确保在高分辨率屏幕上显示时快速扫描。

付款协议

Bitcoin Core 0.9支持新的支付协议。付款协议为付款请求添加了许多重要功能:
  • 支持X.509证书和SSL加密,以验证接收者的身份,并帮助防止中间人攻击。
  • 提供有关所需支付的更多细节给消费者。
  • 允许消费者直接向接收者提交交易,而无需通过P2P网络。这样可以加快付款处理速度,并使用计划功能(如child-pays-for-parent交易费用)和离线NFC或基于蓝牙的付款。
诸如“mjSk1Ny9spzU2fouzYgLqGUD8U41iR35QN”的无意义的地址而不被要求,但要求消费者提供从接收方的X.509证书中支付公用名称(CN)描述,如“www.bitcoin.org”。

要使用支付协议请求付款,您可以使用扩展(但向后兼容)比特币: URI。例如:
比特币开发者指南(8)--支付流程
除了r之外,上述提供的参数都不是支付协议所必需的,但您的应用程序可能会包含它们与钱包程序的向后兼容性其尚未处理支付协议。

r参数指示支付协议感知钱包程序忽略其他参数,并从提供的URL中获取一个PaymentRequest。浏览器,QR码阅读器或处理URI的其他程序打开URI上的花费者Bitcoin 钱包程序。
比特币开发者指南(8)--支付流程
BIP70 Payment Protocol

在BIP70,BIP71和BIP72中深入描述了付款协议。开发者示例付款协议子节中提供了一个示例CGI程序和可在付款协议中使用的所有参数的描述。在本小节中,我们将以故事形式简要介绍如何通常使用付款协议。

Charlie客户,正在购买由Bob商人运营的网站。查理在购物车中添加了几个物品,并点击了“用比特币结帐”按钮。

Bob的服务器会自动将以下信息添加到其发票数据库中:
  • 查理订单的细节,包括订购和运送的商品地址。
  • satoshis中的订单总数,可能是通过将fiat中的价格转换为satoshis中的价格而创建的。
  • 该总计将不再可接受的到期时间。
  • Charlie应向其发送付款的pubkey脚本。通常这将是一个包含一个唯一的(从未使用过的)secp256k1公钥的P2PKH或者P2SH pubkey脚本。
在将所有信息添加到数据库之后,Bob的服务器显示Charlie的比特币: URI以点击付款。

查理点击浏览器中的比特币:URI。他的浏览器的URI处理程序将URI发送到他的钱包程序。钱包知道付款协议,因此它解析了r参数,并向该URL发送一个HTTP GET,查找一个PaymentRequest消息。

返回的PaymentRequest消息可能包括私人信息,例如Charlie的邮件地址,但是钱包必须能够访问它而不使用先前的身份验证,例如HTTP Cookie,因此通常使用具有防猜测部件的可公开访问的HTTPS URL。为支付请求创建的唯一公钥可用于创建唯一标识符。这就是为什么在上面的示例URI中,PaymentRequest URL包含P2PKH地址:https://example.com/pay/mjSk1Ny9spzU2fouzYgLqGUD8U41iR35QN

在收到HTTP GET到上面的URL之后,Bob的Web服务器上的PaymentRequest生成CGI程序从URL获取唯一的标识符,并在数据库中查找相应的详细信息。然后,使用以下信息创建一个PaymentDetails消息:
  • satoshis和pubkey脚本中的订单金额将被支付。
  • 一个包含订购商品列表的备忘录,所以查理知道他付的是什么。它也可能包括查理邮寄地址,所以他可以仔细检查。
  • PaymentDetails消息的创建时间加上它到期的时间。
  • Charlie的钱包应发送完成的交易的网址。

PaymentDetails消息放在PaymentRequest消息中。支付请求允许Bob的服务器使用服务器的X.509 SSL证书签署整个请求。(付款协议旨在允许将来允许其他签名方式。)Bob的服务器在向HTTP GET的回复中发送付款请求到Charlie的钱包。
比特币开发者指南(8)--支付流程
Bitcoin Core Showing Validated Payment Request

Charlie的钱包收到PaymentRequest消息,检查其签名,然后从PaymentDetails消息中显示详细信息给Charlie 。Charlie同意支付,所以钱包构造了一个付款给pubkey脚本提供的Bob的服务器。与传统的比特币支付不同,Charlie的钱包不一定会自动将此付款广播到网络。相反,钱包构造一个付款消息,并将其作为HTTP POST发送到PaymentDetails消息中提供的URL。其中包括:付款信息包含:
  • Charlie支付Bob的签名交易。
  • 可选备忘录Charlie可以发送给Bob。(不能保证Bob会读它。)
  • 如果他需要返回Charlie的satoshis中的一些或全部,那么Bob可以支付的退款 地址(pubkey脚本) 。
Bob的服务器接收到付款消息,验证交易是否向所提供的地址支付请求的金额,然后将交易广播到网络。它还使用PaymentACK消息回复HTTP POSTed Payment消息,其中包括Bob的服务器的可选备忘录,感谢Charlie的赞助,并提供有关订单的其他信息,如预计到达日期。

Charlie的钱包看到了PaymentACK,并通知Charlie付款已发送。PaymentACK并不意味着Bob已经验证了Charlie的付款 - 请参阅下面的验证付款部分,但这意味着Charlie可以在交易获得确认时执行其他操作。在Bob的服务器从块链中验证Charlie的事务已经被确认之后,它授权运送Charlie的订单。

在出现争议的情况下,Charlie可以从各种签名或其他证明的信息中生成经密码证明的收据。
  • Bob的网络服务器签名的PaymentDetails消息证明,Charlie收到了一个发票,用于为指定的satoshis指定的公钥脚本备忘录字段。
  • 比特币块链可以证明由Bob指定的pubkey脚本支付指定数量的satoshis。
如果需要发出退款,Bob的服务器可以安全地支付Charlie提供的退款 -to pubkey脚本。有关详细信息,请参阅下面的退款部分。

验证付款

如交易和块链部分所述,将交易广播到网络不能确保接收方得到报酬。一个恶意的支出者可以创建一个支付收款人的交易,另一个交易支付相同的输入回到自己。只有其中一个交易将被添加到块链,没有人可以肯定地说明它将是哪一个。

花费相同输入的两个或多个交易通常被称为双重支出。

一旦交易被包含在块中,双重支出是不可能的,而不修改块链历史来替换交易,这是相当困难的。使用该系统,Bitcoin协议可以根据需要修改以替换交易的的数量,为每个交易提供更新置信度。对于每个块,交易获得一个确认。由于修改块是相当困难的,所以较高的确认得分表示更大的保护。
  • 0 确认:交易已被广播,但仍未包含在任何块中。一般情况下,零价值确认的交易(未经确认的交易)一律不受信任。虽然矿工通常确认他们收到的第一个交易,但欺诈者可能可以操纵网络来包括其交易版本。
  • 1 确认:交易被包含在最新的块中,双重花费风险急剧下降。支付足够的交易费用的交易平均需要10分钟才能收到确认。然而,最近的块被意外地更换,所以双重支出仍然是一个真正的可能性。
  • 2 确认:最近的块链接到包含交易的块。截至2014年3月,两个块替换是非常罕见的,并且两个块替换攻击是不切实际的,没有昂贵的采矿设备。
  • 6 确认:网络花了大约一个小时的时间来保护交易,避免了双重支出,交易是埋在六块之下。即使是一个相当幸运的攻击者也需要大量的网络哈希功率代替六个块。虽然这个数字有些随意,但处理高价值交易的软件或以其他方式具有欺诈风险的软件,在等待接受付款之前,应至少等待六次确认。
Bitcoin Core提供了几个RPC,可以为您的程序提供钱包中的交易或任意交易的确认分数。例如,listunspent RPC提供了您可以与确认分数一起使用的每个satoshi的数组。

尽管确认大部分时间都提供了优秀的双重支出保护,但至少有三种情况需要双重支出风险分析:

  1. 在程序或其用户无法等待确认并希望接受未确认付款的情况下。
  2. 在程序或其用户接受高价值交易并且不能等待至少六个确认或更多的情况下。
  3. 在实施bug或长时间攻击Bitcoin的情况下,使系统的可靠性低于预期。
双重花费风险分析的有趣来源可以通过连接大量的比特币对等体获取,以跟踪交易和块与每个其他。一些第三方API可以为您提供这种类型的服务。

例如,可以在所有连接的节点中比较未确认的交易,以查看在多个未确认的交易中是否使用任何UTXO,表示双重花费尝试,在这种情况下,支付可以拒绝,直到确认。交易也可以通过他们的交易费用进行排名,以估计它们添加到块之前的时间。

另一个例子可能是当多个对等体在相同块高度之间报告不同的块头散列时,检测fork。如果fork扩展了两个以上的块,则程序可以进入安全模式,表示块链可能出现问题。有关详细信息,请参阅检测叉子小节。

双重支持保护的另一个好的来源可以是人类智慧。例如,欺诈者可能与合法客户的行为不同,让精明的商家手动将其标记为高风险。您的程序可以提供安全模式,可以在全球或每个客户的基础上停止自动付款验收。

发起退款

偶尔使用您的应用程序的接收者将需要发出退款。这样做非常不安全的明显方法是将satoshis返回到他们来的pubkey脚本。例如:
  • Alice想从鲍勃购买一个小部件,所以Bob给Alice一个价钱,比特币地址。
  • Alice打开钱包程序,并向地址发送一些satoshis。她的钱包程序自动选择从其未使用的输出中的一个satoshis,相应于比特币的输出 地址 mjSk1Ny9spzU2fouzYgLqGUD8U41iR35QN。
  • Bob发现Alice支付太多satoshis。作为一个诚实的家伙,Bob 将额外的satoshis退回给mjSk ... 地址。
这似乎应该起作用,但是Alice正在使用一个集中的多用户网络钱包,它不向每个用户提供唯一地址,所以没有办法知道Bob的退款适用于Alice。现在,退款是对集中的钱包背后的公司的无意捐赠,除非Alice打开支持票,并证明那些satoshis是为她。

这使得接收方只有两种正确的方式来发布退款:
  • 如果使用了地址,或者使用基本的比特币: URI,请直接与投寄人联系,要求他们提供退款 地址。
  • 如果使用支付协议,请将退款发送到付款信息的refund_to字段中列出的输出 。
注意:如果退款在原始付款完成后很长时间才会直接与投寄人联系是明智的。这允许您确保用户仍然可以访问refund_to 地址的键或键。

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

许多接收者担心,他们的satoshis将在未来比现在更少的价值,称为外汇(外汇)风险。为了限制外汇风险,许多接收方选择在收到新的收款后立即支付新收购的付款。

如果您的应用程序提供此业务逻辑,则需要首先选择输出。有几种不同的算法可以导致不同的结果。
  • 一个合并回避算法使得外部人员看到块链数据变得更难以确定接收方获得,花费和保存了多少satoshis 。
  • 最先进先出(LIFO)算法花费新获得的satoshis,而仍然有双重支出风险,可能会将风险推向别人。这可能对接收者的资产负债表有好处,但可能对他们的声誉不利。
  • 先入先出(FIFO)算法首先使用最早的satoshis,这有助于确保接收者的付款总是确认,尽管这只能在几个边缘情况下实现。

合并回避

当接收器在输出中接收到satoshis时,花费者可以跟踪(以粗略的方式)接收机如何花费那些satoshis。但是,只要接收方为每个事务使用唯一地址,花费者就不能自动查看其他消费者向接收方支付的其他satoshis。

然而,如果接收方在同一个交易中从两个不同的消费者那里花费了satoshis,则这些消费者中的每一个都可以看到另一个付款人的付款。这被称为合并,接收器合并输出越多,外部人员越容易跟踪接收机具有多少satoshis赚取,消耗和保存。

合并回避表示试图避免在相同的事务中花费不相关的输出。对于想要将交易数据保密的人和企业,可能是一个重要的策略。

粗略的合并回避策略是尝试始终以最小的输出来支付您所要求的数量。例如,如果您有四个输出保持,分别为100,200,500和900 satoshis,则您将支付300 satoshis t2 > 500- satoshi 输出。这样,只要您的输出比您的帐单大,您可以避免合并。

更高级的合并回避策略在很大程度上取决于支付协议的增强,这将允许付款人通过智能地在多个输出之间分配付款来合并由接收者。

后进先出(LIFO)

输出即使在确认之前也可以一次收到。由于最近的输出是双重的最大风险,将它们花在较旧的输出之前,可以让花费者保持较旧的 输出,这些不太可能是双重。

LIFO有两个紧密相关的缺点:
  • 如果在第二个事务中从一个未确认的事务中输入输出,则如果事务可扩展性更改了第一个事务,则第二个事务将变为无效。
  • 如果在第二个事务中从一个未确认事务中输入输出,并且第一个事务的输出成功双用了到另一个输出,第二个事务变得无效。
在上述任何一种情况下,第二个事务的接收者将看到传入的事务通知消失或变成错误消息。

由于LIFO将次要交易的收件人作为主要交易的收件人,将双重支出风险作为收款人,因此在次级收件人不关心风险时最佳使用,例如交换或其他将要等待六个确认的服务,无论您是否使用旧的输出或新的输出。

主要交易受益人的声誉可能受到威胁,例如支付员工时,不应使用LIFO。在这种情况下,最好在使用这些交易进行付款之前等待交易完全验证(参见上述验证子)。

先进先出(FIFO)

最老的输出是最可靠的,因为它们被接收到的时间越长,块越多需要修改为双重支出他们。然而,在仅仅几个块之后,达到快速递减的回报点。假设攻击者拥有总共网络中的30%哈希功率,则原始的比特币纸张预测攻击者能够修改旧的块的机会:
比特币开发者指南(8)--支付流程
当交易费用时,FIFO确实具有很小的优势,因为较旧的输出可能有资格包含在50,000字节中,用于不需要的运行默认Bitcoin Core代码库的矿工的高优先级事务。但是,由于交易费用如此之低,这并不是一个显着的优势。

FIFO的唯一实际用途是接收者在几个块中花费所有或大部分收入,并希望减少他们的付款偶然无效的机会。例如,持有六个确认的每笔付款的接收方,然后以每两小时的时间表向供应商和储蓄账户支付100%的经过验证的付款。

重新定期付款

使用分散的比特币不可能实现自动定期付款。即使钱包支持自动发送不可逆付款,用户仍然需要在指定的时间启动程序,或者一直运行不受加密保护。

这意味着自动重复的比特币付款只能由代表其消费者处理satoshis的集中式服务器进行。实际上,希望在法定价格条件下设定价格的接收方也必须让同一集中式服务器选择合适的汇率。

非自动重新结算可以通过信用卡经常性付款变得普遍使用的相同机制来管理:联系付款人并要求他们再次付款 - 例如,通过发送一个PaymentRequest bitcoin: URI。

在将来,支付协议和新的钱包功能的扩展可能允许一些钱包程序来管理定期交易的列表。花费者仍然需要定期启动该计划并授权付款 - 但是,通过点击电子邮件发票,可以更容易和更安全地支付费用,从而增加接收方按时获得付款的机会。