hyperledger fabric 1.0 源码分析之peer chaincode invoke or query

概述

peer chaincode invoke命令用于调用链码(chaincode)

peer chaincode query命令与invoke实现基本相同,区别在于提交并处理Proposal后,不再创建交易以及广播交易。

实现

命令的定义

func invokeCmd(cf *ChaincodeCmdFactory) *cobra.Command {
	chaincodeInvokeCmd = &cobra.Command{
		Use:       "invoke",
		Short:     fmt.Sprintf("Invoke the specified %s.", chainFuncName),
		Long:      fmt.Sprintf("Invoke the specified %s. It will try to commit the endorsed transaction to the network.", chainFuncName),
		ValidArgs: []string{"1"},
		RunE: func(cmd *cobra.Command, args []string) error {
            //执行命令的具体实现
			return chaincodeInvoke(cmd, args, cf)
		},
	}
	flagList := []string{
		"name",
		"ctor",
		"channelID",
	}
    //为invoke添加命令标记
	attachFlags(chaincodeInvokeCmd, flagList)

	return chaincodeInvokeCmd
}

chaincodeInvoke实现

invoke或query子命令入口

func chaincodeInvoke(cmd *cobra.Command, args []string, cf *ChaincodeCmdFactory) error {
	var err error
	if cf == nil {
        //获取ChaincodeCmdFactory,已多次介绍,这里不在介绍
		cf, err = InitCmdFactory(true, true)
		if err != nil {
			return err
		}
	}
	defer cf.BroadcastClient.Close()
    //chaincode invoke 和 chaincode query都执行这个方法
	return chaincodeInvokeOrQuery(cmd, args, true, cf)
}

chaincodeInvokeOrQuery实现

invoke和query具体实现方法

func chaincodeInvokeOrQuery(cmd *cobra.Command, args []string, invoke bool, cf *ChaincodeCmdFactory) (err error) {
	//获取ChaincodeSpec
    spec, err := getChaincodeSpec(cmd)
	if err != nil {
		return err
	}
    //调用或查询链码,成功返回提案响应ProposalResponse
	proposalResp, err := ChaincodeInvokeOrQuery(
		spec,    //ChaincodeSpec
		chainID,    //链id
		invoke,    //invoke时为true,query是为false
		cf.Signer,    //ChaincodeCmdFactory.Signer msp签名身份
		cf.EndorserClient,    //背书端
		cf.BroadcastClient)    //广播端

	if err != nil {
		return fmt.Errorf("%s - %v", err, proposalResp)
	}

	if invoke {
        //invoke操作
        //shim.ERROR默认值500
        //putils.GetProposalResponsePayload()获取提案响应中的payload
        //putils.GetChaincodeAction()获取读写集
		if proposalResp.Response.Status >= shim.ERROR {
			logger.Debugf("ESCC invoke result: %v", proposalResp)
			pRespPayload, err := putils.GetProposalResponsePayload(proposalResp.Payload)
			if err != nil {
				return fmt.Errorf("Error while unmarshaling proposal response payload: %s", err)
			}
			ca, err := putils.GetChaincodeAction(pRespPayload.Extension)
			if err != nil {
				return fmt.Errorf("Error while unmarshaling chaincode action: %s", err)
			}
			logger.Warningf("Endorsement failure during invoke. chaincode result: %v", ca.Response)
		} else {
			logger.Debugf("ESCC invoke result: %v", proposalResp)
			pRespPayload, err := putils.GetProposalResponsePayload(proposalResp.Payload)
			if err != nil {
				return fmt.Errorf("Error while unmarshaling proposal response payload: %s", err)
			}
			ca, err := putils.GetChaincodeAction(pRespPayload.Extension)
			if err != nil {
				return fmt.Errorf("Error while unmarshaling chaincode action: %s", err)
			}
			logger.Infof("Chaincode invoke successful. result: %v", ca.Response)
		}
	} else {
        //query操作
        //查询成功返回结果
		if proposalResp == nil {
			return fmt.Errorf("Error query %s by endorsing: %s", chainFuncName, err)
		}

		if chaincodeQueryRaw {
			if chaincodeQueryHex {
				return fmt.Errorf("Options --raw (-r) and --hex (-x) are not compatible")
			}
			fmt.Print("Query Result (Raw): ")
			os.Stdout.Write(proposalResp.Response.Payload)
		} else {
			if chaincodeQueryHex {
				fmt.Printf("Query Result: %x\n", proposalResp.Response.Payload)
			} else {
				fmt.Printf("Query Result: %s\n", string(proposalResp.Response.Payload))
			}
		}
	}
	return nil
}

方法详解

getChaincodeSpec()

func getChaincodeSpec(cmd *cobra.Command) (*pb.ChaincodeSpec, error) {
	spec := &pb.ChaincodeSpec{}
    //checkChaincodeCmdParams进行参数验证
    //验证chinacodename、版本、escc、vscc、policy、参数(chaincodeCtorJSON)是否定义
	if err := checkChaincodeCmdParams(cmd); err != nil {
		return spec, err
	}

	// Build the spec
	input := &pb.ChaincodeInput{}
	if err := json.Unmarshal([]byte(chaincodeCtorJSON), &input); err != nil {
		return spec, fmt.Errorf("Chaincode argument error: %s", err)
	}
    //语言验证,链码不允许是java
	chaincodeLang = strings.ToUpper(chaincodeLang)
	if pb.ChaincodeSpec_Type_value[chaincodeLang] == int32(pb.ChaincodeSpec_JAVA) {
		return nil, fmt.Errorf("Java chaincode is work-in-progress and disabled")
	}
    //返回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
}

ChaincodeInvokeOrQuery()

func ChaincodeInvokeOrQuery(
	spec *pb.ChaincodeSpec,
	cID string,
	invoke bool,
	signer msp.SigningIdentity,
	endorserClient pb.EndorserClient,
	bc common.BroadcastClient,
) (*pb.ProposalResponse, error) {
	// Build the ChaincodeInvocationSpec message
	invocation := &pb.ChaincodeInvocationSpec{ChaincodeSpec: spec}
	if customIDGenAlg != common.UndefinedParamValue {
		invocation.IdGenerationAlg = customIDGenAlg
	}
    //获取签名身份(所有人)
	creator, err := signer.Serialize()
	if err != nil {
		return nil, fmt.Errorf("Error serializing identity for %s: %s", signer.GetIdentifier(), err)
	}

	funcName := "invoke"
	if !invoke {
		funcName = "query"
	}
	//创建Proposal
	var prop *pb.Proposal
	prop, _, err = putils.CreateProposalFromCIS(pcommon.HeaderType_ENDORSER_TRANSACTION, cID, invocation, creator)
	if err != nil {
		return nil, fmt.Errorf("Error creating proposal  %s: %s", funcName, err)
	}
	//Proposal签名
	var signedProp *pb.SignedProposal
	signedProp, err = putils.GetSignedProposal(prop, signer)
	if err != nil {
		return nil, fmt.Errorf("Error creating signed proposal  %s: %s", funcName, err)
	}
	//提交处理签名提案signedProp
	var proposalResp *pb.ProposalResponse
	proposalResp, err = endorserClient.ProcessProposal(context.Background(), signedProp)
	if err != nil {
		return nil, fmt.Errorf("Error endorsing %s: %s", funcName, err)
	}
    //invoke操作执行,query操作直接返回
	if invoke {
		if proposalResp != nil {
			if proposalResp.Response.Status >= shim.ERROR {
				return proposalResp, nil
			}
			// assemble a signed transaction (it's an Envelope message)
			//创建签名交易
			env, err := putils.CreateSignedTx(prop, signer, proposalResp)
			if err != nil {
				return proposalResp, fmt.Errorf("Could not assemble transaction, err %s", err)
			}

			// send the envelope for ordering
			if err = bc.Send(env); err != nil {
				return proposalResp, fmt.Errorf("Error sending transaction %s: %s", funcName, err)
			}
		}
	}

	return proposalResp, nil
}

猜你喜欢

转载自blog.csdn.net/cs380637384/article/details/82415053
今日推荐