github.com/kaituanwang/hyperledger@v2.0.1+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  	logger.Infof("Successfully endorsed commit for chaincode name '%s' on channel '%s' with definition {%s}", input.Name, i.Stub.GetChannelID(), cd)
   518  
   519  	return &lb.CommitChaincodeDefinitionResult{}, nil
   520  }
   521  
   522  // QueryChaincodeDefinition is a SCC function that may be dispatched
   523  // to which routes to the underlying lifecycle implementation.
   524  func (i *Invocation) QueryChaincodeDefinition(input *lb.QueryChaincodeDefinitionArgs) (proto.Message, error) {
   525  	logger.Debugf("received invocation of QueryChaincodeDefinition on channel '%s' for chaincode '%s'",
   526  		i.Stub.GetChannelID(),
   527  		input.Name,
   528  	)
   529  
   530  	definedChaincode, err := i.SCC.Functions.QueryChaincodeDefinition(input.Name, i.Stub)
   531  	if err != nil {
   532  		return nil, err
   533  	}
   534  
   535  	opaqueStates, err := i.createOpaqueStates()
   536  	if err != nil {
   537  		return nil, err
   538  	}
   539  
   540  	var approvals map[string]bool
   541  	if approvals, err = i.SCC.Functions.QueryOrgApprovals(input.Name, definedChaincode, opaqueStates); err != nil {
   542  		return nil, err
   543  	}
   544  
   545  	return &lb.QueryChaincodeDefinitionResult{
   546  		Sequence:            definedChaincode.Sequence,
   547  		Version:             definedChaincode.EndorsementInfo.Version,
   548  		EndorsementPlugin:   definedChaincode.EndorsementInfo.EndorsementPlugin,
   549  		ValidationPlugin:    definedChaincode.ValidationInfo.ValidationPlugin,
   550  		ValidationParameter: definedChaincode.ValidationInfo.ValidationParameter,
   551  		InitRequired:        definedChaincode.EndorsementInfo.InitRequired,
   552  		Collections:         definedChaincode.Collections,
   553  		Approvals:           approvals,
   554  	}, nil
   555  }
   556  
   557  // QueryChaincodeDefinitions is a SCC function that may be dispatched
   558  // to which routes to the underlying lifecycle implementation.
   559  func (i *Invocation) QueryChaincodeDefinitions(input *lb.QueryChaincodeDefinitionsArgs) (proto.Message, error) {
   560  	logger.Debugf("received invocation of QueryChaincodeDefinitions on channel '%s'",
   561  		i.Stub.GetChannelID(),
   562  	)
   563  
   564  	namespaces, err := i.SCC.Functions.QueryNamespaceDefinitions(&ChaincodePublicLedgerShim{ChaincodeStubInterface: i.Stub})
   565  	if err != nil {
   566  		return nil, err
   567  	}
   568  
   569  	chaincodeDefinitions := []*lb.QueryChaincodeDefinitionsResult_ChaincodeDefinition{}
   570  	for namespace, nType := range namespaces {
   571  		if nType == FriendlyChaincodeDefinitionType {
   572  			definedChaincode, err := i.SCC.Functions.QueryChaincodeDefinition(namespace, i.Stub)
   573  			if err != nil {
   574  				return nil, err
   575  			}
   576  
   577  			chaincodeDefinitions = append(chaincodeDefinitions, &lb.QueryChaincodeDefinitionsResult_ChaincodeDefinition{
   578  				Name:                namespace,
   579  				Sequence:            definedChaincode.Sequence,
   580  				Version:             definedChaincode.EndorsementInfo.Version,
   581  				EndorsementPlugin:   definedChaincode.EndorsementInfo.EndorsementPlugin,
   582  				ValidationPlugin:    definedChaincode.ValidationInfo.ValidationPlugin,
   583  				ValidationParameter: definedChaincode.ValidationInfo.ValidationParameter,
   584  				InitRequired:        definedChaincode.EndorsementInfo.InitRequired,
   585  				Collections:         definedChaincode.Collections,
   586  			})
   587  		}
   588  	}
   589  
   590  	return &lb.QueryChaincodeDefinitionsResult{
   591  		ChaincodeDefinitions: chaincodeDefinitions,
   592  	}, nil
   593  }
   594  
   595  var (
   596  	// NOTE the chaincode name/version regular expressions should stay in sync
   597  	// with those defined in core/scc/lscc/lscc.go until LSCC has been removed.
   598  	ChaincodeNameRegExp    = regexp.MustCompile("^[a-zA-Z0-9]+([-_][a-zA-Z0-9]+)*$")
   599  	ChaincodeVersionRegExp = regexp.MustCompile("^[A-Za-z0-9_.+-]+$")
   600  
   601  	collectionNameRegExp = regexp.MustCompile("^[A-Za-z0-9-]+([A-Za-z0-9_-]+)*$")
   602  
   603  	// currently defined system chaincode names that shouldn't
   604  	// be allowed as user-defined chaincode names
   605  	systemChaincodeNames = map[string]struct{}{
   606  		"cscc": {},
   607  		"escc": {},
   608  		"lscc": {},
   609  		"qscc": {},
   610  		"vscc": {},
   611  	}
   612  )
   613  
   614  func (i *Invocation) validateInput(name, version string, collections *pb.CollectionConfigPackage) error {
   615  	if !ChaincodeNameRegExp.MatchString(name) {
   616  		return errors.Errorf("invalid chaincode name '%s'. Names can only consist of alphanumerics, '_', and '-' and can only begin with alphanumerics", name)
   617  	}
   618  	if _, ok := systemChaincodeNames[name]; ok {
   619  		return errors.Errorf("chaincode name '%s' is the name of a system chaincode", name)
   620  	}
   621  
   622  	if !ChaincodeVersionRegExp.MatchString(version) {
   623  		return errors.Errorf("invalid chaincode version '%s'. Versions can only consist of alphanumerics, '_', '-', '+', and '.'", version)
   624  	}
   625  
   626  	collConfigs, err := extractStaticCollectionConfigs(collections)
   627  	if err != nil {
   628  		return err
   629  	}
   630  	// we extract the channel config to check whether the supplied collection configuration
   631  	// complies to the given msp configuration and performs semantic validation.
   632  	// Channel config may change afterwards (i.e., after endorsement or commit of this transaction).
   633  	// Fabric will deal with the situation where some collection configs are no longer meaningful.
   634  	// Therefore, the use of channel config for verifying during endorsement is more
   635  	// towards catching manual errors in the config as oppose to any attempt of serializability.
   636  	channelConfig := i.SCC.ChannelConfigSource.GetStableChannelConfig(i.ChannelID)
   637  	if channelConfig == nil {
   638  		return errors.Errorf("could not get channelconfig for channel '%s'", i.ChannelID)
   639  	}
   640  	mspMgr := channelConfig.MSPManager()
   641  	if mspMgr == nil {
   642  		return errors.Errorf("could not get MSP manager for channel '%s'", i.ChannelID)
   643  	}
   644  
   645  	if err := validateCollectionConfigs(collConfigs, mspMgr); err != nil {
   646  		return err
   647  	}
   648  
   649  	// validate against collection configs in the committed definition
   650  	qe := i.SCC.QueryExecutorProvider.TxQueryExecutor(i.Stub.GetChannelID(), i.Stub.GetTxID())
   651  	committedCCDef, err := i.SCC.DeployedCCInfoProvider.ChaincodeInfo(i.ChannelID, name, qe)
   652  	if err != nil {
   653  		return errors.Wrapf(err, "could not retrieve committed definition for chaincode '%s'", name)
   654  	}
   655  	if committedCCDef == nil {
   656  		return nil
   657  	}
   658  	if err := validateCollConfigsAgainstCommittedDef(collConfigs, committedCCDef.ExplicitCollectionConfigPkg); err != nil {
   659  		return err
   660  	}
   661  	return nil
   662  }
   663  
   664  func extractStaticCollectionConfigs(collConfigPkg *pb.CollectionConfigPackage) ([]*pb.StaticCollectionConfig, error) {
   665  	if collConfigPkg == nil || len(collConfigPkg.Config) == 0 {
   666  		return nil, nil
   667  	}
   668  	collConfigs := make([]*pb.StaticCollectionConfig, len(collConfigPkg.Config))
   669  	for i, c := range collConfigPkg.Config {
   670  		switch t := c.Payload.(type) {
   671  		case *pb.CollectionConfig_StaticCollectionConfig:
   672  			collConfig := t.StaticCollectionConfig
   673  			if collConfig == nil {
   674  				return nil, errors.Errorf("collection configuration is empty")
   675  			}
   676  			collConfigs[i] = collConfig
   677  		default:
   678  			// this should only occur if a developer has added a new
   679  			// collection config type
   680  			return nil, errors.Errorf("collection config contains unexpected payload type: %T", t)
   681  		}
   682  	}
   683  	return collConfigs, nil
   684  }
   685  
   686  func validateCollectionConfigs(collConfigs []*pb.StaticCollectionConfig, mspMgr msp.MSPManager) error {
   687  	if len(collConfigs) == 0 {
   688  		return nil
   689  	}
   690  	collNamesMap := map[string]struct{}{}
   691  	// Process each collection config from a set of collection configs
   692  	for _, c := range collConfigs {
   693  		if !collectionNameRegExp.MatchString(c.Name) {
   694  			return errors.Errorf("invalid collection name '%s'. Names can only consist of alphanumerics, '_', and '-' and cannot begin with '_'",
   695  				c.Name)
   696  		}
   697  		// Ensure that there are no duplicate collection names
   698  		if _, ok := collNamesMap[c.Name]; ok {
   699  			return errors.Errorf("collection-name: %s -- found duplicate in collection configuration",
   700  				c.Name)
   701  		}
   702  		collNamesMap[c.Name] = struct{}{}
   703  		// Validate gossip related parameters present in the collection config
   704  		if c.MaximumPeerCount < c.RequiredPeerCount {
   705  			return errors.Errorf("collection-name: %s -- maximum peer count (%d) cannot be less than the required peer count (%d)",
   706  				c.Name, c.MaximumPeerCount, c.RequiredPeerCount)
   707  		}
   708  		if c.RequiredPeerCount < 0 {
   709  			return errors.Errorf("collection-name: %s -- requiredPeerCount (%d) cannot be less than zero",
   710  				c.Name, c.RequiredPeerCount)
   711  		}
   712  		if err := validateCollectionConfigMemberOrgsPolicy(c, mspMgr); err != nil {
   713  			return err
   714  		}
   715  	}
   716  	return nil
   717  }
   718  
   719  // validateCollectionConfigAgainstMsp checks whether the supplied collection configuration
   720  // complies to the given msp configuration
   721  func validateCollectionConfigMemberOrgsPolicy(coll *pb.StaticCollectionConfig, mspMgr msp.MSPManager) error {
   722  	if coll.MemberOrgsPolicy == nil {
   723  		return errors.Errorf("collection member policy is not set for collection '%s'", coll.Name)
   724  	}
   725  	if coll.MemberOrgsPolicy.GetSignaturePolicy() == nil {
   726  		return errors.Errorf("collection member org policy is empty for collection '%s'", coll.Name)
   727  	}
   728  
   729  	// calling this constructor ensures extra semantic validation for the policy
   730  	pp := &cauthdsl.EnvelopeBasedPolicyProvider{Deserializer: mspMgr}
   731  	if _, err := pp.NewPolicy(coll.MemberOrgsPolicy.GetSignaturePolicy()); err != nil {
   732  		return errors.WithMessagef(err, "invalid member org policy for collection '%s'", coll.Name)
   733  	}
   734  
   735  	// make sure that the signature policy is meaningful (only consists of ORs)
   736  	if err := validateSpOrConcat(coll.MemberOrgsPolicy.GetSignaturePolicy().Rule); err != nil {
   737  		return errors.WithMessagef(err, "collection-name: %s -- error in member org policy", coll.Name)
   738  	}
   739  
   740  	msps, err := mspMgr.GetMSPs()
   741  	if err != nil {
   742  		return errors.Wrapf(err, "could not get MSPs")
   743  	}
   744  
   745  	// make sure that the orgs listed are actually part of the channel
   746  	// check all principals in the signature policy
   747  	for _, principal := range coll.MemberOrgsPolicy.GetSignaturePolicy().Identities {
   748  		var orgID string
   749  		// the member org policy only supports certain principal types
   750  		switch principal.PrincipalClassification {
   751  
   752  		case mspprotos.MSPPrincipal_ROLE:
   753  			msprole := &mspprotos.MSPRole{}
   754  			err := proto.Unmarshal(principal.Principal, msprole)
   755  			if err != nil {
   756  				return errors.Wrapf(err, "collection-name: %s -- cannot unmarshal identity bytes into MSPRole", coll.GetName())
   757  			}
   758  			orgID = msprole.MspIdentifier
   759  			// the msp map is indexed using msp IDs - this behavior is implementation specific, making the following check a bit of a hack
   760  			_, ok := msps[orgID]
   761  			if !ok {
   762  				return errors.Errorf("collection-name: %s -- collection member '%s' is not part of the channel", coll.GetName(), orgID)
   763  			}
   764  
   765  		case mspprotos.MSPPrincipal_ORGANIZATION_UNIT:
   766  			mspou := &mspprotos.OrganizationUnit{}
   767  			err := proto.Unmarshal(principal.Principal, mspou)
   768  			if err != nil {
   769  				return errors.Wrapf(err, "collection-name: %s -- cannot unmarshal identity bytes into OrganizationUnit", coll.GetName())
   770  			}
   771  			orgID = mspou.MspIdentifier
   772  			// the msp map is indexed using msp IDs - this behavior is implementation specific, making the following check a bit of a hack
   773  			_, ok := msps[orgID]
   774  			if !ok {
   775  				return errors.Errorf("collection-name: %s -- collection member '%s' is not part of the channel", coll.GetName(), orgID)
   776  			}
   777  
   778  		case mspprotos.MSPPrincipal_IDENTITY:
   779  			if _, err := mspMgr.DeserializeIdentity(principal.Principal); err != nil {
   780  				return errors.Errorf("collection-name: %s -- contains an identity that is not part of the channel", coll.GetName())
   781  			}
   782  
   783  		default:
   784  			return errors.Errorf("collection-name: %s -- principal type %v is not supported", coll.GetName(), principal.PrincipalClassification)
   785  		}
   786  	}
   787  	return nil
   788  }
   789  
   790  // validateSpOrConcat checks if the supplied signature policy is just an OR-concatenation of identities
   791  func validateSpOrConcat(sp *common.SignaturePolicy) error {
   792  	if sp.GetNOutOf() == nil {
   793  		return nil
   794  	}
   795  	// check if N == 1 (OR concatenation)
   796  	if sp.GetNOutOf().N != 1 {
   797  		return errors.Errorf("signature policy is not an OR concatenation, NOutOf %d", sp.GetNOutOf().N)
   798  	}
   799  	// recurse into all sub-rules
   800  	for _, rule := range sp.GetNOutOf().Rules {
   801  		err := validateSpOrConcat(rule)
   802  		if err != nil {
   803  			return err
   804  		}
   805  	}
   806  	return nil
   807  }
   808  
   809  func validateCollConfigsAgainstCommittedDef(
   810  	proposedCollConfs []*pb.StaticCollectionConfig,
   811  	committedCollConfPkg *pb.CollectionConfigPackage,
   812  ) error {
   813  	if committedCollConfPkg == nil || len(committedCollConfPkg.Config) == 0 {
   814  		return nil
   815  	}
   816  
   817  	if len(proposedCollConfs) == 0 {
   818  		return errors.Errorf("the proposed collection config does not contain previously defined collections")
   819  	}
   820  
   821  	proposedCollsMap := map[string]*pb.StaticCollectionConfig{}
   822  	for _, c := range proposedCollConfs {
   823  		proposedCollsMap[c.Name] = c
   824  	}
   825  
   826  	// In the new collection config package, ensure that there is one entry per old collection. Any
   827  	// number of new collections are allowed.
   828  	for _, committedCollConfig := range committedCollConfPkg.Config {
   829  		committedColl := committedCollConfig.GetStaticCollectionConfig()
   830  		// It cannot be nil
   831  		if committedColl == nil {
   832  			return errors.Errorf("unknown collection configuration type")
   833  		}
   834  
   835  		newCollection, ok := proposedCollsMap[committedColl.Name]
   836  		if !ok {
   837  			return errors.Errorf("existing collection [%s] missing in the proposed collection configuration", committedColl.Name)
   838  		}
   839  
   840  		if newCollection.BlockToLive != committedColl.BlockToLive {
   841  			return errors.Errorf("the BlockToLive in an existing collection [%s] modified. Existing value [%d]", committedColl.Name, committedColl.BlockToLive)
   842  		}
   843  	}
   844  	return nil
   845  }
   846  
   847  func (i *Invocation) createOpaqueStates() ([]OpaqueState, error) {
   848  	if i.ApplicationConfig == nil {
   849  		return nil, errors.Errorf("no application config for channel '%s'", i.Stub.GetChannelID())
   850  	}
   851  	orgs := i.ApplicationConfig.Organizations()
   852  	opaqueStates := make([]OpaqueState, 0, len(orgs))
   853  	for _, org := range orgs {
   854  		opaqueStates = append(opaqueStates, &ChaincodePrivateLedgerShim{
   855  			Collection: ImplicitCollectionNameForOrg(org.MSPID()),
   856  			Stub:       i.Stub,
   857  		})
   858  	}
   859  	return opaqueStates, nil
   860  }