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