区块链教程Fabric1.0源代码分析链码 链码语言平台-兄弟连
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
欢迎继续关注兄弟连区块链教程分享!

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
推荐6款 Docker 认证的实用免费插件,帮助您轻松监控容器动态!
出品丨Docker公司(ID:docker-cn)编译丨小东每周一、三、五晚6点10分 与您不见不散! Docker 认证技术项目(Docker Certified Technology Program)是为了帮助合作伙伴和客户识别出在质量、协作支持以及合规性等方面表现出色的容器和插件。Docker 认证项目通过 Docker 以及发行商的支持为组织提供了一种在 Docker Enterprise 容器平台上运行可信任软件和组件的简便方法。 在这篇文章中,我们将着眼于监控 Docker 容器的解决方案。Docker 让开发人员能够使用包含多种微服务的软件架构进行更快地迭代。这无疑对传统的监控解决方案提出了挑战,因为目标进程不再是通过静态分配或绑定到特定主机的方式了。如今的监控解决方案趋向于跟踪短暂和快速扩展的容器集。Docker 引擎公开了用于容器元数据、生命周期事件和关键性能指标的 API。合作伙伴的监控解决方案通过 Docker 引擎公开的 API 可以实时收集系统以及 Docker 容器的事件和指标来监控客户的整个基础架构、应用程序和服务的运行状况和性能。这些解决方案经过 Doc...
- 下一篇
混合云存储在基因领域的应用
序 基因支持着生命的基本构造和性能。储存着生命的种族、血型、孕育、生长、凋亡等过程的全部信息。环境和遗传的互相依赖,演绎着生命的繁衍、细胞分裂和蛋白质合成等重要生理过程。生物体的生、长、衰、病、老、死等一切生命现象都与基因有关。它也是决定生命健康的内在因素。通过基因测序,检测患者的样本基因,通过大数据和相关算法来针对性地推荐用药和治疗方案,从而帮助患者更快的恢复,提高医疗水平。 人类基因组包含 30 亿个碱基对。做一次全基因组检测,会产生 100 多 G 海量数据,其中能被用于科研与临床应用的,只是蛋白编码基因与少量的非蛋白编码基因,占整体数据的 1%-2% 之间;而这部分数据中,被研究透彻的、能将之与疾病关联后得以应用的,仅占 1%,由于基因数据获取成本高,对未来的深入挖掘非常重要,所有的基因组检测数据不能轻易丢弃。基因测试的过程中会产生大量的数据,如何利用云计算,大数据等技术来解决海量数据的存储,并能快速的从海量数据中提取出关键的信息成为重中之重。 基因领域的需求和痛点 国内某医学公司专注于肿瘤患者个体化治疗指导,以二代测序及医学生物信息学为核心,常规肿瘤分子病理检测为基石,致力于...
相关文章
文章评论
共有0条评论来说两句吧...