前言

基于Debian搭建Hyperledger Fabric 2.4开发环境及运行简单案例中,我们已经完成了Fabric 2.4的环境搭建及fabric-samples/test-network官方案例的运行。毫无疑问test-network是一个优秀的入门项目,让我们仅仅通过几行命令就能搭建起常用的Fabric联盟链网络,但我相信很多人第一次使用./network.sh up成功启动联盟链网络时跟我一样是懵的:网络是怎样启动的?它在背后做了什么?该网络包含哪些节点?包含哪些功能?它有什么用?为了解决这些问题,本文根据test-network中的几个Bash脚本源码,从启动流程、创建通道、部署链码等多个入口函数着手详细分析了脚本执行过程,对未来定制自己的Fabric网络提供参考。本文分析源码主要包含启动默认网络、启动CA网络、创建通道、部署链码四个方面,每节分为官方调用和过程详解:官方调用是使用官方Bash脚本实现对应功能、过程详解是该脚本的实际实现流程,根据过程详解中的代码能够搭建出完全可用的网络。

准备

在开始前,需要准备好Fabric的开发环境,具体环境搭建和软件版本可参考基于Debian搭建Hyperledger Fabric 2.4开发环境及运行简单案例。之后将fabric-samples[1]下的test-network目录拷贝到本地,由于官方示例中过于封装导致难以单独使用,因此本文对原test-network项目进行修改,修改内容包括但不限于以下几个方面(建议直接将本案例仓库 FabricLearn 下的 0_TestNetworkExplain 目录拷贝到本地运行):

  1. 修改compose-test-net.yamlcompose-ca.yamldocker/docker-compose-test-net.yamldocker/docker-compose-ca.yaml文件中镜像版本:
hyperledger/fabric-tools:latest    ->  hyperledger/fabric-tools:2.4
hyperledger/fabric-peer:latest -> fabric-peer:2.4
hyperledger/fabric-orderer:latest -> fabric-orderer:2.4
hyperledger/fabric-ca:latest -> fabric-ca:1.5
  1. 基于Debian搭建Hyperledger Fabric 2.4开发环境及运行简单案例中的/usr/local/fabric/config目录复制到test-network根目录下。如无特殊说明,环境变量FABRIC_CFG_PATH总是默认指向test-network/config目录。
  2. 修改docker-compose-test-net.yaml,将${DOCKER_SOCK}改成/var/run/docker.sock
  3. 修改createChannel.shdeployCC.sh,将FABRIC_CFG_PATH=$PWD/../config/改成FABRIC_CFG_PATH=$PWD/config/
  4. 如无特殊说明,本文所有命令皆运行在test-network根目录下。

启动默认网络

官方调用

test-network中,包含一个默认最简网络,该网络只包含两个peer节点、一个orderer节点和一个cli节点,其中各节点的证书使用cryptogen工具静态生成。可以直接运行以下命令启动默认最简网络:

./network.sh up

过程详解

  1. 检查依赖:
  • 检查peer版本
  • 检查./config配置目录是否存在
  • 检查peer版本与docker image版本是否匹配
  • 检查fabric-ca环境是否正常,默认使用cryptogen
  1. 创建组织证书:
cryptogen generate --config=./organizations/cryptogen/crypto-config-org1.yaml --output="organizations"
cryptogen generate --config=./organizations/cryptogen/crypto-config-org2.yaml --output="organizations"
cryptogen generate --config=./organizations/cryptogen/crypto-config-orderer.yaml --output="organizations"
  1. docker-compose启动所有容器:
docker-compose -f compose/compose-test-net.yaml -f compose/docker/docker-compose-test-net.yaml up -d


其中compose-test-net.yaml包含基本镜像配置,docker-compose-test-net.yaml包含基础通用变量,二者缺一不可。以上命令完成后即可实现与./network.sh up完全相同的效果,进行下节实验前可使用./network.sh down关闭此网络。

启动CA网络

官方调用

在test-network中,可以通过fabric-ca启动网络,该网络使用fabric-ca管理所有节点的身份证书,其中包含三个ca节点、两个peer节点、一个orderer节点和一个cli节点。可以直接运行以下命令启动CA网络(后面所有实验基于此网络):

./network.sh up -ca

过程详解

  1. 检查软件、版本依赖:
  2. 启动fabric-ca容器:
docker-compose -f compose/compose-ca.yaml -f compose/docker/docker-compose-ca.yaml up -d
  1. 创建org1证书目录:
# 创建组织证书根目录
mkdir -p organizations/peerOrganizations/org1.example.com/
  1. enroll管理员账户:
# enroll组织默认管理员账户,其配置对应在compose/compose-ca.yaml的command中,enroll过程会获取该账户的全部证书并保存至FABRIC_CA_CLIENT_HOME目录下
export FABRIC_CA_CLIENT_HOME=${PWD}/organizations/peerOrganizations/org1.example.com/
fabric-ca-client enroll -u https://admin:adminpw@localhost:7054 --caname ca-org1 --tls.certfiles "${PWD}/organizations/fabric-ca/org1/ca-cert.pem"
  1. 创建org1组织的OU配置文件:
# 创建组织msp的OU配置文件
echo 'NodeOUs:
Enable: true
ClientOUIdentifier:
Certificate: cacerts/localhost-7054-ca-org1.pem
OrganizationalUnitIdentifier: client
PeerOUIdentifier:
Certificate: cacerts/localhost-7054-ca-org1.pem
OrganizationalUnitIdentifier: peer
AdminOUIdentifier:
Certificate: cacerts/localhost-7054-ca-org1.pem
OrganizationalUnitIdentifier: admin
OrdererOUIdentifier:
Certificate: cacerts/localhost-7054-ca-org1.pem
OrganizationalUnitIdentifier: orderer' > "${PWD}/organizations/peerOrganizations/org1.example.com/msp/config.yaml"
  1. 构造tlscacerts证书目录(用于不同组织通信):
# 由于该CA同时充当组织CA和tlsca,因此直接将CA启动时生成的组织根证书复制到组织级CA和TLS CA目录中
mkdir -p "${PWD}/organizations/peerOrganizations/org1.example.com/msp/tlscacerts"
cp "${PWD}/organizations/fabric-ca/org1/ca-cert.pem" "${PWD}/organizations/peerOrganizations/org1.example.com/msp/tlscacerts/ca.crt"
  1. 构造tlsca证书目录(用于组织内客户端通信):
mkdir -p "${PWD}/organizations/peerOrganizations/org1.example.com/tlsca"
cp "${PWD}/organizations/fabric-ca/org1/ca-cert.pem" "${PWD}/organizations/peerOrganizations/org1.example.com/tlsca/tlsca.org1.example.com-cert.pem"
  1. 构造ca证书目录(用于组织内客户端通信):
mkdir -p "${PWD}/organizations/peerOrganizations/org1.example.com/ca"
cp "${PWD}/organizations/fabric-ca/org1/ca-cert.pem" "${PWD}/organizations/peerOrganizations/org1.example.com/ca/ca.org1.example.com-cert.pem"
  1. 为org1注册新账户:
fabric-ca-client register --caname ca-org1 --id.name peer0 --id.secret peer0pw --id.type peer --tls.certfiles "${PWD}/organizations/fabric-ca/org1/ca-cert.pem"
fabric-ca-client register --caname ca-org1 --id.name user1 --id.secret user1pw --id.type client --tls.certfiles "${PWD}/organizations/fabric-ca/org1/ca-cert.pem"
fabric-ca-client register --caname ca-org1 --id.name org1admin --id.secret org1adminpw --id.type admin --tls.certfiles "${PWD}/organizations/fabric-ca/org1/ca-cert.pem"
  1. 构造peer0的身份证书目录:
# 构造peer0的msp证书目录,证书文件会存在-M指定的文件夹下
fabric-ca-client enroll -u https://peer0:peer0pw@localhost:7054 --caname ca-org1 -M "${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/msp" --csr.hosts peer0.org1.example.com --tls.certfiles "${PWD}/organizations/fabric-ca/org1/ca-cert.pem"
cp "${PWD}/organizations/peerOrganizations/org1.example.com/msp/config.yaml" "${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/msp/config.yaml"
# 构造peer0的msp-tls证书目录
fabric-ca-client enroll -u https://peer0:peer0pw@localhost:7054 --caname ca-org1 -M "${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls" --enrollment.profile tls --csr.hosts peer0.org1.example.com --csr.hosts localhost --tls.certfiles "${PWD}/organizations/fabric-ca/org1/ca-cert.pem"
# 构造peer0的tls证书目录并格式化文件名——用于启动peer docker容器
cp "${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/tlscacerts/"* "${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt"
cp "${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/signcerts/"* "${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/server.crt"
cp "${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/keystore/"* "${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/server.key"
  1. 构造其它用户身份证书目录:
# 构造user1的msp证书目录,因为不用于组织间通信,所以不用配置tls
fabric-ca-client enroll -u https://user1:user1pw@localhost:7054 --caname ca-org1 -M "${PWD}/organizations/peerOrganizations/org1.example.com/users/User1@org1.example.com/msp" --tls.certfiles "${PWD}/organizations/fabric-ca/org1/ca-cert.pem"
cp "${PWD}/organizations/peerOrganizations/org1.example.com/msp/config.yaml" "${PWD}/organizations/peerOrganizations/org1.example.com/users/User1@org1.example.com/msp/config.yaml" # 构造org1admin的msp证书目录
fabric-ca-client enroll -u https://org1admin:org1adminpw@localhost:7054 --caname ca-org1 -M "${PWD}/organizations/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp" --tls.certfiles "${PWD}/organizations/fabric-ca/org1/ca-cert.pem"
cp "${PWD}/organizations/peerOrganizations/org1.example.com/msp/config.yaml" "${PWD}/organizations/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp/config.yaml"
  1. 构造org2的组织证书,关键代码如下(各代码含义如上):
mkdir -p organizations/peerOrganizations/org2.example.com/
export FABRIC_CA_CLIENT_HOME=${PWD}/organizations/peerOrganizations/org2.example.com/ fabric-ca-client enroll -u https://admin:adminpw@localhost:8054 --caname ca-org2 --tls.certfiles "${PWD}/organizations/fabric-ca/org2/ca-cert.pem" echo 'NodeOUs:
Enable: true
ClientOUIdentifier:
Certificate: cacerts/localhost-8054-ca-org2.pem
OrganizationalUnitIdentifier: client
PeerOUIdentifier:
Certificate: cacerts/localhost-8054-ca-org2.pem
OrganizationalUnitIdentifier: peer
AdminOUIdentifier:
Certificate: cacerts/localhost-8054-ca-org2.pem
OrganizationalUnitIdentifier: admin
OrdererOUIdentifier:
Certificate: cacerts/localhost-8054-ca-org2.pem
OrganizationalUnitIdentifier: orderer' > "${PWD}/organizations/peerOrganizations/org2.example.com/msp/config.yaml" mkdir -p "${PWD}/organizations/peerOrganizations/org2.example.com/msp/tlscacerts"
cp "${PWD}/organizations/fabric-ca/org2/ca-cert.pem" "${PWD}/organizations/peerOrganizations/org2.example.com/msp/tlscacerts/ca.crt"
mkdir -p "${PWD}/organizations/peerOrganizations/org2.example.com/tlsca"
cp "${PWD}/organizations/fabric-ca/org2/ca-cert.pem" "${PWD}/organizations/peerOrganizations/org2.example.com/tlsca/tlsca.org2.example.com-cert.pem"
mkdir -p "${PWD}/organizations/peerOrganizations/org2.example.com/ca"
cp "${PWD}/organizations/fabric-ca/org2/ca-cert.pem" "${PWD}/organizations/peerOrganizations/org2.example.com/ca/ca.org2.example.com-cert.pem" fabric-ca-client register --caname ca-org2 --id.name peer0 --id.secret peer0pw --id.type peer --tls.certfiles "${PWD}/organizations/fabric-ca/org2/ca-cert.pem"
fabric-ca-client register --caname ca-org2 --id.name user1 --id.secret user1pw --id.type client --tls.certfiles "${PWD}/organizations/fabric-ca/org2/ca-cert.pem"
fabric-ca-client register --caname ca-org2 --id.name org2admin --id.secret org2adminpw --id.type admin --tls.certfiles "${PWD}/organizations/fabric-ca/org2/ca-cert.pem" fabric-ca-client enroll -u https://peer0:peer0pw@localhost:8054 --caname ca-org2 -M "${PWD}/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/msp" --csr.hosts peer0.org2.example.com --tls.certfiles "${PWD}/organizations/fabric-ca/org2/ca-cert.pem"
cp "${PWD}/organizations/peerOrganizations/org2.example.com/msp/config.yaml" "${PWD}/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/msp/config.yaml"
fabric-ca-client enroll -u https://peer0:peer0pw@localhost:8054 --caname ca-org2 -M "${PWD}/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls" --enrollment.profile tls --csr.hosts peer0.org2.example.com --csr.hosts localhost --tls.certfiles "${PWD}/organizations/fabric-ca/org2/ca-cert.pem" cp "${PWD}/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/tlscacerts/"* "${PWD}/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt"
cp "${PWD}/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/signcerts/"* "${PWD}/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/server.crt"
cp "${PWD}/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/keystore/"* "${PWD}/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/server.key" fabric-ca-client enroll -u https://user1:user1pw@localhost:8054 --caname ca-org2 -M "${PWD}/organizations/peerOrganizations/org2.example.com/users/User1@org2.example.com/msp" --tls.certfiles "${PWD}/organizations/fabric-ca/org2/ca-cert.pem"
cp "${PWD}/organizations/peerOrganizations/org2.example.com/msp/config.yaml" "${PWD}/organizations/peerOrganizations/org2.example.com/users/User1@org2.example.com/msp/config.yaml" fabric-ca-client enroll -u https://org2admin:org2adminpw@localhost:8054 --caname ca-org2 -M "${PWD}/organizations/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp" --tls.certfiles "${PWD}/organizations/fabric-ca/org2/ca-cert.pem"
cp "${PWD}/organizations/peerOrganizations/org2.example.com/msp/config.yaml" "${PWD}/organizations/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp/config.yaml"
  1. 构造orderer的组织证书,关键代码如下:
mkdir -p organizations/ordererOrganizations/example.com
export FABRIC_CA_CLIENT_HOME=${PWD}/organizations/ordererOrganizations/example.com fabric-ca-client enroll -u https://admin:adminpw@localhost:9054 --caname ca-orderer --tls.certfiles "${PWD}/organizations/fabric-ca/ordererOrg/ca-cert.pem" echo 'NodeOUs:
Enable: true
ClientOUIdentifier:
Certificate: cacerts/localhost-9054-ca-orderer.pem
OrganizationalUnitIdentifier: client
PeerOUIdentifier:
Certificate: cacerts/localhost-9054-ca-orderer.pem
OrganizationalUnitIdentifier: peer
AdminOUIdentifier:
Certificate: cacerts/localhost-9054-ca-orderer.pem
OrganizationalUnitIdentifier: admin
OrdererOUIdentifier:
Certificate: cacerts/localhost-9054-ca-orderer.pem
OrganizationalUnitIdentifier: orderer' > "${PWD}/organizations/ordererOrganizations/example.com/msp/config.yaml" mkdir -p "${PWD}/organizations/ordererOrganizations/example.com/msp/tlscacerts"
cp "${PWD}/organizations/fabric-ca/ordererOrg/ca-cert.pem" "${PWD}/organizations/ordererOrganizations/example.com/msp/tlscacerts/tlsca.example.com-cert.pem"
mkdir -p "${PWD}/organizations/ordererOrganizations/example.com/tlsca"
cp "${PWD}/organizations/fabric-ca/ordererOrg/ca-cert.pem" "${PWD}/organizations/ordererOrganizations/example.com/tlsca/tlsca.example.com-cert.pem" fabric-ca-client register --caname ca-orderer --id.name orderer --id.secret ordererpw --id.type orderer --tls.certfiles "${PWD}/organizations/fabric-ca/ordererOrg/ca-cert.pem"
fabric-ca-client register --caname ca-orderer --id.name ordererAdmin --id.secret ordererAdminpw --id.type admin --tls.certfiles "${PWD}/organizations/fabric-ca/ordererOrg/ca-cert.pem"
fabric-ca-client enroll -u https://orderer:ordererpw@localhost:9054 --caname ca-orderer -M "${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp" --csr.hosts orderer.example.com --csr.hosts localhost --tls.certfiles "${PWD}/organizations/fabric-ca/ordererOrg/ca-cert.pem" cp "${PWD}/organizations/ordererOrganizations/example.com/msp/config.yaml" "${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/config.yaml" fabric-ca-client enroll -u https://orderer:ordererpw@localhost:9054 --caname ca-orderer -M "${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/tls" --enrollment.profile tls --csr.hosts orderer.example.com --csr.hosts localhost --tls.certfiles "${PWD}/organizations/fabric-ca/ordererOrg/ca-cert.pem" cp "${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/tls/tlscacerts/"* "${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/tls/ca.crt"
cp "${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/tls/signcerts/"* "${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/tls/server.crt"
cp "${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/tls/keystore/"* "${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/tls/server.key"
mkdir -p "${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts"
cp "${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/tls/tlscacerts/"* "${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem" fabric-ca-client enroll -u https://ordererAdmin:ordererAdminpw@localhost:9054 --caname ca-orderer -M "${PWD}/organizations/ordererOrganizations/example.com/users/Admin@example.com/msp" --tls.certfiles "${PWD}/organizations/fabric-ca/ordererOrg/ca-cert.pem"
cp "${PWD}/organizations/ordererOrganizations/example.com/msp/config.yaml" "${PWD}/organizations/ordererOrganizations/example.com/users/Admin@example.com/msp/config.yaml"
  1. 启动所有容器
docker-compose -f compose/compose-test-net.yaml -f compose/docker/docker-compose-test-net.yaml up -d

以上命令成功后便可使用docker ps命令看到运行的镜像:

CONTAINER ID   IMAGE                            COMMAND                  CREATED          STATUS          PORTS                                                                    NAMES
75e842d165ea hyperledger/fabric-tools:2.4 "/bin/bash" 10 seconds ago Up 8 seconds cli
576b578063c5 hyperledger/fabric-peer:2.4 "peer node start" 16 seconds ago Up 10 seconds 0.0.0.0:9051->9051/tcp, 7051/tcp, 0.0.0.0:9445->9445/tcp peer0.org2.example.com
512d7d98c8c4 hyperledger/fabric-orderer:2.4 "orderer" 16 seconds ago Up 14 seconds 0.0.0.0:7050->7050/tcp, 0.0.0.0:7053->7053/tcp, 0.0.0.0:9443->9443/tcp orderer.example.com
276f463cc6a7 hyperledger/fabric-peer:2.4 "peer node start" 16 seconds ago Up 12 seconds 0.0.0.0:7051->7051/tcp, 0.0.0.0:9444->9444/tcp peer0.org1.example.com
8faaaaa7e17a hyperledger/fabric-ca:1.5 "sh -c 'fabric-ca-se…" 21 seconds ago Up 20 seconds 0.0.0.0:9054->9054/tcp, 7054/tcp, 0.0.0.0:19054->19054/tcp ca_orderer
c253d9b790be hyperledger/fabric-ca:1.5 "sh -c 'fabric-ca-se…" 21 seconds ago Up 20 seconds 0.0.0.0:7054->7054/tcp, 0.0.0.0:17054->17054/tcp ca_org1
0aa90a2686a8 hyperledger/fabric-ca:1.5 "sh -c 'fabric-ca-se…" 21 seconds ago Up 20 seconds 0.0.0.0:8054->8054/tcp, 7054/tcp, 0.0.0.0:18054->18054/tcp ca_org2

创建通道

官方调用

本小节基于上一节 启动CA网络,在上节CA网络启动成功后,可以直接运行以下命令创建通道:

./network.sh createChannel -c mychannel

创建通道的前提是创建该通道的创世区块,在上节步骤中,我们通过无通道、无创世区块的方式启动了整个网络,所在本节创建通道包含创建创世区块的过程。

过程详解

  1. 检查依赖,并启动网络(同上)。
  2. 设置环境变量,用于操作区块链网络
export CORE_PEER_TLS_ENABLED=true
export CHANNEL_NAME=mychannel
export ORDERER_CA=${PWD}/organizations/ordererOrganizations/example.com/tlsca/tlsca.example.com-cert.pem
export PEER0_ORG1_CA=${PWD}/organizations/peerOrganizations/org1.example.com/tlsca/tlsca.org1.example.com-cert.pem
export PEER0_ORG2_CA=${PWD}/organizations/peerOrganizations/org2.example.com/tlsca/tlsca.org2.example.com-cert.pem
export PEER0_ORG3_CA=${PWD}/organizations/peerOrganizations/org3.example.com/tlsca/tlsca.org3.example.com-cert.pem
export ORDERER_ADMIN_TLS_SIGN_CERT=${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/tls/server.crt
export ORDERER_ADMIN_TLS_PRIVATE_KEY=${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/tls/server.key
  1. 创建通道创世区块:
# 创建通道数据目录
mkdir channel-artifacts
# 配置创世区块环境变量
export FABRIC_CFG_PATH=${PWD}/configtx
configtxgen -profile TwoOrgsApplicationGenesis -outputBlock ./channel-artifacts/${CHANNEL_NAME}.block -channelID ${CHANNEL_NAME}
  1. 创建通道:
# 配置通道环境变量
export FABRIC_CFG_PATH=./config
osnadmin channel join --channelID ${CHANNEL_NAME} --config-block ./channel-artifacts/${CHANNEL_NAME}.block -o localhost:7053 --ca-file "$ORDERER_CA" --client-cert "$ORDERER_ADMIN_TLS_SIGN_CERT" --client-key "$ORDERER_ADMIN_TLS_PRIVATE_KEY"
  1. 使peer节点加入通道:
# 将org1的peer加入通道
export CORE_PEER_LOCALMSPID="Org1MSP"
export CORE_PEER_TLS_ROOTCERT_FILE=$PEER0_ORG1_CA
export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp
export CORE_PEER_ADDRESS=localhost:7051
peer channel join -b ./channel-artifacts/${CHANNEL_NAME}.block
# 将org2的peer加入通道
export CORE_PEER_LOCALMSPID="Org2MSP"
export CORE_PEER_TLS_ROOTCERT_FILE=$PEER0_ORG2_CA
export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp
export CORE_PEER_ADDRESS=localhost:9051
peer channel join -b ./channel-artifacts/${CHANNEL_NAME}.block

组织新加入通道后,后面为组织设置锚节点(非必须)。
6. 为通道获取通道最新配置块(以下流程为org1环境):

export CORE_PEER_LOCALMSPID="Org1MSP"
export CORE_PEER_TLS_ROOTCERT_FILE=$PEER0_ORG1_CA
export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp
export CORE_PEER_ADDRESS=localhost:7051
peer channel fetch config config_block.pb -o orderer.example.com:7050 --ordererTLSHostnameOverride orderer.example.com -c ${CHANNEL_NAME} --tls --cafile "$ORDERER_CA"
  1. 将配置块解码为JSON并输出为${CORE_PEER_LOCALMSPID}config.json
configtxlator proto_decode --input config_block.pb --type common.Block --output config_block.json
jq .data.data[0].payload.data.config config_block.json >"${CORE_PEER_LOCALMSPID}config.json"
  1. 追加锚节点配置:
jq '.channel_group.groups.Application.groups.'${CORE_PEER_LOCALMSPID}'.values += {"AnchorPeers":{"mod_policy": "Admins","value":{"anchor_peers": [{"host": "'$HOST'","port": '$PORT'}]},"version": "0"}}' ${CORE_PEER_LOCALMSPID}config.json > ${CORE_PEER_LOCALMSPID}modified_config.json
  1. 根据链上配置${CORE_PEER_LOCALMSPID}config.json和追加配置${CORE_PEER_LOCALMSPID}modified_config.json计算更新的配置,并将其作为一个新交易写入${CORE_PEER_LOCALMSPID}anchors.tx
configtxlator proto_encode --input ${CORE_PEER_LOCALMSPID}config.json --type common.Config --output original_config.pb
configtxlator proto_encode --input ${CORE_PEER_LOCALMSPID}modified_config.json --type common.Config --output modified_config.pb
configtxlator compute_update --channel_id "${CHANNEL_NAME}" --original original_config.pb --updated modified_config.pb --output config_update.pb
configtxlator proto_decode --input config_update.pb --type common.ConfigUpdate --output config_update.json
echo '{"payload":{"header":{"channel_header":{"channel_id":"'$CHANNEL_NAME'", "type":2}},"data":{"config_update":'$(cat config_update.json)'}}}' | jq . >config_update_in_envelope.json
configtxlator proto_encode --input config_update_in_envelope.json --type common.Envelope --output "${CORE_PEER_LOCALMSPID}anchors.tx"
  1. 更新锚节点:
peer channel update -o orderer.example.com:7050 --ordererTLSHostnameOverride orderer.example.com -c $CHANNEL_NAME -f ${CORE_PEER_LOCALMSPID}anchors.tx --tls --cafile "$ORDERER_CA"
  1. org2重复以上流程即创建成功:
echo "update org2 anchor==========="
export CORE_PEER_LOCALMSPID="Org2MSP"
export CORE_PEER_TLS_ROOTCERT_FILE=$PEER0_ORG2_CA
export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp
export CORE_PEER_ADDRESS=localhost:9051
peer channel fetch config config_block.pb -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com -c ${CHANNEL_NAME} --tls --cafile "$ORDERER_CA"
sleep 3 configtxlator proto_decode --input config_block.pb --type common.Block --output config_block.json
jq .data.data[0].payload.data.config config_block.json >"${CORE_PEER_LOCALMSPID}config.json" jq '.channel_group.groups.Application.groups.'${CORE_PEER_LOCALMSPID}'.values += {"AnchorPeers":{"mod_policy": "Admins","value":{"anchor_peers": [{"host": "localhost","port": 9051}]},"version": "0"}}' ${CORE_PEER_LOCALMSPID}config.json > ${CORE_PEER_LOCALMSPID}modified_config.json configtxlator proto_encode --input ${CORE_PEER_LOCALMSPID}config.json --type common.Config --output original_config.pb
configtxlator proto_encode --input ${CORE_PEER_LOCALMSPID}modified_config.json --type common.Config --output original_config.pb
configtxlator compute_update --channel_id "${CHANNEL_NAME}" --original original_config.pb --updated modified_config.pb --output config_update.pb
configtxlator proto_decode --input config_update.pb --type common.ConfigUpdate --output config_update.json
echo '{"payload":{"header":{"channel_header":{"channel_id":"'$CHANNEL_NAME'", "type":2}},"data":{"config_update":'$(cat config_update.json)'}}}' | jq . >config_update_in_envelope.json
configtxlator proto_encode --input config_update_in_envelope.json --type common.Envelope --output "${CORE_PEER_LOCALMSPID}anchors.tx" peer channel update -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com -c $CHANNEL_NAME -f ${CORE_PEER_LOCALMSPID}anchors.tx --tls --cafile "$ORDERER_CA"
sleep 3

部署链码

官方调用

本小节基于上一节 创建通道,在上节通道创建成功后,可以直接运行以下命令部署链码:

./network.sh deployCC -ccn mychaincode -ccp ./asset-transfer-basic-go -ccv 1.0 -ccl go

过程详解

  1. 检查参数是否正常:
  2. 下载asset-transfer-basic-go的包依赖:
pushd asset-transfer-basic-go            # 进入asset-transfer-basic-go目录
GO111MODULE=on go mod vendor # 下载go包依赖
popd #返回当前目录
  1. 检查链码是否需要初始化、设置策略、私有数据集:
  2. 设置环境变量:
export FABRIC_CFG_PATH=$PWD/config/
export CORE_PEER_TLS_ENABLED=true
export ORDERER_CA=${PWD}/organizations/ordererOrganizations/example.com/tlsca/tlsca.example.com-cert.pem
export PEER0_ORG1_CA=${PWD}/organizations/peerOrganizations/org1.example.com/tlsca/tlsca.org1.example.com-cert.pem
export PEER0_ORG2_CA=${PWD}/organizations/peerOrganizations/org2.example.com/tlsca/tlsca.org2.example.com-cert.pem
export PEER0_ORG3_CA=${PWD}/organizations/peerOrganizations/org3.example.com/tlsca/tlsca.org3.example.com-cert.pem
export ORDERER_ADMIN_TLS_SIGN_CERT=${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/tls/server.crt
export ORDERER_ADMIN_TLS_PRIVATE_KEY=${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/tls/server.key
  1. 打包链码:
peer lifecycle chaincode package mychaincode.tar.gz --path ./asset-transfer-basic-go --lang golang --label mychaincode_1.0
  1. 安装链码:
# ORG1安装链码
export CORE_PEER_LOCALMSPID="Org1MSP"
export CORE_PEER_TLS_ROOTCERT_FILE=$PEER0_ORG1_CA
export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp
export CORE_PEER_ADDRESS=localhost:7051
peer lifecycle chaincode install mychaincode.tar.gz
# ORG2安装链码
export CORE_PEER_LOCALMSPID="Org2MSP"
export CORE_PEER_TLS_ROOTCERT_FILE=$PEER0_ORG2_CA
export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp
export CORE_PEER_ADDRESS=localhost:9051
peer lifecycle chaincode install mychaincode.tar.gz

安装链码后会返回一个链码 ID 需要记下:

7. 将链码 ID 设为环境变量:

export PACKAGE_ID=mychaincode_1.0:39889cf0623cce2500261b22914a7aa9037a897bc7f6c5b36df7a922f29b05e0
  1. ORG1查询已安装链码并批准链码:
export CORE_PEER_LOCALMSPID="Org1MSP"
export CORE_PEER_TLS_ROOTCERT_FILE=$PEER0_ORG1_CA
export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp
export CORE_PEER_ADDRESS=localhost:7051
# 查询已安装链码
peer lifecycle chaincode queryinstalled
# 批准链码
peer lifecycle chaincode approveformyorg -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls --cafile "$ORDERER_CA" --channelID mychannel --name mychaincode --version 1.0 --package-id ${PACKAGE_ID} --sequence 1
  1. ORG2查询已安装链码并批准链码:
export CORE_PEER_LOCALMSPID="Org2MSP"
export CORE_PEER_TLS_ROOTCERT_FILE=$PEER0_ORG2_CA
export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp
export CORE_PEER_ADDRESS=localhost:9051
# 查询已安装链码
peer lifecycle chaincode queryinstalled
# 批准链码
peer lifecycle chaincode approveformyorg -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls --cafile "$ORDERER_CA" --channelID mychannel --name mychaincode --version 1.0 --package-id ${PACKAGE_ID} --sequence 1
  1. 检查链码是否已准备好被提交:
peer lifecycle chaincode checkcommitreadiness --channelID mychannel --name mychaincode --version 1.0 --sequence 1 --output json


11. 提交链码:

peer lifecycle chaincode commit -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls --cafile "$ORDERER_CA"  --channelID mychannel --name mychaincode --version 1.0 --sequence 1 --peerAddresses localhost:7051 --tlsRootCertFiles $PEER0_ORG1_CA --peerAddresses localhost:9051 --tlsRootCertFiles $PEER0_ORG2_CA
  1. 查询提交的链码:
peer lifecycle chaincode querycommitted --channelID mychannel --name mychaincode
  1. 调用链码:
peer chaincode invoke -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls --cafile "$ORDERER_CA" -C mychannel -n mychaincode --peerAddresses

总结

本文先是说明了fabric-samples过度的封装不利于我们了解掌握其中各个操作的真实过程,然后单独拿出test-network进行修改定制,最后详细分析了test-network中启动默认网络、启动CA网络、创建通道、部署链码的详细过程,并且给出了每个过程的代码,使我们能够根据代码一步步搭建所述网络,进一步理解Fabric架构。

相关实验源码已上传:https://github.com/wefantasy/FabricLearn

参考


  1. hyperledger. fabric-samples. Github.

Hyperledger Fabric的test-network启动过程Bash源码详解的更多相关文章

  1. Spark Streaming揭秘 Day25 StreamingContext和JobScheduler启动源码详解

    Spark Streaming揭秘 Day25 StreamingContext和JobScheduler启动源码详解 今天主要理一下StreamingContext的启动过程,其中最为重要的就是Jo ...

  2. spring mvc 启动过程及源码分析

    由于公司开源框架选用的spring+spring mvc + mybatis.使用这些框架,网上都有现成的案例:需要那些配置文件.每种类型的配置文件的节点该如何书写等等.如果只是需要项目能够跑起来,只 ...

  3. ASP.NET CORE 启动过程及源码解读

    在这个特殊的春节,大家想必都在家出不了们,远看已经到了回城里上班的日子,但是因为一只蝙蝠的原因导致我们无法回到工作岗位,大家可能有的在家远程办公,有些在家躺着看书,有的是在家打游戏:在这个特殊无聊的日 ...

  4. Springboot启动源码详解

    我们开发任何一个Spring Boot项目,都会用到如下的启动类 @SpringBootApplication public class Application { public static voi ...

  5. Netty服务端启动过程相关源码分析

    1.Netty 是怎么创建服务端Channel的呢? 我们在使用ServerBootstrap.bind(端口)方法时,最终调用其父类AbstractBootstrap中的doBind方法,相关源码如 ...

  6. 从SpringBoot启动,阅读源码设计

    目录 一.背景说明 二.SpringBoot工程 三.应用上下文 四.资源加载 五.应用环境 六.Bean对象 七.Tomcat服务 八.事件模型 九.配置加载 十.数据库集成 十一.参考源码 服务启 ...

  7. android emulator启动的两种方法详解

    android emulator启动的两种方法详解    转https://blog.csdn.net/TTS_Kevin/article/details/7452237 对于android学习者,模 ...

  8. Spring Boot 启动(二) 配置详解

    Spring Boot 启动(二) 配置详解 Spring 系列目录(https://www.cnblogs.com/binarylei/p/10198698.html) Spring Boot 配置 ...

  9. Flink的Job启动TaskManager端(源码分析)

    前面说到了  Flink的JobManager启动(源码分析)  启动了TaskManager 然后  Flink的Job启动JobManager端(源码分析)  说到JobManager会将转化得到 ...

随机推荐

  1. CF1385G口胡

    只能说很神秘??? 首先观察题面,假设给出的第一个序列为 \(a\),第二个序列为 \(b\).对于 \((a_i,b_i)\) 我们连一条边. 得到的是一个 \(n\) 个点 \(n\) 条边的不一 ...

  2. django的request对象方法初识

    1:request.post 拿到的是post请求发送过来的数据,可以将其看作是一个个的键值对 使用get方法可以通过key拿到值,如果该值是一个列表的话,get方法只能拿到列表的最后一个值,使用ge ...

  3. 使用阿里巴巴开源镜像站镜像——Kubernetes 镜像

    镜像下载.域名解析.时间同步请点击 阿里云开源镜像站 Kubernetes 镜像简介 Kubernetes 是一个开源系统,用于容器化应用的自动部署.扩缩和管理.它将构成应用的容器按逻辑单位进行分组以 ...

  4. CVE-2017-11882(Office远程代码执行)

    测试环境:win7+kali+office 2007 xp+kali+office 2003 win7 ip:10.10.1.144 xp ip: 10.10.1.126 kali ip 10.10. ...

  5. Linux 环境Skywalking部署Elasticsearch

    一.环境准备 1.Java jdk 11+(安装教程可参考https://www.cnblogs.com/sportsky/p/15973713.html) 2.elasticsearch 二.环境搭 ...

  6. 什么是 JavaConfig?

    Spring JavaConfig 是 Spring 社区的产品,它提供了配置 Spring IoC 容器的纯 Java 方法.因此它有助于避免使用 XML 配置.使用 JavaConfig 的优点在 ...

  7. String s = new String("xyz");创建了几个String Object?二者之间有什么区别?

    两个或一个,"xyz"对应一个对象,这个对象放在字符串常量缓冲区,常量"xyz"不管出现多少遍,都是缓冲区中的那一个.New String每写一遍,就创建一个新 ...

  8. 什么是 MyBatis 的接口绑定?有哪些实现方式?

    接口绑定,就是在 MyBatis 中任意定义接口,然后把接口里面的方法和 SQL 语句绑 定, 我们直接调用接口方法就可以,这样比起原来了 SqlSession 提供的方法我们可 以有更加灵活的选择和 ...

  9. 说出 JDK 1.7 中的三个新特性?

    虽然 JDK 1.7 不像 JDK 5 和 8 一样的大版本,但是,还是有很多新的特性, 如 try-with-resource 语句,这样你在使用流或者资源的时候,就不需要手动关 闭,Java 会自 ...

  10. Spring 对 DAO 的支持?

    Spring 对数据访问对象(DAO)的支持旨在简化它和数据访问技术如 JDBC, Hibernate or JDO 结合使用.这使我们可以方便切换持久层.编码时也不用担心 会捕获每种技术特有的异常.