安装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、综合示例