淘先锋技术网

首页 1 2 3 4 5 6 7

搭建一个3orderer节点、4个组织,其中每个组织各2个peer节点的fabric区块链网络,前期已完成网络测试和链码调用测试(使用的官方sacc)均能成功。于是我想试试能不能将基于hyperledger fabric v2.x 的学历征信系统 的项目改为多组织架构,目前只对fixtures文件夹以及sdkInit文件夹和main.go函数里涉及到网络架构的部分进行了修改。

在配置完config.yaml,sdk部分和main.go后,go build 通过,但go启动时报错

>> 开始创建通道......
>> Create channel and join error: Create channel error: Channel management client create error: failed to create resmgmt client due to context error: invalid options to create identity, invalid org name

目录

1.版本

docker镜像

git

go

docker

docker-compose

2. 解决思路

①根据https://github.com/akkagao/citizens 提到的相同错误

②setup函数

③ createChannel函数

3. 项目目录和代码片

我的项目目录如下

​编辑

configtx.yaml文件如下

 config.yaml 文件如下

sdkInfo.go 文件如下

sdkSetting.go文件如下


1.版本

docker镜像

root@model:~/go# docker images
REPOSITORY                   TAG       IMAGE ID       CREATED         SIZE
hyperledger/fabric-tools     latest    545af418d284   4 months ago    489MB
hyperledger/fabric-peer      latest    d77dd7cfbcd7   4 months ago    64.2MB
hyperledger/fabric-orderer   latest    77c489caa81b   4 months ago    36.7MB
hyperledger/fabric-ccenv     latest    4eb7ee7f4af5   4 months ago    520MB
hyperledger/fabric-baseos    latest    b20d2dde6941   4 months ago    6.82MB
hyperledger/fabric-ca        latest    93f19fa873cb   8 months ago    76.5MB
portainer/portainer-ce       latest    0df02179156a   15 months ago   273MB

其中fabric是2.4.7,fabric-ca是1.5.5

git

root@model:~/go# git --version
git version 2.17.1

go

root@model:~/go# go version
go version go1.18.6 linux/amd64

docker

root@model:~/go# docker version
Client: Docker Engine - Community
 Version:           23.0.1
 API version:       1.42
 Go version:        go1.19.5
 Git commit:        a5ee5b1
 Built:             Thu Feb  9 19:46:49 2023
 OS/Arch:           linux/amd64
 Context:           default

Server: Docker Engine - Community
 Engine:
  Version:          23.0.1
  API version:      1.42 (minimum version 1.12)
  Go version:       go1.19.5
  Git commit:       bc3805a
  Built:            Thu Feb  9 19:46:49 2023
  OS/Arch:          linux/amd64
  Experimental:     false
 containerd:
  Version:          1.6.18
  GitCommit:        2456e983eb9e37e47538f59ea18f2043c9a73640
 runc:
  Version:          1.1.4
  GitCommit:        v1.1.4-0-g5fd4c4d
 docker-init:
  Version:          0.19.0
  GitCommit:        de40ad0

docker-compose

root@model:~/go# docker-compose -v
docker-compose version 1.29.2, build 5becea4c


2. 解决思路


①根据https://github.com/akkagao/citizens 提到的相同错误

 指的应该是下图OrgName部分

但我看我main.go的配置信息和configtx.yaml中好像是一致的,如果将main函数的orgname改成org1msp,则会报错

>> SDK setup error: non-existent organization: 'Org1MSP'

所以填org1应该是没问题的。

依据sdkSetting.go,出错位置可能在

②setup函数

中后方根据指定的资源管理客户端Context创建通道管理客户端失败
(但报的错是英文所以不一定是在这里,但我也没有在其他地方找到这句错误)


传入的是orgContext,这就是org.OrgAdminUser或者org.OrgName有错误

③ createChannel函数

 依据函数内容,就是OrdererClientContext有问题,它也出现在setup函数末尾

 所以应该是和↓(main.go文件的main函数)传入的OrdererAdminUser、OrdererOrgName有关

但我对照了我自己的配置文件,应该没有问题。
又或许是多组织时main函数部分获取的不只一个org,或者我的config.yaml 中client部分配置不对?
因为我之前没有完整地学过fabric,网上并不能找到完整的讲解多组织网络下sdk应用的案例,搜索错误信息也只有上面那一个例子还比较模糊,卡了好久就是一个不知所措==

3. 项目目录和代码片

我的项目目录如下


 

configtx.yaml文件如下

Organizations:

    # SampleOrg defines an MSP using the sampleconfig.  It should never be used
    # in production but may be used as a template for other definitions
    - &OrdererOrg
        # DefaultOrg defines the organization which is used in the sampleconfig
        # of the fabric.git development environment
        Name: OrdererOrg

        # ID to load the MSP definition as
        ID: OrdererMSP

        # MSPDir is the filesystem path which contains the MSP configuration
        MSPDir: crypto-config/ordererOrganizations/example.com/msp

        # Policies defines the set of policies at this level of the config tree
        # For organization policies, their canonical path is usually
        #   /Channel/<Application|Orderer>/<OrgName>/<PolicyName>
        Policies:
            Readers:
                Type: Signature
                Rule: "OR('OrdererMSP.member')"
            Writers:
                Type: Signature
                Rule: "OR('OrdererMSP.member')"
            Admins:
                Type: Signature
                Rule: "OR('OrdererMSP.admin')"
        OrdererEndpoints:
            - orderer0.example.com:7050
            - orderer1.example.com:8050
            - orderer2.example.com:9050            

    - &Org1
        # DefaultOrg defines the organization which is used in the sampleconfig
        # of the fabric.git development environment
        Name: Org1MSP

        # ID to load the MSP definition as
        ID: Org1MSP

        MSPDir: crypto-config/peerOrganizations/org1.supervisor.com/msp

        # Policies defines the set of policies at this level of the config tree
        # For organization policies, their canonical path is usually
        #   /Channel/<Application|Orderer>/<OrgName>/<PolicyName>
        Policies:
            Readers:
                Type: Signature
                Rule: "OR('Org1MSP.admin', 'Org1MSP.peer', 'Org1MSP.client')"
            Writers:
                Type: Signature
                Rule: "OR('Org1MSP.admin', 'Org1MSP.client')"
            Admins:
                Type: Signature
                Rule: "OR('Org1MSP.admin')"
            Endorsement:
                Type: Signature
                Rule: "OR('Org1MSP.peer')"

        # leave this flag set to true.
        AnchorPeers:
            # AnchorPeers defines the location of peers which can be used
            # for cross org gossip communication.  Note, this value is only
            # encoded in the genesis block in the Application section context
            - Host: peer0.org1.supervisor.com
              Port: 7051

    - &Org2
        # DefaultOrg defines the organization which is used in the sampleconfig
        # of the fabric.git development environment
        Name: Org2MSP

        # ID to load the MSP definition as
        ID: Org2MSP

        MSPDir: crypto-config/peerOrganizations/org2.build.com/msp

        # Policies defines the set of policies at this level of the config tree
        # For organization policies, their canonical path is usually
        #   /Channel/<Application|Orderer>/<OrgName>/<PolicyName>
        Policies:
            Readers:
                Type: Signature
                Rule: "OR('Org2MSP.admin', 'Org2MSP.peer', 'Org2MSP.client')"
            Writers:
                Type: Signature
                Rule: "OR('Org2MSP.admin', 'Org2MSP.client')"
            Admins:
                Type: Signature
                Rule: "OR('Org2MSP.admin')"
            Endorsement:
                Type: Signature
                Rule: "OR('Org2MSP.peer')"

        AnchorPeers:
            # AnchorPeers defines the location of peers which can be used
            # for cross org gossip communication.  Note, this value is only
            # encoded in the genesis block in the Application section context
            - Host: peer0.org2.build.com
              Port: 9051

    - &Org3
        # DefaultOrg defines the organization which is used in the sampleconfig
        # of the fabric.git development environment
        Name: Org3MSP

        # ID to load the MSP definition as
        ID: Org3MSP

        MSPDir: crypto-config/peerOrganizations/org3.supplier.com/msp

        # Policies defines the set of policies at this level of the config tree
        # For organization policies, their canonical path is usually
        #   /Channel/<Application|Orderer>/<OrgName>/<PolicyName>
        Policies:
            Readers:
                Type: Signature
                Rule: "OR('Org3MSP.admin', 'Org3MSP.peer', 'Org3MSP.client')"
            Writers:
                Type: Signature
                Rule: "OR('Org3MSP.admin', 'Org3MSP.client')"
            Admins:
                Type: Signature
                Rule: "OR('Org3MSP.admin')"
            Endorsement:
                Type: Signature
                Rule: "OR('Org3MSP.peer')"

        AnchorPeers:
            # AnchorPeers defines the location of peers which can be used
            # for cross org gossip communication.  Note, this value is only
            # encoded in the genesis block in the Application section context
            - Host: peer0.org3.supplier.com
              Port: 11051

    - &Org4
        # DefaultOrg defines the organization which is used in the sampleconfig
        # of the fabric.git development environment
        Name: Org4MSP

        # ID to load the MSP definition as
        ID: Org4MSP

        MSPDir: crypto-config/peerOrganizations/org4.logistics.com/msp

        # Policies defines the set of policies at this level of the config tree
        # For organization policies, their canonical path is usually
        #   /Channel/<Application|Orderer>/<OrgName>/<PolicyName>
        Policies:
            Readers:
                Type: Signature
                Rule: "OR('Org4MSP.admin', 'Org4MSP.peer', 'Org4MSP.client')"
            Writers:
                Type: Signature
                Rule: "OR('Org4MSP.admin', 'Org4MSP.client')"
            Admins:
                Type: Signature
                Rule: "OR('Org4MSP.admin')"
            Endorsement:
                Type: Signature
                Rule: "OR('Org4MSP.peer')"

        AnchorPeers:
            # AnchorPeers defines the location of peers which can be used
            # for cross org gossip communication.  Note, this value is only
            # encoded in the genesis block in the Application section context
            - Host: peer0.org4.logistics.com
              Port: 13051

################################################################################
#
#   SECTION: Capabilities
#
#   - This section defines the capabilities of fabric network. This is a new
#   concept as of v1.1.0 and should not be utilized in mixed networks with
#   v1.0.x peers and orderers.  Capabilities define features which must be
#   present in a fabric binary for that binary to safely participate in the
#   fabric network.  For instance, if a new MSP type is added, newer binaries
#   might recognize and validate the signatures from this type, while older
#   binaries without this support would be unable to validate those
#   transactions.  This could lead to different versions of the fabric binaries
#   having different world states.  Instead, defining a capability for a channel
#   informs those binaries without this capability that they must cease
#   processing transactions until they have been upgraded.  For v1.0.x if any
#   capabilities are defined (including a map with all capabilities turned off)
#   then the v1.0.x peer will deliberately crash.
#
################################################################################
Capabilities:
    # Channel capabilities apply to both the orderers and the peers and must be
    # supported by both.
    # Set the value of the capability to true to require it.
    Channel: &ChannelCapabilities
        # V2_0 capability ensures that orderers and peers behave according
        # to v2.0 channel capabilities. Orderers and peers from
        # prior releases would behave in an incompatible way, and are therefore
        # not able to participate in channels at v2.0 capability.
        # Prior to enabling V2.0 channel capabilities, ensure that all
        # orderers and peers on a channel are at v2.0.0 or later.
        V2_0: true

    # Orderer capabilities apply only to the orderers, and may be safely
    # used with prior release peers.
    # Set the value of the capability to true to require it.
    Orderer: &OrdererCapabilities
        # V2_0 orderer capability ensures that orderers behave according
        # to v2.0 orderer capabilities. Orderers from
        # prior releases would behave in an incompatible way, and are therefore
        # not able to participate in channels at v2.0 orderer capability.
        # Prior to enabling V2.0 orderer capabilities, ensure that all
        # orderers on channel are at v2.0.0 or later.
        V2_0: true

    # Application capabilities apply only to the peer network, and may be safely
    # used with prior release orderers.
    # Set the value of the capability to true to require it.
    Application: &ApplicationCapabilities
        # V2_0 application capability ensures that peers behave according
        # to v2.0 application capabilities. Peers from
        # prior releases would behave in an incompatible way, and are therefore
        # not able to participate in channels at v2.0 application capability.
        # Prior to enabling V2.0 application capabilities, ensure that all
        # peers on channel are at v2.0.0 or later.
        V2_0: true

################################################################################
#
#   SECTION: Application
#
#   - This section defines the values to encode into a config transaction or
#   genesis block for application related parameters
#
################################################################################
Application: &ApplicationDefaults

    # Organizations is the list of orgs which are defined as participants on
    # the application side of the network
    Organizations:

    # Policies defines the set of policies at this level of the config tree
    # For Application policies, their canonical path is
    #   /Channel/Application/<PolicyName>
    Policies:
        Readers:
            Type: ImplicitMeta
            Rule: "ANY Readers"
        Writers:
            Type: ImplicitMeta
            Rule: "ANY Writers"
        Admins:
            Type: ImplicitMeta
            Rule: "MAJORITY Admins"
        LifecycleEndorsement:
            Type: ImplicitMeta
            Rule: "MAJORITY Endorsement"
        Endorsement:
            Type: ImplicitMeta
            Rule: "MAJORITY Endorsement"

    Capabilities:
        <<: *ApplicationCapabilities
################################################################################
#
#   SECTION: Orderer
#
#   - This section defines the values to encode into a config transaction or
#   genesis block for orderer related parameters
#
################################################################################
Orderer: &OrdererDefaults

    # Orderer Type: The orderer implementation to start
    OrdererType: etcdraft
    
    # Addresses used to be the list of orderer addresses that clients and peers
    # could connect to.  However, this does not allow clients to associate orderer
    # addresses and orderer organizations which can be useful for things such
    # as TLS validation.  The preferred way to specify orderer addresses is now
    # to include the OrdererEndpoints item in your org definition
    Addresses:
        - orderer0.example.com:7050
        - orderer1.example.com:8050
        - orderer2.example.com:9050

    EtcdRaft:
        Consenters:
        - Host: orderer0.example.com
          Port: 7050
          ClientTLSCert: crypto-config/ordererOrganizations/example.com/orderers/orderer.example.com/tls/server.crt
          ServerTLSCert: crypto-config/ordererOrganizations/example.com/orderers/orderer.example.com/tls/server.crt

    # Batch Timeout: The amount of time to wait before creating a batch
    BatchTimeout: 2s

    # Batch Size: Controls the number of messages batched into a block
    BatchSize:

        # Max Message Count: The maximum number of messages to permit in a batch
        MaxMessageCount: 10

        # Absolute Max Bytes: The absolute maximum number of bytes allowed for
        # the serialized messages in a batch.
        AbsoluteMaxBytes: 99 MB

        # Preferred Max Bytes: The preferred maximum number of bytes allowed for
        # the serialized messages in a batch. A message larger than the preferred
        # max bytes will result in a batch larger than preferred max bytes.
        PreferredMaxBytes: 512 KB

    # Organizations is the list of orgs which are defined as participants on
    # the orderer side of the network
    Organizations:

    # Policies defines the set of policies at this level of the config tree
    # For Orderer policies, their canonical path is
    #   /Channel/Orderer/<PolicyName>
    Policies:
        Readers:
            Type: ImplicitMeta
            Rule: "ANY Readers"
        Writers:
            Type: ImplicitMeta
            Rule: "ANY Writers"
        Admins:
            Type: ImplicitMeta
            Rule: "MAJORITY Admins"
        # BlockValidation specifies what signatures must be included in the block
        # from the orderer for the peer to validate it.
        BlockValidation:
            Type: ImplicitMeta
            Rule: "ANY Writers"

################################################################################
#
#   CHANNEL
#
#   This section defines the values to encode into a config transaction or
#   genesis block for channel related parameters.
#
################################################################################
Channel: &ChannelDefaults
    # Policies defines the set of policies at this level of the config tree
    # For Channel policies, their canonical path is
    #   /Channel/<PolicyName>
    Policies:
        # Who may invoke the 'Deliver' API
        Readers:
            Type: ImplicitMeta
            Rule: "ANY Readers"
        # Who may invoke the 'Broadcast' API
        Writers:
            Type: ImplicitMeta
            Rule: "ANY Writers"
        # By default, who may modify elements at this config level
        Admins:
            Type: ImplicitMeta
            Rule: "MAJORITY Admins"

    # Capabilities describes the channel level capabilities, see the
    # dedicated Capabilities section elsewhere in this file for a full
    # description
    Capabilities:
        <<: *ChannelCapabilities

################################################################################
#
#   Profile
#
#   - Different configuration profiles may be encoded here to be specified
#   as parameters to the configtxgen tool
#
################################################################################
Profiles:

    FourOrgsOrdererGenesis:
        <<: *ChannelDefaults
        Orderer:
            <<: *OrdererDefaults
            OrdererType: etcdraft
            EtcdRaft:
                Consenters:
                - Host: orderer0.example.com
                  Port: 7050
                  ClientTLSCert: crypto-config/ordererOrganizations/example.com/orderers/orderer0.example.com/tls/server.crt
                  ServerTLSCert: crypto-config/ordererOrganizations/example.com/orderers/orderer0.example.com/tls/server.crt
                - Host: orderer1.example.com
                  Port: 8050
                  ClientTLSCert: crypto-config/ordererOrganizations/example.com/orderers/orderer1.example.com/tls/server.crt
                  ServerTLSCert: crypto-config/ordererOrganizations/example.com/orderers/orderer1.example.com/tls/server.crt
                - Host: orderer2.example.com
                  Port: 9050
                  ClientTLSCert: crypto-config/ordererOrganizations/example.com/orderers/orderer2.example.com/tls/server.crt
                  ServerTLSCert: crypto-config/ordererOrganizations/example.com/orderers/orderer2.example.com/tls/server.crt
            Addresses:
                - orderer0.example.com:7050
                - orderer1.example.com:8050
                - orderer2.example.com:9050
            Organizations:
                - *OrdererOrg
            Capabilities:
                <<: *OrdererCapabilities
        Consortiums:
            SampleConsortium:
                Organizations:
                    - *Org1
                    - *Org2
                    - *Org3
                    - *Org4

    FourOrgsChannel:
        Consortium: SampleConsortium
        <<: *ChannelDefaults
        Application:
            <<: *ApplicationDefaults
            Organizations:
                - *Org1
                - *Org2
                - *Org3
                - *Org4
            Capabilities:
                <<: *ApplicationCapabilities

 config.yaml 文件如下

name: "my-network"
version: 1.0.0

client:
  organization: Org1
  logging:
    level: info
  cryptoconfig:
    path: ${GOPATH}/src/raft-test/fixtures/crypto-config
  credentialStore:
    path: 
    cryptoStore:
      path: 
  BCCSP:
    security:
     enabled: true
     default:
      provider: "SW"
     hashAlgorithm: "SHA2"
     softVerify: true
     level: 256

  tlsCerts:
    systemCertPool: false

    client:
      key:
        path:
      cert:
        path:


channels:
  mychannel:
    peers:
      peer0.org1.supervisor.com:
        endorsingPeer: true
        chaincodeQuery: true
        ledgerQuery: true
        eventSource: true
      peer1.org1.supervisor.com:
        endorsingPeer: true
        chaincodeQuery: true
        ledgerQuery: true
        eventSource: true
      
      peer0.org2.build.com:
        endorsingPeer: true
        chaincodeQuery: true
        ledgerQuery: true
        eventSource: true
      peer1.org2.build.com:
        endorsingPeer: true
        chaincodeQuery: true
        ledgerQuery: true
        eventSource: true

      peer0.org3.supplier.com:
        endorsingPeer: true
        chaincodeQuery: true
        ledgerQuery: true
        eventSource: true
      peer1.org3.supplier.com:
        endorsingPeer: true
        chaincodeQuery: true
        ledgerQuery: true
        eventSource: true

      peer0.org4.logistics.com:
        endorsingPeer: true
        chaincodeQuery: true
        ledgerQuery: true
        eventSource: true
      peer1.org4.logistics.com:
        endorsingPeer: true
        chaincodeQuery: true
        ledgerQuery: true
        eventSource: true

    policies:
      queryChannelConfig:
        minResponses: 1
        maxTargets: 1
        retryOpts:
          attempts: 5
          initialBackoff: 500ms
          maxBackoff: 5s
          backoffFactor: 2.0
      discovery:
        maxTargets: 2
        retryOpts:
          attempts: 4
          initialBackoff: 500ms
          maxBackoff: 5s
          backoffFactor: 2.0
      eventService:
        resolverStrategy: PreferOrg
        balancer: Random
        blockHeightLagThreshold: 5
        reconnectBlockHeightLagThreshold: 10
        peerMonitorPeriod: 5s


organizations:
  Org1:
    mspid: org1.supervisor.com
    cryptoPath: peerOrganizations/org1.supervisor.com/users/[email protected]/msp
    peers:
      - peer0.org1.supervisor.com
      - peer1.org1.supervisor.com
    # certificateAuthorities:
    #   - ca.org1.supervisor.com
    #因为报错SDK setup error: 根据指定的资源管理客户端Context创建通道管理客户端失败: failed to create resmgmt client due to context error: user not found
    users:
      Admin:
        cert:
          path: /root/go/src/raft-test/fixtures/crypto-config/peerOrganizations/org1.supervisor.com/users/[email protected]/msp/signcerts/[email protected]
        key:
          path: /root/go/src/raft-test/fixtures/crypto-config/peerOrganizations/org1.supervisor.com/users/[email protected]/msp/keystore/priv_sk   
    
  Org2:
    mspid: org2.build.com
    cryptoPath: peerOrganizations/org2.build.com/users/[email protected]/msp
    peers:
      - peer0.org2.build.com
      - peer1.org2.build.com 
    # certificateAuthorities:
    #   - ca.org2.build.com
    #同上
    users:
      Admin:
        cert:
          path: /root/go/src/raft-test/fixtures/crypto-config/peerOrganizations/org2.build.com/users/[email protected]/msp/signcerts/[email protected]
        key:
          path: /root/go/src/raft-test/fixtures/crypto-config/peerOrganizations/org2.build.com/users/[email protected]/msp/keystore/priv_sk

  Org3:
    mspid: org3.supplier.com
    cryptoPath: peerOrganizations/org3.supplier.com/users/[email protected]/msp
    peers:
      - peer0.org3.supplier.com
      - peer1.org3.supplier.com
    # certificateAuthorities:
    #   - ca.org3.supplier.com
    #同上
    users:
      Admin:
        cert:
          path: /root/go/src/raft-test/fixtures/crypto-config/peerOrganizations/org3.supplier.com/users/[email protected]/msp/signcerts/[email protected]
        key:
          path: /root/go/src/raft-test/fixtures/crypto-config/peerOrganizations/org3.supplier.com/users/[email protected]/msp/keystore/priv_sk

  Org4:
    mspid: org4.logistics.com
    cryptoPath: peerOrganizations/org4.logistics.com/users/[email protected]/msp
    peers:
      - peer0.org4.logistics.com
      - peer1.org4.logistics.com
    # certificateAuthorities:
    #   - ca.org4.logistics.com
    #同上
    users:
      Admin:
        cert:
          path: /root/go/src/raft-test/fixtures/crypto-config/peerOrganizations/org4.logistics.com/users/[email protected]/msp/signcerts/[email protected]
        key:
          path: /root/go/src/raft-test/fixtures/crypto-config/peerOrganizations/org4.logistics.com/users/[email protected]/msp/keystore/priv_sk

orderers:
  orderer0.example.com:
    url: localhost:7050
    grpcOptions:
      ssl-target-name-override: orderer0.example.com
      keep-alive-time: 0s
      keep-alive-timeout: 20s
      keep-alive-permit: false
      fail-fast: false
      allow-insecure: false
    tlsCACerts:
      path: ${GOPATH}/src/raft-test/fixtures/crypto-config/ordererOrganizations/example.com/tlsca/tlsca.example.com-cert.pem

  orderer1.example.com:
    url: localhost:8050
    grpcOptions:
      ssl-target-name-override: orderer1.example.com
      keep-alive-time: 0s
      keep-alive-timeout: 20s
      keep-alive-permit: false
      fail-fast: false
      allow-insecure: false
    tlsCACerts:
      path: ${GOPATH}/src/raft-test/fixtures/crypto-config/ordererOrganizations/example.com/tlsca/tlsca.example.com-cert.pem

  orderer2.example.com:
    url: localhost:9050
    grpcOptions:
      ssl-target-name-override: orderer2.example.com
      keep-alive-time: 0s
      keep-alive-timeout: 20s
      keep-alive-permit: false
      fail-fast: false
      allow-insecure: false
    tlsCACerts:
      path: ${GOPATH}/src/raft-test/fixtures/crypto-config/ordererOrganizations/example.com/tlsca/tlsca.example.com-cert.pem


peers:
  #org1
  peer0.org1.supervisor.com:
    url: localhost:7051
    eventUrl: localhost:7051

    grpcOptions:
      ssl-target-name-override: peer0.org1.supervisor.com
      keep-alive-time: 0s
      keep-alive-timeout: 20s
      keep-alive-permit: false
      fail-fast: false
      allow-insecure: false

    tlsCACerts:
      path: ${GOPATH}/src/raft-test/fixtures/crypto-config/peerOrganizations/org1.supervisor.com/tlsca/tlsca.org1.supervisor.com-cert.pem

  peer1.org1.supervisor.com:
    url: localhost:8051
    eventUrl: localhost:8051

    grpcOptions:
      ssl-target-name-override: peer1.org1.supervisor.com
      keep-alive-time: 0s
      keep-alive-timeout: 20s
      keep-alive-permit: false
      fail-fast: false
      allow-insecure: false

    tlsCACerts:
      path: ${GOPATH}/src/raft-test/fixtures/crypto-config/peerOrganizations/org1.supervisor.com/tlsca/tlsca.org1.supervisor.com-cert.pem
#org2
  peer0.org1.supervisor.com:
    url: localhost:9051
    eventUrl: localhost:9051

    grpcOptions:
      ssl-target-name-override: peer0.org2.build.com
      keep-alive-time: 0s
      keep-alive-timeout: 20s
      keep-alive-permit: false
      fail-fast: false
      allow-insecure: false

    tlsCACerts:
      path: ${GOPATH}/src/raft-test/fixtures/crypto-config/peerOrganizations/org2.build.com/tlsca/tlsca.org2.build.com-cert.pem

  peer1.org1.supervisor.com:
    url: localhost:10051
    eventUrl: localhost:10051

    grpcOptions:
      ssl-target-name-override: peer1.org2.build.com
      keep-alive-time: 0s
      keep-alive-timeout: 20s
      keep-alive-permit: false
      fail-fast: false
      allow-insecure: false

    tlsCACerts:
      path: ${GOPATH}/src/raft-test/fixtures/crypto-config/peerOrganizations/org2.build.com/tlsca/tlsca.org2.build.com-cert.pem
#org3
  peer0.org1.supervisor.com:
    url: localhost:11051
    eventUrl: localhost:11051

    grpcOptions:
      ssl-target-name-override: peer0.org3.supplier.com
      keep-alive-time: 0s
      keep-alive-timeout: 20s
      keep-alive-permit: false
      fail-fast: false
      allow-insecure: false

    tlsCACerts:
      path: ${GOPATH}/src/raft-test/fixtures/crypto-config/peerOrganizations/org3.supplier.com/tlsca/tlsca.org3.supplier.com-cert.pem

  peer1.org1.supervisor.com:
    url: localhost:12051
    eventUrl: localhost:12051

    grpcOptions:
      ssl-target-name-override: peer1.org3.supplier.com
      keep-alive-time: 0s
      keep-alive-timeout: 20s
      keep-alive-permit: false
      fail-fast: false
      allow-insecure: false

    tlsCACerts:
      path: ${GOPATH}/src/raft-test/fixtures/crypto-config/peerOrganizations/org3.supplier.com/tlsca/tlsca.org3.supplier.com-cert.pem
#org4
  peer0.org1.supervisor.com:
    url: localhost:13051
    eventUrl: localhost:13051

    grpcOptions:
      ssl-target-name-override: peer0.org4.logistics.com
      keep-alive-time: 0s
      keep-alive-timeout: 20s
      keep-alive-permit: false
      fail-fast: false
      allow-insecure: false

    tlsCACerts:
      path: ${GOPATH}/src/raft-test/fixtures/crypto-config/peerOrganizations/org4.logistics.com/tlsca/tlsca.org4.logistics.com-cert.pem

  peer1.org1.supervisor.com:
    url: localhost:14051
    eventUrl: localhost:14051

    grpcOptions:
      ssl-target-name-override: peer1.org4.logistics.com
      keep-alive-time: 0s
      keep-alive-timeout: 20s
      keep-alive-permit: false
      fail-fast: false
      allow-insecure: false

    tlsCACerts:
      path: ${GOPATH}/src/raft-test/fixtures/crypto-config/peerOrganizations/org4.logistics.com/tlsca/tlsca.org4.logistics.com-cert.pem

# certificateAuthorities:
#   ca.org1.kevin.kongyixueyuan.com:
#     url: http://localhost:7054
#     tlsCACerts:
#       path: ${GOPATH}/src/github.com/kongyixueyuan.com/education/fixtures/crypto-config/peerOrganizations/org1.kevin.kongyixueyuan.com/ca/ca.org1.kevin.kongyixueyuan.com-cert.pem

#     registrar:
#       enrollId: admin
#       enrollSecret: adminpw
#     caName: ca.org1.kevin.kongyixueyuan.com

entityMatchers:
  peer:
#org1
    - pattern: (\w*)peer0.org1.supervisor.com(\w*)
      urlSubstitutionExp: localhost:7051
      eventUrlSubstitutionExp: localhost:7051
      sslTargetOverrideUrlSubstitutionExp: peer0.org1.supervisor.com
      mappedHost: peer0.org1.supervisor.com
    - pattern: (\w*)peer1.org1.supervisor.com(\w*)
      urlSubstitutionExp: localhost:8051
      eventUrlSubstitutionExp: localhost:8051
      sslTargetOverrideUrlSubstitutionExp: peer1.org1.supervisor.com
      mappedHost: peer1.org1.supervisor.com
#org2
    - pattern: (\w*)peer0.org2.build.com(\w*)
      urlSubstitutionExp: localhost:9051
      eventUrlSubstitutionExp: localhost:9051
      sslTargetOverrideUrlSubstitutionExp: peer0.org2.build.com
      mappedHost: peer0.org2.build.com
    - pattern: (\w*)peer1.org2.build.com(\w*)
      urlSubstitutionExp: localhost:10051
      eventUrlSubstitutionExp: localhost:10051
      sslTargetOverrideUrlSubstitutionExp: peer1.org2.build.com
      mappedHost: peer1.org2.build.com
#org3
    - pattern: (\w*)peer0.org3.supplier.com(\w*)
      urlSubstitutionExp: localhost:11051
      eventUrlSubstitutionExp: localhost:11051
      sslTargetOverrideUrlSubstitutionExp: peer0.org3.supplier.com
      mappedHost: peer0.org3.supplier.com
    - pattern: (\w*)peer1.org3.supplier.com(\w*)
      urlSubstitutionExp: localhost:12051
      eventUrlSubstitutionExp: localhost:12051
      sslTargetOverrideUrlSubstitutionExp: peer1.org3.supplier.com
      mappedHost: peer1.org3.supplier.com
#org4 
    - pattern: (\w*)peer0.org4.logistics.com(\w*)
      urlSubstitutionExp: localhost:13051
      eventUrlSubstitutionExp: localhost:13051
      sslTargetOverrideUrlSubstitutionExp: peer0.org4.logistics.com
      mappedHost: peer0.org4.logistics.com
    - pattern: (\w*)peer1.org4.logistics.com(\w*)
      urlSubstitutionExp: localhost:14051
      eventUrlSubstitutionExp: localhost:14051
      sslTargetOverrideUrlSubstitutionExp: peer1.org4.logistics.com
      mappedHost: peer1.org4.logistics.com            

  orderer:
    - pattern: (\w*)orderer0.example.com(\w*)
      urlSubstitutionExp: localhost:7050
      sslTargetOverrideUrlSubstitutionExp: orderer0.example.com
      mappedHost: orderer0.example.com
    - pattern: (\w*)orderer1.example.com(\w*)
      urlSubstitutionExp: localhost:8050
      sslTargetOverrideUrlSubstitutionExp: orderer1.example.com
      mappedHost: orderer1.example.com
    - pattern: (\w*)orderer2.example.com(\w*)
      urlSubstitutionExp: localhost:9050
      sslTargetOverrideUrlSubstitutionExp: orderer2.example.com
      mappedHost: orderer2.example.com

sdkInfo.go 文件如下

package sdkInit

import (
    mspclient "github.com/hyperledger/fabric-sdk-go/pkg/client/msp"
    "github.com/hyperledger/fabric-sdk-go/pkg/client/resmgmt"
    contextAPI "github.com/hyperledger/fabric-sdk-go/pkg/common/providers/context"
)

type OrgInfo struct {
    OrgAdminUser          string // like "Admin"
    OrgName               string // like "Org1"
    OrgMspId              string // like "Org1MSP"
    OrgUser               string // like "User1"
    orgMspClient          *mspclient.Client
    OrgAdminClientContext *contextAPI.ClientProvider
    OrgResMgmt            *resmgmt.Client
    OrgPeerNum            int
    //Peers                 []*fab.Peer
    OrgAnchorFile string // like ./channel-artifacts/Org2MSPanchors.tx
}

type SdkEnvInfo struct {
    // 通道信息
    ChannelID     string // like "simplecc"
    ChannelConfig string // like os.Getenv("GOPATH") + "/src/github.com/hyperledger/fabric-samples/test-network/channel-artifacts/testchannel.tx"

    // 组织信息
    Orgs []*OrgInfo
    // 排序服务节点信息
    OrdererAdminUser     string // like "Admin"
    OrdererOrgName       string // like "OrdererOrg"
    OrdererEndpoint      string
    OrdererClientContext *contextAPI.ClientProvider
    // 链码信息
    ChaincodeID      string
    ChaincodeGoPath  string
    ChaincodePath    string
    ChaincodeVersion string
}

sdkSetting.go文件如下

package sdkInit

import (
    "fmt"
    mb "github.com/hyperledger/fabric-protos-go/msp"
    pb "github.com/hyperledger/fabric-protos-go/peer"
    "github.com/hyperledger/fabric-sdk-go/pkg/client/channel"
    mspclient "github.com/hyperledger/fabric-sdk-go/pkg/client/msp"
    "github.com/hyperledger/fabric-sdk-go/pkg/client/resmgmt"
    "github.com/hyperledger/fabric-sdk-go/pkg/common/errors/retry"
    "github.com/hyperledger/fabric-sdk-go/pkg/common/errors/status"
    "github.com/hyperledger/fabric-sdk-go/pkg/common/providers/fab"
    "github.com/hyperledger/fabric-sdk-go/pkg/common/providers/msp"
    "github.com/hyperledger/fabric-sdk-go/pkg/core/config"
    lcpackager "github.com/hyperledger/fabric-sdk-go/pkg/fab/ccpackager/lifecycle"
    "github.com/hyperledger/fabric-sdk-go/pkg/fabsdk"
    "github.com/hyperledger/fabric-sdk-go/third_party/github.com/hyperledger/fabric/common/policydsl"
    "strings"
)

func Setup(configFile string, info *SdkEnvInfo) (*fabsdk.FabricSDK, error) {
    // Create SDK setup for the integration tests
    var err error
    sdk, err := fabsdk.New(config.FromFile(configFile))
    if err != nil {
        return nil, err
    }

    // 为组织获得Client句柄和Context信息
    for _, org := range info.Orgs {
        org.orgMspClient, err = mspclient.New(sdk.Context(), mspclient.WithOrg(org.OrgName))
        if err != nil {
            return nil, err
        }
        orgContext := sdk.Context(fabsdk.WithUser(org.OrgAdminUser), fabsdk.WithOrg(org.OrgName))
        org.OrgAdminClientContext = &orgContext

        // New returns a resource management client instance.
        resMgmtClient, err := resmgmt.New(orgContext)
        if err != nil {
            return nil, fmt.Errorf("根据指定的资源管理客户端Context创建通道管理客户端失败: %v", err)
        }
        org.OrgResMgmt = resMgmtClient
    }

    // 为Orderer获得Context信息
    ordererClientContext := sdk.Context(fabsdk.WithUser(info.OrdererAdminUser), fabsdk.WithOrg(info.OrdererOrgName))
    info.OrdererClientContext = &ordererClientContext
    return sdk, nil
}

func CreateAndJoinChannel(info *SdkEnvInfo) error {
    fmt.Println(">> 开始创建通道......")
    if len(info.Orgs) == 0 {
        return fmt.Errorf("通道组织不能为空,请提供组织信息")
    }

    // 获得所有组织的签名信息
    signIds := []msp.SigningIdentity{}
    for _, org := range info.Orgs {
        // Get signing identity that is used to sign create channel request
        orgSignId, err := org.orgMspClient.GetSigningIdentity(org.OrgAdminUser)
        if err != nil {
            return fmt.Errorf("GetSigningIdentity error: %v", err)
        }
        signIds = append(signIds, orgSignId)
    }

    // 创建通道
    if err := createChannel(signIds, info); err != nil {
        return fmt.Errorf("Create channel error: %v", err)
    }

    fmt.Println(">> 创建通道成功")

    fmt.Println(">> 加入通道......")
    for _, org := range info.Orgs {
        // 加入通道
        // Org peers join channel
        if err := org.OrgResMgmt.JoinChannel(info.ChannelID, resmgmt.WithRetry(retry.DefaultResMgmtOpts), resmgmt.WithOrdererEndpoint("orderer.example.com")); err != nil {
            return fmt.Errorf("%s peers failed to JoinChannel: %v", org.OrgName, err)
        }
    }
    fmt.Println(">> 加入通道成功")
    return nil
}

func createChannel(signIDs []msp.SigningIdentity, info *SdkEnvInfo) error {
    // Channel management client is responsible for managing channels (create/update channel)
    chMgmtClient, err := resmgmt.New(*info.OrdererClientContext)
    if err != nil {
        return fmt.Errorf("Channel management client create error: %v", err)
    }

    // create a channel for orgchannel.tx
    req := resmgmt.SaveChannelRequest{ChannelID: info.ChannelID,
        ChannelConfigPath: info.ChannelConfig,
        SigningIdentities: signIDs}

    if _, err := chMgmtClient.SaveChannel(req, resmgmt.WithRetry(retry.DefaultResMgmtOpts), resmgmt.WithOrdererEndpoint("orderer.example.com")); err != nil {
        return fmt.Errorf("error should be nil for SaveChannel of orgchannel: %v", err)
    }

    fmt.Println(">>>> 使用每个org的管理员身份更新锚节点配置...")
    //do the same get ch client and create channel for each anchor peer as well (first for Org1MSP)
    for i, org := range info.Orgs {
        req = resmgmt.SaveChannelRequest{ChannelID: info.ChannelID,
            ChannelConfigPath: org.OrgAnchorFile,
            SigningIdentities: []msp.SigningIdentity{signIDs[i]}}

        if _, err = org.OrgResMgmt.SaveChannel(req, resmgmt.WithRetry(retry.DefaultResMgmtOpts), resmgmt.WithOrdererEndpoint("orderer.example.com")); err != nil {
            return fmt.Errorf("SaveChannel for anchor org %s error: %v", org.OrgName, err)
        }
    }
    fmt.Println(">>>> 使用每个org的管理员身份更新锚节点配置完成")
    //integration.WaitForOrdererConfigUpdate(t, configQueryClient, mc.channelID, false, lastConfigBlock)
    return nil
}

func CreateCCLifecycle(info *SdkEnvInfo, sequence int64, upgrade bool, sdk *fabsdk.FabricSDK) error {
    if len(info.Orgs) == 0 {
        return fmt.Errorf("the number of organization should not be zero.")
    }
    // Package cc
    fmt.Println(">> 开始打包链码......")
    label, ccPkg, err := packageCC(info.ChaincodeID, info.ChaincodeVersion, info.ChaincodePath)
    if err != nil {
        return fmt.Errorf("pakcagecc error: %v", err)
    }
    packageID := lcpackager.ComputePackageID(label, ccPkg)
    fmt.Println(">> 打包链码成功")

    // Install cc
    fmt.Println(">> 开始安装链码......")
    if err := installCC(label, ccPkg, info.Orgs); err != nil {
        return fmt.Errorf("installCC error: %v", err)
    }

    // Get installed cc package
    if err := getInstalledCCPackage(packageID, info.Orgs[0]); err != nil {
        return fmt.Errorf("getInstalledCCPackage error: %v", err)
    }

    // Query installed cc
    if err := queryInstalled(packageID, info.Orgs[0]); err != nil {
        return fmt.Errorf("queryInstalled error: %v", err)
    }
    fmt.Println(">> 安装链码成功")

    // Approve cc
    fmt.Println(">> 组织认可智能合约定义......")
    if err := approveCC(packageID, info.ChaincodeID, info.ChaincodeVersion, sequence, info.ChannelID, info.Orgs, info.OrdererEndpoint); err != nil {
        return fmt.Errorf("approveCC error: %v", err)
    }

    // Query approve cc
    if err:=queryApprovedCC(info.ChaincodeID, sequence, info.ChannelID, info.Orgs);err!=nil{
        return fmt.Errorf("queryApprovedCC error: %v", err)
    }
    fmt.Println(">> 组织认可智能合约定义完成")

    // Check commit readiness
    fmt.Println(">> 检查智能合约是否就绪......")
    if err:=checkCCCommitReadiness(packageID, info.ChaincodeID, info.ChaincodeVersion, sequence, info.ChannelID, info.Orgs); err!=nil{
        return fmt.Errorf("checkCCCommitReadiness error: %v", err)
    }
    fmt.Println(">> 智能合约已经就绪")

    // Commit cc
    fmt.Println(">> 提交智能合约定义......")
    if err:=commitCC(info.ChaincodeID, info.ChaincodeVersion, sequence, info.ChannelID, info.Orgs, info.OrdererEndpoint);err!=nil{
        return fmt.Errorf("commitCC error: %v", err)
    }
    // Query committed cc
    if err:=queryCommittedCC(info.ChaincodeID, info.ChannelID, sequence, info.Orgs); err!=nil{
        return fmt.Errorf("queryCommittedCC error: %v", err)
    }
    fmt.Println(">> 智能合约定义提交完成")

    // Init cc
    fmt.Println(">> 调用智能合约初始化方法......")
    if err:=initCC(info.ChaincodeID, upgrade, info.ChannelID, info.Orgs[0], sdk); err!=nil{
        return fmt.Errorf("initCC error: %v", err)
    }
    fmt.Println(">> 完成智能合约初始化")
    return nil
}

func packageCC(ccName, ccVersion, ccpath string) (string, []byte, error) {
    label := ccName + "_" + ccVersion
    desc := &lcpackager.Descriptor{
        Path:  ccpath,
        Type:  pb.ChaincodeSpec_GOLANG,
        Label: label,
    }
    ccPkg, err := lcpackager.NewCCPackage(desc)
    if err != nil {
        return "", nil, fmt.Errorf("Package chaincode source error: %v", err)
    }
    return desc.Label, ccPkg, nil
}

func installCC(label string, ccPkg []byte, orgs []*OrgInfo) error {
    installCCReq := resmgmt.LifecycleInstallCCRequest{
        Label:   label,
        Package: ccPkg,
    }

    packageID := lcpackager.ComputePackageID(installCCReq.Label, installCCReq.Package)
    for _, org := range orgs {
        orgPeers, err := DiscoverLocalPeers(*org.OrgAdminClientContext, org.OrgPeerNum)
        if err != nil {
            fmt.Errorf("DiscoverLocalPeers error: %v", err)
        }
        if flag, _ := checkInstalled(packageID, orgPeers[0], org.OrgResMgmt); flag == false {
            if _, err := org.OrgResMgmt.LifecycleInstallCC(installCCReq, resmgmt.WithTargets(orgPeers...), resmgmt.WithRetry(retry.DefaultResMgmtOpts)); err != nil {
                return fmt.Errorf("LifecycleInstallCC error: %v", err)
            }
        }
    }
    return nil
}

func getInstalledCCPackage(packageID string, org *OrgInfo) error {
    // use org1
    orgPeers, err := DiscoverLocalPeers(*org.OrgAdminClientContext, 1)
    if err != nil {
        return fmt.Errorf("DiscoverLocalPeers error: %v", err)
    }

    if _, err := org.OrgResMgmt.LifecycleGetInstalledCCPackage(packageID, resmgmt.WithTargets([]fab.Peer{orgPeers[0]}...)); err != nil {
        return fmt.Errorf("LifecycleGetInstalledCCPackage error: %v", err)
    }
    return nil
}

func queryInstalled(packageID string, org *OrgInfo) error {
    orgPeers, err := DiscoverLocalPeers(*org.OrgAdminClientContext, 1)
    if err != nil {
        return fmt.Errorf("DiscoverLocalPeers error: %v", err)
    }
    resp1, err := org.OrgResMgmt.LifecycleQueryInstalledCC(resmgmt.WithTargets([]fab.Peer{orgPeers[0]}...))
    if err != nil {
        return fmt.Errorf("LifecycleQueryInstalledCC error: %v", err)
    }
    packageID1 := ""
    for _, t := range resp1 {
        if t.PackageID == packageID {
            packageID1 = t.PackageID
        }
    }
    if !strings.EqualFold(packageID, packageID1) {
        return fmt.Errorf("check package id error")
    }
    return nil
}

func checkInstalled(packageID string, peer fab.Peer, client *resmgmt.Client) (bool, error) {
    flag := false
    resp1, err := client.LifecycleQueryInstalledCC(resmgmt.WithTargets(peer))
    if err != nil {
        return flag, fmt.Errorf("LifecycleQueryInstalledCC error: %v", err)
    }
    for _, t := range resp1 {
        if t.PackageID == packageID {
            flag = true
        }
    }
    return flag, nil
}

func approveCC(packageID string, ccName, ccVersion string, sequence int64, channelID string, orgs []*OrgInfo, ordererEndpoint string) error {
    mspIDs := []string{}
    for _, org := range orgs {
        mspIDs = append(mspIDs, org.OrgMspId)
    }
    ccPolicy := policydsl.SignedByNOutOfGivenRole(int32(len(mspIDs)), mb.MSPRole_MEMBER, mspIDs)
    approveCCReq := resmgmt.LifecycleApproveCCRequest{
        Name:              ccName,
        Version:           ccVersion,
        PackageID:         packageID,
        Sequence:          sequence,
        EndorsementPlugin: "escc",
        ValidationPlugin:  "vscc",
        SignaturePolicy:   ccPolicy,
        InitRequired:      true,
    }

    for _, org := range orgs{
        orgPeers, err := DiscoverLocalPeers(*org.OrgAdminClientContext, org.OrgPeerNum)
        fmt.Printf(">>> chaincode approved by %s peers:\n", org.OrgName)
        for _, p := range orgPeers {
            fmt.Printf("    %s\n", p.URL())
        }

        if err!=nil{
            return fmt.Errorf("DiscoverLocalPeers error: %v", err)
        }
        if _, err := org.OrgResMgmt.LifecycleApproveCC(channelID, approveCCReq, resmgmt.WithTargets(orgPeers...), resmgmt.WithOrdererEndpoint(ordererEndpoint), resmgmt.WithRetry(retry.DefaultResMgmtOpts));err != nil {
            fmt.Errorf("LifecycleApproveCC error: %v", err)
        }
    }
    return nil
}

func queryApprovedCC(ccName string, sequence int64, channelID string, orgs []*OrgInfo) error {
    queryApprovedCCReq := resmgmt.LifecycleQueryApprovedCCRequest{
        Name:     ccName,
        Sequence: sequence,
    }

    for _, org := range orgs{
        orgPeers, err := DiscoverLocalPeers(*org.OrgAdminClientContext, org.OrgPeerNum)
        if err!=nil{
            return fmt.Errorf("DiscoverLocalPeers error: %v", err)
        }
        // Query approve cc
        for _, p := range orgPeers {
            resp, err := retry.NewInvoker(retry.New(retry.TestRetryOpts)).Invoke(
                func() (interface{}, error) {
                    resp1, err := org.OrgResMgmt.LifecycleQueryApprovedCC(channelID, queryApprovedCCReq, resmgmt.WithTargets(p))
                    if err != nil {
                        return nil, status.New(status.TestStatus, status.GenericTransient.ToInt32(), fmt.Sprintf("LifecycleQueryApprovedCC returned error: %v", err), nil)
                    }
                    return resp1, err
                },
            )
            if err != nil {
                return fmt.Errorf("Org %s Peer %s NewInvoker error: %v", org.OrgName, p.URL(), err)
            }
            if resp==nil{
                return fmt.Errorf("Org %s Peer %s Got nil invoker", org.OrgName, p.URL())
            }
        }
    }
    return nil
}

func checkCCCommitReadiness(packageID string, ccName, ccVersion string, sequence int64, channelID string, orgs []*OrgInfo) error {
    mspIds := []string{}
    for _, org := range orgs {
        mspIds = append(mspIds, org.OrgMspId)
    }
    ccPolicy := policydsl.SignedByNOutOfGivenRole(int32(len(mspIds)), mb.MSPRole_MEMBER, mspIds)
    req := resmgmt.LifecycleCheckCCCommitReadinessRequest{
        Name:              ccName,
        Version:           ccVersion,
        //PackageID:         packageID,
        EndorsementPlugin: "escc",
        ValidationPlugin:  "vscc",
        SignaturePolicy:   ccPolicy,
        Sequence:          sequence,
        InitRequired:      true,
    }
    for _, org := range orgs{
        orgPeers, err := DiscoverLocalPeers(*org.OrgAdminClientContext, org.OrgPeerNum)
        if err!=nil{
            fmt.Errorf("DiscoverLocalPeers error: %v", err)
        }
        for _, p := range orgPeers {
            resp, err := retry.NewInvoker(retry.New(retry.TestRetryOpts)).Invoke(
                func() (interface{}, error) {
                    resp1, err := org.OrgResMgmt.LifecycleCheckCCCommitReadiness(channelID, req, resmgmt.WithTargets(p))
                    fmt.Printf("LifecycleCheckCCCommitReadiness cc = %v, = %v\n", ccName, resp1)
                    if err != nil {
                        return nil, status.New(status.TestStatus, status.GenericTransient.ToInt32(), fmt.Sprintf("LifecycleCheckCCCommitReadiness returned error: %v", err), nil)
                    }
                    flag := true
                    for _, r := range resp1.Approvals {
                        flag = flag && r
                    }
                    if !flag {
                        return nil, status.New(status.TestStatus, status.GenericTransient.ToInt32(), fmt.Sprintf("LifecycleCheckCCCommitReadiness returned : %v", resp1), nil)
                    }
                    return resp1, err
                },
            )
            if err != nil {
                return fmt.Errorf("NewInvoker error: %v", err)
            }
            if resp==nil{
                return fmt.Errorf("Got nill invoker response")
            }
        }
    }

    return nil
}

func commitCC(ccName, ccVersion string, sequence int64, channelID string, orgs []*OrgInfo, ordererEndpoint string) error{
    mspIDs := []string{}
    for _, org := range orgs {
        mspIDs = append(mspIDs, org.OrgMspId)
    }
    ccPolicy := policydsl.SignedByNOutOfGivenRole(int32(len(mspIDs)), mb.MSPRole_MEMBER, mspIDs)

    req := resmgmt.LifecycleCommitCCRequest{
        Name:              ccName,
        Version:           ccVersion,
        Sequence:          sequence,
        EndorsementPlugin: "escc",
        ValidationPlugin:  "vscc",
        SignaturePolicy:   ccPolicy,
        InitRequired:      true,
    }
    _, err := orgs[0].OrgResMgmt.LifecycleCommitCC(channelID, req, resmgmt.WithOrdererEndpoint(ordererEndpoint), resmgmt.WithRetry(retry.DefaultResMgmtOpts))
    if err != nil {
        return fmt.Errorf("LifecycleCommitCC error: %v", err)
    }
    return nil
}

func queryCommittedCC( ccName string, channelID string, sequence int64, orgs []*OrgInfo) error {
    req := resmgmt.LifecycleQueryCommittedCCRequest{
        Name: ccName,
    }

    for _, org := range orgs {
        orgPeers, err := DiscoverLocalPeers(*org.OrgAdminClientContext, org.OrgPeerNum)
        if err!=nil{
            return fmt.Errorf("DiscoverLocalPeers error: %v", err)
        }
        for _, p := range orgPeers {
            resp, err := retry.NewInvoker(retry.New(retry.TestRetryOpts)).Invoke(
                func() (interface{}, error) {
                    resp1, err := org.OrgResMgmt.LifecycleQueryCommittedCC(channelID, req, resmgmt.WithTargets(p))
                    if err != nil {
                        return nil, status.New(status.TestStatus, status.GenericTransient.ToInt32(), fmt.Sprintf("LifecycleQueryCommittedCC returned error: %v", err), nil)
                    }
                    flag := false
                    for _, r := range resp1 {
                        if r.Name == ccName && r.Sequence == sequence {
                            flag = true
                            break
                        }
                    }
                    if !flag {
                        return nil, status.New(status.TestStatus, status.GenericTransient.ToInt32(), fmt.Sprintf("LifecycleQueryCommittedCC returned : %v", resp1), nil)
                    }
                    return resp1, err
                },
            )
            if err != nil {
                return  fmt.Errorf("NewInvoker error: %v", err)
            }
            if resp==nil{
                return fmt.Errorf("Got nil invoker response")
            }
        }
    }
    return nil
}

func initCC(ccName string, upgrade bool, channelID string, org *OrgInfo, sdk *fabsdk.FabricSDK) error {
    //prepare channel client context using client context
    clientChannelContext := sdk.ChannelContext(channelID, fabsdk.WithUser(org.OrgUser), fabsdk.WithOrg(org.OrgName))
    // Channel client is used to query and execute transactions (Org1 is default org)
    client, err := channel.New(clientChannelContext)
    if err != nil {
        return fmt.Errorf("Failed to create new channel client: %s", err)
    }

    // init
    _, err = client.Execute(channel.Request{ChaincodeID: ccName, Fcn: "init", Args: nil, IsInit: true},
        channel.WithRetry(retry.DefaultChannelOpts))
    if err != nil {
        return fmt.Errorf("Failed to init: %s", err)
    }
    return nil
}