快速带你上手Hyperledger Fabric环境搭建+开发测试

栏目: IT技术 · 发布时间: 4年前

内容简介:本文采用virtualbox+vagrant方式搭建Hyperledger Fabric环境,采用VSCode远程开发模式开发调试链码和客户端程序。本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

本文采用virtualbox+vagrant方式搭建Hyperledger Fabric环境,采用VSCode远程开发模式开发调试链码和客户端程序。

快速带你上手Hyperledger Fabric环境搭建+开发测试

jasonruan 2020.04.20

[TOC]

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 看到虚拟机已启动

快速带你上手Hyperledger Fabric环境搭建+开发测试

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 ===========

该脚本详细执行过程,请参看: 《Hyperledger Fabric入门1:快速上手》

启动错误处理:

  • 如遇到错误:
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网络进行远程开发。

为了可以找到完整依赖,还需要下载 fabricfabric-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 链码开发

一个更完整的链码开发案例,请参考: 《Hyperledger Fabric入门3:资产交易平台项目实战》

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保存即测试是个不错的选择:

快速带你上手Hyperledger Fabric环境搭建+开发测试

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提供 GoJava 、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

快速带你上手Hyperledger Fabric环境搭建+开发测试

jasonruan 2020.04.20

[TOC]

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 看到虚拟机已启动

快速带你上手Hyperledger Fabric环境搭建+开发测试

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 ===========

该脚本详细执行过程,请参看: 《Hyperledger Fabric入门1:快速上手》

启动错误处理:

  • 如遇到错误:
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网络进行远程开发。

为了可以找到完整依赖,还需要下载 fabricfabric-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 链码开发

一个更完整的链码开发案例,请参考: 《Hyperledger Fabric入门3:资产交易平台项目实战》

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保存即测试是个不错的选择:

快速带你上手Hyperledger Fabric环境搭建+开发测试

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

本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

  • 发表于 11分钟前
  • 阅读 ( 7 )
  • 学分 ( 0 )
  • 分类:Fabric

以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Algorithms in C, Parts 1-4

Algorithms in C, Parts 1-4

Robert Sedgewick / Addison-Wesley Professional / 1997-9-27 / USD 89.99

"This is an eminently readable book which an ordinary programmer, unskilled in mathematical analysis and wary of theoretical algorithms, ought to be able to pick up and get a lot out of.." - Steve Sum......一起来看看 《Algorithms in C, Parts 1-4》 这本书的介绍吧!

CSS 压缩/解压工具
CSS 压缩/解压工具

在线压缩/解压 CSS 代码

JSON 在线解析
JSON 在线解析

在线 JSON 格式化工具

图片转BASE64编码
图片转BASE64编码

在线图片转Base64编码工具