Hyperledger fabric-SDK-GO客户端开发篇(六)

Hyperledger fabric-SDK-GO客户端开发篇(六)

Fabric-SDK-GO是提供的Go语言开发包,应用程序可以利用Fabric-SDK-GO与fabric网络进行交互并访问链码。

软件开发包地址: https://github.com/hyperledger/fabric-sdk-go

1.1、目录介绍

pkg目录是fabric go sdk的主要实现,doc文档介绍了不同目录所提供的功能,以及给出了接口调用样例:

  • pkg/fabsdk:主package,主要用来生成fabsdk以及fabric go sdk中其他pkg使用的option context。
  • pkg/client/channel:主要用来调用、查询Fabric链码,或者注册链码事件。
  • pkg/client/resmgmt:主要用来Hyperledger fabric网络的管理,比如创建通道、加入通道,安装、实例化和升级链码。
  • pkg/client/event:配合channel模块来进行Fabric链码事件的注册和过滤。
  • pkg/client/ledger:主要用来实现Fabric账本的查询,查询区块、交易、配置等。
  • pkg/client/msp:主要用来管理fabric网络中的成员关系。

fabsdk包

  • FabricSDK – sdk入口
  • fabsdk.New() – 创建FabricSDK实例
  • sdk.ChannelContext() – 创建通道上下文实例
  • sdk.Close() – 关闭FabricSDK实例
  • sdk.CloseContext() – 关闭指定的上下文实例
  • sdk.Config() – 创建配置后端实例
  • sdk.Context() – 创建SDK上下文实例
  • fabsdk.ContextOption – SDK上下文配置结构定义
  • fabsdk.WithIdentity() – 创建身份上下文配置对象
  • fabsdk.WithOrg() – 创建机构上下文配置对象
  • fabsdk.WithUser() – 创建用户上下文配置对象
  • fabsdk.Option – SDK配置结构定义
  • fabsdk.WithCorePkg() – 向SDK注入核心包
  • fabsdk.WithCryptoSuiteConfig() – 向SDK注入密码学套件接口
  • fabsdk.WithEndpointConfig() – 向SDK注入端结点配置接口
  • fabsdk.WithErrorHandler() – 设置错误处理程序
  • fabsdk.WithIdentityConfig() – 向SDK注入身份配置接口
  • fabsdk.WithLoggerPkg() – 向SDK注入日志实现
  • fabsdk.WithMSPPkg() – 向SDK注入MSP实现
  • fabsdk.WithMetricsConfig() – 向SDK注入监视指标配置接口
  • fabsdk.WithProviderOpts() – 向提供器添加额外的选项
  • fabsdk.WithServicePkg() – 向SDK注入服务实现

client/channel包

  • channel.Client – 通道客户端结构定义
  • channel.New() – 创建通道客户端
  • cc.Execute() – 执行交易
  • cc.InvokeHandler() – 调用指定的处理器
  • cc.Query() – 查询链码
  • cc.RegisterChaincodeEvent() – 监听链码事件
  • cc.UnregisterChaincodeEvent() – 取消监听链码事件
  • channel.ClientOption – 客户端选项结构定义
  • channel.Request – 链码请求结构定义
  • channle.RequestOption – 链码请求选项函数
  • channel.WithBeforeRetry() – 设置链码请求重试前需调用的函数
  • channel.WithChaincodeFilter() – 为链码请求添加链码过滤器
  • channel.WithParentContext() – 为链码请求封装父级上下文
  • channel.WithRetry() – 为链码请求配置重试参数
  • channel.WithTargetEndpoints() – 为链码请求配置访问端结点
  • channel.WithTargetFilter() – 为特定链码请求指定节点过滤器
  • channel.WithTargetSorter() – 对特定链码请求指定排序器
  • channel.WithTargets() – 为链码请求设置目标peer节点
  • channel.WithTimeout() – 为链码请求设置超时参数
  • channel.Response – 链码响应结构定义

client/event包

  • event.Client – 通道事件客户端结构定义
  • event.New() – 创建通道事件客户端
  • ec.RegisterBlockEvent() – 监听区块事件
  • ec.RegisterChaincodeEvent() – 监听链码事件
  • ec.RegisterFilteredBlockEvent() – 监听过滤的区块事件
  • ec.RegisterTxStatusEvent() – 监听交易状态事件
  • ec.Unregister() – 取消事件监听
  • event.ClientOption – 通道事件客户端选项结构定义
  • event.WithBlockEvents() – 创建监听区块事件的选项
  • event.WithBlockNum() – 只监听指定编号的区块
  • evnet.WithSeekType() – 指定区块定位类型

client/ledger包

  • ledger.Client – 账本客户端结构定义
  • ledger.New() – 创建账本客户端实例
  • lc.QueryBlock() – 按编号查询区块
  • lc.QueryBlockByHash() – 按哈希查询区块
  • lc.QueryBlockByTxID() – 查询包含指定交易的区块
  • lc.QueryConfig() – 查询通道配置
  • lc.QueryConfigBlock() – 查询指定通道的当前配置区块
  • lc.QueryInfo() – 查询指定通道的相关信息
  • lc.QueryTransaction() – 查询指定的交易
  • ClientOption – 账本客户端选项结构定义
  • ledger.WithDefaultTargetFilter – 使用默认的节点过滤器
  • RequestOption – 请求选项函数
  • ledger.WithMaxTargets – 声明每个请求最多可以选择的节点
  • ledger.WithMinTargets – 声明每个请求最少需要的响应
  • ledger.WithParentContext – 使用父级上下文
  • ledger.WithTargetEndpoints – 使用指定的访问端节点
  • ledger.WithTargetFilter – 声明节点选择过滤器
  • ledger.WithTargets – 为特定请求指定目标节点
  • ledger.WithTimeout – 指定账本客户端的超时参数

1.2、一般步骤

  • 编写config.yaml配置文件,给应用程序所使用的 Fabric-SDK-Go 配置相关参数及 Fabric 组件的通信地址
  • 使用配置实例化fabsdk实例。
    注意:fabsdk维护缓存,因此您应尽量减少fabsdk本身的实例。
  • 使用fabsdk实例基于用户和组织创建上下文。
    注意:通道上下文还需要通道ID。
  • 使用其New函数创建一个客户端实例,并传递上下文。
    注意:您需要为每个上下文创建一个新的客户端实例。
  • 使用每个客户提供的功能来创建您的解决方案!
  • 调用fabsdk.Close()释放资源和缓存。

1.3、config.yaml配置文件

client使用sdk与fabric网络交互,需要告诉sdk两类信息:

  • 我是谁:即当前client的信息,包含所属组织、密钥和证书文件的路径等, 这是每个client专用的信息。
  • 对方是谁:即fabric网络结构的信息,channel、org、orderer和peer等 的怎么组合起当前fabric网络的,这些结构信息应当与configytx.yaml中是一致的。这是通用配置,每个客户端都可以拿来使用。另外,这部分信息并不需要是完整fabric网络信息,如果当前client只和部分节点交互,那配置文件中只需要包含所使用到的网络信息。

![](/home/liuhui/文档/hyperledge Fabric/config-yaml.png)

1.4、使用go mod管理项目依赖

fabric go sdk目前本身使用go modules管理依赖,从go.mod可知,依赖的一些包指定了具体的版本, 如果你的项目依赖的版本和fabric go sdk依赖的版本不同,会产生编译问题。

因此建议项目也使用go moudles管理依赖,然后相同的软件包可以使用相同的版本,可以这样操作:

  • go mod init初始化好项目的go.mod文件。
  • 编写代码,完成后运行go mod run,会自动下载依赖的项目,但版本可能与 fabric go sdk中的依赖版本不同,编译存在问题。
  • 把go.mod中的内容复制到项目的go.mod中,然后保存,go mod会自动合并相同的依赖, 运行go mod tidy,会自动添加新的依赖或删除不需要的依赖。

1.5、创建fabric-SDK-GO入口实例

通过config.FromFile解析配置文件,然后通过fabsdk.New创建fabric go sdk的入口实例。

import "github.com/hyperledger/fabric go sdk/pkg/core/config"
import "github.com/hyperledger/fabric go sdk/pkg/fabsdk"
sdk, err := fabsdk.New(config.FromFile(c.ConfigPath))
if err != nil {
log.Panicf("failed to create fabric sdk: %s", err)
}

1.6、创建fabric-SDK-GO的资源管理客户端

管理员账号才能进行Hyperledger fabric网络的管理操作,所以创建资源管理客户端一定要使用管理员账号。

通过 fabsdk.WithOrg("Org1")
fabsdk.WithUser("Admin")
指定Org1的Admin账户,使用 sdk.Context
创建 clientProvider
,然后通过 resmgmt.New
创建fabric-SDK-GO资源管理客户端。

import 	"github.com/hyperledger/fabric go sdk/pkg/client/resmgmt"
rcp := sdk.Context(fabsdk.WithUser("Admin"), fabsdk.WithOrg("Org1"))
rc, err := resmgmt.New(rcp)
if err != nil {
log.Panicf("failed to create resource client: %s", err)
}

1.7、创建fabric-SDK-GO的通道客户端

使用用户账号创建fabric-SDK-GO的通道客户端,以便进行fabric链码的调用和查询。使用sdk.ChannelContext创建channelProvider,需要指定channelID和用户User1,然后通过channel.New创建通道客户端,这个通道客户端就是调用channelID对应channel上链码的channel client。

################两种方法可以创建通道客户端#####################

方法一:

import 	"github.com/hyperledger/fabric go sdk/pkg/client/channel"
ccp := sdk.ChannelContext(ChannelID, fabsdk.WithUser("User1"))
cc, err := channel.New(ccp)
if err != nil {
log.Panicf("failed to create channel client: %s", err)
}

方法二:

// New creates a new Client instance
mspClient, err := mspclient.New(sdk.Context(), mspclient.WithOrg(info.OrgName))
if err != nil {
return fmt.Errorf("根据指定的 OrgName 创建 Org MSP 客户端实例失败: %v", err)
}
//  Returns: signing identity
adminIdentity, err := mspClient.GetSigningIdentity(info.OrgAdmin)
if err != nil {
return fmt.Errorf("获取指定id的签名标识失败: %v", err)
}
// SaveChannelRequest holds parameters for save channel request
channelReq := resmgmt.SaveChannelRequest{ChannelID:info.ChannelID, ChannelConfigPath:info.ChannelConfig, SigningIdentities:[]msp.SigningIdentity{adminIdentity}}
// save channel response with transaction ID
_, err = resMgmtClient.SaveChannel(channelReq, resmgmt.WithRetry(retry.DefaultResMgmtOpts), resmgmt.WithOrdererEndpoint(info.OrdererOrgName))
if err != nil {
return fmt.Errorf("创建应用通道失败: %v", err)
}
fmt.Println("通道已成功创建,")

1.8、peer节点加入通道

// allows for peers to join existing channel with optional custom options (specific peers, filtered peers). If peer(s) are not specified in options it will default to all peers that belong to client's MSP.
err = info.OrgResMgmt.JoinChannel(
info.ChannelID,
resmgmt.WithRetry(retry.DefaultResMgmtOpts),
resmgmt.WithOrdererEndpoint(info.OrdererOrgName)
)
if err != nil {
return fmt.Errorf("Peers加入通道失败: %v", err)
}
fmt.Println("peers 已成功加入通道.")

1.9、资源管理客户端安装链码

安装Fabric链码使用资源管理客户端的InstallCC接口,需要指定resmgmt.InstallCCRequest以及在哪些peers上面安装。resmgmt.InstallCCRequest指明了链码ID、链码路径、链码版本以及打包后的链码。

打包链码需要使用到链码路径CCPath和GoPath,GoPath即本机的$GOPATH,CCPath是相对于GoPath的相对路径,如果路径设置不对,会造成sdk找不到链码。

fmt.Println("开始安装链码......")
// creates new go lang chaincode package
ccPkg, err := gopackager.NewCCPackage(info.ChaincodePath, info.ChaincodeGoPath)
if err != nil {
return nil, fmt.Errorf("创建链码包失败: %v", err)
}
// contains install chaincode request parameters
installCCReq := resmgmt.InstallCCRequest{Name: info.ChaincodeID, Path: info.ChaincodePath, Version: ChaincodeVersion, Package: ccPkg}
/*可以制定安装在哪个peer节点上
reqPeers := resmgmt.WithTargetEndpoints("peer0.org1.example.com")
resps, err := rc.InstallCC(req, reqPeers)
*/
// allows administrators to install chaincode onto the filesystem of a peer
_, err = info.OrgResMgmt.InstallCC(installCCReq, resmgmt.WithRetry(retry.DefaultResMgmtOpts))
if err != nil {
return nil, fmt.Errorf("安装链码失败: %v", err)
}
fmt.Println("指定的链码安装成功")

1.10、资源管理客户端实例化链码

实例化链码需要使用fabric go sdk的资源管理客户端的InstantiateCC接口,需要通过ChannelID、 resmgmt.InstantiateCCRequest和peers,指明在哪个channel上实例化链码,请求包含了链码的ID、路径、版本,以及初始化参数和背书策略,背书策略可以通过cauthdsl.FromString生成。

方法一:

// endorser policy
org1OrOrg2 := "OR('Org1MSP.member','Org2MSP.member')"
ccPolicy, err := cauthdsl.FromString(org1OrOrg2)
if err != nil {
return errors.WithMessage(err, "gen policy from string error")
}
// new request
args := packArgs([]string{"init", "a", "100", "b", "200"})
req := resmgmt.InstantiateCCRequest{
Name:    c.CCID,
Path:    c.CCPath,
Version: v,
Args:    args,
Policy:  ccPolicy,
}
// send request and handle response
reqPeers := resmgmt.WithTargetEndpoints("peer0.org1.example.com")
resp, err := rc.InstantiateCC(ChannelID, req, reqPeers)
if err != nil {
return errors.WithMessage(err, "instantiate chaincode error")
}

方法二:

//  returns a policy that requires one valid
ccPolicy := policydsl.SignedByAnyMember([]string{"org1.kevin.kongyixueyuan.com"})
instantiateCCReq := resmgmt.InstantiateCCRequest{Name: info.ChaincodeID, Path: info.ChaincodePath, Version: ChaincodeVersion, Args: [][]byte{[]byte("init")}, Policy: ccPolicy}
// instantiates chaincode with optional custom options (specific peers, filtered peers, timeout). If peer(s) are not specified
_, err = info.OrgResMgmt.InstantiateCC(info.ChannelID, instantiateCCReq, resmgmt.WithRetry(retry.DefaultResMgmtOpts))
if err != nil {
return nil, fmt.Errorf("实例化链码失败: %v", err)
}
fmt.Println("链码实例化成功")

1.11、资源管理客户端升级链码

升级链码和实例化链码是非常相似的,不同点只在请求是resmgmt.UpgradeCCRequest,调用的接口是rc.UpgradeCC:

// endorser policy
org1AndOrg2 := "AND('Org1MSP.member','Org2MSP.member')"
ccPolicy, err := c.genPolicy(org1AndOrg2)
if err != nil {
return errors.WithMessage(err, "gen policy from string error")
}
// new request
args := packArgs([]string{"init", "a", "100", "b", "200"})
req := resmgmt.UpgradeCCRequest{
Name:    c.CCID,
Path:    c.CCPath,
Version: v,
Args:    args,
Policy:  ccPolicy,
}
// send request and handle response
reqPeers := resmgmt.WithTargetEndpoints("peer0.org1.example.com")
resp, err := rc.UpgradeCC(ChannelID, req, reqPeers)
if err != nil {
return errors.WithMessage(err, "instantiate chaincode error")
}

1.12、通道客户端调用链码

使用通道客户端的Execute接口调用链码,使用入参channel.Request和peers指明要让哪些peer上执行链码,进行背书。channel.Request指明了要调用的链码,以及链码内要Invoke的函数args,args是序列化的结果,序列化是自定义的,只要链码能够按相同的规则进行反序列化即可。

// new channel request for invoke
args := packArgs([]string{"a", "b", "10"})
req := channel.Request{
ChaincodeID: c.CCID,
Fcn:         "invoke",
Args:        args,
}
// send request and handle response
// peers is needed
reqPeers := channel.WithTargetEndpoints("peer0.org1.example.com")
resp, err := cc.Execute(req, reqPeers)
if err != nil {
return errors.WithMessage(err, "invoke chaincode error")
}
log.Printf("invoke chaincode tx: %s", resp.TransactionID)

1.13、通道客户端查询链码

查询和调用链码是非常相似的,使用相同的channel.Request,指明了Invoke链码中的query函数,然后调用cc.Query进行查询操作,这样节点不会对请求进行背书:

// new channel request for query
req := channel.Request{
ChaincodeID: c.CCID,
Fcn:         "query",
Args:        packArgs([]string{keys}),
}
// send request and handle response
reqPeers := channel.WithTargetEndpoints(peer)
resp, err := cc.Query(req, reqPeers)
if err != nil {
return errors.WithMessage(err, "query chaincode error")
}
log.Printf("query chaincode tx: %s", resp.TransactionID)
log.Printf("result: %v", string(resp.Payload))

1.14、综合示例

(1)客户端实现

/**
author: liuhui
*/
package sdkInit
import (
"fmt"
"github.com/astaxie/beego/logs"
mspclient "github.com/hyperledger/fabric-sdk-go/pkg/client/msp"
"github.com/hyperledger/fabric-sdk-go/pkg/client/resmgmt"
"github.com/hyperledger/fabric-sdk-go/pkg/common/errors/retry"
"github.com/hyperledger/fabric-sdk-go/pkg/common/providers/msp"
"github.com/hyperledger/fabric-sdk-go/pkg/core/config"
"github.com/hyperledger/fabric-sdk-go/pkg/fabsdk"
"github.com/hyperledger/fabric-sdk-go/pkg/client/channel"
"github.com/hyperledger/fabric-sdk-go/pkg/fab/ccpackager/gopackager"
"github.com/hyperledger/fabric-sdk-go/third_party/github.com/hyperledger/fabric/common/policydsl"
)
const ChaincodeVersion = "1.0"
//initialized fabric sdk
func SetupSDK(ConfigFile string, initialized bool) (*fabsdk.FabricSDK, error) {
if initialized {
//logs.Error("Fabric SDK has been initialized")
return nil, fmt.Errorf("Fabric SDK has been initialized")
}
sdk, err := fabsdk.New(config.FromFile(ConfigFile))
if err != nil {
//logs.Error("Instantiation Fabric SDK failed")
return nil, fmt.Errorf("Instantiation Fabric SDK failed: %v", err)
}
logs.Informational("Fabric SDK is initialized successfully")
return sdk, nil
}
// create channel and join peers
func CreateChannel(sdk *fabsdk.FabricSDK, info *InitInfo) error {
clientContext := sdk.Context(fabsdk.WithUser(info.OrgAdmin), fabsdk.WithOrg(info.OrgName))
if clientContext == nil {
return fmt.Errorf("Failed to create client context based on organization name and administrator user")
}
// New returns a resource management client instance.
resMgmtClient, err := resmgmt.New(clientContext)
if err != nil {
return fmt.Errorf("Failed to create resource management client by client context: %v", err)
}
// New creates a new Client instance
mspClient, err := mspclient.New(sdk.Context(), mspclient.WithOrg(info.OrgName))
if err != nil {
return fmt.Errorf("Failed to create Org MSP client by specified OrgName: %v", err)
}
//  Returns: signing identity
adminIdentity, err := mspClient.GetSigningIdentity(info.OrgAdmin)
if err != nil {
return fmt.Errorf("Failed to get the signature of the specified ID: %v", err)
}
// SaveChannelRequest holds parameters for save channel request
channelReq := resmgmt.SaveChannelRequest{ChannelID: info.ChannelID, ChannelConfigPath: info.ChannelConfig, SigningIdentities: []msp.SigningIdentity{adminIdentity}}
// save channel response with transaction ID
_, err = resMgmtClient.SaveChannel(channelReq, resmgmt.WithRetry(retry.DefaultResMgmtOpts), resmgmt.WithOrdererEndpoint(info.OrdererOrgName))
if err != nil {
return fmt.Errorf("Failed to create channle: %v", err)
}
logs.Informational("Create channel successful")
info.OrgResMgmt = resMgmtClient
// allows for peers to join existing channel with optional custom options (specific peers, filtered peers). If peer(s) are not specified in options it will default to all peers that belong to client's MSP.
err = info.OrgResMgmt.JoinChannel(info.ChannelID, resmgmt.WithRetry(retry.DefaultResMgmtOpts), resmgmt.WithOrdererEndpoint(info.OrdererOrgName))
if err != nil {
return fmt.Errorf("Peers failed to join channel: %v", err)
}
logs.Informational("Peers join channel successful")
return nil
}
//install and instantiate chaincode
func InstallAndInstantiateCC(sdk *fabsdk.FabricSDK, info *InitInfo) (*channel.Client, error) {
logs.Informational("Start to install chaincode")
// creates new go lang chaincode package
ccPkg, err := gopackager.NewCCPackage(info.ChaincodePath, info.ChaincodeGoPath)
if err != nil {
return nil, fmt.Errorf("Failed to create chaincode package: %v", err)
}
// contains install chaincode request parameters
installCCReq := resmgmt.InstallCCRequest{Name: info.ChaincodeID, Path: info.ChaincodePath, Version: ChaincodeVersion, Package: ccPkg}
// allows administrators to install chaincode onto the filesystem of a peer
_, err = info.OrgResMgmt.InstallCC(installCCReq, resmgmt.WithRetry(retry.DefaultResMgmtOpts))
if err != nil {
return nil, fmt.Errorf("Failed to install chaincode: %v", err)
}
logs.Informational("Install chaincode successful")
logs.Informational("Start to instantiate chaincode")
//  returns a policy that requires one valid
ccPolicy := policydsl.SignedByAnyMember([]string{"org1.institution.com"})
instantiateCCReq := resmgmt.InstantiateCCRequest{Name: info.ChaincodeID, Path: info.ChaincodePath, Version: ChaincodeVersion, Args: [][]byte{[]byte("init")}, Policy: ccPolicy}
// instantiates chaincode with optional custom options (specific peers, filtered peers, timeout). If peer(s) are not specified
_, err = info.OrgResMgmt.InstantiateCC(info.ChannelID, instantiateCCReq, resmgmt.WithRetry(retry.DefaultResMgmtOpts))
if err != nil {
return nil, fmt.Errorf("Failed to instantiate chaincode: %v", err)
}
logs.Informational("Instantiate chaincode successful")
clientChannelContext := sdk.ChannelContext(info.ChannelID, fabsdk.WithUser(info.UserName), fabsdk.WithOrg(info.OrgName))
// returns a Client instance. Channel client can query chaincode, execute chaincode and register/unregister for chaincode events on specific channel.
channelClient, err := channel.New(clientChannelContext)
if err != nil {
return nil, fmt.Errorf("Failed to create channel context: %v", err)
}
logs.Informational("Create channel client successful ,you can use it to execute transactions.")
return channelClient, nil
}
func ChannelClient(sdk *fabsdk.FabricSDK, info *InitInfo) (*channel.Client,error){
clientChannelContext := sdk.ChannelContext(info.ChannelID, fabsdk.WithUser(info.UserName), fabsdk.WithOrg(info.OrgName))
// returns a Client instance. Channel client can query chaincode, execute chaincode and register/unregister for chaincode events on specific channel.
channelClient, err := channel.New(clientChannelContext)
if err != nil {
return nil, fmt.Errorf("Failed to create channel context: %v", err)
}
logs.Informational("Create channel client successful ,you can use it to execute transactions.")
return channelClient, nil
}

(2)调用客户端

package main
import (
"github.com/astaxie/beego"
"github.com/astaxie/beego/logs"
_ "github.com/lib/pq"
"jingjinjiapi/controllers"
_ "jingjinjiapi/routers"
"jingjinjiapi/sdkInit"
"os"
)
const (
//config of SDK
configFile = "config.yaml"
//mark whehter the client is initialized
initialized = false
//the chaincode id
EduCC = "educc"
DOC_TYPE = "insObj"
)
func main() {
//setting loggers level and location
logs.SetLogger("file", `{"filename":"logs/jingjinji_beego.log"}`)
logs.SetLevel(logs.LevelInformational)
logs.Info("setting logs level : information")
//initialized the information of sdk
initInfo := &sdkInit.InitInfo{
ChannelID:     "institutionchannel",
ChannelConfig: os.Getenv("GOPATH") + "/src/jingjinjiapi/fixtures/artifacts/channel.tx",
OrgAdmin:       "Admin",
OrgName:        "Org1",
OrdererOrgName: "orderer.institution.com",
ChaincodeID:     EduCC,
ChaincodeGoPath: os.Getenv("GOPATH"),
ChaincodePath:   "jingjinjiapi/chaincode/",
UserName:        "User1",
}
var serviceSetup controllers.ServiceSetup
//initialize SDK,use the function:fabsdk.new
sdk, err := sdkInit.SetupSDK(configFile, initialized)
if err != nil {
logs.Error(err.Error())
return
}
//free the resource until the main program finish
defer sdk.Close()
flag := false
if flag{
//create channel and add the peer node to the channel
err = sdkInit.CreateChannel(sdk, initInfo)
if err != nil {
logs.Error(err.Error())
return
}
//install chaincode and instantiate chaincode
channelClient, err := sdkInit.InstallAndInstantiateCC(sdk, initInfo)
if err != nil {
logs.Error(err.Error())
return
}
serviceSetup.ChaincodeID = EduCC
serviceSetup.Client = channelClient
}else{
channelClient, err := sdkInit.ChannelClient(sdk,initInfo)
if err != nil {
logs.Error(err.Error())
return
}
serviceSetup.ChaincodeID = EduCC
serviceSetup.Client = channelClient
}
logs.Informational(serviceSetup)
//===========================================//
//start Testing .............................................
//start service
beego.Router("/v1/institution", &controllers.InstitutionController{Setup: &serviceSetup})
}
博客园精华区
我还没有学会写个人说明!
上一篇

一篇文章带你了解Go语言基础之并发(channel)

下一篇

宇航员在ISS庆祝节日:享用大餐、电话联系亲朋好友

你也可能喜欢

评论已经被关闭。

插入图片