多机搭建前准备
本教程使用的是Ubuntu操作系统,所需要的环境包括docker
的安装golang
的安装fabric
的安装等。
1. 网络结构
我们要搭建一个多机多节点的网络,结构如下。网络中有两个组织分别为org1
、org2
,每个组织各有一个peer
节点,同时还有一个orderer
节点。
2. 设置网络host
首先右键打开终端,然后使用以下命令,我们在三台虚拟机中分别查看当前虚拟机的IP,其中最后一行为本机IP。
其中ens3
一栏中的inet地址为本机IP地址。
配置所有服务器网络host,在三台虚拟机中都进行以下操作。
在最后插入(IP与host任意指定,确定后不能更改)。
Copy 172.17.0.10 orderer.example.com
172.17.0.11 peer0.org1.example.com
172.17.0.12 peer0.org2.example.com
3. ssh配置
在多机搭建的过程中我们会使用到scp
命令。Linux scp
命令用于 Linux 之间复制文件和目录。
scp
是 secure copy
的缩写, scp
是 Linux 系统下基于 ssh 登陆进行安全的远程文件拷贝命令。
以下内容需要在三台虚拟机中都操作。
安装好ssh后输入以下命令切换到root
账户。
输入以下命令设置root
账户密码。
输入要修改的root
用户密码,输出信息如下:
Copy Changing password for user root.New password: BAD PASSWORD: The password is shorter than 8 charactersRetype new password: passwd: all authentication tokens updated successfully.
现在我们就可以使用scp
命令来跨主机传输文件了。
生成Fabric证书
1. 创建项目目录
在三台虚拟机上使用以下命令创建相同的项目目录(三台虚拟机项目路径要相同)。
Copy cd ~/hyperledgermkdir multinodes
2. 编写证书文件
首先使用以下命令进入项目目录。
Copy cd ~/hyperledger/multinodes
使用以下命令将模板文件复制到当前目录下。
Copy cryptogen showtemplate > crypto-config.yaml
将配置文件进行修改,修改如下。
Copy OrdererOrgs:
- Name: Orderer
Domain: example.com
EnableNodeOUs: true
Specs:
- Hostname: orderer
PeerOrgs:
- Name: org1
Domain: org1.example.com
EnableNodeOUs: true
Template:
Count: 1
Users:
Count: 1
- Name: org2
Domain: org2.example.com
EnableNodeOUs: true
Template:
Count: 1
Users:
Count: 1
3. 生成证书文件
使用以下命令生成证书文件。
Copy cryptogen generate --config=crypto-config.yaml
使用ls
命令查看生成的文件,可以看到生成了crypto-config
文件,这里存放所有的证书文件。
Copy crypto-config crypto-config.yaml
使用scp
命令将证书文件复制到其他两台虚拟机中(使用scp
命令时会要求输入主机密码)。
Copy scp -r ./crypto-config root@172.17.0.11:~/hyperledger/multinodes/
Copy scp -r ./crypto-config root@172.17.0.12:~/hyperledger/multinodes/
复制后使用以下命令在其他两台虚拟机的multinodes
目录下查看是否复制成功。
生成通道文件
1. 创世块文件的编写
首先回到orderer节点的虚拟机。
首先我们可以参考官方示例项目test-network
中的configtx.yaml
配置文件。
将configtx.yaml
改为以下内容。
Copy ---
Organizations:
- &OrdererOrg
Name: OrdererOrg
ID: OrdererMSP
MSPDir: ./crypto-config/ordererOrganizations/example.com/msp
Policies:
Readers:
Type: Signature
Rule: "OR('OrdererMSP.member')"
Writers:
Type: Signature
Rule: "OR('OrdererMSP.member')"
Admins:
Type: Signature
Rule: "OR('OrdererMSP.admin')"
OrdererEndpoints:
- orderer.example.com:7050
- &Org1
Name: Org1MSP
ID: Org1MSP
MSPDir: ./crypto-config/peerOrganizations/org1.example.com/msp
Policies:
Readers:
Type: Signature
Rule: "OR('Org1MSP.admin', 'Org1MSP.peer', 'Org1MSP.client')"
Writers:
Type: Signature
Rule: "OR('Org1MSP.admin', 'Org1MSP.client')"
Admins:
Type: Signature
Rule: "OR('Org1MSP.admin')"
Endorsement:
Type: Signature
Rule: "OR('Org1MSP.peer')"
AnchorPeers:
- Host: peer0.org1.example.com
Port: 7051
- &Org2
Name: Org2MSP
ID: Org2MSP
MSPDir: ./crypto-config/peerOrganizations/org2.example.com/msp
Policies:
Readers:
Type: Signature
Rule: "OR('Org2MSP.admin', 'Org2MSP.peer', 'Org2MSP.client')"
Writers:
Type: Signature
Rule: "OR('Org2MSP.admin', 'Org2MSP.client')"
Admins:
Type: Signature
Rule: "OR('Org2MSP.admin')"
Endorsement:
Type: Signature
Rule: "OR('Org2MSP.peer')"
AnchorPeers:
- Host: peer0.org2.example.com
Port: 9051
Capabilities:
Channel: &ChannelCapabilities
V2_0: true
Orderer: &OrdererCapabilities
V2_0: true
Application: &ApplicationCapabilities
V2_0: true
Application: &ApplicationDefaults
Organizations:
Policies:
Readers:
Type: ImplicitMeta
Rule: "ANY Readers"
Writers:
Type: ImplicitMeta
Rule: "ANY Writers"
Admins:
Type: ImplicitMeta
Rule: "MAJORITY Admins"
LifecycleEndorsement:
Type: ImplicitMeta
Rule: "MAJORITY Endorsement"
Endorsement:
Type: ImplicitMeta
Rule: "MAJORITY Endorsement"
Capabilities:
<<: *ApplicationCapabilities
Orderer: &OrdererDefaults
OrdererType: solo
Addresses:
- orderer.example.com:7050
EtcdRaft:
Consenters:
- Host: orderer.example.com
Port: 7050
ClientTLSCert: ../organizations/ordererOrganizations/example.com/orderers/orderer.example.com/tls/server.crt
ServerTLSCert: ../organizations/ordererOrganizations/example.com/orderers/orderer.example.com/tls/server.crt
BatchTimeout: 2s
BatchSize:
MaxMessageCount: 10
AbsoluteMaxBytes: 99 MB
PreferredMaxBytes: 512 KB
Organizations:
Policies:
Readers:
Type: ImplicitMeta
Rule: "ANY Readers"
Writers:
Type: ImplicitMeta
Rule: "ANY Writers"
Admins:
Type: ImplicitMeta
Rule: "MAJORITY Admins"
BlockValidation:
Type: ImplicitMeta
Rule: "ANY Writers"
Channel: &ChannelDefaults
Policies:
Readers:
Type: ImplicitMeta
Rule: "ANY Readers"
Writers:
Type: ImplicitMeta
Rule: "ANY Writers"
Admins:
Type: ImplicitMeta
Rule: "MAJORITY Admins"
Capabilities:
<<: *ChannelCapabilities
Profiles:
TwoOrgsOrdererGenesis:
<<: *ChannelDefaults
Orderer:
<<: *OrdererDefaults
Organizations:
- *OrdererOrg
Capabilities:
<<: *OrdererCapabilities
Consortiums:
SampleConsortium:
Organizations:
- *Org1
- *Org2
TwoOrgsChannel:
Consortium: SampleConsortium
<<: *ChannelDefaults
Application:
<<: *ApplicationDefaults
Organizations:
- *Org1
- *Org2
Capabilities:
<<: *ApplicationCapabilities
与单节点搭建的区别:
Organizations部分多了Org2的配置。
Profiles的部分创世块名称与通道名称不同。单节点搭建部分为soloOrgsOrdererGenesis和soloOrgsChannel,多节点搭建部分为TwoOrgsOrdererGenesis和TwoOrgsChannel。(创世块名称与通道名称自己任意取,但是后面使用命令生成文件时命令要与配置文件所定义的名称一致)
Profiles部分创世块配置与通道配置中都多加入了Org2。
2. 生成创世块文件和通道文件
使用以下命令生成创世区块。
Copy configtxgen -profile TwoOrgsOrdererGenesis -channelID fabric-channel -outputBlock ./channel-artifacts/genesis.block
使用以下命令生成通道文件。
Copy configtxgen -profile TwoOrgsChannel -outputCreateChannelTx ./channel-artifacts/channel.tx -channelID mychannel
使用以下命令为 Org1 定义锚节点。
Copy configtxgen -profile TwoOrgsChannel -outputAnchorPeersUpdate ./channel-artifacts/Org1MSPanchors.tx -channelID mychannel -asOrg Org1MSP
使用以下命令为 Org2 定义锚节点。
Copy configtxgen -profile TwoOrgsChannel -outputAnchorPeersUpdate ./channel-artifacts/Org2MSPanchors.tx -channelID mychannel -asOrg Org2MSP
使用以下命令将生成的文件拷贝到另两台主机(过程中会需要输入宿主机的密码)。
Copy scp -r ./channel-artifacts root@172.17.0.11:~/hyperledger/multinodes/scp -r ./channel-artifacts root@172.17.0.11:~/hyperledger/multinodes/
复制后使用以下命令在其他两台虚拟机的multinodes
目录下查看是否复制成功。
docker-compose文件编写
在单节点中我们编写过一个docker-compose文件,在其中我们配置了orderer节点与peer节点。在多机部署的时候我们需要为每台虚拟机都编写一个docker-compose文件来配置相应的节点。多机部署与单机部署的配置文件内容大致相同,下面会介绍单机与多机的异同点。
1. orderer节点
使用以下命令在orderer节点的虚拟机的项目路径上创建一个docker-compose.yaml
文件。
Copy cd ~/hyperledger/multinodesvim docker-compose.yaml
写入以下内容后,保存退出文件。
Copy version: '2'
services:
orderer.example.com:
container_name: orderer.example.com
image: hyperledger/fabric-orderer:latest
environment:
- FABRIC_LOGGING_SPEC=INFO
- ORDERER_GENERAL_LISTENADDRESS=0.0.0.0
- ORDERER_GENERAL_LISTENPORT=7050
- ORDERER_GENERAL_GENESISMETHOD=file
- ORDERER_GENERAL_GENESISFILE=/var/hyperledger/orderer/orderer.genesis.block
- ORDERER_GENERAL_LOCALMSPID=OrdererMSP
- ORDERER_GENERAL_LOCALMSPDIR=/var/hyperledger/orderer/msp
- ORDERER_GENERAL_TLS_ENABLED=true
- ORDERER_GENERAL_TLS_PRIVATEKEY=/var/hyperledger/orderer/tls/server.key
- ORDERER_GENERAL_TLS_CERTIFICATE=/var/hyperledger/orderer/tls/server.crt
- ORDERER_GENERAL_TLS_ROOTCAS=[/var/hyperledger/orderer/tls/ca.crt]
- 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
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
ports:
- 7050:7050
extra_hosts:
- "orderer.example.com:172.17.0.10"
- "peer0.org1.example.com:172.17.0.11"
- "peer0.org2.example.com:172.17.0.12"
与单机搭建的不同:
没有了卷挂载目录orderer.example.com:/var/hyperledger/production/orderer
。
单机搭建中的网络名networks: - example
改为extra_hosts:
,因为我们是多机搭建有真实的IP,所以网络名称都改为真实的IP地址。
2. org1
Fabric中peer节点的世界状态数据库默认是Leveldb,在这个部分我们将使用Couchdb。
Fabric的状态存储支持可插拔的模式,兼容LevelDB、CouchDB等存储。Fabric使用CouchDB作为状态存储与其他数据库相比具有较多优势:
CouchDB是一种NoSQL解决方案。它是一个面向文档的数据库,其中文档字段存储为键值映射。字段可以是简单的键值对、列表或映射。除了支持类似LevelDB的键控/合成键/键范围查询之外,CouchDB还支持完整的数据富查询功能,比如针对整个区块链数据的非键查询,因为它的数据内容是以JSON格式存储的,并且是完全可查询的。因此,CouchDB可以满足LevelDB不支持的许多用例的链代码、审计和报告需求。
CouchDB还可以增强区块链中的遵从性和数据保护的安全性。因为它能够通过筛选和屏蔽事务中的各个属性来实现字段级别的安全性,并且只在需要时授权只读权限。
CouchDB属于CAP定理的ap类型(可用性和分区公差)。它使用具有最终一致性的主-主复制模型。更多信息可以在CouchDB文档的最终一致性页面上找到。然而,在每个fabric对等点下,没有数据库副本,对数据库的写操作保证一致和持久(而不是最终的一致性)。
CouchDB是Fabric的第一个外部可插入状态数据库,可以而且应该有其他外部数据库选项。例如,IBM为其区块链启用关系数据库。还可能需要cp类型(一致性和分区容忍度)的数据库,以便在不保证应用层的情况下实现数据一致性。
使用以下命令在org1节点的虚拟机的项目路径上创建一个docker-compose.yaml
文件。
Copy cd ~/hyperledger/multinodesvim docker-compose.yaml
vim docker-compose.yaml
Copy version: '2'
services:
couchdb0.org1.example.com:
container_name: couchdb0.org1.example.com
image: couchdb:3.1
environment:
- COUCHDB_USER=admin
- COUCHDB_PASSWORD=adminpw
ports:
- 5984:5984
peer0.org1.example.com:
container_name: peer0.org1.example.com
image: hyperledger/fabric-peer:latest
environment:
- CORE_VM_ENDPOINT=unix:///host/var/run/docker.sock
- CORE_PEER_ID=peer0.org1.example.com
- CORE_PEER_ADDRESS=peer0.org1.example.com:7051
- CORE_PEER_LISTENADDRESS=0.0.0.0:7051
- CORE_PEER_CHAINCODEADDRESS=peer0.org1.example.com:7052
- CORE_PEER_CHAINCODELISTENADDRESS=0.0.0.0:7052
- CORE_PEER_GOSSIP_BOOTSTRAP=peer0.org1.example.com:7051
- CORE_PEER_GOSSIP_EXTERNALENDPOINT=peer0.org1.example.com:7051
- CORE_PEER_LOCALMSPID=Org1MSP
- FABRIC_LOGGING_SPEC=INFO
- CORE_PEER_TLS_ENABLED=true
- CORE_PEER_GOSSIP_USELEADERELECTION=true
- CORE_PEER_GOSSIP_ORGLEADER=false
- CORE_PEER_PROFILE_ENABLED=true
- CORE_PEER_TLS_CERT_FILE=/etc/hyperledger/fabric/tls/server.crt
- CORE_PEER_TLS_KEY_FILE=/etc/hyperledger/fabric/tls/server.key
- CORE_PEER_TLS_ROOTCERT_FILE=/etc/hyperledger/fabric/tls/ca.crt
- CORE_CHAINCODE_EXECUTETIMEOUT=300s
- CORE_LEDGER_STATE_STATEDATABASE=CouchDB
- CORE_LEDGER_STATE_COUCHDBCONFIG_COUCHDBADDRESS=couchdb0.org1.example.com:5984
- CORE_LEDGER_STATE_COUCHDBCONFIG_USERNAME=admin
- CORE_LEDGER_STATE_COUCHDBCONFIG_PASSWORD=adminpw
depends_on:
- couchdb0.org1.example.com
working_dir: /opt/gopath/src/github.com/hyperledger/fabric/peer
command: peer node start
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
ports:
- 7051:7051
- 7052:7052
- 7053:7053
extra_hosts:
- "orderer.example.com:172.17.0.10"
- "peer0.org1.example.com:172.17.0.11"
- "peer0.org2.example.com:172.17.0.12"
cli:
container_name: cli
image: hyperledger/fabric-tools:latest
tty: true
stdin_open: true
environment:
- GOPATH=/opt/gopath
- CORE_VM_ENDPOINT=unix:///host/var/run/docker.sock
- FABRIC_LOGGING_SPEC=INFO
- CORE_PEER_ID=cli
- CORE_PEER_ADDRESS=peer0.org1.example.com:7051
- CORE_PEER_LOCALMSPID=Org1MSP
- CORE_PEER_TLS_ENABLED=true
- 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
- 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
- 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_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/go/:/opt/gopath/src/github.com/hyperledger/fabric-cluster/chaincode/go
- ./crypto-config:/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/
- ./channel-artifacts:/opt/gopath/src/github.com/hyperledger/fabric/peer/channel-artifacts
extra_hosts:
- "orderer.example.com:172.17.0.10"
- "peer0.org1.example.com:172.17.0.11"
- "peer0.org2.example.com:172.17.0.12"
与单机搭建的不同:
peer0节点环境变量多了CORE_LEDGER_STATE_STATEDATABASE=CouchDB
,表示peer0节点的状态数据库采用了couchdb。
多了depends_on: - couchdb0.org1.example.com
,表示在couchdb启动后再启动peer0节点。
单机搭建中的网络名networks: - example
改为extra_hosts:
,因为我们是多机搭建有真实的IP,所以网络名称都改为真实的IP地址。
3. org2
组织二的配置文件与组织一基本相同,唯一不同点是把org1改为org2。
使用以下命令在org2节点的虚拟机的项目路径上创建一个docker-compose.yaml
文件。
Copy cd ~/hyperledger/multinodesvim docker-compose.yaml
写入以下内容后,保存退出文件。
Copy version: '2'
services:
couchdb0.org2.example.com:
container_name: couchdb0.org2.example.com
image: couchdb:3.1
environment:
- COUCHDB_USER=admin
- COUCHDB_PASSWORD=adminpw
ports:
- 5984:5984
peer0.org2.example.com:
container_name: peer0.org2.example.com
image: hyperledger/fabric-peer:latest
environment:
- CORE_VM_ENDPOINT=unix:///host/var/run/docker.sock
- CORE_PEER_ID=peer0.org2.example.com
- CORE_PEER_ADDRESS=peer0.org2.example.com:7051
- CORE_PEER_LISTENADDRESS=0.0.0.0:7051
- CORE_PEER_CHAINCODEADDRESS=peer0.org2.example.com:7052
- CORE_PEER_CHAINCODELISTENADDRESS=0.0.0.0:7052
- CORE_PEER_GOSSIP_BOOTSTRAP=peer0.org2.example.com:7051
- CORE_PEER_GOSSIP_EXTERNALENDPOINT=peer0.org2.example.com:7051
- CORE_PEER_LOCALMSPID=Org2MSP
- FABRIC_LOGGING_SPEC=INFO
- CORE_PEER_TLS_ENABLED=true
- CORE_PEER_GOSSIP_USELEADERELECTION=true
- CORE_PEER_GOSSIP_ORGLEADER=false
- CORE_PEER_PROFILE_ENABLED=true
- CORE_PEER_TLS_CERT_FILE=/etc/hyperledger/fabric/tls/server.crt
- CORE_PEER_TLS_KEY_FILE=/etc/hyperledger/fabric/tls/server.key
- CORE_PEER_TLS_ROOTCERT_FILE=/etc/hyperledger/fabric/tls/ca.crt
- CORE_CHAINCODE_EXECUTETIMEOUT=300s
- CORE_LEDGER_STATE_STATEDATABASE=CouchDB
- CORE_LEDGER_STATE_COUCHDBCONFIG_COUCHDBADDRESS=couchdb0.org2.example.com:5984
- CORE_LEDGER_STATE_COUCHDBCONFIG_USERNAME=admin
- CORE_LEDGER_STATE_COUCHDBCONFIG_PASSWORD=adminpw
depends_on:
- couchdb0.org2.example.com
working_dir: /opt/gopath/src/github.com/hyperledger/fabric/peer
command: peer node start
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
ports:
- 7051:7051
- 7052:7052
- 7053:7053
extra_hosts:
- "orderer.example.com:172.17.0.10"
- "peer0.org1.example.com:172.17.0.11"
- "peer0.org2.example.com:172.17.0.12"
cli:
container_name: cli
image: hyperledger/fabric-tools:latest
tty: true
stdin_open: true
environment:
- GOPATH=/opt/gopath
- CORE_VM_ENDPOINT=unix:///host/var/run/docker.sock
- FABRIC_LOGGING_SPEC=INFO
- CORE_PEER_ID=cli
- CORE_PEER_ADDRESS=peer0.org2.example.com:7051
- CORE_PEER_LOCALMSPID=Org2MSP
- CORE_PEER_TLS_ENABLED=true
- CORE_PEER_TLS_CERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/server.crt
- CORE_PEER_TLS_KEY_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/server.key
- 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
- CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp
working_dir: /opt/gopath/src/github.com/hyperledger/fabric/peer
command: /bin/bash
volumes:
- /var/run/:/host/var/run/
- ./chaincode/go/:/opt/gopath/src/github.com/hyperledger/fabric-cluster/chaincode/go
- ./crypto-config:/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/
- ./channel-artifacts:/opt/gopath/src/github.com/hyperledger/fabric/peer/channel-artifacts
extra_hosts:
- "orderer.example.com:172.17.0.10"
- "peer0.org1.example.com:172.17.0.11"
- "peer0.org2.example.com:172.17.0.12"
使用docker-compose
启动服务(三台机器均需要)。
Copy docker-compose up -ddocker ps -a
通道操作
本节主要介绍的peer channel
命令,peer channel
命令主要是用于创建通道以及节点加入通道。
1. 创建通道
使用docker exec
命令进入客户端容器(在Org1主机上操作)。
Copy docker exec -it cli bash
使用以下命令在客户端容器中创建通道(在Org1容器上操作)。
Copy peer channel create -o orderer.example.com:7050 -c mychannel -f ./channel-artifacts/channel.tx --tls true --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/msp/tlscacerts/tlsca.example.com-cert.pem
-o
,--orderer
: orderer节点的地址。
-c
, --channelID
: 要创建的通道的ID, 必须小写, 在250个字符以内。
-f
, -file
: 由configtxgen
生成的通道文件, 用于提交给orderer。
-t
, --timeout
: 创建通道的超时时长, 默认为5s。
--cafile
: 当前orderer节点pem格式的tls证书文件, 要使用绝对路径。
orderer节点pem格式的tls证书文件路径为:crypto-config/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem。
使用ls
命令查看生成的文件(在Org1容器上操作)。
Copy channel-artifacts crypto mychannel.block
使用以下命令将通道文件 mychannel.block 拷贝到宿主机(在Org1主机上操作)。
Copy docker cp cli:/opt/gopath/src/github.com/hyperledger/fabric/peer/mychannel.block ./
然后使用以下命令拷贝到其他服务器上用于其他节点加入通道(在Org1主机上操作)。
Copy scp mychannel.block root@172.17.0.12:~/hyperledger/multinodes/
使用以下命令将通道文件拷贝到容器中(在Org2主机上操作)。
Copy docker cp mychannel.block cli:/opt/gopath/src/github.com/hyperledger/fabric/peer/
使用以下命令进入 cli
容器(在Org2主机上操作)。
Copy docker exec -it cli bash
2. 加入通道
将每个组织的每个节点都加入到通道中需要客户端来完成,一个客户端同时只能连接一个peer节点, 如果想要该客户端连接其他节点, 那么就必须修改当前客户端中相关的环境变量。我们当前在docker-compose.yaml
文件中所配置的cli
连接的是Go组织的peer0
节点。
使用以下命令让peer0
节点加入通道(在Org1和Org2容器上操作)。
Copy peer channel join -b mychannel.block
-b
, --blockpath
: block
文件路径(通过 peer channel create 命令生成的通道文件)。
输出如下,此时组织的peer0
已经加入通道。
Copy -> INFO 002 Successfully submitted proposal to join channel
3. 更新锚节点
使用以下命令来更新锚节点(在org1容器上操作)。
Copy peer channel update -o orderer.example.com:7050 -c mychannel -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
使用以下命令来更新锚节点(在org2容器上操作)
Copy peer channel update -o orderer.example.com:7050 -c mychannel -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
-o
,--orderer
:orderer
节点的地址。
-c
, --channelID
: 要创建的通道的ID, 必须小写, 在250个字符以内。
-f
, -file
: 由cryptogen
生成的锚节点文件。
安装调用智能合约
进入org1虚拟机。
首先我们使用以下命令在项目路径下创建一个文件夹名为chaincode
。
然后使用以下命令将官方示例的智能合约复制到我们刚刚创建的chaincode
文件夹中。
Copy cd ~/hyperledger/fabric-samples/chaincode
cp -r sacc ~/hyperledger/multinodes/chaincode/go/
使用以下命令进入容器。
Copy docker exec -it cli bash
使用以下命令进入链码所在目录。
Copy cd /opt/gopath/src/github.com/hyperledger/fabric-cluster/chaincode/go/sacc
使用以下命令设置go语言依赖包。
Copy go env -w GOPROXY=https://goproxy.cn,direct
go mod vendor
使用以下命令回到peer目录下。
Copy cd /opt/gopath/src/github.com/hyperledger/fabric/peer
Fabric生命周期将链码打包在易于阅读的tar文件中,方便协调跨多个组织的安装,使用以下命令打包链码。
Copy peer lifecycle chaincode package sacc.tar.gz \ --path github.com/hyperledger/fabric-cluster/chaincode/go/sacc/ \ --label sacc_1
使用以下命令退出容器。
使用以下命令将打包好的链码复制到Org2虚拟机中。
Copy docker cp cli:/opt/gopath/src/github.com/hyperledger/fabric/peer/sacc.tar.gz ./ scp sacc.tar.gz root@172.10.0.12:~/hyperledger/multinodes
在Org2的虚拟机中使用以下命令将打包好的链码复制到cli
客户端中。
Copy docker cp ~/hyperledger/multinodes/sacc.tar.gz cli:/opt/gopath/src/github.com/hyperledger/fabric/peer
使用以下命令分别在两个组织的虚拟机上安装链码(Org1和Org2的虚拟机中都要进行以下操作)。
Copy peer lifecycle chaincode install sacc.tar.gz
使用以下命令查询链码(Org1和Org2的虚拟机中都要进行以下操作)。
Copy peer lifecycle chaincode queryinstalled
使用以下命令批准链码(Org1和Org2的虚拟机中都要进行以下操作,其中链码的ID要根据上面查询的结果替换到下面的命令中)。
Copy peer lifecycle chaincode approveformyorg --channelID mychannel --name sacc --version 1.0 --init-required --package-id sacc_1:1d9838e6893e068a94f055e807b18289559af748e5196a79a640b66305a74428 --sequence 1 --tls true --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem
使用以下命令查看链码是否就绪(Org1和Org2的虚拟机中都要进行以下操作)。
Copy peer lifecycle chaincode checkcommitreadiness --channelID mychannel --name sacc --version 1.0 --init-required --sequence 1 --tls true --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem --output json
使用以下命令提交链码(在组织一或者组织二上)。
Copy peer lifecycle chaincode commit -o orderer.example.com:7050 --channelID mychannel --name sacc --version 1.0 --sequence 1 --init-required --tls true --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem --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
使用以下命令将链码初始化。
Copy peer chaincode invoke -o orderer.example.com:7050 --isInit --ordererTLSHostnameOverride orderer.example.com --tls true --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 sacc --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":["a","bb"]}'
Copy INFO 001 Chaincode invoke successful. result: status:200
使用以下命令查询数据。
Copy peer chaincode query -C mychannel -n sacc -c '{"Args":["query","a"]}'
使用以下命令调用链码,新增数据。
Copy peer chaincode invoke -o orderer.example.com:7050 --tls true --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 sacc --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":["set","a","cc"]}'
Copy INFO 001 Chaincode invoke successful. result: status:200 payload:"cc"
使用以下命令查询数据。
Copy peer chaincode query -C mychannel -n sacc -c '{"Args":["query","a"]}'