docker 部署 hyperleger fabric v2.2.0 网络环境

[toc]

环境

GoSDK安装

下载 GO SDK

wget https://golang.google.cn/dl/go1.17.3.linux-amd64.tar.gz
tar xfv go1.14.4.linux-amd64.tar.gz  -C  /usr/local

配置环境变量

在文件最后添加以下内容
vim /etc/profile
export PATH=$PATH:/usr/local/go/bin
export GOROOT=/usr/local/go
export GOPATH=$HOME/go
export PATH=$PATH:$GOPATH/bin
export GOPROXY="https://goproxy.cn,direct"
export GO111MODULE="auto"
source /etc/profile

查看go-SDK 是否安装成功

go version

安装 docker

安装Docker-CE

卸载旧版本docker
sudo apt-get remove docker docker-engine docker.io
添加HTTPS协议,允许apt从HTTPS安装软件包
sudo apt-get -y install apt-transport-https ca-certificates curl software-properties-common
安装GPG证书
curl -fsSL http://mirrors.aliyun.com/docker-ce/linux/ubuntu/gpg | sudo apt-key add -
写入软件源信息
sudo add-apt-repository "deb [arch=amd64] http://mirrors.aliyun.com/docker-ce/linux/ubuntu $(lsb_release -cs) stable"
更新并安装Docker-CE
sudo apt-get -y update && sudo apt-get -y install docker-ce
docker version
将当前用户添加到Docker用户组
创建docker用户组
sudo groupadd docker
将当前用户添加到docker用户组
sudo usermod -aG docker $USER
配置镜像加速器

针对Docker客户端版本大于 1.10.0 的用户

您可以通过修改daemon配置文件/etc/docker/daemon.json来使用加速器

sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json <<-'EOF'
{
  "registry-mirrors": ["https://x9u1rybt.mirror.aliyuncs.com"]
}
EOF
sudo systemctl daemon-reload
sudo systemctl restart docker
查看docker版本,看是否安装成功
docker version
  • 执行docker info,如果结果中含有如下内容则说明镜像配置成功
...
 Registry Mirrors:
  https://obou6wyb.mirror.aliyuncs.com/
  https://registry.docker-cn.com/
  http://hub-mirror.c.163.com/
 Live Restore Enabled: false
 ...

安装Docker-Compose

  • 查看最新版本版本

https://github.com/docker/compose/releases

sudo curl -L https://github.com/docker/compose/releases/download/1.24.0/docker-compose-`uname -s`-`uname -m` -o /usr/local/bin/docker-compose

sudo curl -L https://get.daocloud.io/docker/compose/releases/download/1.29.2/docker-compose-`uname -s`-`uname -m` > /usr/local/bin/docker-compose

-下载完后要设置权限

sudo chmod +x /usr/local/bin/docker-compose
  • 检查
docker-compose version

fabric源码

下载源码

git clone  https://gitee.com/mirrors/hyperledger-fabric.git fabric
cd fabric
  • 切换到v2.2.0版本
git checkout v2.2.0

下载二进制文件(已经准备好)

wget https://github.com/hyperledger/fabric/releases/download/v2.2.0/hyperledger-fabric-linux-amd64-2.2.0.tar.gz
  • 解压
tar -vxzf hyperledger-fabric-linux-amd64-2.2.0.tar.gz -C ./go/
  • 检查
peer version

下载 fabric-sample 源码

git clone https://gitee.com/Alikx/fabric-samples.git
  • 进入项目
cd $GOPATH/src/github.com/hyperledger/fabric-samples/test-network
  • 切换版本
git checkout v2.2.0
  • 移动配置文件,先进gopath的 bin目录下,之前解二进制文件连同配置文件都在这里.
mv config ~/go/src/github.com/hyperledger/fabric-samples

启动网络

  • 进入测试网络
cd $GOPATH/src/github.com/hyperledger/fabric-samples/test-network
  • 修改测试脚本
vim ./network.sh

大概在51行,注释掉二进制文件检查的那一项

function checkPrereqs() {
  ## Check if your have cloned the peer binaries and configuration files.
  peer version > /dev/null 2>&1
    # 注释下面的部分
  # if [[ $? -ne 0 || ! -d "../config" ]]; then
  #   errorln "Peer binary and configuration files not found.."
  #   errorln
  #   errorln "Follow the instructions in the Fabric docs to install the Fabric Binaries:"
  #   errorln "https://hyperledger-fabric.readthedocs.io/en/latest/install.html"
  #   exit 1
  # fi
  # 注释上面的部分
  # use the fabric tools container to see if the samples and binaries match your
  # docker images

执行脚本

export COMPOSE_PROJECT_NAME=fabric
export IMAGE_TAG=2.2
./network.sh up createChannel

启动日志

Creating channel 'mychannel'.
If network is not up, starting nodes with CLI timeout of '5' tries and CLI delay of '3' seconds and using database 'leveldb with crypto from 'cryptogen'
Bringing up network
LOCAL_VERSION=2.2.0
DOCKER_IMAGE_VERSION=2.2.0
/root/go/bin/cryptogen
Generating certificates using cryptogen tool
Creating Org1 Identities
+ cryptogen generate --config=./organizations/cryptogen/crypto-config-org1.yaml --output=organizations
org1.example.com # 新增peer参考配置文件
+ res=0
Creating Org2 Identities
+ cryptogen generate --config=./organizations/cryptogen/crypto-config-org2.yaml --output=organizations
org2.example.com
+ res=0
Creating Orderer Org Identities
+ cryptogen generate --config=./organizations/cryptogen/crypto-config-orderer.yaml --output=organizations
+ res=0
Generating CCP files for Org1 and Org2
/root/go/bin/configtxgen
Generating Orderer Genesis block
+ configtxgen -profile TwoOrgsOrdererGenesis -channelID system-channel -outputBlock ./system-genesis-block/genesis.block
2021-11-23 03:19:32.312 UTC [common.tools.configtxgen] main -> INFO 001 Loading configuration
2021-11-23 03:19:32.340 UTC [common.tools.configtxgen.localconfig] completeInitialization -> INFO 002 orderer type: etcdraft
2021-11-23 03:19:32.340 UTC [common.tools.configtxgen.localconfig] completeInitialization -> INFO 003 Orderer.EtcdRaft.Options unset, setting to tick_interval:"500ms" election_tick:10 heartbeat_tick:1 max_inflight_blocks:5 snapshot_interval_size:16777216
2021-11-23 03:19:32.340 UTC [common.tools.configtxgen.localconfig] Load -> INFO 004 Loaded configuration: /root/go/src/github.com/hyperledger/fabric-samples/test-network/configtx/configtx.yaml
2021-11-23 03:19:32.342 UTC [common.tools.configtxgen] doOutputBlock -> INFO 005 Generating genesis block
2021-11-23 03:19:32.343 UTC [common.tools.configtxgen] doOutputBlock -> INFO 006 Writing genesis block
+ res=0
Creating network "fabric_test" with the default driver
Creating volume "fabric_orderer.example.com" with default driver
Creating volume "fabric_peer0.org1.example.com" with default driver
Creating volume "fabric_peer0.org2.example.com" with default driver
Creating orderer.example.com    ... done
Creating peer0.org1.example.com ... done
Creating peer0.org2.example.com ... done
Creating cli                    ... done
CONTAINER ID   IMAGE                               COMMAND             CREATED         STATUS                  PORTS                                                 NAMES
f19399557a69   hyperledger/fabric-tools:latest     "/bin/bash"         2 seconds ago   Up Less than a second                                                         cli
263f14b81a51   hyperledger/fabric-peer:latest      "peer node start"   5 seconds ago   Up 2 seconds            7051/tcp, 0.0.0.0:9051->9051/tcp, :::9051->9051/tcp   peer0.org2.example.com
5513a783cb6a   hyperledger/fabric-peer:latest      "peer node start"   5 seconds ago   Up 3 seconds            0.0.0.0:7051->7051/tcp, :::7051->7051/tcp             peer0.org1.example.com
1eca52dd33b4   hyperledger/fabric-orderer:latest   "orderer"           5 seconds ago   Up 1 second             0.0.0.0:7050->7050/tcp, :::7050->7050/tcp             orderer.example.com
Generating channel create transaction 'mychannel.tx'
+ configtxgen -profile TwoOrgsChannel -outputCreateChannelTx ./channel-artifacts/mychannel.tx -channelID mychannel
2021-11-23 03:19:38.507 UTC [common.tools.configtxgen] main -> INFO 001 Loading configuration
2021-11-23 03:19:38.558 UTC [common.tools.configtxgen.localconfig] Load -> INFO 002 Loaded configuration: /root/go/src/github.com/hyperledger/fabric-samples/test-network/configtx/configtx.yaml
2021-11-23 03:19:38.558 UTC [common.tools.configtxgen] doOutputChannelCreateTx -> INFO 003 Generating new channel configtx
2021-11-23 03:19:38.570 UTC [common.tools.configtxgen] doOutputChannelCreateTx -> INFO 004 Writing new channel tx
+ res=0
Creating channel mychannel
Using organization 1
+ peer channel create -o localhost:7050 -c mychannel --ordererTLSHostnameOverride orderer.example.com -f ./channel-artifacts/mychannel.tx --outputBlock ./channel-artifacts/mychannel.block --tls --cafile /root/go/src/github.com/hyperledger/fabric-samples/test-network/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem
+ res=0
2021-11-23 03:19:41.846 UTC [channelCmd] InitCmdFactory -> INFO 001 Endorser and orderer connections initialized
2021-11-23 03:19:41.970 UTC [cli.common] readBlock -> INFO 002 Expect block, but got status: &{NOT_FOUND}
2021-11-23 03:19:41.998 UTC [channelCmd] InitCmdFactory -> INFO 003 Endorser and orderer connections initialized
2021-11-23 03:19:42.203 UTC [cli.common] readBlock -> INFO 004 Expect block, but got status: &{SERVICE_UNAVAILABLE}
2021-11-23 03:19:42.210 UTC [channelCmd] InitCmdFactory -> INFO 005 Endorser and orderer connections initialized
2021-11-23 03:19:42.415 UTC [cli.common] readBlock -> INFO 006 Expect block, but got status: &{SERVICE_UNAVAILABLE}
2021-11-23 03:19:42.425 UTC [channelCmd] InitCmdFactory -> INFO 007 Endorser and orderer connections initialized
2021-11-23 03:19:42.628 UTC [cli.common] readBlock -> INFO 008 Expect block, but got status: &{SERVICE_UNAVAILABLE}
2021-11-23 03:19:42.634 UTC [channelCmd] InitCmdFactory -> INFO 009 Endorser and orderer connections initialized
2021-11-23 03:19:42.838 UTC [cli.common] readBlock -> INFO 00a Expect block, but got status: &{SERVICE_UNAVAILABLE}
2021-11-23 03:19:42.843 UTC [channelCmd] InitCmdFactory -> INFO 00b Endorser and orderer connections initialized
2021-11-23 03:19:43.072 UTC [cli.common] readBlock -> INFO 00c Received block: 0
Channel 'mychannel' created
Joining org1 peer to the channel...
Using organization 1
+ peer channel join -b ./channel-artifacts/mychannel.block
+ res=0
2021-11-23 03:19:46.169 UTC [channelCmd] InitCmdFactory -> INFO 001 Endorser and orderer connections initialized
2021-11-23 03:19:46.283 UTC [channelCmd] executeJoin -> INFO 002 Successfully submitted proposal to join channel
Joining org2 peer to the channel...
Using organization 2
+ peer channel join -b ./channel-artifacts/mychannel.block
+ res=0
2021-11-23 03:19:49.373 UTC [channelCmd] InitCmdFactory -> INFO 001 Endorser and orderer connections initialized
2021-11-23 03:19:49.607 UTC [channelCmd] executeJoin -> INFO 002 Successfully submitted proposal to join channel
Setting anchor peer for org1...
Using organization 1
Fetching channel config for channel mychannel
Using organization 1
Fetching the most recent configuration block for the channel
+ peer channel fetch config config_block.pb -o orderer.example.com:7050 --ordererTLSHostnameOverride orderer.example.com -c mychannel --tls --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem
2021-11-23 03:19:49.852 UTC [channelCmd] InitCmdFactory -> INFO 001 Endorser and orderer connections initialized
2021-11-23 03:19:49.855 UTC [cli.common] readBlock -> INFO 002 Received block: 0
2021-11-23 03:19:49.855 UTC [channelCmd] fetch -> INFO 003 Retrieving last config block: 0
2021-11-23 03:19:49.857 UTC [cli.common] readBlock -> INFO 004 Received block: 0
Decoding config block to JSON and isolating config to Org1MSPconfig.json
+ configtxlator proto_decode + jq '.data.data[0].payload.data.config'
--input config_block.pb --type common.Block
Generating anchor peer update transaction for Org1 on channel mychannel
+ jq '.channel_group.groups.Application.groups.Org1MSP.values += {"AnchorPeers":{"mod_policy": "Admins","value":{"anchor_peers": [{"host": "peer0.org1.example.com","port": 7051}]},"version": "0"}}' Org1MSPconfig.json
+ configtxlator proto_encode --input Org1MSPconfig.json --type common.Config
+ configtxlator proto_encode --input Org1MSPmodified_config.json --type common.Config
+ configtxlator compute_update --channel_id mychannel --original original_config.pb --updated modified_config.pb
+ configtxlator proto_decode --input config_update.pb --type common.ConfigUpdate
+ ++ cat config_update.json
jq .
+ echo '{"payload":{"header":{"channel_header":{"channel_id":"mychannel", "type":2}},"data":{"config_update":{' '"channel_id":' '"mychannel",' '"isolated_data":' '{},' '"read_set":' '{' '"groups":' '{' '"Application":' '{' '"groups":' '{' '"Org1MSP":' '{' '"groups":' '{},' '"mod_policy":' '"",' '"policies":' '{' '"Admins":' '{' '"mod_policy":' '"",' '"policy":' null, '"version":' '"0"' '},' '"Endorsement":' '{' '"mod_policy":' '"",' '"policy":' null, '"version":' '"0"' '},' '"Readers":' '{' '"mod_policy":' '"",' '"policy":' null, '"version":' '"0"' '},' '"Writers":' '{' '"mod_policy":' '"",' '"policy":' null, '"version":' '"0"' '}' '},' '"values":' '{' '"MSP":' '{' '"mod_policy":' '"",' '"value":' null, '"version":' '"0"' '}' '},' '"version":' '"0"' '}' '},' '"mod_policy":' '"",' '"policies":' '{},' '"values":' '{},' '"version":' '"1"' '}' '},' '"mod_policy":' '"",' '"policies":' '{},' '"values":' '{},' '"version":' '"0"' '},' '"write_set":' '{' '"groups":' '{' '"Application":' '{' '"groups":' '{' '"Org1MSP":' '{' '"groups":' '{},' '"mod_policy":' '"Admins",' '"policies":' '{' '"Admins":' '{' '"mod_policy":' '"",' '"policy":' null, '"version":' '"0"' '},' '"Endorsement":' '{' '"mod_policy":' '"",' '"policy":' null, '"version":' '"0"' '},' '"Readers":' '{' '"mod_policy":' '"",' '"policy":' null, '"version":' '"0"' '},' '"Writers":' '{' '"mod_policy":' '"",' '"policy":' null, '"version":' '"0"' '}' '},' '"values":' '{' '"AnchorPeers":' '{' '"mod_policy":' '"Admins",' '"value":' '{' '"anchor_peers":' '[' '{' '"host":' '"peer0.org1.example.com",' '"port":' 7051 '}' ']' '},' '"version":' '"0"' '},' '"MSP":' '{' '"mod_policy":' '"",' '"value":' null, '"version":' '"0"' '}' '},' '"version":' '"1"' '}' '},' '"mod_policy":' '"",' '"policies":' '{},' '"values":' '{},' '"version":' '"1"' '}' '},' '"mod_policy":' '"",' '"policies":' '{},' '"values":' '{},' '"version":' '"0"' '}' '}}}}'
+ configtxlator proto_encode --input config_update_in_envelope.json --type common.Envelope
2021-11-23 03:19:50.269 UTC [channelCmd] InitCmdFactory -> INFO 001 Endorser and orderer connections initialized
2021-11-23 03:19:50.293 UTC [channelCmd] update -> INFO 002 Successfully submitted channel update
Anchor peer set for org 'Org1MSP' on channel 'mychannel'
Setting anchor peer for org2...
Using organization 2
Fetching channel config for channel mychannel
Using organization 2
Fetching the most recent configuration block for the channel
+ peer channel fetch config config_block.pb -o orderer.example.com:7050 --ordererTLSHostnameOverride orderer.example.com -c mychannel --tls --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem
2021-11-23 03:19:50.577 UTC [channelCmd] InitCmdFactory -> INFO 001 Endorser and orderer connections initialized
2021-11-23 03:19:50.581 UTC [cli.common] readBlock -> INFO 002 Received block: 1
2021-11-23 03:19:50.581 UTC [channelCmd] fetch -> INFO 003 Retrieving last config block: 1
2021-11-23 03:19:50.583 UTC [cli.common] readBlock -> INFO 004 Received block: 1
Decoding config block to JSON and isolating config to Org2MSPconfig.json
+ configtxlator proto_decode --input + jq '.data.data[0].payload.data.config'
config_block.pb --type common.Block
Generating anchor peer update transaction for Org2 on channel mychannel
+ jq '.channel_group.groups.Application.groups.Org2MSP.values += {"AnchorPeers":{"mod_policy": "Admins","value":{"anchor_peers": [{"host": "peer0.org2.example.com","port": 9051}]},"version": "0"}}' Org2MSPconfig.json
+ configtxlator proto_encode --input Org2MSPconfig.json --type common.Config
+ configtxlator proto_encode --input Org2MSPmodified_config.json --type common.Config
+ configtxlator compute_update --channel_id mychannel --original original_config.pb --updated modified_config.pb
+ configtxlator proto_decode --input config_update.pb --type common.ConfigUpdate
+ ++ cat config_update.json
jq .
+ echo '{"payload":{"header":{"channel_header":{"channel_id":"mychannel", "type":2}},"data":{"config_update":{' '"channel_id":' '"mychannel",' '"isolated_data":' '{},' '"read_set":' '{' '"groups":' '{' '"Application":' '{' '"groups":' '{' '"Org2MSP":' '{' '"groups":' '{},' '"mod_policy":' '"",' '"policies":' '{' '"Admins":' '{' '"mod_policy":' '"",' '"policy":' null, '"version":' '"0"' '},' '"Endorsement":' '{' '"mod_policy":' '"",' '"policy":' null, '"version":' '"0"' '},' '"Readers":' '{' '"mod_policy":' '"",' '"policy":' null, '"version":' '"0"' '},' '"Writers":' '{' '"mod_policy":' '"",' '"policy":' null, '"version":' '"0"' '}' '},' '"values":' '{' '"MSP":' '{' '"mod_policy":' '"",' '"value":' null, '"version":' '"0"' '}' '},' '"version":' '"0"' '}' '},' '"mod_policy":' '"",' '"policies":' '{},' '"values":' '{},' '"version":' '"1"' '}' '},' '"mod_policy":' '"",' '"policies":' '{},' '"values":' '{},' '"version":' '"0"' '},' '"write_set":' '{' '"groups":' '{' '"Application":' '{' '"groups":' '{' '"Org2MSP":' '{' '"groups":' '{},' '"mod_policy":' '"Admins",' '"policies":' '{' '"Admins":' '{' '"mod_policy":' '"",' '"policy":' null, '"version":' '"0"' '},' '"Endorsement":' '{' '"mod_policy":' '"",' '"policy":' null, '"version":' '"0"' '},' '"Readers":' '{' '"mod_policy":' '"",' '"policy":' null, '"version":' '"0"' '},' '"Writers":' '{' '"mod_policy":' '"",' '"policy":' null, '"version":' '"0"' '}' '},' '"values":' '{' '"AnchorPeers":' '{' '"mod_policy":' '"Admins",' '"value":' '{' '"anchor_peers":' '[' '{' '"host":' '"peer0.org2.example.com",' '"port":' 9051 '}' ']' '},' '"version":' '"0"' '},' '"MSP":' '{' '"mod_policy":' '"",' '"value":' null, '"version":' '"0"' '}' '},' '"version":' '"1"' '}' '},' '"mod_policy":' '"",' '"policies":' '{},' '"values":' '{},' '"version":' '"1"' '}' '},' '"mod_policy":' '"",' '"policies":' '{},' '"values":' '{},' '"version":' '"0"' '}' '}}}}'
+ configtxlator proto_encode --input config_update_in_envelope.json --type common.Envelope
2021-11-23 03:19:50.927 UTC [channelCmd] InitCmdFactory -> INFO 001 Endorser and orderer connections initialized
2021-11-23 03:19:50.950 UTC [channelCmd] update -> INFO 002 Successfully submitted channel update
Anchor peer set for org 'Org2MSP' on channel 'mychannel'
Channel 'mychannel' joined
  • 检查
docker ps --format "table {{.ID}}\t{{.Names}}"

输出一下内容,包含三个节点:

CONTAINER ID   NAMES
e3c7b448125d   cli
dfdc10df3d98   peer0.org1.example.com
5c5a432150fe   orderer.example.com
36ad49aa080c   peer0.org2.example.com

清理网络

  • 如果使用了日志监控
docker stop logspout && docker rm logspout && ./network.sh down
  • 没有使用日监控
./network.sh down

日志监控

此步骤不是必需的,但对链码进行故障诊断非常有用。要监控智能合同的日志,管理员可以使用logspout工具查看一组Docker容器的聚合输出。该工具将来自不同Docker容器的输出流收集到一个地方,以便于从单个窗口查看正在发生的事情。这可以帮助管理员在安装智能合同时调试问题,帮助开发人员在调用智能合同时调试问题。由于一些容器的创建纯粹是为了启动智能合同,并且只存在很短的时间,因此从您的网络收集所有日志是有帮助的。

A script to install and configure Logspout, monitordocker.sh, is already included in the commercial-paper sample in the Fabric samples. We will use the same script in this tutorial as well. The Logspout tool will continuously stream logs to your terminal, so you will need to use a new terminal window. Open a new terminal and navigate to the test-network directory.

cd fabric-samples/test-network

You can run the monitordocker.sh script from any directory. For ease of use, we will copy the monitordocker.sh script from the commercial-paper sample to your working directory

cp ../commercial-paper/organization/digibank/configuration/cli/monitordocker.sh .
# if you're not sure where it is
find . -name monitordocker.sh

然后,您可以通过运行以下命令启动Logspout:

./monitordocker.sh fabric_test

您应该会看到类似于以下内容的输出:

Starting monitoring on all containers on the network docker_test
f96a6fae3c8cadcb8f3b5ac0f4fb808b45d1d30cc26498451974bd6a1b16a4b7

您一开始不会看到任何日志,但当我们部署链码时,这种情况会发生变化。使这个终端窗口宽,字体小可能会有帮助。

如果找不到网络,就使用个下面命令查看下网络,实际上网络名字就是上面修改过的名字.

docker network ls

清理

使用完链码后,您也可以使用以下命令删除Logspout工具。

docker stop logspout && docker rm logspout && ./network.sh down

然后,您可以通过从测试网络目录发出以下命令来关闭test-network

./network.sh down

安装链码

打包链码

  • 进去go语言链码包
cd fabric-samples/chaincode/fabcar/go
  • 下载依赖
GO111MODULE=on 
go mod vendor
  • 回到工作目录
cd ../../../test-network
  • 设置管理员1 的环境的变量
export FABRIC_CFG_PATH=$PWD/../config/
export CORE_PEER_TLS_ENABLED=true
export CORE_PEER_LOCALMSPID="Org1MSP"
export CORE_PEER_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt
export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp
export CORE_PEER_ADDRESS=localhost:7051
  • 管理员1和管理员2 (一个打包另一个直接拿来用就好了)打包链码
peer lifecycle chaincode package fabcar.tar.gz --path ../chaincode/fabcar/go/  --lang golang --label fabcar_1

执行完该命令会在当前目录下生成 链码包文件 fabcar.tar.gz .

安装链码

在Org1 的peer 上安装链码

peer lifecycle chaincode install fabcar.tar.gz
2021-11-23 03:32:34.978 UTC [cli.lifecycle.chaincode] submitInstallProposal -> INFO 001 Installed remotely: response:<status:200 payload:"\nIfabcar_1:762e0fe3dbeee0f7b08fb6200adeb4a3a20f649a00f168c0b3c2257e53b6e506\022\010fabcar_1" >
2021-11-23 03:32:34.978 UTC [cli.lifecycle.chaincode] submitInstallProposal -> INFO 002 Chaincode code package identifier: fabcar_1:762e0fe3dbeee0f7b08fb6200adeb4a3a20f649a00f168c0b3c2257e53b6e506
  • 查询已安装的链码
peer lifecycle chaincode queryinstalled
Installed chaincodes on peer:
Package ID: fabcar_1:762e0fe3dbeee0f7b08fb6200adeb4a3a20f649a00f168c0b3c2257e53b6e506, Label: fabcar_1

在Org2的 peer 上安装链码

设置以下环境变量作为Org2管理员操作,并瞄准Org2对等机peer0.org2.example.com

export CORE_PEER_TLS_ENABLED=true
export CORE_PEER_LOCALMSPID="Org2MSP"
export CORE_PEER_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt
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 fabcar.tar.gz
2021-11-23 03:33:56.305 UTC [cli.lifecycle.chaincode] submitInstallProposal -> INFO 001 Installed remotely: response:<status:200 payload:"\nIfabcar_1:762e0fe3dbeee0f7b08fb6200adeb4a3a20f649a00f168c0b3c2257e53b6e506\022\010fabcar_1" >
2021-11-23 03:33:56.305 UTC [cli.lifecycle.chaincode] submitInstallProposal -> INFO 002 Chaincode code package identifier: fabcar_1:762e0fe3dbeee0f7b08fb6200adeb4a3a20f649a00f168c0b3c2257e53b6e506
  • 查询已安装的链码
peer lifecycle chaincode queryinstalled
Installed chaincodes on peer:
Package ID: fabcar_1:762e0fe3dbeee0f7b08fb6200adeb4a3a20f649a00f168c0b3c2257e53b6e506, Label: fabcar_1

批准链码

  • 设置环境变量
export CC_PACKAGE_ID=fabcar_1:762e0fe3dbeee0f7b08fb6200adeb4a3a20f649a00f168c0b3c2257e53b6e506
  • 批准
peer lifecycle chaincode approveformyorg \
-o localhost:7050 \
--ordererTLSHostnameOverride orderer.example.com \
--channelID mychannel \
--name fabcar \
--version 1.0 \
--package-id $CC_PACKAGE_ID \
--sequence 1 \
--tls \
--cafile ${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem
  • 日志
2021-11-23 03:37:54.483 UTC [chaincodeCmd] ClientWait -> INFO 001 txid [377e45a0d4663c9afe9857656d31208bd70e9980373cc1a79256de0af7850311] committed with status (VALID) at
  • 设置环境变量为组织以的管理员
export CORE_PEER_LOCALMSPID="Org1MSP"
export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp
export CORE_PEER_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt
export CORE_PEER_ADDRESS=localhost:7051
  • 批准
peer lifecycle chaincode approveformyorg -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --channelID mychannel --name fabcar --version 1.0 --package-id $CC_PACKAGE_ID --sequence 1 --tls --cafile ${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem
  • 日志
2021-11-23 03:38:51.638 UTC [chaincodeCmd] ClientWait -> INFO 001 txid [6eddec6e2aaced7aac59d7f8f5b3718104f62be4560d49466f9e120390c85292] committed with status (VALID) at

提交链码

  • 检查批准情况
peer lifecycle chaincode checkcommitreadiness  \
--channelID mychannel  \
--name fabcar  \
--version 1.0  \
--sequence 1  \
--tls  \
--cafile ${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem  \
--output json
  • 日志
{
    "approvals": {
        "Org1MSP": true,
        "Org2MSP": true
    }
}
  • 提交
peer lifecycle chaincode commit  \
-o localhost:7050  \
--ordererTLSHostnameOverride orderer.example.com  \
--channelID mychannel  \
--name fabcar  \
--version 1.0  \
--sequence 1  \
--tls  \
--cafile ${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem  \
--peerAddresses localhost:7051  \
--tlsRootCertFiles ${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt  \
--peerAddresses localhost:9051  \
--tlsRootCertFiles ${PWD}/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt
  • 日志
2021-11-23 03:41:47.755 UTC [chaincodeCmd] ClientWait -> INFO 001 txid [1f08b845f0462c415d70799360cc9e72c41e9e768a26a5eef240ed14cd061d0e] committed with status (VALID) at localhost:9051
2021-11-23 03:41:47.806 UTC [chaincodeCmd] ClientWait -> INFO 002 txid [1f08b845f0462c415d70799360cc9e72c41e9e768a26a5eef240ed14cd061d0e] committed with status (VALID) at localhost:7051
  • 查询已提交
peer lifecycle chaincode querycommitted  \
--channelID mychannel  \
--name fabcar  \
--cafile ${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem
  • 日志
Committed chaincode definition for chaincode 'fabcar' on channel 'mychannel':
Version: 1.0, Sequence: 1, Endorsement Plugin: escc, Validation Plugin: vscc, Approvals: [Org1MSP: true, Org2MSP: true]

调用链码

peer chaincode invoke -o localhost:7050 \
--ordererTLSHostnameOverride orderer.example.com \
--tls \
--cafile \
${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem \
-C mychannel \
-n fabcar \
--peerAddresses localhost:7051 \
--tlsRootCertFiles ${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt \
--peerAddresses localhost:9051 \
--tlsRootCertFiles ${PWD}/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt \
-c '{"function":"initLedger","Args":[]}'
  • 日志
2021-11-23 03:43:29.125 UTC [chaincodeCmd] chaincodeInvokeOrQuery -> INFO 001 Chaincode invoke successful. result: status:200
  • 查询
peer chaincode query  \
-C mychannel  \
-n fabcar  \
-c '{"Args":["queryAllCars"]}'
  • 日志
[{"Key":"CAR0","Record":{"make":"Toyota","model":"Prius","colour":"blue","owner":"Tomoko"}},{"Key":"CAR1","Record":{"make":"Ford","model":"Mustang","colour":"red","owner":"Brad"}},{"Key":"CAR2","Record":{"make":"Hyundai","model":"Tucson","colour":"green","owner":"Jin Soo"}},{"Key":"CAR3","Record":{"make":"Volkswagen","model":"Passat","colour":"yellow","owner":"Max"}},{"Key":"CAR4","Record":{"make":"Tesla","model":"S","colour":"black","owner":"Adriana"}},{"Key":"CAR5","Record":{"make":"Peugeot","model":"205","colour":"purple","owner":"Michel"}},{"Key":"CAR6","Record":{"make":"Chery","model":"S22L","colour":"white","owner":"Aarav"}},{"Key":"CAR7","Record":{"make":"Fiat","model":"Punto","colour":"violet","owner":"Pari"}},{"Key":"CAR8","Record":{"make":"Tata","model":"Nano","colour":"indigo","owner":"Valeria"}},{"Key":"CAR9","Record":{"make":"Holden","model":"Barina","colour":"brown","owner":"Shotaro"}}]

升级链码

创建通道

生成通道交易文件

configtxgen \
-profile TwoOrgsChannel \
-outputCreateChannelTx ./channel-artifacts/channel1.tx \
-channelID channel1 \
-configPath ./configtx/
  • 日志
2021-11-23 03:48:12.027 UTC [common.tools.configtxgen] main -> INFO 001 Loading configuration
2021-11-23 03:48:12.049 UTC [common.tools.configtxgen.localconfig] Load -> INFO 002 Loaded configuration: /root/go/src/github.com/hyperledger/fabric-samples/test-network/configtx/configtx.yaml
2021-11-23 03:48:12.049 UTC [common.tools.configtxgen] doOutputChannelCreateTx -> INFO 003 Generating new channel configtx
2021-11-23 03:48:12.051 UTC [common.tools.configtxgen] doOutputChannelCreateTx -> INFO 004 Writing new channel tx

创建通道区块

peer channel create \
-o localhost:7050  \
--ordererTLSHostnameOverride orderer.example.com \
-c channel1 \
-f ./channel-artifacts/channel1.tx \
--outputBlock ./channel-artifacts/channel1.block \
--tls \
--cafile ${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem
  • 日志
2021-11-23 03:48:52.616 UTC [channelCmd] InitCmdFactory -> INFO 001 Endorser and orderer connections initialized
2021-11-23 03:48:52.727 UTC [cli.common] readBlock -> INFO 002 Expect block, but got status: &{SERVICE_UNAVAILABLE}
2021-11-23 03:48:52.734 UTC [channelCmd] InitCmdFactory -> INFO 003 Endorser and orderer connections initialized
2021-11-23 03:48:52.942 UTC [cli.common] readBlock -> INFO 004 Expect block, but got status: &{SERVICE_UNAVAILABLE}
2021-11-23 03:48:52.948 UTC [channelCmd] InitCmdFactory -> INFO 005 Endorser and orderer connections initialized
2021-11-23 03:48:53.159 UTC [cli.common] readBlock -> INFO 006 Expect block, but got status: &{SERVICE_UNAVAILABLE}
2021-11-23 03:48:53.163 UTC [channelCmd] InitCmdFactory -> INFO 007 Endorser and orderer connections initialized
2021-11-23 03:48:53.367 UTC [cli.common] readBlock -> INFO 008 Expect block, but got status: &{SERVICE_UNAVAILABLE}
2021-11-23 03:48:53.372 UTC [channelCmd] InitCmdFactory -> INFO 009 Endorser and orderer connections initialized
2021-11-23 03:48:53.577 UTC [cli.common] readBlock -> INFO 00a Expect block, but got status: &{SERVICE_UNAVAILABLE}
2021-11-23 03:48:53.583 UTC [channelCmd] InitCmdFactory -> INFO 00b Endorser and orderer connections initialized
2021-11-23 03:48:53.789 UTC [cli.common] readBlock -> INFO 00c Received block: 0

加入通道

组织1 的peer加入通道

由于我们已经以Org1管理员的身份使用peer CLI,因此让我们将Org1的Peer加入到通道中。由于Org1提交了通道创建交易,因此我们的文件系统上已经有了通道创世块。使用以下命令将Org1的Peer加入通道。

peer channel join -b ./channel-artifacts/channel1.block

环境变量CORE_PEER_ADDRESS已设置为以peer0.org1.example.com为目标。命令执行成功后将生成peer0.org1.example.com加入通道的响应:

2021-11-23 03:50:44.103 UTC [channelCmd] InitCmdFactory -> INFO 001 Endorser and orderer connections initialized
2021-11-23 03:50:44.234 UTC [channelCmd] executeJoin -> INFO 002 Successfully submitted proposal to join channel
  • 查询已加入的通道
peer channel list
  • 日志
2021-11-23 03:51:13.257 UTC [channelCmd] InitCmdFactory -> INFO 001 Endorser and orderer connections initialized
Channels peers has joined:
channel1
mychannel

组织2 的peer加入通道

  • 设置环境变量
export CORE_PEER_TLS_ENABLED=true
export CORE_PEER_LOCALMSPID="Org2MSP"
export CORE_PEER_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt
export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp
export CORE_PEER_ADDRESS=localhost:9051
  • 列出当前peer 加入的通道
peer channel list
root@fabric:~/go/src/github.com/hyperledger/fabric-samples/test-network# peer channel list
2021-11-23 05:06:44.010 UTC [channelCmd] InitCmdFactory -> INFO 001 Endorser and orderer connections initialized
Channels peers has joined:
mychannel
  • 从排序服务中获取通道区块数据
peer channel fetch 0 \
./channel-artifacts/channel_org2.block \
-o localhost:7050 \
--ordererTLSHostnameOverride orderer.example.com \
-c channel1 \
--tls \
--cafile ${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem
2021-11-23 05:06:29.092 UTC [channelCmd] InitCmdFactory -> INFO 001 Endorser and orderer connections initialized
2021-11-23 05:06:29.097 UTC [cli.common] readBlock -> INFO 002 Received block: 0
  • 加入通道
peer channel join -b ./channel-artifacts/channel_org2.block
2021-11-23 05:11:20.912 UTC [channelCmd] InitCmdFactory -> INFO 001 Endorser and orderer connections initialized
2021-11-23 05:11:21.071 UTC [channelCmd] executeJoin -> INFO 002 Successfully submitted proposal to join channel
  • 查询结果
peer channel list
root@fabric:~/go/src/github.com/hyperledger/fabric-samples/test-network# peer channel list
2021-11-23 05:12:03.257 UTC [channelCmd] InitCmdFactory -> INFO 001 Endorser and orderer connections initialized
Channels peers has joined:
channel1
mychannel

向组织中新增peer

  • 工作目录 :~/go/src/github.com/hyperledger/fabric-samples/test-network
  • 组织:org1

查看当前组织中pee的个数

tree -L 5
│   └── peerOrganizations
│       ├── org1.example.com
│       │   ├── ca
│       │   │   ├── ca.org1.example.com-cert.pem
│       │   │   └── priv_sk
│       │   ├── connection-org1.json
│       │   ├── connection-org1.yaml
│       │   ├── msp
│       │   │   ├── admincerts
│       │   │   ├── cacerts
│       │   │   ├── config.yaml
│       │   │   └── tlscacerts
│       │   ├── peers
│       │   │   └── peer0.org1.example.com
│       │   ├── tlsca
│       │   │   ├── priv_sk
│       │   │   └── tlsca.org1.example.com-cert.pem
│       │   └── users
│       │       ├── Admin@org1.example.com
│       │       └── User1@org1.example.com

新增peer 证书文件

编辑证书配置文件

启动网络的步骤中,查看输出日志

Creating Org1 Identities
+ cryptogen generate --config=./organizations/cryptogen/crypto-config-org1.yaml --output=organizations

修爱配置文件 ./organizations/cryptogen/crypto-config-org1.yaml.

vim ./organizations/cryptogen/crypto-config-org1.yaml
# Copyright IBM Corp. All Rights Reserved.
#
# SPDX-License-Identifier: Apache-2.0
#


# ---------------------------------------------------------------------------
# "PeerOrgs" - Definition of organizations managing peer nodes
# ---------------------------------------------------------------------------
PeerOrgs:
  # ---------------------------------------------------------------------------
  # Org1
  # ---------------------------------------------------------------------------
  - Name: Org1
    Domain: org1.example.com
    EnableNodeOUs: true
    # ---------------------------------------------------------------------------
    # "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.
    # ---------------------------------------------------------------------------
    #   - 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 # 此处由1 改为 2 
      SANS:
        - localhost
      # Start: 5
      # Hostname: {{.Prefix}}{{.Index}} # default
    # ---------------------------------------------------------------------------
    # "Users"
    # ---------------------------------------------------------------------------
    # Count: The number of user accounts _in addition_ to Admin
    # ---------------------------------------------------------------------------
    Users:
      Count: 1
  • 执行网络拓展命令
cryptogen extend --config=./organizations/cryptogen/crypto-config-org1.yaml --input=organizations
  • 再次查看目录结构
ls organizations/peerOrganizations/org1.example.com/peers
peer0.org1.example.com  peer1.org1.example.com

启动新peer节点

查看当前节点

docker ps --format "table {{.ID}} \t {{.Names}}"
root@fabric:~/go/src/github.com/hyperledger/fabric-samples/test-network# docker ps --format "table {{.ID}} \t {{.Names}}"
CONTAINER ID     NAMES
a6b9c523c562     dev-peer0.org2.example.com-fabcar_1-762e0fe3dbeee0f7b08fb6200adeb4a3a20f649a00f168c0b3c2257e53b6e506
a20f2648b557     dev-peer0.org1.example.com-fabcar_1-762e0fe3dbeee0f7b08fb6200adeb4a3a20f649a00f168c0b3c2257e53b6e506
f69bca3357cc     logspout
f19399557a69     cli
263f14b81a51     peer0.org2.example.com
5513a783cb6a     peer0.org1.example.com
1eca52dd33b4     orderer.example.com

新增 docker-compose 配置

#
# Copyright IBM Corp All Rights Reserved
#
# SPDX-License-Identifier: Apache-2.0
#
version: '2'

networks:
  fabric_test:
      driver: bridge
      external: true

services:
  peer1.org1.example.com:
    container_name: peer1.org1.example.com
    tty: true
    image: hyperledger/fabric-peer:$IMAGE_TAG
    environment:
      - CORE_VM_ENDPOINT=unix:///host/var/run/docker.sock
      - CORE_PEER_ID=peer1.org1.example.com
      - FABRIC_LOGGING_SPEC=INFO
      - CORE_PEER_TLS_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_LOGGING_LEVEL=INFO
      - CORE_PEER_LOCALMSPID=Org1MSP
      - CORE_PEER_ADDRESS=peer1.org1.example.com:7051
      - CORE_VM_DOCKER_HOSTCONFIG_NETWORKMODE=${COMPOSE_PROJECT_NAME}_test
    working_dir: /opt/gopath/src/github.com/hyperledger/fabric
    command: peer node start
    ports:
      - 8051:7051
      - 8053:7053
    volumes:
      - /var/run/:/host/var/run/
      - ./organizations/peerOrganizations/org1.example.com/peers/peer1.org1.example.com/msp:/etc/hyperledger/fabric/msp
      - ./organizations/peerOrganizations/org1.example.com/peers/peer1.org1.example.com/tls:/etc/hyperledger/fabric/tls
    networks:
      - fabric_test

启动节点

docker-compose -f docker-compose.yaml up -d peer1.org1.example.com
  • 查看节点信息
docker ps --format "table {{.ID}}\t{{.Names}}" --filter name=org1
3cce207d4570   peer1.org1.example.com
5513a783cb6a   peer0.org1.example.com

将新节点加入通道

  • 配置环境变量
export CORE_PEER_TLS_ENABLED=true
export CORE_PEER_LOCALMSPID="Org1MSP"
export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp
export CORE_PEER_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer1.org1.example.com/tls/ca.crt
export CORE_PEER_ADDRESS=localhost:8051
peer channel fetch 0 \
./channel-artifacts/channel_org1_peer1.block \
-o localhost:7050 \
--ordererTLSHostnameOverride orderer.example.com \
-c mychannel \
--tls \
--cafile ${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem
  • 加入通道 mychannel
peer channel join -b ./channel-artifacts/channel_org1_peer1.block
2021-11-23 06:10:44.200 UTC [channelCmd] InitCmdFactory -> INFO 001 Endorser and orderer connections initialized
2021-11-23 06:10:44.324 UTC [channelCmd] executeJoin -> INFO 002 Successfully submitted proposal to join channel
  • 查看
peer channel  list
2021-11-23 06:11:00.887 UTC [channelCmd] InitCmdFactory -> INFO 001 Endorser and orderer connections initialized
Channels peers has joined:
mychannel

安装链码

  • 安装链码
peer lifecycle chaincode install fabcar.tar.gz
  • 批准链码
peer lifecycle chaincode approveformyorg \
-o localhost:7050 \
--ordererTLSHostnameOverride orderer.example.com \
--channelID mychannel \
--name fabcar \
--version 1.0 \
--package-id $CC_PACKAGE_ID \
--sequence 2 \
--tls \
--cafile ${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem
  • 查询
peer lifecycle chaincode checkcommitreadiness  \
--channelID mychannel  \
--name fabcar  \
--version 1.0  \
--sequence 2  \
--tls  \
--cafile ${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem  \
--output json
  • 调用链码
peer chaincode query  \
-C mychannel  \
-n fabcar  \
-c '{"Args":["queryAllCars"]}'

参考日志

root@fabric:~/go/src/github.com/hyperledger/fabric-samples/test-network# peer lifecycle chaincode approveformyorg \
> -o localhost:7050 \
> --ordererTLSHostnameOverride orderer.example.com \
> --channelID mychannel \
> --name fabcar \
> --version 1.0 \
> --package-id $CC_PACKAGE_ID \
> --sequence 2 \
> --tls \
> --cafile ${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem
2021-11-23 07:26:01.492 UTC [chaincodeCmd] ClientWait -> INFO 001 txid [b1d45658ff7f90866adda7ff81199386cd8dff7cd05819c48228c63eecf6b56a] committed with status (VALID) at
root@fabric:~/go/src/github.com/hyperledger/fabric-samples/test-network# export CORE_PEER_TLS_ENABLED=true
root@fabric:~/go/src/github.com/hyperledger/fabric-samples/test-network# export CORE_PEER_LOCALMSPID="Org2MSP"
root@fabric:~/go/src/github.com/hyperledger/fabric-samples/test-network# export CORE_PEER_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt
root@fabric:~/go/src/github.com/hyperledger/fabric-samples/test-network# export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp
root@fabric:~/go/src/github.com/hyperledger/fabric-samples/test-network# export CORE_PEER_ADDRESS=localhost:9051
root@fabric:~/go/src/github.com/hyperledger/fabric-samples/test-network# peer lifecycle chaincode approveformyorg \
> -o localhost:7050 \
> --ordererTLSHostnameOverride orderer.example.com \
> --channelID mychannel \
> --name fabcar \
> --version 1.0 \
> --package-id $CC_PACKAGE_ID \
> --sequence 2 \
> --tls \
> --cafile ${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem
2021-11-23 07:26:33.901 UTC [chaincodeCmd] ClientWait -> INFO 001 txid [078f3ee511dca0c29f0af021fdf154b3ca05a0ac62f2c7d05c8c77c804cb0f8a] committed with status (VALID) at
root@fabric:~/go/src/github.com/hyperledger/fabric-samples/test-network# peer lifecycle chaincode checkcommitreadiness  \
> --channelID mychannel  \
> --name fabcar  \
> --version 1.0  \
> --sequence 2  \
> --tls  \
> --cafile ${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem  \
> --output json
{
    "approvals": {
        "Org1MSP": true,
        "Org2MSP": true
    }
}
root@fabric:~/go/src/github.com/hyperledger/fabric-samples/test-network# export CORE_PEER_TLS_ENABLED=true
root@fabric:~/go/src/github.com/hyperledger/fabric-samples/test-network# export CORE_PEER_LOCALMSPID="Org1MSP"
root@fabric:~/go/src/github.com/hyperledger/fabric-samples/test-network# export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp
root@fabric:~/go/src/github.com/hyperledger/fabric-samples/test-network# export CORE_PEER_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer1.org1.example.com/tls/ca.crt
root@fabric:~/go/src/github.com/hyperledger/fabric-samples/test-network# export CORE_PEER_ADDRESS=localhost:8051
root@fabric:~/go/src/github.com/hyperledger/fabric-samples/test-network# peer chaincode query  \
> -C mychannel  \
> -n fabcar  \
> -c '{"Args":["queryAllCars"]}'
[{"Key":"CAR0","Record":{"make":"Toyota","model":"Prius","colour":"blue","owner":"Tomoko"}},{"Key":"CAR1","Record":{"make":"Ford","model":"Mustang","colour":"red","owner":"Brad"}},{"Key":"CAR2","Record":{"make":"Hyundai","model":"Tucson","colour":"green","owner":"Jin Soo"}},{"Key":"CAR3","Record":{"make":"Volkswagen","model":"Passat","colour":"yellow","owner":"Max"}},{"Key":"CAR4","Record":{"make":"Tesla","model":"S","colour":"black","owner":"Adriana"}},{"Key":"CAR5","Record":{"make":"Peugeot","model":"205","colour":"purple","owner":"Michel"}},{"Key":"CAR6","Record":{"make":"Chery","model":"S22L","colour":"white","owner":"Aarav"}},{"Key":"CAR7","Record":{"make":"Fiat","model":"Punto","colour":"violet","owner":"Pari"}},{"Key":"CAR8","Record":{"make":"Tata","model":"Nano","colour":"indigo","owner":"Valeria"}},{"Key":"CAR9","Record":{"make":"Holden","model":"Barina","colour":"brown","owner":"Shotaro"}}]

向网络中新增组织

为 Org3生成证书文件

在另一个终端中,addOrg3test-network.

cd addOrg3

首先,我们将为 Org3 对等方以及应用程序和管理员用户创建证书和密钥。因为我们正在更新一个示例通道,所以我们将使用 cryptogen 工具而不是使用证书颁发机构。以下命令使用 cryptogen 读取org3-crypto.yaml文件并在新org3.example.com文件夹中生成 Org3 加密材料:

cryptogen generate --config=org3-crypto.yaml --output="../organizations"

您可以在目录中找到生成的 Org3 加密材料以及 Org1 和 Org2 的证书和密钥:test-network/organizations/peerOrganizations.

一旦我们创建了 Org3 加密材料,我们就可以使用 configtxgen 工具打印出 Org3 组织定义。

我们将通过告诉工具在当前目录中查找configtx.yaml 它需要摄取的文件来开始命令。

export FABRIC_CFG_PATH=$PWD
configtxgen -printOrg Org3MSP > ../organizations/peerOrganizations/org3.example.com/org3.json

上面的命令创建了一个 JSON 文件 org3.json 并将其写入下面文件夹。

test-network/organizations/peerOrganizations/org3.example.com/

组织定义包含 Org3 的策略定义、Org3 的 NodeOU 定义以及两个以 base64 格式编码的重要证书:

  • CA 根证书,用于建立组织间的信任根
  • 一个 TLS 根证书,由 gossip 协议用于标识 Org3 以进行块传播和服务发现

我们将通过将此组织定义附加到通道配置来将 Org3 添加到通道中。

调出 Org3 组件

就是 启动 组织 3 的 peer 节点

创建 Org3 证书材料后,我们现在可以启动 Org3 对等体。从addOrg3目录中,发出以下命令:

docker-compose -f docker/docker-compose-org3.yaml up -d

如果命令成功,您将看到 Org3 peer 的创建:

Creating peer0.org3.example.com ... done

此 Docker Compose 文件已配置为跨我们的初始网络桥接,以便 Org3 对等节点与测试网络的现有对等节点和排序节点进行解析。

获取配置

让我们去获取频道的最新配置块 – channel1

我们必须拉取最新版本的配置的原因是因为通道配置元素是版本化的。

出于多种原因,版本控制很重要。它可以防止重复或重放配置更改(例如,使用旧 CRL 恢复到通道配置将代表安全风险)。它还有助于确保并发性(如果您想从频道中删除组织,例如,在添加新组织后,版本控制将有助于防止您删除两个组织,而不仅仅是要删除的组织)。

导航回test-network目录。因为 Org3 还不是频道的成员,我们需要以另一个组织的管理员身份操作来获取频道配置。因为 Org1 是频道的成员,所以 Org1 管理员有权从排序服务中获取频道配置。发出以下命令以作为 Org1 管理员进行操作。

# you can issue all of these commands at once
export FABRIC_CFG_PATH=${PWD}/../config/
export CORE_PEER_TLS_ENABLED=true
export CORE_PEER_LOCALMSPID="Org1MSP"
export CORE_PEER_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt
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 channel-artifacts/config_block.pb \
-o localhost:7050 \
--ordererTLSHostnameOverride orderer.example.com \
-c mychannel \
--tls \
--cafile ${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem

此命令将二进制 protobuf 通道配置块保存到 config_block.pb. 请注意,名称和文件扩展名的选择是任意的。但是,建议遵循标识所表示的对象类型及其编码(protobuf 或 JSON)的约定。

peer channel fetch发出命令后,日志中会显示以下输出:

2021-11-11 15:32:31.586 CST [channelCmd] InitCmdFactory -> INFO 001 Endorser and orderer connections initialized
2021-11-11 15:32:31.592 CST [cli.common] readBlock -> INFO 002 Received block: 2
2021-11-11 15:32:31.592 CST [channelCmd] fetch -> INFO 003 Retrieving last config block: 2
2021-11-11 15:32:31.595 CST [cli.common] readBlock -> INFO 004 Received block: 2

这告诉我们最近的配置块channel1实际上是块 2,而不是创世块。

默认情况下,该 命令返回目标通道的最新配置块,在这种情况下是第三个块。

这是因为测试网络脚本为我们的两个组织定义了锚点,并且在两个单独的通道更新事务中。因此,我们有以下配置序列:

  • block 0: genesis block
  • block 1: Org1 anchor peer update
  • block 2: Org2 anchor peer update

通道配置文件夹下新增块信息文件

├── channel-artifacts
│   ├── channel1.block
│   ├── channel1.tx
│   └── config_block.pb # 新增

将配置转换为 JSON 并对其进行修剪

通道配置块存储在channel-artifacts文件夹中,以使更新过程与其他工件分开。进入 channel-artifacts 文件夹以完成以下步骤:

cd channel-artifacts
  • 使用该configtxlator工具将这个通道配置块解码为 JSON 格式(可以被人类读取和修改)
configtxlator proto_decode \
--input config_block.pb \
--type common.Block \
--output config_block.json
  • 去除所有与我们想要进行的更改无关的标题、元数据、创建者签名等

带有数组的情况下,加引号,这个命令给我们留下了一个精简的 JSON 对象 config.json 它将作为我们配置更新的基线。

jq '.data.data[0].payload.data.config' config_block.json > config.json

添加 Org3 加密材

jq 语法参考

jq 官方文档

选项解释备注
-sread (slurp) all inputs into an array; apply filter to it使用-s 选项,jq 会将所有的 JSON 输入放入一个数组中并在这个数组上使用 filter。"-s"选项不但影响到 filter 的写法。如果在 filter 中需要对数据进行选择和映射,其还会影响最终结果。
jq -s '.[0] * .[1]' 输入流1 输入流2 > test.json
  • .[0]:由第1个输入流产生的数组数据
  • .[1]:由第2个输入流产生的数组数据
  • *:参考官方文档
Multiplication, division, modulo: *, /, and %
These infix operators behave as expected when given two numbers. Division by zero raises an error. x % y computes x modulo y.

Multiplying a string by a number produces the concatenation of that string that many times. "x" * 0 produces null.

Dividing a string by another splits the first using the second as separators.

Multiplying two objects will merge them recursively: this works like addition but if both objects contain a value for the same key, and the values are objects, the two are merged with the same strategy.

增加配置信息

我们将jq再次使用该工具将 Org3 配置定义 org3.json添加到通道的应用程序组字段,并将输出命名为 modified_config.json

jq -s \
'.[0] * {"channel_group":{"groups":{"Application":{"groups": {"Org3MSP":.[1]}}}}}' \
config.json \
../organizations/peerOrganizations/org3.example.com/org3.json \
> modified_config.json

增量计算,得到增

现在我们有两个感兴趣的 JSON 文件 config.jsonmodified_config.json. 初始文件仅包含 Org1 和 Org2 材料,而修改后的文件包含所有三个 Org。

此时,只需重新编码这两个 JSON 文件并计算增量即可。

  • 首先,转换config.json回一个名为的protobuf config.pb
configtxlator proto_encode \
--input config.json \
--type common.Config \
--output config.pb
  • 接下来,编码modified_config.jsonmodified_config.pb
configtxlator proto_encode \
--input modified_config.json \
--type common.Config \
--output modified_config.pb
  • 在用于configtxlator计算这两个配置 protobufs 之间的增量。此命令将输出一个名为的新 protobuf 二进制文件org3_update.pb
configtxlator compute_update \
--channel_id channel1 \
--original config.pb \
--updated modified_config.pb \
--output org3_update.pb

这个新的 proto org3_update.pb包含 Org3 定义和指向 Org1 和 Org2 材料的高级指针。

封装更新信息

在提交频道更新之前,我们需要执行一些最后的步骤。

  • 首先,让我们将此对象解码为可编辑的 JSON 格式并调用它org3_update.json
configtxlator proto_decode \
--input org3_update.pb \
--type common.ConfigUpdate \
--output org3_update.json

现在,我们有一个解码后的更新文件org3_update.json.我们需要将它包装一下。

这一步将返回我们之前剥离的头字段。我们将此文件命名为org3_update_in_envelope.json

echo '{"payload":{"header":{"channel_header":{"channel_id":"'channel1'", "type":2}},"data":{"config_update":'$(cat org3_update.json)'}}}' | jq . > org3_update_in_envelope.json

使用我们正确形成的 JSONorg3_update_in_envelope.json我们将configtxlator最后一次利用该工具并将其转换为 Fabric 所需的完全成熟的 protobuf 格式。我们将命名我们的最终更新对象org3_update_in_envelope.pb:

configtxlator proto_encode \
--input org3_update_in_envelope.json \
--type common.Envelope \
--output org3_update_in_envelope.pb

签署并提交配置更

签署

现在有一个 protobuf 二进制文件 org3_update_in_envelope.pb. 但是,在将配置写入分类帐之前,我们需要必需的管理员用户的签名。

我们频道应用程序组的修改策略 (mod_policy) 设置为默认值“MAJORITY”,这意味着我们需要大多数现有组织管理员对其进行签名。

因为我们只有两个组织——Org1 和 Org2——而且两个组织中的大多数是两个,==所以我们需要他们都签名==。

如果没有这两个签名,排序服务将拒绝未能满足策略的交易。

  • 首先,让我们将此更新协议签名为 Org1。导航回test-network 目录:

请记住,我们导出了必要的环境变量以作为 Org1 管理员进行操作。因此,以下命令会将更新签名为 Org1。peer channel signconfigtx

peer channel signconfigtx -f channel-artifacts/org3_update_in_envelope.pb

最后一步是切换容器的身份以反映 Org2 Admin 用户。我们通过导出特定于 Org2 MSP 的四个环境变量来做到这一点。

设置 Org2 环境变量:

# you can issue all of these commands at once
export FABRIC_CFG_PATH=${PWD}/../config/
export CORE_PEER_TLS_ENABLED=true
export CORE_PEER_LOCALMSPID="Org2MSP"
export CORE_PEER_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt
export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp
export CORE_PEER_ADDRESS=localhost:9051

更新

最后,我们将发出peer channel update命令。Org2 Admin 的签名将附加到此调用中,因此无需再次手动签署 protobuf。(更新角色会自动签署并且更新通道配置信息)

peer channel update -f channel-artifacts/org3_update_in_envelope.pb -c channel1 -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls --cafile ${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem

成功的通道更新调用会向通道上的所有对等方返回一个新块:块 3

如果您还记得,块 0-2 是初始通道配置。Block 3 作为最新的通道配置,现在在通道上定义了 Org3。

您可以peer0.org1.example.com通过发出以下命令来检查日志:

docker logs -f peer0.org1.example.com

将 Org3的节点加入频道

此时,通道配置已更新为包括我们的新组织 Org3,这意味着它的对等节点现在可以加入channel1。

导出以下环境变量以作为 Org3 管理员进行操作:

# you can issue all of these commands at once
export FABRIC_CFG_PATH=${PWD}/../config/
export CORE_PEER_TLS_ENABLED=true
export CORE_PEER_LOCALMSPID="Org3MSP"
export CORE_PEER_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/org3.example.com/peers/peer0.org3.example.com/tls/ca.crt
export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org3.example.com/users/Admin@org3.example.com/msp
export CORE_PEER_ADDRESS=localhost:11051

作为通道更新成功的结果,排序服务将验证 Org3 是否可以拉取创世块并加入通道。如果 Org3 未成功附加到通道配置,则排序服务将拒绝此请求。

使用命令来检索这个块:peer channel fetch

peer channel fetch 0 channel-artifacts/channel1.block \
-o localhost:7050 \
--ordererTLSHostnameOverride orderer.example.com \
-c channel1 \
--tls \
--cafile ${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem
2021-11-11 17:40:23.213 CST [channelCmd] InitCmdFactory -> INFO 001 Endorser and orderer connections initialized
2021-11-11 17:40:23.220 CST [cli.common] readBlock -> INFO 002 Received block: 0

请注意,我们正在传递 0以指示我们想要通道分类帐上的第一个块;即创世区块。

如果我们简单地传递命令 peer channel fetch config,那么我们将收到块 3——定义了 Org3 的更新配置。但是,我们不能从下游块开始我们的账本——我们必须从块 0 开始。

如果成功,该命令会将创世块返回名为channel1.block. 我们现在可以使用此块channel1.blockpeer加入通道。

发出命令peer channel join并传入创世块以将 Org3 peer 加入通道:

peer channel join -b channel-artifacts/channel1.block
2021-11-12 10:59:01.939 CST [channelCmd] InitCmdFactory -> INFO 001 Endorser and orderer connections initialized
2021-11-12 10:59:02.017 CST [channelCmd] executeJoin -> INFO 002 Successfully submitted proposal to join channel
查询结果

在 Org3的环境下查看该peer peer0.org3.example.com加入的通道

# you can issue all of these commands at once
export FABRIC_CFG_PATH=${PWD}/../config/
export CORE_PEER_TLS_ENABLED=true
export CORE_PEER_LOCALMSPID="Org3MSP"
export CORE_PEER_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/org3.example.com/peers/peer0.org3.example.com/tls/ca.crt
export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org3.example.com/users/Admin@org3.example.com/msp
export CORE_PEER_ADDRESS=localhost:11051
peer channel list
(base) test-network|5b8c439⚡ ⇒ peer channel list
2021-11-11 17:50:00.527 CST [channelCmd] InitCmdFactory -> INFO 001 Endorser and orderer connections initialized
Channels peers has joined:
channel1
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值