github.com/hechain20/hechain@v0.0.0-20220316014945-b544036ba106/core/handlers/validation/builtin/v13/lscc_validation_logic.go (about)

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