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}) }

Hyperledger fabric-SDK-GO客户端开发篇(六)的更多相关文章

  1. 区块链:基于Hyperledger Fabric的 java 客户端开发(java sdk /java api server/java event server)

    fabric针对java 开发的部分支持不是很友好.基于目前较为稳定的fabric 1.4版本,我们封装了一个java sdk,apiserver,eventServer 封装java sdk的主要目 ...

  2. HyperLedger/Fabric SDK使用Docker容器镜像快速部署上线

    HyperLedger/Fabric SDK Docker Image 该项目在github上的地址是:https://github.com/aberic/fabric-sdk-container ( ...

  3. ubuntu16.04 HyperLedger Fabric 1.2.0 开发环境搭建

    安装准备 1. 安装git.cRUL.gcc/g++和make $ sudo apt-get update $ sudo apt-get install build-essential git cur ...

  4. Hyperledger Fabric SDK use case 1

    ///////////////////////////////////////////////////////////////////////:End2endAndBackAgainIT 1.Crea ...

  5. Android NDK开发篇(六):Java与原生代码通信(异常处理)

    一.捕获异常 异常处理是Java中的功能.在Android中使用SDK进行开发的时候常常要用到.Android原生代码在运行过程中假设遇到错误,须要检測,并抛出异常给Java层.运行原生代码出现了问题 ...

  6. 指令汇B新闻客户端开发(六) 浅谈屏幕适配解决方案

    屏幕适配的问题,我相信很多大牛的经验远比我丰富,在此就简单的分享一下我所做的的屏幕适配方案,当然我说的是安卓方面的啦,嘿嘿,屏幕适配我们一般用1280*720的屏幕作为我们的主流开发屏,当然现在And ...

  7. 搭建基于hyperledger fabric的联盟社区(六) --搭建node.js服务器

    接下来我要做的是用fabric sdk来做出应用程序,代替CLI与整个区块链网络交互.并且实现一个http API,向社区提供一个简单的接口,使社区轻松的与区块链交互. 官方虽然提供了Node.JS, ...

  8. hyperledger fabric超级账本java sdk样例e2e代码流程分析

     一  checkConfig  Before     1.1  private static final TestConfig testConfig = TestConfig.getConfig() ...

  9. Hyperledger Fabric 1.0 从零开始(十二)——fabric-sdk-java应用

    Hyperledger Fabric 1.0 从零开始(十)--智能合约 Hyperledger Fabric 1.0 从零开始(十一)--CouchDB 上述两章,最近网上各路大神文章云集,方案多多 ...

随机推荐

  1. 记一次腾讯TBS浏览服务集成实践

    这次的分享源于最近的实际开发工作. 项目需求是 在原生Android应用中嵌入WebView,放置用于支撑音视频直播业务的Web页: 另外还需提供Word.Excel.PowerPoint.PDF等常 ...

  2. Android中Application的意义及使用方法

    首先,在一个Android程序中,有且只有一个Application对象,在程序启动的时候,首先执行Application的onCreate方法,这是一个Android应用的入口,在开发中,我们常常自 ...

  3. 转:为什么浏览器的user-agent字符串以'Mozilla'开头呢?

    本文转自:https://blog.csdn.net/S_gy_Zetrov/article/details/79463093 感谢sgyzetrov翻译 如果熟悉元素审查的童鞋,很多都会发现requ ...

  4. 关于RequestParam在不同的Spring版本上,接口在controller重载时注解可能失效的踩坑记录

    先抛背景: 我项目中的Spring版本是2.0.3.RELEASE. api-demo负责暴露接口,service-demo负责实现功能.接口参数的@RequestParam和@RequestBody ...

  5. John the Ripper快速密码破解工具简单使用

    在某场比赛中师傅们说需要用到该工具,学习之 题目给了我们一个流量包,分析 发现 .hint.php.swp文件 该文件是使用 vim 编辑文件时异常退出而产生的,可以通过 vim -r 文件名 进行相 ...

  6. 云服务器AWD平台搭建

    开学后实验室来了几个新同学,在线上CTF方面大家一直在持续学习,但AWD模式的CTF我们练习并不多,所以准备搭建一个AWD平台用于实验室成员的线下赛攻防练习. 最开始的是防灾科技大学的线下AWD靶场: ...

  7. 小程序editor篇-基本使用图片上传

    今天小程序项目内,要弄一个editor,富文本编辑功能,支持图文并茂,前几天刚好看了小程序的demo应用,刚好看到editor这个东东,那就安排! 官网示例git地址 大概看了下文档,拉下官方示例,看 ...

  8. 漫话docker的衰落与kubernetes的兴起

    本文首发在OPPO互联网公众号,欢迎点击转载 https://mp.weixin.qq.com/s/wBC4CgAzXeTNURa1YdYmIQ. 伴随着kubernetes 1.20中对于docke ...

  9. angular 双向数据绑定与vue数据的双向数据绑定

    二者都是 MVVM 模式开发的典型代表 angular 是通过脏检测实现,angular 会将 UI 事件,请求事件,settimeout 这类延迟的对象放入到事件监测的脏队列,当数据变化的时候,触发 ...

  10. 能否让APP永不崩溃—小光与我的对决

    前言 关于拦截异常,想必大家都知道可以通过Thread.setDefaultUncaughtExceptionHandler来拦截App中发生的异常,然后再进行处理. 于是,我有了一个不成熟的想法.. ...