github.com/hechain20/hechain@v0.0.0-20220316014945-b544036ba106/core/chaincode/lifecycle/scc.go (about)

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