最近在研究一些HyperLedger Fabric平台的相关内容,需要搭建出一个Fabric的运行环境进行测试,在此对搭建的过程进行一个记录与分享,如有不够完善或者做得不对的地方欢迎评论区留言讨论。目前的搭建计划是将利用Go版本的Fabric SDK,从最简单的单Orderer单通道单组织逐步扩充,最终实现多Orderer多通道多组织的Fabric网络环境。

基础环境

1. 安装Docker和Docker Compose

安装Docker

如果原先系统中存在docker,需要先进行卸载

1
sudo apt-get remove docker docker-engine docker.io

卸载完成后再进行安装,在测试或开发环境中 Docker 官方为了简化安装流程,提供了一套便捷的安装脚本,Ubuntu 系统上可以使用这套脚本安装,另外可以通过 --mirror 选项使用国内源进行安装:

若安装测试版的 Docker, 脚本url为 test.docker.com

1
2
curl -fsSL get.docker.com -o get-docker.sh
sudo sh get-docker.sh --mirror Aliyun

启动docker:

1
2
sudo systemctl enable docker
sudo systemctl start docker

允许非root用户使用docker需要将使用docker的用户添加到docker用户组:

建立docker组:

1
sudo groupadd docker

将当前用户加入docker组:

1
sudo usermod -aG docker $USER

重启Ubuntu系统后生效

安装Docker Compose

官方 GitHub Release 处直接下载编译好的二进制文件

1
2
3
4
5
6
sudo curl -L https://github.com/docker/compose/releases/download/v2.7.0/docker-compose-`uname -s`-`uname -m` > /usr/local/bin/docker-compose

# 国内用户可以使用以下方式加快下载
$ sudo curl -L https://download.fastgit.org/docker/compose/releases/download/v2.7.0/docker-compose-`uname -s`-`uname -m` > /usr/local/bin/docker-compose

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

测试

使用命令输出版本信息,能正常输出则说明安装成功

1
2
docker version
docker-compose version

2. 安装Go语言环境

下载Go软件包并解压到/usr/local目录,下载前请访问Go官方下载页面 并检查是否有可用的新版本:

1
wget -c https://go.dev/dl/go1.18.4.linux-amd64.tar.gz -O - | sudo tar -xz -C /usr/local

通过将 Go 目录的位置添加到$PATH环境变量中:

1
2
3
4
5
6
7
vim ~/.profile

#在打开的文件中附加下行
export PATH=$PATH:/usr/local/go/bin

#文件保存后应用更改
source ~/.profile

验证安装:

1
go version

Fabric源码、Docker以及样例安装

文件下载

添加工作目录:

1
2
mkdir -p $HOME/go/src
cd $HOME/go/src

获取安装脚本:

1
curl -sSLO https://raw.githubusercontent.com/hyperledger/fabric/main/scripts/install-fabric.sh && chmod +x install-fabric.sh

指定要下载的组件,需要在执行脚本时添加以下一个或多个参数。每个参数都可以缩短为它的第一个字母。

  • docker使用 Docker 下载 Fabric 容器镜像
  • podman使用 podman 下载 Fabric Container Images
  • binary下载 Fabric 二进制文件
  • samples将 fabric-samples github repo 克隆到当前目录

拉取最新版本的 Docker 容器并克隆示例存储库和二进制文件:

1
./install-fabric.sh d s b

使用Fabric测试网络

进入到测试网络目录:

1
cd fabric-samples/test-network

启动和停止测试网络:

1
2
./network.sh up
./network.sh down

测试过程出现报错的话需要修改host文件对example.com域名进行地址映射,在/etc/hosts文件中添加以下条目:

1
2
3
4
5
6
7
8
9
10
127.0.0.1       orderer.example.com
127.0.0.1 ca.org1.example.com
127.0.0.1 ca.org2.example.com
127.0.0.1 ca.org3.example.com
127.0.0.1 peer0.org1.example.com
127.0.0.1 peer0.org2.example.com
127.0.0.1 peer0.org3.example.com
127.0.0.1 peer1.org1.example.com
127.0.0.1 peer1.org2.example.com
127.0.0.1 peer1.org3.example.com

fabric-go-sdk(1 orderer, 1 org, 2 peers)

跟着sxguan的搭建过程创建Fabric环境的话会出现很多问题,于是直接使用大佬在github上的项目进行修改

修改配置文件

使用如下命令将项目文件拉到本地$GOPATH/src目录中

1
git clone https://github.com/sxguan/fabric-go-sdk.git

下载完后需要对config.yamlmain.go中的路径配置进行修改(改到自己实际的项目路径)

将这两个文件中的/root/go/src全局替换为/home/baymrx/go/src,保存

至此运行环境就没什么问题了

运行项目

在项目根目录$GOPATH/src/fabric-go-sdk启动Docker:

1
cd fixtures && docker-compose up -d && cd ..

如果前面使用Fabric脚本完整安装过Docker环境,建议将fixtures/docker-compose.yaml文件中的镜像版本设置为latest,避免镜像的重复拉取

比如,将下面的镜像配置

1
2
3
image: hyperledger/fabric-orderer:2.2
image: hyperledger/fabric-peer:2.2
image: hyperledger/fabric-ca:1.4.9

分别替换为

1
2
3
image: hyperledger/fabric-orderer:latest
image: hyperledger/fabric-peer:latest
image: hyperledger/fabric-ca:latest

使用go build命令编译项目文件,运行完成后会在项目根目录中生成fabric-go-sdk文件

./fabric-go-sdk执行文件就可以将代码顺利跑到最后

运行结束后使用下面的命令结束并清理Docker环境

cd fixtures && docker-compose down && docker volume prune && cd …

cd fixtures && docker-compose down -v && cd ..

fabric-go-sdk(1 orderer, 2 orgs, 2 peers)

2个组织的fabric网络的搭建,在之前1个组织的项目中对相关配置文件照葫芦画瓢即可,部分过程会参考sxguan的搭建过程

配置文件中相关端口分配情况:

Peer0.Org1:70xx

Peer1.Org1:80xx

Peer0.Org2:90xx

Peer1.Org2:100xx

修改configtx.yaml

这个文件包含了整个Fabric网络的定义,定义了网络组件的拓扑结构和每个网络实体加密证书的存储位置,一般用来配置系统通道初试区块文件、应用通道配置文件、锚节点配置文件等

1、在Organization条目下复制一份Org1的配置,并将其中的org1替换为org2

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
- &Org2
# DefaultOrg defines the organization which is used in the sampleconfig
# of the fabric.git development environment
Name: Org2MSP

# ID to load the MSP definition as
ID: Org2MSP

MSPDir: crypto-config/peerOrganizations/org2.example.com/msp

# Policies defines the set of policies at this level of the config tree
# For organization policies, their canonical path is usually
# /Channel/<Application|Orderer>/<OrgName>/<PolicyName>
Policies:
Readers:
Type: Signature
Rule: "OR('Org2MSP.member')"
Writers:
Type: Signature
Rule: "OR('Org2MSP.member')"
Admins:
Type: Signature
Rule: "OR('Org2MSP.admin')"
Endorsement:
Type: Signature
Rule: "OR('Org2MSP.member')"

# leave this flag set to true.
AnchorPeers:
# AnchorPeers defines the location of peers which can be used
# for cross org gossip communication. Note, this value is only
# encoded in the genesis block in the Application section context
- Host: peer0.org2.example.com
Port: 9051

2、在Application下的Organization中添加Org2

1
2
3
4
5
6
7
Application: &ApplicationDefaults

# Organizations is the list of orgs which are defined as participants on
# the application side of the network
Organizations:
- *Org1
- *Org2

3、在Profiles条目中相对应位置添加Org2

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
Profiles:
TwoOrgsOrdererGenesis:
<<: *ChannelDefaults
Orderer:
<<: *OrdererDefaults
Organizations:
- *OrdererOrg
Capabilities:
<<: *OrdererCapabilities
Consortiums:
SampleConsortium:
Organizations:
- *Org1
- *Org2

TwoOrgsChannel:
Consortium: SampleConsortium
<<: *ChannelDefaults
Application:
<<: *ApplicationDefaults
Organizations:
- *Org1
- *Org2
Capabilities:
<<: *ApplicationCapabilities

修改crypto-config.yaml

crypto-config.yaml是MSP和TLS相关文件的依赖配置文件

在PeerOrgs中复制一份并更改为Org2

1
2
3
4
5
6
7
- Name: Org2
Domain: org2.example.com
EnableNodeOUs: true
Template:
Count: 2
Users:
Count: 1

修改docker-compose.yaml

1、volumes中添加Org2 的peer节点

1
2
peer0.org2.example.com:
peer1.org2.example.com:

2、services中添加Org2的peer节点和ca节点

根据端口分配情况首先将Org1中的90xx端口改为80xx,为方便后续管理,将所有节点environment参数中变量的端口全部改为70xx,最后在ports再进行映射(在同一主机的Docker环境下这样后面会报错)

直接复制Org1节点的配置并将Org1替换为Org2(替换时注意区分大小写),然后修改对应端口即可

3、在services中为Org2添加两个couchDB数据库

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
couchdb2:
container_name: couchdb2
image: hyperledger/fabric-couchdb:latest
# Populate the COUCHDB_USER and COUCHDB_PASSWORD to set an admin user and password
# for CouchDB. This will prevent CouchDB from operating in an "Admin Party" mode.
environment:
- COUCHDB_USER=admin
- COUCHDB_PASSWORD=123456
# Comment/Uncomment the port mapping if you want to hide/expose the CouchDB service,
# for example map it to utilize Fauxton User Interface in dev environments.
ports:
- "9984:5984"
networks:
- test

couchdb3:
container_name: couchdb3
image: hyperledger/fabric-couchdb:latest
# Populate the COUCHDB_USER and COUCHDB_PASSWORD to set an admin user and password
# for CouchDB. This will prevent CouchDB from operating in an "Admin Party" mode.
environment:
- COUCHDB_USER=admin
- COUCHDB_PASSWORD=123456
# Comment/Uncomment the port mapping if you want to hide/expose the CouchDB service,
# for example map it to utilize Fauxton User Interface in dev environments.
ports:
- "10984:5984"
networks:
- test

附上整个docker-compose.yaml文件

链接

重新生成证书文件和通道文件

为避免后续调试的重复操作,将生成证书和通道文件的命令全部放到一个shell脚本中(vim create.sh):

执行下面的命令需要fabric-samples文件夹与fabric-go-sdk项目文件夹在同一父目录下,并且当前目录为fixtures

1
2
3
4
5
6
rm -rf crypto-config channel-artifacts && mkdir crypto-config
../../fabric-samples/bin/cryptogen generate --config=crypto-config.yaml
../../fabric-samples/bin/configtxgen -profile TwoOrgsOrdererGenesis -outputBlock ./channel-artifacts/genesis.block -channelID fabric-channel
../../fabric-samples/bin/configtxgen -profile TwoOrgsChannel -outputCreateChannelTx ./channel-artifacts/channel.tx -channelID mychannel
../../fabric-samples/bin/configtxgen -profile TwoOrgsChannel -outputAnchorPeersUpdate ./channel-artifacts/Org1MSPanchors.tx -channelID mychannel -asOrg Org1MSP
../../fabric-samples/bin/configtxgen -profile TwoOrgsChannel -outputAnchorPeersUpdate ./channel-artifacts/Org2MSPanchors.tx -channelID mychannel -asOrg Org2MSP

执行脚本./create.sh重新生成证书和通道文件,回显中没有报错信息则说明生成成功

修改config.yaml

1、在channels-mychannel-peers中添加org2

1
2
3
4
5
6
7
8
9
10
11
peer0.org2.example.com:
endorsingPeer: true
chaincodeQuery: true
ledgerQuery: true
eventSource: true

peer1.org2.example.com:
endorsingPeer: true
chaincodeQuery: true
ledgerQuery: true
eventSource: true

2、在organizations中添加org2

1
2
3
4
5
6
7
8
9
org2:
mspid: Org2MSP

# This org's MSP store (absolute path or relative to client.cryptoconfig)
cryptoPath: peerOrganizations/org2.example.com/users/{username}@org2.example.com/msp

peers:
- peer0.org2.example.com
- peer1.org2.example.com

3、在peers中添加org2

注意修改peer1.org1的端口为8051

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
peer0.org2.example.com:
# this URL is used to send endorsement and query requests
# [Optional] Default: Infer from hostname
url: peer0.org2.example.com:9051
grpcOptions:
ssl-target-name-override: peer0.org2.example.com
# These parameters should be set in coordination with the keepalive policy on the server,
# as incompatible settings can result in closing of connection.
# When duration of the 'keep-alive-time' is set to 0 or less the keep alive client parameters are disabled
keep-alive-time: 0s
keep-alive-timeout: 20s
keep-alive-permit: false
fail-fast: false
# allow-insecure will be taken into consideration if address has no protocol defined, if true then grpc or else grpcs
allow-insecure: false
#grpcOptions:
# ssl-target-name-override: peer0.org2.example.com

tlsCACerts:
# Certificate location absolute path
path: /home/baymrx/go/src/fabric-go-sdk/fixtures/crypto-config/peerOrganizations/org2.example.com/tlsca/tlsca.org2.example.com-cert.pem


peer1.org2.example.com:
url: peer1.org2.example.com:10051
#grpcOptions:
# ssl-target-name-override: peer0.org2.example.com
grpcOptions:
ssl-target-name-override: peer1.org2.example.com
# These parameters should be set in coordination with the keepalive policy on the server,
# as incompatible settings can result in closing of connection.
# When duration of the 'keep-alive-time' is set to 0 or less the keep alive client parameters are disabled
keep-alive-time: 0s
keep-alive-timeout: 20s
keep-alive-permit: false
fail-fast: false
# allow-insecure will be taken into consideration if address has no protocol defined, if true then grpc or else grpcs
allow-insecure: false
tlsCACerts:
path: /home/baymrx/go/src/fabric-go-sdk/fixtures/crypto-config/peerOrganizations/org2.example.com/tlsca/tlsca.org2.example.com-cert.pem

4、在entityMatchers-peer中添加org2

1
2
3
4
- pattern: (\w+).org2.example.com:(\d+)
urlSubstitutionExp: ${1}.org2.example.com:${2}
sslTargetOverrideUrlSubstitutionExp: ${1}.org2.example.com
mappedHost: peer0.org2.example.com

修改main.go

在main()的orgs变量中添加Org2

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
orgs := []*sdkInit.OrgInfo{
{
OrgAdminUser: "Admin",
OrgName: "Org1",
OrgMspId: "Org1MSP",
OrgUser: "User1",
OrgPeerNum: 2,
OrgAnchorFile: "/home/baymrx/go/src/fabric-go-sdk/fixtures/channel-artifacts/Org1MSPanchors.tx",
},
{
OrgAdminUser: "Admin",
OrgName: "Org2",
OrgMspId: "Org2MSP",
OrgUser: "User1",
OrgPeerNum: 2,
OrgAnchorFile: "/home/baymrx/go/src/fabric-go-sdk/fixtures/channel-artifacts/Org2MSPanchors.tx",
},
}

启动Docker并运行代码

1
2
3
cd fixtures && docker-compose up -d && cd ..
go build
./fabric-go-sdk

报错了o(╯□╰)o

>> 加入通道…
>> Create channel and join error: Org1 peers failed to JoinChannel: join channel failed: Multiple errors occurred: - SendProposal failed: Transaction processing for endorser [peer1.org1.example.com:8051]: Endorser Client Status Code: (2) CONNECTION_FAILED. Description: dialing connection on target [peer1.org1.example.com:8051]: connection is in TRANSIENT_FAILURE - SendProposal failed: Transaction processing for endorser [peer0.org1.example.com:7051]: Endorser Client Status Code: (2) CONNECTION_FAILED. Description: dialing connection on target [peer0.org1.example.com:7051]: connection is in TRANSIENT_FAILURE

执行docker ps -a查看容器的运行状态,其中所有的peer节点状态都为Exited (2)

那么找到其中一个peer节点容器的ID(我这里找的是peer0.org1.example.com,对应ID为39c5829f2a4f),查看其日志docker logs 39c

日志中显示couchDB报错:

2022-08-01 06:27:51.842 UTC 0046 DEBU [couchdb] verifyCouchConfig -> Exiting VerifyCouchConfig()
panic: Error in instantiating ledger provider: Get “http://couchdb0:7984/”: dial tcp 172.21.0.2:7984: connect: connection refused
http error calling couchdb

根据报错信息发现原因是找不到couchdb0:7984这个地址,一番检索后发现是因为我之前在修改docker-compose.yaml时,将CORE_LEDGER_STATE_COUCHDBCONFIG_COUCHDBADDRESS所对应的端口都改为了couchDB容器的外部端口,而这种方式搭建的Docker环境由于networks参数的存在,会将所有的容器都放到同一个网络中,访问时使用容器名即可。所以这里的解决方法是将所有的CORE_LEDGER_STATE_COUCHDBCONFIG_COUCHDBADDRESS的端口都改为5984

那么调整完成之后,重启环境再来运行一遍

Oops!又报错了,这次换了个报错信息

>> 组织认可智能合约定义…
>>> chaincode approved by Org1 peers:
peer0.org1.example.com:7051
peer1.org1.example.com:8051
>>> chaincode approved by Org2 peers:
peer0.org2.example.com:9051
peer1.org2.example.com:10051
[fabsdk/fab] 2022/08/01 07:22:35 UTC - dispatcher.(*Dispatcher).HandleConnectEvent -> WARN error creating connection: could not connect to peer1.org2.example.com:7051: dialing connection on target [peer1.org2.example.com:7051]: connection is in TRANSIENT_FAILURE

>> create chaincode lifecycle error: %v queryApprovedCC error: Org Org2 Peer peer0.org2.example.com:9051 NewInvoker error: Test status Code: (12) UNKNOWN. Description: LifecycleQueryApprovedCC returned error: querying for installed chaincode failed: Transaction processing for endorser [peer0.org2.example.com:9051]: Chaincode status Code: (500) UNKNOWN. Description: failed to invoke backing implementation of ‘QueryApprovedChaincodeDefinition’: could not fetch approved chaincode definition (name: ‘simplecc’, sequence: ‘1’) on channel ‘mychannel’

从报错信息来看是由于连不上peer节点造成的,由于之前将所有节点environment参数中变量的端口全部改为70xx,只在端口参数处进行映射,参考上一个报错,一部分网络连接走Docker内网络一部分走Docker外网络,造成端口不一致。**修改方案:**修改docker-compose.yaml文件,将environment参数下的所有端口都改为对应节点所分配的端口(而不是统一的70xx)

修改完后,再次重启环境运行fabric-go-sdk,这次可以完美运行~

总结一下,遇到类似上面两种报错信息,多检查一下docker-compose.yaml这类配置文件是否正确,特别是端口号、组织号这些

fabric-go-sdk(1 orderer, 3 orgs, 2 peers)

修改配置文件

与上个章节2个组织的配置修改过程基本相同,其他不同的地方单独记录

1、configtx.yaml中的Application-Policies的LifecycleEndorsement和Endorsement需要将Org3添加进去

1
2
3
4
5
6
LifecycleEndorsement:
Type: Signature
Rule: "OR('Org1MSP.member','Org2MSP.member','Org3MSP.member')"
Endorsement:
Type: Signature
Rule: "OR('Org1MSP.member','Org2MSP.member','Org3MSP.member')"

2、create.sh中追加一行Org3的命令

1
../../fabric-samples/bin/configtxgen -profile TwoOrgsChannel -outputAnchorPeersUpdate ./channel-artifacts/Org3MSPanchors.tx -channelID mychannel -asOrg Org3MSP

这里的TwoOrgsChannel是否修改为Three并不重要,只要它与configtx.yaml中Profiles指定的参数相对应即可

运行Fabric

1
2
3
cd fixtures && docker-compose up -d && cd ..
go build
./fabric-go-sdk

代码可以正常跑完,没有问题

Fabcar on fabric-go-sdk(1 orderer, 3 orgs, 2 peers)

组织和peer节点的创建都没有问题的话,换个链码再试一下,这里使用Fabric官方提供的Fabcar链码

chaincode更改

fabric-samples/chaincode/fabcar/go/目录下的所有文件拷贝到项目目录下的chaincode文件夹中,并清除文件夹中之前的所有文件

1
rm -rf ./chaincode/* && cp ../fabric-samples/chaincode/fabcar/go/* ./chaincode

在chaincode文件夹中生成链码的依赖文件

1
cd chaincode && go mod vendor

由于链码的初始化需要从Init()函数方法开始,但直接拷贝过来的fabcar.go中没有这一方法,这里曲线救国,直接将链码中的InitLedger()方法改为Init()

如果链码中没有Init方法,可能发生如下错误:

>> 调用智能合约初始化方法…
>> create chaincode lifecycle error: %v initCC error: Failed to init: Multiple errors occurred: - Transaction processing for endorser [peer0.org3.example.com:11051]: Chaincode status Code: (500) UNKNOWN. Description: error in simulation: transaction returned with failure: Function init not found in contract SmartContract - Transaction processing for endorser [peer0.org2.example.com:9051]: Chaincode status Code: (500) UNKNOWN. Description: error in simulation: transaction returned with failure: Function init not found in contract SmartContract - Transaction processing for endorser [peer1.org1.example.com:8051]: Chaincode status Code: (500) UNKNOWN. Description: error in simulation: transaction returned with failure: Function init not found in contract SmartContract

main.go更改

修改后的文件可在此下载

找到文件fabric-samples/fabcar/go/fabcar.go,将此文件内容与原先项目中的main.go进行合并,在原文件设置链码状态完成之后,将fabcar.go中的功能性代码添加进去,并修改文件依赖,除此之外,链码的名称也要进行修改

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import (
"fabric-go-sdk/sdkInit"
"fmt"
"os"
"errors"
"io/ioutil"
"path/filepath"

"github.com/hyperledger/fabric-sdk-go/pkg/core/config"
"github.com/hyperledger/fabric-sdk-go/pkg/gateway"
)

const (
cc_name = "fabcar"
cc_version = "1.0.0"
)

其中还有三个路径变量ccpPathcredPathcertPath需要修改,否则可能会报如下错误:

Failed to populate wallet contents: open …/…/test-network/organizations/peerOrganizations/org1.example.com/users/User1@org1.example.com/msp/signcerts/cert.pem: no such file or directory

三个路径变量的内容分别为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
ccpPath := filepath.Join(
"fixtures",
"crypto-config",
"peerOrganizations",
"org1.example.com",
"connection-org1.yaml",
)
#下面两个变量在populateWallet函数中
credPath := filepath.Join(
"fixtures",
"crypto-config",
"peerOrganizations",
"org1.example.com",
"users",
"User1@org1.example.com",
"msp",
)

certPath := filepath.Join(credPath, "signcerts", "User1@org1.example.com-cert.pem")

ccpPath中的connection-org1.yaml在之前的配置操作中并没有生成,需要使用脚本手动添加

添加过程如下:

1、将ccp模板文件拷贝到项目目录中

1
cp ../fabric-samples/test-network/organizations/ccp-template.yaml ./fixtures

2、将ccp脚本文件拷贝到项目目录中(或者直接进入第3步创建ccp-generate.sh文件并授予可执行权限)

1
cp ../fabric-samples/test-network/organizations/ccp-generate.sh ./fixtures

3、修改脚本文件,文件内容如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#!/bin/bash

function one_line_pem {
echo "`awk 'NF {sub(/\\n/, ""); printf "%s\\\\\\\n",$0;}' $1`"
}

function yaml_ccp {
local PP=$(one_line_pem $4)
local CP=$(one_line_pem $5)
sed -e "s/\${ORG}/$1/" \
-e "s/\${P0PORT}/$2/" \
-e "s/\${CAPORT}/$3/" \
-e "s#\${PEERPEM}#$PP#" \
-e "s#\${CAPEM}#$CP#" \
./ccp-template.yaml | sed -e $'s/\\\\n/\\\n /g'
}

ORG=1
P0PORT=7051
CAPORT=7054
PEERPEM=crypto-config/peerOrganizations/org1.example.com/tlsca/tlsca.org1.example.com-cert.pem
CAPEM=crypto-config/peerOrganizations/org1.example.com/ca/ca.org1.example.com-cert.pem

echo "$(yaml_ccp $ORG $P0PORT $CAPORT $PEERPEM $CAPEM)" > crypto-config/peerOrganizations/org1.example.com/connection-org1.yaml

ORG=2
P0PORT=9051
CAPORT=9054
PEERPEM=crypto-config/peerOrganizations/org2.example.com/tlsca/tlsca.org2.example.com-cert.pem
CAPEM=crypto-config/peerOrganizations/org2.example.com/ca/ca.org2.example.com-cert.pem

echo "$(yaml_ccp $ORG $P0PORT $CAPORT $PEERPEM $CAPEM)" > crypto-config/peerOrganizations/org2.example.com/connection-org2.yaml

ORG=3
P0PORT=11051
CAPORT=11054
PEERPEM=crypto-config/peerOrganizations/org3.example.com/tlsca/tlsca.org3.example.com-cert.pem
CAPEM=crypto-config/peerOrganizations/org3.example.com/ca/ca.org3.example.com-cert.pem

echo "$(yaml_ccp $ORG $P0PORT $CAPORT $PEERPEM $CAPEM)" > crypto-config/peerOrganizations/org3.example.com/connection-org3.yaml

4、进入到fixtures目录执行脚本

1
./ccp-generate.sh

对go文件编译运行

在项目根目录中执行

1
2
3
4
go mod init
go mod tidy
go build
./fabric-go-sdk

在执行go build构建可执行文件时,可能会报错

# github.com/hyperledger/fabric-sdk-go/internal/github.com/hyperledger/fabric/discovery/client
…/…/pkg/mod/github.com/hyperledger/fabric-sdk-go@v1.0.0/internal/github.com/hyperledger/fabric/discovery/client/api.go:47:38: undefined: discovery.ChaincodeCall
…/…/pkg/mod/github.com/hyperledger/fabric-sdk-go@v1.0.0/internal/github.com/hyperledger/fabric/discovery/client/client.go:83:63: undefined: discovery.ChaincodeInterest
…/…/pkg/mod/github.com/hyperledger/fabric-sdk-go@v1.0.0/internal/github.com/hyperledger/fabric/discovery/client/client.go:120:65: undefined: discovery.ChaincodeCall
…/…/pkg/mod/github.com/hyperledger/fabric-sdk-go@v1.0.0/internal/github.com/hyperledger/fabric/discovery/client/client.go:124:23: undefined: discovery.ChaincodeInterest
…/…/pkg/mod/github.com/hyperledger/fabric-sdk-go@v1.0.0/internal/github.com/hyperledger/fabric/discovery/client/client.go:229:105: undefined: discovery.ChaincodeCall
…/…/pkg/mod/github.com/hyperledger/fabric-sdk-go@v1.0.0/internal/github.com/hyperledger/fabric/discovery/client/client.go:247:64: undefined: discovery.ChaincodeCall
…/…/pkg/mod/github.com/hyperledger/fabric-sdk-go@v1.0.0/internal/github.com/hyperledger/fabric/discovery/client/client.go:604:48: undefined: discovery.ChaincodeInterest
…/…/pkg/mod/github.com/hyperledger/fabric-sdk-go@v1.0.0/internal/github.com/hyperledger/fabric/discovery/client/client.go:620:35: undefined: discovery.ChaincodeCall

这种问题是由于依赖fabric-protos-go在最新版本中删掉了ChaincodeCall和ChaincodeInterest,将go.mod中的fabric-protos-go改为较早版本即可解决(我这里使用的是v0.0.0-20210318103044-13fdee960194,改为此版本或更早版本就行)

1
2
3
4
require (
github.com/hyperledger/fabric-protos-go v0.0.0-20210318103044-13fdee960194
github.com/hyperledger/fabric-sdk-go v1.0.0
)

修改完保存后,重新执行

1
2
3
go mod tidy
go build
./fabric-go-sdk

如果在运行的时候报如下错误:

>> 设置链码状态完成
[fabsdk/fab] 2022/08/07 11:53:33 UTC - peer.(*peerEndorser).sendProposal -> ERRO process proposal failed [rpc error: code = Unknown desc = error validating proposal: access denied: channel [mychannel] creator org unknown, creator is malformed]
Failed to get network: Failed to create new channel client: event service creation failed: could not get chConfig cache reference: QueryBlockConfig failed: QueryBlockConfig failed: queryChaincode failed: Transaction processing for endorser [localhost:7051]: gRPC Transport Status Code: (2) Unknown. Description: error validating proposal: access denied: channel [mychannel] creator org unknown, creator is malformed

通常是因为fabcar生成了wallet,在钱包中会使用到证书的公私钥文件,如果有重新生成过crypto-config文件夹,而没有删除根目录生成的walle,则会报此类错误。**解决方案:**删除项目根目录的wallet文件夹后再重新运行程序

如果运行时遇到下面几类报错,比较玄学,暂时不知道原因,多试几次,可能就行了。

[fabsdk/fab] 2022/08/01 12:15:58 UTC - dispatcher.(*Dispatcher).HandleConnectEvent -> WARN error creating connection: could not connect to localhost:8051: dialing connection on target [localhost:8051]: connection is in TRANSIENT_FAILURE
Failed to submit transaction: Failed to submit: error registering for TxStatus event: could not create client conn: could not connect to localhost:8051: dialing connection on target [localhost:8051]: connection is in TRANSIENT_FAILURE

>> 设置链码状态完成
Failed to evaluate transaction: Failed to evaluate: Multiple errors occurred: - Transaction processing for endorser [localhost:7051]: Chaincode status Code: (500) UNKNOWN. Description: error in simulation: failed to execute transaction 3639c35486a66b66c34667fde1e975d4cc07b3cbdc353d1cb7e1f5c7a319a780: invalid invocation: chaincode ‘fabcar’ has not been initialized for this version, must call as init first - Transaction processing for endorser [localhost:9051]: Chaincode status Code: (500) UNKNOWN. Description: error in simulation: failed to execute transaction 3639c35486a66b66c34667fde1e975d4cc07b3cbdc353d1cb7e1f5c7a319a780: invalid invocation: chaincode ‘fabcar’ has not been initialized for this version, must call as init first

Tape性能测试

部署

部署过程参考官方文档,我这里采用克隆仓库本地编译的形式

1
2
git clone https://github.com/Hyperledger-TWGC/tape.git && cd tape && make t
ape

然后需要在tape目录下修改config.yaml文件

  1. 修改证书和私钥文件的路径,将./organizations改为../fixtures/crypto-config,与文件实际路径相对应即可
  2. 添加策略文件policyFile: ./test/andLogic.rego,否则可能会报错empty endorsement policy%
  3. 修改客户端执行参数,这里只保留一个参数,使用- queryAllCars进行测试
  4. 完善peer和orderer节点的配置,完整config样例参考,若报错rpc error: code = Unavailable desc = closing transport due to: connection error: desc = "error reading from server: EOF", received prior goaway: code: ENHANCE_YOUR_CALM, debug data: "too_many_pings"%则需要完善此配置

修改后的config.yaml文件如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
# Definition of nodes
# addr address for node
# tls_ca_cert tls cert
peer1: &peer1
addr: localhost:7051
ssl_target_name_override: peer0.org1.example.com
org: org1
tls_ca_cert: ../fixtures/crypto-config/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/msp/tlscacerts/tlsca.org1.example.com-cert.pem

peer2: &peer2
addr: localhost:9051
ssl_target_name_override: peer0.org2.example.com
org: org2
tls_ca_cert: ../fixtures/crypto-config/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/msp/tlscacerts/tlsca.org2.example.com-cert.pem

orderer1: &orderer1
addr: localhost:7050
ssl_target_name_override: orderer.example.com
org: org1
tls_ca_cert: ../fixtures/crypto-config/ordererOrganizations/example.com/msp/tlscacerts/tlsca.example.com-cert.pem

policyFile: ./test/andLogic.rego
# Peer Nodes to interact with as endorsement Peers
endorsers:
- *peer1
- *peer2

# Peer Nodes to interact with as Commit Peers as listening
committers:
- *peer1
- *peer2
# we might support multi-committer in the future for more complex test scenario.
# i.e. consider tx committed only if it's done on >50% of nodes.
# Give your commit Threshold as numbers for peers here.
commitThreshold: 2

# orderer Nodes to interact with
orderer: *orderer1

# Invocation configs
channel: mychannel
chaincode: fabcar
# chain code args below, in a list of str
# we provides 3 kinds of randmon
# uuid
# randomString$length
# randomNumber$min_$max
args:
- queryAllCars
# Tx submiter information
mspid: Org1MSP
private_key: ../fixtures/crypto-config/peerOrganizations/org1.example.com/users/User1@org1.example.com/msp/keystore/priv_sk
sign_cert: ../fixtures/crypto-config/peerOrganizations/org1.example.com/users/User1@org1.example.com/msp/signcerts/User1@org1.example.com-cert.pem
# network traffic control
num_of_conn: 10
client_per_conn: 10

运行

在tape目录下执行./tape -c config.yaml -n 10000,该命令的含义是,使用 config.yaml 作为配置文件,向 Fabric 网络发送10000条交易进行性能测试