快速带你上手Hyperledger Fabric环境搭建+开发测试
本文采用virtualbox+vagrant方式搭建Hyperledger Fabric环境,采用VSCode远程开发模式开发调试链码和客户端程序。
# 快速带你上手Hyperledger Fabric环境搭建+开发测试 *jasonruan 2020.04.20* # 1 前言 本文采用`virtualbox+vagrant`方式搭建`Hyperledger Fabric`环境,采用`VSCode`远程开发模式开发调试链码和客户端程序。 # 2 环境搭建 ## 2.1 搭建虚拟机环境 ### 2.1.1 生成配置文件 > 使用版本:Ubuntu 18.04 LTS > > 执行以下命令后,将生成`Vagrantfile`配置文件 ```bash $ vagrant init ubuntu/bionic64 ``` ### 2.1.2 指定虚拟机名称 > 修改`Vagrantfile`配置文件,增加如下内容: ```js config.vm.provider "virtualbox" do |v| v.name = "js-fabric" end ``` ### 2.1.3 拉取镜像并启动 > 根据配置文件拉取镜像并创建`Ubuntu18.04`虚拟机 ```bash $ vagrant up ``` > 在`Virtualbox`看到虚拟机已启动 ![image.png](https://img.learnblockchain.cn/attachments/2020/05/IVqNNXss5ebe38047f3af.png) ### 2.1.4 登录虚拟机 ```bash (2020-04-14 12:44:40) [jason@RUAN:~/Vagrant/js-fabric]$ vagrant ssh Welcome to Ubuntu 18.04.4 LTS (GNU/Linux 4.15.0-96-generic x86_64) vagrant@ubuntu-bionic:~$ ``` ## 2.2 安装依赖工具 ### 2.2.1 go ```bash vagrant@ubuntu-bionic:~/Soft$ wget https://dl.google.com/go/go1.14.2.linux-amd64.tar.gz vagrant@ubuntu-bionic:~/Soft$ sudo tar -zxvf go1.14.2.linux-amd64.tar.gz -C /opt vagrant@ubuntu-bionic:~/Soft$ echo "export GOROOT=/opt/go" >> ~/.bashrc vagrant@ubuntu-bionic:~/Soft$ echo "export GOPATH=/opt/gopath" >> ~/.bashrc vagrant@ubuntu-bionic:~/Soft$ echo "export PATH=\$GOROOT/bin:\$GOPATH/bin:\$PATH" >> ~/.bashrc vagrant@ubuntu-bionic:~/Soft$ . ~/.bashrc vagrant@ubuntu-bionic:~/Soft$ go version go version go1.14.2 linux/amd64 ``` ### 2.2.2 docker ```bash vagrant@ubuntu-bionic:~/Soft$ curl -fsSL https://get.docker.com -o get-docker.sh vagrant@ubuntu-bionic:~/Soft$ sudo sh get-docker.sh vagrant@ubuntu-bionic:~/Soft$ sudo usermod -aG docker $USER vagrant@ubuntu-bionic:~/Soft$ sudo systemctl restart docker vagrant@ubuntu-bionic:~$ docker version Client: Docker Engine - Community Version: 19.03.8 API version: 1.40 Go version: go1.12.17 Git commit: afacb8b7f0 Built: Wed Mar 11 01:25:46 2020 OS/Arch: linux/amd64 Experimental: false Server: Docker Engine - Community Engine: Version: 19.03.8 API version: 1.40 (minimum version 1.12) Go version: go1.12.17 Git commit: afacb8b7f0 Built: Wed Mar 11 01:24:19 2020 OS/Arch: linux/amd64 Experimental: false containerd: Version: 1.2.13 GitCommit: 7ad184331fa3e55e52b890ea95e65ba581ae3429 runc: Version: 1.0.0-rc10 GitCommit: dc9208a3303feef5b3839f4323d9beb36df0a9dd docker-init: Version: 0.18.0 GitCommit: fec3683 ``` ### 2.2.3 docker-compose ```bash vagrant@ubuntu-bionic:~$ sudo curl -L "https://github.com/docker/compose/releases/download/1.25.4/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose vagrant@ubuntu-bionic:~$ sudo chmod 755 /usr/local/bin/docker-compose vagrant@ubuntu-bionic:~$ docker-compose --version docker-compose version 1.25.4, build 8d51620a ``` ## 2.3 官方样例部署 > 官方样例:https://github.com/hyperledger/fabric-samples ### 2.3.1 源码及镜像下载 - 下载源码 ```bash vagrant@ubuntu-bionic:~$ mkdir -p $GOPATH/src/github.com/hyperledger vagrant@ubuntu-bionic:~$ cd $GOPATH/src/github.com/hyperledger vagrant@ubuntu-bionic:/opt/gopath/src/github.com/hyperledger$ git clone https://github.com/hyperledger/fabric-samples.git ``` - 切换分支 ```bash [vagrant@RUAN:/opt/gopath/src/github.com/hyperledger/fabric-samples] (master)$ git checkout -b v1.4.6 v1.4.6 Switched to a new branch 'v1.4.6' ``` - 下载引导脚本 ```bash [vagrant@RUAN:/opt/gopath/src/github.com/hyperledger/fabric-samples] (v1.4.6)$ curl -sS https://raw.githubusercontent.com/hyperledger/fabric/master/scripts/bootstrap.sh -o ./scripts/bootstrap.sh [vagrant@RUAN:/opt/gopath/src/github.com/hyperledger/fabric-samples] (v1.4.6)$ chmod +x scripts/bootstrap.sh ``` - 下载必备二进制文件和docker镜像 ```bash # ./scripts/bootstrap.sh [version] [ca version] [thirdparty_version] [vagrant@RUAN:/opt/gopath/src/github.com/hyperledger/fabric-samples] (v1.4.6)$ ./scripts/bootstrap.sh 1.4.6 1.4.6 0.4.18 -s ``` 具体流程: > - 下载Hyperledger Fabric二进制包: > > ``` > ===> Downloading version 1.4.6 platform specific fabric binaries > ===> Downloading: https://github.com/hyperledger/fabric/releases/download/v1.4.6/hyperledger-fabric-linux-amd64-1.4.6.tar.gz > > ===> Downloading version 1.4.6 platform specific fabric-ca-client binary > ===> Downloading: https://github.com/hyperledger/fabric-ca/releases/download/v1.4.6/hyperledger-fabric-ca-linux-amd64-1.4.6.tar.gz > ``` > - 拉取Hyperledger Fabric Docker镜像: > > ``` > Pull Hyperledger Fabric docker images > FABRIC_IMAGES: peer orderer ccenv tools javaenv > ===> Pulling fabric Images > > ====> hyperledger/fabric-peer:1.4.6 > 1.4.6: Pulling from hyperledger/fabric-peer > > ====> hyperledger/fabric-orderer:1.4.6 > 1.4.6: Pulling from hyperledger/fabric-orderer > > ====> hyperledger/fabric-ccenv:1.4.6 > 1.4.6: Pulling from hyperledger/fabric-ccenv > > ====> hyperledger/fabric-tools:1.4.6 > 1.4.6: Pulling from hyperledger/fabric-tools > > ====> hyperledger/fabric-javaenv:1.4.6 > 1.4.6: Pulling from hyperledger/fabric-javaenv > > ====> hyperledger/fabric-ca:1.4.6 > 1.4.6: Pulling from hyperledger/fabric-ca > > ===> Pulling thirdparty docker images > ====> hyperledger/fabric-zookeeper:0.4.18 > 0.4.18: Pulling from hyperledger/fabric-zookeeper > > ====> hyperledger/fabric-kafka:0.4.18 > 0.4.18: Pulling from hyperledger/fabric-kafka > > ====> hyperledger/fabric-couchdb:0.4.18 > 0.4.18: Pulling from hyperledger/fabric-couchdb > > ===> List out hyperledger docker images > hyperledger/fabric-javaenv 1.4 68914607b3a5 6 weeks ago 1.68GB > hyperledger/fabric-javaenv 1.4.6 68914607b3a5 6 weeks ago 1.68GB > hyperledger/fabric-javaenv latest 68914607b3a5 6 weeks ago 1.68GB > hyperledger/fabric-ca 1.4 3b96a893c1e4 7 weeks ago 150MB > hyperledger/fabric-ca 1.4.6 3b96a893c1e4 7 weeks ago 150MB > hyperledger/fabric-ca latest 3b96a893c1e4 7 weeks ago 150MB > hyperledger/fabric-tools 1.4 0f9743ac0662 7 weeks ago 1.49GB > hyperledger/fabric-tools 1.4.6 0f9743ac0662 7 weeks ago 1.49GB > hyperledger/fabric-tools latest 0f9743ac0662 7 weeks ago 1.49GB > hyperledger/fabric-ccenv 1.4 191911f4454f 7 weeks ago 1.36GB > hyperledger/fabric-ccenv 1.4.6 191911f4454f 7 weeks ago 1.36GB > hyperledger/fabric-ccenv latest 191911f4454f 7 weeks ago 1.36GB > hyperledger/fabric-orderer 1.4 84eaba5388e7 7 weeks ago 120MB > hyperledger/fabric-orderer 1.4.6 84eaba5388e7 7 weeks ago 120MB > hyperledger/fabric-orderer latest 84eaba5388e7 7 weeks ago 120MB > hyperledger/fabric-peer 1.4 5a52faa5d8c2 7 weeks ago 128MB > hyperledger/fabric-peer 1.4.6 5a52faa5d8c2 7 weeks ago 128MB > hyperledger/fabric-peer latest 5a52faa5d8c2 7 weeks ago 128MB > hyperledger/fabric-zookeeper 0.4 ede9389347db 5 months ago 276MB > hyperledger/fabric-zookeeper 0.4.18 ede9389347db 5 months ago 276MB > hyperledger/fabric-zookeeper latest ede9389347db 5 months ago 276MB > hyperledger/fabric-kafka 0.4 caaae0474ef2 5 months ago 270MB > hyperledger/fabric-kafka 0.4.18 caaae0474ef2 5 months ago 270MB > hyperledger/fabric-kafka latest caaae0474ef2 5 months ago 270MB > hyperledger/fabric-couchdb 0.4 d369d4eaa0fd 5 months ago 261MB > hyperledger/fabric-couchdb 0.4.18 d369d4eaa0fd 5 months ago 261MB > hyperledger/fabric-couchdb latest d369d4eaa0fd 5 months ago 261MB > ``` ### 2.3.2 官方first-network网络部署 - 进入对应目录 ```bash [vagrant@RUAN:~]$ cd /opt/gopath/src/github.com/hyperledger/fabric-samples/first-network ``` - 启动网络 ```bash [vagrant@RUAN:/opt/gopath/src/github.com/hyperledger/fabric-samples/first-network] (v1.4.6)$ ./byfn.sh up -c jschannel 。。。。。。 ========= All GOOD, BYFN execution completed =========== ``` > 启动错误处理: > > - 如遇到错误: > > ```bash > 2020-04-16 04:24:25.272 UTC [chaincodeCmd] checkChaincodeCmdParams -> INFO 002 Using default vscc > Error: could not assemble transaction, err proposal response was not successful, error code 500, msg error starting container: error starting container: Get https://registry-1.docker.io/v2/hyperledger/fabric-baseos/manifests/amd64-0.4.18: Get https://auth.docker.io/token?scope=repository%3Ahyperledger%2Ffabric-baseos%3Apull&service=registry.docker.io: net/http: TLS handshake timeout > !!!!!!!!!!!!!!! Chaincode instantiation on peer0.org2 on channel 'jschannel' failed !!!!!!!!!!!!!!!! > ========= ERROR !!! FAILED to execute End-2-End Scenario =========== > ``` > > - 添加docker国内镜像 > > ```json > $ cat /etc/docker/daemon.json > { > "registry-mirrors": ["https://registry.docker-cn.com"] > } > ``` > > - 加载&重启 > > ```bash > $ sudo systemctl daemon-reload > $ sudo systemctl restart docker > ``` - 清理网络 ```bash [vagrant@RUAN:/opt/gopath/src/github.com/hyperledger/fabric-samples/first-network] (v1.4.6)$ ./byfn.sh down ``` # 3 开发测试 > 以下将使用VSCode远程开发模式,连接我们前面启动的Fabric网络进行远程开发。 > > 为了可以找到完整依赖,还需要下载`fabric`和`fabric-sdk-go`项目源码,并切换到恰当的分支: > > ```bash > [vagrant@RUAN:/opt/gopath/src/github.com/hyperledger]$ git clone https://github.com/hyperledger/fabric.git > [vagrant@RUAN:/opt/gopath/src/github.com/hyperledger]$ git checkout -b v1.4.6 v1.4.6 > > [vagrant@RUAN:/opt/gopath/src/github.com/hyperledger/fabric] (master)$ git clone https://github.com/hyperledger/fabric-sdk-go.git > ``` ## 3.1 链码开发 ### 3.1.1 功能说明 本链码实现了一个购物积分平台,拥有如下功能: - 初始化平台管理员拥有10000积分 - 用户注册,将会得到100积分奖励 - 用户之间可以互转积分 ### 3.1.2 链码开发 #### 3.1.2.1 工程创建 ```bash [vagrant@RUAN:/opt/gopath/src/github.com/hyperledger/fabric-samples/chaincode] (v1.4.6)$ cd ptcc/ [vagrant@RUAN:/opt/gopath/src/github.com/hyperledger/fabric-samples/chaincode/ptcc] (v1.4.6)$ go mod init ptcc [vagrant@RUAN:/opt/gopath/src/github.com/hyperledger/fabric-samples/chaincode/ptcc] (v1.4.6)$ go get github.com/hyperledger/fabric@v1.4.6 ``` #### 3.1.2.2 链码开发 ```go package main import ( "fmt" "strconv" "github.com/hyperledger/fabric/core/chaincode/shim" pb "github.com/hyperledger/fabric/protos/peer" ) // PointsTransferChaincode => 声明积分转移智能合约结构体 type PointsTransferChaincode struct { } // Init => 链码初始化接口 func (t *PointsTransferChaincode) Init(stub shim.ChaincodeStubInterface) pb.Response { args := stub.GetStringArgs() if len(args) != 2 { return shim.Error("初始化参数个数不匹配") } err := stub.PutState(args[0], []byte(args[1])) if err != nil { return shim.Error("积分管理员初始化失败") } return shim.Success(nil) } // Invoke => 链码调用接口 func (t *PointsTransferChaincode) Invoke(stub shim.ChaincodeStubInterface) pb.Response { function, args := stub.GetFunctionAndParameters() if function == "transfer" { return t.transfer(stub, args) } else if function == "query" { return t.query(stub, args) } return shim.Error("无效交易方法,仅支持:transfer|query") } func (t *PointsTransferChaincode) transfer(stub shim.ChaincodeStubInterface, args []string) pb.Response { outUser := args[0] inUser := args[1] offsetVal, _ := strconv.Atoi(args[2]) outUserPointBalanceByte, _ := stub.GetState(outUser) outUserPointBalance, _ := strconv.Atoi(string(outUserPointBalanceByte)) inUserPointBalanceByte, _ := stub.GetState(inUser) inUserPointBalance, _ := strconv.Atoi(string(inUserPointBalanceByte)) outUserPointBalance = outUserPointBalance - offsetVal inUserPointBalance = inUserPointBalance + offsetVal err := stub.PutState(outUser, []byte(strconv.Itoa(outUserPointBalance))) if err != nil { return shim.Error(err.Error()) } err = stub.PutState(inUser, []byte(strconv.Itoa(inUserPointBalance))) if err != nil { return shim.Error(err.Error()) } return shim.Success(nil) } func (t *PointsTransferChaincode) query(stub shim.ChaincodeStubInterface, args []string) pb.Response { userPointsBalance, _ := stub.GetState(args[0]) if userPointsBalance == nil { return shim.Error("查询账户余额失败") } return shim.Success(userPointsBalance) } func main() { err := shim.Start(new(PointsTransferChaincode)) if err != nil { fmt.Printf("积分转移链码启动失败: %s\n", err) } } ``` #### 3.1.2.3 编写测试用例 ```go package main import ( "fmt" "testing" "github.com/hyperledger/fabric/core/chaincode/shim" ) func checkInit(t *testing.T, stub *shim.MockStub) { args := [][]byte{[]byte("Jason"), []byte("10000")} res := stub.MockInit("初始化交易", args) if res.Status == shim.OK { fmt.Println("Init success :)") } else { fmt.Println("Init failed :(") t.FailNow() } } func checkPointsTransfer(t *testing.T, stub *shim.MockStub, arg1, arg2, arg3 string) { args := [][]byte{[]byte("transfer"), []byte(arg1), []byte(arg2), []byte(arg3)} res := stub.MockInvoke("积分转移交易", args) if res.Status == shim.OK { fmt.Printf("%s转给%s %s积分交易成功:)\n", arg1, arg2, arg3) } else { fmt.Printf("%s转给%s %s积分交易失败:(\n", arg1, arg2, arg3) t.FailNow() } } func checkQueryBalance(t *testing.T, stub *shim.MockStub, username string) { args := [][]byte{[]byte("query"), []byte(username)} res := stub.MockInvoke("用户积分查询", args) if res.Status == shim.OK { fmt.Printf("%s查询积分交易成功,积分为:%s\n", username, res.GetPayload()) } else { fmt.Printf("%s查询积分交易失败\n", username) t.FailNow() } } func Test_PTCC(t *testing.T) { stub := shim.NewMockStub("ptcc", new(PointsTransferChaincode)) checkInit(t, stub) checkPointsTransfer(t, stub, "Jason", "XX", "100") checkPointsTransfer(t, stub, "Jason", "YY", "100") checkPointsTransfer(t, stub, "XX", "YY", "10") checkQueryBalance(t, stub, "Jason") checkQueryBalance(t, stub, "XX") checkQueryBalance(t, stub, "YY") // === RUN Test_PTCC // Init success 🙂 // Jason转给XX 100积分交易成功:) // Jason转给YY 100积分交易成功:) // XX转给YY 10积分交易成功:) // Jason查询积分交易成功,积分为:9800 // XX查询积分交易成功,积分为:90 // YY查询积分交易成功,积分为:110 // --- PASS: Test_PTCC (0.00s) // PASS // ok ptcc 0.029s // Success: Tests passed. } ``` > TIPS:开启VSCode保存即测试是个不错的选择: > > ![image.png](https://img.learnblockchain.cn/attachments/2020/05/nRklFS745ebe383660501.png) ### 3.1.3 链码部署 > 我们直接将其部署到前面启动的官方`first-network`网络。 #### 3.1.3.1 安装链码 ```bash # 进入工具容器 $ docker exec -it cli bash # 进入链码所在路径 root@ce34ec1e55ae:/opt/gopath/src/github.com/hyperledger/fabric/peer# cd /opt/gopath/src/github.com/chaincode/ptcc # 执行安装链码命令 ## 组织1的peer节点安装 root@ce34ec1e55ae:/opt/gopath/src# peer chaincode install -n ptcc -v 2.0 -l golang -p github.com/chaincode/ptcc 2020-04-17 04:29:09.820 UTC [chaincodeCmd] install -> INFO 003 Installed remotely response:<status:200 payload:"OK" > ## 组织2的peer节点安装 export CORE_PEER_LOCALMSPID=Org2MSP export CORE_PEER_TLS_ROOTCERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt export CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp export CORE_PEER_ADDRESS=peer0.org2.example.com:9051 export CORE_PEER_TLS_KEY_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/server.key export CORE_PEER_TLS_CERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/server.crt export CORE_PEER_TLS_ENABLED=true export CORE_PEER_ID=cli root@ce34ec1e55ae:/opt/gopath/src# peer chaincode install -n ptcc -v 2.0 -l golang -p github.com/chaincode/ptcc 2020-04-17 06:46:16.719 UTC [chaincodeCmd] install -> INFO 003 Installed remotely response:<status:200 payload:"OK" > ``` #### 3.1.3.2 实例化链码 ```bash root@ce34ec1e55ae:/opt/gopath/src# peer chaincode instantiate -o orderer.example.com:7050 --tls true --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem -C jschannel -n ptcc -l golang -v 2.0 -c '{"Args":["Jason","10000"]}' -P 'AND ('\''Org1MSP.peer'\'','\''Org2MSP.peer'\'')' 2020-04-17 04:53:04.776 UTC [chaincodeCmd] checkChaincodeCmdParams -> INFO 001 Using default escc 2020-04-17 04:53:04.777 UTC [chaincodeCmd] checkChaincodeCmdParams -> INFO 002 Using default vscc ``` #### 3.1.3.3 链码容器 > 链码实例化后,将会启动一个链码容器: ```bash IMAGE:dev-peer0.org1.example.com-ptcc-2.0-e3487c2ca0e68959525d94a4bd69896f99c169db1e3d031d4650a9e74d568d4d NAMES:dev-peer0.org1.example.com-ptcc-2.0 ``` ### 3.1.4 链码调用 - 管理员余额查看 ```bash root@ce34ec1e55ae:/opt/gopath/src# peer chaincode query -C jschannel -n ptcc -c '{"Args":["query","Jason"]}' 10000 ``` - 管理员给XX用户发放100积分 ```bash root@ce34ec1e55ae:/opt/gopath/src# peer chaincode invoke -o orderer.example.com:7050 --tls true --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem -C jschannel -n ptcc --peerAddresses peer0.org1.example.com:7051 --tlsRootCertFiles /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt --peerAddresses peer0.org2.example.com:9051 --tlsRootCertFiles /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt -c '{"Args":["transfer","Jason","XX","100"]}' 2020-04-17 06:47:25.599 UTC [chaincodeCmd] chaincodeInvokeOrQuery -> INFO 001 Chaincode invoke successful. result: status:200 ``` - 管理员给YY用户发放100积分 ```bash root@ce34ec1e55ae:/opt/gopath/src# peer chaincode invoke -o orderer.example.com:7050 --tls true --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem -C jschannel -n ptcc --peerAddresses peer0.org1.example.com:7051 --tlsRootCertFiles /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt --peerAddresses peer0.org2.example.com:9051 --tlsRootCertFiles /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt -c '{"Args":["transfer","Jason","YY","100"]}' 2020-04-17 06:48:18.142 UTC [chaincodeCmd] chaincodeInvokeOrQuery -> INFO 001 Chaincode invoke successful. result: status:200 ``` - 用户XX给用户YY转账10积分 ```bash root@ce34ec1e55ae:/opt/gopath/src# peer chaincode invoke -o orderer.example.com:7050 --tls true --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem -C jschannel -n ptcc --peerAddresses peer0.org1.example.com:7051 --tlsRootCertFiles /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt --peerAddresses peer0.org2.example.com:9051 --tlsRootCertFiles /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt -c '{"Args":["transfer","XX","YY","10"]}' 2020-04-17 06:49:15.393 UTC [chaincodeCmd] chaincodeInvokeOrQuery -> INFO 001 Chaincode invoke successful. result: status:200 ``` - 分别查看用户当前积分情况 ```bash root@ce34ec1e55ae:/opt/gopath/src# peer chaincode query -C jschannel -n ptcc -c '{"Args":["query","Jason"]}' 9800 root@ce34ec1e55ae:/opt/gopath/src# peer chaincode query -C jschannel -n ptcc -c '{"Args":["query","XX"]}' 90 root@ce34ec1e55ae:/opt/gopath/src# peer chaincode query -C jschannel -n ptcc -c '{"Args":["query","YY"]}' 110 ``` ## 3.2 客户端SDK开发 ### 3.2.1 功能说明 fabric提供Go、Java、Node的SDK,本节使用Go的SDK开发客户端程序调用前面部署好的链码。 ### 3.2.2 模块开发 #### 3.2.2.1 工程创建 ```bash [vagrant@RUAN:/opt/gopath/src/client]$ go mod init client go: creating new go.mod: module client # 注:这里需要使用master,默认使用v1.0.0-beta1版本,没有所需的这个库:fabric-sdk-go/pkg/gateway [vagrant@RUAN:/opt/gopath/src/client]$ go get github.com/hyperledger/fabric-sdk-go@master go: github.com/hyperledger/fabric-sdk-go master => v1.0.0-beta1.0.20200416003947-f7729f181cbf go: downloading github.com/hyperledger/fabric-sdk-go v1.0.0-beta1.0.20200416003947-f7729f181cbf ``` #### 3.2.2.2 模块开发 ```go package client import ( "log" "github.com/hyperledger/fabric-sdk-go/pkg/core/config" "github.com/hyperledger/fabric-sdk-go/pkg/fabsdk" "github.com/hyperledger/fabric-sdk-go/pkg/gateway" ) // NewContract => 创建Fabric网络交互对象 func NewContract() *gateway.Contract { // 需要修改该配置的channelName为jschannel configPath := "/opt/gopath/src/github.com/hyperledger/fabric-sdk-go/pkg/gateway/testdata/connection-tls.json" channelName := "jschannel" chaincodeName := "ptcc" // 创建SDK操作对象 sdk, err := fabsdk.New(config.FromFile(configPath)) if err != nil { log.Fatalf("fabsdk new failed, %s", err.Error()) } gw, err := gateway.Connect(gateway.WithSDK(sdk), gateway.WithUser("Admin")) if err != nil { log.Fatalf("gateway connect failed, %s", err.Error()) } defer gw.Close() network, err := gw.GetNetwork(channelName) if err != nil { log.Fatalf("gw get network failed, %s", err.Error()) } return network.GetContract(chaincodeName) } func transfer(contract *gateway.Contract) error { _, err := contract.SubmitTransaction("transfer", "XX", "YY", "10") if err != nil { return err } return nil } func query(contract *gateway.Contract, key string) string { resp, err := contract.EvaluateTransaction("query", key) if err != nil { log.Fatalf("query failed, %s", err.Error()) } return string(resp) } ``` #### 3.2.2.3 测试用例编写 ```go package client import ( "fmt" "testing" "time" ) func Test_TransferAndQuery(t *testing.T) { contract := NewContract() valueA := query(contract, "XX") valueB := query(contract, "YY") fmt.Printf("转账前 XX=%s YY=%s\n", valueA, valueB) err := transfer(contract) if err != nil { fmt.Printf("转出接口测试失败, %s\n", err.Error()) t.FailNow() } fmt.Println("a给b转账10元执行成功!") time.Sleep(2 * time.Second) valueA = query(contract, "XX") valueB = query(contract, "YY") fmt.Printf("转账前 XX=%s YY=%s\n", valueA, valueB) } ``` ### 3.2.3 链码调用 - 导入客户端连接fabric所需证书 ```bash [vagrant@RUAN:/opt/gopath/src/github.com/hyperledger/fabric-sdk-go/test/fixtures/fabric/v1] (master)$ ln -s /opt/gopath/src/github.com/hyperledger/fabric-samples/first-network/crypto-config . ``` - 配置hosts ```bash 127.0.0.1 peer0.org1.example.com 127.0.0.1 peer1.org1.example.com 127.0.0.1 peer0.org2.example.com 127.0.0.1 peer1.org2.example.com 127.0.0.1 orderer.example.com ``` - 执行测试命令 ```bash [vagrant@RUAN:/opt/gopath/src/client]$ go test 转账前 XX=90 YY=110 a给b转账10元执行成功! 转账前 XX=80 YY=120 PASS ok client 4.858s ```
快速带你上手Hyperledger Fabric环境搭建+开发测试
jasonruan 2020.04.20
1 前言
本文采用virtualbox+vagrant
方式搭建Hyperledger Fabric
环境,采用VSCode
远程开发模式开发调试链码和客户端程序。
2 环境搭建
2.1 搭建虚拟机环境
2.1.1 生成配置文件
使用版本:Ubuntu 18.04 LTS
执行以下命令后,将生成
Vagrantfile
配置文件
$ vagrant init ubuntu/bionic64
2.1.2 指定虚拟机名称
修改
Vagrantfile
配置文件,增加如下内容:
config.vm.provider "virtualbox" do |v|
v.name = "js-fabric"
end
2.1.3 拉取镜像并启动
根据配置文件拉取镜像并创建
Ubuntu18.04
虚拟机
$ vagrant up
在
Virtualbox
看到虚拟机已启动
2.1.4 登录虚拟机
(2020-04-14 12:44:40) [jason@RUAN:~/Vagrant/js-fabric]$ vagrant ssh
Welcome to Ubuntu 18.04.4 LTS (GNU/Linux 4.15.0-96-generic x86_64)
vagrant@ubuntu-bionic:~$
2.2 安装依赖工具
2.2.1 go
vagrant@ubuntu-bionic:~/Soft$ wget https://dl.google.com/go/go1.14.2.linux-amd64.tar.gz
vagrant@ubuntu-bionic:~/Soft$ sudo tar -zxvf go1.14.2.linux-amd64.tar.gz -C /opt
vagrant@ubuntu-bionic:~/Soft$ echo "export GOROOT=/opt/go" >> ~/.bashrc
vagrant@ubuntu-bionic:~/Soft$ echo "export GOPATH=/opt/gopath" >> ~/.bashrc
vagrant@ubuntu-bionic:~/Soft$ echo "export PATH=\$GOROOT/bin:\$GOPATH/bin:\$PATH" >> ~/.bashrc
vagrant@ubuntu-bionic:~/Soft$ . ~/.bashrc
vagrant@ubuntu-bionic:~/Soft$ go version
go version go1.14.2 linux/amd64
2.2.2 docker
vagrant@ubuntu-bionic:~/Soft$ curl -fsSL https://get.docker.com -o get-docker.sh
vagrant@ubuntu-bionic:~/Soft$ sudo sh get-docker.sh
vagrant@ubuntu-bionic:~/Soft$ sudo usermod -aG docker $USER
vagrant@ubuntu-bionic:~/Soft$ sudo systemctl restart docker
vagrant@ubuntu-bionic:~$ docker version
Client: Docker Engine - Community
Version: 19.03.8
API version: 1.40
Go version: go1.12.17
Git commit: afacb8b7f0
Built: Wed Mar 11 01:25:46 2020
OS/Arch: linux/amd64
Experimental: false
Server: Docker Engine - Community
Engine:
Version: 19.03.8
API version: 1.40 (minimum version 1.12)
Go version: go1.12.17
Git commit: afacb8b7f0
Built: Wed Mar 11 01:24:19 2020
OS/Arch: linux/amd64
Experimental: false
containerd:
Version: 1.2.13
GitCommit: 7ad184331fa3e55e52b890ea95e65ba581ae3429
runc:
Version: 1.0.0-rc10
GitCommit: dc9208a3303feef5b3839f4323d9beb36df0a9dd
docker-init:
Version: 0.18.0
GitCommit: fec3683
2.2.3 docker-compose
vagrant@ubuntu-bionic:~$ sudo curl -L "https://github.com/docker/compose/releases/download/1.25.4/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
vagrant@ubuntu-bionic:~$ sudo chmod 755 /usr/local/bin/docker-compose
vagrant@ubuntu-bionic:~$ docker-compose --version
docker-compose version 1.25.4, build 8d51620a
2.3 官方样例部署
官方样例:https://github.com/hyperledger/fabric-samples
2.3.1 源码及镜像下载
- 下载源码
vagrant@ubuntu-bionic:~$ mkdir -p $GOPATH/src/github.com/hyperledger
vagrant@ubuntu-bionic:~$ cd $GOPATH/src/github.com/hyperledger
vagrant@ubuntu-bionic:/opt/gopath/src/github.com/hyperledger$ git clone https://github.com/hyperledger/fabric-samples.git
- 切换分支
[vagrant@RUAN:/opt/gopath/src/github.com/hyperledger/fabric-samples] (master)$ git checkout -b v1.4.6 v1.4.6
Switched to a new branch 'v1.4.6'
- 下载引导脚本
[vagrant@RUAN:/opt/gopath/src/github.com/hyperledger/fabric-samples] (v1.4.6)$ curl -sS https://raw.githubusercontent.com/hyperledger/fabric/master/scripts/bootstrap.sh -o ./scripts/bootstrap.sh
[vagrant@RUAN:/opt/gopath/src/github.com/hyperledger/fabric-samples] (v1.4.6)$ chmod +x scripts/bootstrap.sh
- 下载必备二进制文件和docker镜像
# ./scripts/bootstrap.sh [version] [ca version] [thirdparty_version]
[vagrant@RUAN:/opt/gopath/src/github.com/hyperledger/fabric-samples] (v1.4.6)$ ./scripts/bootstrap.sh 1.4.6 1.4.6 0.4.18 -s
具体流程:
- 下载Hyperledger Fabric二进制包:
===> Downloading version 1.4.6 platform specific fabric binaries ===> Downloading: https://github.com/hyperledger/fabric/releases/download/v1.4.6/hyperledger-fabric-linux-amd64-1.4.6.tar.gz ===> Downloading version 1.4.6 platform specific fabric-ca-client binary ===> Downloading: https://github.com/hyperledger/fabric-ca/releases/download/v1.4.6/hyperledger-fabric-ca-linux-amd64-1.4.6.tar.gz
- 拉取Hyperledger Fabric Docker镜像:
Pull Hyperledger Fabric docker images FABRIC_IMAGES: peer orderer ccenv tools javaenv ===> Pulling fabric Images ====> hyperledger/fabric-peer:1.4.6 1.4.6: Pulling from hyperledger/fabric-peer ====> hyperledger/fabric-orderer:1.4.6 1.4.6: Pulling from hyperledger/fabric-orderer ====> hyperledger/fabric-ccenv:1.4.6 1.4.6: Pulling from hyperledger/fabric-ccenv ====> hyperledger/fabric-tools:1.4.6 1.4.6: Pulling from hyperledger/fabric-tools ====> hyperledger/fabric-javaenv:1.4.6 1.4.6: Pulling from hyperledger/fabric-javaenv ====> hyperledger/fabric-ca:1.4.6 1.4.6: Pulling from hyperledger/fabric-ca ===> Pulling thirdparty docker images ====> hyperledger/fabric-zookeeper:0.4.18 0.4.18: Pulling from hyperledger/fabric-zookeeper ====> hyperledger/fabric-kafka:0.4.18 0.4.18: Pulling from hyperledger/fabric-kafka ====> hyperledger/fabric-couchdb:0.4.18 0.4.18: Pulling from hyperledger/fabric-couchdb ===> List out hyperledger docker images hyperledger/fabric-javaenv 1.4 68914607b3a5 6 weeks ago 1.68GB hyperledger/fabric-javaenv 1.4.6 68914607b3a5 6 weeks ago 1.68GB hyperledger/fabric-javaenv latest 68914607b3a5 6 weeks ago 1.68GB hyperledger/fabric-ca 1.4 3b96a893c1e4 7 weeks ago 150MB hyperledger/fabric-ca 1.4.6 3b96a893c1e4 7 weeks ago 150MB hyperledger/fabric-ca latest 3b96a893c1e4 7 weeks ago 150MB hyperledger/fabric-tools 1.4 0f9743ac0662 7 weeks ago 1.49GB hyperledger/fabric-tools 1.4.6 0f9743ac0662 7 weeks ago 1.49GB hyperledger/fabric-tools latest 0f9743ac0662 7 weeks ago 1.49GB hyperledger/fabric-ccenv 1.4 191911f4454f 7 weeks ago 1.36GB hyperledger/fabric-ccenv 1.4.6 191911f4454f 7 weeks ago 1.36GB hyperledger/fabric-ccenv latest 191911f4454f 7 weeks ago 1.36GB hyperledger/fabric-orderer 1.4 84eaba5388e7 7 weeks ago 120MB hyperledger/fabric-orderer 1.4.6 84eaba5388e7 7 weeks ago 120MB hyperledger/fabric-orderer latest 84eaba5388e7 7 weeks ago 120MB hyperledger/fabric-peer 1.4 5a52faa5d8c2 7 weeks ago 128MB hyperledger/fabric-peer 1.4.6 5a52faa5d8c2 7 weeks ago 128MB hyperledger/fabric-peer latest 5a52faa5d8c2 7 weeks ago 128MB hyperledger/fabric-zookeeper 0.4 ede9389347db 5 months ago 276MB hyperledger/fabric-zookeeper 0.4.18 ede9389347db 5 months ago 276MB hyperledger/fabric-zookeeper latest ede9389347db 5 months ago 276MB hyperledger/fabric-kafka 0.4 caaae0474ef2 5 months ago 270MB hyperledger/fabric-kafka 0.4.18 caaae0474ef2 5 months ago 270MB hyperledger/fabric-kafka latest caaae0474ef2 5 months ago 270MB hyperledger/fabric-couchdb 0.4 d369d4eaa0fd 5 months ago 261MB hyperledger/fabric-couchdb 0.4.18 d369d4eaa0fd 5 months ago 261MB hyperledger/fabric-couchdb latest d369d4eaa0fd 5 months ago 261MB
2.3.2 官方first-network网络部署
- 进入对应目录
[vagrant@RUAN:~]$ cd /opt/gopath/src/github.com/hyperledger/fabric-samples/first-network
- 启动网络
[vagrant@RUAN:/opt/gopath/src/github.com/hyperledger/fabric-samples/first-network] (v1.4.6)$ ./byfn.sh up -c jschannel
。。。。。。
========= All GOOD, BYFN execution completed ===========
启动错误处理:
- 如遇到错误:
2020-04-16 04:24:25.272 UTC [chaincodeCmd] checkChaincodeCmdParams -> INFO 002 Using default vscc Error: could not assemble transaction, err proposal response was not successful, error code 500, msg error starting container: error starting container: Get https://registry-1.docker.io/v2/hyperledger/fabric-baseos/manifests/amd64-0.4.18: Get https://auth.docker.io/token?scope=repository%3Ahyperledger%2Ffabric-baseos%3Apull&service=registry.docker.io: net/http: TLS handshake timeout !!!!!!!!!!!!!!! Chaincode instantiation on peer0.org2 on channel 'jschannel' failed !!!!!!!!!!!!!!!! ========= ERROR !!! FAILED to execute End-2-End Scenario ===========
- 添加docker国内镜像
$ cat /etc/docker/daemon.json { "registry-mirrors": ["https://registry.docker-cn.com"] }
- 加载&重启
$ sudo systemctl daemon-reload $ sudo systemctl restart docker
- 清理网络
[vagrant@RUAN:/opt/gopath/src/github.com/hyperledger/fabric-samples/first-network] (v1.4.6)$ ./byfn.sh down
3 开发测试
以下将使用VSCode远程开发模式,连接我们前面启动的Fabric网络进行远程开发。
为了可以找到完整依赖,还需要下载
fabric
和fabric-sdk-go
项目源码,并切换到恰当的分支:[vagrant@RUAN:/opt/gopath/src/github.com/hyperledger]$ git clone https://github.com/hyperledger/fabric.git [vagrant@RUAN:/opt/gopath/src/github.com/hyperledger]$ git checkout -b v1.4.6 v1.4.6 [vagrant@RUAN:/opt/gopath/src/github.com/hyperledger/fabric] (master)$ git clone https://github.com/hyperledger/fabric-sdk-go.git
3.1 链码开发
3.1.1 功能说明
本链码实现了一个购物积分平台,拥有如下功能:
- 初始化平台管理员拥有10000积分
- 用户注册,将会得到100积分奖励
- 用户之间可以互转积分
3.1.2 链码开发
3.1.2.1 工程创建
[vagrant@RUAN:/opt/gopath/src/github.com/hyperledger/fabric-samples/chaincode] (v1.4.6)$ cd ptcc/
[vagrant@RUAN:/opt/gopath/src/github.com/hyperledger/fabric-samples/chaincode/ptcc] (v1.4.6)$ go mod init ptcc
[vagrant@RUAN:/opt/gopath/src/github.com/hyperledger/fabric-samples/chaincode/ptcc] (v1.4.6)$ go get github.com/hyperledger/fabric@v1.4.6
3.1.2.2 链码开发
package main
import (
"fmt"
"strconv"
"github.com/hyperledger/fabric/core/chaincode/shim"
pb "github.com/hyperledger/fabric/protos/peer"
)
// PointsTransferChaincode => 声明积分转移智能合约结构体
type PointsTransferChaincode struct {
}
// Init => 链码初始化接口
func (t *PointsTransferChaincode) Init(stub shim.ChaincodeStubInterface) pb.Response {
args := stub.GetStringArgs()
if len(args) != 2 {
return shim.Error("初始化参数个数不匹配")
}
err := stub.PutState(args[0], []byte(args[1]))
if err != nil {
return shim.Error("积分管理员初始化失败")
}
return shim.Success(nil)
}
// Invoke => 链码调用接口
func (t *PointsTransferChaincode) Invoke(stub shim.ChaincodeStubInterface) pb.Response {
function, args := stub.GetFunctionAndParameters()
if function == "transfer" {
return t.transfer(stub, args)
} else if function == "query" {
return t.query(stub, args)
}
return shim.Error("无效交易方法,仅支持:transfer|query")
}
func (t *PointsTransferChaincode) transfer(stub shim.ChaincodeStubInterface, args []string) pb.Response {
outUser := args[0]
inUser := args[1]
offsetVal, _ := strconv.Atoi(args[2])
outUserPointBalanceByte, _ := stub.GetState(outUser)
outUserPointBalance, _ := strconv.Atoi(string(outUserPointBalanceByte))
inUserPointBalanceByte, _ := stub.GetState(inUser)
inUserPointBalance, _ := strconv.Atoi(string(inUserPointBalanceByte))
outUserPointBalance = outUserPointBalance - offsetVal
inUserPointBalance = inUserPointBalance + offsetVal
err := stub.PutState(outUser, []byte(strconv.Itoa(outUserPointBalance)))
if err != nil {
return shim.Error(err.Error())
}
err = stub.PutState(inUser, []byte(strconv.Itoa(inUserPointBalance)))
if err != nil {
return shim.Error(err.Error())
}
return shim.Success(nil)
}
func (t *PointsTransferChaincode) query(stub shim.ChaincodeStubInterface, args []string) pb.Response {
userPointsBalance, _ := stub.GetState(args[0])
if userPointsBalance == nil {
return shim.Error("查询账户余额失败")
}
return shim.Success(userPointsBalance)
}
func main() {
err := shim.Start(new(PointsTransferChaincode))
if err != nil {
fmt.Printf("积分转移链码启动失败: %s\n", err)
}
}
3.1.2.3 编写测试用例
package main
import (
"fmt"
"testing"
"github.com/hyperledger/fabric/core/chaincode/shim"
)
func checkInit(t *testing.T, stub *shim.MockStub) {
args := [][]byte{[]byte("Jason"), []byte("10000")}
res := stub.MockInit("初始化交易", args)
if res.Status == shim.OK {
fmt.Println("Init success :)")
} else {
fmt.Println("Init failed :(")
t.FailNow()
}
}
func checkPointsTransfer(t *testing.T, stub *shim.MockStub, arg1, arg2, arg3 string) {
args := [][]byte{[]byte("transfer"), []byte(arg1), []byte(arg2), []byte(arg3)}
res := stub.MockInvoke("积分转移交易", args)
if res.Status == shim.OK {
fmt.Printf("%s转给%s %s积分交易成功:)\n", arg1, arg2, arg3)
} else {
fmt.Printf("%s转给%s %s积分交易失败:(\n", arg1, arg2, arg3)
t.FailNow()
}
}
func checkQueryBalance(t *testing.T, stub *shim.MockStub, username string) {
args := [][]byte{[]byte("query"), []byte(username)}
res := stub.MockInvoke("用户积分查询", args)
if res.Status == shim.OK {
fmt.Printf("%s查询积分交易成功,积分为:%s\n", username, res.GetPayload())
} else {
fmt.Printf("%s查询积分交易失败\n", username)
t.FailNow()
}
}
func Test_PTCC(t *testing.T) {
stub := shim.NewMockStub("ptcc", new(PointsTransferChaincode))
checkInit(t, stub)
checkPointsTransfer(t, stub, "Jason", "XX", "100")
checkPointsTransfer(t, stub, "Jason", "YY", "100")
checkPointsTransfer(t, stub, "XX", "YY", "10")
checkQueryBalance(t, stub, "Jason")
checkQueryBalance(t, stub, "XX")
checkQueryBalance(t, stub, "YY")
// === RUN Test_PTCC
// Init success :)
// Jason转给XX 100积分交易成功:)
// Jason转给YY 100积分交易成功:)
// XX转给YY 10积分交易成功:)
// Jason查询积分交易成功,积分为:9800
// XX查询积分交易成功,积分为:90
// YY查询积分交易成功,积分为:110
// --- PASS: Test_PTCC (0.00s)
// PASS
// ok ptcc 0.029s
// Success: Tests passed.
}
TIPS:开启VSCode保存即测试是个不错的选择:
3.1.3 链码部署
我们直接将其部署到前面启动的官方
first-network
网络。
3.1.3.1 安装链码
# 进入工具容器
$ docker exec -it cli bash
# 进入链码所在路径
root@ce34ec1e55ae:/opt/gopath/src/github.com/hyperledger/fabric/peer# cd /opt/gopath/src/github.com/chaincode/ptcc
# 执行安装链码命令
## 组织1的peer节点安装
root@ce34ec1e55ae:/opt/gopath/src# peer chaincode install -n ptcc -v 2.0 -l golang -p github.com/chaincode/ptcc
2020-04-17 04:29:09.820 UTC [chaincodeCmd] install -> INFO 003 Installed remotely response:<status:200 payload:"OK" >
## 组织2的peer节点安装
export CORE_PEER_LOCALMSPID=Org2MSP
export CORE_PEER_TLS_ROOTCERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt
export CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp
export CORE_PEER_ADDRESS=peer0.org2.example.com:9051
export CORE_PEER_TLS_KEY_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/server.key
export CORE_PEER_TLS_CERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/server.crt
export CORE_PEER_TLS_ENABLED=true
export CORE_PEER_ID=cli
root@ce34ec1e55ae:/opt/gopath/src# peer chaincode install -n ptcc -v 2.0 -l golang -p github.com/chaincode/ptcc
2020-04-17 06:46:16.719 UTC [chaincodeCmd] install -> INFO 003 Installed remotely response:<status:200 payload:"OK" >
3.1.3.2 实例化链码
root@ce34ec1e55ae:/opt/gopath/src# peer chaincode instantiate -o orderer.example.com:7050 --tls true --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem -C jschannel -n ptcc -l golang -v 2.0 -c '{"Args":["Jason","10000"]}' -P 'AND ('\''Org1MSP.peer'\'','\''Org2MSP.peer'\'')'
2020-04-17 04:53:04.776 UTC [chaincodeCmd] checkChaincodeCmdParams -> INFO 001 Using default escc
2020-04-17 04:53:04.777 UTC [chaincodeCmd] checkChaincodeCmdParams -> INFO 002 Using default vscc
3.1.3.3 链码容器
链码实例化后,将会启动一个链码容器:
IMAGE:dev-peer0.org1.example.com-ptcc-2.0-e3487c2ca0e68959525d94a4bd69896f99c169db1e3d031d4650a9e74d568d4d
NAMES:dev-peer0.org1.example.com-ptcc-2.0
3.1.4 链码调用
- 管理员余额查看
root@ce34ec1e55ae:/opt/gopath/src# peer chaincode query -C jschannel -n ptcc -c '{"Args":["query","Jason"]}'
10000
- 管理员给XX用户发放100积分
root@ce34ec1e55ae:/opt/gopath/src# peer chaincode invoke -o orderer.example.com:7050 --tls true --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem -C jschannel -n ptcc --peerAddresses peer0.org1.example.com:7051 --tlsRootCertFiles /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt --peerAddresses peer0.org2.example.com:9051 --tlsRootCertFiles /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt -c '{"Args":["transfer","Jason","XX","100"]}'
2020-04-17 06:47:25.599 UTC [chaincodeCmd] chaincodeInvokeOrQuery -> INFO 001 Chaincode invoke successful. result: status:200
- 管理员给YY用户发放100积分
root@ce34ec1e55ae:/opt/gopath/src# peer chaincode invoke -o orderer.example.com:7050 --tls true --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem -C jschannel -n ptcc --peerAddresses peer0.org1.example.com:7051 --tlsRootCertFiles /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt --peerAddresses peer0.org2.example.com:9051 --tlsRootCertFiles /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt -c '{"Args":["transfer","Jason","YY","100"]}'
2020-04-17 06:48:18.142 UTC [chaincodeCmd] chaincodeInvokeOrQuery -> INFO 001 Chaincode invoke successful. result: status:200
- 用户XX给用户YY转账10积分
root@ce34ec1e55ae:/opt/gopath/src# peer chaincode invoke -o orderer.example.com:7050 --tls true --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem -C jschannel -n ptcc --peerAddresses peer0.org1.example.com:7051 --tlsRootCertFiles /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt --peerAddresses peer0.org2.example.com:9051 --tlsRootCertFiles /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt -c '{"Args":["transfer","XX","YY","10"]}'
2020-04-17 06:49:15.393 UTC [chaincodeCmd] chaincodeInvokeOrQuery -> INFO 001 Chaincode invoke successful. result: status:200
- 分别查看用户当前积分情况
root@ce34ec1e55ae:/opt/gopath/src# peer chaincode query -C jschannel -n ptcc -c '{"Args":["query","Jason"]}'
9800
root@ce34ec1e55ae:/opt/gopath/src# peer chaincode query -C jschannel -n ptcc -c '{"Args":["query","XX"]}'
90
root@ce34ec1e55ae:/opt/gopath/src# peer chaincode query -C jschannel -n ptcc -c '{"Args":["query","YY"]}'
110
3.2 客户端SDK开发
3.2.1 功能说明
fabric提供Go、Java、Node的SDK,本节使用Go的SDK开发客户端程序调用前面部署好的链码。
3.2.2 模块开发
3.2.2.1 工程创建
[vagrant@RUAN:/opt/gopath/src/client]$ go mod init client
go: creating new go.mod: module client
# 注:这里需要使用master,默认使用v1.0.0-beta1版本,没有所需的这个库:fabric-sdk-go/pkg/gateway
[vagrant@RUAN:/opt/gopath/src/client]$ go get github.com/hyperledger/fabric-sdk-go@master
go: github.com/hyperledger/fabric-sdk-go master => v1.0.0-beta1.0.20200416003947-f7729f181cbf
go: downloading github.com/hyperledger/fabric-sdk-go v1.0.0-beta1.0.20200416003947-f7729f181cbf
3.2.2.2 模块开发
package client
import (
"log"
"github.com/hyperledger/fabric-sdk-go/pkg/core/config"
"github.com/hyperledger/fabric-sdk-go/pkg/fabsdk"
"github.com/hyperledger/fabric-sdk-go/pkg/gateway"
)
// NewContract => 创建Fabric网络交互对象
func NewContract() *gateway.Contract {
// 需要修改该配置的channelName为jschannel
configPath := "/opt/gopath/src/github.com/hyperledger/fabric-sdk-go/pkg/gateway/testdata/connection-tls.json"
channelName := "jschannel"
chaincodeName := "ptcc"
// 创建SDK操作对象
sdk, err := fabsdk.New(config.FromFile(configPath))
if err != nil {
log.Fatalf("fabsdk new failed, %s", err.Error())
}
gw, err := gateway.Connect(gateway.WithSDK(sdk), gateway.WithUser("Admin"))
if err != nil {
log.Fatalf("gateway connect failed, %s", err.Error())
}
defer gw.Close()
network, err := gw.GetNetwork(channelName)
if err != nil {
log.Fatalf("gw get network failed, %s", err.Error())
}
return network.GetContract(chaincodeName)
}
func transfer(contract *gateway.Contract) error {
_, err := contract.SubmitTransaction("transfer", "XX", "YY", "10")
if err != nil {
return err
}
return nil
}
func query(contract *gateway.Contract, key string) string {
resp, err := contract.EvaluateTransaction("query", key)
if err != nil {
log.Fatalf("query failed, %s", err.Error())
}
return string(resp)
}
3.2.2.3 测试用例编写
package client
import (
"fmt"
"testing"
"time"
)
func Test_TransferAndQuery(t *testing.T) {
contract := NewContract()
valueA := query(contract, "XX")
valueB := query(contract, "YY")
fmt.Printf("转账前 XX=%s YY=%s\n", valueA, valueB)
err := transfer(contract)
if err != nil {
fmt.Printf("转出接口测试失败, %s\n", err.Error())
t.FailNow()
}
fmt.Println("a给b转账10元执行成功!")
time.Sleep(2 * time.Second)
valueA = query(contract, "XX")
valueB = query(contract, "YY")
fmt.Printf("转账前 XX=%s YY=%s\n", valueA, valueB)
}
3.2.3 链码调用
- 导入客户端连接fabric所需证书
[vagrant@RUAN:/opt/gopath/src/github.com/hyperledger/fabric-sdk-go/test/fixtures/fabric/v1] (master)$ ln -s /opt/gopath/src/github.com/hyperledger/fabric-samples/first-network/crypto-config .
- 配置hosts
127.0.0.1 peer0.org1.example.com
127.0.0.1 peer1.org1.example.com
127.0.0.1 peer0.org2.example.com
127.0.0.1 peer1.org2.example.com
127.0.0.1 orderer.example.com
- 执行测试命令
[vagrant@RUAN:/opt/gopath/src/client]$ go test
转账前 XX=90 YY=110
a给b转账10元执行成功!
转账前 XX=80 YY=120
PASS
ok client 4.858s
区块链技术网。
- 发表于 2020-05-15 14:36
- 阅读 ( 5780 )
- 学分 ( 243 )
- 分类:Fabric
评论