CentOS搭建docker

  • ​​一、基础环境准备​​
  • ​​1、 安装docker​​
  • ​​2、 安装docker compose​​
  • ​​3、 安装golang​​
  • ​​4、 安装Node​​
  • ​​5、 安装 Git​​
  • ​​二、fabric 源码安装​​
  • ​​1、下载源码​​
  • ​​2、使用测试网络​​
  • ​​三、chaincode部署(以go为例)​​
  • ​​1、打包链码​​
  • ​​1.1、安装依赖​​
  • ​​1.2、使用peer CLI打包链码,​​
  • ​​2、安装打包的链码​​
  • ​​3、审议链码定义​​
  • ​​4、向Channel中提交链码定义​​
  • ​​5、调用链码​​
  • ​​6、升级链码​​
  • ​​四、使用SDK与fabric网络交互​​
  • ​​五、参考文档​​

一、基础环境准备

1、 安装docker

安装docker依赖库:

yum install -y yum-utils device-mapper-persistent-data lvm2

添加Docker CE的软件源信息:

yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo

dnf makecache

安装最新版docker:

yum -y install docker-ce

systemctl start docker

查看是否安装成功:

docker version

注意:在 安装时可能会出现模块依赖问题,
解决方案:

  1. 下载docker-ce的repo
curl https://download.docker.com/linux/centos/docker-ce.repo -o /etc/yum.repos.d/docker-ce.repo
  1. 安装依赖
wget -O /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo

yum install https://download.docker.com/linux/fedora/30/x86_64/stable/Packages/containerd.io-1.2.6-3.3.fc30.x86_64.rpm
  1. 安装docker-ce
yum install docker-ce

即可解决。

查看docker版本:

[lj@localhost yum.repos.d]$ sudo docker version
[sudo] lj 的密码:
Client: Docker Engine - Community
Version: 20.10.16
API version: 1.41
Go version: go1.17.10
Git commit: aa7e414
Built: Thu May 12 09:19:45 2022
OS/Arch: linux/amd64
Context: default
Experimental: true

Server: Docker Engine - Community
Engine:
Version: 20.10.16
API version: 1.41 (minimum version 1.12)
Go version: go1.17.10
Git commit: f756502
Built: Thu May 12 09:18:08 2022
OS/Arch: linux/amd64
Experimental: false
containerd:
Version: 1.6.4
GitCommit: 212e8b6fa2f44b9c21b2798135fc6fb7c53efc16
runc:
Version: 1.1.1
GitCommit: v1.1.1-0-g52de29d
docker-init:
Version: 0.19.0
GitCommit: de40ad0
[lj@localhost yum.repos.d]$

2、 安装docker compose

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

赋权

chmod +x /usr/local/bin/docker-compose

查看版本:

docker-compose version

结果

[root@localhost yum.repos.d]# docker-compose version
docker-compose version 1.25.5, build 8a1c60f6
docker-py version: 4.1.0
CPython version: 3.7.5
OpenSSL version: OpenSSL 1.1.0l 10 Sep 2019

3、 安装golang

下载文件:

wget -P /usr/local https://dl.google.com/go/go1.16.linux-amd64.tar.gz

解压文件到 /usr/local(可以自行选择路径)

cd /usr/local
tar -zxvf go1.16.linux-amd64.tar.gz

配置环境

vim /etc/profile

写入

export PATH=$PATH:/usr/local/go/bin
export GOROOT=/usr/local/go
export GOPATH=/root/go/
#根据自己的路径进行修改

使环境配置生效

source /etc/profile

查看版本

go version

结果

[root@localhost ~]# vim /etc/profile
[root@localhost ~]# source /etc/profile
[root@localhost ~]# go version
go version go1.16 linux/amd64

4、 安装Node

wget https://npm.taobao.org/mirrors/node/v14.4.0/node-v14.4.0-linux-x64.tar.xz
tar -xvf node-v14.4.0-linux-x64.tar.xz
cd node-v14.4.0-linux-x64/
cd bin
sudo ln -s ${PWD}/node /usr/bin/node
sudo ln -s ${PWD}/npm /usr/bin/npm
[lj@localhost ~]$ wget https://npm.taobao.org/mirrors/node/v14.4.0/node-v14.4.0-linux-x64.tar.xz
--2022-06-03 21:22:55-- https://npm.taobao.org/mirrors/node/v14.4.0/node-v14.4.0-linux-x64.tar.xz
正在解析主机 npm.taobao.org (npm.taobao.org)... 114.55.80.225
正在连接 npm.taobao.org (npm.taobao.org)|114.55.80.225|:443... 已连接。
已发出 HTTP 请求,正在等待回应... 302 Moved Temporarily
位置:https://cdn.npmmirror.com/binaries/node/v14.4.0/node-v14.4.0-linux-x64.tar.xz [跟随至新的 URL]
--2022-06-03 21:22:55-- https://cdn.npmmirror.com/binaries/node/v14.4.0/node-v14.4.0-linux-x64.tar.xz
正在解析主机 cdn.npmmirror.com (cdn.npmmirror.com)... 183.204.38.243, 183.204.38.239, 183.204.38.238, ...
正在连接 cdn.npmmirror.com (cdn.npmmirror.com)|183.204.38.243|:443... 已连接。
已发出 HTTP 请求,正在等待回应... 200 OK
长度:20837612 (20M) [application/x-xz]
正在保存至: “node-v14.4.0-linux-x64.tar.xz”

100%[========================================================================================================================================================>] 20,837,612 9.92MB/s 用时 2.0s

2022-06-03 21:22:57 (9.92 MB/s) - 已保存 “node-v14.4.0-linux-x64.tar.xz” [20837612/20837612])

查看版本

[lj@localhost bin]$ npm -v
6.14.5
[lj@localhost bin]$ node -v
v14.4.0

5、 安装 Git

yum install git

查看版本

git version

二、fabric 源码安装

1、下载源码

git clone https://github.com/hyperledger/fabric.git
cd fabric/scripts
#下载镜像和二进制文件:
sudo ./bootstrap.sh

过程会比较慢,有可能出现卡顿的情况,多试几次。

2、使用测试网络

跑之前先清一下docker网络环境

docker stop $(docker ps -aq)

docker rm $(docker ps -qa)

启动test-network测试网络:

cd /home/lj/fabric/scripts/fabric-samples/test-network #(改成自己的安装目录)

./network.sh up

结果如下

[root@localhost test-network]# ./network.sh up
Using docker and docker-compose
Starting nodes with CLI timeout of '5' tries and CLI delay of '3' seconds and using database 'leveldb'
LOCAL_VERSION=2.3.0
DOCKER_IMAGE_VERSION=2.3.0
Creating peer0.org1.example.com ... done
Creating orderer.example.com ... done
Creating peer0.org2.example.com ... done
Creating cli ... done
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
da86cd62b2cc hyperledger/fabric-tools:latest "/bin/bash" 1 second ago Up Less than a second cli
e663bfeb201f hyperledger/fabric-peer:latest "peer node start" 2 seconds ago Up Less than a second 0.0.0.0:9051->9051/tcp, :::9051->9051/tcp, 7051/tcp, 0.0.0.0:9445->9445/tcp, :::9445->9445/tcp peer0.org2.example.com
149fc15023d5 hyperledger/fabric-orderer:latest "orderer" 2 seconds ago Up Less than a second 0.0.0.0:7050->7050/tcp, :::7050->7050/tcp, 0.0.0.0:7053->7053/tcp, :::7053->7053/tcp, 0.0.0.0:9443->9443/tcp, :::9443->9443/tcp orderer.example.com
e2f5ac4e9918 hyperledger/fabric-peer:latest "peer node start" 2 seconds ago Up Less than a second 0.0.0.0:7051->7051/tcp, :::7051->7051/tcp, 0.0.0.0:9444->9444/tcp, :::9444->9444/tcp peer0.org1.example.com

查看docker容器:

docker ps
[root@localhost test-network]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
21caae6bbc81 hyperledger/fabric-tools:latest "/bin/bash" 20 minutes ago Up 20 minutes cli
3a624444b3cf hyperledger/fabric-peer:latest "peer node start" 20 minutes ago Up 20 minutes 0.0.0.0:9051->9051/tcp, :::9051->9051/tcp, 7051/tcp, 0.0.0.0:9445->9445/tcp, :::9445->9445/tcp peer0.org2.example.com
cf821462d4c3 hyperledger/fabric-orderer:latest "orderer" 20 minutes ago Up 20 minutes 0.0.0.0:7050->7050/tcp, :::7050->7050/tcp, 0.0.0.0:7053->7053/tcp, :::7053->7053/tcp, 0.0.0.0:9443->9443/tcp, :::9443->9443/tcp orderer.example.com
0f59c549dffd hyperledger/fabric-peer:latest "peer node start" 20 minutes ago Up 20 minutes 0.0.0.0:7051->7051/tcp, :::7051->7051/tcp, 0.0.0.0:9444->9444/tcp, :::9444->9444/tcp peer0.org1.example.com
  • 至此,fabric测试网络test-network跑通了。

创建channel,使用network.sh脚本创建来创建一个连接org1和org2组织并加入他们peer的通道,命令如下:

./network.sh createChannel
[root@localhost test-network]# ./network.sh createChannel
Using docker and docker-compose
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
Network Running Already
Using docker and docker-compose
Generating channel genesis block 'mychannel.block'
/home/lj/fabric/scripts/fabric-samples/bin/configtxgen
+ configtxgen -profile TwoOrgsApplicationGenesis -outputBlock ./channel-artifacts/mychannel.block -channelID mychannel
2022-05-29 13:42:27.026 CST [common.tools.configtxgen] main -> INFO 001 Loading configuration
2022-05-29 13:42:27.033 CST [common.tools.configtxgen.localconfig] completeInitialization -> INFO 002 orderer type: etcdraft
2022-05-29 13:42:27.033 CST [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
2022-05-29 13:42:27.033 CST [common.tools.configtxgen.localconfig] Load -> INFO 004 Loaded configuration: /home/lj/fabric/scripts/fabric-samples/test-network/configtx/configtx.yaml
2022-05-29 13:42:27.043 CST [common.tools.configtxgen] doOutputBlock -> INFO 005 Generating genesis block
2022-05-29 13:42:27.043 CST [common.tools.configtxgen] doOutputBlock -> INFO 006 Creating application channel genesis block
2022-05-29 13:42:27.043 CST [common.tools.configtxgen] doOutputBlock -> INFO 007 Writing genesis block
+ res=0
Creating channel mychannel
Using organization 1
+ osnadmin channel join --channel-id mychannel --config-block ./channel-artifacts/mychannel.block -o localhost:7053 --ca-file /home/lj/fabric/scripts/fabric-samples/test-network/organizations/ordererOrganizations/example.com/tlsca/tlsca.example.com-cert.pem --client-cert /home/lj/fabric/scripts/fabric-samples/test-network/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/tls/server.crt --client-key /home/lj/fabric/scripts/fabric-samples/test-network/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/tls/server.key
+ res=0
Status: 201
{
"name": "mychannel",
"url": "/participation/v1/channels/mychannel",
"consensusRelation": "consenter",
"status": "active",
"height": 1
}

Channel 'mychannel' created
Joining org1 peer to the channel...
Using organization 1
+ peer channel join -b ./channel-artifacts/mychannel.block
+ res=0
2022-05-29 13:42:33.319 CST [channelCmd] InitCmdFactory -> INFO 001 Endorser and orderer connections initialized
2022-05-29 13:42:33.350 CST [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
2022-05-29 13:42:36.466 CST [channelCmd] InitCmdFactory -> INFO 001 Endorser and orderer connections initialized
2022-05-29 13:42:36.485 CST [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/tlsca/tlsca.example.com-cert.pem
2022-05-29 05:42:36.822 UTC [channelCmd] InitCmdFactory -> INFO 001 Endorser and orderer connections initialized
2022-05-29 05:42:36.826 UTC [cli.common] readBlock -> INFO 002 Received block: 0
2022-05-29 05:42:36.826 UTC [channelCmd] fetch -> INFO 003 Retrieving last config block: 0
2022-05-29 05:42:36.830 UTC [cli.common] readBlock -> INFO 004 Received block: 0
Decoding config block to JSON and isolating config to Org1MSPconfig.json
+ configtxlator proto_decode --input config_block.pb --type common.Block --output config_block.json
+ jq '.data.data[0].payload.data.config' config_block.json
+ 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
Generating anchor peer update transaction for Org1 on channel mychannel
+ configtxlator proto_encode --input Org1MSPconfig.json --type common.Config --output original_config.pb
+ configtxlator proto_encode --input Org1MSPmodified_config.json --type common.Config --output modified_config.pb
+ configtxlator compute_update --channel_id mychannel --original original_config.pb --updated modified_config.pb --output config_update.pb
+ configtxlator proto_decode --input config_update.pb --type common.ConfigUpdate --output config_update.json
+ jq .
++ cat config_update.json
+ 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":' '"0"' '}' '},' '"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":' '"0"' '}' '},' '"mod_policy":' '"",' '"policies":' '{},' '"values":' '{},' '"version":' '"0"' '}' '}}}}'
+ configtxlator proto_encode --input config_update_in_envelope.json --type common.Envelope --output Org1MSPanchors.tx
2022-05-29 05:42:37.170 UTC [channelCmd] InitCmdFactory -> INFO 001 Endorser and orderer connections initialized
2022-05-29 05:42:37.192 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/tlsca/tlsca.example.com-cert.pem
2022-05-29 05:42:37.440 UTC [channelCmd] InitCmdFactory -> INFO 001 Endorser and orderer connections initialized
2022-05-29 05:42:37.443 UTC [cli.common] readBlock -> INFO 002 Received block: 1
2022-05-29 05:42:37.443 UTC [channelCmd] fetch -> INFO 003 Retrieving last config block: 1
2022-05-29 05:42:37.444 UTC [cli.common] readBlock -> INFO 004 Received block: 1
Decoding config block to JSON and isolating config to Org2MSPconfig.json
+ configtxlator proto_decode --input config_block.pb --type common.Block --output config_block.json
+ jq '.data.data[0].payload.data.config' config_block.json
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 --output original_config.pb
+ configtxlator proto_encode --input Org2MSPmodified_config.json --type common.Config --output modified_config.pb
+ configtxlator compute_update --channel_id mychannel --original original_config.pb --updated modified_config.pb --output config_update.pb
+ configtxlator proto_decode --input config_update.pb --type common.ConfigUpdate --output config_update.json
++ 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":' '"0"' '}' '},' '"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":' '"0"' '}' '},' '"mod_policy":' '"",' '"policies":' '{},' '"values":' '{},' '"version":' '"0"' '}' '}}}}'
+ configtxlator proto_encode --input config_update_in_envelope.json --type common.Envelope --output Org2MSPanchors.tx
2022-05-29 05:42:37.725 UTC [channelCmd] InitCmdFactory -> INFO 001 Endorser and orderer connections initialized
2022-05-29 05:42:37.741 UTC [channelCmd] update -> INFO 002 Successfully submitted channel update
Anchor peer set for org 'Org2MSP' on channel 'mychannel'
Channel 'mychannel' joined

也可以带上channel标签,命令如下(-c channelName):

./network.sh createChannel -c channel1

如果要在一个步骤中启动网络并创建频道,可以同时使用up和create channel模式:

./network.sh up createChannel

在通道上启动链码

使用network.sh创建通道之后,可以使用以下命令在通道上启动链码(默认使用go语言):

./network.sh deployCC
[root@localhost test-network]# ./network.sh deployCC
Using docker and docker-compose
deploying chaincode on channel 'mychannel'
executing with the following
- CHANNEL_NAME: mychannel
- CC_NAME: NA
- CC_SRC_PATH: NA
- CC_SRC_LANGUAGE: NA
- CC_VERSION: 1.0
- CC_SEQUENCE: 1
- CC_END_POLICY: NA
- CC_COLL_CONFIG: NA
- CC_INIT_FCN: NA
- DELAY: 3
- MAX_RETRY: 5
- VERBOSE: false
No chaincode name was provided. Valid call example: ./network.sh deployCC -ccn basic -ccp ../asset-transfer-basic/chaincode-go -ccl go
Deploying chaincode failed

提示:

No chaincode name was provided. Valid call example: ./network.sh deployCC -ccn basic -ccp ../asset-transfer-basic/chaincode-go -ccl go
Deploying chaincode failed

意思是默认缺省参数的方式不太行,需要指定 -ccn -ccp 参数。

当补全 -ccn 和 -ccp 参数后,继续执行:

./network.sh deployCC -ccn basic -ccp ../asset-transfer-basic/chaincode-go -ccl go
[root@localhost test-network]#  ./network.sh deployCC -ccn basic -ccp ../asset-transfer-basic/chaincode-go -ccl go
Using docker and docker-compose
deploying chaincode on channel 'mychannel'
executing with the following
- CHANNEL_NAME: mychannel
- CC_NAME: basic
- CC_SRC_PATH: ../asset-transfer-basic/chaincode-go
- CC_SRC_LANGUAGE: go
- CC_VERSION: 1.0
- CC_SEQUENCE: 1
- CC_END_POLICY: NA
- CC_COLL_CONFIG: NA
- CC_INIT_FCN: NA
- DELAY: 3
- MAX_RETRY: 5
- VERBOSE: false
Vendoring Go dependencies at ../asset-transfer-basic/chaincode-go
/home/lj/fabric/scripts/fabric-samples/asset-transfer-basic/chaincode-go /home/lj/fabric/scripts/fabric-samples/test-network
go: github.com/golang/protobuf@v1.3.2: Get "https://proxy.golang.org/github.com/golang/protobuf/@v/v1.3.2.mod": dial tcp 172.217.163.49:443: connect: connection refused
/home/lj/fabric/scripts/fabric-samples/test-network
Finished vendoring Go dependencies
+ peer lifecycle chaincode package basic.tar.gz --path ../asset-transfer-basic/chaincode-go --lang golang --label basic_1.0
+ res=1
Error: failed to normalize chaincode path: 'go list' failed with: go: github.com/golang/protobuf@v1.3.2: Get "https://proxy.golang.org/github.com/golang/protobuf/@v/v1.3.2.mod": dial tcp 172.217.163.49:443: connect: connection refused: exit status 1
Chaincode packaging has failed
Deploying chaincode failed

提示:

Error: failed to normalize chaincode path: 'go list' failed with: go: github.com/golang/protobuf@v1.3.2: Get "https://proxy.golang.org/github.com/golang/protobuf/@v/v1.3.2.mod": dial tcp 172.217.163.49:443: connect: connection refused: exit status 1
Chaincode packaging has failed
Deploying chaincode failed

go list 发生失败,这时通过 ​​go env​​ 可以看到,go 的代理默认是:https://proxy.golang.org,direct.

CentOS7部署fabric_docker


将代理更改为:goproxy.cn,direct。

执行:

go env -w GOPROXY=https://goproxy.cn,direct

再次执行 go env 可以看到代理已经更换了。

好,再去执行:

./network.sh deployCC -ccn basic  -ccp ../asset-transfer-basic/chaincode-go -ccl go

执行结果

[root@localhost test-network]# ./network.sh deployCC -ccn basic  -ccp ../asset-transfer-basic/chaincode-go -ccl go
Using docker and docker-compose
deploying chaincode on channel 'mychannel'
executing with the following
- CHANNEL_NAME: mychannel
- CC_NAME: basic
- CC_SRC_PATH: ../asset-transfer-basic/chaincode-go
- CC_SRC_LANGUAGE: go
- CC_VERSION: 1.0
- CC_SEQUENCE: 1
- CC_END_POLICY: NA
- CC_COLL_CONFIG: NA
- CC_INIT_FCN: NA
- DELAY: 3
- MAX_RETRY: 5
- VERBOSE: false
Vendoring Go dependencies at ../asset-transfer-basic/chaincode-go
/home/lj/fabric/scripts/fabric-samples/asset-transfer-basic/chaincode-go /home/lj/fabric/scripts/fabric-samples/test-network
go: downloading github.com/hyperledger/fabric-contract-api-go v1.1.0
go: downloading github.com/hyperledger/fabric-chaincode-go v0.0.0-20200424173110-d7076418f212
go: downloading github.com/hyperledger/fabric-protos-go v0.0.0-20200424173316-dd554ba3746e
go: downloading github.com/stretchr/testify v1.5.1
go: downloading github.com/golang/protobuf v1.3.2
go: downloading google.golang.org/grpc v1.23.0
go: downloading github.com/xeipuuv/gojsonschema v1.2.0
go: downloading github.com/go-openapi/spec v0.19.4
go: downloading github.com/gobuffalo/packr v1.30.1
go: downloading github.com/davecgh/go-spew v1.1.1
go: downloading github.com/pmezard/go-difflib v1.0.0
go: downloading gopkg.in/yaml.v2 v2.2.8
go: downloading google.golang.org/genproto v0.0.0-20180831171423-11092d34479b
go: downloading golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297
go: downloading github.com/go-openapi/jsonpointer v0.19.3
go: downloading github.com/go-openapi/jsonreference v0.19.2
go: downloading github.com/go-openapi/swag v0.19.5
go: downloading github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415
go: downloading github.com/gobuffalo/envy v1.7.0
go: downloading github.com/gobuffalo/packd v0.3.0
go: downloading golang.org/x/sys v0.0.0-20190710143415-6ec70d6a5542
go: downloading github.com/PuerkitoBio/purell v1.1.1
go: downloading github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e
go: downloading github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f
go: downloading github.com/joho/godotenv v1.3.0
go: downloading github.com/rogpeppe/go-internal v1.3.0
go: downloading github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578
go: downloading golang.org/x/text v0.3.2
/home/lj/fabric/scripts/fabric-samples/test-network
Finished vendoring Go dependencies
+ peer lifecycle chaincode package basic.tar.gz --path ../asset-transfer-basic/chaincode-go --lang golang --label basic_1.0
+ res=0
Chaincode is packaged
Installing chaincode on peer0.org1...
Using organization 1
+ peer lifecycle chaincode install basic.tar.gz
+ res=0
2022-05-29 14:14:08.299 CST [cli.lifecycle.chaincode] submitInstallProposal -> INFO 001 Installed remotely: response:<status:200 payload:"\nJbasic_1.0:2e20ce421c8037420718c8a3918a1eea76343b7361fffdac454181c54e5736c7\022\tbasic_1.0" >
2022-05-29 14:14:08.301 CST [cli.lifecycle.chaincode] submitInstallProposal -> INFO 002 Chaincode code package identifier: basic_1.0:2e20ce421c8037420718c8a3918a1eea76343b7361fffdac454181c54e5736c7
Chaincode is installed on peer0.org1
Install chaincode on peer0.org2...
Using organization 2
+ peer lifecycle chaincode install basic.tar.gz
+ res=0
2022-05-29 14:14:23.243 CST [cli.lifecycle.chaincode] submitInstallProposal -> INFO 001 Installed remotely: response:<status:200 payload:"\nJbasic_1.0:2e20ce421c8037420718c8a3918a1eea76343b7361fffdac454181c54e5736c7\022\tbasic_1.0" >
2022-05-29 14:14:23.246 CST [cli.lifecycle.chaincode] submitInstallProposal -> INFO 002 Chaincode code package identifier: basic_1.0:2e20ce421c8037420718c8a3918a1eea76343b7361fffdac454181c54e5736c7
Chaincode is installed on peer0.org2
Using organization 1
+ peer lifecycle chaincode queryinstalled
+ res=0
Installed chaincodes on peer:
Package ID: basic_1.0:2e20ce421c8037420718c8a3918a1eea76343b7361fffdac454181c54e5736c7, Label: basic_1.0
Query installed successful on peer0.org1 on channel
Using organization 1
+ peer lifecycle chaincode approveformyorg -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls --cafile /home/lj/fabric/scripts/fabric-samples/test-network/organizations/ordererOrganizations/example.com/tlsca/tlsca.example.com-cert.pem --channelID mychannel --name basic --version 1.0 --package-id basic_1.0:2e20ce421c8037420718c8a3918a1eea76343b7361fffdac454181c54e5736c7 --sequence 1
+ res=0
2022-05-29 14:14:25.477 CST [chaincodeCmd] ClientWait -> INFO 001 txid [c391c143c073e73a2a17200eaebd1d1ed69923ac79e4dafb0450bea6961ca050] committed with status (VALID) at localhost:7051
Chaincode definition approved on peer0.org1 on channel 'mychannel'
Using organization 1
Checking the commit readiness of the chaincode definition on peer0.org1 on channel 'mychannel'...
Attempting to check the commit readiness of the chaincode definition on peer0.org1, Retry after 3 seconds.
+ peer lifecycle chaincode checkcommitreadiness --channelID mychannel --name basic --version 1.0 --sequence 1 --output json
+ res=0
{
"approvals": {
"Org1MSP": true,
"Org2MSP": false
}
}
Checking the commit readiness of the chaincode definition successful on peer0.org1 on channel 'mychannel'
Using organization 2
Checking the commit readiness of the chaincode definition on peer0.org2 on channel 'mychannel'...
Attempting to check the commit readiness of the chaincode definition on peer0.org2, Retry after 3 seconds.
+ peer lifecycle chaincode checkcommitreadiness --channelID mychannel --name basic --version 1.0 --sequence 1 --output json
+ res=0
{
"approvals": {
"Org1MSP": true,
"Org2MSP": false
}
}
Checking the commit readiness of the chaincode definition successful on peer0.org2 on channel 'mychannel'
Using organization 2
+ peer lifecycle chaincode approveformyorg -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls --cafile /home/lj/fabric/scripts/fabric-samples/test-network/organizations/ordererOrganizations/example.com/tlsca/tlsca.example.com-cert.pem --channelID mychannel --name basic --version 1.0 --package-id basic_1.0:2e20ce421c8037420718c8a3918a1eea76343b7361fffdac454181c54e5736c7 --sequence 1
+ res=0
2022-05-29 14:14:33.794 CST [chaincodeCmd] ClientWait -> INFO 001 txid [74afc86b32cc27d3fd153f01f9052a09ad64883f36d67fb6bc262d40dcfeaf27] committed with status (VALID) at localhost:9051
Chaincode definition approved on peer0.org2 on channel 'mychannel'
Using organization 1
Checking the commit readiness of the chaincode definition on peer0.org1 on channel 'mychannel'...
Attempting to check the commit readiness of the chaincode definition on peer0.org1, Retry after 3 seconds.
+ peer lifecycle chaincode checkcommitreadiness --channelID mychannel --name basic --version 1.0 --sequence 1 --output json
+ res=0
{
"approvals": {
"Org1MSP": true,
"Org2MSP": true
}
}
Checking the commit readiness of the chaincode definition successful on peer0.org1 on channel 'mychannel'
Using organization 2
Checking the commit readiness of the chaincode definition on peer0.org2 on channel 'mychannel'...
Attempting to check the commit readiness of the chaincode definition on peer0.org2, Retry after 3 seconds.
+ peer lifecycle chaincode checkcommitreadiness --channelID mychannel --name basic --version 1.0 --sequence 1 --output json
+ res=0
{
"approvals": {
"Org1MSP": true,
"Org2MSP": true
}
}
Checking the commit readiness of the chaincode definition successful on peer0.org2 on channel 'mychannel'
Using organization 1
Using organization 2
+ peer lifecycle chaincode commit -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls --cafile /home/lj/fabric/scripts/fabric-samples/test-network/organizations/ordererOrganizations/example.com/tlsca/tlsca.example.com-cert.pem --channelID mychannel --name basic --peerAddresses localhost:7051 --tlsRootCertFiles /home/lj/fabric/scripts/fabric-samples/test-network/organizations/peerOrganizations/org1.example.com/tlsca/tlsca.org1.example.com-cert.pem --peerAddresses localhost:9051 --tlsRootCertFiles /home/lj/fabric/scripts/fabric-samples/test-network/organizations/peerOrganizations/org2.example.com/tlsca/tlsca.org2.example.com-cert.pem --version 1.0 --sequence 1
+ res=0
2022-05-29 14:14:42.423 CST [chaincodeCmd] ClientWait -> INFO 001 txid [d44c99e9512990754db87f10c235aaf0c5118dea3b3ddf695c54427d614d02b1] committed with status (VALID) at localhost:9051
2022-05-29 14:14:42.423 CST [chaincodeCmd] ClientWait -> INFO 002 txid [d44c99e9512990754db87f10c235aaf0c5118dea3b3ddf695c54427d614d02b1] committed with status (VALID) at localhost:7051
Chaincode definition committed on channel 'mychannel'
Using organization 1
Querying chaincode definition on peer0.org1 on channel 'mychannel'...
Attempting to Query committed status on peer0.org1, Retry after 3 seconds.
+ peer lifecycle chaincode querycommitted --channelID mychannel --name basic
+ res=0
Committed chaincode definition for chaincode 'basic' on channel 'mychannel':
Version: 1.0, Sequence: 1, Endorsement Plugin: escc, Validation Plugin: vscc, Approvals: [Org1MSP: true, Org2MSP: true]
Query chaincode definition successful on peer0.org1 on channel 'mychannel'
Using organization 2
Querying chaincode definition on peer0.org2 on channel 'mychannel'...
Attempting to Query committed status on peer0.org2, Retry after 3 seconds.
+ peer lifecycle chaincode querycommitted --channelID mychannel --name basic
+ res=0
Committed chaincode definition for chaincode 'basic' on channel 'mychannel':
Version: 1.0, Sequence: 1, Endorsement Plugin: escc, Validation Plugin: vscc, Approvals: [Org1MSP: true, Org2MSP: true]
Query chaincode definition successful on peer0.org2 on channel 'mychannel'
Chaincode initialization is not required

最后会看到提示:

Query chaincode definition successful on peer0.org2 on channel 'mychannel'
Chaincode initialization is not required

CentOS7部署fabric_docker_02


代表链码部署成功。

可以指定语言,加-l ,比如用java,命令如下:

./network.sh deployCC -l java

关闭网络:

./network.sh down

三、chaincode部署(以go为例)

使用Peer CLI来向通道中部署链代码:

  • 第一步,打包链码
  • 第二步,安装打包的链码
  • 第三步,各组织对链码内容和定义达成一致
  • 第四步,向channel中提交链码

在进行如下步骤之前,首先需要关闭网络,然后再重启网络,同时创建channel,即如下两条命令。

./network.sh down
./network.sh up createChannel

1、打包链码

1.1、安装依赖

cd fabric/scripts/fabric-samples/chaincode/fabcar/go

GO111MODULE=on go mod vendor

1.2、使用peer CLI打包链码,

peer的可执行二级制文件在fabric-sample的bin文件夹中。使用如下命令添加Peer到CLI命令路径中

cd ../../../test-network

export PATH=${PWD}/../bin:$PATH

还需要设置指向fabric-samples中core.yaml的FABRIC_CFG_PATH

export FABRIC_CFG_PATH=$PWD/../config/

查看peer版本来确认是否安装成功

peer version
[root@localhost lj]# cd fabric
[root@localhost fabric]# cd scripts
[root@localhost scripts]# cd fabric-samples/chaincode/fabcar/go
[root@localhost go]# GO111MODULE=on go mod vendor
[root@localhost go]# cd ../../../test-network
[root@localhost test-network]# export PATH=${PWD}/../bin:$PATH
[root@localhost test-network]# export FABRIC_CFG_PATH=$PWD/../config/
[root@localhost test-network]# peer version
peer:
Version: 2.3.0
Commit SHA: ec81f3e74
Go version: go1.14.12
OS/Arch: linux/amd64
Chaincode:
Base Docker Label: org.hyperledger.fabric
Docker Namespace: hyperledger

打包链代码

peer lifecycle chaincode package fabcar.tar.gz --path ../chaincode/fabcar/go/ --lang golang --label fabcar_1

此命令会在当前目录下创建fabcar.tar.gz文件,–lang标识链码的编程语言,–path链码路径,–label链码安装后的标签,建议包含链码名称和版本。

2、安装打包的链码

由于有两个peer链码需要再所有参与背书的peer上安装。因为我们将要设置的背书策略是,Org1和Org2同时背书,所以Org1和Org2上都要安装链码。

首先在Org1的peer上安装,通过设置环境变量来指定peer操作的是Org1

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上安装链码

peer lifecycle chaincode install fabcar.tar.gz
[lj@localhost test-network]$ peer lifecycle chaincode install fabcar.tar.gz

2022-06-03 02:13:35.452 CST [cli.lifecycle.chaincode] submitInstallProposal -> INFO 001 Installed remotely: response:<status:200 payload:"\nIfabcar_1:1146b4b491871bf18b23dd67dd8cc058655b36cc0e2274f165ed06b796a8f276\022\010fabcar_1" >
2022-06-03 02:13:35.452 CST [cli.lifecycle.chaincode] submitInstallProposal -> INFO 002 Chaincode code package identifier: fabcar_1:1146b4b491871bf18b23dd67dd8cc058655b36cc0e2274f165ed06b796a8f276

下面安装Org2的peer

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_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
[lj@localhost test-network]$ peer lifecycle chaincode install fabcar.tar.gz
2022-06-03 02:16:45.300 CST [cli.lifecycle.chaincode] submitInstallProposal -> INFO 001 Installed remotely: response:<status:200 payload:"\nIfabcar_1:1146b4b491871bf18b23dd67dd8cc058655b36cc0e2274f165ed06b796a8f276\022\010fabcar_1" >
2022-06-03 02:16:45.307 CST [cli.lifecycle.chaincode] submitInstallProposal -> INFO 002 Chaincode code package identifier: fabcar_1:1146b4b491871bf18b23dd67dd8cc058655b36cc0e2274f165ed06b796a8f276

3、审议链码定义

安装链码包后,需要组织审议链码的定义。定义包含管理链码的参数如名称、版本,背书策略.

channel内的成员需要在部署链码之前对链码的定义达成一致。使用Application/Channel/lifeycleEndorsement。默认需要大多数成员对链码定义达成一致。这里我们有两个组织Org1和Org2,多数的情况是,两个组织都要达成一致。

如果一个组织内的peer已经安装了链码,那么组织在审议链码定义时需要包含packageID。packageID用于关联peer上安装的链码和审议过的链码定义,且用于组织为交易做背书。

可以用下面命令查找peer上的package ID

peer lifecycle chaincode queryinstalled
[lj@localhost test-network]$ peer lifecycle chaincode queryinstalled
Installed chaincodes on peer:
Package ID: fabcar_1:1146b4b491871bf18b23dd67dd8cc058655b36cc0e2274f165ed06b796a8f276, Label: fabcar_1

package ID是链码标签和链码二级制hash值的结合,每个peer会产生相同的packageID。

在审议链码时会用到packageID,所以我们先把它保存到一个环境变量中,执行下面命令(值为上一步得到的输出)

export CC_PACKAGE_ID=fabcar_1:1146b4b491871bf18b23dd67dd8cc058655b36cc0e2274f165ed06b796a8f276

因为当前设置的是Org2的环境变量,我们可以用Org2来审议链码。审议是组织级别的,所以只需要一个peer节点操作,审议结果会通过gossip协议通知到组织内。审议链码执行以下命令:

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 true --cafile ${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem
[lj@localhost 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 1 --tls true --cafile ${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem
2022-06-03 02:30:09.030 CST [chaincodeCmd] ClientWait -> INFO 001 txid [5e96f08ad85e711cfa703b0cd3b2bead73308ebeccfb550687a8dc1ed6847c60] committed with status (VALID) at localhost:9051

通过–package-id来标识链码,–sequence是一个整数用来追踪链码定义和升级次数。因为此处是第一次部署链码到channel中,所以sequence是1,当此链码升级的时候,sequence要递增到2。如果你使用的是低版本的链码API,可以使用–init-required来执行链码的初始化init。第一次invoke调用链码时需要使用–isInit来初始化链码,执行init函数。

我们可以对approveformyorg 命令使用–signature-policy 或–channel-config-policy参数来指定链码的背书策略。背书策略指定需要多个组织内的peer来为交易做背书。此处我们没有指定背书策略,链码会使用默认的背书策略(运行的peer中大多数为交易做背书)。预示着如果新组织加入或删除组织,背书策略会自动升级为需要更多或更少的背书。本文档中,默认策略是需要来自Org1和Org2的2个peer。如果要自定义背书策略,查看官方文档。

需要用admin的身份来审议链码定义,因此CORE_PEER_MSPCONFIGPATH 要执行admin的账户。客户端用户不能审议链码,审议结果会提交给排序服务器,排序服务器验证管理员签名后会将审议结果分发给组织内的peers。

同样Org1也需要进行相同的操作

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 true --cafile ${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem
[lj@localhost test-network]$ export CORE_PEER_LOCALMSPID="Org1MSP"
[lj@localhost test-network]$
[lj@localhost test-network]$ export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp
[lj@localhost test-network]$
[lj@localhost test-network]$ export CORE_PEER_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt
[lj@localhost test-network]$
[lj@localhost test-network]$ export CORE_PEER_ADDRESS=localhost:7051
[lj@localhost test-network]$
[lj@localhost 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 1 --tls true --cafile ${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem
2022-06-03 02:30:55.745 CST [chaincodeCmd] ClientWait -> INFO 001 txid [6535be744fdd71f89122c5977807e94d299703697865a8fe8724aab819501523] committed with status (VALID) at localhost:7051

我们现在有了大多数成员的同意可以在channel上部署链码了。虽然只需要大多数组织来审议链码定义,但只有审议通过链码的组织,才能安装链码。在某个组织审议链码之前提交的链码定义,此组织不可为交易做背书。因此推荐在所有组织审议链码之后再提交链码定义。

4、向Channel中提交链码定义

在足够数量的组织为链码定义达成一致后,一个组织可以提交链码定义到Channel中。如果大多数组织同意了链码定义,提交事务会成功执行,且链码定义的参数会在channel中生效。

可以使用如下命令来查看哪些成员已经同意了链码定义。

peer lifecycle chaincode checkcommitreadiness --channelID mychannel --name fabcar --version 1.0 --sequence 1 --tls true --cafile ${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem --output json
2022-06-03 02:30:55.745 CST [chaincodeCmd] ClientWait -> INFO 001 txid [6535be744fdd71f89122c5977807e94d299703697865a8fe8724aab819501523] committed with status (VALID) at localhost:7051
[lj@localhost test-network]$ peer lifecycle chaincode checkcommitreadiness --channelID mychannel --name fabcar --version 1.0 --sequence 1 --tls true --cafile ${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem --output json
{
"approvals": {
"Org1MSP": true,
"Org2MSP": true
}
}

命令会以json的形式显示输出,组织是否已经同意了checkcommitreadiness命令中指定的参数。

通道内所有组织都同意了链码定义之后,链码定义就可以提交到channel中,执行以下命令提交提交channel中

peer lifecycle chaincode commit -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --channelID mychannel --name fabcar --version 1.0 --sequence 1 --tls true --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
[lj@localhost test-network]$ peer lifecycle chaincode commit -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --channelID mychannel --name fabcar --version 1.0 --sequence 1 --tls true --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
2022-06-03 02:32:04.393 CST [chaincodeCmd] ClientWait -> INFO 001 txid [5ffcf0867756ac022ccbef8ee190a43763224f1b52eea33e37c5ccff24a20e90] committed with status (VALID) at localhost:9051
2022-06-03 02:32:04.495 CST [chaincodeCmd] ClientWait -> INFO 002 txid [5ffcf0867756ac022ccbef8ee190a43763224f1b52eea33e37c5ccff24a20e90] committed with status (VALID) at localhost:7051

上述命令使用了–peerAddresses来指定Org1和Org2中的两个节点,提交事务提交给了加入通道peers,可以用来查询链码定义。

这个命令需要有满足部署链码策略的数量peers,因为同意链码定义已经同步到组织内部,所以可以选择组织内任意一个peer。

通道内成员背书的链码定义会提交到排序服务节点上,然后在通道中会创建一个区块。通道上的peers会验证是否有足够的组织同意了链码定义,peer lifecycle chaincode commit会一直等待peers的验证结果。

可以使用如下命令来确认链码定义是否已经被提交到通道上。

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
[lj@localhost test-network]$ 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]

CentOS7部署fabric_centos_03

5、调用链码

如果链码定义提交成功,链码会在安装的peer上开始运行。链码已经可以被客户端调用。使用下面的命令初始化创建一组cars数据。注意链码调用需要有满足策略的足够的背书节点。

peer chaincode invoke -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls true --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":[]}'

CentOS7部署fabric_docker_04

可以使用query函数来查询数据

peer chaincode query -C mychannel -n fabcar -c '{"Args":["queryAllCars"]}'

CentOS7部署fabric_docker_05

6、升级链码

可以使用lifecycle 来升级已经部署的链码。通道中成员可以升级链码:安装新链码包,审议链码定义,新的链码版本,新的sequence(递增一位)。新的链码在提交到channel后可以调用。lifecycle进程使通道内的成员在链码升级时协调一致,并确保在部署新链码之前有足够数量的通道成员已经准备使用新链码。

通道内成员也可以使用升级程序来升级链码的背书策略。通过审议新背书策略的链码定义并提交链码定义到通道中,通道成员可以成员可以更改背书策略而不用安装新的链码。

假设链码升级的场景是,Org1和Org2想安装一般用另一种语言写的链码。使用lifecycle升级链码,并确保每个组织都安装上了新的链码后才激活新链码。

我们一开始在Org1和Org2上安装的是GO语言的版本链码,但为了更合适的开发需要JS写的链码。第一步是打包JS版本的链码。如果你一开始使用的是JS版本链码,这里你可以使用Go或者Java版。

执行test-network目录下如下命令,来安装依赖包

cd ../chaincode/fabcar/javascript

npm install

cd ../../../test-network
[lj@localhost test-network]$ cd ../chaincode/fabcar/javascript
[lj@localhost javascript]$ npm install
npm WARN deprecated mkdirp@0.5.1: Legacy versions of mkdirp are no longer supported. Please update to mkdirp 1.x. (Note that the API surface has changed to use Promises in 1.x.)
npm WARN deprecated uuid@3.4.0: Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.
npm WARN deprecated circular-json@0.3.3: CircularJSON is in maintenance only, flatted is its successor.

> protobufjs@6.11.3 postinstall /home/lj/fabric/scripts/fabric-samples/chaincode/fabcar/javascript/node_modules/protobufjs
> node scripts/postinstall

npm notice created a lockfile as package-lock.json. You should commit this file.
npm WARN notsup Unsupported engine for fabric-contract-api@2.2.3: wanted: {"node":"^12.16.1","npm":"^6.4.1"} (current: {"node":"14.4.0","npm":"6.14.5"})
npm WARN notsup Not compatible with your version of node/npm: fabric-contract-api@2.2.3
npm WARN notsup Unsupported engine for fabric-shim@2.2.3: wanted: {"node":"^12.16.1","npm":"^6.4.1"} (current: {"node":"14.4.0","npm":"6.14.5"})
npm WARN notsup Not compatible with your version of node/npm: fabric-shim@2.2.3
npm WARN notsup Unsupported engine for fabric-shim-api@2.2.3: wanted: {"node":"^12.16.1","npm":"^6.4.1","eslint":"6.6.0"} (current: {"node":"14.4.0","npm":"6.14.5"})
npm WARN notsup Not compatible with your version of node/npm: fabric-shim-api@2.2.3
npm WARN ajv-keywords@2.1.1 requires a peer of ajv@^5.0.0 but none is installed. You must install peer dependencies yourself.
npm WARN fabcar@1.0.0 No repository field.

added 382 packages from 1052 contributors and audited 382 packages in 100.636s

10 packages are looking for funding
run `npm fund` for details

found 4 vulnerabilities (3 moderate, 1 critical)
run `npm audit fix` to fix them, or `npm audit` for details

CentOS7部署fabric_linux_06

执行test-network目录下如下命令来打包链码。并且设置peer CLI的环境变量,以防已经关闭了CLI终端。

export PATH=${PWD}/../bin:$PATH

export FABRIC_CFG_PATH=$PWD/../config/

export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp

peer lifecycle chaincode package fabcar_2.tar.gz --path ../chaincode/fabcar/javascript/ --lang node --label fabcar_2

设置环境变量使用Org1 Admin身份运行peer CLI

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

接下来在Org1的peer上安装新的链码

peer lifecycle chaincode install fabcar_2.tar.gz

新安装的链码会有新的packageID,使用如下命令查询pacage ID

peer lifecycle chaincode queryinstalled
[lj@localhost test-network]$ peer lifecycle chaincode queryinstalled
Installed chaincodes on peer:
Package ID: fabcar_1:1146b4b491871bf18b23dd67dd8cc058655b36cc0e2274f165ed06b796a8f276, Label: fabcar_1
Package ID: fabcar_2:42f98fe23534452f034acd1f9ccea876a3dbf92819bf19d0469aa891535a9d81, Label: fabcar_2

保存新的packageID到环境变量

export NEW_CC_PACKAGE_ID=fabcar_2:42f98fe23534452f034acd1f9ccea876a3dbf92819bf19d0469aa891535a9d81

接下来Org1投票链码的定义。

peer lifecycle chaincode approveformyorg -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --channelID mychannel --name fabcar --version 2.0 --package-id $NEW_CC_PACKAGE_ID --sequence 2 --tls --cafile ${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem

新的链码定义使用JS版链码的packageID并且升级了链码的版本。因为sequence参数是用来追踪量升级的,所以Org1需要将值从1变到2。如果忘记上个版本的sequence值,可以使用peer lifecycle chaincode querycommitted查询。

现在操作Org2

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_2.tar.gz

peer lifecycle chaincode approveformyorg -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --channelID mychannel --name fabcar --version 2.0 --package-id $NEW_CC_PACKAGE_ID --sequence 2 --tls --cafile ${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem

CentOS7部署fabric_docker_07

查询是否达成一致,可以提交到channel中了

peer lifecycle chaincode checkcommitreadiness --channelID mychannel --name fabcar --version 2.0 --sequence 2 --tls --cafile ${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem --output json

当新的链码定义通过之后,就可以在channel中升级链码了。直到现在,之前版本的链码还在各组织上运行。Org2使用如下命令执行channel中链码升级。

peer lifecycle chaincode commit -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --channelID mychannel --name fabcar --version 2.0 --sequence 2 --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

CentOS7部署fabric_linux_08

一个新的交易提交到Fabric后会立即使用新版链码。如果过新的链码定义改变了背书策略,新的策略也会立即生效。

可以使用docker ps命令来验证新的链码已经在peer上启动

docker ps
[lj@localhost test-network]$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
672e6c91bd92 dev-peer0.org1.example.com-fabcar_2-42f98fe23534452f034acd1f9ccea876a3dbf92819bf19d0469aa891535a9d81-884eb00aa405a427116c213996f06009de4556a153310888f502ea332e59da69 "docker-entrypoint.s…" 28 seconds ago Up 27 seconds dev-peer0.org1.example.com-fabcar_2-42f98fe23534452f034acd1f9ccea876a3dbf92819bf19d0469aa891535a9d81
2b521755a9b1 dev-peer0.org2.example.com-fabcar_2-42f98fe23534452f034acd1f9ccea876a3dbf92819bf19d0469aa891535a9d81-9f01fcf52f73cc60a8545d2637e669dcb6a931dff54ebcd6af0a54c0c46835a4 "docker-entrypoint.s…" 28 seconds ago Up 27 seconds dev-peer0.org2.example.com-fabcar_2-42f98fe23534452f034acd1f9ccea876a3dbf92819bf19d0469aa891535a9d81
79de8b7f689f hyperledger/fabric-tools:latest "/bin/bash" About an hour ago Up About an hour cli
ecf944e84c01 hyperledger/fabric-peer:latest "peer node start" About an hour ago Up About an hour 0.0.0.0:7051->7051/tcp, :::7051->7051/tcp, 0.0.0.0:9444->9444/tcp, :::9444->9444/tcp peer0.org1.example.com
5b0151c73077 hyperledger/fabric-peer:latest "peer node start" About an hour ago Up About an hour 0.0.0.0:9051->9051/tcp, :::9051->9051/tcp, 7051/tcp, 0.0.0.0:9445->9445/tcp, :::9445->9445/tcp peer0.org2.example.com
cc47d3dc26b4 hyperledger/fabric-orderer:latest "orderer" About an hour ago Up About an hour 0.0.0.0:7050->7050/tcp, :::7050->7050/tcp, 0.0.0.0:7053->7053/tcp, :::7053->7053/tcp, 0.0.0.0:9443->9443/tcp, :::9443->9443/tcp orderer.example.com
[lj@localhost test-network]$

CentOS7部署fabric_容器_09

如果使用了–init-required参数,你需要首先调用Init函数。这里因为不用执行Init,我们可以直接测试新链码。

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":"createCar","Args":["CAR11","Honda","Accord","Black","Tom"]}'
[lj@localhost test-network]$ 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":"createCar","Args":["CAR11","Honda","Accord","Black","Tom"]}'
2022-06-03 23:31:09.211 CST [chaincodeCmd] chaincodeInvokeOrQuery -> INFO 001 Chaincode invoke successful. result: status:200

可以再查一下数据,看有没有新数据。

peer chaincode query -C mychannel -n fabcar -c '{"Args":["queryAllCars"]}'

复原环境

当调用完毕链码,你可以使用下面的命令来删除Logspout tool。

docker stop logspout

docker rm logspout

#停止测试网络

./network.sh down

CentOS7部署fabric_docker_10

四、使用SDK与fabric网络交互

跑之前先清一下docker网络环境

docker stop $(docker ps -aq)

docker rm $(docker ps -qa)

启动fabric

cd  ../fabcar

./startFabric.sh

交互

cd javascript

#注册管理员用户

node enrollAdmin.js

#注册普通用户:user1 - 将是我们在查询和更新账本时使用的身份

node registerUser.js

#执行交易

node invoke.js

#查询交易:

node query.js

#停止网络:

./networkDown.sh
[lj@localhost javascript]$ node enrollAdmin.js
Wallet path: /home/lj/fabric/scripts/fabric-samples/fabcar/javascript/wallet
Successfully enrolled admin user "admin" and imported it into the wallet
[lj@localhost javascript]$ node registerUser.js
Wallet path: /home/lj/fabric/scripts/fabric-samples/fabcar/javascript/wallet
Successfully registered and enrolled admin user "appUser" and imported it into the wallet
[lj@localhost javascript]$ node invoke.js
Wallet path: /home/lj/fabric/scripts/fabric-samples/fabcar/javascript/wallet
Transaction has been submitted
[lj@localhost javascript]$ node query.js

Wallet path: /home/lj/fabric/scripts/fabric-samples/fabcar/javascript/wallet
Transaction has been evaluated, result is: [{"Key":"CAR0","Record":{"make":"Toyota","model":"Prius","colour":"blue","owner":"Tomoko"}},{"Key":"CAR1","Record":{"make":"Ford","model":"Mustang","colour":"red","owner":"Brad"}},{"Key":"CAR12","Record":{"make":"Honda","model":"Accord","colour":"Black","owner":"Tom"}},{"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"}}]
[lj@localhost javascript]$ cd ..
[lj@localhost fabcar]$ ./networkDown.sh
+ pushd ../test-network
~/fabric/scripts/fabric-samples/test-network ~/fabric/scripts/fabric-samples/fabcar
+ ./network.sh down
Using docker and docker-compose
Stopping network
Stopping cli ... done
Stopping peer0.org2.example.com ... done
Stopping peer0.org1.example.com ... done
Stopping couchdb1 ... done
Stopping couchdb0 ... done
Stopping orderer.example.com ... done
Stopping ca_orderer ... done
Stopping ca_org1 ... done
Stopping ca_org2 ... done
Removing cli ... done
Removing peer0.org2.example.com ... done
Removing peer0.org1.example.com ... done
Removing couchdb1 ... done
Removing couchdb0 ... done
Removing orderer.example.com ... done
Removing ca_orderer ... done
Removing ca_org1 ... done
Removing ca_org2 ... done
Removing network compose_default
WARNING: Network compose_default not found.
Removing network fabric_test
Removing volume compose_orderer.example.com
Removing volume compose_peer0.org1.example.com
Removing volume compose_peer0.org2.example.com
Removing volume compose_peer0.org3.example.com
WARNING: Volume compose_peer0.org3.example.com not found.
Error: No such volume: docker_orderer.example.com
Error: No such volume: docker_peer0.org1.example.com
Error: No such volume: docker_peer0.org2.example.com
Removing remaining containers
Removing generated chaincode docker images
Untagged: dev-peer0.org2.example.com-fabcar_1-1146b4b491871bf18b23dd67dd8cc058655b36cc0e2274f165ed06b796a8f276-a4cab14b5de537f62499c097120e5c3cfdbf203a973d378e7c07724e21e5c507:latest
Deleted: sha256:bcf19ff9716231f2ca87992a0349838d3cce62b2851eaa23593d74961835169a
Deleted: sha256:199c9cfa1ee3ea50d8e48376b443b1ac868e8f8f7cc4ff7ed72fa4a79d613c24
Deleted: sha256:cbd45baa2790925094ea4313e1436e8f978d5fbf02455eec05ea3d5deffa9eed
Deleted: sha256:25cc5480224ca5fc74771bbfb65424fb9d0494dd881ebf4af77b4de385d2d363
Untagged: dev-peer0.org1.example.com-fabcar_1-1146b4b491871bf18b23dd67dd8cc058655b36cc0e2274f165ed06b796a8f276-307a9f515c3848393541e112fc5aba7c1ab4dfb679dd01daef81437e31b44c66:latest
Deleted: sha256:8f5efd83f7aa476f2f47640d0c9e70d0077ecd5f2581f4d2781491227f9b3ffc
Deleted: sha256:4f5a3e8d142da56efb3e31f04ac8fdbc5ec03f5fc67ec2175d8c965e9f966e90
Deleted: sha256:deda8812b38057e4014f3a9eb489896249c360d512fcc2392f7840921b378707
Deleted: sha256:80d2ae843bf4e62183245de8872db58f9187328d758a303af479edd36407cdef
"docker kill" requires at least 1 argument.
See 'docker kill --help'.

Usage: docker kill [OPTIONS] CONTAINER [CONTAINER...]

Kill one or more running containers
+ popd
~/fabric/scripts/fabric-samples/fabcar
+ rm -rf javascript/wallet/admin.id javascript/wallet/appUser.id
+ rm -rf 'java/wallet/*'
+ rm -rf 'typescript/wallet/*'

CentOS7部署fabric_centos_11

五、参考文档

官方文档:https://hyperledger-fabric.readthedocs.io/en/latest/getting_started.html