github.com/adnan-c/fabric_e2e_couchdb@v0.6.1-preview.0.20170228180935-21ce6b23cf91/core/scc/lccc/lccc.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 lccc
    18  
    19  import (
    20  	"fmt"
    21  	"strconv"
    22  	"strings"
    23  
    24  	"github.com/golang/protobuf/proto"
    25  	"github.com/hyperledger/fabric/common/cauthdsl"
    26  	"github.com/hyperledger/fabric/core/chaincode/shim"
    27  	"github.com/hyperledger/fabric/core/common/ccprovider"
    28  	"github.com/hyperledger/fabric/core/common/sysccprovider"
    29  	pb "github.com/hyperledger/fabric/protos/peer"
    30  	"github.com/hyperledger/fabric/protos/utils"
    31  	"github.com/op/go-logging"
    32  )
    33  
    34  //The life cycle system chaincode manages chaincodes deployed
    35  //on this peer. It manages chaincodes via Invoke proposals.
    36  //     "Args":["deploy",<ChaincodeDeploymentSpec>]
    37  //     "Args":["upgrade",<ChaincodeDeploymentSpec>]
    38  //     "Args":["stop",<ChaincodeInvocationSpec>]
    39  //     "Args":["start",<ChaincodeInvocationSpec>]
    40  
    41  var logger = logging.MustGetLogger("lccc")
    42  
    43  const (
    44  	//CHAINCODETABLE prefix for chaincode tables
    45  	CHAINCODETABLE = "chaincodes"
    46  
    47  	//chaincode lifecyle commands
    48  
    49  	//INSTALL install command
    50  	INSTALL = "install"
    51  
    52  	//DEPLOY deploy command
    53  	DEPLOY = "deploy"
    54  
    55  	//UPGRADE upgrade chaincode
    56  	UPGRADE = "upgrade"
    57  
    58  	//GETCCINFO get chaincode
    59  	GETCCINFO = "getid"
    60  
    61  	//GETDEPSPEC get ChaincodeDeploymentSpec
    62  	GETDEPSPEC = "getdepspec"
    63  
    64  	//GETCCDATA get ChaincodeData
    65  	GETCCDATA = "getccdata"
    66  
    67  	//GETCHAINCODES gets the instantiated chaincodes on a channel
    68  	GETCHAINCODES = "getchaincodes"
    69  
    70  	//GETINSTALLEDCHAINCODES gets the installed chaincodes on a peer
    71  	GETINSTALLEDCHAINCODES = "getinstalledchaincodes"
    72  
    73  	//characters used in chaincodenamespace
    74  	specialChars = "/:[]${}"
    75  )
    76  
    77  //---------- the LCCC -----------------
    78  
    79  // LifeCycleSysCC implements chaincode lifecycle and policies aroud it
    80  type LifeCycleSysCC struct {
    81  	// sccprovider is the interface with which we call
    82  	// methods of the system chaincode package without
    83  	// import cycles
    84  	sccprovider sysccprovider.SystemChaincodeProvider
    85  }
    86  
    87  //----------------errors---------------
    88  
    89  //AlreadyRegisteredErr Already registered error
    90  type AlreadyRegisteredErr string
    91  
    92  func (f AlreadyRegisteredErr) Error() string {
    93  	return fmt.Sprintf("%s already registered", string(f))
    94  }
    95  
    96  //InvalidFunctionErr invalid function error
    97  type InvalidFunctionErr string
    98  
    99  func (f InvalidFunctionErr) Error() string {
   100  	return fmt.Sprintf("invalid function to lccc %s", string(f))
   101  }
   102  
   103  //InvalidArgsLenErr invalid arguments length error
   104  type InvalidArgsLenErr int
   105  
   106  func (i InvalidArgsLenErr) Error() string {
   107  	return fmt.Sprintf("invalid number of argument to lccc %d", int(i))
   108  }
   109  
   110  //InvalidArgsErr invalid arguments error
   111  type InvalidArgsErr int
   112  
   113  func (i InvalidArgsErr) Error() string {
   114  	return fmt.Sprintf("invalid argument (%d) to lccc", int(i))
   115  }
   116  
   117  //TXExistsErr transaction exists error
   118  type TXExistsErr string
   119  
   120  func (t TXExistsErr) Error() string {
   121  	return fmt.Sprintf("transaction exists %s", string(t))
   122  }
   123  
   124  //TXNotFoundErr transaction not found error
   125  type TXNotFoundErr string
   126  
   127  func (t TXNotFoundErr) Error() string {
   128  	return fmt.Sprintf("transaction not found %s", string(t))
   129  }
   130  
   131  //InvalidDeploymentSpecErr invalide chaincode deployment spec error
   132  type InvalidDeploymentSpecErr string
   133  
   134  func (f InvalidDeploymentSpecErr) Error() string {
   135  	return fmt.Sprintf("Invalid deployment spec : %s", string(f))
   136  }
   137  
   138  //ExistsErr chaincode exists error
   139  type ExistsErr string
   140  
   141  func (t ExistsErr) Error() string {
   142  	return fmt.Sprintf("Chaincode exists %s", string(t))
   143  }
   144  
   145  //NotFoundErr chaincode not registered with LCCC error
   146  type NotFoundErr string
   147  
   148  func (t NotFoundErr) Error() string {
   149  	return fmt.Sprintf("chaincode not found %s", string(t))
   150  }
   151  
   152  //InvalidChainNameErr invalid chain name error
   153  type InvalidChainNameErr string
   154  
   155  func (f InvalidChainNameErr) Error() string {
   156  	return fmt.Sprintf("invalid chain name %s", string(f))
   157  }
   158  
   159  //InvalidChaincodeNameErr invalid chaincode name error
   160  type InvalidChaincodeNameErr string
   161  
   162  func (f InvalidChaincodeNameErr) Error() string {
   163  	return fmt.Sprintf("invalid chain code name %s", string(f))
   164  }
   165  
   166  //MarshallErr error marshaling/unmarshalling
   167  type MarshallErr string
   168  
   169  func (m MarshallErr) Error() string {
   170  	return fmt.Sprintf("error while marshalling %s", string(m))
   171  }
   172  
   173  //IdenticalVersionErr trying to upgrade to same version of Chaincode
   174  type IdenticalVersionErr string
   175  
   176  func (f IdenticalVersionErr) Error() string {
   177  	return fmt.Sprintf("chain code with the same version exists %s", string(f))
   178  }
   179  
   180  //InvalidVersionErr trying to upgrade to same version of Chaincode
   181  type InvalidVersionErr string
   182  
   183  func (f InvalidVersionErr) Error() string {
   184  	return fmt.Sprintf("invalid version %s", string(f))
   185  }
   186  
   187  //EmptyVersionErr trying to upgrade to same version of Chaincode
   188  type EmptyVersionErr string
   189  
   190  func (f EmptyVersionErr) Error() string {
   191  	return fmt.Sprintf("version not provided for chaincode %s", string(f))
   192  }
   193  
   194  //-------------- helper functions ------------------
   195  //create the chaincode on the given chain
   196  func (lccc *LifeCycleSysCC) createChaincode(stub shim.ChaincodeStubInterface, chainname string, ccname string, version string, cccode []byte, policy []byte, escc []byte, vscc []byte) (*ccprovider.ChaincodeData, error) {
   197  	return lccc.putChaincodeData(stub, chainname, ccname, version, cccode, policy, escc, vscc)
   198  }
   199  
   200  //upgrade the chaincode on the given chain
   201  func (lccc *LifeCycleSysCC) upgradeChaincode(stub shim.ChaincodeStubInterface, chainname string, ccname string, version string, cccode []byte, policy []byte, escc []byte, vscc []byte) (*ccprovider.ChaincodeData, error) {
   202  	return lccc.putChaincodeData(stub, chainname, ccname, version, cccode, policy, escc, vscc)
   203  }
   204  
   205  //create the chaincode on the given chain
   206  func (lccc *LifeCycleSysCC) putChaincodeData(stub shim.ChaincodeStubInterface, chainname string, ccname string, version string, cccode []byte, policy []byte, escc []byte, vscc []byte) (*ccprovider.ChaincodeData, error) {
   207  	// check that escc and vscc are real system chaincodes
   208  	if !lccc.sccprovider.IsSysCC(string(escc)) {
   209  		return nil, fmt.Errorf("%s is not a valid endorsement system chaincode", string(escc))
   210  	}
   211  	if !lccc.sccprovider.IsSysCC(string(vscc)) {
   212  		return nil, fmt.Errorf("%s is not a valid validation system chaincode", string(vscc))
   213  	}
   214  
   215  	cd := &ccprovider.ChaincodeData{Name: ccname, Version: version, DepSpec: cccode, Policy: policy, Escc: string(escc), Vscc: string(vscc)}
   216  	cdbytes, err := proto.Marshal(cd)
   217  	if err != nil {
   218  		return nil, err
   219  	}
   220  
   221  	if cdbytes == nil {
   222  		return nil, MarshallErr(ccname)
   223  	}
   224  
   225  	err = stub.PutState(ccname, cdbytes)
   226  
   227  	return cd, err
   228  }
   229  
   230  //checks for existence of chaincode on the given chain
   231  func (lccc *LifeCycleSysCC) getChaincode(stub shim.ChaincodeStubInterface, ccname string, checkFS bool) (*ccprovider.ChaincodeData, []byte, error) {
   232  	cdbytes, err := stub.GetState(ccname)
   233  	if err != nil {
   234  		return nil, nil, err
   235  	}
   236  
   237  	if cdbytes != nil {
   238  		cd := &ccprovider.ChaincodeData{}
   239  		err = proto.Unmarshal(cdbytes, cd)
   240  		if err != nil {
   241  			return nil, nil, MarshallErr(ccname)
   242  		}
   243  
   244  		if checkFS {
   245  			cd.DepSpec, _, err = ccprovider.GetChaincodeFromFS(ccname, cd.Version)
   246  			if err != nil {
   247  				return cd, nil, InvalidDeploymentSpecErr(err.Error())
   248  			}
   249  		}
   250  
   251  		return cd, cdbytes, nil
   252  	}
   253  
   254  	return nil, nil, NotFoundErr(ccname)
   255  }
   256  
   257  // getChaincodes returns all chaincodes instantiated on this LCCC's channel
   258  func (lccc *LifeCycleSysCC) getChaincodes(stub shim.ChaincodeStubInterface) pb.Response {
   259  	// get all rows from LCCC
   260  	itr, err := stub.GetStateByRange("", "")
   261  
   262  	if err != nil {
   263  		return shim.Error(err.Error())
   264  	}
   265  	defer itr.Close()
   266  
   267  	// array to store metadata for all chaincode entries from LCCC
   268  	var ccInfoArray []*pb.ChaincodeInfo
   269  
   270  	for itr.HasNext() {
   271  		_, value, err := itr.Next()
   272  		if err != nil {
   273  			return shim.Error(err.Error())
   274  		}
   275  
   276  		ccdata := &ccprovider.ChaincodeData{}
   277  		if err = proto.Unmarshal(value, ccdata); err != nil {
   278  			return shim.Error(err.Error())
   279  		}
   280  
   281  		ccdepspec := &pb.ChaincodeDeploymentSpec{}
   282  		if err = proto.Unmarshal(ccdata.DepSpec, ccdepspec); err != nil {
   283  			return shim.Error(err.Error())
   284  		}
   285  
   286  		path := ccdepspec.GetChaincodeSpec().ChaincodeId.Path
   287  		input := ccdepspec.GetChaincodeSpec().Input.String()
   288  
   289  		ccInfo := &pb.ChaincodeInfo{Name: ccdata.Name, Version: ccdata.Version, Path: path, Input: input, Escc: ccdata.Escc, Vscc: ccdata.Vscc}
   290  
   291  		// add this specific chaincode's metadata to the array of all chaincodes
   292  		ccInfoArray = append(ccInfoArray, ccInfo)
   293  	}
   294  	// add array with info about all instantiated chaincodes to the query
   295  	// response proto
   296  	cqr := &pb.ChaincodeQueryResponse{Chaincodes: ccInfoArray}
   297  
   298  	cqrbytes, err := proto.Marshal(cqr)
   299  	if err != nil {
   300  		return shim.Error(err.Error())
   301  	}
   302  
   303  	return shim.Success(cqrbytes)
   304  }
   305  
   306  // getInstalledChaincodes returns all chaincodes installed on the peer
   307  func (lccc *LifeCycleSysCC) getInstalledChaincodes() pb.Response {
   308  	// get chaincode query response proto which contains information about all
   309  	// installed chaincodes
   310  	cqr, err := ccprovider.GetInstalledChaincodes()
   311  	if err != nil {
   312  		return shim.Error(err.Error())
   313  	}
   314  
   315  	cqrbytes, err := proto.Marshal(cqr)
   316  	if err != nil {
   317  		return shim.Error(err.Error())
   318  	}
   319  
   320  	return shim.Success(cqrbytes)
   321  }
   322  
   323  //do access control
   324  func (lccc *LifeCycleSysCC) acl(stub shim.ChaincodeStubInterface, chainname string, cds *pb.ChaincodeDeploymentSpec) error {
   325  	return nil
   326  }
   327  
   328  //check validity of chain name
   329  func (lccc *LifeCycleSysCC) isValidChainName(chainname string) bool {
   330  	//TODO we probably need more checks
   331  	if chainname == "" {
   332  		return false
   333  	}
   334  	return true
   335  }
   336  
   337  //check validity of chaincode name
   338  func (lccc *LifeCycleSysCC) isValidChaincodeName(chaincodename string) bool {
   339  	//TODO we probably need more checks
   340  	if chaincodename == "" {
   341  		return false
   342  	}
   343  
   344  	//do not allow special characters in chaincode name
   345  	if strings.ContainsAny(chaincodename, specialChars) {
   346  		return false
   347  	}
   348  
   349  	return true
   350  }
   351  
   352  //this implements "install" Invoke transaction
   353  func (lccc *LifeCycleSysCC) executeInstall(stub shim.ChaincodeStubInterface, depSpec []byte) error {
   354  	cds, err := utils.GetChaincodeDeploymentSpec(depSpec)
   355  
   356  	if err != nil {
   357  		return err
   358  	}
   359  
   360  	if !lccc.isValidChaincodeName(cds.ChaincodeSpec.ChaincodeId.Name) {
   361  		return InvalidChaincodeNameErr(cds.ChaincodeSpec.ChaincodeId.Name)
   362  	}
   363  
   364  	if cds.ChaincodeSpec.ChaincodeId.Version == "" {
   365  		return EmptyVersionErr(cds.ChaincodeSpec.ChaincodeId.Name)
   366  	}
   367  
   368  	if err = ccprovider.PutChaincodeIntoFS(cds); err != nil {
   369  		return fmt.Errorf("Error installing chaincode code %s:%s(%s)", cds.ChaincodeSpec.ChaincodeId.Name, cds.ChaincodeSpec.ChaincodeId.Version, err)
   370  	}
   371  
   372  	return err
   373  }
   374  
   375  //this implements "deploy" Invoke transaction
   376  func (lccc *LifeCycleSysCC) executeDeploy(stub shim.ChaincodeStubInterface, chainname string, depSpec []byte, policy []byte, escc []byte, vscc []byte) error {
   377  	cds, err := utils.GetChaincodeDeploymentSpec(depSpec)
   378  
   379  	if err != nil {
   380  		return err
   381  	}
   382  
   383  	if !lccc.isValidChaincodeName(cds.ChaincodeSpec.ChaincodeId.Name) {
   384  		return InvalidChaincodeNameErr(cds.ChaincodeSpec.ChaincodeId.Name)
   385  	}
   386  
   387  	if err = lccc.acl(stub, chainname, cds); err != nil {
   388  		return err
   389  	}
   390  
   391  	cd, _, err := lccc.getChaincode(stub, cds.ChaincodeSpec.ChaincodeId.Name, true)
   392  	if cd != nil {
   393  		return ExistsErr(cds.ChaincodeSpec.ChaincodeId.Name)
   394  	}
   395  
   396  	if cds.ChaincodeSpec.ChaincodeId.Version == "" {
   397  		return EmptyVersionErr(cds.ChaincodeSpec.ChaincodeId.Name)
   398  	}
   399  
   400  	_, err = lccc.createChaincode(stub, chainname, cds.ChaincodeSpec.ChaincodeId.Name, cds.ChaincodeSpec.ChaincodeId.Version, depSpec, policy, escc, vscc)
   401  
   402  	return err
   403  }
   404  
   405  func (lccc *LifeCycleSysCC) getUpgradeVersion(cd *ccprovider.ChaincodeData, cds *pb.ChaincodeDeploymentSpec) (string, error) {
   406  	if cd.Version == cds.ChaincodeSpec.ChaincodeId.Version {
   407  		return "", IdenticalVersionErr(cds.ChaincodeSpec.ChaincodeId.Name)
   408  	}
   409  
   410  	if cds.ChaincodeSpec.ChaincodeId.Version != "" {
   411  		return cds.ChaincodeSpec.ChaincodeId.Version, nil
   412  	}
   413  
   414  	//user did not specifcy Version. the previous version better be a number
   415  	v, err := strconv.ParseInt(cd.Version, 10, 32)
   416  
   417  	//This should never happen as long we don't expose version as version is computed internally
   418  	//so panic till we find a need to relax
   419  	if err != nil {
   420  		return "", InvalidVersionErr(cd.Version)
   421  	}
   422  
   423  	// replace the ChaincodeDeploymentSpec using the next version
   424  	newVersion := fmt.Sprintf("%d", (v + 1))
   425  
   426  	return newVersion, nil
   427  }
   428  
   429  //this implements "upgrade" Invoke transaction
   430  func (lccc *LifeCycleSysCC) executeUpgrade(stub shim.ChaincodeStubInterface, chainName string, depSpec []byte, policy []byte, escc []byte, vscc []byte) ([]byte, error) {
   431  	cds, err := utils.GetChaincodeDeploymentSpec(depSpec)
   432  	if err != nil {
   433  		return nil, err
   434  	}
   435  
   436  	if err = lccc.acl(stub, chainName, cds); err != nil {
   437  		return nil, err
   438  	}
   439  
   440  	chaincodeName := cds.ChaincodeSpec.ChaincodeId.Name
   441  	if !lccc.isValidChaincodeName(chaincodeName) {
   442  		return nil, InvalidChaincodeNameErr(chaincodeName)
   443  	}
   444  
   445  	// check for existence of chaincode
   446  	cd, _, err := lccc.getChaincode(stub, chaincodeName, true)
   447  	if cd == nil {
   448  		return nil, NotFoundErr(chainName)
   449  	}
   450  
   451  	ver, err := lccc.getUpgradeVersion(cd, cds)
   452  	if err != nil {
   453  		return nil, err
   454  	}
   455  
   456  	newCD, err := lccc.upgradeChaincode(stub, chainName, chaincodeName, ver, depSpec, policy, escc, vscc)
   457  	if err != nil {
   458  		return nil, err
   459  	}
   460  
   461  	return []byte(newCD.Version), nil
   462  }
   463  
   464  //-------------- the chaincode stub interface implementation ----------
   465  
   466  //Init only initializes the system chaincode provider
   467  func (lccc *LifeCycleSysCC) Init(stub shim.ChaincodeStubInterface) pb.Response {
   468  	lccc.sccprovider = sysccprovider.GetSystemChaincodeProvider()
   469  	return shim.Success(nil)
   470  }
   471  
   472  // Invoke implements lifecycle functions "deploy", "start", "stop", "upgrade".
   473  // Deploy's arguments -  {[]byte("deploy"), []byte(<chainname>), <unmarshalled pb.ChaincodeDeploymentSpec>}
   474  //
   475  // Invoke also implements some query-like functions
   476  // Get chaincode arguments -  {[]byte("getid"), []byte(<chainname>), []byte(<chaincodename>)}
   477  func (lccc *LifeCycleSysCC) Invoke(stub shim.ChaincodeStubInterface) pb.Response {
   478  	args := stub.GetArgs()
   479  	if len(args) < 1 {
   480  		return shim.Error(InvalidArgsLenErr(len(args)).Error())
   481  	}
   482  
   483  	function := string(args[0])
   484  
   485  	switch function {
   486  	case INSTALL:
   487  		if len(args) < 2 {
   488  			return shim.Error(InvalidArgsLenErr(len(args)).Error())
   489  		}
   490  
   491  		depSpec := args[1]
   492  
   493  		err := lccc.executeInstall(stub, depSpec)
   494  		if err != nil {
   495  			return shim.Error(err.Error())
   496  		}
   497  		return shim.Success([]byte("OK"))
   498  	case DEPLOY:
   499  		if len(args) < 3 || len(args) > 6 {
   500  			return shim.Error(InvalidArgsLenErr(len(args)).Error())
   501  		}
   502  
   503  		//chain the chaincode shoud be associated with. It
   504  		//should be created with a register call
   505  		chainname := string(args[1])
   506  
   507  		if !lccc.isValidChainName(chainname) {
   508  			return shim.Error(InvalidChainNameErr(chainname).Error())
   509  		}
   510  
   511  		depSpec := args[2]
   512  
   513  		// optional arguments here (they can each be nil and may or may not be present)
   514  		// args[3] is a marshalled SignaturePolicyEnvelope representing the endorsement policy
   515  		// args[4] is the name of escc
   516  		// args[5] is the name of vscc
   517  		var policy []byte
   518  		if len(args) > 3 && args[3] != nil {
   519  			policy = args[3]
   520  		} else {
   521  			// FIXME: temporary workaround until all SDKs provide a policy
   522  			policy = utils.MarshalOrPanic(cauthdsl.SignedByMspMember("DEFAULT"))
   523  		}
   524  
   525  		var escc []byte
   526  		if len(args) > 4 && args[4] != nil {
   527  			escc = args[4]
   528  		} else {
   529  			escc = []byte("escc")
   530  		}
   531  
   532  		var vscc []byte
   533  		if len(args) > 5 && args[5] != nil {
   534  			vscc = args[5]
   535  		} else {
   536  			vscc = []byte("vscc")
   537  		}
   538  
   539  		err := lccc.executeDeploy(stub, chainname, depSpec, policy, escc, vscc)
   540  		if err != nil {
   541  			return shim.Error(err.Error())
   542  		}
   543  		return shim.Success(nil)
   544  	case UPGRADE:
   545  		if len(args) < 3 || len(args) > 6 {
   546  			return shim.Error(InvalidArgsLenErr(len(args)).Error())
   547  		}
   548  
   549  		chainname := string(args[1])
   550  		if !lccc.isValidChainName(chainname) {
   551  			return shim.Error(InvalidChainNameErr(chainname).Error())
   552  		}
   553  
   554  		depSpec := args[2]
   555  
   556  		// optional arguments here (they can each be nil and may or may not be present)
   557  		// args[3] is a marshalled SignaturePolicyEnvelope representing the endorsement policy
   558  		// args[4] is the name of escc
   559  		// args[5] is the name of vscc
   560  		var policy []byte
   561  		if len(args) > 3 && args[3] != nil {
   562  			policy = args[3]
   563  		} else {
   564  			// FIXME: temporary workaround until all SDKs provide a policy
   565  			policy = utils.MarshalOrPanic(cauthdsl.SignedByMspMember("DEFAULT"))
   566  		}
   567  
   568  		var escc []byte
   569  		if len(args) > 4 && args[4] != nil {
   570  			escc = args[4]
   571  		} else {
   572  			escc = []byte("escc")
   573  		}
   574  
   575  		var vscc []byte
   576  		if len(args) > 5 && args[5] != nil {
   577  			vscc = args[5]
   578  		} else {
   579  			vscc = []byte("vscc")
   580  		}
   581  
   582  		verBytes, err := lccc.executeUpgrade(stub, chainname, depSpec, policy, escc, vscc)
   583  		if err != nil {
   584  			return shim.Error(err.Error())
   585  		}
   586  		return shim.Success(verBytes)
   587  	case GETCCINFO, GETDEPSPEC, GETCCDATA:
   588  		if len(args) != 3 {
   589  			return shim.Error(InvalidArgsLenErr(len(args)).Error())
   590  		}
   591  
   592  		chain := string(args[1])
   593  		ccname := string(args[2])
   594  
   595  		//check the FS only for deployment spec
   596  		//other calls are looking for LCCC entries only
   597  		checkFS := false
   598  		if function == GETDEPSPEC {
   599  			checkFS = true
   600  		}
   601  		cd, cdbytes, err := lccc.getChaincode(stub, ccname, checkFS)
   602  		if cd == nil || cdbytes == nil {
   603  			logger.Errorf("ChaincodeId: %s does not exist on channel: %s(err:%s)", ccname, chain, err)
   604  			return shim.Error(TXNotFoundErr(ccname + "/" + chain).Error())
   605  		}
   606  
   607  		switch function {
   608  		case GETCCINFO:
   609  			return shim.Success([]byte(cd.Name))
   610  		case GETCCDATA:
   611  			return shim.Success(cdbytes)
   612  		default:
   613  			return shim.Success(cd.DepSpec)
   614  		}
   615  	case GETCHAINCODES:
   616  		if len(args) != 1 {
   617  			return shim.Error(InvalidArgsLenErr(len(args)).Error())
   618  		}
   619  		return lccc.getChaincodes(stub)
   620  	case GETINSTALLEDCHAINCODES:
   621  		if len(args) != 1 {
   622  			return shim.Error(InvalidArgsLenErr(len(args)).Error())
   623  		}
   624  		return lccc.getInstalledChaincodes()
   625  	}
   626  
   627  	return shim.Error(InvalidFunctionErr(function).Error())
   628  }