使用fabric-sdk-go操作链码
前言
本文把与fabric网络交互的baas、应用程序、客户端统称成为客户端,它们可以使用sdk和fabric网络进行交互,sdk调用grpc可以与指定的peer和orderer进行通信,本文的目的是在BYFN搭建的fabric网络的基础之上,展示如何使用fabric-sdk-go操作链码。
fabric-sdk-go项目简介
fabric-sdk-go是Fabric官方的Go语言SDK,它的目录结构如下:
有2个目录需要注意一下,internal和third_party,它们两个包含了sdk依赖的一些代码,来自于fabric、fabric-ca,当使用到fabric的一些类型时,应当使用以下的方式,而不是直接导入fabric或者fabric-ca:
1 | import "github.com/hyperledger/fabric-sdk-go/third_party/github.com/hyperledger/fabric/xxx" |
pkg目录是sdk的主要实现,doc 文档介绍了不同目录所提供的功能,以及给出了接口调用样例:
- pkg/fabsdk:主package,主要用来生成fabsdk以及各种其他pkg使用的option context。
- pkg/client/channel:主要用来调用、查询链码,或者注册链码事件。
- pkg/client/resmgmt:主要用来fabric网络的管理,比如创建、加入通道,安装、实例化和升级链码。
- pkg/client/event:配合channel模块来进行链码事件注册和过滤。
- pkg/client/ledger:主要用来账本的查询,查询区块、交易、配置等。
- pkg/client/msp:主要用来管理fabric的成员关系。
想用好fabric-go-sdk,建议仔细看看doc 文档。
使用SDK步骤
- 为client编写配置文件config.yaml
- 为client创建fabric sdk实例fabsdk
- 为client创建resource manage client,简称RC,RC用来进行管理操作的client,比如通道的创建,链码的安装、实例化和升级等
- 为client创建channel client,简称CC,CC用来链码的调用、查询以及链码事件的注册和取消注册
SDK配置文件config.yaml
client使用sdk与fabric网络交互,需要告诉sdk两类信息:
- 我是谁:即当前client的信息,包含所属组织、密钥和证书文件的路径等,这是每个client专用的信息。
- 对方是谁:即fabric网络结构的信息,channel、org、orderer和peer等的怎么组合起当前fabric网络的,这些结构信息应当与
configytx.yaml
中是一致的。这是通用配置,每个客户端都可以拿来使用。另外,这部分信息并不需要是完整fabric网络信息,如果当前client只和部分节点交互,那配置文件中只需要包含所使用到的网络信息。
这里提供一个适合BFYN的精简配置文件fabric-sdk-go-sample/config.yaml。
使用go mod管理依赖
fabric-sdk-go目前本身使用go modules管理依赖,从go.mod可知,依赖的一些包指定了具体的版本,如果项目依赖的版本和sdk依赖的版本不同,会产生编译问题。
建议项目也使用go moudles管理依赖,然后相同的软件包可以使用相同的版本,可以这样操作:
- go mod init初始化好项目的go.mod文件。
- 编写代码,完成后运行go mod run,会自动下载依赖的项目,但版本可能与fabric-sdk-go中的依赖版本不同,编译存在问题。
- 把go.mod中的内容复制到项目的go.mod中,然后保存,go mod会自动合并相同的依赖,运行go mod tidy,会自动添加新的依赖或删除不需要的依赖。
项目的go mod样例可以参考securekey/fabric-examples … /go.mod,shitaibin/fabric-sdk-go-sample/go.mod。
创建Client
利用config.yaml创建fabsdk
通过config.FromFile
解析配置文件,然后通过fabsdk.New
创建sdk实例。
1 | import "github.com/hyperledger/fabric-sdk-go/pkg/core/config" |
创建RC
管理员账号才能进行fabric网络的管理操作,所以创建rc一定要使用管理员账号。
通过fabsdk.WithOrg("Org1")
和fabsdk.WithUser("Admin")
指定Org1的Admin账户,使用sdk.Context
创建clientProvider,然后通过resmgmt.New
创建rc。
1 | import "github.com/hyperledger/fabric-sdk-go/pkg/client/resmgmt" |
创建CC
创建cc使用用户账号,进行链码的调用和查询,使用sdk.ChannelContext
创建channelProvider,需要指定channelID和用户User1,然后通过channel.New
创建cc,此cc就是调用channelID对应channel上链码的channel client。
1 | import "github.com/hyperledger/fabric-sdk-go/pkg/client/channel" |
管理操作
安装链码
安装链码使用rc.InstallCC
接口,需要指定resmgmt.InstallCCRequest
以及在哪些peers上面安装。resmgmt.InstallCCRequest
指明了链码ID、链码路径、链码版本以及打包后的链码。
打包链码需要使用到链码路径CCPath
和GoPath
,GoPath
即本机的$GOPATH
,CCPath
是相对于GoPath
的相对路径,如果路径设置不对,会造成sdk找不到链码。
1 | // pack the chaincode |
实例化链码
实例化链码需要使用rc.InstantiateCC
接口,需要通过ChannelID、resmgmt.InstantiateCCRequest
和peers,指明在哪个channel上实例化链码,请求包含了链码的ID、路径、版本,以及初始化参数和背书策略,背书策略可以通过cauthdsl.FromString
生成。
1 | // endorser policy |
升级链码
升级链码和实例化链码是非常相似的,不同点只在请求是resmgmt.UpgradeCCRequest
,调用的接口是rc.UpgradeCC
。
1 | // endorser policy |
查询操作
调用链码
调用链码使用cc.Execute
接口,使用入参channel.Request
和peers指明要让哪些peer上执行链码,进行背书。channel.Request
指明了要调用的链码,以及链码内要Invoke的函数args,args是序列化的结果,序列化是自定义的,只要链码能够按相同的规则进行反序列化即可。
1 | // new channel request for invoke |
查询链码
查询和调用链码是非常相似的,使用相同的channel.Request
,指明了Invoke链码中的query
函数,然后调用cc.Query
进行查询操作,这样节点不会对请求进行背书。
1 | // new channel request for query |
示例项目
本文的基础是创建了一个结合fabric byfn的示例项目,在byfn的基础之上对链码进行安装、实例化、升级,调用和查询等操作,项目的使用可见项目README文档,项目地址:https://github.com/Shitaibin/fabric-sdk-go-sample ,项目样例执行后,可见新部署和升级成功的链码容器,操作日志可见项目。