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

     1  /*
     2  Copyright hechain. All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  package v12
     8  
     9  import (
    10  	"bytes"
    11  	"fmt"
    12  	"regexp"
    13  
    14  	"github.com/golang/protobuf/proto"
    15  	commonerrors "github.com/hechain20/hechain/common/errors"
    16  	"github.com/hechain20/hechain/common/flogging"
    17  	"github.com/hechain20/hechain/core/common/ccprovider"
    18  	"github.com/hechain20/hechain/core/common/privdata"
    19  	vc "github.com/hechain20/hechain/core/handlers/validation/api/capabilities"
    20  	vi "github.com/hechain20/hechain/core/handlers/validation/api/identities"
    21  	vp "github.com/hechain20/hechain/core/handlers/validation/api/policies"
    22  	vs "github.com/hechain20/hechain/core/handlers/validation/api/state"
    23  	"github.com/hechain20/hechain/core/ledger/kvledger/txmgmt/rwsetutil"
    24  	"github.com/hechain20/hechain/core/scc/lscc"
    25  	"github.com/hechain20/hechain/protoutil"
    26  	"github.com/hyperledger/fabric-protos-go/common"
    27  	"github.com/hyperledger/fabric-protos-go/ledger/rwset/kvrwset"
    28  	"github.com/hyperledger/fabric-protos-go/msp"
    29  	pb "github.com/hyperledger/fabric-protos-go/peer"
    30  	"github.com/pkg/errors"
    31  )
    32  
    33  var (
    34  	logger = flogging.MustGetLogger("vscc")
    35  
    36  	// currently defined system chaincode names that shouldn't
    37  	// be allowed as user-defined chaincode names
    38  	systemChaincodeNames = map[string]struct{}{
    39  		"cscc": {},
    40  		"escc": {},
    41  		"lscc": {},
    42  		"qscc": {},
    43  		"vscc": {},
    44  	}
    45  )
    46  
    47  const (
    48  	DUPLICATED_IDENTITY_ERROR = "Endorsement policy evaluation failure might be caused by duplicated identities"
    49  )
    50  
    51  const AllowedCharsCollectionName = "[A-Za-z0-9_-]+"
    52  
    53  var validCollectionNameRegex = regexp.MustCompile(AllowedCharsCollectionName)
    54  
    55  //go:generate mockery -dir . -name Capabilities -case underscore -output mocks/
    56  
    57  // Capabilities is the local interface that used to generate mocks for foreign interface.
    58  type Capabilities interface {
    59  	vc.Capabilities
    60  }
    61  
    62  //go:generate mockery -dir . -name StateFetcher -case underscore -output mocks/
    63  
    64  // StateFetcher is the local interface that used to generate mocks for foreign interface.
    65  type StateFetcher interface {
    66  	vs.StateFetcher
    67  }
    68  
    69  //go:generate mockery -dir . -name IdentityDeserializer -case underscore -output mocks/
    70  
    71  // IdentityDeserializer is the local interface that used to generate mocks for foreign interface.
    72  type IdentityDeserializer interface {
    73  	vi.IdentityDeserializer
    74  }
    75  
    76  //go:generate mockery -dir . -name PolicyEvaluator -case underscore -output mocks/
    77  
    78  // PolicyEvaluator is the local interface that used to generate mocks for foreign interface.
    79  type PolicyEvaluator interface {
    80  	vp.PolicyEvaluator
    81  }
    82  
    83  // New creates a new instance of the default VSCC
    84  // Typically this will only be invoked once per peer.
    85  func New(c vc.Capabilities, s vs.StateFetcher, d vi.IdentityDeserializer, pe vp.PolicyEvaluator) *Validator {
    86  	return &Validator{
    87  		capabilities:    c,
    88  		stateFetcher:    s,
    89  		deserializer:    d,
    90  		policyEvaluator: pe,
    91  	}
    92  }
    93  
    94  // Validator implements the default transaction validation policy,
    95  // which is to check the correctness of the read-write set and the endorsement
    96  // signatures against an endorsement policy that is supplied as argument to
    97  // every invoke.
    98  type Validator struct {
    99  	deserializer    vi.IdentityDeserializer
   100  	capabilities    vc.Capabilities
   101  	stateFetcher    vs.StateFetcher
   102  	policyEvaluator vp.PolicyEvaluator
   103  }
   104  
   105  // Validate validates the given envelope corresponding to a transaction with an endorsement
   106  // policy as given in its serialized form.
   107  func (vscc *Validator) Validate(
   108  	block *common.Block,
   109  	namespace string,
   110  	txPosition int,
   111  	actionPosition int,
   112  	policyBytes []byte,
   113  ) commonerrors.TxValidationError {
   114  	// get the envelope...
   115  	env, err := protoutil.GetEnvelopeFromBlock(block.Data.Data[txPosition])
   116  	if err != nil {
   117  		logger.Errorf("VSCC error: GetEnvelope failed, err %s", err)
   118  		return policyErr(err)
   119  	}
   120  
   121  	// ...and the payload...
   122  	payl, err := protoutil.UnmarshalPayload(env.Payload)
   123  	if err != nil {
   124  		logger.Errorf("VSCC error: GetPayload failed, err %s", err)
   125  		return policyErr(err)
   126  	}
   127  
   128  	chdr, err := protoutil.UnmarshalChannelHeader(payl.Header.ChannelHeader)
   129  	if err != nil {
   130  		return policyErr(err)
   131  	}
   132  
   133  	// validate the payload type
   134  	if common.HeaderType(chdr.Type) != common.HeaderType_ENDORSER_TRANSACTION {
   135  		logger.Errorf("Only Endorser Transactions are supported, provided type %d", chdr.Type)
   136  		return policyErr(fmt.Errorf("Only Endorser Transactions are supported, provided type %d", chdr.Type))
   137  	}
   138  
   139  	// ...and the transaction...
   140  	tx, err := protoutil.UnmarshalTransaction(payl.Data)
   141  	if err != nil {
   142  		logger.Errorf("VSCC error: GetTransaction failed, err %s", err)
   143  		return policyErr(err)
   144  	}
   145  
   146  	cap, err := protoutil.UnmarshalChaincodeActionPayload(tx.Actions[actionPosition].Payload)
   147  	if err != nil {
   148  		logger.Errorf("VSCC error: GetChaincodeActionPayload failed, err %s", err)
   149  		return policyErr(err)
   150  	}
   151  
   152  	signatureSet, err := vscc.deduplicateIdentity(cap)
   153  	if err != nil {
   154  		return policyErr(err)
   155  	}
   156  
   157  	// evaluate the signature set against the policy
   158  	err = vscc.policyEvaluator.Evaluate(policyBytes, signatureSet)
   159  	if err != nil {
   160  		logger.Warningf("Endorsement policy failure for transaction txid=%s, err: %s", chdr.GetTxId(), err.Error())
   161  		if len(signatureSet) < len(cap.Action.Endorsements) {
   162  			// Warning: duplicated identities exist, endorsement failure might be cause by this reason
   163  			return policyErr(errors.New(DUPLICATED_IDENTITY_ERROR))
   164  		}
   165  		return policyErr(fmt.Errorf("VSCC error: endorsement policy failure, err: %s", err))
   166  	}
   167  
   168  	// do some extra validation that is specific to lscc
   169  	if namespace == "lscc" {
   170  		logger.Debugf("VSCC info: doing special validation for LSCC")
   171  		err := vscc.ValidateLSCCInvocation(chdr.ChannelId, env, cap, payl, vscc.capabilities)
   172  		if err != nil {
   173  			logger.Errorf("VSCC error: ValidateLSCCInvocation failed, err %s", err)
   174  			return err
   175  		}
   176  	}
   177  
   178  	return nil
   179  }
   180  
   181  // checkInstantiationPolicy evaluates an instantiation policy against a signed proposal.
   182  func (vscc *Validator) checkInstantiationPolicy(chainName string, env *common.Envelope, instantiationPolicy []byte, payl *common.Payload) commonerrors.TxValidationError {
   183  	// get the signature header
   184  	shdr, err := protoutil.UnmarshalSignatureHeader(payl.Header.SignatureHeader)
   185  	if err != nil {
   186  		return policyErr(err)
   187  	}
   188  
   189  	// construct signed data we can evaluate the instantiation policy against
   190  	sd := []*protoutil.SignedData{{
   191  		Data:      env.Payload,
   192  		Identity:  shdr.Creator,
   193  		Signature: env.Signature,
   194  	}}
   195  	err = vscc.policyEvaluator.Evaluate(instantiationPolicy, sd)
   196  	if err != nil {
   197  		return policyErr(fmt.Errorf("chaincode instantiation policy violated, error %s", err))
   198  	}
   199  	return nil
   200  }
   201  
   202  func validateNewCollectionConfigs(newCollectionConfigs []*pb.CollectionConfig) error {
   203  	newCollectionsMap := make(map[string]bool, len(newCollectionConfigs))
   204  	// Process each collection config from a set of collection configs
   205  	for _, newCollectionConfig := range newCollectionConfigs {
   206  
   207  		newCollection := newCollectionConfig.GetStaticCollectionConfig()
   208  		if newCollection == nil {
   209  			return errors.New("unknown collection configuration type")
   210  		}
   211  
   212  		// Ensure that there are no duplicate collection names
   213  		collectionName := newCollection.GetName()
   214  
   215  		if err := validateCollectionName(collectionName); err != nil {
   216  			return err
   217  		}
   218  
   219  		if _, ok := newCollectionsMap[collectionName]; !ok {
   220  			newCollectionsMap[collectionName] = true
   221  		} else {
   222  			return fmt.Errorf("collection-name: %s -- found duplicate collection configuration", collectionName)
   223  		}
   224  
   225  		// Validate gossip related parameters present in the collection config
   226  		maximumPeerCount := newCollection.GetMaximumPeerCount()
   227  		requiredPeerCount := newCollection.GetRequiredPeerCount()
   228  		if maximumPeerCount < requiredPeerCount {
   229  			return fmt.Errorf("collection-name: %s -- maximum peer count (%d) cannot be less than the required peer count (%d)",
   230  				collectionName, maximumPeerCount, requiredPeerCount)
   231  		}
   232  		if requiredPeerCount < 0 {
   233  			return fmt.Errorf("collection-name: %s -- requiredPeerCount (%d) cannot be less than zero",
   234  				collectionName, requiredPeerCount)
   235  		}
   236  
   237  		// make sure that the signature policy is meaningful (only consists of ORs)
   238  		err := validateSpOrConcat(newCollection.MemberOrgsPolicy.GetSignaturePolicy().Rule)
   239  		if err != nil {
   240  			return errors.WithMessagef(err, "collection-name: %s -- error in member org policy", collectionName)
   241  		}
   242  	}
   243  	return nil
   244  }
   245  
   246  // validateSpOrConcat checks if the supplied signature policy is just an OR-concatenation of identities.
   247  func validateSpOrConcat(sp *common.SignaturePolicy) error {
   248  	if sp.GetNOutOf() == nil {
   249  		return nil
   250  	}
   251  	// check if N == 1 (OR concatenation)
   252  	if sp.GetNOutOf().N != 1 {
   253  		return errors.New(fmt.Sprintf("signature policy is not an OR concatenation, NOutOf %d", sp.GetNOutOf().N))
   254  	}
   255  	// recurse into all sub-rules
   256  	for _, rule := range sp.GetNOutOf().Rules {
   257  		err := validateSpOrConcat(rule)
   258  		if err != nil {
   259  			return err
   260  		}
   261  	}
   262  	return nil
   263  }
   264  
   265  func checkForMissingCollections(newCollectionsMap map[string]*pb.StaticCollectionConfig, oldCollectionConfigs []*pb.CollectionConfig,
   266  ) error {
   267  	var missingCollections []string
   268  
   269  	// In the new collection config package, ensure that there is one entry per old collection. Any
   270  	// number of new collections are allowed.
   271  	for _, oldCollectionConfig := range oldCollectionConfigs {
   272  
   273  		oldCollection := oldCollectionConfig.GetStaticCollectionConfig()
   274  		// It cannot be nil
   275  		if oldCollection == nil {
   276  			return policyErr(fmt.Errorf("unknown collection configuration type"))
   277  		}
   278  
   279  		// All old collection must exist in the new collection config package
   280  		oldCollectionName := oldCollection.GetName()
   281  		_, ok := newCollectionsMap[oldCollectionName]
   282  		if !ok {
   283  			missingCollections = append(missingCollections, oldCollectionName)
   284  		}
   285  	}
   286  
   287  	if len(missingCollections) > 0 {
   288  		return policyErr(fmt.Errorf("the following existing collections are missing in the new collection configuration package: %v",
   289  			missingCollections))
   290  	}
   291  
   292  	return nil
   293  }
   294  
   295  func checkForModifiedCollectionsBTL(newCollectionsMap map[string]*pb.StaticCollectionConfig, oldCollectionConfigs []*pb.CollectionConfig,
   296  ) error {
   297  	var modifiedCollectionsBTL []string
   298  
   299  	// In the new collection config package, ensure that the block to live value is not
   300  	// modified for the existing collections.
   301  	for _, oldCollectionConfig := range oldCollectionConfigs {
   302  
   303  		oldCollection := oldCollectionConfig.GetStaticCollectionConfig()
   304  		// It cannot be nil
   305  		if oldCollection == nil {
   306  			return policyErr(fmt.Errorf("unknown collection configuration type"))
   307  		}
   308  
   309  		oldCollectionName := oldCollection.GetName()
   310  		newCollection := newCollectionsMap[oldCollectionName]
   311  		// BlockToLive cannot be changed
   312  		if newCollection.GetBlockToLive() != oldCollection.GetBlockToLive() {
   313  			modifiedCollectionsBTL = append(modifiedCollectionsBTL, oldCollectionName)
   314  		}
   315  	}
   316  
   317  	if len(modifiedCollectionsBTL) > 0 {
   318  		return policyErr(fmt.Errorf("the BlockToLive in the following existing collections must not be modified: %v",
   319  			modifiedCollectionsBTL))
   320  	}
   321  
   322  	return nil
   323  }
   324  
   325  func validateNewCollectionConfigsAgainstOld(newCollectionConfigs []*pb.CollectionConfig, oldCollectionConfigs []*pb.CollectionConfig,
   326  ) error {
   327  	newCollectionsMap := make(map[string]*pb.StaticCollectionConfig, len(newCollectionConfigs))
   328  
   329  	for _, newCollectionConfig := range newCollectionConfigs {
   330  		newCollection := newCollectionConfig.GetStaticCollectionConfig()
   331  		// Collection object itself is stored as value so that we can
   332  		// check whether the block to live is changed -- FAB-7810
   333  		newCollectionsMap[newCollection.GetName()] = newCollection
   334  	}
   335  
   336  	if err := checkForMissingCollections(newCollectionsMap, oldCollectionConfigs); err != nil {
   337  		return err
   338  	}
   339  
   340  	if err := checkForModifiedCollectionsBTL(newCollectionsMap, oldCollectionConfigs); err != nil {
   341  		return err
   342  	}
   343  
   344  	return nil
   345  }
   346  
   347  func validateCollectionName(collectionName string) error {
   348  	if collectionName == "" {
   349  		return fmt.Errorf("empty collection-name is not allowed")
   350  	}
   351  	match := validCollectionNameRegex.FindString(collectionName)
   352  	if len(match) != len(collectionName) {
   353  		return fmt.Errorf("collection-name: %s not allowed. A valid collection name follows the pattern: %s",
   354  			collectionName, AllowedCharsCollectionName)
   355  	}
   356  	return nil
   357  }
   358  
   359  // validateRWSetAndCollection performs validation of the rwset
   360  // of an LSCC deploy operation and then it validates any collection
   361  // configuration.
   362  func (vscc *Validator) validateRWSetAndCollection(
   363  	lsccrwset *kvrwset.KVRWSet,
   364  	cdRWSet *ccprovider.ChaincodeData,
   365  	lsccArgs [][]byte,
   366  	lsccFunc string,
   367  	ac vc.Capabilities,
   368  	channelName string,
   369  ) commonerrors.TxValidationError {
   370  	/********************************************/
   371  	/* security check 0.a - validation of rwset */
   372  	/********************************************/
   373  	// there can only be one or two writes
   374  	if len(lsccrwset.Writes) > 2 {
   375  		return policyErr(fmt.Errorf("LSCC can only issue one or two putState upon deploy"))
   376  	}
   377  
   378  	/**********************************************************/
   379  	/* security check 0.b - validation of the collection data */
   380  	/**********************************************************/
   381  	var collectionsConfigArg []byte
   382  	if len(lsccArgs) > 5 {
   383  		collectionsConfigArg = lsccArgs[5]
   384  	}
   385  
   386  	var collectionsConfigLedger []byte
   387  	if len(lsccrwset.Writes) == 2 {
   388  		key := privdata.BuildCollectionKVSKey(cdRWSet.Name)
   389  		if lsccrwset.Writes[1].Key != key {
   390  			return policyErr(fmt.Errorf("invalid key for the collection of chaincode %s:%s; expected '%s', received '%s'",
   391  				cdRWSet.Name, cdRWSet.Version, key, lsccrwset.Writes[1].Key))
   392  		}
   393  
   394  		collectionsConfigLedger = lsccrwset.Writes[1].Value
   395  	}
   396  
   397  	if !bytes.Equal(collectionsConfigArg, collectionsConfigLedger) {
   398  		return policyErr(fmt.Errorf("collection configuration arguments supplied for chaincode %s:%s do not match the configuration in the lscc writeset",
   399  			cdRWSet.Name, cdRWSet.Version))
   400  	}
   401  
   402  	channelState, err := vscc.stateFetcher.FetchState()
   403  	if err != nil {
   404  		return &commonerrors.VSCCExecutionFailureError{Err: fmt.Errorf("failed obtaining query executor: %v", err)}
   405  	}
   406  	defer channelState.Done()
   407  
   408  	state := &state{channelState}
   409  
   410  	// The following condition check added in v1.1 may not be needed as it is not possible to have the chaincodeName~collection key in
   411  	// the lscc namespace before a chaincode deploy. To avoid forks in v1.2, the following condition is retained.
   412  	if lsccFunc == lscc.DEPLOY {
   413  		colCriteria := privdata.CollectionCriteria{Channel: channelName, Namespace: cdRWSet.Name}
   414  		ccp, err := privdata.RetrieveCollectionConfigPackageFromState(colCriteria, state)
   415  		if err != nil {
   416  			// fail if we get any error other than NoSuchCollectionError
   417  			// because it means something went wrong while looking up the
   418  			// older collection
   419  			if _, ok := err.(privdata.NoSuchCollectionError); !ok {
   420  				return &commonerrors.VSCCExecutionFailureError{
   421  					Err: fmt.Errorf("unable to check whether collection existed earlier for chaincode %s:%s",
   422  						cdRWSet.Name, cdRWSet.Version),
   423  				}
   424  			}
   425  		}
   426  		if ccp != nil {
   427  			return policyErr(fmt.Errorf("collection data should not exist for chaincode %s:%s", cdRWSet.Name, cdRWSet.Version))
   428  		}
   429  	}
   430  
   431  	// TODO: Once the new chaincode lifecycle is available (FAB-8724), the following validation
   432  	// and other validation performed in ValidateLSCCInvocation can be moved to LSCC itself.
   433  	newCollectionConfigPackage := &pb.CollectionConfigPackage{}
   434  
   435  	if collectionsConfigArg != nil {
   436  		err := proto.Unmarshal(collectionsConfigArg, newCollectionConfigPackage)
   437  		if err != nil {
   438  			return policyErr(fmt.Errorf("invalid collection configuration supplied for chaincode %s:%s",
   439  				cdRWSet.Name, cdRWSet.Version))
   440  		}
   441  	} else {
   442  		return nil
   443  	}
   444  
   445  	if ac.V1_2Validation() {
   446  		newCollectionConfigs := newCollectionConfigPackage.GetConfig()
   447  		if err := validateNewCollectionConfigs(newCollectionConfigs); err != nil {
   448  			return policyErr(err)
   449  		}
   450  
   451  		if lsccFunc == lscc.UPGRADE {
   452  
   453  			collectionCriteria := privdata.CollectionCriteria{Channel: channelName, Namespace: cdRWSet.Name}
   454  			// oldCollectionConfigPackage denotes the existing collection config package in the ledger
   455  			oldCollectionConfigPackage, err := privdata.RetrieveCollectionConfigPackageFromState(collectionCriteria, state)
   456  			if err != nil {
   457  				// fail if we get any error other than NoSuchCollectionError
   458  				// because it means something went wrong while looking up the
   459  				// older collection
   460  				if _, ok := err.(privdata.NoSuchCollectionError); !ok {
   461  					return &commonerrors.VSCCExecutionFailureError{
   462  						Err: fmt.Errorf("unable to check whether collection existed earlier for chaincode %s:%s: %v",
   463  							cdRWSet.Name, cdRWSet.Version, err),
   464  					}
   465  				}
   466  			}
   467  
   468  			// oldCollectionConfigPackage denotes the existing collection config package in the ledger
   469  			if oldCollectionConfigPackage != nil {
   470  				oldCollectionConfigs := oldCollectionConfigPackage.GetConfig()
   471  				if err := validateNewCollectionConfigsAgainstOld(newCollectionConfigs, oldCollectionConfigs); err != nil {
   472  					return policyErr(err)
   473  				}
   474  
   475  			}
   476  		}
   477  	}
   478  
   479  	return nil
   480  }
   481  
   482  func (vscc *Validator) ValidateLSCCInvocation(
   483  	chid string,
   484  	env *common.Envelope,
   485  	cap *pb.ChaincodeActionPayload,
   486  	payl *common.Payload,
   487  	ac vc.Capabilities,
   488  ) commonerrors.TxValidationError {
   489  	cpp, err := protoutil.UnmarshalChaincodeProposalPayload(cap.ChaincodeProposalPayload)
   490  	if err != nil {
   491  		logger.Errorf("VSCC error: GetChaincodeProposalPayload failed, err %s", err)
   492  		return policyErr(err)
   493  	}
   494  
   495  	cis := &pb.ChaincodeInvocationSpec{}
   496  	err = proto.Unmarshal(cpp.Input, cis)
   497  	if err != nil {
   498  		logger.Errorf("VSCC error: Unmarshal ChaincodeInvocationSpec failed, err %s", err)
   499  		return policyErr(err)
   500  	}
   501  
   502  	if cis.ChaincodeSpec == nil ||
   503  		cis.ChaincodeSpec.Input == nil ||
   504  		cis.ChaincodeSpec.Input.Args == nil {
   505  		logger.Errorf("VSCC error: committing invalid vscc invocation")
   506  		return policyErr(fmt.Errorf("malformed chaincode invocation spec"))
   507  	}
   508  
   509  	lsccFunc := string(cis.ChaincodeSpec.Input.Args[0])
   510  	lsccArgs := cis.ChaincodeSpec.Input.Args[1:]
   511  
   512  	logger.Debugf("VSCC info: ValidateLSCCInvocation acting on %s %#v", lsccFunc, lsccArgs)
   513  
   514  	switch lsccFunc {
   515  	case lscc.UPGRADE, lscc.DEPLOY:
   516  		logger.Debugf("VSCC info: validating invocation of lscc function %s on arguments %#v", lsccFunc, lsccArgs)
   517  
   518  		if len(lsccArgs) < 2 {
   519  			return policyErr(fmt.Errorf("Wrong number of arguments for invocation lscc(%s): expected at least 2, received %d", lsccFunc, len(lsccArgs)))
   520  		}
   521  
   522  		if (!ac.PrivateChannelData() && len(lsccArgs) > 5) ||
   523  			(ac.PrivateChannelData() && len(lsccArgs) > 6) {
   524  			return policyErr(fmt.Errorf("Wrong number of arguments for invocation lscc(%s): received %d", lsccFunc, len(lsccArgs)))
   525  		}
   526  
   527  		cdsArgs, err := protoutil.UnmarshalChaincodeDeploymentSpec(lsccArgs[1])
   528  		if err != nil {
   529  			return policyErr(fmt.Errorf("GetChaincodeDeploymentSpec error %s", err))
   530  		}
   531  
   532  		if cdsArgs == nil || cdsArgs.ChaincodeSpec == nil || cdsArgs.ChaincodeSpec.ChaincodeId == nil ||
   533  			cap.Action == nil || cap.Action.ProposalResponsePayload == nil {
   534  			return policyErr(fmt.Errorf("VSCC error: invocation of lscc(%s) does not have appropriate arguments", lsccFunc))
   535  		}
   536  
   537  		switch cdsArgs.ChaincodeSpec.Type.String() {
   538  		case "GOLANG", "NODE", "JAVA", "CAR":
   539  		default:
   540  			return policyErr(fmt.Errorf("unexpected chaincode spec type: %s", cdsArgs.ChaincodeSpec.Type.String()))
   541  		}
   542  
   543  		// validate chaincode name
   544  		ccName := cdsArgs.ChaincodeSpec.ChaincodeId.Name
   545  		// it must comply with the lscc.ChaincodeNameRegExp
   546  		if !lscc.ChaincodeNameRegExp.MatchString(ccName) {
   547  			return policyErr(errors.Errorf("invalid chaincode name '%s'", ccName))
   548  		}
   549  		// it can't match the name of one of the system chaincodes
   550  		if _, in := systemChaincodeNames[ccName]; in {
   551  			return policyErr(errors.Errorf("chaincode name '%s' is reserved for system chaincodes", ccName))
   552  		}
   553  
   554  		// validate chaincode version
   555  		ccVersion := cdsArgs.ChaincodeSpec.ChaincodeId.Version
   556  		// it must comply with the lscc.ChaincodeVersionRegExp
   557  		if !lscc.ChaincodeVersionRegExp.MatchString(ccVersion) {
   558  			return policyErr(errors.Errorf("invalid chaincode version '%s'", ccVersion))
   559  		}
   560  
   561  		// get the rwset
   562  		pRespPayload, err := protoutil.UnmarshalProposalResponsePayload(cap.Action.ProposalResponsePayload)
   563  		if err != nil {
   564  			return policyErr(fmt.Errorf("GetProposalResponsePayload error %s", err))
   565  		}
   566  		if pRespPayload.Extension == nil {
   567  			return policyErr(fmt.Errorf("nil pRespPayload.Extension"))
   568  		}
   569  		respPayload, err := protoutil.UnmarshalChaincodeAction(pRespPayload.Extension)
   570  		if err != nil {
   571  			return policyErr(fmt.Errorf("GetChaincodeAction error %s", err))
   572  		}
   573  		txRWSet := &rwsetutil.TxRwSet{}
   574  		if err = txRWSet.FromProtoBytes(respPayload.Results); err != nil {
   575  			return policyErr(fmt.Errorf("txRWSet.FromProtoBytes error %s", err))
   576  		}
   577  
   578  		// extract the rwset for lscc
   579  		var lsccrwset *kvrwset.KVRWSet
   580  		for _, ns := range txRWSet.NsRwSets {
   581  			logger.Debugf("Namespace %s", ns.NameSpace)
   582  			if ns.NameSpace == "lscc" {
   583  				lsccrwset = ns.KvRwSet
   584  				break
   585  			}
   586  		}
   587  
   588  		// retrieve from the ledger the entry for the chaincode at hand
   589  		cdLedger, ccExistsOnLedger, err := vscc.getInstantiatedCC(chid, cdsArgs.ChaincodeSpec.ChaincodeId.Name)
   590  		if err != nil {
   591  			return &commonerrors.VSCCExecutionFailureError{Err: err}
   592  		}
   593  
   594  		/******************************************/
   595  		/* security check 0 - validation of rwset */
   596  		/******************************************/
   597  		// there has to be a write-set
   598  		if lsccrwset == nil {
   599  			return policyErr(fmt.Errorf("No read write set for lscc was found"))
   600  		}
   601  		// there must be at least one write
   602  		if len(lsccrwset.Writes) < 1 {
   603  			return policyErr(fmt.Errorf("LSCC must issue at least one single putState upon deploy/upgrade"))
   604  		}
   605  		// the first key name must be the chaincode id provided in the deployment spec
   606  		if lsccrwset.Writes[0].Key != cdsArgs.ChaincodeSpec.ChaincodeId.Name {
   607  			return policyErr(fmt.Errorf("expected key %s, found %s", cdsArgs.ChaincodeSpec.ChaincodeId.Name, lsccrwset.Writes[0].Key))
   608  		}
   609  		// the value must be a ChaincodeData struct
   610  		cdRWSet := &ccprovider.ChaincodeData{}
   611  		err = proto.Unmarshal(lsccrwset.Writes[0].Value, cdRWSet)
   612  		if err != nil {
   613  			return policyErr(fmt.Errorf("unmarhsalling of ChaincodeData failed, error %s", err))
   614  		}
   615  		// the chaincode name in the lsccwriteset must match the chaincode name in the deployment spec
   616  		if cdRWSet.Name != cdsArgs.ChaincodeSpec.ChaincodeId.Name {
   617  			return policyErr(fmt.Errorf("expected cc name %s, found %s", cdsArgs.ChaincodeSpec.ChaincodeId.Name, cdRWSet.Name))
   618  		}
   619  		// the chaincode version in the lsccwriteset must match the chaincode version in the deployment spec
   620  		if cdRWSet.Version != cdsArgs.ChaincodeSpec.ChaincodeId.Version {
   621  			return policyErr(fmt.Errorf("expected cc version %s, found %s", cdsArgs.ChaincodeSpec.ChaincodeId.Version, cdRWSet.Version))
   622  		}
   623  		// it must only write to 2 namespaces: LSCC's and the cc that we are deploying/upgrading
   624  		for _, ns := range txRWSet.NsRwSets {
   625  			if ns.NameSpace != "lscc" && ns.NameSpace != cdRWSet.Name && len(ns.KvRwSet.Writes) > 0 {
   626  				return policyErr(fmt.Errorf("LSCC invocation is attempting to write to namespace %s", ns.NameSpace))
   627  			}
   628  		}
   629  
   630  		logger.Debugf("Validating %s for cc %s version %s", lsccFunc, cdRWSet.Name, cdRWSet.Version)
   631  
   632  		switch lsccFunc {
   633  		case lscc.DEPLOY:
   634  
   635  			/******************************************************************/
   636  			/* security check 1 - cc not in the LCCC table of instantiated cc */
   637  			/******************************************************************/
   638  			if ccExistsOnLedger {
   639  				return policyErr(fmt.Errorf("Chaincode %s is already instantiated", cdsArgs.ChaincodeSpec.ChaincodeId.Name))
   640  			}
   641  
   642  			/****************************************************************************/
   643  			/* security check 2 - validation of rwset (and of collections if enabled) */
   644  			/****************************************************************************/
   645  			if ac.PrivateChannelData() {
   646  				// do extra validation for collections
   647  				err := vscc.validateRWSetAndCollection(lsccrwset, cdRWSet, lsccArgs, lsccFunc, ac, chid)
   648  				if err != nil {
   649  					return err
   650  				}
   651  			} else {
   652  				// there can only be a single ledger write
   653  				if len(lsccrwset.Writes) != 1 {
   654  					return policyErr(fmt.Errorf("LSCC can only issue a single putState upon deploy"))
   655  				}
   656  			}
   657  
   658  			/*****************************************************/
   659  			/* security check 3 - check the instantiation policy */
   660  			/*****************************************************/
   661  			pol := cdRWSet.InstantiationPolicy
   662  			if pol == nil {
   663  				return policyErr(fmt.Errorf("no instantiation policy was specified"))
   664  			}
   665  			// FIXME: could we actually pull the cds package from the
   666  			// file system to verify whether the policy that is specified
   667  			// here is the same as the one on disk?
   668  			// PROS: we prevent attacks where the policy is replaced
   669  			// CONS: this would be a point of non-determinism
   670  			err := vscc.checkInstantiationPolicy(chid, env, pol, payl)
   671  			if err != nil {
   672  				return err
   673  			}
   674  
   675  		case lscc.UPGRADE:
   676  			/**************************************************************/
   677  			/* security check 1 - cc in the LCCC table of instantiated cc */
   678  			/**************************************************************/
   679  			if !ccExistsOnLedger {
   680  				return policyErr(fmt.Errorf("Upgrading non-existent chaincode %s", cdsArgs.ChaincodeSpec.ChaincodeId.Name))
   681  			}
   682  
   683  			/**********************************************************/
   684  			/* security check 2 - existing cc's version was different */
   685  			/**********************************************************/
   686  			if cdLedger.Version == cdsArgs.ChaincodeSpec.ChaincodeId.Version {
   687  				return policyErr(fmt.Errorf("Existing version of the cc on the ledger (%s) should be different from the upgraded one", cdsArgs.ChaincodeSpec.ChaincodeId.Version))
   688  			}
   689  
   690  			/****************************************************************************/
   691  			/* security check 3 validation of rwset (and of collections if enabled) */
   692  			/****************************************************************************/
   693  			// Only in v1.2, a collection can be updated during a chaincode upgrade
   694  			if ac.V1_2Validation() {
   695  				// do extra validation for collections
   696  				err := vscc.validateRWSetAndCollection(lsccrwset, cdRWSet, lsccArgs, lsccFunc, ac, chid)
   697  				if err != nil {
   698  					return err
   699  				}
   700  			} else {
   701  				// there can only be a single ledger write
   702  				if len(lsccrwset.Writes) != 1 {
   703  					return policyErr(fmt.Errorf("LSCC can only issue a single putState upon upgrade"))
   704  				}
   705  			}
   706  
   707  			/*****************************************************/
   708  			/* security check 4 - check the instantiation policy */
   709  			/*****************************************************/
   710  			pol := cdLedger.InstantiationPolicy
   711  			if pol == nil {
   712  				return policyErr(fmt.Errorf("No instantiation policy was specified"))
   713  			}
   714  			// FIXME: could we actually pull the cds package from the
   715  			// file system to verify whether the policy that is specified
   716  			// here is the same as the one on disk?
   717  			// PROS: we prevent attacks where the policy is replaced
   718  			// CONS: this would be a point of non-determinism
   719  			err := vscc.checkInstantiationPolicy(chid, env, pol, payl)
   720  			if err != nil {
   721  				return err
   722  			}
   723  
   724  			/******************************************************************/
   725  			/* security check 5 - check the instantiation policy in the rwset */
   726  			/******************************************************************/
   727  			if ac.V1_1Validation() {
   728  				polNew := cdRWSet.InstantiationPolicy
   729  				if polNew == nil {
   730  					return policyErr(fmt.Errorf("No instantiation policy was specified"))
   731  				}
   732  
   733  				// no point in checking it again if they are the same policy
   734  				if !bytes.Equal(polNew, pol) {
   735  					err = vscc.checkInstantiationPolicy(chid, env, polNew, payl)
   736  					if err != nil {
   737  						return err
   738  					}
   739  				}
   740  			}
   741  		}
   742  
   743  		// all is good!
   744  		return nil
   745  	default:
   746  		return policyErr(fmt.Errorf("VSCC error: committing an invocation of function %s of lscc is invalid", lsccFunc))
   747  	}
   748  }
   749  
   750  func (vscc *Validator) getInstantiatedCC(chid, ccid string) (cd *ccprovider.ChaincodeData, exists bool, err error) {
   751  	qe, err := vscc.stateFetcher.FetchState()
   752  	if err != nil {
   753  		err = fmt.Errorf("could not retrieve QueryExecutor for channel %s, error %s", chid, err)
   754  		return
   755  	}
   756  	defer qe.Done()
   757  	channelState := &state{qe}
   758  	bytes, err := channelState.GetState("lscc", ccid)
   759  	if err != nil {
   760  		err = fmt.Errorf("could not retrieve state for chaincode %s on channel %s, error %s", ccid, chid, err)
   761  		return
   762  	}
   763  
   764  	if bytes == nil {
   765  		return
   766  	}
   767  
   768  	cd = &ccprovider.ChaincodeData{}
   769  	err = proto.Unmarshal(bytes, cd)
   770  	if err != nil {
   771  		err = fmt.Errorf("unmarshalling ChaincodeQueryResponse failed, error %s", err)
   772  		return
   773  	}
   774  
   775  	exists = true
   776  	return
   777  }
   778  
   779  func (vscc *Validator) deduplicateIdentity(cap *pb.ChaincodeActionPayload) ([]*protoutil.SignedData, error) {
   780  	// this is the first part of the signed message
   781  	prespBytes := cap.Action.ProposalResponsePayload
   782  
   783  	// build the signature set for the evaluation
   784  	signatureSet := []*protoutil.SignedData{}
   785  	signatureMap := make(map[string]struct{})
   786  	// loop through each of the endorsements and build the signature set
   787  	for _, endorsement := range cap.Action.Endorsements {
   788  		// unmarshal endorser bytes
   789  		serializedIdentity := &msp.SerializedIdentity{}
   790  		if err := proto.Unmarshal(endorsement.Endorser, serializedIdentity); err != nil {
   791  			logger.Errorf("Unmarshal endorser error: %s", err)
   792  			return nil, policyErr(fmt.Errorf("Unmarshal endorser error: %s", err))
   793  		}
   794  		identity := serializedIdentity.Mspid + string(serializedIdentity.IdBytes)
   795  		if _, ok := signatureMap[identity]; ok {
   796  			// Endorsement with the same identity has already been added
   797  			logger.Warningf("Ignoring duplicated identity, Mspid: %s, pem:\n%s", serializedIdentity.Mspid, serializedIdentity.IdBytes)
   798  			continue
   799  		}
   800  		data := make([]byte, len(prespBytes)+len(endorsement.Endorser))
   801  		copy(data, prespBytes)
   802  		copy(data[len(prespBytes):], endorsement.Endorser)
   803  		signatureSet = append(signatureSet, &protoutil.SignedData{
   804  			// set the data that is signed; concatenation of proposal response bytes and endorser ID
   805  			Data: data,
   806  			// set the identity that signs the message: it's the endorser
   807  			Identity: endorsement.Endorser,
   808  			// set the signature
   809  			Signature: endorsement.Signature,
   810  		})
   811  		signatureMap[identity] = struct{}{}
   812  	}
   813  
   814  	logger.Debugf("Signature set is of size %d out of %d endorsement(s)", len(signatureSet), len(cap.Action.Endorsements))
   815  	return signatureSet, nil
   816  }
   817  
   818  type state struct {
   819  	vs.State
   820  }
   821  
   822  // GetState retrieves the value for the given key in the given namespace.
   823  func (s *state) GetState(namespace string, key string) ([]byte, error) {
   824  	values, err := s.GetStateMultipleKeys(namespace, []string{key})
   825  	if err != nil {
   826  		return nil, err
   827  	}
   828  	if len(values) == 0 {
   829  		return nil, nil
   830  	}
   831  	return values[0], nil
   832  }
   833  
   834  func policyErr(err error) *commonerrors.VSCCEndorsementPolicyError {
   835  	return &commonerrors.VSCCEndorsementPolicyError{
   836  		Err: err,
   837  	}
   838  }