之前说完了链码的安装过程, 接下来说一下链码的实例化过程好了, 再然后是链码的调用过程. 其实这几个过程内容已经很相似了, 都是涉及到 Proposal, 不过整体流程还是要说一下的.
同样, 切入点仍然是 fabric/peer/main.go 文件中的 main() 方法:
- # 这一句定义了关于通过 Peer 节点操作链码的命令
- mainCmd.AddCommand(chaincode.Cmd(nil))
然后是 fabric/peer/chaincode/chaincode.go 文件中的 Cmd() 方法, 这里则是具体的操作链码的命令, 其中就有对链码进行实例化的命令:
chaincodeCmd.AddCommand(instantiateCmd(cf))
最后调用到了 fabric/peer/chaincode/instantiate.go 文件中的第 57 行的 instantiate() 方法. 也就是说, 当我们在 Peer 节点执行以下命令时, 最终会到这个方法:
- # 以官方的实例化链码的方法为例
- peer chaincode instantiate -o orderer.example.com:7050 --tls true --cafile $ORDERER_CA -C mychannel -n mycc -v 1.0 -c '{"Args":["init","a","100","b","200"]}' -P "OR ('Org1MSP.member','Org2MSP.member')"
接下来就看一下 instantiate() 方法:
- # 首先获取要实例化的链码的信息
- spec, err := getChaincodeSpec(cmd)
- if err != nil {
- return nil, err
- }
getChaincodeSpec() 方法在 peer/chaincode/common.go 文件中第 69 行:
- # 将用户实例化链码所执行的命令作为参数传入进去
- func getChaincodeSpec(cmd *cobra.Command) (*pb.ChaincodeSpec, error) {
- #定义一个 ChaincodeSpec 结构体
- spec := &pb.ChaincodeSpec{}
- ====================ChaincodeSpec===========================
- type ChaincodeSpec struct {
- #Type 表示链码的类型 有 GOLANG,NODE,CAR,JAVA,UNDEFINED 五种类型
- Type ChaincodeSpec_Type `protobuf:"varint,1,opt,name=type,proto3,enum=protos.ChaincodeSpec_Type" json:"type,omitempty"`
- #ChaincodeId 也是一个结构体, 定义了链码的路径信息, 链码的名称以及版本信息
- ChaincodeId *ChaincodeID `protobuf:"bytes,2,opt,name=chaincode_id,json=chaincodeId,proto3" json:"chaincode_id,omitempty"`
- #ChaincodeInput 结构体中定义链码的功能以及函数参数信息
- Input *ChaincodeInput `protobuf:"bytes,3,opt,name=input,proto3" json:"input,omitempty"`
- Timeout int32 `protobuf:"varint,4,opt,name=timeout,proto3" json:"timeout,omitempty"`
- XXX_NoUnkeyedLiteral struct{} `json:"-"`
- XXX_unrecognized []byte `json:"-"`
- XXX_sizecache int32 `json:"-"`
- }
- ====================ChaincodeSpec===========================
- #对用户输入的命令进行检查
- if err := checkChaincodeCmdParams(cmd); err != nil {
- // unset usage silence because it's a command line usage error
- cmd.SilenceUsage = false
- return spec, err
- }
- #定义 ChaincodeInput 结构体, 就是上面说过的那个
- input := &pb.ChaincodeInput{}
- if err := JSON.Unmarshal([]byte(chaincodeCtorJSON), &input); err != nil {
- return spec, errors.Wrap(err, "chaincode argument error")
- }
- chaincodeLang = strings.ToUpper(chaincodeLang)
- #最后将创建的 ChaincodeSpec 结构体返回
- spec = &pb.ChaincodeSpec{
- Type: pb.ChaincodeSpec_Type(pb.ChaincodeSpec_Type_value[chaincodeLang]),
- ChaincodeId: &pb.ChaincodeID{Path: chaincodePath, Name: chaincodeName, Version: chaincodeVersion},
- Input: input,
- }
- return spec, nil
- }
看一下 checkChaincodeCmdParams() 方法做了哪些工作, 在 219 行:
- func checkChaincodeCmdParams(cmd *cobra.Command) error {
- #检查用户输入的链码名称是否为空字符串
- if chaincodeName == common.UndefinedParamValue {
- return errors.Errorf("must supply value for %s name parameter", chainFuncName)
- }
- #调用的方法是否为 instantiate,install,upgrade,package 其中的一个
- if cmd.Name() == instantiateCmdName || cmd.Name() == installCmdName ||
- cmd.Name() == upgradeCmdName || cmd.Name() == packageCmdName {
- if chaincodeVersion == common.UndefinedParamValue {
- return errors.Errorf("chaincode version is not provided for %s", cmd.Name())
- }
- if escc != common.UndefinedParamValue {
- logger.Infof("Using escc %s", escc)
- } else {
- logger.Info("Using default escc")
- escc = "escc"
- }
- if vscc != common.UndefinedParamValue {
- logger.Infof("Using vscc %s", vscc)
- } else {
- logger.Info("Using default vscc")
- vscc = "vscc"
- }
- if policy != common.UndefinedParamValue {
- #获取定义的策略, 就比如 OR ('Org1MSP.member','Org2MSP.member') 这条信息是否有误
- p, err := cauthdsl.FromString(policy)
- if err != nil {
- return errors.Errorf("invalid policy %s", policy)
- }
- policyMarshalled = putils.MarshalOrPanic(p)
- }
- #如果定义了配置文件, 则从配置文件中读取配置信息
- if collectionsConfigFile != common.UndefinedParamValue {
- var err error
- collectionConfigBytes, err = getCollectionConfigFromFile(collectionsConfigFile)
- if err != nil {
- return errors.WithMessage(err, fmt.Sprintf("invalid collection configuration in file %s", collectionsConfigFile))
- }
- }
- }
- #对用户传入的实例化参数比如:-c '{"Args":["init","a","100","b","200"]}'
- if chaincodeCtorJSON != "{}" {
- ...
- }
- return nil
- }
回到 instantiate() 方法:
- cds, err := getChaincodeDeploymentSpec(spec, false)
- if err != nil {
- return nil, fmt.Errorf("error getting chaincode code %s: %s", chaincodeName, err)
- }
获取 ChaincodeDeploymentSpec 这个结构体:
- type ChaincodeDeploymentSpec struct {
- #这个是之前获取到的结构体
- ChaincodeSpec *ChaincodeSpec `protobuf:"bytes,1,opt,name=chaincode_spec,json=chaincodeSpec,proto3" json:"chaincode_spec,omitempty"`
- #链码数据
- CodePackage []byte `protobuf:"bytes,3,opt,name=code_package,json=codePackage,proto3" json:"code_package,omitempty"`
- #链码的运行环境, 有两种, Docker 容器或者直接在系统中运行
- ExecEnv ChaincodeDeploymentSpec_ExecutionEnvironment `protobuf:"varint,4,opt,name=exec_env,json=execEnv,proto3,enum=protos.ChaincodeDeploymentSpec_ExecutionEnvironment" json:"exec_env,omitempty"`
- XXX_NoUnkeyedLiteral struct{} `json:"-"`
- XXX_unrecognized []byte `json:"-"`
- XXX_sizecache int32 `json:"-"`
- }
看一下如何获取 ChaincodeDeploymentSpec 结构体:
- # 定义了 ChaincodeDeploymentSpec 中的 CodePackage
- var codePackageBytes []byte
- # 判断是否为开发模式
- if chaincode.IsDevMode() == false && crtPkg {
- var err error
- #如果不是则检查链码是否为空, 以及路径是否正确
- if err = checkSpec(spec); err != nil {
- return nil, err
- }
- #将链码转换为 Byte 数据
- codePackageBytes, err = container.GetChaincodePackageBytes(platformRegistry, spec)
- ...
- }
- # 构造 chaincodeDeploymentSpec 并返回
- chaincodeDeploymentSpec := &pb.ChaincodeDeploymentSpec{ChaincodeSpec: spec, CodePackage: codePackageBytes}
- return chaincodeDeploymentSpec, nil
回到 instantiate() 方法:
- # 获取一全个签名者, 需要对创建实例化链码的 Proposal 进行签名
- creator, err := cf.Signer.Serialize()
- if err != nil {
- return nil, fmt.Errorf("error serializing identity for %s: %s", cf.Signer.GetIdentifier(), err)
- }
- # 要创建用于实例化链码的 Proposal 了
- prop, _, err := utils.CreateDeployProposalFromCDS(channelID, cds, creator, policyMarshalled, []byte(escc), []byte(vscc), collectionConfigBytes)
- if err != nil {
- return nil, fmt.Errorf("error creating proposal %s: %s", chainFuncName, err)
- }
看一下 CreateDeployProposalFromCDS() 方法, 看名字了解到是根据 chaincodeDeploymentSpec 创建用于部署链码的 Proposal:
- func CreateDeployProposalFromCDS(
- #通道 Id
- chainID string,
- cds *peer.ChaincodeDeploymentSpec,
- #签名者
- creator []byte,
- #具体的策略
- policy []byte,
- #endorser system chaincode
- escc []byte,
- #Verification System ChainCode
- vscc []byte,
- collectionConfig []byte) (*peer.Proposal, string, error) {
- #下面的两个方法调用的是同一个, 只是传入的参数不同, 点进去
- if collectionConfig == nil {
- return createProposalFromCDS(chainID, cds, creator, "deploy", policy, escc, vscc)
- }
- return createProposalFromCDS(chainID, cds, creator, "deploy", policy, escc, vscc, collectionConfig)
- }
该方法在 538 行, 接下来的部分与客户端安装链码所执行的流程基本是相同的, 只有下面的一部分不同:
- # 对于实例化链码来说, 执行的是 deploy 与 upgrade 这两部分, 而安装链码则是 install 这部分, 差异就在于 ChaincodeInput 结构体内的参数不同
- case "deploy":
- fallthrough
- case "upgrade":
- cds, ok := msg.(*peer.ChaincodeDeploymentSpec)
- if !ok || cds == nil {
- return nil, "", errors.New("invalid message for creating lifecycle chaincode proposal")
- }
- Args := [][]byte{[]byte(propType), []byte(chainID), b}
- Args = append(Args, args...)
- ccinp = &peer.ChaincodeInput{Args: Args}
- case "install":
- ccinp = &peer.ChaincodeInput{Args: [][]byte{[]byte(propType), b}}
- }
- // wrap the deployment in an invocation spec to lscc...
- lsccSpec := &peer.ChaincodeInvocationSpec{
- ChaincodeSpec: &peer.ChaincodeSpec{
- Type: peer.ChaincodeSpec_GOLANG,
- ChaincodeId: &peer.ChaincodeID{Name: "lscc"},
- Input: ccinp,
- },
- }
剩下的部分就不再重复看了, 可以参考 Fabric1.4 源码解析: 客户端安装链码这篇文章.
总的来说, 整个流程共有以下几部分:
根据用户执行实例化链码的命令启动全过程
获取需要实例化链码的基本信息
创建
ChaincodeDeploymentSpec
结构体.
获取用于对 Proposal 进行签名的 Creator.
创建 Proposal,Proposal 的 Header 定义为
ENDORSER_TRANSACTION
, 表示是一个需要背书的交易.
由之前获取的 Creator 进行签名操作.
由 Peer 节点调用 ProcessProposal() 方法进行处理, 该方法的解析在这里. 这是一个很重要的方法.
接收到由 Peer 节点处理完成所返回的 Response 消息后发送到 Orderer 节点.
Orderer 节点接收到消息后进行排序操作, 如果是 SOLO 模式则由 Orderer 节点生成区块, 最后将区块广播至 Peer 节点,
Peer 节点接收到区块消息后验证有效性, 最后更新账本数据.
最后附上参考链接: 1. 传送门 https://github.com/hyperledger/fabric
2. 传送门
来源: https://www.cnblogs.com/cbkj-xd/p/11149791.html