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 }