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
}
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)
}
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
}
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
}
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
}