阅读完本文,你将可以:
至少部署三个节点构建完成FABRIC区块链
通过GO语言开发,实现自定义的数据提交到链,并能查询交易的数据
如果本文对你有用,麻烦请给我点个赞👍,这是对我很大的鼓励!
大致简介
文章有三个部分
- 第一个部分是搭建Fabric节点网络;
- 第二部分是学习使用GO语言开发链码;
- 第三部分是学习在区块链网络上部署链码。
自身理解
- Fabric使用test-network和docker-compose技术来搭建,比较方便
- Go语言链码开发,需要仔细阅读开发文档,弄清楚链码接口的实现。
- test-network部署链码比较方便。
技术路线
- Docker
Docker是一种虚拟化容器技术,可以创建轻量级容器,将应用包及其依赖打包发布
- Fabric
Hyperledger Fabric是IBM推出的一种新型联盟链,其不以算力竞争来产生新区块。
- Golang
Golang是Google推出的新兴的编程语言
系统平台
- Linux系统版本:Ubuntu 20.04 64位
- Docker版本: Docker version 20.10.12, build 20.10.12-0ubuntu2~20.04.1
- Go语言版本: go1.18.2 linux/arm64
- GoLand版本:2021.2.4
实现过程
Fabric网络搭建
安装docker和docker-compose
apt update
apt install docker.io -y
apt install docker-compose -y
确认Go版本
如果有旧版本的go,先卸载
安装1.18版本的golang
wget https://go.dev/dl/go1.18.2.linux-amd64.tar.gz
tar -C /usr/local -xzf go1.18.2.linux-amd64.tar.gz
vim /etc/profile
# 在文件里添加下面这一行(如果没有)
export PATH=$PATH:/usr/local/go/bin
source /etc/profile
Fabric的下载
由于国内云服务器访问github不稳定,所以从镜像源hub.fastgit.xyz拉取项目
git clone https://hub.fastgit.xyz/hyperledger/fabric.git
拉取完之后,本地出现fabric项目
Fabric-samples的拉取
在 fabric/scripts下有一脚本bootstrap.sh,用于下载fabric-samples测试样例
- 因为脚本当中还是从GitHub拉取项目,所以依然需要改为镜像源
- 一共有三处,不能改少了
- 除了拉取项目以外,这个脚本还会下载测试网络需要的docker images
编辑脚本vim bootstrap.sh
把所以github.com都改成hub.fastgit.xyz
保存退出文件之后,. bootstrap.sh 执行脚本,下载fabric-samples
test-network的基本操作
-
进入fabric-samples/test-network 目录
-
使用
./network.sh up启动网络
看到三个节点容器,网络搭建起来了
3. 使用./network.sh down关闭网络
-
在启动指令后加
createChannel参数, 创建一个通道,默认名称为mychannel,名称全小写 -
在启动指令后加上
-ca标签, 使用ca认证方式启动网络, 使用docker ps查看,发现多了几个ca相关容器 -
在启动指令后加上
-s couchdb参数, 将数据库设为CouchDB
Go语言链码编写
-
要点
- 导入shim和peer包
- 写一个空结构体作为资产
- 编写Init和Invoke方法
- 写实际需要调用的服务
先导入依赖
go get -u github.com/hyperledger/fabric-chaincode-go/shim
go get -u github.com/hyperledger/fabric-protos-go/peer
在main.go里写入下面的内容
package main
import (
"fmt"
"github.com/hyperledger/fabric-chaincode-go/shim"
"github.com/hyperledger/fabric-protos-go/peer"
)
type Asset struct {
// 资产定义
// 空结构体,后面使用
}
//Init 是初始化方法,是必须要实现的
func (a *Asset) Init(stub shim.ChaincodeStubInterface) peer.Response {
// args用字符串切片来存储参数
args := stub.GetStringArgs()
// 参数是键值对,切片长度为2
if len(args)!=2 {
return shim.Error("参数错误 .... ")
}
err := stub.PutState(args[0],[]byte(args[1])) //把键值对传入fabric数据库
if err!=nil {
return shim.Error("创建资产失败: "+args[0])
}
return shim.Success(nil)
}
// Invoke 是调用链码的方式,调用其他函数
func (a *Asset) Invoke(stub shim.ChaincodeStubInterface) peer.Response {
// 拿到函数和参数,我们设定有set函数和get函数,对应键值对的读写
fn,args := stub.GetFunctionAndParameters()
var result string
var err error
if fn == "set" {//调用 set函数
result,err = set(stub,args)
}else {
//那就是get函数
result,err = get(stub,args)
}
if err != nil {
return shim.Error(err.Error())
}
return shim.Success([]byte(result))
}
// 下面是set和get函数的具体实现
// set 存入键值对
func set(stub shim.ChaincodeStubInterface, args []string) (string, error) {
if len(args) != 2 {
return "", fmt.Errorf("参数错误")
}
// 把键值对传入数据库状态
err := stub.PutState(args[0], []byte(args[1]))
if err != nil {
return "", fmt.Errorf("创建资产失败:%s", args[0])
}
return args[1], nil
}
// get 读取键值对
func get(stub shim.ChaincodeStubInterface, args []string) (string, error) {
if len(args) != 1 {
return "", fmt.Errorf("参数错误")
}
value, err := stub.GetState(args[0])
if err != nil {
return "", fmt.Errorf("获取资产失败: %s ,发生错误为: %s", args[0], err)
}
if value == nil {
return "", fmt.Errorf("不存在数据 %s", args[0])
}
return string(value), nil
}
// 在 main函数里启动链码
func main() {
if err := shim.Start(new(Asset)); err != nil {
fmt.Printf("启动链码失败: %s", err)
}
}
链码编写完毕
Go语言链码部署
将自己编写的链码main.go文件放在 fabric-samples/chaincode/ 下(没有就自己创建此文件夹)
- 设置goproxy并下载依赖
export GO111MODULE=on
export GOPROXY=https://proxy.golang.com.cn,direct
go mod tidy
进入测试网络目录
cd test-network
先启动测试网络 . network up createChannel -c testchannel
网络启动好之后,部署链码 . network deployCC -ccn demo -ccl go -ccp ../chaincode/ -c testchannel,使用-c来指定通道名称
测试
设定环境变量
进入fabric-samples/test-network
设定环境变量,使用peer0.org1.example.com 节点身份
export CORE_PEER_TLS_ENABLED=true
export CORE_PEER_LOCALMSPID="Org1MSP"
export CORE_PEER_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt
export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp
export CORE_PEER_ADDRESS=localhost:7051
export FABRIC_CFG_PATH=$PWD/../config/
export PATH=${PWD}/../bin:$PATH
调用链码
调用编写的set函数,传入参数"foo"---"bar",存储此键值对
peer chaincode invoke -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls --cafile "${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem" -C testchannel -n demo --peerAddresses localhost:7051 --tlsRootCertFiles organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt --peerAddresses localhost:9051 --tlsRootCertFiles organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt -c '{"function":"set","Args":["foo","bar"]}'
调用编写的get函数,传入参数“foo"来查存入的值
peer chaincode invoke -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls --cafile "${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem" -C testchannel -n demo --peerAddresses localhost:7051 --tlsRootCertFiles organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt --peerAddresses localhost:9051 --tlsRootCertFiles organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt -c '{"function":"get","Args":["foo"]}'
下面是对这个调用指令的解析
//该指令用于将已经提交到通道的链码进行函数的调用
peer chaincode invoke
//本地端口
-o localhost:7050
//验证TLS连接时使用的排序节点主机名
--ordererTLSHostnameOverride orderer.example.com
//与排序节点通信时使用 TLS
--tls
//包含排序端点的 PEM 编码可信证书的文件路径
--cafile "${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem"
//在哪个通道上执行,应该是已经提交完成的通道上
-C testchannel
//链码名字
-n demo
//要连接的背书节点端口地址 --peerAddresses localhost:7051
//如果TLS启用了,背书节点需要链接到TLS根证书的路径。
--tlsRootCertFiles "${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt"
//第二个背书节点的端口地址
--peerAddresses localhost:9051
//第二个背书节点需要链接到TLS根证书的路径
--tlsRootCertFiles "${PWD}/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt"
//JSON 格式的链码的构造函数消息
-c '{"function":"set","Args":["foo","bar"]}'
总结
- 这里,我们主要实现了Fabric测试网络的部署,以及通过Go编程进行简要的数据交互。
- 从源码搭建Fabric网络需要修改大量的配置,过程复杂,没有基础的掘友可以从测试网络fabric-samples/test-network开始学起,通过对network.sh脚本的阅读,理清fabric网络的启动过程
关于network.sh脚本解析的内容,可以继续阅读 juejin.cn/post/713791…
\