github.com/yous1230/fabric@v2.0.0-beta.0.20191224111736-74345bee6ac2+incompatible/core/chaincode/lifecycle/scc.go (about)

     1  /*
     2  Copyright IBM Corp. All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  package lifecycle
     8  
     9  import (
    10  	"fmt"
    11  	"regexp"
    12  
    13  	"github.com/hyperledger/fabric-chaincode-go/shim"
    14  	"github.com/hyperledger/fabric-protos-go/common"
    15  	mspprotos "github.com/hyperledger/fabric-protos-go/msp"
    16  	pb "github.com/hyperledger/fabric-protos-go/peer"
    17  	lb "github.com/hyperledger/fabric-protos-go/peer/lifecycle"
    18  	"github.com/hyperledger/fabric/common/cauthdsl"
    19  	"github.com/hyperledger/fabric/common/chaincode"
    20  	"github.com/hyperledger/fabric/common/channelconfig"
    21  	"github.com/hyperledger/fabric/core/aclmgmt"
    22  	"github.com/hyperledger/fabric/core/chaincode/persistence"
    23  	"github.com/hyperledger/fabric/core/dispatcher"
    24  	"github.com/hyperledger/fabric/core/ledger"
    25  	"github.com/hyperledger/fabric/msp"
    26  
    27  	"github.com/golang/protobuf/proto"
    28  	"github.com/pkg/errors"
    29  	"go.uber.org/zap/zapcore"
    30  )
    31  
    32  const (
    33  	// LifecycleNamespace is the namespace in the statedb where lifecycle
    34  	// information is stored
    35  	LifecycleNamespace = "_lifecycle"
    36  
    37  	// InstallChaincodeFuncName is the chaincode function name used to install
    38  	// a chaincode
    39  	InstallChaincodeFuncName = "InstallChaincode"
    40  
    41  	// QueryInstalledChaincodeFuncName is the chaincode function name used to
    42  	// query an installed chaincode
    43  	QueryInstalledChaincodeFuncName = "QueryInstalledChaincode"
    44  
    45  	// QueryInstalledChaincodesFuncName is the chaincode function name used to
    46  	// query all installed chaincodes
    47  	QueryInstalledChaincodesFuncName = "QueryInstalledChaincodes"
    48  
    49  	// ApproveChaincodeDefinitionForMyOrgFuncName is the chaincode function name
    50  	// used to approve a chaincode definition for execution by the user's own org
    51  	ApproveChaincodeDefinitionForMyOrgFuncName = "ApproveChaincodeDefinitionForMyOrg"
    52  
    53  	// CheckCommitReadinessFuncName is the chaincode function name used to check
    54  	// a specified chaincode definition is ready to be committed. It returns the
    55  	// approval status for a given definition over a given set of orgs
    56  	CheckCommitReadinessFuncName = "CheckCommitReadiness"
    57  
    58  	// CommitChaincodeDefinitionFuncName is the chaincode function name used to
    59  	// 'commit' (previously 'instantiate') a chaincode in a channel.
    60  	CommitChaincodeDefinitionFuncName = "CommitChaincodeDefinition"
    61  
    62  	// QueryChaincodeDefinitionFuncName is the chaincode function name used to
    63  	// query a committed chaincode definition in a channel.
    64  	QueryChaincodeDefinitionFuncName = "QueryChaincodeDefinition"
    65  
    66  	// QueryChaincodeDefinitionsFuncName is the chaincode function name used to
    67  	// query the committed chaincode definitions in a channel.
    68  	QueryChaincodeDefinitionsFuncName = "QueryChaincodeDefinitions"
    69  )
    70  
    71  // SCCFunctions provides a backing implementation with concrete arguments
    72  // for each of the SCC functions
    73  type SCCFunctions interface {
    74  	// InstallChaincode persists a chaincode definition to disk
    75  	InstallChaincode([]byte) (*chaincode.InstalledChaincode, error)
    76  
    77  	// QueryInstalledChaincode returns metadata for the chaincode with the supplied package ID.
    78  	QueryInstalledChaincode(packageID string) (*chaincode.InstalledChaincode, error)
    79  
    80  	// GetInstalledChaincodePackage returns the chaincode package
    81  	// installed on the peer as bytes.
    82  	GetInstalledChaincodePackage(packageID string) ([]byte, error)
    83  
    84  	// QueryInstalledChaincodes returns the currently installed chaincodes
    85  	QueryInstalledChaincodes() []*chaincode.InstalledChaincode
    86  
    87  	// ApproveChaincodeDefinitionForOrg records a chaincode definition into this org's implicit collection.
    88  	ApproveChaincodeDefinitionForOrg(chname, ccname string, cd *ChaincodeDefinition, packageID string, publicState ReadableState, orgState ReadWritableState) error
    89  
    90  	// CheckCommitReadiness returns a map containing the orgs
    91  	// whose orgStates were supplied and whether or not they have approved
    92  	// the specified definition.
    93  	CheckCommitReadiness(chname, ccname string, cd *ChaincodeDefinition, publicState ReadWritableState, orgStates []OpaqueState) (map[string]bool, error)
    94  
    95  	// CommitChaincodeDefinition records a new chaincode definition into the
    96  	// public state and returns a map containing the orgs whose orgStates
    97  	// were supplied and whether or not they have approved the definition.
    98  	CommitChaincodeDefinition(chname, ccname string, cd *ChaincodeDefinition, publicState ReadWritableState, orgStates []OpaqueState) (map[string]bool, error)
    99  
   100  	// QueryChaincodeDefinition returns a chaincode definition from the public
   101  	// state.
   102  	QueryChaincodeDefinition(name string, publicState ReadableState) (*ChaincodeDefinition, error)
   103  
   104  	// QueryOrgApprovals returns a map containing the orgs whose orgStates were
   105  	// supplied and whether or not they have approved a chaincode definition with
   106  	// the specified parameters.
   107  	QueryOrgApprovals(name string, cd *ChaincodeDefinition, orgStates []OpaqueState) (map[string]bool, error)
   108  
   109  	// QueryNamespaceDefinitions returns all defined namespaces
   110  	QueryNamespaceDefinitions(publicState RangeableState) (map[string]string, error)
   111  }
   112  
   113  //go:generate counterfeiter -o mock/channel_config_source.go --fake-name ChannelConfigSource . ChannelConfigSource
   114  
   115  // ChannelConfigSource provides a way to retrieve the channel config for a given
   116  // channel ID.
   117  type ChannelConfigSource interface {
   118  	// GetStableChannelConfig returns the channel config for a given channel id.
   119  	// Note, it is a stable bundle, which means it will not be updated, even if
   120  	// the channel is, so it should be discarded after use.
   121  	GetStableChannelConfig(channelID string) channelconfig.Resources
   122  }
   123  
   124  //go:generate counterfeiter -o mock/queryexecutor_provider.go --fake-name QueryExecutorProvider . QueryExecutorProvider
   125  
   126  // QueryExecutorProvider provides a way to retrieve the query executor assosciated with an invocation
   127  type QueryExecutorProvider interface {
   128  	TxQueryExecutor(channelID, txID string) ledger.SimpleQueryExecutor
   129  }
   130  
   131  // SCC implements the required methods to satisfy the chaincode interface.
   132  // It routes the invocation calls to the backing implementations.
   133  type SCC struct {
   134  	OrgMSPID string
   135  
   136  	ACLProvider aclmgmt.ACLProvider
   137  
   138  	ChannelConfigSource ChannelConfigSource
   139  
   140  	DeployedCCInfoProvider ledger.DeployedChaincodeInfoProvider
   141  	QueryExecutorProvider  QueryExecutorProvider
   142  
   143  	// Functions provides the backing implementation of lifecycle.
   144  	Functions SCCFunctions
   145  
   146  	// Dispatcher handles the rote protobuf boilerplate for unmarshaling/marshaling
   147  	// the inputs and outputs of the SCC functions.
   148  	Dispatcher *dispatcher.Dispatcher
   149  }
   150  
   151  // Name returns "_lifecycle"
   152  func (scc *SCC) Name() string {
   153  	return LifecycleNamespace
   154  }
   155  
   156  // Chaincode returns a reference to itself
   157  func (scc *SCC) Chaincode() shim.Chaincode {
   158  	return scc
   159  }
   160  
   161  // Init is mostly useless for system chaincodes and always returns success
   162  func (scc *SCC) Init(stub shim.ChaincodeStubInterface) pb.Response {
   163  	return shim.Success(nil)
   164  }
   165  
   166  // Invoke takes chaincode invocation arguments and routes them to the correct
   167  // underlying lifecycle operation.  All functions take a single argument of
   168  // type marshaled lb.<FunctionName>Args and return a marshaled lb.<FunctionName>Result
   169  func (scc *SCC) Invoke(stub shim.ChaincodeStubInterface) pb.Response {
   170  	args := stub.GetArgs()
   171  	if len(args) == 0 {
   172  		return shim.Error("lifecycle scc must be invoked with arguments")
   173  	}
   174  
   175  	if len(args) != 2 {
   176  		return shim.Error(fmt.Sprintf("lifecycle scc operations require exactly two arguments but received %d", len(args)))
   177  	}
   178  
   179  	var ac channelconfig.Application
   180  	var channelID string
   181  	if channelID = stub.GetChannelID(); channelID != "" {
   182  		channelConfig := scc.ChannelConfigSource.GetStableChannelConfig(channelID)
   183  		if channelConfig == nil {
   184  			return shim.Error(fmt.Sprintf("could not get channelconfig for channel '%s'", channelID))
   185  		}
   186  		var ok bool
   187  		ac, ok = channelConfig.ApplicationConfig()
   188  		if !ok {
   189  			return shim.Error(fmt.Sprintf("could not get application config for channel '%s'", channelID))
   190  		}
   191  		if !ac.Capabilities().LifecycleV20() {
   192  			return shim.Error(fmt.Sprintf("cannot use new lifecycle for channel '%s' as it does not have the required capabilities enabled", channelID))
   193  		}
   194  	}
   195  
   196  	// Handle ACL:
   197  	sp, err := stub.GetSignedProposal()
   198  	if err != nil {
   199  		return shim.Error(fmt.Sprintf("Failed getting signed proposal from stub: [%s]", err))
   200  	}
   201  
   202  	err = scc.ACLProvider.CheckACL(fmt.Sprintf("%s/%s", LifecycleNamespace, args[0]), stub.GetChannelID(), sp)
   203  	if err != nil {
   204  		return shim.Error(fmt.Sprintf("Failed to authorize invocation due to failed ACL check: %s", err))
   205  	}
   206  
   207  	outputBytes, err := scc.Dispatcher.Dispatch(
   208  		args[1],
   209  		string(args[0]),
   210  		&Invocation{
   211  			ChannelID:         channelID,
   212  			ApplicationConfig: ac,
   213  			SCC:               scc,
   214  			Stub:              stub,
   215  		},
   216  	)
   217  	if err != nil {
   218  		switch err.(type) {
   219  		case ErrNamespaceNotDefined, persistence.CodePackageNotFoundErr:
   220  			return pb.Response{
   221  				Status:  404,
   222  				Message: err.Error(),
   223  			}
   224  		default:
   225  			return shim.Error(fmt.Sprintf("failed to invoke backing implementation of '%s': %s", string(args[0]), err.Error()))
   226  		}
   227  	}
   228  
   229  	return shim.Success(outputBytes)
   230  }
   231  
   232  type Invocation struct {
   233  	ChannelID         string
   234  	ApplicationConfig channelconfig.Application // Note this may be nil
   235  	Stub              shim.ChaincodeStubInterface
   236  	SCC               *SCC
   237  }
   238  
   239  // InstallChaincode is a SCC function that may be dispatched to which routes
   240  // to the underlying lifecycle implementation.
   241  func (i *Invocation) InstallChaincode(input *lb.InstallChaincodeArgs) (proto.Message, error) {
   242  	if logger.IsEnabledFor(zapcore.DebugLevel) {
   243  		end := 35
   244  		if len(input.ChaincodeInstallPackage) < end {
   245  			end = len(input.ChaincodeInstallPackage)
   246  		}
   247  
   248  		// the first tens of bytes contain the (compressed) portion
   249  		// of the package metadata and so they'll be different across
   250  		// different packages, acting as a package fingerprint useful
   251  		// to identify various packages from the content
   252  		packageFingerprint := input.ChaincodeInstallPackage[0:end]
   253  		logger.Debugf("received invocation of InstallChaincode for install package %x...",
   254  			packageFingerprint,
   255  		)
   256  	}
   257  
   258  	installedCC, err := i.SCC.Functions.InstallChaincode(input.ChaincodeInstallPackage)
   259  	if err != nil {
   260  		return nil, err
   261  	}
   262  
   263  	return &lb.InstallChaincodeResult{
   264  		Label:     installedCC.Label,
   265  		PackageId: installedCC.PackageID,
   266  	}, nil
   267  }
   268  
   269  // QueryInstalledChaincode is a SCC function that may be dispatched to which
   270  // routes to the underlying lifecycle implementation.
   271  func (i *Invocation) QueryInstalledChaincode(input *lb.QueryInstalledChaincodeArgs) (proto.Message, error) {
   272  	logger.Debugf("received invocation of QueryInstalledChaincode for install package ID '%s'",
   273  		input.PackageId,
   274  	)
   275  
   276  	chaincode, err := i.SCC.Functions.QueryInstalledChaincode(input.PackageId)
   277  	if err != nil {
   278  		return nil, err
   279  	}
   280  
   281  	references := map[string]*lb.QueryInstalledChaincodeResult_References{}
   282  	for channel, chaincodeMetadata := range chaincode.References {
   283  		chaincodes := make([]*lb.QueryInstalledChaincodeResult_Chaincode, len(chaincodeMetadata))
   284  		for i, metadata := range chaincodeMetadata {
   285  			chaincodes[i] = &lb.QueryInstalledChaincodeResult_Chaincode{
   286  				Name:    metadata.Name,
   287  				Version: metadata.Version,
   288  			}
   289  		}
   290  
   291  		references[channel] = &lb.QueryInstalledChaincodeResult_References{
   292  			Chaincodes: chaincodes,
   293  		}
   294  	}
   295  
   296  	return &lb.QueryInstalledChaincodeResult{
   297  		Label:      chaincode.Label,
   298  		PackageId:  chaincode.PackageID,
   299  		References: references,
   300  	}, nil
   301  }
   302  
   303  // GetInstalledChaincodePackage is a SCC function that may be dispatched to
   304  // which routes to the underlying lifecycle implementation.
   305  func (i *Invocation) GetInstalledChaincodePackage(input *lb.GetInstalledChaincodePackageArgs) (proto.Message, error) {
   306  	logger.Debugf("received invocation of GetInstalledChaincodePackage")
   307  
   308  	pkgBytes, err := i.SCC.Functions.GetInstalledChaincodePackage(input.PackageId)
   309  	if err != nil {
   310  		return nil, err
   311  	}
   312  
   313  	return &lb.GetInstalledChaincodePackageResult{
   314  		ChaincodeInstallPackage: pkgBytes,
   315  	}, nil
   316  }
   317  
   318  // QueryInstalledChaincodes is a SCC function that may be dispatched to which
   319  // routes to the underlying lifecycle implementation.
   320  func (i *Invocation) QueryInstalledChaincodes(input *lb.QueryInstalledChaincodesArgs) (proto.Message, error) {
   321  	logger.Debugf("received invocation of QueryInstalledChaincodes")
   322  
   323  	chaincodes := i.SCC.Functions.QueryInstalledChaincodes()
   324  
   325  	result := &lb.QueryInstalledChaincodesResult{}
   326  	for _, chaincode := range chaincodes {
   327  		references := map[string]*lb.QueryInstalledChaincodesResult_References{}
   328  		for channel, chaincodeMetadata := range chaincode.References {
   329  			chaincodes := make([]*lb.QueryInstalledChaincodesResult_Chaincode, len(chaincodeMetadata))
   330  			for i, metadata := range chaincodeMetadata {
   331  				chaincodes[i] = &lb.QueryInstalledChaincodesResult_Chaincode{
   332  					Name:    metadata.Name,
   333  					Version: metadata.Version,
   334  				}
   335  			}
   336  
   337  			references[channel] = &lb.QueryInstalledChaincodesResult_References{
   338  				Chaincodes: chaincodes,
   339  			}
   340  		}
   341  
   342  		result.InstalledChaincodes = append(result.InstalledChaincodes,
   343  			&lb.QueryInstalledChaincodesResult_InstalledChaincode{
   344  				Label:      chaincode.Label,
   345  				PackageId:  chaincode.PackageID,
   346  				References: references,
   347  			})
   348  	}
   349  
   350  	return result, nil
   351  }
   352  
   353  // ApproveChaincodeDefinitionForMyOrg is a SCC function that may be dispatched
   354  // to which routes to the underlying lifecycle implementation.
   355  func (i *Invocation) ApproveChaincodeDefinitionForMyOrg(input *lb.ApproveChaincodeDefinitionForMyOrgArgs) (proto.Message, error) {
   356  	if err := i.validateInput(input.Name, input.Version, input.Collections); err != nil {
   357  		return nil, err
   358  	}
   359  	collectionName := ImplicitCollectionNameForOrg(i.SCC.OrgMSPID)
   360  	var collectionConfig []*pb.CollectionConfig
   361  	if input.Collections != nil {
   362  		collectionConfig = input.Collections.Config
   363  	}
   364  
   365  	var packageID string
   366  	if input.Source != nil {
   367  		switch source := input.Source.Type.(type) {
   368  		case *lb.ChaincodeSource_LocalPackage:
   369  			packageID = source.LocalPackage.PackageId
   370  		case *lb.ChaincodeSource_Unavailable_:
   371  		default:
   372  		}
   373  	}
   374  
   375  	cd := &ChaincodeDefinition{
   376  		Sequence: input.Sequence,
   377  		EndorsementInfo: &lb.ChaincodeEndorsementInfo{
   378  			Version:           input.Version,
   379  			EndorsementPlugin: input.EndorsementPlugin,
   380  			InitRequired:      input.InitRequired,
   381  		},
   382  		ValidationInfo: &lb.ChaincodeValidationInfo{
   383  			ValidationPlugin:    input.ValidationPlugin,
   384  			ValidationParameter: input.ValidationParameter,
   385  		},
   386  		Collections: &pb.CollectionConfigPackage{
   387  			Config: collectionConfig,
   388  		},
   389  	}
   390  
   391  	logger.Debugf("received invocation of ApproveChaincodeDefinitionForMyOrg on channel '%s' for definition '%s'",
   392  		i.Stub.GetChannelID(),
   393  		cd,
   394  	)
   395  
   396  	if err := i.SCC.Functions.ApproveChaincodeDefinitionForOrg(
   397  		i.Stub.GetChannelID(),
   398  		input.Name,
   399  		cd,
   400  		packageID,
   401  		i.Stub,
   402  		&ChaincodePrivateLedgerShim{
   403  			Collection: collectionName,
   404  			Stub:       i.Stub,
   405  		},
   406  	); err != nil {
   407  		return nil, err
   408  	}
   409  	return &lb.ApproveChaincodeDefinitionForMyOrgResult{}, nil
   410  }
   411  
   412  // CheckCommitReadiness is a SCC function that may be dispatched
   413  // to the underlying lifecycle implementation.
   414  func (i *Invocation) CheckCommitReadiness(input *lb.CheckCommitReadinessArgs) (proto.Message, error) {
   415  	opaqueStates, err := i.createOpaqueStates()
   416  	if err != nil {
   417  		return nil, err
   418  	}
   419  
   420  	cd := &ChaincodeDefinition{
   421  		Sequence: input.Sequence,
   422  		EndorsementInfo: &lb.ChaincodeEndorsementInfo{
   423  			Version:           input.Version,
   424  			EndorsementPlugin: input.EndorsementPlugin,
   425  			InitRequired:      input.InitRequired,
   426  		},
   427  		ValidationInfo: &lb.ChaincodeValidationInfo{
   428  			ValidationPlugin:    input.ValidationPlugin,
   429  			ValidationParameter: input.ValidationParameter,
   430  		},
   431  		Collections: input.Collections,
   432  	}
   433  
   434  	logger.Debugf("received invocation of CheckCommitReadiness on channel '%s' for definition '%s'",
   435  		i.Stub.GetChannelID(),
   436  		cd,
   437  	)
   438  
   439  	approvals, err := i.SCC.Functions.CheckCommitReadiness(
   440  		i.Stub.GetChannelID(),
   441  		input.Name,
   442  		cd,
   443  		i.Stub,
   444  		opaqueStates,
   445  	)
   446  	if err != nil {
   447  		return nil, err
   448  	}
   449  
   450  	return &lb.CheckCommitReadinessResult{
   451  		Approvals: approvals,
   452  	}, nil
   453  }
   454  
   455  // CommitChaincodeDefinition is a SCC function that may be dispatched
   456  // to which routes to the underlying lifecycle implementation.
   457  func (i *Invocation) CommitChaincodeDefinition(input *lb.CommitChaincodeDefinitionArgs) (proto.Message, error) {
   458  	if err := i.validateInput(input.Name, input.Version, input.Collections); err != nil {
   459  		return nil, err
   460  	}
   461  
   462  	if i.ApplicationConfig == nil {
   463  		return nil, errors.Errorf("no application config for channel '%s'", i.Stub.GetChannelID())
   464  	}
   465  
   466  	orgs := i.ApplicationConfig.Organizations()
   467  	opaqueStates := make([]OpaqueState, 0, len(orgs))
   468  	var myOrg string
   469  	for _, org := range orgs {
   470  		opaqueStates = append(opaqueStates, &ChaincodePrivateLedgerShim{
   471  			Collection: ImplicitCollectionNameForOrg(org.MSPID()),
   472  			Stub:       i.Stub,
   473  		})
   474  		if org.MSPID() == i.SCC.OrgMSPID {
   475  			myOrg = i.SCC.OrgMSPID
   476  		}
   477  	}
   478  
   479  	if myOrg == "" {
   480  		return nil, errors.Errorf("impossibly, this peer's org is processing requests for a channel it is not a member of")
   481  	}
   482  
   483  	cd := &ChaincodeDefinition{
   484  		Sequence: input.Sequence,
   485  		EndorsementInfo: &lb.ChaincodeEndorsementInfo{
   486  			Version:           input.Version,
   487  			EndorsementPlugin: input.EndorsementPlugin,
   488  			InitRequired:      input.InitRequired,
   489  		},
   490  		ValidationInfo: &lb.ChaincodeValidationInfo{
   491  			ValidationPlugin:    input.ValidationPlugin,
   492  			ValidationParameter: input.ValidationParameter,
   493  		},
   494  		Collections: input.Collections,
   495  	}
   496  
   497  	logger.Debugf("received invocation of CommitChaincodeDefinition on channel '%s' for definition '%s'",
   498  		i.Stub.GetChannelID(),
   499  		cd,
   500  	)
   501  
   502  	approvals, err := i.SCC.Functions.CommitChaincodeDefinition(
   503  		i.Stub.GetChannelID(),
   504  		input.Name,
   505  		cd,
   506  		i.Stub,
   507  		opaqueStates,
   508  	)
   509  	if err != nil {
   510  		return nil, err
   511  	}
   512  
   513  	if !approvals[myOrg] {
   514  		return nil, errors.Errorf("chaincode definition not agreed to by this org (%s)", i.SCC.OrgMSPID)
   515  	}
   516  
   517  	return &lb.CommitChaincodeDefinitionResult{}, nil
   518  }
   519  
   520  // QueryChaincodeDefinition is a SCC function that may be dispatched
   521  // to which routes to the underlying lifecycle implementation.
   522  func (i *Invocation) QueryChaincodeDefinition(input *lb.QueryChaincodeDefinitionArgs) (proto.Message, error) {
   523  	logger.Debugf("received invocation of QueryChaincodeDefinition on channel '%s' for chaincode '%s'",
   524  		i.Stub.GetChannelID(),
   525  		input.Name,
   526  	)
   527  
   528  	definedChaincode, err := i.SCC.Functions.QueryChaincodeDefinition(input.Name, i.Stub)
   529  	if err != nil {
   530  		return nil, err
   531  	}
   532  
   533  	opaqueStates, err := i.createOpaqueStates()
   534  	if err != nil {
   535  		return nil, err
   536  	}
   537  
   538  	var approvals map[string]bool
   539  	if approvals, err = i.SCC.Functions.QueryOrgApprovals(input.Name, definedChaincode, opaqueStates); err != nil {
   540  		return nil, err
   541  	}
   542  
   543  	return &lb.QueryChaincodeDefinitionResult{
   544  		Sequence:            definedChaincode.Sequence,
   545  		Version:             definedChaincode.EndorsementInfo.Version,
   546  		EndorsementPlugin:   definedChaincode.EndorsementInfo.EndorsementPlugin,
   547  		ValidationPlugin:    definedChaincode.ValidationInfo.ValidationPlugin,
   548  		ValidationParameter: definedChaincode.ValidationInfo.ValidationParameter,
   549  		InitRequired:        definedChaincode.EndorsementInfo.InitRequired,
   550  		Collections:         definedChaincode.Collections,
   551  		Approvals:           approvals,
   552  	}, nil
   553  }
   554  
   555  // QueryChaincodeDefinitions is a SCC function that may be dispatched
   556  // to which routes to the underlying lifecycle implementation.
   557  func (i *Invocation) QueryChaincodeDefinitions(input *lb.QueryChaincodeDefinitionsArgs) (proto.Message, error) {
   558  	logger.Debugf("received invocation of QueryChaincodeDefinitions on channel '%s'",
   559  		i.Stub.GetChannelID(),
   560  	)
   561  
   562  	namespaces, err := i.SCC.Functions.QueryNamespaceDefinitions(&ChaincodePublicLedgerShim{ChaincodeStubInterface: i.Stub})
   563  	if err != nil {
   564  		return nil, err
   565  	}
   566  
   567  	chaincodeDefinitions := []*lb.QueryChaincodeDefinitionsResult_ChaincodeDefinition{}
   568  	for namespace, nType := range namespaces {
   569  		if nType == FriendlyChaincodeDefinitionType {
   570  			definedChaincode, err := i.SCC.Functions.QueryChaincodeDefinition(namespace, i.Stub)
   571  			if err != nil {
   572  				return nil, err
   573  			}
   574  
   575  			chaincodeDefinitions = append(chaincodeDefinitions, &lb.QueryChaincodeDefinitionsResult_ChaincodeDefinition{
   576  				Name:                namespace,
   577  				Sequence:            definedChaincode.Sequence,
   578  				Version:             definedChaincode.EndorsementInfo.Version,
   579  				EndorsementPlugin:   definedChaincode.EndorsementInfo.EndorsementPlugin,
   580  				ValidationPlugin:    definedChaincode.ValidationInfo.ValidationPlugin,
   581  				ValidationParameter: definedChaincode.ValidationInfo.ValidationParameter,
   582  				InitRequired:        definedChaincode.EndorsementInfo.InitRequired,
   583  				Collections:         definedChaincode.Collections,
   584  			})
   585  		}
   586  	}
   587  
   588  	return &lb.QueryChaincodeDefinitionsResult{
   589  		ChaincodeDefinitions: chaincodeDefinitions,
   590  	}, nil
   591  }
   592  
   593  var (
   594  	// NOTE the chaincode name/version regular expressions should stay in sync
   595  	// with those defined in core/scc/lscc/lscc.go until LSCC has been removed.
   596  	ChaincodeNameRegExp    = regexp.MustCompile("^[a-zA-Z0-9]+([-_][a-zA-Z0-9]+)*$")
   597  	ChaincodeVersionRegExp = regexp.MustCompile("^[A-Za-z0-9_.+-]+$")
   598  
   599  	collectionNameRegExp = regexp.MustCompile("^[A-Za-z0-9-]+([A-Za-z0-9_-]+)*$")
   600  
   601  	// currently defined system chaincode names that shouldn't
   602  	// be allowed as user-defined chaincode names
   603  	systemChaincodeNames = map[string]struct{}{
   604  		"cscc": {},
   605  		"escc": {},
   606  		"lscc": {},
   607  		"qscc": {},
   608  		"vscc": {},
   609  	}
   610  )
   611  
   612  func (i *Invocation) validateInput(name, version string, collections *pb.CollectionConfigPackage) error {
   613  	if !ChaincodeNameRegExp.MatchString(name) {
   614  		return errors.Errorf("invalid chaincode name '%s'. Names can only consist of alphanumerics, '_', and '-' and can only begin with alphanumerics", name)
   615  	}
   616  	if _, ok := systemChaincodeNames[name]; ok {
   617  		return errors.Errorf("chaincode name '%s' is the name of a system chaincode", name)
   618  	}
   619  
   620  	if !ChaincodeVersionRegExp.MatchString(version) {
   621  		return errors.Errorf("invalid chaincode version '%s'. Versions can only consist of alphanumerics, '_', '-', '+', and '.'", version)
   622  	}
   623  
   624  	collConfigs, err := extractStaticCollectionConfigs(collections)
   625  	if err != nil {
   626  		return err
   627  	}
   628  	// we extract the channel config to check whether the supplied collection configuration
   629  	// complies to the given msp configuration and performs semantic validation.
   630  	// Channel config may change afterwards (i.e., after endorsement or commit of this transaction).
   631  	// Fabric will deal with the situation where some collection configs are no longer meaningful.
   632  	// Therefore, the use of channel config for verifying during endorsement is more
   633  	// towards catching manual errors in the config as oppose to any attempt of serializability.
   634  	channelConfig := i.SCC.ChannelConfigSource.GetStableChannelConfig(i.ChannelID)
   635  	if channelConfig == nil {
   636  		return errors.Errorf("could not get channelconfig for channel '%s'", i.ChannelID)
   637  	}
   638  	mspMgr := channelConfig.MSPManager()
   639  	if mspMgr == nil {
   640  		return errors.Errorf("could not get MSP manager for channel '%s'", i.ChannelID)
   641  	}
   642  
   643  	if err := validateCollectionConfigs(collConfigs, mspMgr); err != nil {
   644  		return err
   645  	}
   646  
   647  	// validate against collection configs in the committed definition
   648  	qe := i.SCC.QueryExecutorProvider.TxQueryExecutor(i.Stub.GetChannelID(), i.Stub.GetTxID())
   649  	committedCCDef, err := i.SCC.DeployedCCInfoProvider.ChaincodeInfo(i.ChannelID, name, qe)
   650  	if err != nil {
   651  		return errors.Wrapf(err, "could not retrieve committed definition for chaincode '%s'", name)
   652  	}
   653  	if committedCCDef == nil {
   654  		return nil
   655  	}
   656  	if err := validateCollConfigsAgainstCommittedDef(collConfigs, committedCCDef.ExplicitCollectionConfigPkg); err != nil {
   657  		return err
   658  	}
   659  	return nil
   660  }
   661  
   662  func extractStaticCollectionConfigs(collConfigPkg *pb.CollectionConfigPackage) ([]*pb.StaticCollectionConfig, error) {
   663  	if collConfigPkg == nil || len(collConfigPkg.Config) == 0 {
   664  		return nil, nil
   665  	}
   666  	collConfigs := make([]*pb.StaticCollectionConfig, len(collConfigPkg.Config))
   667  	for i, c := range collConfigPkg.Config {
   668  		switch t := c.Payload.(type) {
   669  		case *pb.CollectionConfig_StaticCollectionConfig:
   670  			collConfig := t.StaticCollectionConfig
   671  			if collConfig == nil {
   672  				return nil, errors.Errorf("collection configuration is empty")
   673  			}
   674  			collConfigs[i] = collConfig
   675  		default:
   676  			// this should only occur if a developer has added a new
   677  			// collection config type
   678  			return nil, errors.Errorf("collection config contains unexpected payload type: %T", t)
   679  		}
   680  	}
   681  	return collConfigs, nil
   682  }
   683  
   684  func validateCollectionConfigs(collConfigs []*pb.StaticCollectionConfig, mspMgr msp.MSPManager) error {
   685  	if len(collConfigs) == 0 {
   686  		return nil
   687  	}
   688  	collNamesMap := map[string]struct{}{}
   689  	// Process each collection config from a set of collection configs
   690  	for _, c := range collConfigs {
   691  		if !collectionNameRegExp.MatchString(c.Name) {
   692  			return errors.Errorf("invalid collection name '%s'. Names can only consist of alphanumerics, '_', and '-' and cannot begin with '_'",
   693  				c.Name)
   694  		}
   695  		// Ensure that there are no duplicate collection names
   696  		if _, ok := collNamesMap[c.Name]; ok {
   697  			return errors.Errorf("collection-name: %s -- found duplicate in collection configuration",
   698  				c.Name)
   699  		}
   700  		collNamesMap[c.Name] = struct{}{}
   701  		// Validate gossip related parameters present in the collection config
   702  		if c.MaximumPeerCount < c.RequiredPeerCount {
   703  			return errors.Errorf("collection-name: %s -- maximum peer count (%d) cannot be less than the required peer count (%d)",
   704  				c.Name, c.MaximumPeerCount, c.RequiredPeerCount)
   705  		}
   706  		if c.RequiredPeerCount < 0 {
   707  			return errors.Errorf("collection-name: %s -- requiredPeerCount (%d) cannot be less than zero",
   708  				c.Name, c.RequiredPeerCount)
   709  		}
   710  		if err := validateCollectionConfigMemberOrgsPolicy(c, mspMgr); err != nil {
   711  			return err
   712  		}
   713  	}
   714  	return nil
   715  }
   716  
   717  // validateCollectionConfigAgainstMsp checks whether the supplied collection configuration
   718  // complies to the given msp configuration
   719  func validateCollectionConfigMemberOrgsPolicy(coll *pb.StaticCollectionConfig, mspMgr msp.MSPManager) error {
   720  	if coll.MemberOrgsPolicy == nil {
   721  		return errors.Errorf("collection member policy is not set for collection '%s'", coll.Name)
   722  	}
   723  	if coll.MemberOrgsPolicy.GetSignaturePolicy() == nil {
   724  		return errors.Errorf("collection member org policy is empty for collection '%s'", coll.Name)
   725  	}
   726  
   727  	// calling this constructor ensures extra semantic validation for the policy
   728  	pp := &cauthdsl.EnvelopeBasedPolicyProvider{Deserializer: mspMgr}
   729  	if _, err := pp.NewPolicy(coll.MemberOrgsPolicy.GetSignaturePolicy()); err != nil {
   730  		return errors.WithMessagef(err, "invalid member org policy for collection '%s'", coll.Name)
   731  	}
   732  
   733  	// make sure that the signature policy is meaningful (only consists of ORs)
   734  	if err := validateSpOrConcat(coll.MemberOrgsPolicy.GetSignaturePolicy().Rule); err != nil {
   735  		return errors.WithMessagef(err, "collection-name: %s -- error in member org policy", coll.Name)
   736  	}
   737  
   738  	msps, err := mspMgr.GetMSPs()
   739  	if err != nil {
   740  		return errors.Wrapf(err, "could not get MSPs")
   741  	}
   742  
   743  	// make sure that the orgs listed are actually part of the channel
   744  	// check all principals in the signature policy
   745  	for _, principal := range coll.MemberOrgsPolicy.GetSignaturePolicy().Identities {
   746  		var orgID string
   747  		// the member org policy only supports certain principal types
   748  		switch principal.PrincipalClassification {
   749  
   750  		case mspprotos.MSPPrincipal_ROLE:
   751  			msprole := &mspprotos.MSPRole{}
   752  			err := proto.Unmarshal(principal.Principal, msprole)
   753  			if err != nil {
   754  				return errors.Wrapf(err, "collection-name: %s -- cannot unmarshal identity bytes into MSPRole", coll.GetName())
   755  			}
   756  			orgID = msprole.MspIdentifier
   757  			// the msp map is indexed using msp IDs - this behavior is implementation specific, making the following check a bit of a hack
   758  			_, ok := msps[orgID]
   759  			if !ok {
   760  				return errors.Errorf("collection-name: %s -- collection member '%s' is not part of the channel", coll.GetName(), orgID)
   761  			}
   762  
   763  		case mspprotos.MSPPrincipal_ORGANIZATION_UNIT:
   764  			mspou := &mspprotos.OrganizationUnit{}
   765  			err := proto.Unmarshal(principal.Principal, mspou)
   766  			if err != nil {
   767  				return errors.Wrapf(err, "collection-name: %s -- cannot unmarshal identity bytes into OrganizationUnit", coll.GetName())
   768  			}
   769  			orgID = mspou.MspIdentifier
   770  			// the msp map is indexed using msp IDs - this behavior is implementation specific, making the following check a bit of a hack
   771  			_, ok := msps[orgID]
   772  			if !ok {
   773  				return errors.Errorf("collection-name: %s -- collection member '%s' is not part of the channel", coll.GetName(), orgID)
   774  			}
   775  
   776  		case mspprotos.MSPPrincipal_IDENTITY:
   777  			if _, err := mspMgr.DeserializeIdentity(principal.Principal); err != nil {
   778  				return errors.Errorf("collection-name: %s -- contains an identity that is not part of the channel", coll.GetName())
   779  			}
   780  
   781  		default:
   782  			return errors.Errorf("collection-name: %s -- principal type %v is not supported", coll.GetName(), principal.PrincipalClassification)
   783  		}
   784  	}
   785  	return nil
   786  }
   787  
   788  // validateSpOrConcat checks if the supplied signature policy is just an OR-concatenation of identities
   789  func validateSpOrConcat(sp *common.SignaturePolicy) error {
   790  	if sp.GetNOutOf() == nil {
   791  		return nil
   792  	}
   793  	// check if N == 1 (OR concatenation)
   794  	if sp.GetNOutOf().N != 1 {
   795  		return errors.Errorf("signature policy is not an OR concatenation, NOutOf %d", sp.GetNOutOf().N)
   796  	}
   797  	// recurse into all sub-rules
   798  	for _, rule := range sp.GetNOutOf().Rules {
   799  		err := validateSpOrConcat(rule)
   800  		if err != nil {
   801  			return err
   802  		}
   803  	}
   804  	return nil
   805  }
   806  
   807  func validateCollConfigsAgainstCommittedDef(
   808  	proposedCollConfs []*pb.StaticCollectionConfig,
   809  	committedCollConfPkg *pb.CollectionConfigPackage,
   810  ) error {
   811  	if committedCollConfPkg == nil || len(committedCollConfPkg.Config) == 0 {
   812  		return nil
   813  	}
   814  
   815  	if len(proposedCollConfs) == 0 {
   816  		return errors.Errorf("the proposed collection config does not contain previously defined collections")
   817  	}
   818  
   819  	proposedCollsMap := map[string]*pb.StaticCollectionConfig{}
   820  	for _, c := range proposedCollConfs {
   821  		proposedCollsMap[c.Name] = c
   822  	}
   823  
   824  	// In the new collection config package, ensure that there is one entry per old collection. Any
   825  	// number of new collections are allowed.
   826  	for _, committedCollConfig := range committedCollConfPkg.Config {
   827  		committedColl := committedCollConfig.GetStaticCollectionConfig()
   828  		// It cannot be nil
   829  		if committedColl == nil {
   830  			return errors.Errorf("unknown collection configuration type")
   831  		}
   832  
   833  		newCollection, ok := proposedCollsMap[committedColl.Name]
   834  		if !ok {
   835  			return errors.Errorf("existing collection [%s] missing in the proposed collection configuration", committedColl.Name)
   836  		}
   837  
   838  		if newCollection.BlockToLive != committedColl.BlockToLive {
   839  			return errors.Errorf("the BlockToLive in an existing collection [%s] modified. Existing value [%d]", committedColl.Name, committedColl.BlockToLive)
   840  		}
   841  	}
   842  	return nil
   843  }
   844  
   845  func (i *Invocation) createOpaqueStates() ([]OpaqueState, error) {
   846  	if i.ApplicationConfig == nil {
   847  		return nil, errors.Errorf("no application config for channel '%s'", i.Stub.GetChannelID())
   848  	}
   849  	orgs := i.ApplicationConfig.Organizations()
   850  	opaqueStates := make([]OpaqueState, 0, len(orgs))
   851  	for _, org := range orgs {
   852  		opaqueStates = append(opaqueStates, &ChaincodePrivateLedgerShim{
   853  			Collection: ImplicitCollectionNameForOrg(org.MSPID()),
   854  			Stub:       i.Stub,
   855  		})
   856  	}
   857  	return opaqueStates, nil
   858  }