本文还未编写完成,后面会逐步完成。
Fabric v1.x 的组件包括client、orderer节点、peer节点、chaincode容器,各个容器节点间的交互关系如下:
上图中可知,最主要的5个交互步骤为:
下图中可以看到各个容器节点间通过gRPC进行通信,其中Peer与chaincode容器是通过ChaincodeSuppport的gRPC接口服务进行交互:
关于chaincode的开发请参考Fabric v1.x 应用开发指南(2 3 4章节)。
开发模式:ChaincodeSupportService会等待来自独立chaincode进程的连接;
非开发模式:大致包括这些启动步骤
func (vm *DockerVM) GetEnv(ccid string, tlsConfig *ccintf.TLSConfig) []string {
envs := []string{fmt.Sprintf("CORE_CHAINCODE_ID_NAME=%s", ccid)}
envs = append(envs, vm.LoggingEnv...)
if tlsConfig != nil {
envs = append(envs, "CORE_PEER_TLS_ENABLED=true")
envs = append(envs, fmt.Sprintf("CORE_TLS_CLIENT_KEY_PATH=%s", TLSClientKeyPath))
envs = append(envs, fmt.Sprintf("CORE_TLS_CLIENT_CERT_PATH=%s", TLSClientCertPath))
envs = append(envs, fmt.Sprintf("CORE_TLS_CLIENT_KEY_FILE=%s", TLSClientKeyFile))
envs = append(envs, fmt.Sprintf("CORE_TLS_CLIENT_CERT_FILE=%s", TLSClientCertFile))
envs = append(envs, fmt.Sprintf("CORE_PEER_TLS_ROOTCERT_FILE=%s", TLSClientRootCertFile))
} else {
envs = append(envs, "CORE_PEER_TLS_ENABLED=false")
}
envs = append(envs, fmt.Sprintf("CORE_PEER_LOCALMSPID=%s", vm.MSPID))
return envs
}
func (vm *DockerVM) GetArgs(ccType string, peerAddress string) ([]string, error) {
switch ccType {
case pb.ChaincodeSpec_GOLANG.String(), pb.ChaincodeSpec_CAR.String():
return []string{"chaincode", fmt.Sprintf("-peer.address=%s", peerAddress)}, nil
case pb.ChaincodeSpec_JAVA.String():
return []string{"/root/chaincode-java/start", "--peerAddress", peerAddress}, nil
case pb.ChaincodeSpec_NODE.String():
return []string{"/bin/sh", "-c", fmt.Sprintf(nodeStartScript, peerAddress)}, nil
default:
return nil, errors.Errorf("unknown chaincodeType: %s", ccType)
}
}
args: chaincode启动命令
envs: chaincode环境变量
平台抽象的接口为Platform :
core/chaincode/platforms/platforms.go
type Platform interface {
Name() string
GenerateDockerfile() (string, error)
DockerBuildOptions(path string) (util.DockerBuildOptions, error)
}
Fabric支持golang、java、node语言的chaincode平台,下面主要解析golang的platform抽象。
core/chaincode/platforms/golang/platform.go
GenerateDockerfile函数用于生成Dockerfile:
func (p *Platform) GenerateDockerfile() (string, error) {
var buf []string
buf = append(buf, "FROM "+util.GetDockerImageFromConfig("chaincode.golang.runtime"))
buf = append(buf, "ADD binpackage.tar /usr/local/bin")
return strings.Join(buf, "\n"), nil
}
chaincode.golang.runtime参数在core.yaml中配置:
chaincode:
golang:
runtime: $(DOCKER_NS)/fabric-baseos:$(TWO_DIGIT_VERSION)
DockerBuildOptions函数:
core/chaincode/platforms/golang/platform.go
func (p *Platform) DockerBuildOptions(path string) (util.DockerBuildOptions, error) {
env := []string{}
for _, key := range []string{"GOPROXY", "GOSUMDB"} {
if val, ok := os.LookupEnv(key); ok {
env = append(env, fmt.Sprintf("%s=%s", key, val))
continue
}
if key == "GOPROXY" {
env = append(env, "GOPROXY=https://proxy.golang.org")
}
}
ldFlagOpts := getLDFlagsOpts()
return util.DockerBuildOptions{
Cmd: fmt.Sprintf(buildScript, ldFlagOpts, path),
Env: env,
}, nil
}
DockerBuildOptions为构造二进制文件时增加一些选项,包括GOPROXY、GOSUMDB。
core/chaincode/handler.go:
hyperledger/fabric-chaincode-go/shim/handler.go:
readyStateHandler:不同的消息类型,选择不同的handler
transactionContext:对应chaincodeSupport,queryIteratorMap、historyQueryExecutor