2. 为什么要共识
理解了notary的交易确认机制,会不会产生一个感觉:挺完美的嘛——半信任中介方式,加上各种规则的严防死守,感觉把双花攻击都杜绝了啊,还需要共识机制吗?在给出这个问题的答案之前,我们先兜个圈子,介绍一些更基本的概念,不仅对后续讨论Corda的共识机制有帮助,也有利于更深入地理解去中心化数据库的一些关键概念。
只许州官放火,不许百姓点灯
首先我们探讨notary模式下节点间的信任关系:notary是两个交易者之间的第三方,这是与交易者不同的一种角色,因此Corda系统节点间的信任关系相对于比特币的节点间关系要复杂得多,无法做到全都是相互不信任的对等节点那么简单的模型。(当然,比特币其实也会有全功能节点和SPV的关系,但性质上跟notary和交易节点的关系还是有本质差别的)。我们可以用一张图来表示Corda系统中节点间信任关系的模型(暂时排除了Oracle等其他角色的节点,因为对共识这个主题不产生实质性影响):
我们逐个看一下不同角色之间的几种信任关系:
- 黑色连线的“互不信任”,是所有交易系统的固有特征,也是区块链/类区块链系统要解决的问题,这方面Corda与其他类型的系统没有区别
- 红色连线的“信任”,是基于notary的机制“强加”给我们的,是Corda区别于普通区块链的根本特点。当然, 这种信任也不是无条件的,各种密码学手段、联盟机制也会有所控制。不过,毕竟这成为了Corda模式的前提之一,因此对这种信任关系的讨论超出了本文的范围,只能作为讨论的前提
- 蓝色连线的“不信任”,则是本文第一部分所讨论并解决的问题,也就是通过notary机制来防止双花,从而使得“互不信任”的交易双方通过notary可以进行交易
- 最后剩下的就是notary之间的黄色连线:这种“互不信任”的关系,也就是R3一直强调的,notary可以是一些mutually distrusting的节点,这应该也是现实世界的特点。如果系统无法处理这个互不信任的关系,则会导致文章第一部分所说的情况:整个网络被notary划分成若干相互隔绝的子网,Corda这套体系恐怕也就没什么意义了。因此,系统必须有机制能够让这些notary在一起“合作”,相信读者已经能够猜出来:解决这个问题的,就是本文的主题——共识机制。
简单地总结一下:Corda系统中,强制引入了交易者对notary的信任关系,除此之外都是与其他区块链系统类似的,只是因为多了一种角色而更加复杂。听起来有点“只许州官放火,不许百姓点灯”的意味——你必须信任notary,而notary不信任你,并且它们之间也不互相信任。没办法,这种模式的根本特点就是这样,不得不说是所有讨论的一个略显遗憾的前提。不过,从后面共识机制的讨论可以看到,对于一个体系而言,这个模式还是有一定价值的,至少可以防止风险的扩散。
UTXO vs. STXO
本文一开头说到:“听到R3的企业产品部门负责人Mike Ward简介Corda的时候,受到相关概念的启发”,这个相关概念,就是指STXO(Spent Transaction Object)。STXO这个概念并不新鲜,但是Mike Ward说:“Notary就是STXO的database”,这就有些与众不同了。我想大部分人都能感受到,采用交易对象(“TXO”)模型的系统,如比特币、Corda,一般人都只针对UTXO这个概念进行讨论,STXO则基本上是个附属品——经常和UTXO成对出现,但默认不需要解释。STXO DB这个提法,更是鲜见——不仅在其他UTXO模型的区块链系统中没有看到过,在R3 Corda其他相关文档中也从未出现。
很明显,对于“TXO”模型的系统,下面这个等式成立:TXO = STXO + UTXO,也就是说,TXO是一个全集,STXO和UTXO则互为“补集”。针对这种关系,有一个很容易推导出的结论:当你能访问整个TXO集合的时候,用UTXO还是用STXO来判断一个交易对象的状态是等价的——你想知道一个交易对象是否UTXO,可以在UTXO的集合中进行搜索,能搜到则是UTXO,搜不到就不是;反过来也可以在STXO集合中搜索,搜到了就不是UTXO,搜不到就是。
理论上听起来没毛病,实践中我们先看一下比特币是怎么做的:比特币(0.8版以上)的数据中,有一个chainstate目录,其下放的就是UTXO数据库。这是个levelDB数据库,比特币的全功能节点需要对它进行维护:在确认一个区块时,首先要检索所有交易的输入项,如果发现没有对应的UTXO,应该要拒绝。确认区块的时候,要把所有交易的输入项在这个数据库中删除,并且把输出项插入。由此可见,这是比特币交易确认的过程中非常重要的一步,融合在比特币交易确认的复杂流程中,这个处理的正确性决定了确保数据准确以实现防止双花的能力,是比特币节点的重要功能之一。
比特币的这个实现模式有很合理的原因:随着交易的不断进行,越来越多的对象被“花掉”,因此STXO是一个有历史积累的集合,数量只增不减,越积越多。UTXO则有增有减——虽然比特币可以分解,但除非所有交易都是一进多出,否则增减总量相对还是有匹配的,这样可以保证UTXO的增长速度没有那么快。既然如此,作为交易验证过程中必须查询的数据,显然选择数据量小的那部分是合理的,虽然需要不断增删,付出一定维护一致性的代价,总还是好过每一次查询时间越来越长的问题。总之,这是个系统设计的取舍问题,而非原理上的区别。
全局 vs. 局部
那么,对于notary模式的系统而言,是不是应该采用与比特币相同的模式呢,即:随时记录/更新UTXO的信息,验证交易的时候查询一个对象是否UTXO?我们先给出答案,也就是上面提到的:notary是STXO数据库——它是通过保存/查询STXO来实现相关功能的。
在论证这个方案的合理性之前,又要谈谈概念了:notary的数据是“局部”的,每个notary只掌握经过自己公证的交易,这也是Corda“信息部分可见”特性的根本保障。所以,严格来说UTXO和STXO这两个概念对于notary而言,存在局部性和全局性双重含义:从局部看,UTXO表示“没有在我这里花过”,而STXO则表示“在我这里花过”;从全局看,UTXO表示“在整个Corda网络中没有花过”,而STXO则表示“在整个Corda网络中花过”。这样一对比就很明显了:在我这里花过,则在整个Corda网络中花过;没在我这里花过,不代表没在别处花过。反过来,要在整个网络中没花过,必须在所有notary那里都没花过;而在整个网络中花过,只需要在任何一个notary那里花过就可以了。因此:某种意义上说,STXO的概念是绝对的,无范围限制的,而UTXO的概念是相对的,局部的。
从实践的角度,我们首先看单一notary的情况:对于单个notary而言,他可以保存所有“经过”他公证的交易记录,从而拥有一切他处理过的交易的TXO记录,因此对于一个notary而言,UTXO和STXO仍然是补集关系,采用保存哪一部分的方式来实现双花检测,从实现的角度看都是没问题的。也就是说,虽然概念上STXO比UTXO更具有绝对性,但实践上却因为两者都被限定在一个局部,因而用哪一类对象做判定依据仍然是等价的。
再看多个notary,并且出现对象notary变更的情况(如果没有notary变更,任何交易对象的状态变化仍然被永久限定在某个notary局部,等同于单notary)。根据前面的介绍,notary变更是交易者将一个对象通过当前notary跟自己做一个交易,形成一个新的UTXO,其notary是新notary;原对象则变成了STXO。此时,新的UTXO是针对新notary的,对于系统中其他notary而言,没有什么意义——由于UTXO概念的局部性,这个新的UTXO对象在他们那里“既非UTXO,也非STXO”。原对象的STXO是针对原notary的,但是由于STXO的全局性,其实对于整个Corda网络的所有notary而言,这应该都是一个STXO。
讨论到这里,我们可以给出本文最重要的结论:对于一个基于notary机制的系统而言,当有多个notary可能会关心一个TXO的状态时,STXO是对所有notary都有意义的,UTXO则只对未来会处理到他的notary才有意义。
共识
说完了所有这些概念,终于可以讲讲共识了。为了简化讨论,我们只设想一个场景:不管出于什么原因,比如程序bug、网络通讯故障、甚至notary蓄意欺骗等等,一个对象的当前notary对它执行了两次notary变更,分别将其notary属性变更为notary A、notary B,如果系统可以允许这种情况的发生,不就出现了双花吗?这也印证了上面讨论过的前提——notary之间相互应该是不信任的,对变更notary这件事,由于涉及一个对象可以在其他notary那里进行交易的问题,因此必须有机制保证一个对象变更两次notary的行为受到阻止。唯一的办法显然就是notary变更必须要所有notary节点都达成共识——这也就是Corda系统中需要共识机制的根本原因,相信读者非常容易理解和证明。
那么,从实践角度而言,系统的“notary们”需要针对什么达成共识,又如何达成共识呢?相信真正理解了前面几个概念的读者,已经有个大概的思路了:由于对象状态的判断要作为全系统notary达成一致的结论,就应该使用全系统一致的概念来进行处理,而根据前面的结论,STXO自然是应该使用的概念。因此,notary作为STXO DB的模式,就自然而然地成为共识机制的解决方案了。具体设计和实现方面的建议,我们就放到下一节再讲。
小结
本节主要是一些概念的深入讨论,首先是信任关系问题:基于notary的系统,信任关系要复杂一些,notary之间互不信任,应该是共识机制存在的大前提。其次,UTXO和STXO在信息全局可见的系统中互为补集,因此实践中使用哪个作为防止双花的依据都是可以的,只需要根据系统设计的优化方案来考虑。然而,对于notary模式的系统而言,UTXO和STXO在局部和全局的意义是不同的,这将导致无论从概念上还是实践上,使用STXO作为交易确认的依据更具有一致性,不过这一特点只在发生notary变更的情况下才会体现出来。综合上述三点可以得出结论:Corda确实是需要共识机制的,共识应该针对状态的notary变更,并且可以基于notary作为STXO DB的模式来实现。
此外,作为本节的结束,我顺便提一个有意思的问题供读者思考:基于TXO模式的系统,共识是针对TXO的状态的(不管是UTXO还是STXO),那基于账户模型的系统,共识机制是针对什么的呢,或者说应该是怎样一个模式呢?