现在CLI
,链码都有了,但是还不能将它们联系起来,上一篇调用链码还需要使用命令行来测试,这篇实现通过代码代用链码
一、安装初始化链码
安装、执行链码需要有一个客户端对象并指定链码名称,链码路径和版本,所以需要对FabricSetup
结构体进行修改
打开startInit.go
文件
修改FabricSetup
结构体
type FabricSetup struct {
//应用配置文件路径
ConfigFile string
//通道ID
ChannelID string
//sdk是否已初始化过,若已初始化,不再做初始化操作
Initialized bool
//通道配置文件路径
ChannelConfig string
//组织管理员账户名
OrgAdmin string
//组织名
OrgName string
//ResourceMgmtClient 使用'github.com/hyperledger/fabric-sdk-go/api/apitxn/resmgmtclient'包下的结构体,不要搞错
Admin resmgmtclient.ResourceMgmtClient
sdk *fabsdk.FabricSDK
//链码所需参数
ChaincodeID string //链码名称
ChaincodeGoPath string //系统GOPATH路径
ChaincodePath string //链码所在路径
ChaincodeVersion string //链码版本
//执行链码的用户名
UserName string
//chclient.ChannelClient 使用的是 "github.com/hyperledger/fabric-sdk-go/api/apitxn/chclient" 包下的结构体
Client chclient.ChannelClient
}
添加方法InstallAndInstantiateCC
安装和实例化链码
func (t *FabricSetup) InstallAndInstantiateCC()error {
fmt.Println("开始安装链码...")
//对链码进行打包
ccPkg,err := gopackager.NewCCPackage(t.ChaincodePath,t.ChaincodeGoPath)
if err != nil {
return fmt.Errorf("创建指定的链码包失败%s",err.Error())
}
//指定安装链码时的所需参数
installCCRequest := resmgmtclient.InstallCCRequest{
Name:t.ChaincodeID,
Path:t.ChaincodePath,
Version:t.ChaincodeVersion,
Package:ccPkg,
}
//安装链码
_,err = t.Admin.InstallCC(installCCRequest)
if err != nil {
return fmt.Errorf("安装链码失败%s",err.Error())
}
fmt.Println("安装链码成功")
fmt.Println("开始实例化链码...")
//指定链码策略
//cauthdsl.SignedByAnyMember 使用 "github.com/hyperledger/fabric-sdk-go/third_party/github.com/hyperledger/fabric/common/cauthdsl"包下的
ccPolicy := cauthdsl.SignedByAnyMember([]string{"Org1MSP"})
//指定实例化链码时的所需参数
instantiateCCReq := resmgmtclient.InstantiateCCRequest{
Name:t.ChaincodeID,
Path:t.ChaincodePath,
Version:t.ChaincodeVersion,
Args:[][]byte{[]byte("init")},
Policy:ccPolicy,
}
err = t.Admin.InstantiateCC(t.ChannelID,instantiateCCReq)
if err != nil {
return fmt.Errorf("实例化链码失败%s",err.Error())
}
fmt.Println("实例化链码成功")
//创建客户端对象,能够通过该对象执行链码查询及事务执行
t.Client,err = t.sdk.NewClient(fabsdk.WithUser(t.UserName)).Channel(t.ChannelID)
if err != nil {
return fmt.Errorf("创建新的通道客户端失败:%s",err.Error())
}
fmt.Println("链码安装实例化完成,且成功创建客户端对象")
return nil
}
二、service
1、准备数据
新建domain.go
package Service
import "zhq/bill/Blockchain"
type FabricSetupService struct {
Setup *Blockchain.FabricSetup
}
// 票据数据结构
type Bill struct {
BillInfoID string `json:"BillInfoID"` // 票据号码
BillInfoAmt string `json:"BillInfoAmt"` // 票据金额
BillInfoType string `json:"BillInfoType"` // 票据类型
BillInfoIsseDate string `json:"BillInfoIsseDate"` // 票据出票日期
BillInfoDueDate string `json:"billInfoDueDate"` // 票据到期日期
DrwrCmID string `json:"DrwrCmID"` // 出票人证件号码
DrwrAcct string `json:"DrwrAcct"` // 出票人名称
AccptrCmID string `json:"AccptrCmID"` // 承兑人证件号码
AccptrAcct string `json:"AccptrAcct"` // 承兑人名称
PyeeCmID string `json:"PyeeCmID"` // 收款人证件号码
PyeeAcct string `json:"PyeeAcct"` // 收款人名称
HoldrCmID string `json:"HodrCmID"` // 当前持票人证件号码
HoldrAcct string `json:"HodrAcct"` // 当前持票人名称
WaitEndorseCmID string `json:"WaitEndorseCmID"` // 待背书人证件号码
WaitEndorseAcct string `json:"WaitEndorseAcct"` // 待背书人名称
RejectEndorseCmID string `json:"RejectEndorseCmID"` // 拒绝背书人证件号码
RejectEndorseAcct string `json:"RejectEndorseAcct"` // 拒绝背书人名称
State string `json:"State"` // 票据状态
History []HistoryItem `json:"History"` // 票据背书历史
}
// 票据历史信息
type HistoryItem struct {
TxId string `json:"TxId"`
Bill Bill `json:"bill"`
}
-
FabricSetupService
结构体存储的是初始化SDK时实例的FabricSetup
对象,里面包含通道、节点等一些需要用到的数据 -
Bill
结构体与链码中定义的结构体一致
2、调用链码
新建billService.go
- 发布票据
func (t *FabricSetupService) IssueBill(bill Bill) (string, error) {
//序列化票据
b, err := json.Marshal(bill)
if err != nil {
return "", fmt.Errorf("指定的票据对象序列化错误:%s",err.Error())
}
//指定调用链码时的请求参数
req := chclient.Request{
ChaincodeID: t.Setup.ChaincodeID,
Fcn: "issue",
Args: [][]byte{b},
}
//使用实例化链码时创建的客户端对象执行链码
response,err := t.Setup.Client.Execute(req)
if err != nil {
return "",fmt.Errorf("保存票据信息失败:%s",err.Error())
}
//返回交易ID和错误信息
return response.TransactionID.ID,nil
}
- req := chclient.Request{ ChaincodeID: t.Setup.ChaincodeID, Fcn: “issue”, Args: [][]byte{b}, } 设置请求参数,
ChaincodeID
:链码ID,Fcn
:执行的方法名,Args
:指定参数- response,err := t.Setup.Client.Execute(req)
Execute
对应的还有Query
,一个相当于set
一个是get
,区别在于会不会生成新的交易
- 查询用户所有订单
func (t *FabricSetupService)QueryBill(holderCmId string)([]byte,error) {
var args []string
args = append(args,"queryMyBills")
args = append(args,holderCmId)
req := chclient.Request{
ChaincodeID:t.Setup.ChaincodeID,
Fcn:args[0],
Args:[][]byte{[]byte(holderCmId)},
}
response,err := t.Setup.Client.Query(req)
if err != nil {
return nil,fmt.Errorf("根据持票人证件号查询票据失败:%s",err.Error())
}
b := response.Payload
return b[:],nil
}
其余5个方法,跟这两个类似,只需要改Fcn
和形参就可以了
三、测试
修改工程目录下的main.go
func main() {
setup := Blockchain.FabricSetup{
//组织内管理员用户
OrgAdmin: "Admin",
//组织ID
OrgName: "Org1",
//通道ID
ChannelID: "mychannel",
//应用配置文件路径
ConfigFile: "config.yaml",
//通道配置文件路径
ChannelConfig: os.Getenv("GOPATH") + "/src/zhq/bill/fixtures/artifacts/channel.tx",
//链码相关
ChaincodeID: "bill",
ChaincodeGoPath: os.Getenv("GOPATH"),
ChaincodePath: "zhq/bill/ChainCode",
ChaincodeVersion: "1.0",
UserName: "User1",
}
err := setup.Initialize()
if err != nil {
fmt.Println(err)
}
//安装实例化链码
err = setup.InstallAndInstantiateCC()
if err != nil {
fmt.Printf("链码安装实例化发生错误:%s",err.Error())
}
serv := new(Service.FabricSetupService)
serv.Setup = &setup
//测试数据
bill := Service.Bill{
BillInfoID: "123456",
BillInfoAmt: "10",
BillInfoType: "liangpiao",
BillInfoIsseDate: "20180702",
BillInfoDueDate: "20190702",
DrwrCmID: "120xxxxxxx",
DrwrAcct: "zhq",
AccptrCmID: "accp120xxxxx",
AccptrAcct: "AccpName",
PyeeCmID: "Pyee120xxxxx",
PyeeAcct: "PyeeName",
HoldrCmID: "120xxxxxxx",
HoldrAcct: "zhq",
WaitEndorseCmID: "",
WaitEndorseAcct: "",
RejectEndorseCmID: "",
RejectEndorseAcct: "",
State: "",
History: nil,
}
response, err := serv.IssueBill(bill)
if err != nil {
fmt.Println(err)
} else {
fmt.Println("交易ID:", response)
}
b, err := serv.QueryBill("120xxxxxxx")
if err != nil {
fmt.Errorf(err.Error())
} else {
var bills = []Service.Bill{}
json.Unmarshal(b, &bills)
for _, temp := range bills {
fmt.Println(temp)
}
}
b, err = serv.QueryBillByNo("123456")
if err != nil {
fmt.Errorf(err.Error())
} else {
var result Service.Bill
json.Unmarshal(b, &result)
fmt.Println(result)
for _, history := range result.History {
fmt.Println(history)
}
}
//发起背书
res, err := serv.Endorse("123456", "pei120xxxxxx", "pei")
if err != nil {
fmt.Println(err)
} else {
fmt.Println(res)
}
//
b, err = serv.QueryMyWaitBills("pei120xxxxxx")
if err != nil {
fmt.Println(err.Error())
} else {
var bills = []Service.Bill{}
json.Unmarshal(b, &bills)
for _, temp := range bills {
fmt.Println(temp)
}
}
//签收票据
res, err = serv.Accept("123456", "pei120xxxxxx", "pei")
if err != nil {
fmt.Println(err)
} else {
fmt.Println(res)
}
//拒签票据
res, err = serv.Accept("123456", "pei120xxxxxx", "pei")
if err != nil {
fmt.Println(err)
} else {
fmt.Println(res)
}
}
cd $GOPATH/src/zhq/bill go build make
如果运行没有问题将会输出