您现在的位置是:首页 > 文章详情

区块链教程Fabric1.0源代码分析链码 链码语言平台-兄弟连

日期:2018-10-28点击:427

Fabric 1.0源代码笔记 之 Chaincode(链码) #platforms(链码语言平台)

1、platforms概述

platforms代码集中在core/chaincode/platforms目录下。

  • core/chaincode/platforms目录,链码的编写语言平台实现,如golang或java。
        * platforms.go,Platform接口定义,及platforms相关工具函数。

    * util目录,Docker相关工具函数。
    * java目录,java语言平台实现。
    * golang目录,golang语言平台实现。
    

2、Platform接口定义

type Platform interface {     //验证ChaincodeSpec     ValidateSpec(spec *pb.ChaincodeSpec) error     //验证ChaincodeDeploymentSpec     ValidateDeploymentSpec(spec *pb.ChaincodeDeploymentSpec) error     //获取部署Payload     GetDeploymentPayload(spec *pb.ChaincodeSpec) ([]byte, error)     //生成Dockerfile     GenerateDockerfile(spec *pb.ChaincodeDeploymentSpec) (string, error)     //生成DockerBuild     GenerateDockerBuild(spec *pb.ChaincodeDeploymentSpec, tw *tar.Writer) error } //代码在core/chaincode/platforms/platforms.go

3、platforms相关工具函数

3.1、platforms相关工具函数

//按链码类型构造Platform接口实例,如golang.Platform{} func Find(chaincodeType pb.ChaincodeSpec_Type) (Platform, error) //调取platform.GetDeploymentPayload(spec),获取部署Payload func GetDeploymentPayload(spec *pb.ChaincodeSpec) ([]byte, error) //优先获取tls根证书,如无则获取tls证书 func getPeerTLSCert() ([]byte, error) //调取platform.GenerateDockerfile(cds),创建Dockerfile func generateDockerfile(platform Platform, cds *pb.ChaincodeDeploymentSpec, tls bool) ([]byte, error) //调取platform.GenerateDockerBuild(cds, tw),创建DockerBuild func generateDockerBuild(platform Platform, cds *pb.ChaincodeDeploymentSpec, inputFiles InputFiles, tw *tar.Writer) error //调取generateDockerfile(platform, cds, cert != nil) func GenerateDockerBuild(cds *pb.ChaincodeDeploymentSpec) (io.Reader, error) //代码在core/chaincode/platforms/platforms.go

3.2、Docker相关工具函数

//contents+hash合并后再哈希 func ComputeHash(contents []byte, hash []byte) []byte //哈希目录下文件并打包 func HashFilesInDir(rootDir string, dir string, hash []byte, tw *tar.Writer) ([]byte, error) //目录是否存在 func IsCodeExist(tmppath string) error //编译链码 func DockerBuild(opts DockerBuildOptions) error //代码在core/chaincode/platforms/util/utils.go

func DockerBuild(opts DockerBuildOptions) error代码如下:

type DockerBuildOptions struct {     Image string     Env []string     Cmd string     InputStream io.Reader     OutputStream io.Writer } func DockerBuild(opts DockerBuildOptions) error {     client, err := cutil.NewDockerClient()     if err != nil {         return fmt.Errorf("Error creating docker client: %s", err)     }     if opts.Image == "" {         //通用的本地编译环境         opts.Image = cutil.GetDockerfileFromConfig("chaincode.builder")     }     //确认镜像是否存在或从远程拉取     _, err = client.InspectImage(opts.Image)     if err != nil {         err = client.PullImage(docker.PullImageOptions{Repository: opts.Image}, docker.AuthConfiguration{})     }     //创建一个暂时的容器     container, err := client.CreateContainer(docker.CreateContainerOptions{         Config: &docker.Config{             Image: opts.Image,             Env: opts.Env,             Cmd: []string{"/bin/sh", "-c", opts.Cmd},             AttachStdout: true,             AttachStderr: true,         },     })     //删除容器     defer client.RemoveContainer(docker.RemoveContainerOptions{ID: container.ID})     //上传输入     err = client.UploadToContainer(container.ID, docker.UploadToContainerOptions{         Path: "/chaincode/input",         InputStream: opts.InputStream,     })     stdout := bytes.NewBuffer(nil)     _, err = client.AttachToContainerNonBlocking(docker.AttachToContainerOptions{         Container: container.ID,         OutputStream: stdout,         ErrorStream: stdout,         Logs: true,         Stdout: true,         Stderr: true,         Stream: true,     })     //启动容器     err = client.StartContainer(container.ID, nil)     //等待容器返回     retval, err := client.WaitContainer(container.ID)     //获取容器输出     err = client.DownloadFromContainer(container.ID, docker.DownloadFromContainerOptions{         Path: "/chaincode/output/.",         OutputStream: opts.OutputStream,     })     return nil } //代码在core/chaincode/platforms/util/utils.go

4、golang语言平台实现

4.1、golang.Platform结构体定义及方法

Platform接口golang语言平台实现,即golang.Platform结构体定义及方法。

type Platform struct { } //验证ChaincodeSpec,即检查spec.ChaincodeId.Path是否存在 func (goPlatform *Platform) ValidateSpec(spec *pb.ChaincodeSpec) error //验证ChaincodeDeploymentSpec,即检查cds.CodePackage(tar.gz文件)解压后文件合法性 func (goPlatform *Platform) ValidateDeploymentSpec(cds *pb.ChaincodeDeploymentSpec) error //获取部署Payload,即将链码目录下文件及导入包所依赖的外部包目录下文件达成tar.gz包 func (goPlatform *Platform) GetDeploymentPayload(spec *pb.ChaincodeSpec) ([]byte, error) func (goPlatform *Platform) GenerateDockerfile(cds *pb.ChaincodeDeploymentSpec) (string, error) func (goPlatform *Platform) GenerateDockerBuild(cds *pb.ChaincodeDeploymentSpec, tw *tar.Writer) error func pathExists(path string) (bool, error) //路径是否存在 func decodeUrl(spec *pb.ChaincodeSpec) (string, error) //spec.ChaincodeId.Path去掉http://或https:// func getGopath() (string, error) //获取GOPATH func filter(vs []string, f func(string) bool) []string //按func(string) bool过滤[]string func vendorDependencies(pkg string, files Sources) //重新映射依赖关系 //代码在core/chaincode/platforms/golang/platform.go

4.1.1 func (goPlatform Platform) GetDeploymentPayload(spec pb.ChaincodeSpec) ([]byte, error)

func (goPlatform *Platform) GetDeploymentPayload(spec *pb.ChaincodeSpec) ([]byte, error) {     var err error     code, err := getCode(spec) //获取代码,即构造CodeDescriptor,Gopath为代码真实路径,Pkg为代码相对路径     env, err := getGoEnv()     gopaths := splitEnvPaths(env["GOPATH"]) //GOPATH     goroots := splitEnvPaths(env["GOROOT"]) //GOROOT,go安装路径     gopaths[code.Gopath] = true //链码真实路径     env["GOPATH"] = flattenEnvPaths(gopaths) //GOPATH、GOROOT、链码真实路径重新拼合为新GOPATH          imports, err := listImports(env, code.Pkg) //获取导入包列表     var provided = map[string]bool{ //如下两个包为ccenv已自带,可删除         "github.com/hyperledger/fabric/core/chaincode/shim": true,         "github.com/hyperledger/fabric/protos/peer": true,     }          imports = filter(imports, func(pkg string) bool {         if _, ok := provided[pkg]; ok == true { //从导入包中删除ccenv已自带的包             return false         }         for goroot := range goroots { //删除goroot中自带的包             fqp := filepath.Join(goroot, "src", pkg)             exists, err := pathExists(fqp)             if err == nil && exists {                 return false             }         }            return true     })          deps := make(map[string]bool)     for _, pkg := range imports {         transitives, err := listDeps(env, pkg) //列出所有导入包的依赖包         deps[pkg] = true         for _, dep := range transitives {             deps[dep] = true         }     }     delete(deps, "") //删除空          fileMap, err := findSource(code.Gopath, code.Pkg) //遍历链码路径下文件     for dep := range deps {         for gopath := range gopaths {             fqp := filepath.Join(gopath, "src", dep)             exists, err := pathExists(fqp)             if err == nil && exists {                 files, err := findSource(gopath, dep) //遍历依赖包下文件                 for _, file := range files {                     fileMap[file.Name] = file                 }                              }         }     }          files := make(Sources, 0) //数组     for _, file := range fileMap {         files = append(files, file)     }     vendorDependencies(code.Pkg, files) //重新映射依赖关系     sort.Sort(files)          payload := bytes.NewBuffer(nil)     gw := gzip.NewWriter(payload)     tw := tar.NewWriter(gw)     for _, file := range files {         err = cutil.WriteFileToPackage(file.Path, file.Name, tw) //将文件写入压缩包中     }     tw.Close()     gw.Close()     return payload.Bytes(), nil } //代码在core/chaincode/platforms/golang/platform.go

4.1.2、func (goPlatform Platform) GenerateDockerfile(cds pb.ChaincodeDeploymentSpec) (string, error)

func (goPlatform *Platform) GenerateDockerfile(cds *pb.ChaincodeDeploymentSpec) (string, error) {     var buf []string     //go语言链码部署依赖的基础镜像     buf = append(buf, "FROM "+cutil.GetDockerfileFromConfig("chaincode.golang.runtime"))     //binpackage.tar添加到/usr/local/bin目录下     buf = append(buf, "ADD binpackage.tar /usr/local/bin")     dockerFileContents := strings.Join(buf, "\n")     return dockerFileContents, nil } //代码在core/chaincode/platforms/golang/platform.go

4.1.3、func (goPlatform Platform) GenerateDockerBuild(cds pb.ChaincodeDeploymentSpec, tw *tar.Writer) error

func (goPlatform *Platform) GenerateDockerBuild(cds *pb.ChaincodeDeploymentSpec, tw *tar.Writer) error {     spec := cds.ChaincodeSpec     pkgname, err := decodeUrl(spec)     const ldflags = "-linkmode external -extldflags '-static'"     codepackage := bytes.NewReader(cds.CodePackage)     binpackage := bytes.NewBuffer(nil)     //编译链码     err = util.DockerBuild(util.DockerBuildOptions{         Cmd: fmt.Sprintf("GOPATH=/chaincode/input:$GOPATH go build -ldflags \"%s\" -o /chaincode/output/chaincode %s", ldflags, pkgname),         InputStream: codepackage,         OutputStream: binpackage,     })     return cutil.WriteBytesToPackage("binpackage.tar", binpackage.Bytes(), tw) } //代码在core/chaincode/platforms/golang/platform.go

4.2、env相关函数

type Env map[string]string type Paths map[string]bool func getEnv() Env //获取环境变量,写入map[string]string func getGoEnv() (Env, error) //执行go env获取go环境变量,写入map[string]string func flattenEnv(env Env) []string //拼合env,形式k=v,写入[]string func splitEnvPaths(value string) Paths //分割多个路径字符串,linux下按:分割 func flattenEnvPaths(paths Paths) string //拼合多个路径字符串,以:分隔 //代码在core/chaincode/platforms/golang/env.go

4.3、list相关函数

//执行命令pgm,支持设置timeout,timeout后将kill进程 func runProgram(env Env, timeout time.Duration, pgm string, args ...string) ([]byte, error) //执行go list -f 规则 链码路径,获取导入包列表或依赖包列表 func list(env Env, template, pkg string) ([]string, error) //执行go list -f "{{ join .Deps \"\\n\"}}" 链码路径,获取依赖包列表 func listDeps(env Env, pkg string) ([]string, error) //执行go list -f "{{ join .Imports \"\\n\"}}" 链码路径,获取导入包列表 func listImports(env Env, pkg string) ([]string, error) //代码在core/chaincode/platforms/golang/list.go

4.4、Sources类型及方法

type Sources []SourceDescriptor type SourceMap map[string]SourceDescriptor type SourceDescriptor struct {     Name, Path string     Info os.FileInfo } type CodeDescriptor struct {     Gopath, Pkg string     Cleanup func() } //代码在core/chaincode/platforms/golang/package.go

涉及方法如下:

//获取代码真实路径 func getCodeFromFS(path string) (codegopath string, err error) //获取代码,即构造CodeDescriptor,Gopath为代码真实路径,Pkg为代码相对路径 func getCode(spec *pb.ChaincodeSpec) (*CodeDescriptor, error) //数组长度 func (s Sources) Len() int //交换数组i,j内容 func (s Sources) Swap(i, j int) //比较i,j的名称 func (s Sources) Less(i, j int) bool //遍历目录下文件,填充type SourceMap map[string]SourceDescriptor func findSource(gopath, pkg string) (SourceMap, error) //代码在core/chaincode/platforms/golang/package.go

欢迎继续关注兄弟连区块链教程分享!

原文链接:https://yq.aliyun.com/articles/658768
关注公众号

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。

持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。

转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。

文章评论

共有0条评论来说两句吧...

文章二维码

扫描即可查看该文章

点击排行

推荐阅读

最新文章