ブロックチェーン教程Fabric 1.0ソースコード分析チェーンコード言語プラットフォーム


Fabric 1.0ソースコードノートのChincode(鎖コード)
1、plotforms概要
plotformsコードはcore/chaincode/plotformsディレクトリに集中しています。
  • core/chaincode/plotformsディレクトリ、チェーンコードの作成言語プラットフォーム、例えばgolangまたはjava。     plotforms.go、Platformインターフェース定義、およびplotforms関連ツール関数。     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、plotforms関連ツール関数
    3.1、plotforms関連ツール関数
    //       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 DocerBuild 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)Get Deployment Payload(spec pb.C haincodeSpec)([]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)Generate Docerfile(cds pb.ChiincodeDeployments Spec)(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, "
    ")     return dockerFileContents, nil } // core/chaincode/platforms/golang/platform.go
    4.1.3、func(goplatform Platform)Generate DocerBuild(cds pb.C haincodeDeployment Spec、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 \"\
    \"}}" , func listDeps(env Env, pkg string) ([]string, error) // go list -f "{{ join .Imports \"\
    \"}}" , 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