github.com/Hnampk/my-fabric@v0.0.0-20201028083322-75069da399c0/core/handlers/validation/builtin/v13/lscc_validation_logic.go (about)

     1  /*
     2  Copyright IBM Corp. All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  package v13
     8  
     9  import (
    10  	"bytes"
    11  	"fmt"
    12  
    13  	"github.com/golang/protobuf/proto"
    14  	"github.com/hyperledger/fabric-protos-go/common"
    15  	"github.com/hyperledger/fabric-protos-go/ledger/rwset/kvrwset"
    16  	pb "github.com/hyperledger/fabric-protos-go/peer"
    17  	commonerrors "github.com/hyperledger/fabric/common/errors"
    18  	"github.com/hyperledger/fabric/core/common/ccprovider"
    19  	"github.com/hyperledger/fabric/core/common/privdata"
    20  	vc "github.com/hyperledger/fabric/core/handlers/validation/api/capabilities"
    21  	vs "github.com/hyperledger/fabric/core/handlers/validation/api/state"
    22  	"github.com/hyperledger/fabric/core/ledger/kvledger/txmgmt/rwsetutil"
    23  	"github.com/hyperledger/fabric/core/scc/lscc"
    24  	"github.com/hyperledger/fabric/protoutil"
    25  	"github.com/pkg/errors"
    26  )
    27  
    28  // currently defined system chaincode names that shouldn't
    29  // be allowed as user-defined chaincode names
    30  var systemChaincodeNames = map[string]struct{}{
    31  	"cscc": {},
    32  	"escc": {},
    33  	"lscc": {},
    34  	"qscc": {},
    35  	"vscc": {},
    36  }
    37  
    38  // checkInstantiationPolicy evaluates an instantiation policy against a signed proposal
    39  func (vscc *Validator) checkInstantiationPolicy(chainName string, env *common.Envelope, instantiationPolicy []byte, payl *common.Payload) commonerrors.TxValidationError {
    40  	// get the signature header
    41  	shdr, err := protoutil.UnmarshalSignatureHeader(payl.Header.SignatureHeader)
    42  	if err != nil {
    43  		return policyErr(err)
    44  	}
    45  
    46  	// construct signed data we can evaluate the instantiation policy against
    47  	sd := []*protoutil.SignedData{{
    48  		Data:      env.Payload,
    49  		Identity:  shdr.Creator,
    50  		Signature: env.Signature,
    51  	}}
    52  	err = vscc.policyEvaluator.Evaluate(instantiationPolicy, sd)
    53  	if err != nil {
    54  		return policyErr(fmt.Errorf("chaincode instantiation policy violated, error %s", err))
    55  	}
    56  	return nil
    57  }
    58  
    59  func validateNewCollectionConfigs(newCollectionConfigs []*pb.CollectionConfig) error {
    60  	newCollectionsMap := make(map[string]bool, len(newCollectionConfigs))
    61  	// Process each collection config from a set of collection configs
    62  	for _, newCollectionConfig := range newCollectionConfigs {
    63  
    64  		newCollection := newCollectionConfig.GetStaticCollectionConfig()
    65  		if newCollection == nil {
    66  			return errors.New("unknown collection configuration type")
    67  		}
    68  
    69  		// Ensure that there are no duplicate collection names
    70  		collectionName := newCollection.GetName()
    71  
    72  		if err := validateCollectionName(collectionName); err != nil {
    73  			return err
    74  		}
    75  
    76  		if _, ok := newCollectionsMap[collectionName]; !ok {
    77  			newCollectionsMap[collectionName] = true
    78  		} else {
    79  			return fmt.Errorf("collection-name: %s -- found duplicate collection configuration", collectionName)
    80  		}
    81  
    82  		// Validate gossip related parameters present in the collection config
    83  		maximumPeerCount := newCollection.GetMaximumPeerCount()
    84  		requiredPeerCount := newCollection.GetRequiredPeerCount()
    85  		if maximumPeerCount < requiredPeerCount {
    86  			return fmt.Errorf("collection-name: %s -- maximum peer count (%d) cannot be less than the required peer count (%d)",
    87  				collectionName, maximumPeerCount, requiredPeerCount)
    88  
    89  		}
    90  		if requiredPeerCount < 0 {
    91  			return fmt.Errorf("collection-name: %s -- requiredPeerCount (%d) cannot be less than zero (%d)",
    92  				collectionName, maximumPeerCount, requiredPeerCount)
    93  
    94  		}
    95  
    96  		// make sure that the signature policy is meaningful (only consists of ORs)
    97  		err := validateSpOrConcat(newCollection.MemberOrgsPolicy.GetSignaturePolicy().Rule)
    98  		if err != nil {
    99  			return errors.WithMessagef(err, "collection-name: %s -- error in member org policy", collectionName)
   100  		}
   101  	}
   102  	return nil
   103  }
   104  
   105  // validateSpOrConcat checks if the supplied signature policy is just an OR-concatenation of identities
   106  func validateSpOrConcat(sp *common.SignaturePolicy) error {
   107  	if sp.GetNOutOf() == nil {
   108  		return nil
   109  	}
   110  	// check if N == 1 (OR concatenation)
   111  	if sp.GetNOutOf().N != 1 {
   112  		return errors.New(fmt.Sprintf("signature policy is not an OR concatenation, NOutOf %d", sp.GetNOutOf().N))
   113  	}
   114  	// recurse into all sub-rules
   115  	for _, rule := range sp.GetNOutOf().Rules {
   116  		err := validateSpOrConcat(rule)
   117  		if err != nil {
   118  			return err
   119  		}
   120  	}
   121  	return nil
   122  }
   123  
   124  func checkForMissingCollections(newCollectionsMap map[string]*pb.StaticCollectionConfig, oldCollectionConfigs []*pb.CollectionConfig,
   125  ) error {
   126  	var missingCollections []string
   127  
   128  	// In the new collection config package, ensure that there is one entry per old collection. Any
   129  	// number of new collections are allowed.
   130  	for _, oldCollectionConfig := range oldCollectionConfigs {
   131  
   132  		oldCollection := oldCollectionConfig.GetStaticCollectionConfig()
   133  		// It cannot be nil
   134  		if oldCollection == nil {
   135  			return policyErr(fmt.Errorf("unknown collection configuration type"))
   136  		}
   137  
   138  		// All old collection must exist in the new collection config package
   139  		oldCollectionName := oldCollection.GetName()
   140  		_, ok := newCollectionsMap[oldCollectionName]
   141  		if !ok {
   142  			missingCollections = append(missingCollections, oldCollectionName)
   143  		}
   144  	}
   145  
   146  	if len(missingCollections) > 0 {
   147  		return policyErr(fmt.Errorf("the following existing collections are missing in the new collection configuration package: %v",
   148  			missingCollections))
   149  	}
   150  
   151  	return nil
   152  }
   153  
   154  func checkForModifiedCollectionsBTL(newCollectionsMap map[string]*pb.StaticCollectionConfig, oldCollectionConfigs []*pb.CollectionConfig,
   155  ) error {
   156  	var modifiedCollectionsBTL []string
   157  
   158  	// In the new collection config package, ensure that the block to live value is not
   159  	// modified for the existing collections.
   160  	for _, oldCollectionConfig := range oldCollectionConfigs {
   161  
   162  		oldCollection := oldCollectionConfig.GetStaticCollectionConfig()
   163  		// It cannot be nil
   164  		if oldCollection == nil {
   165  			return policyErr(fmt.Errorf("unknown collection configuration type"))
   166  		}
   167  
   168  		oldCollectionName := oldCollection.GetName()
   169  		newCollection, _ := newCollectionsMap[oldCollectionName]
   170  		// BlockToLive cannot be changed
   171  		if newCollection.GetBlockToLive() != oldCollection.GetBlockToLive() {
   172  			modifiedCollectionsBTL = append(modifiedCollectionsBTL, oldCollectionName)
   173  		}
   174  	}
   175  
   176  	if len(modifiedCollectionsBTL) > 0 {
   177  		return policyErr(fmt.Errorf("the BlockToLive in the following existing collections must not be modified: %v",
   178  			modifiedCollectionsBTL))
   179  	}
   180  
   181  	return nil
   182  }
   183  
   184  func validateNewCollectionConfigsAgainstOld(newCollectionConfigs []*pb.CollectionConfig, oldCollectionConfigs []*pb.CollectionConfig,
   185  ) error {
   186  	newCollectionsMap := make(map[string]*pb.StaticCollectionConfig, len(newCollectionConfigs))
   187  
   188  	for _, newCollectionConfig := range newCollectionConfigs {
   189  		newCollection := newCollectionConfig.GetStaticCollectionConfig()
   190  		// Collection object itself is stored as value so that we can
   191  		// check whether the block to live is changed -- FAB-7810
   192  		newCollectionsMap[newCollection.GetName()] = newCollection
   193  	}
   194  
   195  	if err := checkForMissingCollections(newCollectionsMap, oldCollectionConfigs); err != nil {
   196  		return err
   197  	}
   198  
   199  	if err := checkForModifiedCollectionsBTL(newCollectionsMap, oldCollectionConfigs); err != nil {
   200  		return err
   201  	}
   202  
   203  	return nil
   204  }
   205  
   206  func validateCollectionName(collectionName string) error {
   207  	if collectionName == "" {
   208  		return fmt.Errorf("empty collection-name is not allowed")
   209  	}
   210  	match := validCollectionNameRegex.FindString(collectionName)
   211  	if len(match) != len(collectionName) {
   212  		return fmt.Errorf("collection-name: %s not allowed. A valid collection name follows the pattern: %s",
   213  			collectionName, AllowedCharsCollectionName)
   214  	}
   215  	return nil
   216  }
   217  
   218  // validateRWSetAndCollection performs validation of the rwset
   219  // of an LSCC deploy operation and then it validates any collection
   220  // configuration
   221  func (vscc *Validator) validateRWSetAndCollection(
   222  	lsccrwset *kvrwset.KVRWSet,
   223  	cdRWSet *ccprovider.ChaincodeData,
   224  	lsccArgs [][]byte,
   225  	lsccFunc string,
   226  	ac vc.Capabilities,
   227  	channelName string,
   228  ) commonerrors.TxValidationError {
   229  	/********************************************/
   230  	/* security check 0.a - validation of rwset */
   231  	/********************************************/
   232  	// there can only be one or two writes
   233  	if len(lsccrwset.Writes) > 2 {
   234  		return policyErr(fmt.Errorf("LSCC can only issue one or two putState upon deploy"))
   235  	}
   236  
   237  	/**********************************************************/
   238  	/* security check 0.b - validation of the collection data */
   239  	/**********************************************************/
   240  	var collectionsConfigArg []byte
   241  	if len(lsccArgs) > 5 {
   242  		collectionsConfigArg = lsccArgs[5]
   243  	}
   244  
   245  	var collectionsConfigLedger []byte
   246  	if len(lsccrwset.Writes) == 2 {
   247  		key := privdata.BuildCollectionKVSKey(cdRWSet.Name)
   248  		if lsccrwset.Writes[1].Key != key {
   249  			return policyErr(fmt.Errorf("invalid key for the collection of chaincode %s:%s; expected '%s', received '%s'",
   250  				cdRWSet.Name, cdRWSet.Version, key, lsccrwset.Writes[1].Key))
   251  
   252  		}
   253  
   254  		collectionsConfigLedger = lsccrwset.Writes[1].Value
   255  	}
   256  
   257  	if !bytes.Equal(collectionsConfigArg, collectionsConfigLedger) {
   258  		return policyErr(fmt.Errorf("collection configuration arguments supplied for chaincode %s:%s do not match the configuration in the lscc writeset",
   259  			cdRWSet.Name, cdRWSet.Version))
   260  
   261  	}
   262  
   263  	channelState, err := vscc.stateFetcher.FetchState()
   264  	if err != nil {
   265  		return &commonerrors.VSCCExecutionFailureError{Err: fmt.Errorf("failed obtaining query executor: %v", err)}
   266  	}
   267  	defer channelState.Done()
   268  
   269  	state := &state{channelState}
   270  
   271  	// The following condition check added in v1.1 may not be needed as it is not possible to have the chaincodeName~collection key in
   272  	// the lscc namespace before a chaincode deploy. To avoid forks in v1.2, the following condition is retained.
   273  	if lsccFunc == lscc.DEPLOY {
   274  		colCriteria := privdata.CollectionCriteria{Channel: channelName, Namespace: cdRWSet.Name}
   275  		ccp, err := privdata.RetrieveCollectionConfigPackageFromState(colCriteria, state)
   276  		if err != nil {
   277  			// fail if we get any error other than NoSuchCollectionError
   278  			// because it means something went wrong while looking up the
   279  			// older collection
   280  			if _, ok := err.(privdata.NoSuchCollectionError); !ok {
   281  				return &commonerrors.VSCCExecutionFailureError{Err: fmt.Errorf("unable to check whether collection existed earlier for chaincode %s:%s",
   282  					cdRWSet.Name, cdRWSet.Version),
   283  				}
   284  			}
   285  		}
   286  		if ccp != nil {
   287  			return policyErr(fmt.Errorf("collection data should not exist for chaincode %s:%s", cdRWSet.Name, cdRWSet.Version))
   288  		}
   289  	}
   290  
   291  	// TODO: Once the new chaincode lifecycle is available (FAB-8724), the following validation
   292  	// and other validation performed in ValidateLSCCInvocation can be moved to LSCC itself.
   293  	newCollectionConfigPackage := &pb.CollectionConfigPackage{}
   294  
   295  	if collectionsConfigArg != nil {
   296  		err := proto.Unmarshal(collectionsConfigArg, newCollectionConfigPackage)
   297  		if err != nil {
   298  			return policyErr(fmt.Errorf("invalid collection configuration supplied for chaincode %s:%s",
   299  				cdRWSet.Name, cdRWSet.Version))
   300  		}
   301  	} else {
   302  		return nil
   303  	}
   304  
   305  	if ac.V1_2Validation() {
   306  		newCollectionConfigs := newCollectionConfigPackage.GetConfig()
   307  		if err := validateNewCollectionConfigs(newCollectionConfigs); err != nil {
   308  			return policyErr(err)
   309  		}
   310  
   311  		if lsccFunc == lscc.UPGRADE {
   312  
   313  			collectionCriteria := privdata.CollectionCriteria{Channel: channelName, Namespace: cdRWSet.Name}
   314  			// oldCollectionConfigPackage denotes the existing collection config package in the ledger
   315  			oldCollectionConfigPackage, err := privdata.RetrieveCollectionConfigPackageFromState(collectionCriteria, state)
   316  			if err != nil {
   317  				// fail if we get any error other than NoSuchCollectionError
   318  				// because it means something went wrong while looking up the
   319  				// older collection
   320  				if _, ok := err.(privdata.NoSuchCollectionError); !ok {
   321  					return &commonerrors.VSCCExecutionFailureError{Err: fmt.Errorf("unable to check whether collection existed earlier for chaincode %s:%s: %v",
   322  						cdRWSet.Name, cdRWSet.Version, err),
   323  					}
   324  				}
   325  			}
   326  
   327  			// oldCollectionConfigPackage denotes the existing collection config package in the ledger
   328  			if oldCollectionConfigPackage != nil {
   329  				oldCollectionConfigs := oldCollectionConfigPackage.GetConfig()
   330  				if err := validateNewCollectionConfigsAgainstOld(newCollectionConfigs, oldCollectionConfigs); err != nil {
   331  					return policyErr(err)
   332  				}
   333  
   334  			}
   335  		}
   336  	}
   337  
   338  	return nil
   339  }
   340  
   341  func (vscc *Validator) ValidateLSCCInvocation(
   342  	chid string,
   343  	env *common.Envelope,
   344  	cap *pb.ChaincodeActionPayload,
   345  	payl *common.Payload,
   346  	ac vc.Capabilities,
   347  ) commonerrors.TxValidationError {
   348  	cpp, err := protoutil.UnmarshalChaincodeProposalPayload(cap.ChaincodeProposalPayload)
   349  	if err != nil {
   350  		logger.Errorf("VSCC error: GetChaincodeProposalPayload failed, err %s", err)
   351  		return policyErr(err)
   352  	}
   353  
   354  	cis := &pb.ChaincodeInvocationSpec{}
   355  	err = proto.Unmarshal(cpp.Input, cis)
   356  	if err != nil {
   357  		logger.Errorf("VSCC error: Unmarshal ChaincodeInvocationSpec failed, err %s", err)
   358  		return policyErr(err)
   359  	}
   360  
   361  	if cis.ChaincodeSpec == nil ||
   362  		cis.ChaincodeSpec.Input == nil ||
   363  		cis.ChaincodeSpec.Input.Args == nil {
   364  		logger.Errorf("VSCC error: committing invalid vscc invocation")
   365  		return policyErr(fmt.Errorf("malformed chaincode invocation spec"))
   366  	}
   367  
   368  	lsccFunc := string(cis.ChaincodeSpec.Input.Args[0])
   369  	lsccArgs := cis.ChaincodeSpec.Input.Args[1:]
   370  
   371  	logger.Debugf("VSCC info: ValidateLSCCInvocation acting on %s %#v", lsccFunc, lsccArgs)
   372  
   373  	switch lsccFunc {
   374  	case lscc.UPGRADE, lscc.DEPLOY:
   375  		logger.Debugf("VSCC info: validating invocation of lscc function %s on arguments %#v", lsccFunc, lsccArgs)
   376  
   377  		if len(lsccArgs) < 2 {
   378  			return policyErr(fmt.Errorf("Wrong number of arguments for invocation lscc(%s): expected at least 2, received %d", lsccFunc, len(lsccArgs)))
   379  		}
   380  
   381  		if (!ac.PrivateChannelData() && len(lsccArgs) > 5) ||
   382  			(ac.PrivateChannelData() && len(lsccArgs) > 6) {
   383  			return policyErr(fmt.Errorf("Wrong number of arguments for invocation lscc(%s): received %d", lsccFunc, len(lsccArgs)))
   384  		}
   385  
   386  		cdsArgs, err := protoutil.UnmarshalChaincodeDeploymentSpec(lsccArgs[1])
   387  		if err != nil {
   388  			return policyErr(fmt.Errorf("GetChaincodeDeploymentSpec error %s", err))
   389  		}
   390  
   391  		if cdsArgs == nil || cdsArgs.ChaincodeSpec == nil || cdsArgs.ChaincodeSpec.ChaincodeId == nil ||
   392  			cap.Action == nil || cap.Action.ProposalResponsePayload == nil {
   393  			return policyErr(fmt.Errorf("VSCC error: invocation of lscc(%s) does not have appropriate arguments", lsccFunc))
   394  		}
   395  
   396  		switch cdsArgs.ChaincodeSpec.Type.String() {
   397  		case "GOLANG", "NODE", "JAVA", "CAR":
   398  		default:
   399  			return policyErr(fmt.Errorf("unexpected chaincode spec type: %s", cdsArgs.ChaincodeSpec.Type.String()))
   400  		}
   401  
   402  		// validate chaincode name
   403  		ccName := cdsArgs.ChaincodeSpec.ChaincodeId.Name
   404  		// it must comply with the lscc.ChaincodeNameRegExp
   405  		if !lscc.ChaincodeNameRegExp.MatchString(ccName) {
   406  			return policyErr(errors.Errorf("invalid chaincode name '%s'", ccName))
   407  		}
   408  
   409  		// it can't match the name of one of the system chaincodes
   410  		if _, in := systemChaincodeNames[ccName]; in {
   411  			return policyErr(errors.Errorf("chaincode name '%s' is reserved for system chaincodes", ccName))
   412  		}
   413  
   414  		// validate chaincode version
   415  		ccVersion := cdsArgs.ChaincodeSpec.ChaincodeId.Version
   416  		// it must comply with the lscc.ChaincodeVersionRegExp
   417  		if !lscc.ChaincodeVersionRegExp.MatchString(ccVersion) {
   418  			return policyErr(errors.Errorf("invalid chaincode version '%s'", ccVersion))
   419  		}
   420  
   421  		// get the rwset
   422  		pRespPayload, err := protoutil.UnmarshalProposalResponsePayload(cap.Action.ProposalResponsePayload)
   423  		if err != nil {
   424  			return policyErr(fmt.Errorf("GetProposalResponsePayload error %s", err))
   425  		}
   426  		if pRespPayload.Extension == nil {
   427  			return policyErr(fmt.Errorf("nil pRespPayload.Extension"))
   428  		}
   429  		respPayload, err := protoutil.UnmarshalChaincodeAction(pRespPayload.Extension)
   430  		if err != nil {
   431  			return policyErr(fmt.Errorf("GetChaincodeAction error %s", err))
   432  		}
   433  		txRWSet := &rwsetutil.TxRwSet{}
   434  		if err = txRWSet.FromProtoBytes(respPayload.Results); err != nil {
   435  			return policyErr(fmt.Errorf("txRWSet.FromProtoBytes error %s", err))
   436  		}
   437  
   438  		// extract the rwset for lscc
   439  		var lsccrwset *kvrwset.KVRWSet
   440  		for _, ns := range txRWSet.NsRwSets {
   441  			logger.Debugf("Namespace %s", ns.NameSpace)
   442  			if ns.NameSpace == "lscc" {
   443  				lsccrwset = ns.KvRwSet
   444  				break
   445  			}
   446  		}
   447  
   448  		// retrieve from the ledger the entry for the chaincode at hand
   449  		cdLedger, ccExistsOnLedger, err := vscc.getInstantiatedCC(chid, cdsArgs.ChaincodeSpec.ChaincodeId.Name)
   450  		if err != nil {
   451  			return &commonerrors.VSCCExecutionFailureError{Err: err}
   452  		}
   453  
   454  		/******************************************/
   455  		/* security check 0 - validation of rwset */
   456  		/******************************************/
   457  		// there has to be a write-set
   458  		if lsccrwset == nil {
   459  			return policyErr(fmt.Errorf("No read write set for lscc was found"))
   460  		}
   461  		// there must be at least one write
   462  		if len(lsccrwset.Writes) < 1 {
   463  			return policyErr(fmt.Errorf("LSCC must issue at least one single putState upon deploy/upgrade"))
   464  		}
   465  		// the first key name must be the chaincode id provided in the deployment spec
   466  		if lsccrwset.Writes[0].Key != cdsArgs.ChaincodeSpec.ChaincodeId.Name {
   467  			return policyErr(fmt.Errorf("expected key %s, found %s", cdsArgs.ChaincodeSpec.ChaincodeId.Name, lsccrwset.Writes[0].Key))
   468  		}
   469  		// the value must be a ChaincodeData struct
   470  		cdRWSet := &ccprovider.ChaincodeData{}
   471  		err = proto.Unmarshal(lsccrwset.Writes[0].Value, cdRWSet)
   472  		if err != nil {
   473  			return policyErr(fmt.Errorf("unmarhsalling of ChaincodeData failed, error %s", err))
   474  		}
   475  		// the chaincode name in the lsccwriteset must match the chaincode name in the deployment spec
   476  		if cdRWSet.Name != cdsArgs.ChaincodeSpec.ChaincodeId.Name {
   477  			return policyErr(fmt.Errorf("expected cc name %s, found %s", cdsArgs.ChaincodeSpec.ChaincodeId.Name, cdRWSet.Name))
   478  		}
   479  		// the chaincode version in the lsccwriteset must match the chaincode version in the deployment spec
   480  		if cdRWSet.Version != cdsArgs.ChaincodeSpec.ChaincodeId.Version {
   481  			return policyErr(fmt.Errorf("expected cc version %s, found %s", cdsArgs.ChaincodeSpec.ChaincodeId.Version, cdRWSet.Version))
   482  		}
   483  		// it must only write to 2 namespaces: LSCC's and the cc that we are deploying/upgrading
   484  		for _, ns := range txRWSet.NsRwSets {
   485  			if ns.NameSpace != "lscc" && ns.NameSpace != cdRWSet.Name && len(ns.KvRwSet.Writes) > 0 {
   486  				return policyErr(fmt.Errorf("LSCC invocation is attempting to write to namespace %s", ns.NameSpace))
   487  			}
   488  		}
   489  
   490  		logger.Debugf("Validating %s for cc %s version %s", lsccFunc, cdRWSet.Name, cdRWSet.Version)
   491  
   492  		switch lsccFunc {
   493  		case lscc.DEPLOY:
   494  
   495  			/******************************************************************/
   496  			/* security check 1 - cc not in the LCCC table of instantiated cc */
   497  			/******************************************************************/
   498  			if ccExistsOnLedger {
   499  				return policyErr(fmt.Errorf("Chaincode %s is already instantiated", cdsArgs.ChaincodeSpec.ChaincodeId.Name))
   500  			}
   501  
   502  			/****************************************************************************/
   503  			/* security check 2 - validation of rwset (and of collections if enabled) */
   504  			/****************************************************************************/
   505  			if ac.PrivateChannelData() {
   506  				// do extra validation for collections
   507  				err := vscc.validateRWSetAndCollection(lsccrwset, cdRWSet, lsccArgs, lsccFunc, ac, chid)
   508  				if err != nil {
   509  					return err
   510  				}
   511  			} else {
   512  				// there can only be a single ledger write
   513  				if len(lsccrwset.Writes) != 1 {
   514  					return policyErr(fmt.Errorf("LSCC can only issue a single putState upon deploy"))
   515  				}
   516  			}
   517  
   518  			/*****************************************************/
   519  			/* security check 3 - check the instantiation policy */
   520  			/*****************************************************/
   521  			pol := cdRWSet.InstantiationPolicy
   522  			if pol == nil {
   523  				return policyErr(fmt.Errorf("no instantiation policy was specified"))
   524  			}
   525  			// FIXME: could we actually pull the cds package from the
   526  			// file system to verify whether the policy that is specified
   527  			// here is the same as the one on disk?
   528  			// PROS: we prevent attacks where the policy is replaced
   529  			// CONS: this would be a point of non-determinism
   530  			err := vscc.checkInstantiationPolicy(chid, env, pol, payl)
   531  			if err != nil {
   532  				return err
   533  			}
   534  
   535  		case lscc.UPGRADE:
   536  			/**************************************************************/
   537  			/* security check 1 - cc in the LCCC table of instantiated cc */
   538  			/**************************************************************/
   539  			if !ccExistsOnLedger {
   540  				return policyErr(fmt.Errorf("Upgrading non-existent chaincode %s", cdsArgs.ChaincodeSpec.ChaincodeId.Name))
   541  			}
   542  
   543  			/**********************************************************/
   544  			/* security check 2 - existing cc's version was different */
   545  			/**********************************************************/
   546  			if cdLedger.Version == cdsArgs.ChaincodeSpec.ChaincodeId.Version {
   547  				return policyErr(fmt.Errorf("Existing version of the cc on the ledger (%s) should be different from the upgraded one", cdsArgs.ChaincodeSpec.ChaincodeId.Version))
   548  			}
   549  
   550  			/****************************************************************************/
   551  			/* security check 3 validation of rwset (and of collections if enabled) */
   552  			/****************************************************************************/
   553  			// Only in v1.2, a collection can be updated during a chaincode upgrade
   554  			if ac.V1_2Validation() {
   555  				// do extra validation for collections
   556  				err := vscc.validateRWSetAndCollection(lsccrwset, cdRWSet, lsccArgs, lsccFunc, ac, chid)
   557  				if err != nil {
   558  					return err
   559  				}
   560  			} else {
   561  				// there can only be a single ledger write
   562  				if len(lsccrwset.Writes) != 1 {
   563  					return policyErr(fmt.Errorf("LSCC can only issue a single putState upon upgrade"))
   564  				}
   565  			}
   566  
   567  			/*****************************************************/
   568  			/* security check 4 - check the instantiation policy */
   569  			/*****************************************************/
   570  			pol := cdLedger.InstantiationPolicy
   571  			if pol == nil {
   572  				return policyErr(fmt.Errorf("No instantiation policy was specified"))
   573  			}
   574  			// FIXME: could we actually pull the cds package from the
   575  			// file system to verify whether the policy that is specified
   576  			// here is the same as the one on disk?
   577  			// PROS: we prevent attacks where the policy is replaced
   578  			// CONS: this would be a point of non-determinism
   579  			err := vscc.checkInstantiationPolicy(chid, env, pol, payl)
   580  			if err != nil {
   581  				return err
   582  			}
   583  
   584  			/******************************************************************/
   585  			/* security check 5 - check the instantiation policy in the rwset */
   586  			/******************************************************************/
   587  			if ac.V1_1Validation() {
   588  				polNew := cdRWSet.InstantiationPolicy
   589  				if polNew == nil {
   590  					return policyErr(fmt.Errorf("No instantiation policy was specified"))
   591  				}
   592  
   593  				// no point in checking it again if they are the same policy
   594  				if !bytes.Equal(polNew, pol) {
   595  					err = vscc.checkInstantiationPolicy(chid, env, polNew, payl)
   596  					if err != nil {
   597  						return err
   598  					}
   599  				}
   600  			}
   601  		}
   602  
   603  		// all is good!
   604  		return nil
   605  	default:
   606  		return policyErr(fmt.Errorf("VSCC error: committing an invocation of function %s of lscc is invalid", lsccFunc))
   607  	}
   608  }
   609  
   610  func (vscc *Validator) getInstantiatedCC(chid, ccid string) (cd *ccprovider.ChaincodeData, exists bool, err error) {
   611  	qe, err := vscc.stateFetcher.FetchState()
   612  	if err != nil {
   613  		err = fmt.Errorf("could not retrieve QueryExecutor for channel %s, error %s", chid, err)
   614  		return
   615  	}
   616  	defer qe.Done()
   617  	channelState := &state{qe}
   618  	bytes, err := channelState.GetState("lscc", ccid)
   619  	if err != nil {
   620  		err = fmt.Errorf("could not retrieve state for chaincode %s on channel %s, error %s", ccid, chid, err)
   621  		return
   622  	}
   623  
   624  	if bytes == nil {
   625  		return
   626  	}
   627  
   628  	cd = &ccprovider.ChaincodeData{}
   629  	err = proto.Unmarshal(bytes, cd)
   630  	if err != nil {
   631  		err = fmt.Errorf("unmarshalling ChaincodeQueryResponse failed, error %s", err)
   632  		return
   633  	}
   634  
   635  	exists = true
   636  	return
   637  }
   638  
   639  type state struct {
   640  	vs.State
   641  }
   642  
   643  // GetState retrieves the value for the given key in the given namespace
   644  func (s *state) GetState(namespace string, key string) ([]byte, error) {
   645  	values, err := s.GetStateMultipleKeys(namespace, []string{key})
   646  	if err != nil {
   647  		return nil, err
   648  	}
   649  	if len(values) == 0 {
   650  		return nil, nil
   651  	}
   652  	return values[0], nil
   653  }