github.com/hechain20/hechain@v0.0.0-20220316014945-b544036ba106/core/chaincode/lifecycle/lifecycle.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  	"bytes"
    11  	"fmt"
    12  	"sync"
    13  
    14  	"github.com/hechain20/hechain/common/chaincode"
    15  	"github.com/hechain20/hechain/common/flogging"
    16  	"github.com/hechain20/hechain/common/policydsl"
    17  	"github.com/hechain20/hechain/core/chaincode/implicitcollection"
    18  	"github.com/hechain20/hechain/core/chaincode/persistence"
    19  	"github.com/hechain20/hechain/core/container"
    20  	"github.com/hechain20/hechain/protoutil"
    21  	cb "github.com/hyperledger/fabric-protos-go/common"
    22  	"github.com/hyperledger/fabric-protos-go/msp"
    23  	pb "github.com/hyperledger/fabric-protos-go/peer"
    24  	lb "github.com/hyperledger/fabric-protos-go/peer/lifecycle"
    25  
    26  	"github.com/golang/protobuf/proto"
    27  	"github.com/pkg/errors"
    28  )
    29  
    30  var logger = flogging.MustGetLogger("lifecycle")
    31  
    32  const (
    33  	// NamespacesName is the prefix (or namespace) of the DB which will be used to store
    34  	// the information about other namespaces (for things like chaincodes) in the DB.
    35  	// We want a sub-namespaces within lifecycle in case other information needs to be stored here
    36  	// in the future.
    37  	NamespacesName = "namespaces"
    38  
    39  	// ChaincodeSourcesName is the namespace reserved for storing the information about where
    40  	// to find the chaincode (such as as a package on the local filesystem, or in the future,
    41  	// at some network resource). This namespace is only populated in the org implicit collection.
    42  	ChaincodeSourcesName = "chaincode-sources"
    43  
    44  	// ChaincodeLocalPackageType is the name of the type of chaincode-sources which may be serialized
    45  	// into the org's private data collection
    46  	ChaincodeLocalPackageType = "ChaincodeLocalPackage"
    47  
    48  	// ChaincodeParametersType is the name of the type used to store the parts of the chaincode definition
    49  	// which are serialized as values in the statedb
    50  	ChaincodeParametersType = "ChaincodeParameters"
    51  
    52  	// ChaincodeDefinitionType is the name of the type used to store defined chaincodes
    53  	ChaincodeDefinitionType = "ChaincodeDefinition"
    54  
    55  	// FriendlyChaincodeDefinitionType is the name exposed to the outside world for the chaincode namespace
    56  	FriendlyChaincodeDefinitionType = "Chaincode"
    57  
    58  	// DefaultEndorsementPolicyRef is the name of the default endorsement policy for this channel
    59  	DefaultEndorsementPolicyRef = "/Channel/Application/Endorsement"
    60  )
    61  
    62  var DefaultEndorsementPolicyBytes = protoutil.MarshalOrPanic(&pb.ApplicationPolicy{
    63  	Type: &pb.ApplicationPolicy_ChannelConfigPolicyReference{
    64  		ChannelConfigPolicyReference: DefaultEndorsementPolicyRef,
    65  	},
    66  })
    67  
    68  // Sequences are the underpinning of the definition framework for lifecycle.
    69  // All definitions must have a Sequence field in the public state.  This
    70  // sequence is incremented by exactly 1 with each redefinition of the
    71  // namespace. The private state org approvals also have a Sequence number
    72  // embedded into the key which matches them either to the vote for the commit,
    73  // or registers approval for an already committed definition.
    74  //
    75  // Public/World DB layout looks like the following:
    76  // namespaces/metadata/<namespace> -> namespace metadata, including namespace type
    77  // namespaces/fields/<namespace>/Sequence -> sequence for this namespace
    78  // namespaces/fields/<namespace>/<field> -> field of namespace type
    79  //
    80  // So, for instance, a db might look like:
    81  //
    82  // namespaces/metadata/mycc:                   "ChaincodeDefinition"
    83  // namespaces/fields/mycc/Sequence             1 (The current sequence)
    84  // namespaces/fields/mycc/EndorsementInfo:     {Version: "1.3", EndorsementPlugin: "builtin", InitRequired: true}
    85  // namespaces/fields/mycc/ValidationInfo:      {ValidationPlugin: "builtin", ValidationParameter: <application-policy>}
    86  // namespaces/fields/mycc/Collections          {<collection info>}
    87  //
    88  // Private/Org Scope Implcit Collection layout looks like the following
    89  // namespaces/metadata/<namespace>#<sequence_number> -> namespace metadata, including type
    90  // namespaces/fields/<namespace>#<sequence_number>/<field>  -> field of namespace type
    91  //
    92  // namespaces/metadata/mycc#1:                   "ChaincodeParameters"
    93  // namespaces/fields/mycc#1/EndorsementInfo:     {Version: "1.3", EndorsementPlugin: "builtin", InitRequired: true}
    94  // namespaces/fields/mycc#1/ValidationInfo:      {ValidationPlugin: "builtin", ValidationParameter: <application-policy>}
    95  // namespaces/fields/mycc#1/Collections          {<collection info>}
    96  // namespaces/metadata/mycc#2:                   "ChaincodeParameters"
    97  // namespaces/fields/mycc#2/EndorsementInfo:     {Version: "1.4", EndorsementPlugin: "builtin", InitRequired: true}
    98  // namespaces/fields/mycc#2/ValidationInfo:      {ValidationPlugin: "builtin", ValidationParameter: <application-policy>}
    99  // namespaces/fields/mycc#2/Collections          {<collection info>}
   100  //
   101  // chaincode-sources/metadata/mycc#1              "ChaincodeLocalPackage"
   102  // chaincode-sources/fields/mycc#1/PackageID      "hash1"
   103  
   104  // ChaincodeLocalPackage is a type of chaincode-sources which may be serialized
   105  // into the org's private data collection.
   106  // WARNING: This structure is serialized/deserialized from the DB, re-ordering
   107  // or adding fields will cause opaque checks to fail.
   108  type ChaincodeLocalPackage struct {
   109  	PackageID string
   110  }
   111  
   112  // ChaincodeParameters are the parts of the chaincode definition which are serialized
   113  // as values in the statedb.  It is expected that any instance will have no nil fields once initialized.
   114  // WARNING: This structure is serialized/deserialized from the DB, re-ordering or adding fields
   115  // will cause opaque checks to fail.
   116  type ChaincodeParameters struct {
   117  	EndorsementInfo *lb.ChaincodeEndorsementInfo
   118  	ValidationInfo  *lb.ChaincodeValidationInfo
   119  	Collections     *pb.CollectionConfigPackage
   120  }
   121  
   122  func (cp *ChaincodeParameters) Equal(ocp *ChaincodeParameters) error {
   123  	switch {
   124  	case cp.EndorsementInfo.Version != ocp.EndorsementInfo.Version:
   125  		return errors.Errorf("expected Version '%s' does not match passed Version '%s'", cp.EndorsementInfo.Version, ocp.EndorsementInfo.Version)
   126  	case cp.EndorsementInfo.EndorsementPlugin != ocp.EndorsementInfo.EndorsementPlugin:
   127  		return errors.Errorf("expected EndorsementPlugin '%s' does not match passed EndorsementPlugin '%s'", cp.EndorsementInfo.EndorsementPlugin, ocp.EndorsementInfo.EndorsementPlugin)
   128  	case cp.EndorsementInfo.InitRequired != ocp.EndorsementInfo.InitRequired:
   129  		return errors.Errorf("expected InitRequired '%t' does not match passed InitRequired '%t'", cp.EndorsementInfo.InitRequired, ocp.EndorsementInfo.InitRequired)
   130  	case cp.ValidationInfo.ValidationPlugin != ocp.ValidationInfo.ValidationPlugin:
   131  		return errors.Errorf("expected ValidationPlugin '%s' does not match passed ValidationPlugin '%s'", cp.ValidationInfo.ValidationPlugin, ocp.ValidationInfo.ValidationPlugin)
   132  	case !bytes.Equal(cp.ValidationInfo.ValidationParameter, ocp.ValidationInfo.ValidationParameter):
   133  		return errors.Errorf("expected ValidationParameter '%x' does not match passed ValidationParameter '%x'", cp.ValidationInfo.ValidationParameter, ocp.ValidationInfo.ValidationParameter)
   134  	case !proto.Equal(cp.Collections, ocp.Collections):
   135  		return errors.Errorf("Collections do not match")
   136  	default:
   137  	}
   138  	return nil
   139  }
   140  
   141  // ChaincodeDefinition contains the chaincode parameters, as well as the sequence number of the definition.
   142  // Note, it does not embed ChaincodeParameters so as not to complicate the serialization.  It is expected
   143  // that any instance will have no nil fields once initialized.
   144  // WARNING: This structure is serialized/deserialized from the DB, re-ordering or adding fields
   145  // will cause opaque checks to fail.
   146  type ChaincodeDefinition struct {
   147  	Sequence        int64
   148  	EndorsementInfo *lb.ChaincodeEndorsementInfo
   149  	ValidationInfo  *lb.ChaincodeValidationInfo
   150  	Collections     *pb.CollectionConfigPackage
   151  }
   152  
   153  type ApprovedChaincodeDefinition struct {
   154  	Sequence        int64
   155  	EndorsementInfo *lb.ChaincodeEndorsementInfo
   156  	ValidationInfo  *lb.ChaincodeValidationInfo
   157  	Collections     *pb.CollectionConfigPackage
   158  	Source          *lb.ChaincodeSource
   159  }
   160  
   161  // Parameters returns the non-sequence info of the chaincode definition
   162  func (cd *ChaincodeDefinition) Parameters() *ChaincodeParameters {
   163  	return &ChaincodeParameters{
   164  		EndorsementInfo: cd.EndorsementInfo,
   165  		ValidationInfo:  cd.ValidationInfo,
   166  		Collections:     cd.Collections,
   167  	}
   168  }
   169  
   170  func (cd *ChaincodeDefinition) String() string {
   171  	endorsementInfo := "endorsement info: <EMPTY>"
   172  	if cd.EndorsementInfo != nil {
   173  		endorsementInfo = fmt.Sprintf("endorsement info: (version: '%s', plugin: '%s', init required: %t)",
   174  			cd.EndorsementInfo.Version,
   175  			cd.EndorsementInfo.EndorsementPlugin,
   176  			cd.EndorsementInfo.InitRequired,
   177  		)
   178  	}
   179  
   180  	validationInfo := "validation info: <EMPTY>"
   181  	if cd.ValidationInfo != nil {
   182  		validationInfo = fmt.Sprintf("validation info: (plugin: '%s', policy: '%x')",
   183  			cd.ValidationInfo.ValidationPlugin,
   184  			cd.ValidationInfo.ValidationParameter,
   185  		)
   186  	}
   187  
   188  	return fmt.Sprintf("sequence: %d, %s, %s, collections: (%+v)",
   189  		cd.Sequence,
   190  		endorsementInfo,
   191  		validationInfo,
   192  		cd.Collections,
   193  	)
   194  }
   195  
   196  //go:generate counterfeiter -o mock/chaincode_builder.go --fake-name ChaincodeBuilder . ChaincodeBuilder
   197  
   198  type ChaincodeBuilder interface {
   199  	Build(ccid string) error
   200  }
   201  
   202  // ChaincodeStore provides a way to persist chaincodes
   203  type ChaincodeStore interface {
   204  	Save(label string, ccInstallPkg []byte) (string, error)
   205  	ListInstalledChaincodes() ([]chaincode.InstalledChaincode, error)
   206  	Load(packageID string) (ccInstallPkg []byte, err error)
   207  	Delete(packageID string) error
   208  }
   209  
   210  type PackageParser interface {
   211  	Parse(data []byte) (*persistence.ChaincodePackage, error)
   212  }
   213  
   214  //go:generate counterfeiter -o mock/install_listener.go --fake-name InstallListener . InstallListener
   215  type InstallListener interface {
   216  	HandleChaincodeInstalled(md *persistence.ChaincodePackageMetadata, packageID string)
   217  }
   218  
   219  //go:generate counterfeiter -o mock/installed_chaincodes_lister.go --fake-name InstalledChaincodesLister . InstalledChaincodesLister
   220  type InstalledChaincodesLister interface {
   221  	ListInstalledChaincodes() []*chaincode.InstalledChaincode
   222  	GetInstalledChaincode(packageID string) (*chaincode.InstalledChaincode, error)
   223  }
   224  
   225  // Resources stores the common functions needed by all components of the lifecycle
   226  // by the SCC as well as internally.  It also has some utility methods attached to it
   227  // for querying the lifecycle definitions.
   228  type Resources struct {
   229  	ChannelConfigSource ChannelConfigSource
   230  	ChaincodeStore      ChaincodeStore
   231  	PackageParser       PackageParser
   232  	Serializer          *Serializer
   233  }
   234  
   235  // ChaincodeDefinitionIfDefined returns whether the chaincode name is defined in the new lifecycle, a shim around
   236  // the SimpleQueryExecutor to work with the serializer, or an error.  If the namespace is defined, but it is
   237  // not a chaincode, this is considered an error.
   238  func (r *Resources) ChaincodeDefinitionIfDefined(chaincodeName string, state ReadableState) (bool, *ChaincodeDefinition, error) {
   239  	if chaincodeName == LifecycleNamespace {
   240  		return true, &ChaincodeDefinition{
   241  			EndorsementInfo: &lb.ChaincodeEndorsementInfo{
   242  				InitRequired: false,
   243  			},
   244  			ValidationInfo: &lb.ChaincodeValidationInfo{},
   245  		}, nil
   246  	}
   247  
   248  	metadata, ok, err := r.Serializer.DeserializeMetadata(NamespacesName, chaincodeName, state)
   249  	if err != nil {
   250  		return false, nil, errors.WithMessagef(err, "could not deserialize metadata for chaincode %s", chaincodeName)
   251  	}
   252  
   253  	if !ok {
   254  		return false, nil, nil
   255  	}
   256  
   257  	if metadata.Datatype != ChaincodeDefinitionType {
   258  		return false, nil, errors.Errorf("not a chaincode type: %s", metadata.Datatype)
   259  	}
   260  
   261  	definedChaincode := &ChaincodeDefinition{}
   262  	err = r.Serializer.Deserialize(NamespacesName, chaincodeName, metadata, definedChaincode, state)
   263  	if err != nil {
   264  		return false, nil, errors.WithMessagef(err, "could not deserialize chaincode definition for chaincode %s", chaincodeName)
   265  	}
   266  
   267  	return true, definedChaincode, nil
   268  }
   269  
   270  func (r *Resources) LifecycleEndorsementPolicyAsBytes(channelID string) ([]byte, error) {
   271  	channelConfig := r.ChannelConfigSource.GetStableChannelConfig(channelID)
   272  	if channelConfig == nil {
   273  		return nil, errors.Errorf("could not get channel config for channel '%s'", channelID)
   274  	}
   275  
   276  	if _, ok := channelConfig.PolicyManager().GetPolicy(LifecycleEndorsementPolicyRef); ok {
   277  		return LifecycleDefaultEndorsementPolicyBytes, nil
   278  	}
   279  
   280  	// This was a channel which was upgraded or did not define a lifecycle endorsement policy, use a default
   281  	// of "a majority of orgs must have a member sign".
   282  	ac, ok := channelConfig.ApplicationConfig()
   283  	if !ok {
   284  		return nil, errors.Errorf("could not get application config for channel '%s'", channelID)
   285  	}
   286  	orgs := ac.Organizations()
   287  	mspids := make([]string, 0, len(orgs))
   288  	for _, org := range orgs {
   289  		mspids = append(mspids, org.MSPID())
   290  	}
   291  
   292  	return protoutil.MarshalOrPanic(&cb.ApplicationPolicy{
   293  		Type: &cb.ApplicationPolicy_SignaturePolicy{
   294  			SignaturePolicy: policydsl.SignedByNOutOfGivenRole(int32(len(mspids)/2+1), msp.MSPRole_MEMBER, mspids),
   295  		},
   296  	}), nil
   297  }
   298  
   299  // ExternalFunctions is intended primarily to support the SCC functions.
   300  // In general, its methods signatures produce writes (which must be commmitted
   301  // as part of an endorsement flow), or return human readable errors (for
   302  // instance indicating a chaincode is not found) rather than sentinels.
   303  // Instead, use the utility functions attached to the lifecycle Resources
   304  // when needed.
   305  type ExternalFunctions struct {
   306  	Resources                 *Resources
   307  	InstallListener           InstallListener
   308  	InstalledChaincodesLister InstalledChaincodesLister
   309  	ChaincodeBuilder          ChaincodeBuilder
   310  	BuildRegistry             *container.BuildRegistry
   311  	mutex                     sync.Mutex
   312  	BuildLocks                map[string]sync.Mutex
   313  }
   314  
   315  // CheckCommitReadiness takes a chaincode definition, checks that
   316  // its sequence number is the next allowable sequence number and checks which
   317  // organizations have approved the definition.
   318  func (ef *ExternalFunctions) CheckCommitReadiness(chname, ccname string, cd *ChaincodeDefinition, publicState ReadWritableState, orgStates []OpaqueState) (map[string]bool, error) {
   319  	currentSequence, err := ef.Resources.Serializer.DeserializeFieldAsInt64(NamespacesName, ccname, "Sequence", publicState)
   320  	if err != nil {
   321  		return nil, errors.WithMessage(err, "could not get current sequence")
   322  	}
   323  
   324  	if cd.Sequence != currentSequence+1 {
   325  		return nil, errors.Errorf("requested sequence is %d, but new definition must be sequence %d", cd.Sequence, currentSequence+1)
   326  	}
   327  
   328  	if err := ef.SetChaincodeDefinitionDefaults(chname, cd); err != nil {
   329  		return nil, errors.WithMessagef(err, "could not set defaults for chaincode definition in channel %s", chname)
   330  	}
   331  
   332  	var approvals map[string]bool
   333  	if approvals, err = ef.QueryOrgApprovals(ccname, cd, orgStates); err != nil {
   334  		return nil, err
   335  	}
   336  
   337  	logger.Infof("Successfully checked commit readiness of chaincode name '%s' on channel '%s' with definition {%s}", ccname, chname, cd)
   338  
   339  	return approvals, nil
   340  }
   341  
   342  // CommitChaincodeDefinition takes a chaincode definition, checks that its
   343  // sequence number is the next allowable sequence number, checks which
   344  // organizations have approved the definition, and applies the definition to
   345  // the public world state. It is the responsibility of the caller to check
   346  // the approvals to determine if the result is valid (typically, this means
   347  // checking that the peer's own org has approved the definition).
   348  func (ef *ExternalFunctions) CommitChaincodeDefinition(chname, ccname string, cd *ChaincodeDefinition, publicState ReadWritableState, orgStates []OpaqueState) (map[string]bool, error) {
   349  	approvals, err := ef.CheckCommitReadiness(chname, ccname, cd, publicState, orgStates)
   350  	if err != nil {
   351  		return nil, err
   352  	}
   353  
   354  	if err = ef.Resources.Serializer.Serialize(NamespacesName, ccname, cd, publicState); err != nil {
   355  		return nil, errors.WithMessage(err, "could not serialize chaincode definition")
   356  	}
   357  
   358  	return approvals, nil
   359  }
   360  
   361  // DefaultEndorsementPolicyAsBytes returns a marshalled version
   362  // of the default chaincode endorsement policy in the supplied channel
   363  func (ef *ExternalFunctions) DefaultEndorsementPolicyAsBytes(channelID string) ([]byte, error) {
   364  	channelConfig := ef.Resources.ChannelConfigSource.GetStableChannelConfig(channelID)
   365  	if channelConfig == nil {
   366  		return nil, errors.Errorf("could not get channel config for channel '%s'", channelID)
   367  	}
   368  
   369  	// see if the channel defines a default
   370  	if _, ok := channelConfig.PolicyManager().GetPolicy(DefaultEndorsementPolicyRef); ok {
   371  		return DefaultEndorsementPolicyBytes, nil
   372  	}
   373  
   374  	return nil, errors.Errorf(
   375  		"policy '%s' must be defined for channel '%s' before chaincode operations can be attempted",
   376  		DefaultEndorsementPolicyRef,
   377  		channelID,
   378  	)
   379  }
   380  
   381  // SetChaincodeDefinitionDefaults fills any empty fields in the
   382  // supplied ChaincodeDefinition with the supplied channel's defaults
   383  func (ef *ExternalFunctions) SetChaincodeDefinitionDefaults(chname string, cd *ChaincodeDefinition) error {
   384  	if cd.EndorsementInfo.EndorsementPlugin == "" {
   385  		// TODO:
   386  		// 1) rename to "default" or "builtin"
   387  		// 2) retrieve from channel config
   388  		cd.EndorsementInfo.EndorsementPlugin = "escc"
   389  	}
   390  
   391  	if cd.ValidationInfo.ValidationPlugin == "" {
   392  		// TODO:
   393  		// 1) rename to "default" or "builtin"
   394  		// 2) retrieve from channel config
   395  		cd.ValidationInfo.ValidationPlugin = "vscc"
   396  	}
   397  
   398  	if len(cd.ValidationInfo.ValidationParameter) == 0 {
   399  		policyBytes, err := ef.DefaultEndorsementPolicyAsBytes(chname)
   400  		if err != nil {
   401  			return err
   402  		}
   403  
   404  		cd.ValidationInfo.ValidationParameter = policyBytes
   405  	}
   406  
   407  	return nil
   408  }
   409  
   410  // ApproveChaincodeDefinitionForOrg adds a chaincode definition entry into the passed in Org state.  The definition must be
   411  // for either the currently defined sequence number or the next sequence number.  If the definition is
   412  // for the current sequence number, then it must match exactly the current definition or it will be rejected.
   413  func (ef *ExternalFunctions) ApproveChaincodeDefinitionForOrg(chname, ccname string, cd *ChaincodeDefinition, packageID string, publicState ReadableState, orgState ReadWritableState) error {
   414  	// Get the current sequence from the public state
   415  	currentSequence, err := ef.Resources.Serializer.DeserializeFieldAsInt64(NamespacesName, ccname, "Sequence", publicState)
   416  	if err != nil {
   417  		return errors.WithMessage(err, "could not get current sequence")
   418  	}
   419  
   420  	requestedSequence := cd.Sequence
   421  
   422  	if currentSequence == requestedSequence && requestedSequence == 0 {
   423  		return errors.Errorf("requested sequence is 0, but first definable sequence number is 1")
   424  	}
   425  
   426  	if requestedSequence < currentSequence {
   427  		return errors.Errorf("currently defined sequence %d is larger than requested sequence %d", currentSequence, requestedSequence)
   428  	}
   429  
   430  	if requestedSequence > currentSequence+1 {
   431  		return errors.Errorf("requested sequence %d is larger than the next available sequence number %d", requestedSequence, currentSequence+1)
   432  	}
   433  
   434  	if err := ef.SetChaincodeDefinitionDefaults(chname, cd); err != nil {
   435  		return errors.WithMessagef(err, "could not set defaults for chaincode definition in channel %s", chname)
   436  	}
   437  
   438  	if requestedSequence == currentSequence {
   439  		metadata, ok, err := ef.Resources.Serializer.DeserializeMetadata(NamespacesName, ccname, publicState)
   440  		if err != nil {
   441  			return errors.WithMessage(err, "could not fetch metadata for current definition")
   442  		}
   443  		if !ok {
   444  			return errors.Errorf("missing metadata for currently committed sequence number (%d)", currentSequence)
   445  		}
   446  
   447  		definedChaincode := &ChaincodeDefinition{}
   448  		if err := ef.Resources.Serializer.Deserialize(NamespacesName, ccname, metadata, definedChaincode, publicState); err != nil {
   449  			return errors.WithMessagef(err, "could not deserialize namespace %s as chaincode", ccname)
   450  		}
   451  
   452  		if err := definedChaincode.Parameters().Equal(cd.Parameters()); err != nil {
   453  			return errors.WithMessagef(err, "attempted to redefine the current committed sequence (%d) for namespace %s with different parameters", currentSequence, ccname)
   454  		}
   455  	}
   456  
   457  	privateName := fmt.Sprintf("%s#%d", ccname, requestedSequence)
   458  
   459  	// if requested sequence is not committed, and attempt is made to update its content,
   460  	// we need to check whether new definition actually contains updated content, to avoid
   461  	// empty write set.
   462  	if requestedSequence == currentSequence+1 {
   463  		uncommittedMetadata, ok, err := ef.Resources.Serializer.DeserializeMetadata(NamespacesName, privateName, orgState)
   464  		if err != nil {
   465  			return errors.WithMessage(err, "could not fetch uncommitted definition")
   466  		}
   467  
   468  		if ok {
   469  			logger.Debugf("Attempting to redefine uncommitted definition at sequence %d", requestedSequence)
   470  
   471  			uncommittedParameters := &ChaincodeParameters{}
   472  			if err := ef.Resources.Serializer.Deserialize(NamespacesName, privateName, uncommittedMetadata, uncommittedParameters, orgState); err != nil {
   473  				return errors.WithMessagef(err, "could not deserialize namespace %s as chaincode", privateName)
   474  			}
   475  
   476  			if err := uncommittedParameters.Equal(cd.Parameters()); err == nil {
   477  				// also check package ID updates
   478  				metadata, ok, err := ef.Resources.Serializer.DeserializeMetadata(ChaincodeSourcesName, privateName, orgState)
   479  				if err != nil {
   480  					return errors.WithMessagef(err, "could not deserialize chaincode-source metadata for %s", privateName)
   481  				}
   482  				if ok {
   483  					ccLocalPackage := &ChaincodeLocalPackage{}
   484  					if err := ef.Resources.Serializer.Deserialize(ChaincodeSourcesName, privateName, metadata, ccLocalPackage, orgState); err != nil {
   485  						return errors.WithMessagef(err, "could not deserialize chaincode package for %s", privateName)
   486  					}
   487  
   488  					if ccLocalPackage.PackageID == packageID {
   489  						return errors.Errorf("attempted to redefine uncommitted sequence (%d) for namespace %s with unchanged content", requestedSequence, ccname)
   490  					}
   491  				}
   492  			}
   493  		}
   494  	}
   495  
   496  	if err := ef.Resources.Serializer.Serialize(NamespacesName, privateName, cd.Parameters(), orgState); err != nil {
   497  		return errors.WithMessage(err, "could not serialize chaincode parameters to state")
   498  	}
   499  
   500  	// set the package id - whether empty or not. Setting
   501  	// an empty package ID means that the chaincode won't
   502  	// be invocable. The package might be set empty after
   503  	// the definition commits as a way of instructing the
   504  	// peers of an org no longer to endorse invocations
   505  	// for this chaincode
   506  	if err := ef.Resources.Serializer.Serialize(ChaincodeSourcesName, privateName, &ChaincodeLocalPackage{
   507  		PackageID: packageID,
   508  	}, orgState); err != nil {
   509  		return errors.WithMessage(err, "could not serialize chaincode package info to state")
   510  	}
   511  
   512  	logger.Infof("Successfully endorsed chaincode approval with name '%s', package ID '%s', on channel '%s' with definition {%s}", ccname, packageID, chname, cd)
   513  
   514  	return nil
   515  }
   516  
   517  // QueryApprovedChaincodeDefinition returns the approved chaincode definition in Org state by using the given parameters.
   518  // If the parameter of sequence is not provided, this function returns the latest approved chaincode definition
   519  // (latest: new one of the currently defined sequence number and the next sequence number).
   520  func (ef *ExternalFunctions) QueryApprovedChaincodeDefinition(chname, ccname string, sequence int64, publicState ReadableState, orgState ReadableState) (*ApprovedChaincodeDefinition, error) {
   521  	requestedSequence := sequence
   522  
   523  	// If requested sequence is not provided,
   524  	// set the latest sequence number (either the currently defined sequence number or the next sequence number)
   525  	if requestedSequence == 0 {
   526  		currentSequence, err := ef.Resources.Serializer.DeserializeFieldAsInt64(NamespacesName, ccname, "Sequence", publicState)
   527  		if err != nil {
   528  			return nil, errors.WithMessage(err, "could not get current sequence")
   529  		}
   530  		requestedSequence = currentSequence
   531  
   532  		nextSequence := currentSequence + 1
   533  		privateName := fmt.Sprintf("%s#%d", ccname, nextSequence)
   534  		_, ok, err := ef.Resources.Serializer.DeserializeMetadata(NamespacesName, privateName, orgState)
   535  		if err != nil {
   536  			return nil, errors.WithMessagef(err, "could not deserialize namespace metadata for next sequence %d", nextSequence)
   537  		}
   538  		if ok {
   539  			requestedSequence = nextSequence
   540  		}
   541  	}
   542  
   543  	logger.Infof("Attempting to fetch approved definition (name: '%s', sequence: '%d') on channel '%s'", ccname, requestedSequence, chname)
   544  	privateName := fmt.Sprintf("%s#%d", ccname, requestedSequence)
   545  	metadata, ok, err := ef.Resources.Serializer.DeserializeMetadata(NamespacesName, privateName, orgState)
   546  	if err != nil {
   547  		return nil, errors.WithMessagef(err, "could not deserialize namespace metadata for %s", privateName)
   548  	}
   549  
   550  	if !ok {
   551  		return nil, errors.Errorf("could not fetch approved chaincode definition (name: '%s', sequence: '%d') on channel '%s'", ccname, sequence, chname)
   552  	}
   553  
   554  	if metadata.Datatype != ChaincodeParametersType {
   555  		return nil, errors.Errorf("not a chaincode parameters type: %s", metadata.Datatype)
   556  	}
   557  
   558  	// Get chaincode parameters for the request sequence
   559  	ccParameters := &ChaincodeParameters{}
   560  	if err := ef.Resources.Serializer.Deserialize(NamespacesName, privateName, metadata, ccParameters, orgState); err != nil {
   561  		return nil, errors.WithMessagef(err, "could not deserialize chaincode parameters for %s", privateName)
   562  	}
   563  
   564  	// Get package ID for the requested sequence
   565  	metadata, ok, err = ef.Resources.Serializer.DeserializeMetadata(ChaincodeSourcesName, privateName, orgState)
   566  	if err != nil {
   567  		return nil, errors.WithMessagef(err, "could not deserialize chaincode-source metadata for %s", privateName)
   568  	}
   569  	if !ok {
   570  		return nil, errors.Errorf("could not fetch approved chaincode definition (name: '%s', sequence: '%d') on channel '%s'", ccname, sequence, chname)
   571  	}
   572  	if metadata.Datatype != ChaincodeLocalPackageType {
   573  		return nil, errors.Errorf("not a chaincode local package type: %s", metadata.Datatype)
   574  	}
   575  
   576  	ccLocalPackage := &ChaincodeLocalPackage{}
   577  	if err := ef.Resources.Serializer.Deserialize(ChaincodeSourcesName, privateName, metadata, ccLocalPackage, orgState); err != nil {
   578  		return nil, errors.WithMessagef(err, "could not deserialize chaincode package for %s", privateName)
   579  	}
   580  
   581  	// Convert to lb.ChaincodeSource
   582  	// An empty package ID means that the chaincode won't be invocable
   583  	var ccsrc *lb.ChaincodeSource
   584  	if ccLocalPackage.PackageID != "" {
   585  		ccsrc = &lb.ChaincodeSource{
   586  			Type: &lb.ChaincodeSource_LocalPackage{
   587  				LocalPackage: &lb.ChaincodeSource_Local{
   588  					PackageId: ccLocalPackage.PackageID,
   589  				},
   590  			},
   591  		}
   592  	} else {
   593  		ccsrc = &lb.ChaincodeSource{
   594  			Type: &lb.ChaincodeSource_Unavailable_{
   595  				Unavailable: &lb.ChaincodeSource_Unavailable{},
   596  			},
   597  		}
   598  	}
   599  
   600  	return &ApprovedChaincodeDefinition{
   601  		Sequence:        requestedSequence,
   602  		EndorsementInfo: ccParameters.EndorsementInfo,
   603  		ValidationInfo:  ccParameters.ValidationInfo,
   604  		Collections:     ccParameters.Collections,
   605  		Source:          ccsrc,
   606  	}, nil
   607  }
   608  
   609  // ErrNamespaceNotDefined is the error returned when a namespace
   610  // is not defined. This indicates that the chaincode definition
   611  // has not been committed.
   612  type ErrNamespaceNotDefined struct {
   613  	Namespace string
   614  }
   615  
   616  func (e ErrNamespaceNotDefined) Error() string {
   617  	return fmt.Sprintf("namespace %s is not defined", e.Namespace)
   618  }
   619  
   620  // QueryChaincodeDefinition returns the defined chaincode by the given name (if it is committed, and a chaincode)
   621  // or otherwise returns an error.
   622  func (ef *ExternalFunctions) QueryChaincodeDefinition(name string, publicState ReadableState) (*ChaincodeDefinition, error) {
   623  	metadata, ok, err := ef.Resources.Serializer.DeserializeMetadata(NamespacesName, name, publicState)
   624  	if err != nil {
   625  		return nil, errors.WithMessagef(err, "could not fetch metadata for namespace %s", name)
   626  	}
   627  	if !ok {
   628  		return nil, ErrNamespaceNotDefined{Namespace: name}
   629  	}
   630  
   631  	definedChaincode := &ChaincodeDefinition{}
   632  	if err := ef.Resources.Serializer.Deserialize(NamespacesName, name, metadata, definedChaincode, publicState); err != nil {
   633  		return nil, errors.WithMessagef(err, "could not deserialize namespace %s as chaincode", name)
   634  	}
   635  
   636  	logger.Infof("Successfully queried chaincode name '%s' with definition {%s},", name, definedChaincode)
   637  
   638  	return definedChaincode, nil
   639  }
   640  
   641  // QueryOrgApprovals returns a map containing the orgs whose orgStates were
   642  // provided and whether or not they have approved a chaincode definition with
   643  // the specified parameters.
   644  func (ef *ExternalFunctions) QueryOrgApprovals(name string, cd *ChaincodeDefinition, orgStates []OpaqueState) (map[string]bool, error) {
   645  	approvals := map[string]bool{}
   646  	privateName := fmt.Sprintf("%s#%d", name, cd.Sequence)
   647  	for _, orgState := range orgStates {
   648  		match, err := ef.Resources.Serializer.IsSerialized(NamespacesName, privateName, cd.Parameters(), orgState)
   649  		if err != nil {
   650  			return nil, errors.WithMessagef(err, "serialization check failed for key %s", privateName)
   651  		}
   652  
   653  		_, org := implicitcollection.MspIDIfImplicitCollection(orgState.CollectionName())
   654  		approvals[org] = match
   655  	}
   656  
   657  	return approvals, nil
   658  }
   659  
   660  // InstallChaincode installs a given chaincode to the peer's chaincode store.
   661  // It returns the hash to reference the chaincode by or an error on failure.
   662  func (ef *ExternalFunctions) InstallChaincode(chaincodeInstallPackage []byte) (*chaincode.InstalledChaincode, error) {
   663  	// Let's validate that the chaincodeInstallPackage is at least well formed before writing it
   664  	pkg, err := ef.Resources.PackageParser.Parse(chaincodeInstallPackage)
   665  	if err != nil {
   666  		return nil, errors.WithMessage(err, "could not parse as a chaincode install package")
   667  	}
   668  
   669  	if pkg.Metadata == nil {
   670  		return nil, errors.New("empty metadata for supplied chaincode")
   671  	}
   672  
   673  	packageID, err := ef.Resources.ChaincodeStore.Save(pkg.Metadata.Label, chaincodeInstallPackage)
   674  	if err != nil {
   675  		return nil, errors.WithMessage(err, "could not save cc install package")
   676  	}
   677  
   678  	buildLock := ef.getBuildLock(packageID)
   679  	buildLock.Lock()
   680  	defer buildLock.Unlock()
   681  
   682  	buildStatus, ok := ef.BuildRegistry.BuildStatus(packageID)
   683  	if ok {
   684  		// another invocation of lifecycle has concurrently
   685  		// installed a chaincode with this package id
   686  		<-buildStatus.Done()
   687  		if buildStatus.Err() == nil {
   688  			return nil, errors.Errorf("chaincode already successfully installed (package ID '%s')", packageID)
   689  		}
   690  		buildStatus = ef.BuildRegistry.ResetBuildStatus(packageID)
   691  	}
   692  	err = ef.ChaincodeBuilder.Build(packageID)
   693  	buildStatus.Notify(err)
   694  	<-buildStatus.Done()
   695  	if err := buildStatus.Err(); err != nil {
   696  		ef.Resources.ChaincodeStore.Delete(packageID)
   697  		return nil, errors.WithMessage(err, "could not build chaincode")
   698  	}
   699  
   700  	if ef.InstallListener != nil {
   701  		ef.InstallListener.HandleChaincodeInstalled(pkg.Metadata, packageID)
   702  	}
   703  
   704  	logger.Infof("Successfully installed chaincode with package ID '%s'", packageID)
   705  
   706  	return &chaincode.InstalledChaincode{
   707  		PackageID: packageID,
   708  		Label:     pkg.Metadata.Label,
   709  	}, nil
   710  }
   711  
   712  func (ef *ExternalFunctions) getBuildLock(packageID string) *sync.Mutex {
   713  	ef.mutex.Lock()
   714  	defer ef.mutex.Unlock()
   715  
   716  	if ef.BuildLocks == nil {
   717  		ef.BuildLocks = map[string]sync.Mutex{}
   718  	}
   719  
   720  	buildLock, ok := ef.BuildLocks[packageID]
   721  	if !ok {
   722  		ef.BuildLocks[packageID] = sync.Mutex{}
   723  	}
   724  
   725  	return &buildLock
   726  }
   727  
   728  // GetInstalledChaincodePackage retrieves the installed chaincode with the given package ID
   729  // from the peer's chaincode store.
   730  func (ef *ExternalFunctions) GetInstalledChaincodePackage(packageID string) ([]byte, error) {
   731  	pkgBytes, err := ef.Resources.ChaincodeStore.Load(packageID)
   732  	if err != nil {
   733  		return nil, errors.WithMessage(err, "could not load cc install package")
   734  	}
   735  
   736  	return pkgBytes, nil
   737  }
   738  
   739  // QueryNamespaceDefinitions lists the publicly defined namespaces in a channel.  Today it should only ever
   740  // find Datatype encodings of 'ChaincodeDefinition'.
   741  func (ef *ExternalFunctions) QueryNamespaceDefinitions(publicState RangeableState) (map[string]string, error) {
   742  	metadatas, err := ef.Resources.Serializer.DeserializeAllMetadata(NamespacesName, publicState)
   743  	if err != nil {
   744  		return nil, errors.WithMessage(err, "could not query namespace metadata")
   745  	}
   746  
   747  	result := map[string]string{}
   748  	for key, value := range metadatas {
   749  		switch value.Datatype {
   750  		case ChaincodeDefinitionType:
   751  			result[key] = FriendlyChaincodeDefinitionType
   752  		default:
   753  			// This should never execute, but seems preferable to returning an error
   754  			result[key] = value.Datatype
   755  		}
   756  	}
   757  	return result, nil
   758  }
   759  
   760  // QueryInstalledChaincode returns metadata for the chaincode with the supplied package ID.
   761  func (ef *ExternalFunctions) QueryInstalledChaincode(packageID string) (*chaincode.InstalledChaincode, error) {
   762  	return ef.InstalledChaincodesLister.GetInstalledChaincode(packageID)
   763  }
   764  
   765  // QueryInstalledChaincodes returns a list of installed chaincodes
   766  func (ef *ExternalFunctions) QueryInstalledChaincodes() []*chaincode.InstalledChaincode {
   767  	return ef.InstalledChaincodesLister.ListInstalledChaincodes()
   768  }