github.com/hechain20/hechain@v0.0.0-20220316014945-b544036ba106/core/chaincode/lifecycle/deployedcc_infoprovider.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 "fmt" 11 "regexp" 12 13 "github.com/hechain20/hechain/common/policydsl" 14 "github.com/hechain20/hechain/common/util" 15 "github.com/hechain20/hechain/core/chaincode/implicitcollection" 16 validationState "github.com/hechain20/hechain/core/handlers/validation/api/state" 17 "github.com/hechain20/hechain/core/ledger" 18 "github.com/hechain20/hechain/core/peer" 19 "github.com/hechain20/hechain/gossip/privdata" 20 "github.com/hechain20/hechain/protoutil" 21 cb "github.com/hyperledger/fabric-protos-go/common" 22 "github.com/hyperledger/fabric-protos-go/ledger/rwset/kvrwset" 23 pb "github.com/hyperledger/fabric-protos-go/peer" 24 25 "github.com/pkg/errors" 26 ) 27 28 //go:generate counterfeiter -o mock/legacy_ccinfo.go --fake-name LegacyDeployedCCInfoProvider . LegacyDeployedCCInfoProvider 29 type LegacyDeployedCCInfoProvider interface { 30 ledger.DeployedChaincodeInfoProvider 31 } 32 33 const ( 34 LifecycleEndorsementPolicyRef = "/Channel/Application/LifecycleEndorsement" 35 ) 36 37 // This is a channel which was created with a lifecycle endorsement policy 38 var LifecycleDefaultEndorsementPolicyBytes = protoutil.MarshalOrPanic(&cb.ApplicationPolicy{ 39 Type: &cb.ApplicationPolicy_ChannelConfigPolicyReference{ 40 ChannelConfigPolicyReference: LifecycleEndorsementPolicyRef, 41 }, 42 }) 43 44 type ValidatorCommitter struct { 45 CoreConfig *peer.Config 46 PrivdataConfig *privdata.PrivdataConfig 47 Resources *Resources 48 LegacyDeployedCCInfoProvider LegacyDeployedCCInfoProvider 49 } 50 51 // Namespaces returns the list of namespaces which are relevant to chaincode lifecycle 52 func (vc *ValidatorCommitter) Namespaces() []string { 53 return append([]string{LifecycleNamespace}, vc.LegacyDeployedCCInfoProvider.Namespaces()...) 54 } 55 56 var SequenceMatcher = regexp.MustCompile("^" + NamespacesName + "/fields/([^/]+)/Sequence$") 57 58 // UpdatedChaincodes returns the chaincodes that are getting updated by the supplied 'stateUpdates' 59 func (vc *ValidatorCommitter) UpdatedChaincodes(stateUpdates map[string][]*kvrwset.KVWrite) ([]*ledger.ChaincodeLifecycleInfo, error) { 60 lifecycleInfo := []*ledger.ChaincodeLifecycleInfo{} 61 62 // If the lifecycle table was updated, report only modified chaincodes 63 lifecycleUpdates := stateUpdates[LifecycleNamespace] 64 65 for _, kvWrite := range lifecycleUpdates { 66 matches := SequenceMatcher.FindStringSubmatch(kvWrite.Key) 67 if len(matches) != 2 { 68 continue 69 } 70 // XXX Note, this may not be a chaincode namespace, handle this later 71 lifecycleInfo = append(lifecycleInfo, &ledger.ChaincodeLifecycleInfo{Name: matches[1]}) 72 } 73 74 legacyUpdates, err := vc.LegacyDeployedCCInfoProvider.UpdatedChaincodes(stateUpdates) 75 if err != nil { 76 return nil, errors.WithMessage(err, "error invoking legacy deployed cc info provider") 77 } 78 79 return append(lifecycleInfo, legacyUpdates...), nil 80 } 81 82 func (vc *ValidatorCommitter) ChaincodeInfo(channelName, chaincodeName string, qe ledger.SimpleQueryExecutor) (*ledger.DeployedChaincodeInfo, error) { 83 exists, definedChaincode, err := vc.Resources.ChaincodeDefinitionIfDefined(chaincodeName, &SimpleQueryExecutorShim{ 84 Namespace: LifecycleNamespace, 85 SimpleQueryExecutor: qe, 86 }) 87 if err != nil { 88 return nil, errors.WithMessage(err, "could not get info about chaincode") 89 } 90 91 if !exists { 92 return vc.LegacyDeployedCCInfoProvider.ChaincodeInfo(channelName, chaincodeName, qe) 93 } 94 95 return &ledger.DeployedChaincodeInfo{ 96 Name: chaincodeName, 97 Version: definedChaincode.EndorsementInfo.Version, 98 Hash: util.ComputeSHA256([]byte(chaincodeName + ":" + definedChaincode.EndorsementInfo.Version)), 99 ExplicitCollectionConfigPkg: definedChaincode.Collections, 100 IsLegacy: false, 101 }, nil 102 } 103 104 // AllChaincodesInfo returns the mapping of chaincode name to DeployedChaincodeInfo for all the deployed chaincodes 105 func (vc *ValidatorCommitter) AllChaincodesInfo(channelName string, sqe ledger.SimpleQueryExecutor) (map[string]*ledger.DeployedChaincodeInfo, error) { 106 sqes := &SimpleQueryExecutorShim{ 107 Namespace: LifecycleNamespace, 108 SimpleQueryExecutor: sqe, 109 } 110 ccQuery := &ExternalFunctions{Resources: vc.Resources} 111 namespaceDefs, err := ccQuery.QueryNamespaceDefinitions(sqes) 112 if err != nil { 113 return nil, err 114 } 115 116 result := make(map[string]*ledger.DeployedChaincodeInfo) 117 for ccName, value := range namespaceDefs { 118 if value != FriendlyChaincodeDefinitionType { 119 continue 120 } 121 deployedccInfo, err := vc.ChaincodeInfo(channelName, ccName, sqe) 122 if err != nil { 123 return nil, err 124 } 125 result[ccName] = deployedccInfo 126 } 127 128 legacyCCs, err := vc.LegacyDeployedCCInfoProvider.AllChaincodesInfo(channelName, sqe) 129 if err != nil { 130 return nil, err 131 } 132 133 for ccName, deployedccInfo := range legacyCCs { 134 if _, ok := result[ccName]; !ok { 135 result[ccName] = deployedccInfo 136 } 137 } 138 139 return result, nil 140 } 141 142 // AllCollectionsConfigPkg implements function in interface ledger.DeployedChaincodeInfoProvider 143 // this implementation returns a combined collection config pkg that contains both explicit and implicit collections 144 func (vc *ValidatorCommitter) AllCollectionsConfigPkg(channelName, chaincodeName string, qe ledger.SimpleQueryExecutor) (*pb.CollectionConfigPackage, error) { 145 chaincodeInfo, err := vc.ChaincodeInfo(channelName, chaincodeName, qe) 146 if err != nil { 147 return nil, err 148 } 149 explicitCollectionConfigPkg := chaincodeInfo.ExplicitCollectionConfigPkg 150 151 if chaincodeInfo.IsLegacy { 152 return explicitCollectionConfigPkg, nil 153 } 154 155 implicitCollections, err := vc.ImplicitCollections(channelName, chaincodeName, qe) 156 if err != nil { 157 return nil, err 158 } 159 160 var combinedColls []*pb.CollectionConfig 161 if explicitCollectionConfigPkg != nil { 162 combinedColls = append(combinedColls, explicitCollectionConfigPkg.Config...) 163 } 164 for _, implicitColl := range implicitCollections { 165 c := &pb.CollectionConfig{} 166 c.Payload = &pb.CollectionConfig_StaticCollectionConfig{StaticCollectionConfig: implicitColl} 167 combinedColls = append(combinedColls, c) 168 } 169 return &pb.CollectionConfigPackage{ 170 Config: combinedColls, 171 }, nil 172 } 173 174 // CollectionInfo implements function in interface ledger.DeployedChaincodeInfoProvider, it returns config for 175 // both static and implicit collections. 176 func (vc *ValidatorCommitter) CollectionInfo(channelName, chaincodeName, collectionName string, qe ledger.SimpleQueryExecutor) (*pb.StaticCollectionConfig, error) { 177 exists, definedChaincode, err := vc.Resources.ChaincodeDefinitionIfDefined(chaincodeName, &SimpleQueryExecutorShim{ 178 Namespace: LifecycleNamespace, 179 SimpleQueryExecutor: qe, 180 }) 181 if err != nil { 182 return nil, errors.WithMessage(err, "could not get chaincode") 183 } 184 185 if !exists { 186 return vc.LegacyDeployedCCInfoProvider.CollectionInfo(channelName, chaincodeName, collectionName, qe) 187 } 188 189 isImplicitCollection, mspID := implicitcollection.MspIDIfImplicitCollection(collectionName) 190 if isImplicitCollection { 191 return vc.GenerateImplicitCollectionForOrg(mspID), nil 192 } 193 194 if definedChaincode.Collections != nil { 195 for _, conf := range definedChaincode.Collections.Config { 196 staticCollConfig := conf.GetStaticCollectionConfig() 197 if staticCollConfig != nil && staticCollConfig.Name == collectionName { 198 return staticCollConfig, nil 199 } 200 } 201 } 202 return nil, nil 203 } 204 205 // ImplicitCollections implements function in interface ledger.DeployedChaincodeInfoProvider. It returns 206 // a slice that contains one proto msg for each of the implicit collections 207 func (vc *ValidatorCommitter) ImplicitCollections(channelName, chaincodeName string, qe ledger.SimpleQueryExecutor) ([]*pb.StaticCollectionConfig, error) { 208 exists, _, err := vc.Resources.ChaincodeDefinitionIfDefined(chaincodeName, &SimpleQueryExecutorShim{ 209 Namespace: LifecycleNamespace, 210 SimpleQueryExecutor: qe, 211 }) 212 if err != nil { 213 return nil, errors.WithMessage(err, "could not get info about chaincode") 214 } 215 216 if !exists { 217 // Implicit collections are a v2.0 lifecycle concept, if the chaincode is not in the new lifecycle, return nothing 218 return nil, nil 219 } 220 221 return vc.ChaincodeImplicitCollections(channelName) 222 } 223 224 // ChaincodeImplicitCollections assumes the chaincode exists in the new lifecycle and returns the implicit collections 225 func (vc *ValidatorCommitter) ChaincodeImplicitCollections(channelName string) ([]*pb.StaticCollectionConfig, error) { 226 channelConfig := vc.Resources.ChannelConfigSource.GetStableChannelConfig(channelName) 227 if channelConfig == nil { 228 return nil, errors.Errorf("could not get channelconfig for channel %s", channelName) 229 } 230 ac, ok := channelConfig.ApplicationConfig() 231 if !ok { 232 return nil, errors.Errorf("could not get application config for channel %s", channelName) 233 } 234 235 orgs := ac.Organizations() 236 implicitCollections := make([]*pb.StaticCollectionConfig, 0, len(orgs)) 237 for _, org := range orgs { 238 implicitCollections = append(implicitCollections, vc.GenerateImplicitCollectionForOrg(org.MSPID())) 239 } 240 241 return implicitCollections, nil 242 } 243 244 // GenerateImplicitCollectionForOrg generates implicit collection for the org 245 func (vc *ValidatorCommitter) GenerateImplicitCollectionForOrg(mspid string) *pb.StaticCollectionConfig { 246 // set Required/MaxPeerCount to 0 if it is other org's implicit collection (mspid does not match peer's local mspid) 247 // set Required/MaxPeerCount to the config values if it is the peer org's implicit collection (mspid matches peer's local mspid) 248 requiredPeerCount := 0 249 maxPeerCount := 0 250 if mspid == vc.CoreConfig.LocalMSPID { 251 requiredPeerCount = vc.PrivdataConfig.ImplicitCollDisseminationPolicy.RequiredPeerCount 252 maxPeerCount = vc.PrivdataConfig.ImplicitCollDisseminationPolicy.MaxPeerCount 253 } 254 return &pb.StaticCollectionConfig{ 255 Name: implicitcollection.NameForOrg(mspid), 256 MemberOrgsPolicy: &pb.CollectionPolicyConfig{ 257 Payload: &pb.CollectionPolicyConfig_SignaturePolicy{ 258 SignaturePolicy: policydsl.SignedByMspMember(mspid), 259 }, 260 }, 261 RequiredPeerCount: int32(requiredPeerCount), 262 MaximumPeerCount: int32(maxPeerCount), 263 } 264 } 265 266 func (vc *ValidatorCommitter) ImplicitCollectionEndorsementPolicyAsBytes(channelID, orgMSPID string) (policy []byte, unexpectedErr, validationErr error) { 267 channelConfig := vc.Resources.ChannelConfigSource.GetStableChannelConfig(channelID) 268 if channelConfig == nil { 269 return nil, errors.Errorf("could not get channel config for channel '%s'", channelID), nil 270 } 271 272 ac, ok := channelConfig.ApplicationConfig() 273 if !ok { 274 return nil, errors.Errorf("could not get application config for channel '%s'", channelID), nil 275 } 276 277 matchedOrgName := "" 278 for orgName, org := range ac.Organizations() { 279 if org.MSPID() == orgMSPID { 280 matchedOrgName = orgName 281 break 282 } 283 } 284 285 if matchedOrgName == "" { 286 return nil, nil, errors.Errorf("no org found in channel with MSPID '%s'", orgMSPID) 287 } 288 289 policyName := fmt.Sprintf("/Channel/Application/%s/Endorsement", matchedOrgName) 290 if _, ok := channelConfig.PolicyManager().GetPolicy(policyName); ok { 291 return protoutil.MarshalOrPanic(&cb.ApplicationPolicy{ 292 Type: &cb.ApplicationPolicy_ChannelConfigPolicyReference{ 293 ChannelConfigPolicyReference: policyName, 294 }, 295 }), nil, nil 296 } 297 298 // This was a channel which was upgraded or did not define an org level endorsement policy, use a default 299 // of "any member of the org" 300 301 return protoutil.MarshalOrPanic(&cb.ApplicationPolicy{ 302 Type: &cb.ApplicationPolicy_SignaturePolicy{ 303 SignaturePolicy: policydsl.SignedByAnyMember([]string{orgMSPID}), 304 }, 305 }), nil, nil 306 } 307 308 // ValidationInfo returns the name and arguments of the validation plugin for the supplied 309 // chaincode. The function returns two types of errors, unexpected errors and validation 310 // errors. The reason for this is that this function is called from the validation code, 311 // which needs to differentiate the two types of error to halt processing on the channel 312 // if the unexpected error is not nil and mark the transaction as invalid if the validation 313 // error is not nil. 314 func (vc *ValidatorCommitter) ValidationInfo(channelID, chaincodeName string, qe ledger.SimpleQueryExecutor) (plugin string, args []byte, unexpectedErr error, validationErr error) { 315 // TODO, this is a bit of an overkill check, and will need to be scaled back for non-chaincode type namespaces 316 exists, definedChaincode, err := vc.Resources.ChaincodeDefinitionIfDefined(chaincodeName, &SimpleQueryExecutorShim{ 317 Namespace: LifecycleNamespace, 318 SimpleQueryExecutor: qe, 319 }) 320 if err != nil { 321 return "", nil, errors.WithMessage(err, "could not get chaincode"), nil 322 } 323 324 if !exists { 325 // TODO, this is inconsistent with how the legacy lifecycle reports 326 // that a missing chaincode is a validation error. But, for now 327 // this is required to make the passthrough work. 328 return "", nil, nil, nil 329 } 330 331 if chaincodeName == LifecycleNamespace { 332 b, err := vc.Resources.LifecycleEndorsementPolicyAsBytes(channelID) 333 if err != nil { 334 return "", nil, errors.WithMessage(err, "unexpected failure to create lifecycle endorsement policy"), nil 335 } 336 return "vscc", b, nil, nil 337 } 338 339 return definedChaincode.ValidationInfo.ValidationPlugin, definedChaincode.ValidationInfo.ValidationParameter, nil, nil 340 } 341 342 // CollectionValidationInfo returns information about collections to the validation component 343 func (vc *ValidatorCommitter) CollectionValidationInfo(channelID, chaincodeName, collectionName string, state validationState.State) (args []byte, unexpectedErr, validationErr error) { 344 exists, definedChaincode, err := vc.Resources.ChaincodeDefinitionIfDefined(chaincodeName, &ValidatorStateShim{ 345 Namespace: LifecycleNamespace, 346 ValidatorState: state, 347 }) 348 if err != nil { 349 return nil, errors.WithMessage(err, "could not get chaincode"), nil 350 } 351 352 if !exists { 353 // TODO, this is inconsistent with how the legacy lifecycle reports 354 // that a missing chaincode is a validation error. But, for now 355 // this is required to make the passthrough work. 356 return nil, nil, nil 357 } 358 359 isImplicitCollection, mspID := implicitcollection.MspIDIfImplicitCollection(collectionName) 360 if isImplicitCollection { 361 return vc.ImplicitCollectionEndorsementPolicyAsBytes(channelID, mspID) 362 } 363 364 if definedChaincode.Collections != nil { 365 for _, conf := range definedChaincode.Collections.Config { 366 staticCollConfig := conf.GetStaticCollectionConfig() 367 if staticCollConfig != nil && staticCollConfig.Name == collectionName { 368 if staticCollConfig.EndorsementPolicy != nil { 369 return protoutil.MarshalOrPanic(staticCollConfig.EndorsementPolicy), nil, nil 370 } 371 // default to chaincode endorsement policy 372 return definedChaincode.ValidationInfo.ValidationParameter, nil, nil 373 } 374 } 375 } 376 377 return nil, nil, errors.Errorf("no such collection '%s'", collectionName) 378 }