Fabric在将交易发送到网络中之前,需要先向背书节点收集足够多的背书支持,同时采用专门的排序节点来负责整个网络中十分核心的排序环境。目前,网络中存在4种不同种类的服务节点,彼此写作完成整个区块链系统的功能。

    背书节点(Endorser):负责对交易提案(proposal)进行检查和背书,计算交易执行结果

    确认节点(Committer):负责在接受交易结果前再次检查合法性,接受合法交易对账本的修改,并写入区块链结构

    排序节点(Order):对所有发往网络中的交易进行排序,将排序后的交易按照配置中的约定整理为区块,之后提交给确认节点进行处理

    证书节点(CA):负责对网络中所有的证书进行管理,提供标准的PKI服务

  网络中支持多通道的特性。使用一条独立的系统通道(System channel)负责管理网络中的各种配置信息,并完成对其他应用通道(application channel,供用户发送交易使用)的创建。

  启动一个Fabric网络,需遵循如下主要步骤:

    1.预备网络內各项配置,包括网络中成员的组织结构和对应的身份证书(cryptogen);生成系统通道的初识配置区块文件,新建应用通道的配置,更新交易文件以及可能需要的锚节点配置更新交易文件(configtxgen)

    2.使用系统通道的初识配置区块文件启动排序节点,排序节点启动后自动按照制定配置创建系统通道

    3.不同的组织按照预置角色分别启动Peer节点。这个时候网络中不存在应用通道,Peer节点也并没有加入网络中  

    4.使用新建应用通道的配置更新交易文件,向系统通道发送交易,创建新的应用通道

    5.让对应的Peer节点加入所创建的应用通道中,此时Peer节点加入网络,可以准备接收交易了

    6.用户通过客户端向网络中安装注册链码,链码容器启动成功后用户即可对链码进行调用,将交易发送到网络中

 

  启动Fabric网络主要步骤包括计划拓扑,准备相关配置文件,启动Ordered节点,启动Peer节点和操作网络等。

  启动的Fabric网络中包括一个Ordered节点和四个Peer节点,以及一个管理节点生成相关启动文件,在网络启动后作为操作客户端执行命令。四个Peer节点分属于同一个管理域下的两个组织Org1和Org2。这两个组织都加入同一个应用通道中。每个组织中的第一个节点作为锚节点与其他组织进行通信,所有节点通过域名都可以互相访问。

  Fabric网络在启动之前,需要提前生成一些用于启动的配置文件,主要包括MSP相关文件(msp/*),TLS相关文件(tls/*),系统通道初识区块,新建应用通道交易文件,锚节点配置更新文件等。

配置 存放节点 依赖配置 主要功能
MSP相关文件msp/* Peer,Orderer,客户端 crypto-config.yaml 包括证书文件,签名私钥等,用于管理实体在网络中的身份信息
TLS相关文件tls/* Peer,Orderer,客户端 crypto-config.yaml 若网络中启用了TLS,则节点需要准备TLS证书
系统通道初识区块文件 orderer.genesis.block Orderer configtx.yaml 用于启动Ordering服务,配置网络中策略
新建应用通道交易文件businesschannel.tx 客户端 configtx.yaml 用于新建应用通道,指定通道成员,访问策略等

锚节点配置更新文件

Org1MSPanchors.tx和OrgMSPanchros.tx

客户端 configtx.yaml 用于配置通道中各组织的锚节点信息

 

 

 

 

 

 

 

  Fabric网络提供的是联盟链服务,联盟由多个组织构成,组织中的成员提供了节点服务来维护网络,并且通过身份来进行权限管理。因此首先需对各个组织和成员的关系进行规划,分别生成对应的身份证书文件,并部署到其对应的节点上。Fabric提供了cryptogen工具实现自动化生成,这一过程首先依赖crypto-config.yaml配置文件。crypto-config.yaml中定义了一个OrdererOrgs类型的组织Orderer,以及两个PeerOrgs类型的组织Org1和Org2。使用该配置文件通过命令$cryptogen generate --config=./crypto-config.yaml --output ./crypto-config生成指定的拓扑结构的组织和身份文件,存放到crypto-config目录下。

  Orderer节点在启动时,可以指定使用提前生成的初识区块文件作为系统通道的初识配置。初识区块中包括了Ordering服务的相关配置信息以及联盟信息。初识区块可以使用configtxgen工具进行生成。生成过程需要依赖/etc/hyperledger/fabric/configtx.yaml文件。configtx.yaml配置文件定义了整个网络中的相关配置和拓扑结构信息。该配置文件主要分为两个模板TwoOrgsOrdererGenesis和TwoOrgsChannel,前者可以用来生成Ordering服务的初识区块文件。通过使用$ configtxgen -profile TwoOrgsOrdererGenesis -outputBlock ./orderer.gensis.block来生成Ordering服务系统通道的初识区块文件。

  新建应用通道时,需要事先准备好配置交易文件,其中包括属于该通道的组织结构信息。这些信息会写入该应用通道的初识区块中。通过$ configtxgen -profile TwoOrgsChannel -outputCreateChannelTx ./businesschannel.tx -channelID ${CHANNEL_NAME}生成新建通道的配置交易文件。

  锚节点配置更新文件可以用来对组织的锚节点进行配置。

  

  启动Orderer节点

    首先检查启动节点的所有配置是否就绪:

      在/hyperledger/fabric路径下放置有编写好的orderer.yaml

      在/hyperledger/fabric路径下放置生成的msp文件目录,tls文件目录

      在/hyperledger/fabric路径下放置初识区块文件orderer.genesis.block

    启动一个Peer节点

      在/hyperledger/fabric路径下放置有对应编写好的core.yaml

      在/hyperledger/fabric路径下放置生成的对应msp文件,tls文件

 

  网络启动后,默认并不存在任何应用通道,需要手动创建应用通道,并让合作的Peer节点加入通道中。

  在客户端使用Org1的管理员身份来创建新的应用通道,需要指定msp的ID信息,msp文件所在路径,Orderering服务的tl证书位置,以及网络中Ordering服务地址,应用通道名称和交易文件。创建通道成功后,会自动在本地生成该应用通道同名的初识区块bussinesschannel.block文件。只有拥有该文件才可以加入创建的应用通道中。

  应用通道使用管理员身份依次让组织Org1和Org2中的所有节点都加入新的应用通道,需要指定所操作的Peer的地址,以及通道的初识区块。

  锚节点负责代表组织与其他组织中的节点进行Gossip通信。客户端使用管理员的身份来更新锚节点配置,需要指定msp的ID信息,msp文件所在路径,Ordering服务地址,所操作的应用通道,锚节点配置更新文件,以及Orderering服务tls证书位置

  Peer加入应用通道后,可以执行链码相关操作,进行测试。链码在调用之前,必须经过安装和实例化两个步骤,部署到Peer节点上。

  监听事件

    用户可以通过block-listener工具来监听网络中的事件。该工具支持的命令行选项包括

      -events-address "0.0.0.0:7053" :监听事件的来源地址,一般为Peer节点的7053接口

      -events-from-chaincode string:仅监听与指定链码相关的事件

      -events-mspdir string:本地所使用的MSP路径,默认在sampleconfig下

      -events-mspid string:所使用的MSP的ID

  链上代码(chaincode)。简称链码。一般指用户编写的应用代码。链码被部署在Fabric网络节点上,运行在Docker中,并通过gRPC协议与相应的Peer节点进行交互,以操作分布式账本中的数据。用户可以通过命令行方式操作链码,支持的链码子命令包括install,instantiate,invoke,query,upgrade,packag,signpackage等。

 

 

  安装链码

    install命令将链码的源码和环境等内容封装为一个链码安装打包文件(Chaincode Install Package, CIP),并传输到背书节点。背书节点解析后一般会保存在$CORE_PEER_FILESYSTEMPATH/chaincodes目录下。安装链码只需要与Peer打交道

    打包文件以name.version命名,主要包括:

      ChaincodeDeploymentSpec:链码的源码和一些相关环境

      链码实例化策略,默认是任意通道上的MSP管理员身份

      拥有这个链码的实体的证书和签名

      安装时,本地MSP管理员的签名

    ChaincodeDeploymentSpec(CDS)结构包括了最核心的ChaincodeSpec(CS)数据结构,同时也被其他链码命令使用。

  主要步骤包括:

    1.首先是构造签名提案消息(SignedProposal)

      调用InitCmdFactory(isEndorserRequired, isOrdererRequired bool)(*ChaincodeCmdFactory,error)方法,初始化EndoserClient,Signer等结构。

      根据命令行参数进行解析,判断是根据传入的打包文件直接读取ChaincodeDeploymentSpec(CDS)结构,还是根据传入参数从本地链码文件来重新构造

      以本地重新构造情况为例,首先根据命令行中传入的路径,名称等信息,构造生成ChaincodeSpec(CS)结构

      利用ChaincodeSpec结构,结合链码包数据生成一个ChaincodeDeploymentSpec结构,调用本地的install(msg proto.Message, cf *ChaincodeCmdFactory,error)方法

      install方法基于传入的ChaincodeDeploymentSpec结构,构造成一个对生命周期管理系统链码(LSCC)调用的ChaincodeSpec结构,其中Type为ChaincodeSpec_GOLANG,ChaincodeId.Name为“lscc”,Input为“install”+ChaincodeDeploymentSpec。进一步地,构造一个LSCC地ChaincodeInvokcationSpec(CIS)结构,对ChaincodeSpec结构进行封装

      基于LSCC地ChaincodeInvocationSpec结构,添加头部结构,生成一个提案(Proposal)结构,其中,通道头部中类型为ENDORSER_TRANSACTION,TxID为对随机数+签名实体,进行Hash  

      对Proposal进行签名,转化为一个签名后的提案消息SignedProposal

    2.通过EndorserClient经由gRPC通道发送给Peer的ProcessProposal(ctx context.Context, in *SignedProposal, opts ...grpc.CallOption)(*PropoalResponse, error)接口

    3.Peer模式运行生命周期链码的调用交易进行处理,检查格式,签名和权限等,通过则保存到本地文件系统

  

  实例化链码

    instantiate命令通过构造生命周期管理系统链码(Lifecycle System Chaincode, LSCC)的交易,将安装过的链码在指定通道上进行实例化调用,在节点上创建容器启动,并执行初始化操作。实例化链码需要同时跟Peer和Orderer打交道。

    执行instantiate命令的用户身份必须满足实例化的策略,并且在所指定的通道上拥有写权限。在instantiate命令中通过-P参数指定链码的背书策略(Endorsement Policy),不满足背书策略的链码调用将在Commit阶段被作废。

  主要步骤包括:

    1.首先,类似链码安装命令,需要创建一个SignedProposal消息。注意instantiate和upgrade支持policy,escc,vscc等参数,LSCC的ChaincodeSpec结构中,Input中包括类型("deploy"),通道ID,ChaincodeDeploymentSpec结构,背书策略,escc和vscc等。

    2.调用EndorserClient,发送gRPC消息,将签名后的Proposal发给指定的Peer节点(Endorser),调用ProcessProposal(ctx context.Context, in *SignedProposal, opts ...grpc.CallOption)(*ProposalResponse, error)方法,进行背书处理。节点会模拟运行LSCC的调用交易,启动链码容器。实例化成功后会返回ProposalResponse消息。

    3.根据Peere返回的ProposalResponse消息,创建一个SignedTX(Envelop结构的交易,带有签名)

    4.使用BroadcastClient将交易消息通过gRPC通道发给Orderer,Orderer会进行全网排序,并广播给Peer进行交易确认

 

  调用链码

    通过invoke命令可以调用运行中的链码的方法。“-c”参数指定的函数名和参数会被传入到链码的Invoke()方法进行处理。调用链码操作需要同时跟Peer和Orderer打交道。invoke命令不支持指定链码版本,只能调用最新版本的链码。invoke是异步操作,invoke成功只能保证交易已经进入Orderer进行排序,但无法保障最终写到账本中,有可能交易未通过Committer验证而被拒绝。需要通过eventHub或查询方式来进行确认交易是否最终写入到账本上

    主要步骤如下:

      1.创建一个SignedProposal消息。根据传入的各种参数,生成ChaincodeSpec结构。然后根绝ChaincodeSpec,chainID,签名尸体等,生成ChaincodeInvocationSpec结构。进而封装生成Proposal结构,并进行签名。

      2.调用EndorserClient,发送gRPC消息,将签名后的Proposal发给指定的Peer节点,调用ProcessProsal(ctc context.Context, in *SignedProposal, opts ...grpc.CallOption)(*ProposalResponse, error)方法,进行背书处理。节点会模拟运行链码调用交易,成功后会返回ProposalResponse消息

      3.根据Peer返回的ProposalResponse消息,创建一个SignedTX(Envelop结构的交易,带有签名)

      4.使用BroadcastClient将交易消息通过gRPC通道发给Orderer进行全网排序并广播给Peer进行确认提交

 

  查询链码

    查询链码可以通过query命令进行。query命令的执行过程与invoke命令类似,实际上同样是将-c指定的命令参数发送给链码中的Invoke()方法执行。与invoke的区别在与,query操作只能查询Peer上账本状态,不生成交易,也不需要与Orderer打交道。query不需要穿件SignedTx发送到Orderer,而且返回会查询结果

    主要过程如下:

      1.根据传入的各种参数,最终构造签名提案,通过endorsercClient发送给指定的Peer

      2.成功的话,获取到ProposalResponse,打印出proposalResp.Response.Payload内容

    

  升级链码

    当需要修复链码漏洞或进行功能拓展时,可以对链码进行升级,部署新版本的链码。主要步骤如下:

      1.安装新版本的链码,打包到Peer节点

      2.运行upgrade命令升级指定通道上的链码,需要指定相同的链码名称

    升级过程会将给定的参数传入新链码的Init()方法中执行。只要Init()方法中对应的逻辑不改写状态,则升级前后链码的所有状态值可以保持不变。若链码将来要考虑在保留状态情况下升级,需要在编写Init()方法时妥善处理升级时的逻辑。

   升级操作实现的主要过程如下:

      1.首先创建一个封装了LSCC调用交易的SignedProposal消息,

      2.调用EndorserClient,发送gRPC消息,将签名后的Proposal发送给指定的Peer节点,调用ProcessProposal(ctx context.Context, in *SignedProposal, opts ...grpc.CallOption)(*ProposalResponse, error)方法进行背书处理,节点会模拟运行LSCC的调用交易,启动链码容器

      3.根据Peer返回的ProposalResponse消息,创建一个SignedTX(Envelop结构的交易,带有签名)

      4.使用BroadcastClient将交易消息通过gRPC通道发给Orderer,Orderer会进行全网排序,并广播给Peer进行确认提交

 

  打包链码和签名

    通过将链码相关的数据进行封装,可以事先对其进行打包和签名的操作。打包命令支持三个特定参数:

      -s,--cc-package:表示创建完整打包形式,而不是仅打包ChaincodeDeploymentSpec结构

      -S,--sign:对打包的文件使用本地的MSP(core.yaml中的localMspid指定)进行签名

      -i,--instantiate-policy string:指定实例化策略,可选参数

     打包后的文件可以直接用于install操作。

    签名命令则对一个打包文件进行签名操作(添加当前MSP签名到签名列表中)。打包文件结构主要包括以下三部分信息:

      ChaincodeDeploymentSpec结构

      实例化策略信息

      拥有者的签名列表

    事先的整体流程如下:

      1.首先会调用InitCmdFactory(isEndorserRequired, isOrdererRequired bool)(*ChainCmdFactory, error)方法初始化Signer等结构。对于打包命令来说纯属本地操作,不需要Endorser和Orderer的链接

      2.调用getChaincodeSpec()方法,解析命令行参数,根据所指定的数据生成ChaincodeSpec结构

      3.根据ChaincodeSpec结构,结合链码相关数据构造ChaincodeDeploymentSpec结构,并传入getChaincodeInstallPakcage方法

      4.getChaincodeInstallPackage方法基于传入的ChaincodeDeploymentSpec结构,添加实例化策略和签名信息等,生成一个SignedChaincodeDeploymentSpec,并进一步作为Data生成一个Envlope结构,其中ChannelHeader指定为CHAINCODE_PACKAGE

      5.将Envelope结构序列化,写到指定的本地文件

 

  使用多通道

    命令行下peer channel命令支持包括create,fetch,join,list,update等子命令。

      create:创建一个新的应用通道

      join:将本Peer节点加入到某个应用通道中

      list:列出本Peer已经加入的所有的应用通道

      fetch:从Ordering服务获取指定应用通道的配置区块

      update:更新通道的配置信息,如锚节点配置

    默认情况下,客户端执行命令会以本地的Peer为操作对象,若要操作远端的Peer,需要通过环境配置指定Peer的相关信息,包括地址或MSP配置等。并且执行命令的用户身份需要以组织管理员身份进行。

 

  创建通道

    拥有创建通道权限的组织管理员身份才能调用create子命令,在指定的Ordering服务上创建新的应用通道,需要提供Ordering服务地址。通过提前创建的通道配置交易文件来指定配置信息。若不指定通道配置文件,则默认采用SampleConsortium配置和本地的MSP组织来构造配置交易结构。加入成功后,本地会产生该应用通道的初识区块文件businesschannel.block。Ordering服务端也会输出类似order|UTC[order/multichain] new Chain -> INFO 004 Created and starting new chain newchannel的成功消息

    主要步骤包括:

      1.客户端调用sendCreateChainTransaction(),检查指定的配置交易文件,或利用默认配置,构造一个创建应用通道的配置交易结构,封装为Envelope,指定channel头部为CONFIG_UPDATE

      2.客户端发送配置交易到Ordering服务

      3.Orderer收到CONFIG_UPDATE消息后,检查指定的通道还不存在,则开始新建过成,构造该应用的初识区块

        1.Orderer首先检查通道应用配置中的组织是否都在创建的联盟配置组织汇中

        2.之后从系统通道中获取Orderer相关的配置,并创建应用通道配置,对应mod_policy为系统通道配置中的联盟指定信息  

        3.根据CONFIG_UPDATE消息的内容更新获取到的配置信息。所有配置发生变更后版本号都要更新

        4.最后,创建签名Proposal消息(头部类型为ORDERER_TRANSACTION),发送到系统通道中,完成应用通道的创建过程

      4.客户端利用gRPC通道从Orderer服务获取到该应用通道的初识区块

      5.客户端将收到的区块写入到本地的chainID+".block"文件。这个文件后续会被需要加入到通道的节点使用

   

  加入通道

    join子命令会让指定的Peer节点加入到指定的应用通道。需要提前拥有所加入应用通道的初识区块文件,并且只有属于通道的某个组织的管理员身份可以成功执行该操作。加入通道命令主要通过调用Peer的配置系统链码进行处理

    主要步骤包括:

      1.客户端首先创建一个ChaincodeSpec结构,其input中的Args第一参数是CSCC,JoinChain,第二个操作为所加入通道的初识区块

      2.利用ChaincodeSpec构造一个ChaincodeInvocationSpec结构

      3.利用ChaincodeInvocationSpec,创建Proposal结构并进行签名,channel头部类型为CONFIG

      4.客户端通过gRPC将Proposal签名后发给Endorser,调用ProcessProposal(ctx context.Context, in *SignedProposal, opts ...grpc.CallOption)(*ProposalResponse, error)方法进行处理,主要通过配置系统链码进行本地链的初始化工作

      5.初始化完成后,即可收到来自通道内的Gossip消息等

 

  列入所加入的通道

    list子命令会列出指定的Peer节点已经加入的所有应用通道的列表。加入通道的命令也是主要通过调用Peer的配置系统链码进行处理

    主要步骤包括:

      1.客户端首先创建一个ChaincodeSpec结构,其中input中的Args第一个参数是CSCC.GetChannels

      2.利用ChaincodeSpec构造一个ChaincodeInvocationSpec结构

      3.利用ChaincodeInvocationSpec创建Proposal结构并进行签名,channel头部类型为ENDORSER_TRANSACTION

      4.客户端通过gRPC将Proposal发送给Endorser,调用ProcessProposal(ctx context.Context, in *SignedProposal, opts ...grpc.CallOption)(*ProposalResponse, error)方法进行处理,主要是通过配置系统链码查询本地链信息并返回

      5.命令执行成功后,客户端会收到来自Peer端的回复消息,从其中提取出应用通道列表信息并输出

 

  获取某区块

    fetch子命令会向Ordering服务进行查询,获取到指定通道的指定区块。并将收到的区块写入到本地的文件。命令格式为peer channel fetch <newest|oldest|config|(number)> [outputfile] [flags]

    主要步骤包括:

      1.客户端构造SeekInfo结构,该结构可以指定要获取的区块范围。这里start,stop指定为目标区块

      2.客户端利用SeekInfo结构,构造Envelope并进行签名,通过deliverClient经gRPC通道发给Ordering服务

      3.从Orderer获取指定通道的区块后,写到本地文件中

 

  更新通道配置

    update子命令的执行过程与create命令类似,会向Ordering服务发起更新配置交易请求。该命令执行也需要提前创建的通道更新配置交易文件来指定配置信息。

   

  生产环境注意事项

    节点角色差异

      Fabric网络中各个节点可以拥有不同的角色。不同角色的众多节点负责整个网络功能中不同环节的工作负载,呈现了差异化的处理特性

      Ordering服务需要处理整个网络中所有的交易消息。Orderer节点采用Kafka集群进行排序,本地维护了网络中所有通道的区块结构。对于Orderer节点需要加强内存,存储,网络IO方面的配置,并且采用集群的方式提高可靠性

      Peer节点处理处理区块和背书交易之外,还需要对账本状态进行更新,对身份进行认证。同时,对于每个通道来说,加入通道的节点都需要维护一个针对该通道的账本结构和区块链结构。因此,Peer节点则在计算,内存等方面需要进行强化配置,Endorser还可以在签名计算方面进行加权。对于打开文件句柄较多的节点。可能还需要对系统的uliit等参数进行调整。一般来讲,链码容器常常跟Peer节点处在同一服务器上,建议为主服务预留2GB以上的空闲内存,并且一般每个链码容器分配256MB运行内存和1/10的CPU核资源。

    日志级别

      日志级别越低,输出日志内容越详细,出现问题后越方便调试。但输出过多的日志会拖慢系统的吞吐性能。对于关键路径上的系统,通常要配置不低于Warning级别的日志输出;对于非关键路径上的系统,则可以采用不低于Info级别的日志输出。

    链码升级

      Fabric升级时会调用链码中的Init方法。通过合适地设计链码,对其进行升级操作并不需要整个网络的共识,因此对部分节点上链码版本升级后,违背升级的节点仍然会运行旧版本的链码。从数据一致性上考虑,在对某链码代码进行升级前,推荐先将所有该链码的容器停止,并从Peer上备份并移除旧链码部署文件,之后先在个别Peer节点上部署新链码,对原有数据进行测试,成功后再其他节点上进行升级操作。另外,在一开始编写链码过程中,需要考虑链码升级操作,通过传入Init参数指定特定的升级方法来保护原有数据

    组织结构

      组织代表了维护网络的独立成员身份。一般来说,组成联盟链的各个成员,每个都拥有代表自己身份的组织。一个组织可以进一步包括多个资源实体,这些资源实体彼此具有较强的信任度,并且对外都呈现同一组织身份。由于Gossip协议目前在MSP范围内进行传播,因此一般建议将组织与MSP一一对应,即每个组织拥有自己专属的MSP。当一个组织拥有多个MSP时,不同成员之间的交互可能会带来障碍;当多个组织同属于一个MSP时,可能会发生不希望的跨组织数据泄漏。另外,一个组织可以包括多个成员身份,多个Peer可以通过使用同一成员身份来提高可用性。

    证书管理

      Fabric网络中给你,CA负责证书的管理。CA占据网络中安全和隐私的最核心位置,因此需要加强安全方面的防护。CA不应该暴漏在公共网络域中,并且只能由有限个具备权限的用户访问。另外,根证书往往要进行离线保护,减少解除和泄漏的可能性。通常使用中间层证书来完成实体证书的签发。同时,绝对不能直接用根证书作为组织管理员的身份证书