Fabric1.4:手动启动 first-network 网络(三)
注意:本文所使用的 fabric 版本为 v1.4.3,与其它版本的网络存在差异。
手动启动 first-network 网络系列分为三部分:
第一篇单纯使用命令行的形式执行 byfn.sh 脚本中的内容,第二篇和第三篇是对手动启动网络过程所使用的命令和配置文件的解释。
启动分布式网络
手动生成 fabric 网络所需的配置文件(查看手动启动 first-network 网络(二))后,接下来需要启动区块链中提供网络服务的各个节点。fabric 采用容器技术,使用 docker-compose
这个工具来实现区块链网络所需的节点容器管理,实现方式只需要编写节点相应的配置文件即可。
docker-compose-cli.yaml
在first-network
目录下提供了一个dokcer-compose
工具所需的配置文件docker-compose-cli.yaml
,我们使用该文件启动网络节点,下面是该文件的内容:
version: '2' # 表示用的版本 2 的 YAML 版本
volumes:
orderer.example.com:
peer0.org1.example.com:
peer1.org1.example.com:
peer0.org2.example.com:
peer1.org2.example.com:
networks:
byfn:
services:
orderer.example.com: # Orderer 节点
extends: # 扩展自 base/docker-compose-base.yaml 文件的 orderer.example.com
file: base/docker-compose-base.yaml
service: orderer.example.com
container_name: orderer.example.com # 容器名称
networks:
- byfn
peer0.org1.example.com: # peer0.org1.example.com 节点
container_name: peer0.org1.example.com
extends:
file: base/docker-compose-base.yaml
service: peer0.org1.example.com
networks:
- byfn
peer1.org1.example.com: # peer1.org1.example.com 节点
container_name: peer1.org1.example.com
extends:
file: base/docker-compose-base.yaml
service: peer1.org1.example.com
networks:
- byfn
peer0.org2.example.com: # peer0.org2.example.com 节点
container_name: peer0.org2.example.com
extends:
file: base/docker-compose-base.yaml
service: peer0.org2.example.com
networks:
- byfn
peer1.org2.example.com: # peer1.org2.example.com 节点
container_name: peer1.org2.example.com
extends:
file: base/docker-compose-base.yaml
service: peer1.org2.example.com
networks:
- byfn
cli: # CLI 用户客户端节点
container_name: cli # 容器名称
image: hyperledger/fabric-tools:$IMAGE_TAG # 依赖的容器镜像
tty: true
stdin_open: true
environment: # 环境变量
- SYS_CHANNEL=$SYS_CHANNEL
- GOPATH=/opt/gopath
- CORE_VM_ENDPOINT=unix:///host/var/run/docker.sock
#- FABRIC_LOGGING_SPEC=DEBUG
- FABRIC_LOGGING_SPEC=INFO # 容器日志级别
- CORE_PEER_ID=cli # 当前节点名字 cli
- CORE_PEER_ADDRESS=peer0.org1.example.com:7051 # 连接的 peer 节点的地址
- CORE_PEER_LOCALMSPID=Org1MSP # 连接的 peer 节点所属的组织 MSPID
- CORE_PEER_TLS_ENABLED=true # 是否启动 TLS 通信
# 通信用的 TLS 证书
- CORE_PEER_TLS_CERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/server.crt
# TLS 证书对应的私钥
- CORE_PEER_TLS_KEY_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/server.key
# TLS 证书的根证书
- 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
# 设置 CLI 客户端身份账号(MSP),客户端的角色不同,权限不同,此处是管理员账号
# 普通用户账号:对账本数据进行读写操作
# 管理员账号:对账本数据进行读写,创建通道,让节点加入通道,安装并实例化链码
- CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp
working_dir: /opt/gopath/src/github.com/hyperledger/fabric/peer # 容器的默认工作目录
command: /bin/bash # 容器启动时执行的命令
volumes: # 本地系统文件路径与容器指定路径的映射
- /var/run/:/host/var/run/
- ./../chaincode/:/opt/gopath/src/github.com/chaincode
- ./crypto-config:/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/
- ./scripts:/opt/gopath/src/github.com/hyperledger/fabric/peer/scripts/
- ./channel-artifacts:/opt/gopath/src/github.com/hyperledger/fabric/peer/channel-artifacts
depends_on: # 依赖的相关容器
- orderer.example.com
- peer0.org1.example.com
- peer1.org1.example.com
- peer0.org2.example.com
- peer1.org2.example.com
networks:
- byfn
以上配置文件指定了网络中各个节点容器(共计 6 个容器,包括 1 个 Orderer节点、4 个 Peer节点和 1 个 CLI 客户端)的信息。除了 CLI 容器之外的,其他容器都有 extends 指向 base/docker-compose-base.yaml
文件,下面是关联的 docker-compose-base.yaml
文件的具体内容:
version: '2'
services:
orderer.example.com:
container_name: orderer.example.com # 容器名称
extends: # 扩展自 peer-base.yaml 文件的 orderer-base
file: peer-base.yaml
service: orderer-base
volumes: # 本地系统文件路径与容器指定路径的映射
- ../channel-artifacts/genesis.block:/var/hyperledger/orderer/orderer.genesis.block
- ../crypto-config/ordererOrganizations/example.com/orderers/orderer.example.com/msp:/var/hyperledger/orderer/msp
- ../crypto-config/ordererOrganizations/example.com/orderers/orderer.example.com/tls/:/var/hyperledger/orderer/tls
- orderer.example.com:/var/hyperledger/production/orderer
ports:
- 7050:7050 # 本地系统端口与容器监听端口的映射
peer0.org1.example.com:
container_name: peer0.org1.example.com # 容器名称
extends: # 扩展自 peer-base.yaml 文件的 peer-base
file: peer-base.yaml
service: peer-base
environment: # 环境变量
- CORE_PEER_ID=peer0.org1.example.com # peer 节点的名字
- CORE_PEER_ADDRESS=peer0.org1.example.com:7051 # peer 节点的访问地址
- CORE_PEER_LISTENADDRESS=0.0.0.0:7051 # peer 节点的监听地址,设置为 0.0.0.0 会自动读取网卡,识别实际的本机 IP
- CORE_PEER_CHAINCODEADDRESS=peer0.org1.example.com:7052 # peer 节点上链码的访问地址
- CORE_PEER_CHAINCODELISTENADDRESS=0.0.0.0:7052 # peer 节点上链码的监听地址,设置为 0.0.0.0 会自动读取网卡,识别实际的本机 IP
- CORE_PEER_GOSSIP_BOOTSTRAP=peer1.org1.example.com:8051 # gossip协议配置
- CORE_PEER_GOSSIP_EXTERNALENDPOINT=peer0.org1.example.com:7051
- CORE_PEER_LOCALMSPID=Org1MSP # 所属组织的 MSPID
volumes: # 本地系统文件路径与容器指定路径的映射
- /var/run/:/host/var/run/
- ../crypto-config/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/msp:/etc/hyperledger/fabric/msp
- ../crypto-config/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls:/etc/hyperledger/fabric/tls
- peer0.org1.example.com:/var/hyperledger/production
ports:
- 7051:7051 # 本地系统端口与容器监听端口的映射
peer1.org1.example.com:
container_name: peer1.org1.example.com
extends:
file: peer-base.yaml
service: peer-base
environment:
- CORE_PEER_ID=peer1.org1.example.com
- CORE_PEER_ADDRESS=peer1.org1.example.com:8051
- CORE_PEER_LISTENADDRESS=0.0.0.0:8051
- CORE_PEER_CHAINCODEADDRESS=peer1.org1.example.com:8052
- CORE_PEER_CHAINCODELISTENADDRESS=0.0.0.0:8052
- CORE_PEER_GOSSIP_EXTERNALENDPOINT=peer1.org1.example.com:8051
- CORE_PEER_GOSSIP_BOOTSTRAP=peer0.org1.example.com:7051
- CORE_PEER_LOCALMSPID=Org1MSP
volumes:
- /var/run/:/host/var/run/
- ../crypto-config/peerOrganizations/org1.example.com/peers/peer1.org1.example.com/msp:/etc/hyperledger/fabric/msp
- ../crypto-config/peerOrganizations/org1.example.com/peers/peer1.org1.example.com/tls:/etc/hyperledger/fabric/tls
- peer1.org1.example.com:/var/hyperledger/production
ports:
- 8051:8051
peer0.org2.example.com:
container_name: peer0.org2.example.com
extends:
file: peer-base.yaml
service: peer-base
environment:
- CORE_PEER_ID=peer0.org2.example.com
- CORE_PEER_ADDRESS=peer0.org2.example.com:9051
- CORE_PEER_LISTENADDRESS=0.0.0.0:9051
- CORE_PEER_CHAINCODEADDRESS=peer0.org2.example.com:9052
- CORE_PEER_CHAINCODELISTENADDRESS=0.0.0.0:9052
- CORE_PEER_GOSSIP_EXTERNALENDPOINT=peer0.org2.example.com:9051
- CORE_PEER_GOSSIP_BOOTSTRAP=peer1.org2.example.com:10051
- CORE_PEER_LOCALMSPID=Org2MSP
volumes:
- /var/run/:/host/var/run/
- ../crypto-config/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/msp:/etc/hyperledger/fabric/msp
- ../crypto-config/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls:/etc/hyperledger/fabric/tls
- peer0.org2.example.com:/var/hyperledger/production
ports:
- 9051:9051
peer1.org2.example.com:
container_name: peer1.org2.example.com
extends:
file: peer-base.yaml
service: peer-base
environment:
- CORE_PEER_ID=peer1.org2.example.com
- CORE_PEER_ADDRESS=peer1.org2.example.com:10051
- CORE_PEER_LISTENADDRESS=0.0.0.0:10051
- CORE_PEER_CHAINCODEADDRESS=peer1.org2.example.com:10052
- CORE_PEER_CHAINCODELISTENADDRESS=0.0.0.0:10052
- CORE_PEER_GOSSIP_EXTERNALENDPOINT=peer1.org2.example.com:10051
- CORE_PEER_GOSSIP_BOOTSTRAP=peer0.org2.example.com:9051
- CORE_PEER_LOCALMSPID=Org2MSP
volumes:
- /var/run/:/host/var/run/
- ../crypto-config/peerOrganizations/org2.example.com/peers/peer1.org2.example.com/msp:/etc/hyperledger/fabric/msp
- ../crypto-config/peerOrganizations/org2.example.com/peers/peer1.org2.example.com/tls:/etc/hyperledger/fabric/tls
- peer1.org2.example.com:/var/hyperledger/production
ports:
- 10051:10051
在 docker-compose-cli.yaml
配置文件中,由 extends 指向了一个 peer-base.yaml
配置文件,下面是又关联的 peer-base.yaml
配置文件的具体内容:
version: '2'
services:
peer-base:
image: hyperledger/fabric-peer:$IMAGE_TAG # 容器所依赖的镜像
environment: # 环境变量
- CORE_VM_ENDPOINT=unix:///host/var/run/docker.sock
# the following setting starts chaincode containers on the same
# bridge network as the peers
# https://docs.docker.com/compose/networking/
- CORE_VM_DOCKER_HOSTCONFIG_NETWORKMODE=${COMPOSE_PROJECT_NAME}_byfn
- FABRIC_LOGGING_SPEC=INFO
#- FABRIC_LOGGING_SPEC=DEBUG
- CORE_PEER_TLS_ENABLED=true # 是否开启 TLS 验证
- CORE_PEER_GOSSIP_USELEADERELECTION=true # 是否采用选举方式产生主节点
- CORE_PEER_GOSSIP_ORGLEADER=false # 是否将当前节点设定为主节点
- CORE_PEER_PROFILE_ENABLED=true # 节点启动后 PROFILE 进程是否启动
- CORE_PEER_TLS_CERT_FILE=/etc/hyperledger/fabric/tls/server.crt # Peer 节点的 TLS 证书所在路径
- CORE_PEER_TLS_KEY_FILE=/etc/hyperledger/fabric/tls/server.key # Peer 节点的 TLS 证书对应的密钥所在路径
- CORE_PEER_TLS_ROOTCERT_FILE=/etc/hyperledger/fabric/tls/ca.crt # Peer 节点的 TLS 证书的根证书所在路径
working_dir: /opt/gopath/src/github.com/hyperledger/fabric/peer # 进入容器后的默认工作目录
command: peer node start # 容器启动执行的命令
orderer-base:
image: hyperledger/fabric-orderer:$IMAGE_TAG # 指定容器的镜像
environment: # 设置环境变量
- FABRIC_LOGGING_SPEC=INFO
- ORDERER_GENERAL_LISTENADDRESS=0.0.0.0 # 监听本机地址,如果使用 0.0.0.0 会自动读取网卡,识别实际的本机 IP
- ORDERER_GENERAL_GENESISMETHOD=file # 创世区块的形式
- ORDERER_GENERAL_GENESISFILE=/var/hyperledger/orderer/orderer.genesis.block # 指定在 Orderer 容器中创世区块的所在路径
- ORDERER_GENERAL_LOCALMSPID=OrdererMSP # 当前 Orderer 节点的 MSPID
- ORDERER_GENERAL_LOCALMSPDIR=/var/hyperledger/orderer/msp # 指定当前 Orderer 节点的 MSP 所在路径
# enabled TLS
- ORDERER_GENERAL_TLS_ENABLED=true # 是否开启 TLS 验证
- ORDERER_GENERAL_TLS_PRIVATEKEY=/var/hyperledger/orderer/tls/server.key # Orderer 节点的 TLS 证书所在路径
- ORDERER_GENERAL_TLS_CERTIFICATE=/var/hyperledger/orderer/tls/server.crt # Orderer 节点的 TLS 证书对应的密钥所在路径
- ORDERER_GENERAL_TLS_ROOTCAS=[/var/hyperledger/orderer/tls/ca.crt] # Orderer 节点的 TLS 证书的根证书所在路径
- ORDERER_KAFKA_TOPIC_REPLICATIONFACTOR=1
- ORDERER_KAFKA_VERBOSE=true
- ORDERER_GENERAL_CLUSTER_CLIENTCERTIFICATE=/var/hyperledger/orderer/tls/server.crt
- ORDERER_GENERAL_CLUSTER_CLIENTPRIVATEKEY=/var/hyperledger/orderer/tls/server.key
- ORDERER_GENERAL_CLUSTER_ROOTCAS=[/var/hyperledger/orderer/tls/ca.crt]
working_dir: /opt/gopath/src/github.com/hyperledger/fabric # 进入容器后的默认工作目录
command: orderer # 容器启动执行的命令
启动网络节点
使用 docker-compose
工具将 docker-compose-cli.yaml
文件作为参数,启动提供网络服务的各个节点:
$ docker-compose -f docker-compose-cli.yaml up -d
参数说明:
- -f: 启动容器时所使用的
docker-compose
配置文件 - -d:是否显示网络启动过程中的实时日志信息,如果需要查看详细网络启动日志,则可以不提供此参数
如果节点启动成功,会出现如下信息:
Creating network "net_byfn" with the default driver
Creating volume "net_peer0.org2.example.com" with default driver
Creating volume "net_peer1.org2.example.com" with default driver
Creating volume "net_peer1.org1.example.com" with default driver
Creating volume "net_peer0.org1.example.com" with default driver
Creating volume "net_orderer.example.com" with default driver
Creating orderer.example.com ...
Creating peer0.org2.example.com ...
Creating peer1.org2.example.com ...
Creating peer0.org1.example.com ...
Creating peer1.org1.example.com ...
Creating orderer.example.com
Creating peer0.org2.example.com
Creating peer0.org1.example.com
Creating peer1.org1.example.com
Creating peer1.org2.example.com ... done
Creating cli ...
Creating cli ... done
Peer 节点启动之后,默认情况下没有加入区块链网络中的任何应用通道,也不会与 Orderer 节点建立连接,只是单纯的容器启动。我们需要使用 CLI 客户端对 Peer 节点进行操作,让它加入网络和指定的应用通道。
应用通道的创建与测试
我们使用 docker exec 命令进行 CLI 容器:
$ docker exec -it cli bash
启动成功,会看到以下内容:
root@5e7e7a9c84ef:/opt/gopath/src/github.com/hyperledger/fabric/peer#
CLI 容器是用户客户端节点,默认情况下是以 admin.org1
身份连接 peer0.org1
运行命令。如果想切换 CLI 客户端的身份和连接的节点,则需要对以下四个环境变量进行修改:
# peer0.org1 的环境变量
CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp
CORE_PEER_ADDRESS=peer0.org1.example.com:7051
CORE_PEER_LOCALMSPID="Org1MSP"
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
创建应用通道
使用以下命令通道,设置的通道名称必须与创建通道交易配置文件时指定的通道名称相同:
# export CHANNEL_NAME=mychannel
# export 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
# peer channel create -o orderer.example.com:7050 -c $CHANNEL_NAME -f ./channel-artifacts/channel.tx --tls --cafile $ORDERER_CA
参数说明:
- -o:要连接的 Orderer 节点地址
- -c:要创建的应用通道的名称
- -f:创建应用通道时所使用的应用通道交易配置文件
- --tls:开启 TLS 验证
- --cafile: Orderer 节点的根证书路径,用于验证 TLS 握手
成功执行,返回如下内容:
2019-12-02 14:01:20.468 UTC [channelCmd] InitCmdFactory -> INFO 001 Endorser and orderer connections initialized
2019-12-02 14:01:20.642 UTC [cli.common] readBlock -> INFO 002 Received block: 0
该命令执行之后,会返回一个与应用通道同名的的区块文件 mychannel.block
,该文件是应用通道的创世区块,peer 节点只有拥有该文件才可以加入到已创建的应用通道中。返回的区块文件保存在 CLI 容器的当前目录下,使用 ll
命令查看容器当前目录,可以找到该区块文件:
total 44
drwxr-xr-x 5 root root 4096 Dec 2 14:01 ./
drwxr-xr-x 3 root root 4096 Dec 2 13:47 ../
drwxr-xr-x 2 1000 1000 4096 Dec 2 13:46 channel-artifacts/
drwxr-xr-x 4 1000 1000 4096 Dec 2 13:45 crypto/
-rw-r--r-- 1 root root 20559 Dec 2 14:01 mychannel.block
drwxr-xr-x 2 1000 1000 4096 Oct 14 14:24 scripts/
各节点加入应用通道
peer0.org1 加入应用通道
CLI 客户端默认的身份为 admin.org1
,连接 peer0.org1
节点。使用如下命令将 peer0.org1
加入应用通道:
# peer channel join -b mychannel.block
参数说明:
-
join:将当前 Peer 节点加入应用通道中
-
-b: 指定当前节点要加入/连接至哪个应用通道
-
mychannel.block: 是先前创建应用通道时保存在 CLI 容器当前目录的区块文件
成功执行,返回如下内容:
2019-12-02 14:15:44.673 UTC [channelCmd] InitCmdFactory -> INFO 001 Endorser and orderer connections initialized
2019-12-02 14:15:44.802 UTC [channelCmd] executeJoin -> INFO 002 Successfully submitted proposal to join channel
peer1.org1 加入应用通道
更改 CLI 容器的环境变量,让当前节点变为 peer1.org1
:
# CORE_PEER_ADDRESS=peer1.org1.example.com:8051
使用如下命令将 peer1.org1 加入应用通道:
# peer channel join -b mychannel.block
peer0.org2 加入应用通道
更改 CLI 容器的环境变量,让当前用户变为 admin.org2
,连接 peer0.org2
:
# CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp
# CORE_PEER_ADDRESS=peer0.org2.example.com:9051
# CORE_PEER_LOCALMSPID="Org2MSP"
# CORE_PEER_TLS_ROOTCERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt
使用如下命令将 peer0.org2
加入应用通道:
# peer channel join -b mychannel.block
peer1.org2 加入应用通道
更改 CLI 容器的环境变量,让当前节点变为 peer1.org2
:
# CORE_PEER_ADDRESS=peer1.org2.example.com:10051
使用如下命令将 peer1.org2
加入应用通道:
# peer channel join -b mychannel.block
注意:
上述节点加入都能使用 mychannel.block
,是因为使用同一个 CLI 容器连接所有节点。如果各节点使用不同的 CLI 容器,有以下两个解决方式:
-
把
mychannel.block
复制过去 -
使用通道提取命令:
# peer channel fetch oldest mychannel.block -o orderer.example.com:7050 -c $CHANNEL_NAME --tls --cafile $ORDERER_CA
需要注意,一般只有管理员 Admin 或有读取权限的用户 User 才能使用通道提取的节点(可以在
configtx.yaml
预定义策略规则中设置)。
更新锚节点并安装链码
peer0.org1 更新为锚节点并安装链码
# CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp
# CORE_PEER_ADDRESS=peer0.org1.example.com:7051
# CORE_PEER_LOCALMSPID="Org1MSP"
# 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
使用如下命令更新将 peer0.org1
节点定义为 org1 的锚节点:
# peer channel update -o orderer.example.com:7050 -c $CHANNEL_NAME -f ./channel-artifacts/Org1MSPanchors.tx --tls --cafile $ORDERER_CA
2019-12-02 15:08:09.306 UTC [channelCmd] InitCmdFactory -> INFO 001 Endorser and orderer connections initialized
2019-12-02 15:08:09.335 UTC [channelCmd] update -> INFO 002 Successfully submitted channel update
在 peer0.org1
节点上安装链码:
# peer chaincode install -n mycc -v 1.0 -p github.com/chaincode/chaincode_example02/go/
2019-12-02 15:08:16.912 UTC [chaincodeCmd] checkChaincodeCmdParams -> INFO 001 Using default escc
2019-12-02 15:08:16.912 UTC [chaincodeCmd] checkChaincodeCmdParams -> INFO 002 Using default vscc
2019-12-02 15:08:17.113 UTC [chaincodeCmd] install -> INFO 003 Installed remotely response:<status:200 payload:"OK" >
peer0.org2 更新为锚节点并安装链码
# CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp
# CORE_PEER_ADDRESS=peer0.org2.example.com:9051
# CORE_PEER_LOCALMSPID="Org2MSP"
# CORE_PEER_TLS_ROOTCERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt
使用如下命令更新将 peer0.org2
节点定义为 org2 的锚节点:
# peer channel update -o orderer.example.com:7050 -c $CHANNEL_NAME -f ./channel-artifacts/Org2MSPanchors.tx --tls --cafile $ORDERER_CA
在 peer0.org2
节点上安装链码:
# peer chaincode install -n mycc -v 1.0 -p github.com/chaincode/chaincode_example02/go/
实例化链码并测试
实例化链码
通道上的链码采用多次安装,一次实例化的方式,且必须是管理员用户 admin 实例化链码。在通道上实例化链码,为链码设置背书策略,在目标节点上启动链码容器。
# 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')"
2019-12-02 15:22:44.911 UTC [chaincodeCmd] checkChaincodeCmdParams -> INFO 001 Using default escc
2019-12-02 15:22:44.911 UTC [chaincodeCmd] checkChaincodeCmdParams -> INFO 002 Using default vscc
实例化之后,某个安装有链码的 peer 尝试与链码交换,就会为它们启动一个链码容器。任何安装链码的 peer,在被调用时都会检查是否生成了链码容器,如果没有生成,则首先生成链码容器。
Query
查询 a 的值,确保是否正确实例化了链码并写入状态数据库:
# peer chaincode query -C $CHANNEL_NAME -n mycc -c '{"Args":["query","a"]}'
返回了 100,说明正确安装和实例化了。
Invoke
现在从 a 账户转 10 到 b 账户,这个交易将创建一个新的区块并更新状态 DB。因此,该交易需要 peer0.org1
和 peer0.org2
的背书,多个节点的背书由 --peerAddresses
标志指定:
# peer chaincode invoke -o orderer.example.com:7050 --tls --cafile $ORDERER_CA -C $CHANNEL_NAME -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:9051 --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"]}'
2019-12-02 15:25:16.413 UTC [chaincodeCmd] chaincodeInvokeOrQuery -> INFO 001 Chaincode invoke successful. result: status:200
在 peer1.org1 上安装链码
# CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp
# CORE_PEER_ADDRESS=peer1.org1.example.com:8051
# CORE_PEER_LOCALMSPID="Org1MSP"
# CORE_PEER_TLS_ROOTCERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer1.org1.example.com/tls/ca.crt
# peer chaincode install -n mycc -v 1.0 -p github.com/chaincode/chaincode_example02/go/
2019-12-02 15:29:56.247 UTC [chaincodeCmd] checkChaincodeCmdParams -> INFO 001 Using default escc
2019-12-02 15:29:56.251 UTC [chaincodeCmd] checkChaincodeCmdParams -> INFO 002 Using default vscc
2019-12-02 15:29:56.399 UTC [chaincodeCmd] install -> INFO 003 Installed remotely response:<status:200 payload:"OK" >
Query
查询 a 的值,确保是否正确实例化了链码并写入状态数据库:
# peer chaincode query -C $CHANNEL_NAME -n mycc -c '{"Args":["query","a"]}'
返回了 90,说明正确安装和实例化了。
查看日志:
使用 docker ps
命令,可以查看到有三个链码容器运行,分别是:dev-peer0.org1.example.com-mycc-1.0
、dev-peer0.org2.example.com-mycc-1.0
和 dev-peer1.org1.example.com-mycc-1.0
。可以使用 docker logs
命令查看日志:
$ docker logs dev-peer0.org2.example.com-mycc-1.0
ex02 Init
Aval = 100, Bval = 200
ex02 Invoke
Query Response:{"Name":"a","Amount":"100"}
ex02 Invoke
Aval = 90, Bval = 210
$ docker logs dev-peer0.org1.example.com-mycc-1.0
ex02 Invoke
Aval = 90, Bval = 210
$ docker logs dev-peer1.org1.example.com-mycc-1.0
ex02 Invoke
Query Response:{"Name":"a","Amount":"90"}
清除分布式网络
$ docker-compose -f docker-compose-cli.yaml down
成功执行返回:
Stopping cli ... done
Stopping orderer.example.com ... done
Stopping peer1.org2.example.com ... done
Stopping peer0.org1.example.com ... done
Stopping peer1.org1.example.com ... done
Stopping peer0.org2.example.com ... done
Removing cli ... done
Removing orderer.example.com ... done
Removing peer1.org2.example.com ... done
Removing peer0.org1.example.com ... done
Removing peer1.org1.example.com ... done
Removing peer0.org2.example.com ... done
Removing network net_byfn
该命令暂停并移除网络中的容器节点,但是不会删除网络启动过程生成的配置文件,所以手动删除 crypto-config
和 channel-artifacts
目录下的全部配置文件。需要注意的是,channel-artifacts
文件夹不能删除,网络启动过程会自动创建 crypto-config
文件夹,但不会创建 channel-artifacts
文件夹。因此,如果误删了 channel-artifacts
文件夹,请手动创建它。
参考
- 《Hyperledger Fabric 菜鸟进阶攻略》
- 《Hyperledger Fabric技术内幕 架构设计与实现原理》