fabric1.2网络环境启动过程详解

fabric运行机制及环境搭建


环境依赖

fabric官方推荐的开发环境是基于docker搭建的,使用docker搭建需要一下前置条件

  • docker一一Docker version 17.06.2-ce 或以上版本
  • Docker Compose一一1.14或以上版本
  • Go一一1.10或以上版本
  • Node.js一一8.9.x或以上版本
  • Python一一如果是Ubuntu16.04需要把默认的python软链链接到python2.7

这些条件都满足以后,可以执行以下命令下载fabric源码

cd $GOPATH/src  
mkdir -p  github.com/hyperledger
cd  github.com/hyperledger
git  clone  https://github.com/hyperledger/fabric.git

目前的最新版本是release1.2,以下流程也是基于1.2版本。下载好源码后我们可以基于docker来搭建开发环境

基于docker镜像的fabric1.2开发环境搭建流程

首先进入examples/e2e_cli目录,执行download脚本下载所需的fabric镜像

cd $GOPATH/src/github.com/hyperledger/fabric/examples/e2e_cli/
bash download-dockerimages.sh

直接执行download-dockerimages.sh脚本会在下载fabric-javaenv:latest这个镜像时卡主,这是因为目前hyperledger的镜像仓库里的fabric-javaenv镜像还没有latest的tag,可以自行在docker.hub下搜索fabric-javaenv下最新的tag,我搜到的最新tag是ppc64le-1.1.1,那么将download-dockerimages.sh脚本中的这两行脚本

docker pull hyperledger/fabric-$IMAGES:$FABRIC_TAG
docker tag hyperledger/fabric-$IMAGES:$FABRIC_TAG hyperledger/fabric-$IMAGES

替换为

if [ $IMAGES == "javaenv" ] ; then
        docker pull hyperledger/fabric-javaenv:ppc64le-1.1.1
        docker tag hyperledger/fabric-javaenv:ppc64le-1.1.1 hyperledger/fabric-javaenv:latest
      else
        docker pull hyperledger/fabric-$IMAGES:$FABRIC_TAG
        docker tag hyperledger/fabric-$IMAGES:$FABRIC_TAG hyperledger/fabric-$IMAGES
fi

然后重新执行就可以拉取到所需的全部镜像镜像列表如下:


fabric-images.png

接下来就可以执行network_setup.sh来一键部署环境

bash  network_setup.sh  up

这个脚本执行了以下操作:

1. 编译生成Fabric公私钥、证书的程序,程序在目录:fabric/release/linux-amd64/bin

其中主要用到如下5个程序

  • cryptogen:通过crypto-config.yaml配置文件生成公私钥和证书
  • idemixgen:为签名和认证生成ca证书已经msp配置文件
  • onfixtxgen:通过configtx.yaml生成创世区块和通道相关信息
  • orderer:用户启动orderer服务
  • peer:用户启动peer服务

如果需要动态添加组织还需要configtxlator这个工具

2. 基于crypto-config.yaml生成公私钥和证书信息,并保存在crypto-config文件夹中。

crypto-config.yaml定义了组织成员以及组织下的peer节点个数,以如下配置为例

# Copyright IBM Corp. All Rights Reserved.
#
# SPDX-License-Identifier: Apache-2.0
#

# ---------------------------------------------------------------------------
# "OrdererOrgs" - Definition of organizations managing orderer nodes
# ---------------------------------------------------------------------------
OrdererOrgs:
  # ---------------------------------------------------------------------------
  # Orderer
  # ---------------------------------------------------------------------------
  - Name: Orderer
    Domain: cryptogen generate --config=./crypto-config.yamlexample.com
    CA:
        Country: US
        Province: California
        Locality: San Francisco
    # ---------------------------------------------------------------------------
    # "Specs" - See PeerOrgs below for complete description
    # ---------------------------------------------------------------------------
    Specs:
      - Hostname: orderer
# ---------------------------------------------------------------------------
# "PeerOrgs" - Definition of organizations managing peer nodes
# ---------------------------------------------------------------------------
PeerOrgs:
  # ---------------------------------------------------------------------------
  # Org1
  # ---------------------------------------------------------------------------
  - Name: Org1
    Domain: org1.example.com
    EnableNodeOUs: true
    CA:
        Country: US
        Province: California
        Locality: San Francisco
    # ---------------------------------------------------------------------------
    # "Specs"
    # ---------------------------------------------------------------------------
    # Uncomment this section to enable the explicit definition of hosts in your
    # configuration.  Most users will want to use Template, below
    #
    # Specs is an array of Spec entries.  Each Spec entry consists of two fields:
    #   - Hostname:   (Required) The desired hostname, sans the domain.
    #   - CommonName: (Optional) Specifies the template or explicit override for
    #                 the CN.  By default, this is the template:
    #
    #                              "{{.Hostname}}.{{.Domain}}"
    #
    #                 which obtains its values from the Spec.Hostname and
    #                 Org.Domain, respectively.
    # ---------------------------------------------------------------------------
    # Specs:
    #   - Hostname: foo # implicitly "foo.org1.example.com"
    #     CommonName: foo27.org5.example.com # overrides Hostname-based FQDN set above
    #   - Hostname: bar
    #   - Hostname: baz
    # ---------------------------------------------------------------------------
    # "Template"
    # ---------------------------------------------------------------------------
    # Allows for the definition of 1 or more hosts that are created sequentially
    # from a template. By default, this looks like "peer%d" from 0 to Count-1.
    # You may override the number of nodes (Count), the starting index (Start)
    # or the template used to construct the name (Hostname).
    #
    # Note: Template and Specs are not mutually exclusive.  You may define both
    # sections and the aggregate nodes will be created for you.  Take care with
    # name collisions
    # ---------------------------------------------------------------------------
    Template:
      Count: 2
      # Start: 5
      # Hostname: {{.Prefix}}{{.Index}} # default
    # ---------------------------------------------------------------------------
    # "Users"
    # ---------------------------------------------------------------------------
    # Count: The number of user accounts _in addition_ to Admin
    # ---------------------------------------------------------------------------
    Users:
      Count: 1
  # ---------------------------------------------------------------------------
  # Org2: See "Org1" for full specification
  # ---------------------------------------------------------------------------
  - Name: Org2
    Domain: org2.example.com
    EnableNodeOUs: true
    CA:
        Country: US
        Province: California
        Locality: San Francisco
    Template:
      Count: 2
    Users:
      Count: 1

Name和Domain就是关于这个组织的名字和域名,这主要是用于生成证书的时候,证书内会包含该信息。而Template.Count=2是说我们要生成2套公私钥和证书,一套是peer0.org2的,还有一套是peer1.org2的。最后Users.Count=1是说每个Template下面会有几个普通User(注意,Admin是Admin,不包含在这个计数中),这里配置了1,也就是说我们只需要一个普通用户User1@org2.example.com 我们可以根据实际需要调整这个配置文件,增删Org Users等

通过以下命令生成相关配置

cryptogen generate --config=./crypto-config.yaml

可以看到在example目录下多了一个crypto-config文件夹,部分结构如下


fabric-cryptconfig.png

fabric网络中包括orderer,peer,client applications,admin等角色。这些参与者中的每一个都具有封装在X.509数字证书中的数字身份。Fabirc的成员身份基于标准的X.509证书,密钥使用的是ECDSA算法,利用PKI体系给每个成员颁发数字证书,通道内只有相同MSP内的节点才可以通过Gossip协议进行数据分发。

3. 生成idemix配置文件

在刚刚生成的crypto-config目录里,新建一个idemix目录,然后生成对应的发行者公私钥以及msp公钥和签名用户

mkdir -p crypto-config/idemix
# 生成证书
idemixgen ca-keygen
# 新建一个签名用户,以下命令创建一个OU1组织单位的成员(-u标识组织),成员标识为OU1(-e标识成员),撤销该签名用户的密码(The handle used to revoke this signer)为1(-r标识)
idemixgen signerconfig -u OU1 -e OU1 -r 1

idemix是ibm实现的一种加密算法,fabric中使用idemix实现的msp允许匿名签署交易

4. 基于configtx.yaml生成创世区块和通道相关信息,并保存在channel-artifacts文件夹。

官方提供的examples/e2e_cli/configtx.yaml这个文件里面配置了由2个Org参与的Orderer共识配置TwoOrgsOrdererGenesis,以及由2个Org参与的Channel配置:TwoOrgsChannel。Orderer可以设置共识的算法是Solo还是Kafka,以及共识时区块大小,超时时间等,我们使用默认值即可,不用更改。而Peer节点的配置包含了MSP的配置,锚节点的配置。如果我们有更多的Org,或者有更多的Channel,那么就可以根据模板进行对应的修改。配置文件如下:

# Copyright IBM Corp. All Rights Reserved.
#
# SPDX-License-Identifier: Apache-2.0
#

---
################################################################################
#
#   Section: Organizations
#
#   - This section defines the different organizational identities which will
#   be referenced later in the configuration.
#
################################################################################
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')"

    - &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.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('Org1MSP.admin', 'Org1MSP.peer', 'Org1MSP.client')"
            Writers:
                Type: Signature
                Rule: "OR('Org1MSP.admin', 'Org1MSP.client')"
            Admins:
                Type: Signature
                Rule: "OR('Org1MSP.admin')"

        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.example.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.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('Org2MSP.admin', 'Org2MSP.peer', 'Org2MSP.client')"
            Writers:
                Type: Signature
                Rule: "OR('Org2MSP.admin', 'Org2MSP.client')"
            Admins:
                Type: Signature
                Rule: "OR('Org2MSP.admin')"

        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.example.com
              Port: 7051

    - &Org3
        # Name of the organization
        Name: Org3MSP

        # ID to load the MSP definition as
        ID: Org3MSP

        # Type of MSP - this org uses idemix for its MSP implementation
        MSPType: idemix

        MSPDir: crypto-config/idemix/idemix-config

        # 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')"
        Policies:
            Readers:
                Type: Signature
                Rule: "OR('Org3MSP.admin', 'Org3MSP.peer', 'Org3MSP.client', 'Org3MSP.member')"
            Writers:
                Type: Signature
                Rule: "OR('Org3MSP.admin', 'Org3MSP.client', 'Org3MSP.member')"
            Admins:
                Type: Signature
                Rule: "OR('Org3MSP.admin')"

        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.example.com
              Port: 7051

################################################################################
#
#   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.
    Global: &ChannelCapabilities
        # V1.1 for Global is a catchall flag for behavior which has been
        # determined to be desired for all orderers and peers running v1.0.x,
        # but the modification of which would cause incompatibilities.  Users
        # should leave this flag set to true.
        V1_1: true

    # Orderer capabilities apply only to the orderers, and may be safely
    # manipulated without concern for upgrading peers.  Set the value of the
    # capability to true to require it.
    Orderer: &OrdererCapabilities
        # V1.1 for Order is a catchall flag for behavior which has been
        # determined to be desired for all orderers running v1.0.x, but the
        # modification of which  would cause incompatibilities.  Users should
        # leave this flag set to true.
        V1_1: true

    # Application capabilities apply only to the peer network, and may be safely
    # manipulated without concern for upgrading orderers.  Set the value of the
    # capability to true to require it.
    Application: &ApplicationCapabilities
        # V1.1 for Application is a catchall flag for behavior which has been
        # determined to be desired for all peers running v1.0.x, but the
        # modification of which would cause incompatibilities.  Users should
        # leave this flag set to true.
        V1_2: 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"

    # Capabilities describes the application level capabilities, see the
    # dedicated Capabilities section elsewhere in this file for a full
    # description
    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
    # Available types are "solo" and "kafka"
    OrdererType: kafka

    Addresses:
        - orderer.example.com:7050

    # 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: 98 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

    Kafka:
        # Brokers: A list of Kafka brokers to which the orderer connects. Edit
        # this list to identify the brokers of the ordering service.
        # NOTE: Use IP:port notation.
        Brokers:
            - kafka0:9092
            - kafka1:9092
            - kafka2:9092
            - kafka3:9092

    # 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"

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

################################################################################
#
#   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:

    TwoOrgsOrdererGenesis:
        <<: *ChannelDefaults
        Orderer:
            <<: *OrdererDefaults
            Organizations:
                - *OrdererOrg
        Consortiums:
            SampleConsortium:
                Organizations:
                    - *Org1
                    - *Org2
                    - *Org3
    TwoOrgsChannel:
        Consortium: SampleConsortium
        Application:
            <<: *ApplicationDefaults
            Organizations:
                - *Org1
                - *Org2
                - *Org3

以上配置中比较重要的时Policies配置,该配置项定义了不同角色的权限,Reader,Writer以及Admin分别对应读,写,以及admin权限,读权限角色只能从别的peer节点同步账本而不能发起交易,只有writer定义项下的角色才拥有发起交易的也就是调用chaincode的invoke方法的权限(不一定都是invoke方案,只要涉及到chaincode中状态修改的方法,都只有拥有writer权限或admin权限的角色才能调用).以该配置的Organizations配置下的Org1配置为例,"OR('Org1MSP.admin', 'Org1MSP.client')",表示org1的msp服务中的admin或者client角色拥有发起交易的权限

接下来执行以下命令生成创世区块和peer节点

生成创世块,-profile对应配置文件中profile的配置项定义,channelID指定通道名称,channelID不允许重复

configtxgen -profile TwoOrgsOrdererGenesis -channelID e2e-orderer-syschan -outputBlock ./channel-artifacts/genesis.block

生成channel配置交易账本:

configtxgen -profile TwoOrgsChannel -outputCreateChannelTx ./channel-artifacts/channel.tx -channelID mychannel

生成org1的msp服务的锚节点更新账本

configtxgen -profile TwoOrgsChannel -outputAnchorPeersUpdate ./channel-artifacts/Org1MSPanchors.tx -channelID mychannel -asOrg Org1MSP

生成org2的msp服务的锚节点更新账本

configtxgen -profile TwoOrgsChannel -outputAnchorPeersUpdate ./channel-artifacts/Org2MSPanchors.tx -channelID mychannel -asOrg Org2MSP

5. 基于docker-compose-cli.yaml启动1Orderer+4Peer+1CLI的Fabric容器。

启动容器时实际上就是执行了如下脚本

docker-compose -f docker-compose-cli.yaml up -d 2>&1

6. 在CLI启动的时候,会运行scripts/script.sh文件,这个脚本文件包含了创建Channel,加入Channel,安装Example02的链码,运行链码等功能。

script.sh代码如下,该脚本是在docker容器内运行的

#!/bin/bash
# Copyright London Stock Exchange Group All Rights Reserved.
#
# SPDX-License-Identifier: Apache-2.0
#
echo
echo " ____    _____      _      ____    _____           _____   ____    _____ "
echo "/ ___|  |_   _|    / \    |  _ \  |_   _|         | ____| |___ \  | ____|"
echo "\___ \    | |     / _ \   | |_) |   | |    _____  |  _|     __) | |  _|  "
echo " ___) |   | |    / ___ \  |  _ <    | |   |_____| | |___   / __/  | |___ "
echo "|____/    |_|   /_/   \_\ |_| \_\   |_|           |_____| |_____| |_____|"
echo

CHANNEL_NAME="$1"
: ${CHANNEL_NAME:="mychannel"}
: ${TIMEOUT:="60"}
COUNTER=1
MAX_RETRY=5
ORDERER_CA=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem
PEER0_ORG1_CA=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt
PEER0_ORG2_CA=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt
ORDERER_SYSCHAN_ID=e2e-orderer-syschan

echo "Channel name : "$CHANNEL_NAME

verifyResult () {
    if [ $1 -ne 0 ] ; then
        echo "!!!!!!!!!!!!!!! "$2" !!!!!!!!!!!!!!!!"
                echo "================== ERROR !!! FAILED to execute End-2-End Scenario =================="
        echo
        exit 1
    fi
}

setGlobals () {
    PEER=$1
    ORG=$2
    if [ $ORG -eq 1 ] ; then
        CORE_PEER_LOCALMSPID="Org1MSP"
        CORE_PEER_TLS_ROOTCERT_FILE=$PEER0_ORG1_CA
        CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp
        if [ $PEER -eq 0 ]; then
            CORE_PEER_ADDRESS=peer0.org1.example.com:7051
        else
            CORE_PEER_ADDRESS=peer1.org1.example.com:7051
        fi
    elif [ $ORG -eq 3 ] ; then
        CORE_PEER_LOCALMSPID="Org3MSP"
        CORE_PEER_TLS_ROOTCERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt
        CORE_PEER_ADDRESS=peer0.org1.example.com:7051
        CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/idemix/idemix-config
        CORE_PEER_LOCALMSPTYPE=idemix
    else
        CORE_PEER_LOCALMSPID="Org2MSP"
        CORE_PEER_TLS_ROOTCERT_FILE=$PEER0_ORG2_CA
        CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp
        if [ $PEER -eq 0 ]; then
            CORE_PEER_ADDRESS=peer0.org2.example.com:7051
        else
            CORE_PEER_ADDRESS=peer1.org2.example.com:7051
        fi
    fi

    env |grep CORE
}

checkOSNAvailability() {
    # Use orderer's MSP for fetching system channel config block
    CORE_PEER_LOCALMSPID="OrdererMSP"
    CORE_PEER_TLS_ROOTCERT_FILE=$ORDERER_CA
    CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp

    local rc=1
    local starttime=$(date +%s)

    # continue to poll
    # we either get a successful response, or reach TIMEOUT
    while test "$(($(date +%s)-starttime))" -lt "$TIMEOUT" -a $rc -ne 0
    do
         sleep 3
         echo "Attempting to fetch system channel '$ORDERER_SYSCHAN_ID' ...$(($(date +%s)-starttime)) secs"
         if [ -z "$CORE_PEER_TLS_ENABLED" -o "$CORE_PEER_TLS_ENABLED" = "false" ]; then
             peer channel fetch 0 -o orderer.example.com:7050 -c "$ORDERER_SYSCHAN_ID" >&log.txt
         else
             peer channel fetch 0 0_block.pb -o orderer.example.com:7050 -c "$ORDERER_SYSCHAN_ID" --tls --cafile $ORDERER_CA >&log.txt
         fi
         test $? -eq 0 && VALUE=$(cat log.txt | awk '/Received block/ {print $NF}')
         test "$VALUE" = "0" && let rc=0
    done
    cat log.txt
    verifyResult $rc "Ordering Service is not available, Please try again ..."
    echo "===================== Ordering Service is up and running ===================== "
    echo
}

createChannel() {
    setGlobals 0 1
    if [ -z "$CORE_PEER_TLS_ENABLED" -o "$CORE_PEER_TLS_ENABLED" = "false" ]; then
        peer channel create -o orderer.example.com:7050 -c $CHANNEL_NAME -f ./channel-artifacts/channel.tx >&log.txt
    else
        peer channel create -o orderer.example.com:7050 -c $CHANNEL_NAME -f ./channel-artifacts/channel.tx --tls --cafile $ORDERER_CA >&log.txt
    fi
    res=$?
    cat log.txt
    verifyResult $res "Channel creation failed"
    echo "===================== Channel '$CHANNEL_NAME' created ===================== "
    echo
}

updateAnchorPeers() {
    PEER=$1
    ORG=$2
    setGlobals $PEER $ORG

    if [ -z "$CORE_PEER_TLS_ENABLED" -o "$CORE_PEER_TLS_ENABLED" = "false" ]; then
        peer channel update -o orderer.example.com:7050 -c $CHANNEL_NAME -f ./channel-artifacts/${CORE_PEER_LOCALMSPID}anchors.tx >&log.txt
    else
        peer channel update -o orderer.example.com:7050 -c $CHANNEL_NAME -f ./channel-artifacts/${CORE_PEER_LOCALMSPID}anchors.tx --tls --cafile $ORDERER_CA >&log.txt
    fi
    res=$?
    cat log.txt
    verifyResult $res "Anchor peer update failed"
    echo "===================== Anchor peers updated for org '$CORE_PEER_LOCALMSPID' on channel '$CHANNEL_NAME' ===================== "
    sleep 5
    echo
}

## Sometimes Join takes time hence RETRY atleast for 5 times
joinChannelWithRetry () {
    PEER=$1
    ORG=$2
    setGlobals $PEER $ORG

    peer channel join -b $CHANNEL_NAME.block  >&log.txt
    res=$?
    cat log.txt
    if [ $res -ne 0 -a $COUNTER -lt $MAX_RETRY ]; then
        COUNTER=` expr $COUNTER + 1`
        echo "peer${PEER}.org${ORG} failed to join the channel, Retry after 2 seconds"
        sleep 2
        joinChannelWithRetry $1
    else
        COUNTER=1
    fi
    verifyResult $res "After $MAX_RETRY attempts, peer${PEER}.org${ORG} has failed to join channel '$CHANNEL_NAME' "
}

joinChannel () {
    for org in 1 2; do
        for peer in 0 1; do
            joinChannelWithRetry $peer $org
            echo "===================== peer${peer}.org${org} joined channel '$CHANNEL_NAME' ===================== "
            sleep 2
            echo
        done
    done
}

installChaincode () {
    PEER=$1
    ORG=$2
    setGlobals $PEER $ORG
    peer chaincode install -n mycc -v 1.0 -p github.com/hyperledger/fabric/examples/chaincode/go/example02/cmd >&log.txt
    res=$?
    cat log.txt
    verifyResult $res "Chaincode installation on peer peer${PEER}.org${ORG} has Failed"
    echo "===================== Chaincode is installed on peer${PEER}.org${ORG} ===================== "
    echo
}

instantiateChaincode () {
    PEER=$1
    ORG=$2
    setGlobals $PEER $ORG
    # while 'peer chaincode' command can get the orderer endpoint from the peer (if join was successful),
    # lets supply it directly as we know it using the "-o" option
    if [ -z "$CORE_PEER_TLS_ENABLED" -o "$CORE_PEER_TLS_ENABLED" = "false" ]; then
        peer chaincode instantiate -o orderer.example.com:7050 -C $CHANNEL_NAME -n mycc -v 1.0 -c '{"Args":["init","a","100","b","200"]}' -P "AND ('Org1MSP.peer','Org2MSP.peer')" >&log.txt
    else
        peer chaincode instantiate -o orderer.example.com:7050 --tls --cafile $ORDERER_CA -C $CHANNEL_NAME -n mycc -v 1.0 -c '{"Args":["init","a","100","b","200"]}' -P "AND ('Org1MSP.peer','Org2MSP.peer')" >&log.txt
    fi
    res=$?
    cat log.txt
    verifyResult $res "Chaincode instantiation on peer${PEER}.org${ORG} on channel '$CHANNEL_NAME' failed"
    echo "===================== Chaincode is instantiated on peer${PEER}.org${ORG} on channel '$CHANNEL_NAME' ===================== "
    echo
}

chaincodeQuery () {
    PEER=$1
    ORG=$2
    setGlobals $PEER $ORG
    EXPECTED_RESULT=$3
    echo "===================== Querying on peer${PEER}.org${ORG} on channel '$CHANNEL_NAME'... ===================== "
    local rc=1
    local starttime=$(date +%s)

    # continue to poll
    # we either get a successful response, or reach TIMEOUT
    while test "$(($(date +%s)-starttime))" -lt "$TIMEOUT" -a $rc -ne 0
    do
            sleep 3
            echo "Attempting to Query peer${PEER}.org${ORG} ...$(($(date +%s)-starttime)) secs"
            peer chaincode query -C $CHANNEL_NAME -n mycc -c '{"Args":["query","a"]}' >&log.txt
            test $? -eq 0 && VALUE=$(cat log.txt | egrep '^[0-9]+$')
            test "$VALUE" = "$EXPECTED_RESULT" && let rc=0
    done
    echo
    cat log.txt
    if test $rc -eq 0 ; then
        echo "===================== Query successful on peer${PEER}.org${ORG} on channel '$CHANNEL_NAME' ===================== "
        else
        echo "!!!!!!!!!!!!!!! Query result on peer${PEER}.org${ORG} is INVALID !!!!!!!!!!!!!!!!"
            echo "================== ERROR !!! FAILED to execute End-2-End Scenario =================="
        echo
        exit 1
        fi
}

# parsePeerConnectionParameters $@
# Helper function that takes the parameters from a chaincode operation
# (e.g. invoke, query, instantiate) and checks for an even number of
# peers and associated org, then sets $PEER_CONN_PARMS and $PEERS
parsePeerConnectionParameters() {
    # check for uneven number of peer and org parameters
    if [ $(( $# % 2 )) -ne 0 ]; then
            exit 1
    fi

    PEER_CONN_PARMS=""
    PEERS=""
    while [ "$#" -gt 0 ]; do
        PEER="peer$1.org$2"
        PEERS="$PEERS $PEER"
        PEER_CONN_PARMS="$PEER_CONN_PARMS --peerAddresses $PEER.example.com:7051"
        if [ -z "$CORE_PEER_TLS_ENABLED" -o "$CORE_PEER_TLS_ENABLED" = "true" ]; then
                TLSINFO=$(eval echo "--tlsRootCertFiles \$PEER$1_ORG$2_CA")
                PEER_CONN_PARMS="$PEER_CONN_PARMS $TLSINFO"
            fi
        # shift by two to get the next pair of peer/org parameters
            shift; shift
    done
    # remove leading space for output
    PEERS="$(echo -e "$PEERS" | sed -e 's/^[[:space:]]*//')"
}

# chaincodeInvoke <peer> <org> ...
# Accepts as many peer/org pairs as desired and requests endorsement from each
chaincodeInvoke () {
    parsePeerConnectionParameters $@
    res=$?
    verifyResult $res "Invoke transaction failed on channel '$CHANNEL_NAME' due to uneven number of peer and org parameters "

    # while 'peer chaincode' command can get the orderer endpoint from the
    # peer (if join was successful), let's supply it directly as we know
    # it using the "-o" option
    echo "CORE_PEER_TLS_ENABLED $CORE_PEER_TLS_ENABLED"
    echo "PEER_CONN_PARMS $PEER_CONN_PARMS"
    echo "ORDERER_CA $ORDERER_CA"
    if [ -z "$CORE_PEER_TLS_ENABLED" -o "$CORE_PEER_TLS_ENABLED" = "false" ]; then
        peer chaincode invoke -o orderer.example.com:7050 -C $CHANNEL_NAME -n mycc $PEER_CONN_PARMS -c '{"Args":["invoke","a","b","10"]}' >&log.txt
    else
        peer chaincode invoke -o orderer.example.com:7050  --tls --cafile $ORDERER_CA -C $CHANNEL_NAME -n mycc $PEER_CONN_PARMS -c '{"Args":["invoke","a","b","10"]}' >&log.txt
    fi
    res=$?
    cat log.txt
    verifyResult $res "Invoke execution on PEER$PEER failed "
    echo "===================== Invoke transaction successful on $PEERS on channel '$CHANNEL_NAME' ===================== "
    echo
}

# Check for orderering service availablility
echo "Check orderering service availability..."
checkOSNAvailability

# Create channel
echo "Creating channel..."
createChannel

# Join all the peers to the channel
echo "Having all peers join the channel..."
joinChannel

# Set the anchor peers for each org in the channel
echo "Updating anchor peers for org1..."
updateAnchorPeers 0 1
echo "Updating anchor peers for org2..."
updateAnchorPeers 0 2

# Install chaincode on peer0.org1 and peer2.org2
echo "Installing chaincode on peer0.org1..."
installChaincode 0 1
echo "Install chaincode on peer0.org2..."
installChaincode 0 2

# Instantiate chaincode on peer0.org2
echo "Instantiating chaincode on peer0.org2..."
instantiateChaincode 0 2

# Query on chaincode on peer0.org1
echo "Querying chaincode on peer0.org1..."
chaincodeQuery 0 1 100

# Invoke on chaincode on peer0.org1 and peer0.org2
echo "Sending invoke transaction on peer0.org1 and peer0.org2..."
chaincodeInvoke 0 1 0 2

# Install chaincode on peer1.org2
echo "Installing chaincode on peer1.org2..."
installChaincode 1 2

# Query on chaincode on peer1.org2, check if the result is 90
echo "Querying chaincode on peer1.org2..."
chaincodeQuery 1 2 90

#Query on chaincode on peer1.org3 with idemix MSP type, check if the result is 90
echo "Querying chaincode on peer1.org3..."
chaincodeQuery 1 3 90

echo
echo "===================== All GOOD, End-2-End execution completed ===================== "
echo

echo
echo " _____   _   _   ____            _____   ____    _____ "
echo "| ____| | \ | | |  _ \          | ____| |___ \  | ____|"
echo "|  _|   |  \| | | | | |  _____  |  _|     __) | |  _|  "
echo "| |___  | |\  | | |_| | |_____| | |___   / __/  | |___ "
echo "|_____| |_| \_| |____/          |_____| |_____| |_____|"
echo

exit 0

从脚本可以知道,scripts.sh脚本执行了创建通道,加入通道,安装链码,初始化链码,执行链码函数等操作,这些操作都是在cli容器内执行了,我们先执行以下命令进入cli容器

docker exec -it cli bash

peer的命令结构如下


fabric-peer.png

相关命令行参数见官方文档,或者直接查看源代码,peer命令行代码入口在fabric/peer/main.go

我们接下来执行peer的相关操作,首先创建一个通道

peer channel create -o orderer.example.com:7050 -c mychannel -f ./channel-artifacts/channel.tx --tls --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem >&log.txt

-o 是指定orderer节点的通讯地址,-c 指定通道名,-f 指定账本文件路径,在fabric中,账本是跟channel一一对应的,一个通道对应一个账本,peer与peer之间只有处于同一个channel才能发生交易

接下来将peer加入通道

peer channel join -b mychannel.block  >&log.txt

-b 指定包含创世块的block路径
将对应的peer加入通道后,更新anchor peer

peer channel update -o orderer.example.com:7050 -c mychaanel -f ./channel-artifacts/Org1MSPanchors.tx --tls --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem >&log.txt
peer channel update -o orderer.example.com:7050 -c mychaanel -f ./channel-artifacts/Org2MSPanchors.tx --tls --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem >&log.txt

anchor peer:作为一个channel或org的代表,从orderer获取信息,并且组内广播给其他peer。其他peer可以不直接跟orderer打交道。可以定义多个anchor peer来防止单点故障
设置好anchor peer后就可以在锚节点上安装链码

peer chaincode install -n mycc -v 1.0 -p github.com/hyperledger/fabric/examples/chaincode/go/example02/cmd >&log.txt

-p 指定chaincode源码路径,目前只支持go跟node.js开发的源码,后续会支持java
接下来初始化链码

peer chaincode instantiate -o orderer.example.com:7050 --tls --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem -C mychannel -n mycc -v 1.0 -c '{"Args":["init","a","100","b","200"]}' -P "AND ('Org1MSP.peer','Org2MSP.peer')" >&log.txt

-p 指定背书策略,and表示用该链码发交易时必须要收集到org1的peer和org2的peer的签名,该交易才能发送成功
初始化成功后我们可以在安装了链码的本地peer执行query方法,query操作不需要与其它peer通信

peer chaincode query -C mychannel -n mycc -c '{"Args":["query","a"]}' >&log.txt

接下来我们执行一次invoke操作从a向b转账,根据初始化链码时指定的背书策略,invoke操作需要收集来自org1中任意一个peer的签名和org2中任意一个peer的签名

peer chaincode invoke -o orderer.example.com:7050  --tls --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem -C mychannel -n mycc --peerAddresses peer0.org1.example.com:7051 --tlsRootCertFiles /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt --peerAddresses peer0.org2.example.com:7051 --tlsRootCertFiles /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt -c '{"Args":["invoke","a","b","10"]}' >&log.txt

fabric的交易流程

fabric中的所有交易都是通过chaincode执行的,fabric中也不会有空块,只有有交易才会出块,fabric的交易流程图如下


fabric-transflow.jpg
  1. 应用程序客户端通过SDK调用证书服务(CA)服务,进行注册和登记,并获取身份证书
  2. 应用程序客户端通过SDK向区块链网络发起一个交易提案(Proposal),交易提案把带有本次交易要调用的合约标识、合约方法和参数信息以及客户端签名等信息发送给背书(Endorser)节点
  3. 背书(Endorser)节点收到交易提案(Proposal)后,需要进行以下验证
    • 交易预案是完好的
    • 该预案以前没有提交过(防止重放攻击)
    • 签名是合法的
    • 交易发起者(客户A)是否满足区块链写策略
      满足以上要求后,背书节点把’交易预案’作为输入参数,调用智能合约中的函数,智能合约根据当前的账本状态计算出一个’交易结果’,该结果包括返回值,读写集。此时,区块链账本并不会被更新。’交易结果’在被签名后与一个是/否的背书结果一同返回,称之为’预案回复’。
  4. 应用程序客户端收到背书(Endorser)节点返回的信息后,判断提案结果是否一致,以及是否参照指定的背书策略执行,如果没有足够的背书,则中止处理;否则,应用程序客户端把数据打包到一起组成一个交易并签名,发送给Orderers。
  5. Orderers对接收到的交易进行共识排序,分通道对’交易消息’按时间排序,并按通道将交易打包成块,发送给提交(Committer)节点;
  6. 提交(Committer)节点收到区块后,会对区块中的每笔交易进行校验,检查交易依赖的输入输出是否符合当前区块链的状态,完成后将区块追加到本地的区块链,并修改世界状态。

MSP服务介绍

整个交易流程中,msp服务担当权限管理的职责,包括身份识别,权限鉴定,签名,认证,背书策略校验等功能,下图详细解释了msp的在整个fabric网络中的定义及功能


![fabric-msp2.png](https://upload-images.jianshu.io/upload_images/5590710-bed3f1925b1fc51a.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

msp分类

1. 根据MSP出现的位置分类

MSP出现在区块链网络中的两个地方:Channel配置(Channel MSP),以及本地(local MSP)。因此,MSP可以分为:local 和 channel MSPs。

localMSP

localMSP,是为节点(peer 或 orderer)和用户(使用CLI或使用SDK的客户端应用程序的管理员)定义的。每个节点和用户都必须定义一个localMSP,以便在加入区块链的时候,进行权限验证。

channelMSP

channel MSP在channel层面定义管理和参与权。参与Channel的每个组织,都必须为其定义MSP。Channel上的Peers 和 orderers将在Channel MSP上共享数据,并且此后将能够正确认证Channel参与者。这意味着如果一个组织希望加入该Channel,那么需要在Channel配置中,加入一个包含该组织成员的信任链的MSP。否则来自该组织身份的交易将被拒绝。

下图是区块链网络中LocalMSP 以及ChannelMSP配置示意图:


fabric-msp-local.jpg

其中,P代表Peer节点,C代表channel,RCA表示根证书,ORG代表组织,B代表管理员B。

现在,从上到下来介绍该示意图:

最上面两个蓝色的三角形,分别代表组织ORG1和ORG2。

其中,ORG1的证书由RCA1颁发,ORG2的证书由RCA2颁发。

ORG1的MSP名称为ORG1.MSP;ORG2的MSP名为ORG2.MSP,此两者为LocalMSP。

在椭圆形C表示的通道的下面,是Channel MSP

从上图可知,Channel MSP包含加入通道的所有组织的MSP信息。实际上,Channel MSP在channel中的每个节点的文件系统上,实例化并且通过共识保持同步。也就是说,Channel通道中的每个节点的本地文件系统上存着每个channel MSP的副本。但从逻辑上来看,channel MSP驻留在channel或网络上并由其维护。ChannelMSP的存在,使得加入通道中的所有节点之间的数据共享。

综上所述:local和channel MSP之间的主要区别不在于它们的功能,而在于它们的范围。

2. 按照MSP管理的资源级别分类

channel MSP 和 local MSP之间的分割,反应了不同类型的MSP管理不同的资源。

比如,Local MSP主要是组织管理其本地资源,如peer or orderer节点等;

channel MSP 主要管理Channel资源,如Channel或网络级别,运营的ledgers,智能合约和联盟等。

将这些MSP视为处于不同级别是有好处的,其中较高级别的MSP,处理与网络管理有关的问题,而较低级别的MSP,处理私有资源管理的身份。 MSP在每个管理级别都是必须的 。按照网络,Channel,peer, orderer 和 users 等资源的等级,可将MSP分为以下几类:

Network MSP

通过定义参与者组织MSPs,来定义网络中的成员。同时定义这些成员中哪些成员,有权执行管理任务(例如,创建Channel)

Channel MSP

Channel提供了一组特定的组织之间的私人通信,这些组织又对其进行管理控制。在该Channel的MSP上下文中的Channel policies定义谁能够参与Channel上的某些操作,例如添加组织或实例化chaincodes。

Peer MSP

此Local MSP在每个peer的文件系统上定义,并且每个peer都有一个MSP实例。从概念上讲,它执行的功能与Channel MSP完全相同,限制条件是它仅用于定义它的peer上。

Orderer MSP

与peer MSP一样,orderer local MSP也在节点的文件系统上定义,并且仅用于该节点。与peer 节点相似,orderer也由单个组织拥有,因此只有一个MSP来列出其信任的参与者或节点。
如下图所示:


fabric-msp-range.jpg

peer 和 orderer的MSP是本地的,而Channel MSP 和 Network MSP在该Channel的所有参与者之间共享。

在上图中,网络配置Channel由ORG1管理,但另一个应用程序Channel可由ORG1和ORG2管理。peer是ORG2的成员,并由ORG2管理,而ORG1管理orderer。 ORG1信任来自RCA1的身份,而ORG2信任来自RCA2的身份。 请注意,这些是管理身份,反映了谁可以管理这些组件。 所以当ORG1管理网络时,ORG2.MSP确实存在于网络定义中。

MSP的实践

在实际的生产环境中,组织与MSP存在着多种映射关系,而且,通过设置不同的MSP,可以达到实现不同的权限控制目的。接下来,将从这两个方面介绍MSP的实践:

1. 组织与MSP之间建立映射关系

通常情况下,建议实际的组织和MSP之间建立一一对应关系。当然也可以选择其他类型的映射关系,我们一起来看一下。

  • 一个组织对应多个MSP的情况

这种情况是一个组织有多个部门,从方便管理的角度或者隐私保护的角度而言,每个部门都要设置不同的MSP。每个Peer节点只设置一个MSP,同一组织内不同MSP的Peer节点之间不能互相认证,这样相同组织的不同部门之间不会同步数据,数据不能共享。

  • 多个组织对应一个MSP

这种情况是同一个联盟的不同组织之间采用相同的成员管理架构,数据会在不同组织之间同步。在Peer节点之间的Gossip通信中,数据是在相同通道配置了相同MSP的Peer节点之间同步的。如果多个组织对应一个MSP,则数据就不会限制在组织内部,会跨组织进行同步。这种情况我觉得很有应用场景。比如,C9联盟可以在同一个MSP管理下,既能够确保信任的基础,又能够实现数据的共享。

其实这是由MSP定义的粒度问题,一个MSP可以和一个组织对应,也可以和多个组织对应,还可以和一个组织内部的多个部门对应,根据MSP配置好Peer节点后,数据同步就限制在了MSP定义的范围内。

2. 一个组织内部实现不同的权限控制

一个组织内部有多个部门,从而实现不同部门的权限控制。有两种方法可以实现这个场景:

  • 给组织内的所有部门定义一个MSP

给Peer节点配置MSP的时候,包含相同的可信根CA证书列表、中间CA证书、管理员证书,不同的Peer节点设置不同的所属部门。节点所属的部门是利用证书和部门之间映射的OrganizationalUnitIdentifiers定义的,它包含在MSP目录下配置文件“config.yaml”中。按照基于部门验证的方法来定义交易背书策略和通道管理策略,这样就可以实现不同的权限控制了。

这种方法会有一个问题
数据实际还是会在不同的Peer节点之间同步。因为Peer节点在识别组织身份类型OrgIdentityType的时候获取的是MSP标识,它会认为通道内相同MSP的节点都是可以分发数据的。

  • 给组织内的每个部门单独定义MSP

给Peer节点配置MSP的时候,不同部门配置的可信中间CA证书、管理员证书可以是不同的,不同部门成员的证书路径也是不同的。这种方式解决了所有部门定义在一个MSP中的问题,但是会带来管理上的复杂度。

另外一个办法是每个部门都设置不同的MSP,利用证书和部门之间映射的OrganizationalUnitIdentifiers实现不同部门的权限控制,数据同步仍然会限制在组织的不同部门内,这同样也会有管理上的复杂度。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,163评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,301评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,089评论 0 352
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,093评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,110评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,079评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,005评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,840评论 0 273
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,278评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,497评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,667评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,394评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,980评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,628评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,796评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,649评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,548评论 2 352

推荐阅读更多精彩内容