github.com/hechain20/hechain@v0.0.0-20220316014945-b544036ba106/core/chaincode/lifecycle/endorsement_info.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  	"github.com/hechain20/hechain/core/ledger"
    11  	"github.com/hechain20/hechain/core/scc"
    12  	"github.com/pkg/errors"
    13  )
    14  
    15  //go:generate counterfeiter -o mock/legacy_lifecycle.go --fake-name LegacyLifecycle . Lifecycle
    16  
    17  // Lifecycle is the interface which the core/chaincode package and core/endorser package requires that lifecycle satisfy.
    18  type Lifecycle interface {
    19  	ChaincodeEndorsementInfo(channelID, chaincodeName string, qe ledger.SimpleQueryExecutor) (*ChaincodeEndorsementInfo, error)
    20  }
    21  
    22  //go:generate counterfeiter -o mock/chaincode_info_cache.go --fake-name ChaincodeInfoCache . ChaincodeInfoCache
    23  type ChaincodeInfoCache interface {
    24  	ChaincodeInfo(channelID, chaincodeName string) (definition *LocalChaincodeInfo, err error)
    25  }
    26  
    27  // ChaincodeEndorsementInfo contains the information necessary to handle a chaincode invoke request.
    28  type ChaincodeEndorsementInfo struct {
    29  	// Version is the version from the definition in this particular channel and namespace context.
    30  	Version string
    31  
    32  	// EnforceInit is set to true for definitions which require the chaincode package to enforce
    33  	// 'init exactly once' semantics.
    34  	EnforceInit bool
    35  
    36  	// ChaincodeID is the name by which to look up or launch the underlying chaincode.
    37  	ChaincodeID string
    38  
    39  	// EndorsementPlugin is the name of the plugin to use when endorsing.
    40  	EndorsementPlugin string
    41  }
    42  
    43  type ChaincodeEndorsementInfoSource struct {
    44  	Resources   *Resources
    45  	Cache       ChaincodeInfoCache
    46  	LegacyImpl  Lifecycle
    47  	BuiltinSCCs scc.BuiltinSCCs
    48  	UserRunsCC  bool
    49  }
    50  
    51  func (cei *ChaincodeEndorsementInfoSource) CachedChaincodeInfo(channelID, chaincodeName string, qe ledger.SimpleQueryExecutor) (*LocalChaincodeInfo, bool, error) {
    52  	var qes ReadableState = &SimpleQueryExecutorShim{
    53  		Namespace:           LifecycleNamespace,
    54  		SimpleQueryExecutor: qe,
    55  	}
    56  
    57  	if qe == nil {
    58  		// NOTE: the core/chaincode package inconsistently sets the
    59  		// query executor depending on whether the call has a channel
    60  		// context or not. We use this dummy shim which always returns
    61  		// an error for GetState calls to avoid a peer panic.
    62  		qes = &DummyQueryExecutorShim{}
    63  	}
    64  
    65  	currentSequence, err := cei.Resources.Serializer.DeserializeFieldAsInt64(NamespacesName, chaincodeName, "Sequence", qes)
    66  	if err != nil {
    67  		return nil, false, errors.WithMessagef(err, "could not get current sequence for chaincode '%s' on channel '%s'", chaincodeName, channelID)
    68  	}
    69  
    70  	// Committed sequences begin at 1
    71  	if currentSequence == 0 {
    72  		return nil, false, nil
    73  	}
    74  
    75  	chaincodeInfo, err := cei.Cache.ChaincodeInfo(channelID, chaincodeName)
    76  	if err != nil {
    77  		return nil, false, errors.WithMessage(err, "could not get approved chaincode info from cache")
    78  	}
    79  
    80  	if chaincodeInfo.Definition.Sequence != currentSequence {
    81  		// TODO this is a transient error which indicates that this query executor is executing against a chaincode
    82  		// whose definition has already changed (the cache may be ahead of the committed state, but never behind).  In this
    83  		// case, we should simply abort the tx, and re-acquire a query executor and re-execute.  There is no reason this
    84  		// error needs to be returned to the client.
    85  		return nil, false, errors.Errorf("chaincode cache at sequence %d but current sequence is %d, chaincode definition for '%s' changed during invoke", chaincodeInfo.Definition.Sequence, currentSequence, chaincodeName)
    86  	}
    87  
    88  	if !chaincodeInfo.Approved {
    89  		return nil, false, errors.Errorf("chaincode definition for '%s' at sequence %d on channel '%s' has not yet been approved by this org", chaincodeName, currentSequence, channelID)
    90  	}
    91  
    92  	if chaincodeInfo.InstallInfo == nil {
    93  		if cei.UserRunsCC {
    94  			chaincodeInfo.InstallInfo = &ChaincodeInstallInfo{
    95  				PackageID: chaincodeName + ":" + chaincodeInfo.Definition.EndorsementInfo.Version,
    96  			}
    97  			return chaincodeInfo, true, nil
    98  		}
    99  		return nil, false, errors.Errorf("chaincode definition for '%s' exists, but chaincode is not installed", chaincodeName)
   100  	}
   101  
   102  	return chaincodeInfo, true, nil
   103  }
   104  
   105  // ChaincodeEndorsementInfo returns the information necessary to handle a chaincode invocation request, as well as a function to
   106  // enforce security checks on the chaincode (in case the definition is from the legacy lscc).
   107  func (cei *ChaincodeEndorsementInfoSource) ChaincodeEndorsementInfo(channelID, chaincodeName string, qe ledger.SimpleQueryExecutor) (*ChaincodeEndorsementInfo, error) {
   108  	if cei.BuiltinSCCs.IsSysCC(chaincodeName) {
   109  		return &ChaincodeEndorsementInfo{
   110  			Version:           scc.SysCCVersion,
   111  			EndorsementPlugin: "escc",
   112  			EnforceInit:       false,
   113  			ChaincodeID:       scc.ChaincodeID(chaincodeName),
   114  		}, nil
   115  	}
   116  
   117  	// return legacy cc endorsement info if V20 is not enabled
   118  	channelConfig := cei.Resources.ChannelConfigSource.GetStableChannelConfig(channelID)
   119  	if channelConfig == nil {
   120  		return nil, errors.Errorf("could not get channel config for channel '%s'", channelID)
   121  	}
   122  	ac, ok := channelConfig.ApplicationConfig()
   123  	if !ok {
   124  		return nil, errors.Errorf("could not get application config for channel '%s'", channelID)
   125  	}
   126  	if !ac.Capabilities().LifecycleV20() {
   127  		return cei.LegacyImpl.ChaincodeEndorsementInfo(channelID, chaincodeName, qe)
   128  	}
   129  
   130  	chaincodeInfo, ok, err := cei.CachedChaincodeInfo(channelID, chaincodeName, qe)
   131  	if err != nil {
   132  		return nil, err
   133  	}
   134  	if !ok {
   135  		return cei.LegacyImpl.ChaincodeEndorsementInfo(channelID, chaincodeName, qe)
   136  	}
   137  
   138  	if chaincodeInfo.InstallInfo == nil {
   139  		chaincodeInfo.InstallInfo = &ChaincodeInstallInfo{}
   140  	}
   141  
   142  	return &ChaincodeEndorsementInfo{
   143  		Version:           chaincodeInfo.Definition.EndorsementInfo.Version,
   144  		EnforceInit:       chaincodeInfo.Definition.EndorsementInfo.InitRequired,
   145  		EndorsementPlugin: chaincodeInfo.Definition.EndorsementInfo.EndorsementPlugin,
   146  		ChaincodeID:       chaincodeInfo.InstallInfo.PackageID, // Local packages use package ID for ccid
   147  	}, nil
   148  }