区块链国产化实践指南:基于Fabric 2.0

978-7-115-58037-5
作者: 王雅震
译者:
编辑: 孙喆思

图书目录:

详情

本书以Hyperledger Fabric2.0为蓝本,由浅入深地剖析底层源码,系统讲解Fabric2.0的技术框架、各个模块实现以及背后所蕴含的技术思想,并结合区块链国产化的当前发展,分析Fabric技术的国产化实践。本书主要分为三个部分,第一部分(第1~12章)介绍区块链和Fabric技术相关概念、Fabric2.0底层源码;第二部分(第13章)讲述如何部署Fabric2.0,包括使用Kubernetes进行部署;第三部分(第14~17章)融合自主可控技术国产化趋势,结合“5G+物联网”等区块链国内应用场景,通过实际应用分析Fabric技术的国产化实践。 无论是对区块链感兴趣,想要入门Fabric技术的新手,还是初涉Fabric技术,需要通过源码深入理解并使用该技术的区块链行业从业者,抑或是对区块链国产化实践有需求,需要实践案例参考的区块链国产化践行者,都能从本书中获益。


图书摘要

版权信息

书名:区块链国产化实践指南:基于Fabric 2.0

ISBN:978-7-115-58037-5

本书由人民邮电出版社发行数字版。版权所有,侵权必究。

您购买的人民邮电出版社电子书仅供您个人使用,未经授权,不得以任何方式复制和传播本书内容。

我们愿意相信读者具有这样的良知和觉悟,与我们共同保护知识产权。

如果购买者有侵权行为,我们可能对该用户实施包括但不限于关闭该帐号等维权措施,并可能追究法律责任。


编  著 王雅震

责任编辑 杨海玲

人民邮电出版社出版发行  北京市丰台区成寿寺路11号

邮编 100164  电子邮件 315@ptpress.com.cn

网址 http://www.ptpress.com.cn

读者服务热线:(010)81055410

反盗版热线:(010)81055315


本书以Hyperledger Fabric 2.0为蓝本,由浅入深地剖析底层源码,系统讲解Fabric 2.0的技术框架、各个模块实现以及背后所蕴含的技术思想,并结合区块链国产化的当前发展,分析Fabric技术的国产化实践。本书主要分为三个部分,第一部分(第1~12章)介绍区块链和Fabric技术相关概念、Fabric 2.0底层源码;第二部分(第13章)讲述如何部署Fabric 2.0,包括使用Kubernetes进行部署;第三部分(第14~17章)融合自主可控技术国产化趋势,结合“5G+物联网”等区块链国内应用场景,通过实际应用分析Fabric技术的国产化实践。

无论是对区块链感兴趣,想要入门Fabric技术的新手,还是初涉Fabric技术,需要通过源码深入理解并使用该技术的区块链行业从业者,抑或是对区块链国产化实践有需求,需要实践案例参考的区块链国产化践行者,都能从本书中获益。


区块链作为一项可以改变互联网底层基础设施服务的分布式账本技术,已经是我国重点发展的战略性技术,它逐渐在我国各行业落地。在社会分工日益明细的趋势下,区块链的分布式技术可以在一定程度上解决由分工导致的生产要素在协同、整合方面出现的问题,提高社会生产的效率,为我国的全面深化改革、传统产业改造升级、大国“智”造等,注入新的技术能量。可以预见,区块链技术将对城市的发展和管理,以及我们的日常生活产生越来越大的影响。

区块链是一项较新的技术,各国区块链技术的发展基本处于同一起跑线,在奔跑的过程中,首先要做到“自立自强”,实现自主可控。在国际竞争环境下,自主可控的重要性不言而喻。其中,区块链技术的国产化是实现自主可控的重要途径之一。

本书以主流开源区块链技术Hyperledger Fabric 2.0(文中简称Fabric)为研究对象,研究思路是在研究现有技术的基础上,探究如何升级改造现有技术,使技术符合我国标准或主流需求,以实现国产化,进而达到自主可控的目的。全书共分为三个部分。

第一部分,第1章~第12章,从源码层面深入剖析Fabric的实现。第1章,从顶层视角,概述Fabric相关的概念、架构,目的是让读者对Fabric架构有初步的认识。第2章,讲述Fabric的配置。第3章~第5章是小单元,均与Fabric区块链网络中的身份有关,按照对象包含与被包含的关系,从上层到下层,依次讲述MSP、BCCSP、身份对象的实现。策略的实现依赖于身份,在理解身份的基础上,第6章主要叙述策略模块的实现。第7章,讲述账本模块的实现。可以说,讲述第3章~第7章的各个模块,是为第8章~第11章叙述通道、通道服务和节点的内容打基础。第12章,专门讲述链码的生命周期管理。

第二部分,第13章,讲述如何部署Fabric,包括使用Kubernetes进行部署。

第三部分,第14章~第17章,叙述区块链技术在国内的发展和对Fabric进行国产化改造的实践,包括4个方向:国密改造、性能改造、BaaS平台以及与物联网相结合。这些都是实践性的尝试,以抛砖引玉。国密改造、BaaS平台的实现,主要以代码的形式呈现。性能改造的实现,主要以详述性能优化方案的形式呈现。与物联网相结合的实现,主要以实际部署操作的形式呈现。

其中,第一部分的大量内容是关于源码的引用、解析,可以称得上“密密麻麻”。过程性的内容均以代码清单的形式罗列,并存在前后章节内容的引用,在阅读上会造成一些不便。但没办法,Fabric源码如此,“跳来跳去”,我思考再三,仍然认为代码清单的形式,是讲述源码最适当和清晰的方式。

如下罗列本书引用源码的规范,有助于读者顺利阅读。

(1)代码的引用、讲述,以代码重要程度为标准,即只引用、讲述重点功能、关键步骤、关键逻辑判断的实现。

例如,if err != nil {return nil, err}、defer txParams.TXSimulator.Done()、handler := &Handler {Invoker:cs, Keepalive:cs.Keepalive, …}等“白话”代码,若无特别含义,将不引用或简洁引用。

例如,if err := recordHeightIfGreaterThanPreviousRecording(r.ledgerDir); err != nil {…},若错误无须特殊说明,则此类判断错误的代码将被直接省略。

(2)描述源码调用过程的边界,最深至调用的标准库或第三方库。文中Fabric 2.0的源码和第三方库均托管于GitHub网站。

(3)由于源码的对象、服务存在大量交互,因此存在内容引用,引用格式如“参见2.2节”。

综上,阅读第一部分时,读者可以参考Fabric 2.0源码学习源码的原理与实现。阅读第二部分时,读者可以学习如何完成区块链网络的实际部署工作。阅读第三部分时,读者可以了解Fabric在国密改造、性能改造、BaaS平台以及与物联网相结合方面的实践思路。本书将是读者学习Fabric源码、实现区块链网络部署和拓展实践思路时不错的辅助工具和参考资料。

王雅震

2021年3月


本章以鸟瞰的视角,站在高处,对Fabric进行整体概述。首先,本章介绍Fabric中出现的若干核心概念,这些概念会在本书中频繁地出现。然后,对Fabric区块链网络的架构进行描述,使读者对其有一个图像化的整体认知。在此基础上,简述Fabric区块链网络如何处理一笔交易,这个流程还会在之后的章节中详述。最后,我们初览Fabric源码目录,为之后深入讲解源码打下基础。

区块链网络(blockchain network)从参与者范围的角度定义,分为公有链、联盟链和私有链。公有链人人均可参与,如以太坊。联盟链将参与者的范围限制在联盟成员范围内。私有链则是单个组织或个人私有的,目前应用较少。本书中讨论的Hyperledger Fabric 2.0(项目仓库为hyperledger/fabric)属于联盟链。区块链网络本质上是基础设施,向外可以提供容错、共识、防篡改交易、分布式账本存储等服务。在Fabric区块链网络中,所有参与者各自提供一部分基础设施和资源,组成网络,并参与网络管理或交易服务。

联盟(consortium)表示若干个组织通过现实手段达成一定的协议,彼此作为“命运共同体”成员。在Fabric区块链网络中,联盟成员认可彼此的身份、权限配置、责任划分,成员依据相同的交易逻辑产生数据、依据相同的策略认可交易。

通道(channel)是Fabric区块链网络中隔离账本交易数据的逻辑主体。一个通道对应着一个联盟,一个通道也对应着一个账本。通道中的账本数据在联盟成员之间共享,但完全与另一个通道的数据隔离。这就让通道与通道之间具有私有数据集合的功能,但通道在Fabric区块链网络中是“较重”的资源,每个通道均需完整地运行一套交易服务、账本服务、共识服务等,因此在设计通道时需慎重对待。更多的情况下,如果是为了隔离业务数据,应使用私有数据集合功能。

组织(organization)是参与Fabric区块链网络、组成一个联盟的基本单位,也是一个逻辑主体。任何因一定的属性、目的而将多个单体编制成集合的主体,都可以是组织,如现实中的公司、行业协会、多个工厂同类产品的生产线等。

节点(peer)是组成组织的个体在Fabric区块链网络中运行的基础设施实体。在Fabric区块链网络中,节点在广义概念上的专用名词为Peer。具体地,由于职责和功能的迥异,Fabric区块链网络将主要的参与节点分为orderer和peer,orderer节点主要负责运行系统通道、共识排序服务,peer节点负责背书、广播、散播等服务。但orderer节点和peer节点均可被视为区块链网络中广义概念上的节点,因而两者在配置上又存在很多类似的地方。

智能合约(smart contract)是使用编程语言实现的一种交易规则,以链码(chaincode)的形式部署在Fabric区块链网络中。智能合约属于通道,供联盟成员调用,产生交易数据。使用智能合约的目的是依托区块链网络赋予账本数据的可信性,在技术上完全地模拟实现商业交易规则,减少或消除人为干预合约履行的可能性。虽然智能合约支持Go、Java这样的高级语言,但在实际项目应用时,由于智能合约是依托区块链网络运行的,其在实用性、适用范围、效率、功能拓展等方面能力有限,因此Fabric官方也在积极探索拓展链码能力的途径。

账本(ledger)是Fabric区块链网络中数据存储的主体,用于以多种形式记录网络中所有发生的成功或失败的交易。具体地,账本使用blockfile存储区块,使用LevelDB或CouchDB存储来自区块的有效交易数据、区块索引、历史数据、私有交易数据。账本与通道是一对一的,账本与账本之间数据隔离,不产生任何关联。

区块(block)是区块链特性在数据存储方面的核心体现,也是Fabric区块链网络中账本数据存储的基本单位。区块的次序号由0开始,依次递增,前后块相互验证关联,形成一条不可篡改的链。一条链中区块的数量,也被称为高度(height)。一个通道的账本,可以视为一条区块链。

交易(transaction)是Fabric区块链网络的通道账本中组成区块的基本单位,主要描述了依据交易规则对应用通道中账本数据的读取、更改,以及对交易数据表示认可的背书主体。

私有数据集合(private data collection)是在Fabric区块链网络参与者之间隔离交易数据方面更细化的应用。通道与通道之间的交易数据是隔离的,但通道是“较重”的资源,而面对大量细化的交易数据隔离需求,通过通道实现数据隔离,显得过于“笨重”,因此设计了私有数据集合的概念。通道中,有不公开交易需求的若干参与者组成一个“小团体”,遵循一份私有数据集合定义,执行交易,产生的交易数据只在“小团体”范围内散播存储。

共识机制(consensus mechanism)保证了Fabric区块链网络的账本数据的可信、防篡改等特性。从技术上讲,Fabric区块链网络运行的最终目的是产生所有参与者均认可的账本数据,即在交易数据方面达成共识。Fabric区块链网络中的共识机制不单指某一共识算法(如PoW、PoS、Raft、PBFT等),而是基于交易处理流程的分阶段共识,并在分阶段共识的基础上,达成整个网络交易处理的共识。背书阶段,与交易相关的参与者已就链码定义(包括背书策略等)达成了共识,因而均认可链码产生的交易数据。排序阶段,由Raft算法主导确定每个交易在块和账本中的位置,参与者对此也达成共识。散播阶段,由gossip算法按已排序好的位置,将包含交易的块散播、存储至所有参与者节点本地的账本副本中,参与者对此也达成共识。在这些阶段共识的基础上,参与者对整个交易流程、结果可以达成共识。

结合1.1节介绍的Fabric核心概念,我们先来了解一下Fabric区块链网络。Fabric官方文档中给出了一个Fabric区块链网络经典拓扑结构,如图1-1所示[1]。图1-1中,N代表Fabric区块链网络(network),NC代表网络配置(network configuration),C代表应用通道(channel),CC代表应用通道配置(channel configuration),L代表账本副本(ledger eplica),S代表智能合约(smart contract),R代表组织(organization),P代表peer节点,O代表orderer节点,A代表组织的应用客户端(application client),CA代表组织的身份认证机构(certification authority)。1、2、3等数字是多个同类主体的编号,其中对应主体间的编号保持一致,如账本与通道一一对应,则L1表示应用通道C1的账本副本。

图1-1 Fabric区块链网络经典拓扑结构

4个组织R1、R2、R3、R4订立协议,一同组建Fabric区块链网络N。R4是orderer组织,只有一个节点O4,且约定只负责启动和管理N,不参与具体商业交易。R1、R2、R3为peer组织,各有一个应用客户端A1、A2、A3,参与N中的商业交易,商业交易合约由S5、S6实现。R1与R2、R2与R3之间存在隐藏双方交易的需求,因此R1与R2组成一个通道配置CC1,一同属于通道C1;R2与R3组成一个通道配置CC2,一同属于通道C2。P1是R1的节点,部署了S5,维护了L1。P2是R2的节点,部署了S5、S6,维护了L1、L2。P3是R3的节点,部署了S6,维护了L2。

在N由O4初始启动时,NC4中只有R4有权限管理N。R4通过更新NC4配置(更新系统通道配置),添加R1并赋予相同的管理权限。R1或R4通过更新NC4配置,可以继续添加R2、R3,但只赋予非管理权限。之后,R1或R4通过更新NC4配置,添加R1与R2、R2与R3两个联盟(也可称为“命运共同体”),对应CC1、CC2。R1或R2均有权限使用CC1创建C1,R2或R3均有权限使用CC2创建C2。属于各组织的P1、P2、P3也可以加入组织所在的应用通道,并通过应用通道与O4通信。其中P2同时加入了C1、C2。

在实际操作时,NC4是创世纪块(genesis块),通过configtxgen工具依据configtx.yaml生成,一般已经包含已授权的R1、R2、R3、R4,不需要单独通过更新NC4进行添加、授权。赋予R1管理权限也是可选的。

S5描述了在C1中R1与R2之间的商业交易逻辑,具体部署在P1、P2。S6描述了在C2中R2与R3之间的商业交易逻辑,具体部署在P2、P3。从应用角度讲,Fabric区块链网络是一个向应用客户端提供智能合约和账本服务的基础设施系统,外界通过A1、A2、A3,调用S5或S6,产生N的账本数据,再由各个peer节点复制。

在理解Fabric区块链网络拓扑结构的基础上,我们可以继续了解Fabric区块链网络处理一笔交易的经典流程,如图1-2所示。图中,N代表Fabric网络。CA代表网络身份认证服务节点,一般为Fabric CA或其他CA认证中心。P代表peer节点,L、S、DB分别代表一个peer节点所使用的账本副本、智能合约、状态数据库。SP、PR、ENV、BLK分别代表不同阶段的交易数据。O代表orderer节点,5个orderer节点形成了一个Raft共识集群。

图1-2 Fabric区块链网络经典交易流程

Fabric区块链网络经典交易流程描述如下。

(1)应用客户端向CA(Fabric CA或其他CA)提交认证请求,验证用户或应用客户端自身的合法性。若验证有效,则继续之后的步骤。

(2)应用客户端(一般为peer命令行客户端、Fabric SDK或第三方授权应用)收集交易参数,创建一笔背书签名申请SP,并将SP发送给若干个背书节点。

(3)每个背书节点接收SP,并依据SP调用智能合约S。S执行所实现的合约逻辑,模拟交易行为,产生模拟交易数据。背书节点代表组织,对模拟交易数据进行签名,形成一个背书应答PR,返回给应用客户端。

(4)应用客户端收集各个背书节点返回的PR,比较PR中的模拟交易数据是否一致,确认一致后,收集每个PR中各个背书节点的签名,创建一笔交易ENV,然后将ENV发送至一个orderer节点。

(5)orderer节点接收ENV,按出块规则,将ENV放至一个块BLK,然后将BLK发送至orderer节点所在的Raft集群中进行共识排序。确定BLK的序号后,BLK被写入orderer节点的本地应用通道的账本中。每个peer组织中的leader节点,会从orderer节点账本中顺序索要新写入的BLK。BLK被发送至各个peer组织的leader节点。

(6)leader节点收到BLK后,将BLK写入本地应用通道的账本,并从BLK中解析出ENV,将ENV中的交易数据提交至状态数据库DB。然后,leader节点将BLK散播至同组织中的其他peer节点,或同通道中其他组织的peer节点,这些节点同样会写入BLK和提交ENV中的交易数据,然后尝试将BLK继续散播至其他peer节点。

接触一个项目的源码,能够了解该项目源码的目录结构以及重要文件的含义、主体和功能,这会是一个很好的开始。如图1-3所示,在Fabric项目源码的根目录下,我们可以将所有子目录分为3类:源码目录、工程目录、第三方库。

图1-3 Fabric源码的根目录结构

Fabric项目源码目录的描述如表1-1所示。

表1-1 Fabric项目源码目录的描述

子目录

描述

bccsp

存放了以各种加解密算法、哈希算法为基础的PKI证书体系的工具,主要供MSP使用

cmd、internal

存放了Fabric中所有可生成二进制程序的main函数,如peer程序、configtxgen工具

common

存放了Fabric项目各模块或子领域公用的逻辑代码

core

存放了Fabric项目的核心领域代码,包含各个核心子模块的核心逻辑代码

discovery

存放了discovery服务模块代码。该模块以peer节点为服务端,向外提供通道配置信息查询服务

gossip

存放了gossip服务模块代码

msp

存放了MSP服务模块代码,该模块在Fabric区块链网络中对所有参与者进行MSP身份体系管理、认证

idemix

存放了Fabric项目实现另一种基于零知识证明的身份体系的代码实现,该身份体系被纳入MSP的管理范围

orderer

存放了orderer节点所实现的功能,如系统通道服务、共识服务、Broadcast服务、Deliver服务

pkg

存放了部分公用接口和数据结构定义,如交易、状态数据。可作为Fabric库,供与Fabric交互的第三方应用引用

protoutil

汇总了处理hyperledger项目下的fabric-protos-go仓库中数据结构和服务的工具性函数

Fabric项目引用的第三方库汇总在vendor目录下,其中由Fabric开发的第三方库,在vendor目录的hyperledger子目录下,如表1-2所示。

表1-2 由Fabric开发的第三方库的描述

子目录

描述

fabric-protos
fabric-protos-go

存放了供Fabric使用的protobuf数据结构、服务原型,以及由protoc工具编译生成的Go语言的数据结构和服务

fabric-chaincode-go

应用链码库,定义了应用链码的接口,实现了应用链码与背书节点通信的机制

Fabric项目源码的工程目录,一般用于项目自身的测试、编译、集成、文档生成等,主要是开发者关注和使用的目录,如docs目录用于项目通过Sphinx工具进行一体化文档集成,ci目录、integration目录用于集成化测试,images目录、scripts目录用于存放编译所用的镜像配置和脚本,sampleconfig目录用于存放配置示例。

在了解Fabric项目源码的目录结构后,我们可以了解一些Fabric项目在源码编写上的惯例。Fabric项目的源码编写十分规范,在目录、文件、接口、方法、对象的命名和使用上,形成了一些惯例,如表1-3所示。了解这些惯例,有助于大家更好地理解源码。

表1-3 Fabric项目源码编写的部分惯例

惯例

描述

common目录

存放了当级目录下公用的逻辑代码。如core/common目录存放了core目录下公用的逻辑代码

×××impl.go

接口定义与实现在源码文件上分离。×××一般为对象名称或缩写,×××.go文件中定义接口,×××impl.go文件中实现该接口,如msp.go与mspimpl.go

×××Provider

复杂对象一般存在对应的提供者。×××一般为对象名称或缩写,×××Provider则是用于创建该对象的提供者,如DB与DBProvider

×××Manager

复杂对象一般存在对应的管理者。×××一般为对象名称或缩写,×××Manager则是该对象的管理者,如msp/msp.go中,MSP与MSPManager

×××Support

复杂对象一般存在对应的支持者对象,让对象专注于自身逻辑,将其他的功能交由Support对象负责,如core/endorser/plugin_endorser.go中,PluginEndorser的支持对象PluginSupport

Legacy×××

遗留性质的函数或对象,用于兼容旧版本功能,×××一般为函数或对象名称,如core/scc/lscc/ lscc.go中的LegacySecurity

资源的聚合、继承

这里的资源指对象、函数等。A负责功能func1,B负责功能func2,C聚合或继承A和B。例如orderer/common/multichannel/registrar.go中的ledgerResources

[1] 引用自Fabric官方文档,版本为release-2.0。


配置是使用一个系统或理解系统功能的基础。本章首先叙述Fabric的配置所涉及的形式,然后从大到小,详细叙述Fabric区块链网络、通道、节点、MSP的配置。在后续章节讲述Fabric源码的过程中,将常常涉及配置,尤其是在初始化节点、子模块和对象的时候。

Fabric项目涉及较多的技术领域,如Go语言、PKI证书体系、Docker容器等,因而配置来源有多种形式,归纳总结如下。

Fabric使用上述配置形式的配置,有如下两个特性。

在具体部署时,节点一般以Docker容器的形式运行。在官方的默认镜像中,peer.yaml、orderer.yaml分别在peer节点容器、orderer节点容器中的/etc/hyperledger/fabric目录下。节点在配置文件的配置项和容器的环境变量是一一对应的,如core.yaml中peer下的id配置项,对应的环境变量为CORE_PEER_ID。再如orderer.yaml中General下的LedgerType配置项,对应的环境变量为ORDERER_GENERAL_LEDGERTYPE,依此类推。

提示

为释义清晰,本书在讲述源码的过程中,若涉及配置,也会以A.B.C的形式进行引用,如core.peer.id,指core.yaml中peer下的id配置项。

在源码层面,Fabric配置的管理主要使用第三方库viper(项目仓库为spf13/viper)实现。viper可以对环境变量、YAML/JSON等格式的配置文件,甚至是远程配置,进行读取和设置,是一个专用于处理配置的解决方案。viper提供的配置具有优先级,由低到高为“硬编码的默认配置 < 配置文件 < 环境变量 < 命令行参数 < viper.Set函数”。此外,viper对于配置项的大小写是不敏感的,在读取配置时,viper均会将配置项转化为小写,如对于3个配置abc=1、ABC=1或AbC=1,viper均视为同一个配置项abc。

viper的典型用法,也是Fabric使用的方式,如代码清单2-1所示。

代码清单2-1 viper的典型用法

1.  //1.viper读取环境变量
2.  viper.SetEnvPrefix("CORE")  //设置环境变量前缀,若为core,会将core变为大写并设为前缀
3.  viper.AutomaticEnv()        //获取当前系统所有以CORE为前缀的环境变量
4.  replacer := strings.NewReplacer(".", "_")  //将环境变量名称中的 . 换成 _
5.  viper.SetEnvKeyReplacer(replacer)   
6.  //2.viper获取配置文件
7.  viper.SetConfigName("config_name")   //设置配置文件名,不包含后缀,viper自动判断
8.  viper.AddConfigPath("/app/config/path")
9.  viper.AddConfigPath(".")             //设置查找配置文件的路径,可以有多个
10. viper.ReadInConfig()                 //读取配置文件中的所有配置项
11. viper.Get("common.name")             //获取common下name项的值
12. viper.Set("common.name", "Bill")     //将common下name项的值设置为Bill

Fabric区块链网络配置主要指系统通道(system channel)配置。系统通道配置主要定义了整个网络的所有联盟和orderer组织的信息,该配置作为第一个块,即创世纪块,在启动网络时被用作整个网络的基础配置。这里,我们从配置来源的角度讲述系统通道配置。生成系统通道配置的文件为configtx.yaml,参见sampleconfig/configtx.yaml,基本结构如图2-1所示。

图2-1 系统通道配置文件基本结构

在图2-1中,要理解configtx.yaml文件,除需理解YAML的基础知识外,重点需要理解configtx.yaml文件中“锚节点和引用”的用法,如第2行和第15行,使用类似于C语言中的取地址符号“&”,定义了锚节点SampleOrg、ChannelDefaults。引用锚节点共有两种方式,如第18行,在该处插入ChannelDefaults所有的下级配置项;如第21行,在该处直接插入SampleOrg配置项。

configtx.yaml文件主要由configtxgen程序使用,该程序使用Profiles下的配置项。Profiles下的配置项代表一个完整的通道配置,由configtxgen -profile指定。Profiles下的配置项更多通过引用上文定义的各类配置,汇总成自己的配置。该文件中主要的配置项含义如下。

应用通道配置定义了所使用的联盟和该联盟的参与者,原始数据也来自configtx.yaml,但这里,我们从通道账本的角度讲述应用通道配置。configtxgen工具依据configtx.yaml为创建应用通道生成的配置交易文件,为Envelope结构。创建时,应用通道会从已运行的系统通道中复制一部分系统通道配置,补充到自己的配置中,最终形成一个以配置为核心数据的区块,作为应用通道的第一个块,写入账本。

我们可以通过peer channel fetch 0命令,从应用通道获取第一个块,然后使用configtxlator工具,将区块转为可读的JSON格式,具体命令如下。

peer channel fetch config config_block.pb -o orderer.example.com:7050 -c mychannel --tls --cafile /path/to/orderer_ca#获取mychannel通道的最新配置块,存入config_block.pb文件中。
configtxlator proto_decode --input config_block.pb --type common.Block | jq .data.data[0].payload.data.config > config.json#使用configtxlator工具,从config_block.pb文件中读取数据,将配置从区块转为可读的JSON格式,并使用jq工具获取其中的配置,存入config.json文件中。

一个典型的JSON格式应用通道配置如图2-2所示。

图2-2 应用通道配置

从图2-2中,我们可以看出应用通道配置的如下特性。

包含系统通道配置。每一个应用通道配置都包含一个Application配置(第5~24行)和一个Orderer配置(第25行,在创建应用通道时,从系统通道配置中复制而来)。

递归性。配置的层级是递归的。顶层,即第3行的channel_group,就是一个组(groups),作为整个Fabric区块链网络的配置对象,对应fabric-protos-go仓库下common/ configtx.pb.go中定义的ConfigGroup。参见ConfigGroup的成员和对应的JSON标签,每一层配置都包含groups、policies、values、mod_policy和version这5个成员。

提示

Fabric中关于通道配置路径的表述有两种方式:经典路径方式和JSON路径方式。以图2-2中第 29 行所配置的区块链网络 Admins 策略为例,JSON 路径表示为 config.channel_groups. policies.Admins。经典路径则以简洁的标识组成,如Channel代表联盟网络根配置、Orderer代表系统通道,Application代表应用通道,经典路径表示为/Channel/Admins。

通道配置中的groups、values、mod_policy、version,较易于理解。但是policies则需基于配置的递归进行理解。在Fabric 2.0中,定义了多种类型的策略,应用在Fabric区块链网络中的各种主体和行为之上,细节会在第6章详述,这里可以将策略简单地理解为:以修改通道配置为例,因为一般只有管理员才能修改配置,策略规定了在当前层级哪些参与者的管理员同意的情况下,配置才能被修改。

图2-2中第29行,定义了顶层整个Fabric区块链网络配置的Admins策略,值为MAJORITY Admins,表示当层级(顶层)拥有2个子组参与者Application(第5行)、Orderer(第25行)的情况下,必须有半数以上的参与者的管理员同意修改Fabric区块链网络的配置,才满足该Admins策略。2的半数以上,即大于1,那只能是2个,即Application、Orderer的管理员都要同意。此时,若要Application的管理员同意,就需要满足Application下的Admins策略;若要Orderer的管理员同意,就需要满足Orderer下的Admins策略。

图2-2中应用通道Application的Admins策略在第18行指定,值也为MAJORITY Admins,即若要满足Application的Admins策略,就需要Application的2个子组参与者的半数以上同意修改配置,即Org1MSP(第7行)、Org2MSP(第14行)的管理员都要同意。此时,若要Org1MSP的管理员同意,就需要满足Org1MSP的Admins策略;若要Org2MSP的管理员同意,就需要满足Org2MSP的Admins策略。

如图2-3所示,Org1MSP的Admins策略在第6行(图左)指定,为Org1MSP.Admins,表示需要Org1MSP组织的管理员同意;Org2MSP的Admins策略在第7行(图右)指定,为Org2MSP.Admins,表示需要Org2MSP组织的管理员同意。

图2-3 子组Org1MSP(左)、Org2MSP(右)的Admins策略

系统通道Orderer下的Admins策略在图2-2中未显示,其设定值也为MAJORITY Admins。遵循的规则与Application一致,Orderer下只有一个参与者OrdererMSP,最终只需OrdererMSP组织的管理员同意,即可满足Orderer下的Admins策略。

当递归至Org1MSP、Org2MSP、OrdererMSP的Admins策略时,策略已经递归至某参与者下的某个具体角色身份,即已递归到底。如此,总结一下,要满足图2-2中第29行定义的顶层整个Fabric区块链网络配置的Admins策略,经策略递归,最终需要OrdererMSP、Org1MSP、Org2MSP这3个组织的管理员同意。

提示

应用通道配置和系统通道配置在逻辑上是一致的,主要的不同点在于:系统通道中主要包含Orderer、Consortiums两个子组,应用通道中主要包含Application、Orderer两个子组。此外,第一次创建应用通道时,应用通道对应的联盟和联盟的参与者,必须是系统通道配置中已定义的。当应用通道启动后,可自行管理联盟的参与者,如添加新组织。

peer节点的主要配置文件为core.yaml。由于peer节点一般以Docker容器的方式运行,因而在容器设置了对应环境变量时,core.yaml中的配置项会被覆盖。依据配置的优先级,覆盖动作由viper工具实现。peer节点的配置项过多,在此不一一列明,后续章节会根据需要,对涉及的配置进行引用和释义。参见sampleconfig/core.yaml,core.yaml的基础结构如图2-4所示。

图2-4 peer节点配置示例

在图2-4中,第1行,peer下是对peer节点的设置,多是与peer节点在Fabric区块链网络中进行交互时所使用的身份、服务认证相关的设置。

第12行,vm下是对peer节点所使用的虚拟机信息以及与宿主机虚拟机程序进行交互的相关设置,peer节点默认使用的虚拟机程序为Docker容器。

第14行,chaincode下是与链码相关的配置,在peer节点部署链码时使用。其中,定义了系统链码的开关,默认全部开启。

第18行,ledger下定义了peer节点在区块链网络中作为一个账本副本的记录者角色,对账本的类型、状态数据库、私有数据等方面进行设置。

第21行,operations下定义了peer节点的operations服务。peer节点作为服务端,这里主要设置了peer节点的监听地址、TLS(Transport Layer Security,传输层安全协议)连接配置。

第24行,metrics下定义了peer节点监测指标数据的设置。由provider指定监测服务:prometheus、statsd或disable。前者使用Prometheus系统,peer节点作为服务端提供RESTful接口,由Prometheus主动从peer节点拉取监测指标数据。后者则由peer节点主动将监测指标数据推送到statsd服务指定的地址和端口。disable则表示不启用监测功能。

当启动一个peer节点容器时,一个典型的容器配置如图2-5所示。

图2-5 peer节点容器配置示例

在图2-5中,第3行,image定义了peer节点使用的镜像为hyperledger/fabric-peer:2.0。第4行,environment下定义了启动peer节点容器后,容器运行环境中的环境变量,其中以CORE为前缀的环境变量的值将覆盖core.yaml文件中定义的对应配置值,如CORE_PEER_ID=peer0.org1. example.com将覆盖core.yaml文件中peer下的id配置项的值。

第11行,command定义了peer节点容器启动时自动执行的命令。在这里是peer node start命令,即在peer节点容器启动后,自动执行peer node start命令,对peer节点容器所要承担的各项服务进行初始化。

peer CLI执行命令时,以peer channel为例,读取配置的过程,如代码清单2-2所示。

代码清单2-2 cmd/peer/main.go

1.  const CmdRoot = "core"                 //在internal/peer/common/common.go中定义
2.  var mainCmd = &cobra.Command{Use: "peer"}//根命令peer
3.  func main() {
4.    viper.SetEnvPrefix(common.CmdRoot); viper.AutomaticEnv()
5.    replacer := strings.NewReplacer(".", "_"); viper.SetEnvKeyReplacer(replacer)
6.    mainFlags := mainCmd.PersistentFlags(); mainFlags.String("logging-level",...)
7.    mainCmd.AddCommand(channel.Cmd(nil))
8.    if mainCmd.Execute() != nil {os.Exit(1)}
9.  }

在代码清单2-2中,第4~5行,读取了所有以core(对大小写不敏感)为前缀的环境变量,并把环境变量的键中的.替换成_。

第6行,根命令添加参数支持,这里添加了logging-level,指定日志级别。

第7行,添加channel子命令,在internal/peer/channel/channel.go中实现,channel子命令执行时,调用了代码清单2-3所示的函数。

代码清单2-3 internal/peer/common/common.go

1.  const CmdRoot = "core"
2.  func InitCmd(cmd *cobra.Command, args []string) {
3.    err := InitConfig(CmdRoot)...  //调用下面的函数
4.  }
5.  func InitConfig(cmdRoot string) error {
6.    err := config.InitViper(nil, cmdRoot)
7.    err = viper.ReadInConfig()
8.  }

在代码清单2-3中,第6行,在core/config/config.go中实现,初始化了viper读取配置数据所需的两个关键项——配置文件所在路径和配置文件名。配置文件所在路径读取了环境变量FABRIC_CFG_PATH,若值不为空,则将之作为配置文件所在路径;否则,将当前路径./和/etc/hyperledger/fabric作为配置文件所在路径。配置文件名为core。

第7行,在配置文件所在路径下,搜索名为core的配置文件,并读取。该配置文件,一般为peer节点容器内部的/etc/hyperledger/fabric/core.yaml。

orderer节点的配置文件为orderer.yaml,同peer节点一样,orderer节点一般以Docker容器的方式启动,在这种情况下,orderer.yaml中的对应配置一样会被环境变量所覆盖。参见sampleconfig/ orderer.yaml,orderer.yaml的基础结构如图2-6所示。

图2-6 orderer节点配置示例

在图2-6中,第1行,General下定义orderer节点的设置,多是与orderer节点在Fabric区块链网络中进行交互时所使用的身份和服务认证相关的设置。其中General.Cluster是orderer作为共识集群节点的设置。

第9行,FileLedger下定义了orderer节点使用的账本的设置。

第12行,Kafka下定义了orderer节点与Kafka集群交互的设置,如是否启用TLS连接、重试间隔和超时时间等,当orderer节点使用Kafka类型的共识排序服务时,orderer节点为Kafka集群消息的生产者、消费者。

第13行,Debug下定义了追踪orderer节点的Broadcast、Deliver服务调用的记录的存储目录。

第16~17行,operations、metrics下定义了同peer节点一样的服务。

第18行,Consensus下定义了orderer节点使用etcdraft类型的共识排序服务时,作为etcdraft共识网络节点,使用的两个数据目录——日志目录WALDir和快照目录SnapDir。

当启动一个orderer节点容器时,一个典型的容器配置,与peer节点容器配置类似,如图2-7所示。

图2-7 orderer节点容器配置示例

orderer节点启动时,执行了orderer/common/server/main.go中的main函数。其中,调用了代码清单2-4中的函数,读取了配置。

代码清单2-4 orderer/common/localconfig/config.go

1.  type TopLevel struct {...}   //对应orderer.yaml中配置的结构
2.  var Defaults=TopLevel{...}   //默认配置
3.  func Load() (*TopLevel, error) {
4.    config := viper.New()
5.    coreconfig.InitViper(config, "orderer")
6.    config.SetEnvPrefix(Prefix)
7.    config.AutomaticEnv() //Prefix值为ORDERER
8.    replacer := strings.NewReplacer(".", "_")
9.    config.SetEnvKeyReplacer(replacer)
10.   if err := config.ReadInConfig(); err != nil {...}
11.   if err := viperutil.EnhancedExactUnmarshal(config, &uconf); err != nil {...}
12.   uconf.completeInitialization(filepath.Dir(config.ConfigFileUsed()))
13. }

在代码清单2-4中,第4~10行,使用viper工具,读取以ORDERER为前缀的环境变量,替换 . 为_。在配置文件所在路径下搜索名为orderer的配置文件,即orderer.yaml,并读取该文件。

第11行,将读取的配置解析到TopLevel中。

第12行,对于环境变量、orderer.yaml中未设置但又不能为空的配置项,使用Defaults中的默认值填补。

MSP(Membership Service Provider,成员服务提供者)对应的是组织,由组织的节点持有并使用,在Fabric区块链网络交互过程中,用于表明自己身份,验证他人身份。peer节点和orderer节点使用MSP的方式一样,这里以peer节点为例。在任一peer节点命令具体执行之前,在读取节点配置数据之后,会根据MSP的配置初始化本地的MSP,过程如代码清单2-5所示。

代码清单2-5 internal/peer/common/common.go

1.  func InitConfig(cmdRoot string) error {
2.    var mspMgrConfigDir=...;    var mspID=...;     var mspType=...
3.    err = InitCrypto(mspMgrConfigDir, mspID, mspType) //调用下面的函数
4.  }
5.  func InitCrypto(mspMgrConfigDir, localMSPID, localMSPType string) error {
6.    bccspConfig := factory.GetDefaultOpts()
7.    if config := viper.Get("peer.BCCSP"); config != nil {
8.      err = mapstructure.Decode(config, bccspConfig)...
9.    }
10.   err = mspmgmt.LoadLocalMspWithType(...,localMSPID,localMSPType)
11. }

在代码清单2-5中,第2行,使用viper工具,从peer节点配置数据中读取MSP的ID、路径、类型。

第6~9行,将从peer节点配置中获取的BCCSP配置,解析到BCCSP默认配置实例bccspConfig中。

第10行,使用MSP的路径、ID、类型、BCCSP配置实例,初始化本地MSP,具体过程在第3章中详述。但据此可知,MSP的关键配置信息有ID、路径、BCCSP配置、类型。其中,ID为MSP的ID,具有唯一性,由core.peer.localMspId指定。路径指MSP目录所在路径,由core.peer.mspConfigPath指定。若值是绝对路径,则直接使用;若值是相对路径,则该相对路径将与core.yaml所在路径(FABRIC_CFG_PATH、./或/etc/hyperledger/fabric)拼接成一个完整路径。

MSP目录下的证书,表示节点在网络中的身份和组织关系。参见hyperledger项目下Fabric官方示例仓库fabric-samples中的first-network/crypto-config.yaml,crypto-config.yaml的基本结构如图2-8所示。

图2-8 crypto-config.yaml的基本结构

在图2-8中,参见sampleconfig/msp,执行cryptogen generate --config=./crypto-config.yaml命令,生成的MSP目录结构如表2-1所示。

表2-1 MSP目录结构

子目录

描述

admincerts

组织的管理员证书

cacerts

CA证书,即发行组织节点证书、管理员证书的根证书

intermediatecerts

签发节点证书的中间CA证书,可选

keystore

节点使用的身份证书对应的私钥

signcerts

节点使用的身份证书,pem格式,代表节点的身份

tlscacerts

组织中节点TLS证书的根证书

tlsintermediatecerts

节点使用的TLS证书的中间CA证书,可选

crls

组织中因过期或注销而失效的节点签名证书,可选

operationcerts

专用于operation和metrics服务的证书,可选,示例中没有

config.yaml

节点组织角色验证功能的配置,可选。图2-8中,第4行,若开启了NodeOUs验证,则自动生成预定义的config.yaml文件

其中,config.yaml文件如图2-9所示。

图2-9 MSP目录下config.yaml文件示例

在图2-9中,通过config.yaml的配置,MSP可以利用X.509证书中的OU(Organization Unit,组织单元)字段(如图2-10所示,第一个OU字段特指角色主体,其余OU字段为正常的OU主体),以实现对身份更自主、更细致地验证,验证包括如下两类。

图2-10 X.509证书

Fabric 2.0中,预定义了4类角色OU标识:PeerOUIdentifier、OrdererOUIdentifier、ClientOUIdentifier、AdminOUIdentifier。合理情况下,各类角色职责如下。

依据上述角色的分类和限定,我们可以更细致、自主地管理Fabric区块链网络的参与者。但这牵扯到整个系统的配置工作,如设定背书策略为OR(Org1MSP.SYR),认定组织Org1MSP下的SYR负责背书交易,则需先通过Fabric CA或其他方法,签发一个OU字段值包含SYR的证书,并配置config.yaml。

BCCSP配置,指core.peer.BCCSP这部分的配置,用于初始化MSP使用的BCCSP实例。MSP实现了对Fabric区块链网络参与者的身份管理,包括对参与者关系的维护、身份的认证、身份的使用等,所用到的技术工具,就是BCCSP,如验证交易签名、计算交易数据哈希。关于BCCSP,将在第4章详述。

MSP有两种类型:BCCSP(默认)和IDEMIX。BCCSP为传统的以PKI证书的加解密技术为基础的身份认证方式,有软件方式的实现,如SW,也有第三方插件或硬件的实现方式PKCS11,如SoftHSM插件或HSM加密机。IDEMIX则是以零知识证明理论为基础的身份认证方式。


相关图书

微服务中台架构开发
微服务中台架构开发
数字突围:私域流量的用户数字化运营体系构建
数字突围:私域流量的用户数字化运营体系构建
关联数据:万维网上的结构化数据
关联数据:万维网上的结构化数据
互联网产品经理实务全书
互联网产品经理实务全书
Producter:让产品从0到1
Producter:让产品从0到1
产品经理游戏化设计思维70计
产品经理游戏化设计思维70计

相关文章

相关课程