本文选自新书《区块链核心技术与应用》,略有删节。上期介绍了超级账本的主要组件,本次介绍共识机制和交易流程。Fabric 的网络节点本质上是互相复制的状态机,节点之间需要保持相同的账本状态。为了实现这个目的,各个节点需要通过共识( consensus )过程,对账本状态的变化达成一致性的认同。
Fabric 的共识过程包括 3 个阶段:背书、排序和校验。
1. 背书
在背书( endorsement )阶段中,背书节点对客户端发来的交易预案进行合法性检验,然后模拟执行链码得到交易结果,最后根据设定的背书逻辑判断是否支持该交易预案。如果背书逻辑决定支持交易预案,它将把预案签名后发回给客户端。
客户端通常需要根据链码的背书策略,向一个或者多个成员的背书节点发出背书请求。背书策略会定义需要哪些节点背书交易才有效,例如需要5个成员的背书节点中至少3个同意;或者某个特殊身份的成员支持等。客户端只有在收集满足背书策略的支持之后,广播出去的交易才能被视为有效。
2. 排序
排序( ordering )阶段就是由排序服务对交易进行排序,确定交易之间的时序关系。排序服务把一段时间内收到的交易进行排序,然后把排序后的交易打包成数据块(区块),再把区块广播给通道中的成员。采用这种方式,各个成员收到的是一组发生顺序相同的交易,从而保证了所有节点的数据一致性。
Fabric 1.0 中的排序服务支持可插拔的架构,除了提供的 SOLO 和 Kafka 模式外,用户可以添加第三方的排序服务。SOLO 是单机确认模式,仅适合开发测试中使用。Kafka 模式是基于 Kafka 开源的分布式数据流平台,具有高扩展性和容错能力,适合用在生产系统。需要注意的是,Kafka 只提供了 CFT 类型的容错能力,即仅可对节点的一般故障失效容错,缺乏对节点故意作恶的行为进行容错的能力。
排序服务是共识机制中重要的一环,所有交易都要通过排序服务的排序才可以达成全网共识,因此排序服务要避免成为网络上的性能瓶颈。
3. 校验
校验( validation )阶段是确认节点对排序后的交易进行一系列的检验,包括交易数据的完整性检查、是否重复交易、背书签名是否符合背书策略的要求、交易的读写集是否符合多版本并发控制 MVCC ( Multiversion Concurrency Control )的校验等等。当交易通过了所有校验之后,将被标注为合法并写入账本中。因为所有的确认节点都按照相同的顺序检验交易,并且把合法的交易依次写入账本中,因此它们的状态能够始终保持一致。
基于上面的共识机制,Fabric 的交易流程如下图所示:
1)应用端首先构建交易的预案,预案的作用是调用通道中的链码来读取或者写入账本的数据。应用端使用 Fabric 的 SDK 打包交易预案,并使用用户的私钥对预案进行签名。
应用打包完交易预案后,接着把预案提交给通道中的背书节点。通道的背书策略定义了哪些节点背书后交易才能有效,应用端根据背书策略选择相应的背书节点,并向它们提交交易预案。
2)背书节点收到交易预案后,首先校验交易的签名是否合法,然后根据签名者的身份,确认其是否具有权限进行相关交易。此外,背书节点还需要检查交易预案的格式是否正确以及是否之前提交过(防止重放攻击)。
在所有合法性校验通过后,背书节点按照交易预案,调用链码。链码执行时,读取的数据(键值对)是节点中本地的状态数据库。需要指出的是,链码在背书节点中是模拟执行,即对数据库的写操作并不会对账本作改变,所有的写操作将归总到一个写入的集合( Write Set )中记录下来。
在链码执行完成之后,将返回链码读取过的数据集( Read Set )和链码写入的数据集( Write Set )。读集和写集将在确认节点中用于确定交易是否最终写入账本。
3)背书节点把链码模拟执行后得到的读写集( Read-Write Set )等信息签名后发回给预案提交方(应用端)。
4)应用端在收到背书响应之后,检查背书节点的签名和比较不同节点背书的结果是否一致。如果预案是查询账本的请求,则应用端无需提交交易给排序节点。如果是更新账本的请求,应用端在收集到满足背书策略的背书响应数量之后,把背书预案中得到的读写集、所有背书节点的签名和通道号发给排序节点。
5)排序节点在收到各个节点发来的交易后,并不检查交易的全部内容,而是按照交易中的通道号对交易分类排序,然后把相同通道的交易打包成数据块( blob )。
6)排序节点把打包好的数据块广播给通道中所有的成员。数据块的广播有两种触发条件,一种是当通道的交易数量达到某个预设的阈值,另一种是在交易数量没有超过阈值但距离上次广播的时间超过某个特定阈值,也可触发广播数据块。两种方式相结合,使得排序过的交易可以及时广播出去。
7)确认节点收到排序节点发来的交易数据块后,逐笔检查区块中的交易。先检查交易的合法性以及该交易是否曾经出现过。然后调用 VSCC( Validation System Chaincode )的系统链码检验交易的背书签名是否合法,以及背书的数量是否满足背书策略的要求。
接下来进行多版本并发控制 MVCC 的检查,即校验交易的读集(Read Set)是否和当前账本中的版本一致(即没有变化)。如果没有改变,说明交易写集(Write Set)中对数据的修改有效,把该交易标注为有效,交易的写集更新到状态数据库中。
如果当前账本的数据和读集版本不一致,则该交易被标注为无效,不更新状态数据库。数据块中的交易数据在标注成“有效”或“无效”后封装成区块(block)写入账本的区块链中。
上述的交易流程中,采用了 MVCC 的乐观锁( optimistic locking )模型,提高了系统的并发能力。需要注意的是,MVCC 也带来了一些局限性。例如,在同一个区块中若有两个交易先后对某个数据项做更新,顺序在后的交易将失败,因为它的读集版本和当前数据项版本已经不一致(因为之前的交易更新了数据)。(未完待续)