github.com/kchristidis/fabric@v1.0.4-0.20171028114726-837acd08cde1/peer/chaincode/common.go (about)

     1  /*
     2  Copyright IBM Corp. 2016 All Rights Reserved.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8  		 http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package chaincode
    18  
    19  import (
    20  	"encoding/json"
    21  	"errors"
    22  	"fmt"
    23  	"os"
    24  	"strings"
    25  
    26  	"github.com/hyperledger/fabric/common/cauthdsl"
    27  	"github.com/hyperledger/fabric/core/chaincode"
    28  	"github.com/hyperledger/fabric/core/chaincode/platforms"
    29  	"github.com/hyperledger/fabric/core/chaincode/shim"
    30  	"github.com/hyperledger/fabric/core/container"
    31  	"github.com/hyperledger/fabric/msp"
    32  	"github.com/hyperledger/fabric/peer/common"
    33  	pcommon "github.com/hyperledger/fabric/protos/common"
    34  	pb "github.com/hyperledger/fabric/protos/peer"
    35  	putils "github.com/hyperledger/fabric/protos/utils"
    36  	"github.com/spf13/cobra"
    37  	"golang.org/x/net/context"
    38  )
    39  
    40  // checkSpec to see if chaincode resides within current package capture for language.
    41  func checkSpec(spec *pb.ChaincodeSpec) error {
    42  	// Don't allow nil value
    43  	if spec == nil {
    44  		return errors.New("Expected chaincode specification, nil received")
    45  	}
    46  
    47  	platform, err := platforms.Find(spec.Type)
    48  	if err != nil {
    49  		return fmt.Errorf("Failed to determine platform type: %s", err)
    50  	}
    51  
    52  	return platform.ValidateSpec(spec)
    53  }
    54  
    55  // getChaincodeDeploymentSpec get chaincode deployment spec given the chaincode spec
    56  func getChaincodeDeploymentSpec(spec *pb.ChaincodeSpec, crtPkg bool) (*pb.ChaincodeDeploymentSpec, error) {
    57  	var codePackageBytes []byte
    58  	if chaincode.IsDevMode() == false && crtPkg {
    59  		var err error
    60  		if err = checkSpec(spec); err != nil {
    61  			return nil, err
    62  		}
    63  
    64  		codePackageBytes, err = container.GetChaincodePackageBytes(spec)
    65  		if err != nil {
    66  			err = fmt.Errorf("Error getting chaincode package bytes: %s", err)
    67  			return nil, err
    68  		}
    69  	}
    70  	chaincodeDeploymentSpec := &pb.ChaincodeDeploymentSpec{ChaincodeSpec: spec, CodePackage: codePackageBytes}
    71  	return chaincodeDeploymentSpec, nil
    72  }
    73  
    74  // getChaincodeSpec get chaincode spec from the cli cmd pramameters
    75  func getChaincodeSpec(cmd *cobra.Command) (*pb.ChaincodeSpec, error) {
    76  	spec := &pb.ChaincodeSpec{}
    77  	if err := checkChaincodeCmdParams(cmd); err != nil {
    78  		return spec, err
    79  	}
    80  
    81  	// Build the spec
    82  	input := &pb.ChaincodeInput{}
    83  	if err := json.Unmarshal([]byte(chaincodeCtorJSON), &input); err != nil {
    84  		return spec, fmt.Errorf("Chaincode argument error: %s", err)
    85  	}
    86  
    87  	chaincodeLang = strings.ToUpper(chaincodeLang)
    88  	if pb.ChaincodeSpec_Type_value[chaincodeLang] == int32(pb.ChaincodeSpec_JAVA) {
    89  		return nil, fmt.Errorf("Java chaincode is work-in-progress and disabled")
    90  	}
    91  	spec = &pb.ChaincodeSpec{
    92  		Type:        pb.ChaincodeSpec_Type(pb.ChaincodeSpec_Type_value[chaincodeLang]),
    93  		ChaincodeId: &pb.ChaincodeID{Path: chaincodePath, Name: chaincodeName, Version: chaincodeVersion},
    94  		Input:       input,
    95  	}
    96  	return spec, nil
    97  }
    98  
    99  func chaincodeInvokeOrQuery(cmd *cobra.Command, args []string, invoke bool, cf *ChaincodeCmdFactory) (err error) {
   100  	spec, err := getChaincodeSpec(cmd)
   101  	if err != nil {
   102  		return err
   103  	}
   104  
   105  	proposalResp, err := ChaincodeInvokeOrQuery(
   106  		spec,
   107  		chainID,
   108  		invoke,
   109  		cf.Signer,
   110  		cf.EndorserClient,
   111  		cf.BroadcastClient)
   112  
   113  	if err != nil {
   114  		return fmt.Errorf("%s - %v", err, proposalResp)
   115  	}
   116  
   117  	if invoke {
   118  		if proposalResp.Response.Status >= shim.ERROR {
   119  			logger.Debugf("ESCC invoke result: %v", proposalResp)
   120  			pRespPayload, err := putils.GetProposalResponsePayload(proposalResp.Payload)
   121  			if err != nil {
   122  				return fmt.Errorf("Error while unmarshaling proposal response payload: %s", err)
   123  			}
   124  			ca, err := putils.GetChaincodeAction(pRespPayload.Extension)
   125  			if err != nil {
   126  				return fmt.Errorf("Error while unmarshaling chaincode action: %s", err)
   127  			}
   128  			logger.Warningf("Endorsement failure during invoke. chaincode result: %v", ca.Response)
   129  		} else {
   130  			logger.Debugf("ESCC invoke result: %v", proposalResp)
   131  			pRespPayload, err := putils.GetProposalResponsePayload(proposalResp.Payload)
   132  			if err != nil {
   133  				return fmt.Errorf("Error while unmarshaling proposal response payload: %s", err)
   134  			}
   135  			ca, err := putils.GetChaincodeAction(pRespPayload.Extension)
   136  			if err != nil {
   137  				return fmt.Errorf("Error while unmarshaling chaincode action: %s", err)
   138  			}
   139  			logger.Infof("Chaincode invoke successful. result: %v", ca.Response)
   140  		}
   141  	} else {
   142  		if proposalResp == nil {
   143  			return fmt.Errorf("Error query %s by endorsing: %s", chainFuncName, err)
   144  		}
   145  
   146  		if chaincodeQueryRaw {
   147  			if chaincodeQueryHex {
   148  				return fmt.Errorf("Options --raw (-r) and --hex (-x) are not compatible")
   149  			}
   150  			fmt.Print("Query Result (Raw): ")
   151  			os.Stdout.Write(proposalResp.Response.Payload)
   152  		} else {
   153  			if chaincodeQueryHex {
   154  				fmt.Printf("Query Result: %x\n", proposalResp.Response.Payload)
   155  			} else {
   156  				fmt.Printf("Query Result: %s\n", string(proposalResp.Response.Payload))
   157  			}
   158  		}
   159  	}
   160  	return nil
   161  }
   162  
   163  func checkChaincodeCmdParams(cmd *cobra.Command) error {
   164  	//we need chaincode name for everything, including deploy
   165  	if chaincodeName == common.UndefinedParamValue {
   166  		return fmt.Errorf("Must supply value for %s name parameter.", chainFuncName)
   167  	}
   168  
   169  	if cmd.Name() == instantiateCmdName || cmd.Name() == installCmdName ||
   170  		cmd.Name() == upgradeCmdName || cmd.Name() == packageCmdName {
   171  		if chaincodeVersion == common.UndefinedParamValue {
   172  			return fmt.Errorf("Chaincode version is not provided for %s", cmd.Name())
   173  		}
   174  	}
   175  
   176  	if escc != common.UndefinedParamValue {
   177  		logger.Infof("Using escc %s", escc)
   178  	} else {
   179  		logger.Info("Using default escc")
   180  		escc = "escc"
   181  	}
   182  
   183  	if vscc != common.UndefinedParamValue {
   184  		logger.Infof("Using vscc %s", vscc)
   185  	} else {
   186  		logger.Info("Using default vscc")
   187  		vscc = "vscc"
   188  	}
   189  
   190  	if policy != common.UndefinedParamValue {
   191  		p, err := cauthdsl.FromString(policy)
   192  		if err != nil {
   193  			return fmt.Errorf("Invalid policy %s", policy)
   194  		}
   195  		policyMarhsalled = putils.MarshalOrPanic(p)
   196  	}
   197  
   198  	// Check that non-empty chaincode parameters contain only Args as a key.
   199  	// Type checking is done later when the JSON is actually unmarshaled
   200  	// into a pb.ChaincodeInput. To better understand what's going
   201  	// on here with JSON parsing see http://blog.golang.org/json-and-go -
   202  	// Generic JSON with interface{}
   203  	if chaincodeCtorJSON != "{}" {
   204  		var f interface{}
   205  		err := json.Unmarshal([]byte(chaincodeCtorJSON), &f)
   206  		if err != nil {
   207  			return fmt.Errorf("Chaincode argument error: %s", err)
   208  		}
   209  		m := f.(map[string]interface{})
   210  		sm := make(map[string]interface{})
   211  		for k := range m {
   212  			sm[strings.ToLower(k)] = m[k]
   213  		}
   214  		_, argsPresent := sm["args"]
   215  		_, funcPresent := sm["function"]
   216  		if !argsPresent || (len(m) == 2 && !funcPresent) || len(m) > 2 {
   217  			return errors.New("Non-empty JSON chaincode parameters must contain the following keys: 'Args' or 'Function' and 'Args'")
   218  		}
   219  	} else {
   220  		if cmd == nil || (cmd != chaincodeInstallCmd && cmd != chaincodePackageCmd) {
   221  			return errors.New("Empty JSON chaincode parameters must contain the following keys: 'Args' or 'Function' and 'Args'")
   222  		}
   223  	}
   224  
   225  	return nil
   226  }
   227  
   228  // ChaincodeCmdFactory holds the clients used by ChaincodeCmd
   229  type ChaincodeCmdFactory struct {
   230  	EndorserClient  pb.EndorserClient
   231  	Signer          msp.SigningIdentity
   232  	BroadcastClient common.BroadcastClient
   233  }
   234  
   235  // InitCmdFactory init the ChaincodeCmdFactory with default clients
   236  func InitCmdFactory(isEndorserRequired, isOrdererRequired bool) (*ChaincodeCmdFactory, error) {
   237  	var err error
   238  	var endorserClient pb.EndorserClient
   239  	if isEndorserRequired {
   240  		endorserClient, err = common.GetEndorserClientFnc()
   241  		if err != nil {
   242  			return nil, fmt.Errorf("Error getting endorser client %s: %s", chainFuncName, err)
   243  		}
   244  	}
   245  
   246  	signer, err := common.GetDefaultSignerFnc()
   247  	if err != nil {
   248  		return nil, fmt.Errorf("Error getting default signer: %s", err)
   249  	}
   250  
   251  	var broadcastClient common.BroadcastClient
   252  	if isOrdererRequired {
   253  		if len(orderingEndpoint) == 0 {
   254  			orderingEndpoints, err := common.GetOrdererEndpointOfChainFnc(chainID, signer, endorserClient)
   255  			if err != nil {
   256  				return nil, fmt.Errorf("Error getting (%s) orderer endpoint: %s", chainID, err)
   257  			}
   258  			if len(orderingEndpoints) == 0 {
   259  				return nil, fmt.Errorf("Error no orderer endpoint got for %s", chainID)
   260  			}
   261  			logger.Infof("Get chain(%s) orderer endpoint: %s", chainID, orderingEndpoints[0])
   262  			orderingEndpoint = orderingEndpoints[0]
   263  		}
   264  
   265  		broadcastClient, err = common.GetBroadcastClientFnc(orderingEndpoint, tls, caFile)
   266  
   267  		if err != nil {
   268  			return nil, fmt.Errorf("Error getting broadcast client: %s", err)
   269  		}
   270  	}
   271  	return &ChaincodeCmdFactory{
   272  		EndorserClient:  endorserClient,
   273  		Signer:          signer,
   274  		BroadcastClient: broadcastClient,
   275  	}, nil
   276  }
   277  
   278  // ChaincodeInvokeOrQuery invokes or queries the chaincode. If successful, the
   279  // INVOKE form prints the ProposalResponse to STDOUT, and the QUERY form prints
   280  // the query result on STDOUT. A command-line flag (-r, --raw) determines
   281  // whether the query result is output as raw bytes, or as a printable string.
   282  // The printable form is optionally (-x, --hex) a hexadecimal representation
   283  // of the query response. If the query response is NIL, nothing is output.
   284  //
   285  // NOTE - Query will likely go away as all interactions with the endorser are
   286  // Proposal and ProposalResponses
   287  func ChaincodeInvokeOrQuery(
   288  	spec *pb.ChaincodeSpec,
   289  	cID string,
   290  	invoke bool,
   291  	signer msp.SigningIdentity,
   292  	endorserClient pb.EndorserClient,
   293  	bc common.BroadcastClient,
   294  ) (*pb.ProposalResponse, error) {
   295  	// Build the ChaincodeInvocationSpec message
   296  	invocation := &pb.ChaincodeInvocationSpec{ChaincodeSpec: spec}
   297  	if customIDGenAlg != common.UndefinedParamValue {
   298  		invocation.IdGenerationAlg = customIDGenAlg
   299  	}
   300  
   301  	creator, err := signer.Serialize()
   302  	if err != nil {
   303  		return nil, fmt.Errorf("Error serializing identity for %s: %s", signer.GetIdentifier(), err)
   304  	}
   305  
   306  	funcName := "invoke"
   307  	if !invoke {
   308  		funcName = "query"
   309  	}
   310  
   311  	var prop *pb.Proposal
   312  	prop, _, err = putils.CreateProposalFromCIS(pcommon.HeaderType_ENDORSER_TRANSACTION, cID, invocation, creator)
   313  	if err != nil {
   314  		return nil, fmt.Errorf("Error creating proposal  %s: %s", funcName, err)
   315  	}
   316  
   317  	var signedProp *pb.SignedProposal
   318  	signedProp, err = putils.GetSignedProposal(prop, signer)
   319  	if err != nil {
   320  		return nil, fmt.Errorf("Error creating signed proposal  %s: %s", funcName, err)
   321  	}
   322  
   323  	var proposalResp *pb.ProposalResponse
   324  	proposalResp, err = endorserClient.ProcessProposal(context.Background(), signedProp)
   325  	if err != nil {
   326  		return nil, fmt.Errorf("Error endorsing %s: %s", funcName, err)
   327  	}
   328  
   329  	if invoke {
   330  		if proposalResp != nil {
   331  			if proposalResp.Response.Status >= shim.ERROR {
   332  				return proposalResp, nil
   333  			}
   334  			// assemble a signed transaction (it's an Envelope message)
   335  			env, err := putils.CreateSignedTx(prop, signer, proposalResp)
   336  			if err != nil {
   337  				return proposalResp, fmt.Errorf("Could not assemble transaction, err %s", err)
   338  			}
   339  
   340  			// send the envelope for ordering
   341  			if err = bc.Send(env); err != nil {
   342  				return proposalResp, fmt.Errorf("Error sending transaction %s: %s", funcName, err)
   343  			}
   344  		}
   345  	}
   346  
   347  	return proposalResp, nil
   348  }