github.com/adnan-c/fabric_e2e_couchdb@v0.6.1-preview.0.20170228180935-21ce6b23cf91/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/container"
    30  	"github.com/hyperledger/fabric/msp"
    31  	"github.com/hyperledger/fabric/peer/common"
    32  	pcommon "github.com/hyperledger/fabric/protos/common"
    33  	pb "github.com/hyperledger/fabric/protos/peer"
    34  	putils "github.com/hyperledger/fabric/protos/utils"
    35  	"github.com/spf13/cobra"
    36  	"golang.org/x/net/context"
    37  )
    38  
    39  // checkSpec to see if chaincode resides within current package capture for language.
    40  func checkSpec(spec *pb.ChaincodeSpec) error {
    41  	// Don't allow nil value
    42  	if spec == nil {
    43  		return errors.New("Expected chaincode specification, nil received")
    44  	}
    45  
    46  	platform, err := platforms.Find(spec.Type)
    47  	if err != nil {
    48  		return fmt.Errorf("Failed to determine platform type: %s", err)
    49  	}
    50  
    51  	return platform.ValidateSpec(spec)
    52  }
    53  
    54  // getChaincodeBytes get chaincode deployment spec given the chaincode spec
    55  func getChaincodeBytes(spec *pb.ChaincodeSpec, crtPkg bool) (*pb.ChaincodeDeploymentSpec, error) {
    56  	var codePackageBytes []byte
    57  	if chaincode.IsDevMode() == false && crtPkg {
    58  		var err error
    59  		if err = checkSpec(spec); err != nil {
    60  			return nil, err
    61  		}
    62  
    63  		codePackageBytes, err = container.GetChaincodePackageBytes(spec)
    64  		if err != nil {
    65  			err = fmt.Errorf("Error getting chaincode package bytes: %s", err)
    66  			return nil, err
    67  		}
    68  	}
    69  	chaincodeDeploymentSpec := &pb.ChaincodeDeploymentSpec{ChaincodeSpec: spec, CodePackage: codePackageBytes}
    70  	return chaincodeDeploymentSpec, nil
    71  }
    72  
    73  func getChaincodeSpecification(cmd *cobra.Command) (*pb.ChaincodeSpec, error) {
    74  	spec := &pb.ChaincodeSpec{}
    75  	if err := checkChaincodeCmdParams(cmd); err != nil {
    76  		return spec, err
    77  	}
    78  
    79  	// Build the spec
    80  	input := &pb.ChaincodeInput{}
    81  	if err := json.Unmarshal([]byte(chaincodeCtorJSON), &input); err != nil {
    82  		return spec, fmt.Errorf("Chaincode argument error: %s", err)
    83  	}
    84  
    85  	chaincodeLang = strings.ToUpper(chaincodeLang)
    86  	spec = &pb.ChaincodeSpec{
    87  		Type:        pb.ChaincodeSpec_Type(pb.ChaincodeSpec_Type_value[chaincodeLang]),
    88  		ChaincodeId: &pb.ChaincodeID{Path: chaincodePath, Name: chaincodeName, Version: chaincodeVersion},
    89  		Input:       input,
    90  	}
    91  	return spec, nil
    92  }
    93  
    94  func chaincodeInvokeOrQuery(cmd *cobra.Command, args []string, invoke bool, cf *ChaincodeCmdFactory) (err error) {
    95  	spec, err := getChaincodeSpecification(cmd)
    96  	if err != nil {
    97  		return err
    98  	}
    99  
   100  	proposalResp, err := ChaincodeInvokeOrQuery(spec, chainID, invoke, cf.Signer, cf.EndorserClient, cf.BroadcastClient)
   101  	if err != nil {
   102  		return err
   103  	}
   104  
   105  	if invoke {
   106  		logger.Infof("Invoke result: %v", proposalResp)
   107  	} else {
   108  		if proposalResp == nil {
   109  			return fmt.Errorf("Error query %s by endorsing: %s", chainFuncName, err)
   110  		}
   111  
   112  		if chaincodeQueryRaw {
   113  			if chaincodeQueryHex {
   114  				err = errors.New("Options --raw (-r) and --hex (-x) are not compatible")
   115  				return
   116  			}
   117  			fmt.Print("Query Result (Raw): ")
   118  			os.Stdout.Write(proposalResp.Response.Payload)
   119  		} else {
   120  			if chaincodeQueryHex {
   121  				fmt.Printf("Query Result: %x\n", proposalResp.Response.Payload)
   122  			} else {
   123  				fmt.Printf("Query Result: %s\n", string(proposalResp.Response.Payload))
   124  			}
   125  		}
   126  	}
   127  	return err
   128  }
   129  
   130  func checkChaincodeCmdParams(cmd *cobra.Command) error {
   131  	//we need chaincode name for everything, including deploy
   132  	if chaincodeName == common.UndefinedParamValue {
   133  		return fmt.Errorf("Must supply value for %s name parameter.", chainFuncName)
   134  	}
   135  
   136  	if cmd.Name() == instantiate_cmdname || cmd.Name() == install_cmdname || cmd.Name() == upgrade_cmdname {
   137  		if chaincodeVersion == common.UndefinedParamValue {
   138  			return fmt.Errorf("Chaincode version is not provided for %s", cmd.Name())
   139  		}
   140  	}
   141  
   142  	// if it's not a deploy or an upgrade we don't need policy, escc and vscc
   143  	if cmd.Name() != instantiate_cmdname && cmd.Name() != upgrade_cmdname {
   144  		if escc != common.UndefinedParamValue {
   145  			return errors.New("escc should be supplied only to chaincode deploy requests")
   146  		}
   147  
   148  		if vscc != common.UndefinedParamValue {
   149  			return errors.New("vscc should be supplied only to chaincode deploy requests")
   150  		}
   151  
   152  		if policy != common.UndefinedParamValue {
   153  			return errors.New("policy should be supplied only to chaincode deploy requests")
   154  		}
   155  	} else {
   156  		if escc != common.UndefinedParamValue {
   157  			logger.Infof("Using escc %s", escc)
   158  		} else {
   159  			logger.Info("Using default escc")
   160  			escc = "escc"
   161  		}
   162  
   163  		if vscc != common.UndefinedParamValue {
   164  			logger.Infof("Using vscc %s", vscc)
   165  		} else {
   166  			logger.Info("Using default vscc")
   167  			vscc = "vscc"
   168  		}
   169  
   170  		if policy != common.UndefinedParamValue {
   171  			p, err := cauthdsl.FromString(policy)
   172  			if err != nil {
   173  				return fmt.Errorf("Invalid policy %s", policy)
   174  			}
   175  			policyMarhsalled = putils.MarshalOrPanic(p)
   176  		} else {
   177  			// FIXME: we need to get the default from somewhere
   178  			p := cauthdsl.SignedByMspMember("DEFAULT")
   179  			policyMarhsalled = putils.MarshalOrPanic(p)
   180  		}
   181  	}
   182  
   183  	// Check that non-empty chaincode parameters contain only Args as a key.
   184  	// Type checking is done later when the JSON is actually unmarshaled
   185  	// into a pb.ChaincodeInput. To better understand what's going
   186  	// on here with JSON parsing see http://blog.golang.org/json-and-go -
   187  	// Generic JSON with interface{}
   188  	if chaincodeCtorJSON != "{}" {
   189  		var f interface{}
   190  		err := json.Unmarshal([]byte(chaincodeCtorJSON), &f)
   191  		if err != nil {
   192  			return fmt.Errorf("Chaincode argument error: %s", err)
   193  		}
   194  		m := f.(map[string]interface{})
   195  		sm := make(map[string]interface{})
   196  		for k := range m {
   197  			sm[strings.ToLower(k)] = m[k]
   198  		}
   199  		_, argsPresent := sm["args"]
   200  		_, funcPresent := sm["function"]
   201  		if !argsPresent || (len(m) == 2 && !funcPresent) || len(m) > 2 {
   202  			return errors.New("Non-empty JSON chaincode parameters must contain the following keys: 'Args' or 'Function' and 'Args'")
   203  		}
   204  	} else {
   205  		if cmd == nil || cmd != chaincodeInstallCmd {
   206  			return errors.New("Empty JSON chaincode parameters must contain the following keys: 'Args' or 'Function' and 'Args'")
   207  		}
   208  	}
   209  
   210  	return nil
   211  }
   212  
   213  // ChaincodeCmdFactory holds the clients used by ChaincodeCmd
   214  type ChaincodeCmdFactory struct {
   215  	EndorserClient  pb.EndorserClient
   216  	Signer          msp.SigningIdentity
   217  	BroadcastClient common.BroadcastClient
   218  }
   219  
   220  // InitCmdFactory init the ChaincodeCmdFactory with default clients
   221  func InitCmdFactory() (*ChaincodeCmdFactory, error) {
   222  	endorserClient, err := common.GetEndorserClient()
   223  	if err != nil {
   224  		return nil, fmt.Errorf("Error getting endorser client %s: %s", chainFuncName, err)
   225  	}
   226  
   227  	signer, err := common.GetDefaultSigner()
   228  	if err != nil {
   229  		return nil, fmt.Errorf("Error getting default signer: %s", err)
   230  	}
   231  
   232  	broadcastClient, err := common.GetBroadcastClient()
   233  	if err != nil {
   234  		return nil, fmt.Errorf("Error getting broadcast client: %s", err)
   235  	}
   236  
   237  	return &ChaincodeCmdFactory{
   238  		EndorserClient:  endorserClient,
   239  		Signer:          signer,
   240  		BroadcastClient: broadcastClient,
   241  	}, nil
   242  }
   243  
   244  // ChaincodeInvokeOrQuery invokes or queries the chaincode. If successful, the
   245  // INVOKE form prints the ProposalResponse to STDOUT, and the QUERY form prints
   246  // the query result on STDOUT. A command-line flag (-r, --raw) determines
   247  // whether the query result is output as raw bytes, or as a printable string.
   248  // The printable form is optionally (-x, --hex) a hexadecimal representation
   249  // of the query response. If the query response is NIL, nothing is output.
   250  //
   251  // NOTE - Query will likely go away as all interactions with the endorser are
   252  // Proposal and ProposalResponses
   253  func ChaincodeInvokeOrQuery(spec *pb.ChaincodeSpec, cID string, invoke bool, signer msp.SigningIdentity, endorserClient pb.EndorserClient, bc common.BroadcastClient) (*pb.ProposalResponse, error) {
   254  	// Build the ChaincodeInvocationSpec message
   255  	invocation := &pb.ChaincodeInvocationSpec{ChaincodeSpec: spec}
   256  	if customIDGenAlg != common.UndefinedParamValue {
   257  		invocation.IdGenerationAlg = customIDGenAlg
   258  	}
   259  
   260  	creator, err := signer.Serialize()
   261  	if err != nil {
   262  		return nil, fmt.Errorf("Error serializing identity for %s: %s", signer.GetIdentifier(), err)
   263  	}
   264  
   265  	funcName := "invoke"
   266  	if !invoke {
   267  		funcName = "query"
   268  	}
   269  
   270  	var prop *pb.Proposal
   271  	prop, _, err = putils.CreateProposalFromCIS(pcommon.HeaderType_ENDORSER_TRANSACTION, cID, invocation, creator)
   272  	if err != nil {
   273  		return nil, fmt.Errorf("Error creating proposal  %s: %s", funcName, err)
   274  	}
   275  
   276  	var signedProp *pb.SignedProposal
   277  	signedProp, err = putils.GetSignedProposal(prop, signer)
   278  	if err != nil {
   279  		return nil, fmt.Errorf("Error creating signed proposal  %s: %s", funcName, err)
   280  	}
   281  
   282  	var proposalResp *pb.ProposalResponse
   283  	proposalResp, err = endorserClient.ProcessProposal(context.Background(), signedProp)
   284  	if err != nil {
   285  		return nil, fmt.Errorf("Error endorsing %s: %s", funcName, err)
   286  	}
   287  
   288  	if invoke {
   289  		if proposalResp != nil {
   290  			// assemble a signed transaction (it's an Envelope message)
   291  			env, err := putils.CreateSignedTx(prop, signer, proposalResp)
   292  			if err != nil {
   293  				return proposalResp, fmt.Errorf("Could not assemble transaction, err %s", err)
   294  			}
   295  
   296  			// send the envelope for ordering
   297  			if err = bc.Send(env); err != nil {
   298  				return proposalResp, fmt.Errorf("Error sending transaction %s: %s", funcName, err)
   299  			}
   300  		}
   301  	}
   302  
   303  	return proposalResp, nil
   304  }