瑞波Ripple是如何处理一致共识错误的
扫描二维码
随时随地手机看文章
Ripple是一个国际性支付系统,允许用户像发送电子邮件一样无缝地进行跨国界转移资金(包括法定货币、数字货币和其他形式的价值)。如同比特币等其他数字货币,ripple协议通过去中心化的计算机网络允许进行P2P交易结算。然而,与其他数字货币协议不同,ripple协议的货币是不可知的,不要求用户使用协议中的原生货币(XRP)。此外,技术能够实现几乎实时结算(3-6秒),而且将把每个国际交易发送给网络中可得的最便宜的买卖差价。
机制
在核心处,ripple有记录用来交易资产的账户、余额和要约信息的“总账(Ledger)”。类似创建账户、进行支付、转变资产等操作通过被称为“交易”的签署指令来进行。
因为ripple是一个用密码写的系统,账户可通过加密身份进行鉴定。交易被与加密身份相匹配的加密签名检验。根据确定的、已知的规则,每个服务器处理每个交易。
双重支付问题
根本无效的交易可以被所有参与者识别出来,例如从一个只有10美元的账户中发送20美元。然而,也有可能创建两个交易,其中只有一个有效。这种情况被称为双重支付问题。
假设Alice在某个支付系统中有10美元。假定是一个有用的支付系统,如果她想的话,就必须能向Bob发送10美元。而且同样,也可以发送给Charlie。然而,如果她向Bob和Charlie发送了相同的10美元,那么支付系统停止使用。因此以某种方法,向Bob发送10美元的行为必须阻止她向Charlie发送相同的10美元。
按照惯例,这是由中央机构解决的。例如,银行会清除基于发行者可利用余额的支票,其中银行是这些余额的唯一托管人。然而,像ripple一样的分布式系统,明显没有中央机关。他们必须通过其他方式解决双重支付问题。
简化(双重支付)问题
大部分双重支付问题可以通过众所周知的方法来解决,比如阻止一个账户支付它没有的资金。实际上,双重支付问题可以简化为给交易排序。
再来看Alice试图给Bob和Charlie发送相同10美元的例子。如果支付给Bob的行为被认为是第一位,那每个人都会同意她有资金支付Bob。而且如果支付给Charlie的行为被认为是第二位,那每个人都会同意她不能把那些资金给Charilie,因为现在是属于Bob的。
我们也可以按照确定性的规则给交易排序。由于交易是数字信息的集合,所以它们能轻易被排序。
没有中央机关的情况下,这对解决双重支付问题来说足够了,但它要求我们在确定交易结果之前掌握所有将要发生的交易,以便于我们进行排序。显然,这是不实际的。
然而,如果我们能把交易分成群组而且就那些群组达成一致,那么我们就可以在那个群组中对交易进行排序。也就是说,只要每个参与者都同意把这些交易按照一个单位来处理,那么他们就能使用确定性的规则来解决双重支付问题,不需要任何中央机构。参与者只各自对交易进行排序,并按照已知的规则以确定性的方法应用到交易上。
Ripple不依赖于两个互相冲突的交易中的任何一个。根据确定性规则,交易群组是已生效的,而且一个群组里有两个相冲突的交易没有伤害。根据排序规定,第一位的交易会成功,第二位的交易会失败。
一致共识的基本角色是让过程中的参与者就交易可以被处理为一个单元来解决双重支付问题的事宜达成一致。有四个理由说明这个协议比预期更容易达成。
1. 如果实在没有理由让一个交易不被纳入此交易群组,那所有可靠的参与者都会同意收纳它。如果所有参与者都已经同意,那一致共识就不用做任何事情了。
2. 如果有该交易不应被纳入交易群组的任何理由,所有可靠的参与者会倾向于排斥它。如果交易仍然有效,那就没有理由在第二轮不包含它,而且那时他们都应该同意包含它。
3. 有极少数的参与者会特别关心交易分组的方式。当所有人的重点是达成一致时,实现一致最为简单。只有当他们分发利益时,实现一致才面临挑战。确定性原则甚至可以被用来构建组群,只有在边界条件时才会导致不一致。例如,如果在一轮中有两个相冲突的交易,确定性原则可以被用来决定谁进入下一轮。
4. 每个参与者最优先的事情是正确性。也就是说,不能违反那些人们所依赖的用来维护网络完整性的准则。例如,一定不能处理一个没有被正确签署的交易。然而,每个可靠参与者的第二优先事情是一致性。一个具有双重支付可能性的网络根本没有效用。每个可靠参与者最重视的是正确性,这个事实推进一致性进程。
如何实现一致共识
达成一致性开始于每个想要这样做的参与者作出最初的决定。这是他们目睹的有效交易集合。
然后参与者大量投入到达成一致性的过程中:如果一个特定交易没有得到多数支持,那参与者将同意推迟那个交易。如果一个特定交易拥有多数支持,参与者将同意包含这个交易。因此,轻微的多数快速成为全部支持,而且轻微的少数快速成为现有这一轮的普遍拒绝者。
为了防止一致性过程停留在50%附近,而且为了减少可靠的收敛性造成的重叠,要求包含某个交易的阈值越来越高。首先,如果超过50%的参与者同意,那参与者将持续同意包含这个交易。然后这个数字会上升至60%,而且会持续增加,直至有争议性的交易被推迟至下一轮。
如果参与者发现绝对多数同意接下来处理某个交易集合,那就会宣布达成一致共识。
一致共识可能会失败
开发一种永远都能达成完美共识的一致性算法是不实际的。理解为什么会这样的途径之一是考虑一致共识过程是如何终止的。在某种程度上,每个参与者必须宣布已经达成一致性,而且某些交易集合已被认为是这个过程的结果。该声明不能撤回地将参与者引入某些作为一致性过程结果的特定交易集合。
很明显,有些参与者必须第一个做这件事或者永远不会有参与者做,一致性永远不能达成。目前,假设参与者首先已经这样做了。当参与者决定一致性达成的时候,其他参与者还没有做出这个决定。如果从他们角度而言,没能改变这个已被同意的集合,那么他们就会作出一致性达成的决定。所以他们必须有能力改变被同意的集合。
换句话说,对于终止的一致共识进程,某个参与者必须宣布交易集合已达成一致,尽管其他每个参与者理论上仍能改变同意交易集合的决定。
这种失败的可能性非常低,但不能缩减为零。技术性交易(engineering tradeoff)促使这种可能性降至千分之一以下,使得一致共识进程明显放缓,并使一致共识更难容忍网络和端点错误。
Ripple如何处理一致共识错误的
在一轮一致共识进程结束后,每个参与者申请他们认为被赞同的交易集合。这促使构建他们所认为的总账应有的下一个状态。
然后,同样也是验证者的参与者发布下一个总账的加密指纹(cryptographic fingerprint),这被称为“验证”。如果达成一致,那绝大多数的验证者应发布相同的指纹。
之后,参与者收集这些验证。从验证中,他们可以判断出先前的一致共识是否会导致绝大多数参与者同意这个交易集合。
参与者将面临以下三种情况之一,按可能性大小排序。
1. 他们建立了绝对多数同意的相同总账。这种情况下,他们可以认为总账被充分验证,而且可以信赖总账的内容。
2. 他们建立了不同于绝对多数同意的总账。这种情况下,他们必须建立和接受绝对多数同意的总账。这是一个典型的例子,他们很早宣布达成一致,之后其他参与者进行了修改。他们必须“跳转”至绝对多数总账,从而实现继续运转。
3. 收到的验证中没有出现明显的绝对多数。这种情况下,先前的一致共识就被废弃了,而且在任何一个总账被验证前,必须发起新一轮一致性协商。
当然,情况1是最常见的。无论如何,情况2是不会损害网络的。小部分参与者会每一轮都出现情况2,而且网络会顺利运行。
情况3导致网络停止几秒来推动进程向前,但这极其少见。这种情况下,后来的一致共识更不容易失败,因为一致共识进程化解了不一致,而且只有存在不一致会导致失败。
在很少的情况中,整个网络会几秒钟不能取得进展。作为交换,交易确认的平均次数会比较少。
理念
系统在某些组件失败或某些参与者具有恶意的情况下提供结果的能力是可靠性的一种表现形式。尽管这很重要,但在加密支付系统中还有另一种更为重要的可靠性形式,即系统产生可信赖结果的能力。也就是说,当系统报告结果可靠时,我们应信赖那个结果。
然而,现实世界系统面临以上两种可靠性都让步的运行状况。这包括硬件故障、通信故障,甚至不可靠的参与者。Ripple部分设计理念就是为了发现并报告结果可靠性被削弱的情况,而不是提供一定不可靠的结果。
Ripple一致性算法为工作系统证明提供了另一种方法,而不是不必要地消耗计算资源。拜占庭错误是有可能的,而且确实发生过,但结果只是少数延迟。在所有情况中,ripple一致性算法只有在结果真正可靠时才会进行报告。
图解
这是关于一致性共识算法的大致图解。
一致性共识的目的是让所有服务器都同意一组交易并生效到最后关闭总账(Last Closed Ledger)上。他们不关心交易是否有效或者交易发生的顺序。他们只关心所有服务器都赞同这组数据是什么。
一致共识是个持续迭代的过程。服务器发出一组交易的提案,然后其他从对端接收到(提案)的服务器也发出自己的提案。
这里我们有某一台在Ripple网络中的服务器的抽象化图解。
在中间显示了关闭包(Closing Bundle)。这是一组交易,网络正在尝试达成一致。
现在我们看到,(左上角)一个提案来到了这台服务器。在一致共识达成期间,每个服务器都发出一系列的提案。提案就是 该服务器认为应该把他包含到关闭包里的交易列表。
(该服务器会对)这传入的提案针对UNL进行检查。如果发送提案的服务器在UNL列表上,那么这个提案被发送到关闭包,并且里面的所有交易都获得1票。
而在网络试图达成在最后一个交易集合的共识(的过程中),新的交易进入。这些交易被收集在下一包。它们将被施加到下一个总帐(Ledger)。
在这里,我们看到了一个提案,来源服务器不是我们的UNL。这个提案被简单地丢弃,而不用判断什么要包含到最后关闭包里。
part2
现在,我们已经得到了来自其他服务器的一些提案。目前我们有5个活跃的UNL服务器。那些被超过50%的活跃服务器投过票的交易,都被认为应该(被服务器)打包。你可以看到标记为绿色的这些交易。
现在,计时器已经用完了,所以我们把我们的针对当前包的投票发送到网络。一个交易是否该放到当前包里,这个(得票率)阈值也从50%提高到60%。这样有很多不同意见的交易,将有一种倾向–被推到下一个总帐。
我们已经收到更多的提案(上图是Server5的新提案到达),改变了我们的想法:关闭包应该包括(哪些交易)。(上图可见“=”这个交易也到达了3/5的投票率)
一致共识机制认为:达到UNL的80% 服务器同意的那些交易,应该放入这个总账。你可以看到在这里发生了,因为每个交易有4个或更多的得票或小于2票。这些交易将被发送并被施加到上次关闭总帐(Last Closed Ledger)。 (译注:这里有个bug?图标为“=”的交易,只有3票,也被发送到LCL了)
关闭包开始着手生成新的LCL。你在那个关闭过程中收集到的新交易,将被添加到之前的没能到放总帐的交易候选集里。现在达成一致共识的过程重新开始……
译者补充
这个文章只说了proposal过程。实际过程比这个复杂,一致性会包括两步,Proposal和Validation;Ledger状态会有三个,ClosingLedger,LCL,AcceptedL。
1. Proposal阶段会发出自己的closing ledger,大家不断根据收到的proposal建立交集,剩下的建disputed TXs进行投票,投票通过的会继续保留在closing ledger,得票率要求随时间提高
2. 投票不通过的留在下一个ledger处理
3. 然后就是靠那个复杂的ConTInuousLedgerTIming::haveConsensus算法判定何时可以将closing ledger转成LCL并发出validaTIon
4. 然后validaTIon超过quorum个则将LCL转为accepted ledger继续往前走,
5. 之后走的过程中一旦发现validation最多的LCL和自己的不一样,则会转入分支切换流程从网络获取新的LCL。