github.com/hechain20/hechain@v0.0.0-20220316014945-b544036ba106/core/handlers/validation/builtin/v13/lscc_validation_logic.go (about) 1 /* 2 Copyright hechain. All Rights Reserved. 3 4 SPDX-License-Identifier: Apache-2.0 5 */ 6 7 package v13 8 9 import ( 10 "bytes" 11 "fmt" 12 13 "github.com/golang/protobuf/proto" 14 commonerrors "github.com/hechain20/hechain/common/errors" 15 "github.com/hechain20/hechain/core/common/ccprovider" 16 "github.com/hechain20/hechain/core/common/privdata" 17 vc "github.com/hechain20/hechain/core/handlers/validation/api/capabilities" 18 vs "github.com/hechain20/hechain/core/handlers/validation/api/state" 19 "github.com/hechain20/hechain/core/ledger/kvledger/txmgmt/rwsetutil" 20 "github.com/hechain20/hechain/core/scc/lscc" 21 "github.com/hechain20/hechain/protoutil" 22 "github.com/hyperledger/fabric-protos-go/common" 23 "github.com/hyperledger/fabric-protos-go/ledger/rwset/kvrwset" 24 pb "github.com/hyperledger/fabric-protos-go/peer" 25 "github.com/pkg/errors" 26 ) 27 28 // currently defined system chaincode names that shouldn't 29 // be allowed as user-defined chaincode names 30 var systemChaincodeNames = map[string]struct{}{ 31 "cscc": {}, 32 "escc": {}, 33 "lscc": {}, 34 "qscc": {}, 35 "vscc": {}, 36 } 37 38 // checkInstantiationPolicy evaluates an instantiation policy against a signed proposal 39 func (vscc *Validator) checkInstantiationPolicy(chainName string, env *common.Envelope, instantiationPolicy []byte, payl *common.Payload) commonerrors.TxValidationError { 40 // get the signature header 41 shdr, err := protoutil.UnmarshalSignatureHeader(payl.Header.SignatureHeader) 42 if err != nil { 43 return policyErr(err) 44 } 45 46 // construct signed data we can evaluate the instantiation policy against 47 sd := []*protoutil.SignedData{{ 48 Data: env.Payload, 49 Identity: shdr.Creator, 50 Signature: env.Signature, 51 }} 52 err = vscc.policyEvaluator.Evaluate(instantiationPolicy, sd) 53 if err != nil { 54 return policyErr(fmt.Errorf("chaincode instantiation policy violated, error %s", err)) 55 } 56 return nil 57 } 58 59 func validateNewCollectionConfigs(newCollectionConfigs []*pb.CollectionConfig) error { 60 newCollectionsMap := make(map[string]bool, len(newCollectionConfigs)) 61 // Process each collection config from a set of collection configs 62 for _, newCollectionConfig := range newCollectionConfigs { 63 64 newCollection := newCollectionConfig.GetStaticCollectionConfig() 65 if newCollection == nil { 66 return errors.New("unknown collection configuration type") 67 } 68 69 // Ensure that there are no duplicate collection names 70 collectionName := newCollection.GetName() 71 72 if err := validateCollectionName(collectionName); err != nil { 73 return err 74 } 75 76 if _, ok := newCollectionsMap[collectionName]; !ok { 77 newCollectionsMap[collectionName] = true 78 } else { 79 return fmt.Errorf("collection-name: %s -- found duplicate collection configuration", collectionName) 80 } 81 82 // Validate gossip related parameters present in the collection config 83 maximumPeerCount := newCollection.GetMaximumPeerCount() 84 requiredPeerCount := newCollection.GetRequiredPeerCount() 85 if maximumPeerCount < requiredPeerCount { 86 return fmt.Errorf("collection-name: %s -- maximum peer count (%d) cannot be less than the required peer count (%d)", 87 collectionName, maximumPeerCount, requiredPeerCount) 88 } 89 if requiredPeerCount < 0 { 90 return fmt.Errorf("collection-name: %s -- requiredPeerCount (%d) cannot be less than zero (%d)", 91 collectionName, maximumPeerCount, requiredPeerCount) 92 } 93 94 // make sure that the signature policy is meaningful (only consists of ORs) 95 err := validateSpOrConcat(newCollection.MemberOrgsPolicy.GetSignaturePolicy().Rule) 96 if err != nil { 97 return errors.WithMessagef(err, "collection-name: %s -- error in member org policy", collectionName) 98 } 99 } 100 return nil 101 } 102 103 // validateSpOrConcat checks if the supplied signature policy is just an OR-concatenation of identities 104 func validateSpOrConcat(sp *common.SignaturePolicy) error { 105 if sp.GetNOutOf() == nil { 106 return nil 107 } 108 // check if N == 1 (OR concatenation) 109 if sp.GetNOutOf().N != 1 { 110 return errors.New(fmt.Sprintf("signature policy is not an OR concatenation, NOutOf %d", sp.GetNOutOf().N)) 111 } 112 // recurse into all sub-rules 113 for _, rule := range sp.GetNOutOf().Rules { 114 err := validateSpOrConcat(rule) 115 if err != nil { 116 return err 117 } 118 } 119 return nil 120 } 121 122 func checkForMissingCollections(newCollectionsMap map[string]*pb.StaticCollectionConfig, oldCollectionConfigs []*pb.CollectionConfig, 123 ) error { 124 var missingCollections []string 125 126 // In the new collection config package, ensure that there is one entry per old collection. Any 127 // number of new collections are allowed. 128 for _, oldCollectionConfig := range oldCollectionConfigs { 129 130 oldCollection := oldCollectionConfig.GetStaticCollectionConfig() 131 // It cannot be nil 132 if oldCollection == nil { 133 return policyErr(fmt.Errorf("unknown collection configuration type")) 134 } 135 136 // All old collection must exist in the new collection config package 137 oldCollectionName := oldCollection.GetName() 138 _, ok := newCollectionsMap[oldCollectionName] 139 if !ok { 140 missingCollections = append(missingCollections, oldCollectionName) 141 } 142 } 143 144 if len(missingCollections) > 0 { 145 return policyErr(fmt.Errorf("the following existing collections are missing in the new collection configuration package: %v", 146 missingCollections)) 147 } 148 149 return nil 150 } 151 152 func checkForModifiedCollectionsBTL(newCollectionsMap map[string]*pb.StaticCollectionConfig, oldCollectionConfigs []*pb.CollectionConfig, 153 ) error { 154 var modifiedCollectionsBTL []string 155 156 // In the new collection config package, ensure that the block to live value is not 157 // modified for the existing collections. 158 for _, oldCollectionConfig := range oldCollectionConfigs { 159 160 oldCollection := oldCollectionConfig.GetStaticCollectionConfig() 161 // It cannot be nil 162 if oldCollection == nil { 163 return policyErr(fmt.Errorf("unknown collection configuration type")) 164 } 165 166 oldCollectionName := oldCollection.GetName() 167 newCollection := newCollectionsMap[oldCollectionName] 168 // BlockToLive cannot be changed 169 if newCollection.GetBlockToLive() != oldCollection.GetBlockToLive() { 170 modifiedCollectionsBTL = append(modifiedCollectionsBTL, oldCollectionName) 171 } 172 } 173 174 if len(modifiedCollectionsBTL) > 0 { 175 return policyErr(fmt.Errorf("the BlockToLive in the following existing collections must not be modified: %v", 176 modifiedCollectionsBTL)) 177 } 178 179 return nil 180 } 181 182 func validateNewCollectionConfigsAgainstOld(newCollectionConfigs []*pb.CollectionConfig, oldCollectionConfigs []*pb.CollectionConfig, 183 ) error { 184 newCollectionsMap := make(map[string]*pb.StaticCollectionConfig, len(newCollectionConfigs)) 185 186 for _, newCollectionConfig := range newCollectionConfigs { 187 newCollection := newCollectionConfig.GetStaticCollectionConfig() 188 // Collection object itself is stored as value so that we can 189 // check whether the block to live is changed -- FAB-7810 190 newCollectionsMap[newCollection.GetName()] = newCollection 191 } 192 193 if err := checkForMissingCollections(newCollectionsMap, oldCollectionConfigs); err != nil { 194 return err 195 } 196 197 if err := checkForModifiedCollectionsBTL(newCollectionsMap, oldCollectionConfigs); err != nil { 198 return err 199 } 200 201 return nil 202 } 203 204 func validateCollectionName(collectionName string) error { 205 if collectionName == "" { 206 return fmt.Errorf("empty collection-name is not allowed") 207 } 208 match := validCollectionNameRegex.FindString(collectionName) 209 if len(match) != len(collectionName) { 210 return fmt.Errorf("collection-name: %s not allowed. A valid collection name follows the pattern: %s", 211 collectionName, AllowedCharsCollectionName) 212 } 213 return nil 214 } 215 216 // validateRWSetAndCollection performs validation of the rwset 217 // of an LSCC deploy operation and then it validates any collection 218 // configuration 219 func (vscc *Validator) validateRWSetAndCollection( 220 lsccrwset *kvrwset.KVRWSet, 221 cdRWSet *ccprovider.ChaincodeData, 222 lsccArgs [][]byte, 223 lsccFunc string, 224 ac vc.Capabilities, 225 channelName string, 226 ) commonerrors.TxValidationError { 227 /********************************************/ 228 /* security check 0.a - validation of rwset */ 229 /********************************************/ 230 // there can only be one or two writes 231 if len(lsccrwset.Writes) > 2 { 232 return policyErr(fmt.Errorf("LSCC can only issue one or two putState upon deploy")) 233 } 234 235 /**********************************************************/ 236 /* security check 0.b - validation of the collection data */ 237 /**********************************************************/ 238 var collectionsConfigArg []byte 239 if len(lsccArgs) > 5 { 240 collectionsConfigArg = lsccArgs[5] 241 } 242 243 var collectionsConfigLedger []byte 244 if len(lsccrwset.Writes) == 2 { 245 key := privdata.BuildCollectionKVSKey(cdRWSet.Name) 246 if lsccrwset.Writes[1].Key != key { 247 return policyErr(fmt.Errorf("invalid key for the collection of chaincode %s:%s; expected '%s', received '%s'", 248 cdRWSet.Name, cdRWSet.Version, key, lsccrwset.Writes[1].Key)) 249 } 250 251 collectionsConfigLedger = lsccrwset.Writes[1].Value 252 } 253 254 if !bytes.Equal(collectionsConfigArg, collectionsConfigLedger) { 255 return policyErr(fmt.Errorf("collection configuration arguments supplied for chaincode %s:%s do not match the configuration in the lscc writeset", 256 cdRWSet.Name, cdRWSet.Version)) 257 } 258 259 channelState, err := vscc.stateFetcher.FetchState() 260 if err != nil { 261 return &commonerrors.VSCCExecutionFailureError{Err: fmt.Errorf("failed obtaining query executor: %v", err)} 262 } 263 defer channelState.Done() 264 265 state := &state{channelState} 266 267 // The following condition check added in v1.1 may not be needed as it is not possible to have the chaincodeName~collection key in 268 // the lscc namespace before a chaincode deploy. To avoid forks in v1.2, the following condition is retained. 269 if lsccFunc == lscc.DEPLOY { 270 colCriteria := privdata.CollectionCriteria{Channel: channelName, Namespace: cdRWSet.Name} 271 ccp, err := privdata.RetrieveCollectionConfigPackageFromState(colCriteria, state) 272 if err != nil { 273 // fail if we get any error other than NoSuchCollectionError 274 // because it means something went wrong while looking up the 275 // older collection 276 if _, ok := err.(privdata.NoSuchCollectionError); !ok { 277 return &commonerrors.VSCCExecutionFailureError{ 278 Err: fmt.Errorf("unable to check whether collection existed earlier for chaincode %s:%s", 279 cdRWSet.Name, cdRWSet.Version), 280 } 281 } 282 } 283 if ccp != nil { 284 return policyErr(fmt.Errorf("collection data should not exist for chaincode %s:%s", cdRWSet.Name, cdRWSet.Version)) 285 } 286 } 287 288 // TODO: Once the new chaincode lifecycle is available (FAB-8724), the following validation 289 // and other validation performed in ValidateLSCCInvocation can be moved to LSCC itself. 290 newCollectionConfigPackage := &pb.CollectionConfigPackage{} 291 292 if collectionsConfigArg != nil { 293 err := proto.Unmarshal(collectionsConfigArg, newCollectionConfigPackage) 294 if err != nil { 295 return policyErr(fmt.Errorf("invalid collection configuration supplied for chaincode %s:%s", 296 cdRWSet.Name, cdRWSet.Version)) 297 } 298 } else { 299 return nil 300 } 301 302 if ac.V1_2Validation() { 303 newCollectionConfigs := newCollectionConfigPackage.GetConfig() 304 if err := validateNewCollectionConfigs(newCollectionConfigs); err != nil { 305 return policyErr(err) 306 } 307 308 if lsccFunc == lscc.UPGRADE { 309 310 collectionCriteria := privdata.CollectionCriteria{Channel: channelName, Namespace: cdRWSet.Name} 311 // oldCollectionConfigPackage denotes the existing collection config package in the ledger 312 oldCollectionConfigPackage, err := privdata.RetrieveCollectionConfigPackageFromState(collectionCriteria, state) 313 if err != nil { 314 // fail if we get any error other than NoSuchCollectionError 315 // because it means something went wrong while looking up the 316 // older collection 317 if _, ok := err.(privdata.NoSuchCollectionError); !ok { 318 return &commonerrors.VSCCExecutionFailureError{ 319 Err: fmt.Errorf("unable to check whether collection existed earlier for chaincode %s:%s: %v", 320 cdRWSet.Name, cdRWSet.Version, err), 321 } 322 } 323 } 324 325 // oldCollectionConfigPackage denotes the existing collection config package in the ledger 326 if oldCollectionConfigPackage != nil { 327 oldCollectionConfigs := oldCollectionConfigPackage.GetConfig() 328 if err := validateNewCollectionConfigsAgainstOld(newCollectionConfigs, oldCollectionConfigs); err != nil { 329 return policyErr(err) 330 } 331 332 } 333 } 334 } 335 336 return nil 337 } 338 339 func (vscc *Validator) ValidateLSCCInvocation( 340 chid string, 341 env *common.Envelope, 342 cap *pb.ChaincodeActionPayload, 343 payl *common.Payload, 344 ac vc.Capabilities, 345 ) commonerrors.TxValidationError { 346 cpp, err := protoutil.UnmarshalChaincodeProposalPayload(cap.ChaincodeProposalPayload) 347 if err != nil { 348 logger.Errorf("VSCC error: GetChaincodeProposalPayload failed, err %s", err) 349 return policyErr(err) 350 } 351 352 cis := &pb.ChaincodeInvocationSpec{} 353 err = proto.Unmarshal(cpp.Input, cis) 354 if err != nil { 355 logger.Errorf("VSCC error: Unmarshal ChaincodeInvocationSpec failed, err %s", err) 356 return policyErr(err) 357 } 358 359 if cis.ChaincodeSpec == nil || 360 cis.ChaincodeSpec.Input == nil || 361 cis.ChaincodeSpec.Input.Args == nil { 362 logger.Errorf("VSCC error: committing invalid vscc invocation") 363 return policyErr(fmt.Errorf("malformed chaincode invocation spec")) 364 } 365 366 lsccFunc := string(cis.ChaincodeSpec.Input.Args[0]) 367 lsccArgs := cis.ChaincodeSpec.Input.Args[1:] 368 369 logger.Debugf("VSCC info: ValidateLSCCInvocation acting on %s %#v", lsccFunc, lsccArgs) 370 371 switch lsccFunc { 372 case lscc.UPGRADE, lscc.DEPLOY: 373 logger.Debugf("VSCC info: validating invocation of lscc function %s on arguments %#v", lsccFunc, lsccArgs) 374 375 if len(lsccArgs) < 2 { 376 return policyErr(fmt.Errorf("Wrong number of arguments for invocation lscc(%s): expected at least 2, received %d", lsccFunc, len(lsccArgs))) 377 } 378 379 if (!ac.PrivateChannelData() && len(lsccArgs) > 5) || 380 (ac.PrivateChannelData() && len(lsccArgs) > 6) { 381 return policyErr(fmt.Errorf("Wrong number of arguments for invocation lscc(%s): received %d", lsccFunc, len(lsccArgs))) 382 } 383 384 cdsArgs, err := protoutil.UnmarshalChaincodeDeploymentSpec(lsccArgs[1]) 385 if err != nil { 386 return policyErr(fmt.Errorf("GetChaincodeDeploymentSpec error %s", err)) 387 } 388 389 if cdsArgs == nil || cdsArgs.ChaincodeSpec == nil || cdsArgs.ChaincodeSpec.ChaincodeId == nil || 390 cap.Action == nil || cap.Action.ProposalResponsePayload == nil { 391 return policyErr(fmt.Errorf("VSCC error: invocation of lscc(%s) does not have appropriate arguments", lsccFunc)) 392 } 393 394 switch cdsArgs.ChaincodeSpec.Type.String() { 395 case "GOLANG", "NODE", "JAVA", "CAR": 396 default: 397 return policyErr(fmt.Errorf("unexpected chaincode spec type: %s", cdsArgs.ChaincodeSpec.Type.String())) 398 } 399 400 // validate chaincode name 401 ccName := cdsArgs.ChaincodeSpec.ChaincodeId.Name 402 // it must comply with the lscc.ChaincodeNameRegExp 403 if !lscc.ChaincodeNameRegExp.MatchString(ccName) { 404 return policyErr(errors.Errorf("invalid chaincode name '%s'", ccName)) 405 } 406 407 // it can't match the name of one of the system chaincodes 408 if _, in := systemChaincodeNames[ccName]; in { 409 return policyErr(errors.Errorf("chaincode name '%s' is reserved for system chaincodes", ccName)) 410 } 411 412 // validate chaincode version 413 ccVersion := cdsArgs.ChaincodeSpec.ChaincodeId.Version 414 // it must comply with the lscc.ChaincodeVersionRegExp 415 if !lscc.ChaincodeVersionRegExp.MatchString(ccVersion) { 416 return policyErr(errors.Errorf("invalid chaincode version '%s'", ccVersion)) 417 } 418 419 // get the rwset 420 pRespPayload, err := protoutil.UnmarshalProposalResponsePayload(cap.Action.ProposalResponsePayload) 421 if err != nil { 422 return policyErr(fmt.Errorf("GetProposalResponsePayload error %s", err)) 423 } 424 if pRespPayload.Extension == nil { 425 return policyErr(fmt.Errorf("nil pRespPayload.Extension")) 426 } 427 respPayload, err := protoutil.UnmarshalChaincodeAction(pRespPayload.Extension) 428 if err != nil { 429 return policyErr(fmt.Errorf("GetChaincodeAction error %s", err)) 430 } 431 txRWSet := &rwsetutil.TxRwSet{} 432 if err = txRWSet.FromProtoBytes(respPayload.Results); err != nil { 433 return policyErr(fmt.Errorf("txRWSet.FromProtoBytes error %s", err)) 434 } 435 436 // extract the rwset for lscc 437 var lsccrwset *kvrwset.KVRWSet 438 for _, ns := range txRWSet.NsRwSets { 439 logger.Debugf("Namespace %s", ns.NameSpace) 440 if ns.NameSpace == "lscc" { 441 lsccrwset = ns.KvRwSet 442 break 443 } 444 } 445 446 // retrieve from the ledger the entry for the chaincode at hand 447 cdLedger, ccExistsOnLedger, err := vscc.getInstantiatedCC(chid, cdsArgs.ChaincodeSpec.ChaincodeId.Name) 448 if err != nil { 449 return &commonerrors.VSCCExecutionFailureError{Err: err} 450 } 451 452 /******************************************/ 453 /* security check 0 - validation of rwset */ 454 /******************************************/ 455 // there has to be a write-set 456 if lsccrwset == nil { 457 return policyErr(fmt.Errorf("No read write set for lscc was found")) 458 } 459 // there must be at least one write 460 if len(lsccrwset.Writes) < 1 { 461 return policyErr(fmt.Errorf("LSCC must issue at least one single putState upon deploy/upgrade")) 462 } 463 // the first key name must be the chaincode id provided in the deployment spec 464 if lsccrwset.Writes[0].Key != cdsArgs.ChaincodeSpec.ChaincodeId.Name { 465 return policyErr(fmt.Errorf("expected key %s, found %s", cdsArgs.ChaincodeSpec.ChaincodeId.Name, lsccrwset.Writes[0].Key)) 466 } 467 // the value must be a ChaincodeData struct 468 cdRWSet := &ccprovider.ChaincodeData{} 469 err = proto.Unmarshal(lsccrwset.Writes[0].Value, cdRWSet) 470 if err != nil { 471 return policyErr(fmt.Errorf("unmarhsalling of ChaincodeData failed, error %s", err)) 472 } 473 // the chaincode name in the lsccwriteset must match the chaincode name in the deployment spec 474 if cdRWSet.Name != cdsArgs.ChaincodeSpec.ChaincodeId.Name { 475 return policyErr(fmt.Errorf("expected cc name %s, found %s", cdsArgs.ChaincodeSpec.ChaincodeId.Name, cdRWSet.Name)) 476 } 477 // the chaincode version in the lsccwriteset must match the chaincode version in the deployment spec 478 if cdRWSet.Version != cdsArgs.ChaincodeSpec.ChaincodeId.Version { 479 return policyErr(fmt.Errorf("expected cc version %s, found %s", cdsArgs.ChaincodeSpec.ChaincodeId.Version, cdRWSet.Version)) 480 } 481 // it must only write to 2 namespaces: LSCC's and the cc that we are deploying/upgrading 482 for _, ns := range txRWSet.NsRwSets { 483 if ns.NameSpace != "lscc" && ns.NameSpace != cdRWSet.Name && len(ns.KvRwSet.Writes) > 0 { 484 return policyErr(fmt.Errorf("LSCC invocation is attempting to write to namespace %s", ns.NameSpace)) 485 } 486 } 487 488 logger.Debugf("Validating %s for cc %s version %s", lsccFunc, cdRWSet.Name, cdRWSet.Version) 489 490 switch lsccFunc { 491 case lscc.DEPLOY: 492 493 /******************************************************************/ 494 /* security check 1 - cc not in the LCCC table of instantiated cc */ 495 /******************************************************************/ 496 if ccExistsOnLedger { 497 return policyErr(fmt.Errorf("Chaincode %s is already instantiated", cdsArgs.ChaincodeSpec.ChaincodeId.Name)) 498 } 499 500 /****************************************************************************/ 501 /* security check 2 - validation of rwset (and of collections if enabled) */ 502 /****************************************************************************/ 503 if ac.PrivateChannelData() { 504 // do extra validation for collections 505 err := vscc.validateRWSetAndCollection(lsccrwset, cdRWSet, lsccArgs, lsccFunc, ac, chid) 506 if err != nil { 507 return err 508 } 509 } else { 510 // there can only be a single ledger write 511 if len(lsccrwset.Writes) != 1 { 512 return policyErr(fmt.Errorf("LSCC can only issue a single putState upon deploy")) 513 } 514 } 515 516 /*****************************************************/ 517 /* security check 3 - check the instantiation policy */ 518 /*****************************************************/ 519 pol := cdRWSet.InstantiationPolicy 520 if pol == nil { 521 return policyErr(fmt.Errorf("no instantiation policy was specified")) 522 } 523 // FIXME: could we actually pull the cds package from the 524 // file system to verify whether the policy that is specified 525 // here is the same as the one on disk? 526 // PROS: we prevent attacks where the policy is replaced 527 // CONS: this would be a point of non-determinism 528 err := vscc.checkInstantiationPolicy(chid, env, pol, payl) 529 if err != nil { 530 return err 531 } 532 533 case lscc.UPGRADE: 534 /**************************************************************/ 535 /* security check 1 - cc in the LCCC table of instantiated cc */ 536 /**************************************************************/ 537 if !ccExistsOnLedger { 538 return policyErr(fmt.Errorf("Upgrading non-existent chaincode %s", cdsArgs.ChaincodeSpec.ChaincodeId.Name)) 539 } 540 541 /**********************************************************/ 542 /* security check 2 - existing cc's version was different */ 543 /**********************************************************/ 544 if cdLedger.Version == cdsArgs.ChaincodeSpec.ChaincodeId.Version { 545 return policyErr(fmt.Errorf("Existing version of the cc on the ledger (%s) should be different from the upgraded one", cdsArgs.ChaincodeSpec.ChaincodeId.Version)) 546 } 547 548 /****************************************************************************/ 549 /* security check 3 validation of rwset (and of collections if enabled) */ 550 /****************************************************************************/ 551 // Only in v1.2, a collection can be updated during a chaincode upgrade 552 if ac.V1_2Validation() { 553 // do extra validation for collections 554 err := vscc.validateRWSetAndCollection(lsccrwset, cdRWSet, lsccArgs, lsccFunc, ac, chid) 555 if err != nil { 556 return err 557 } 558 } else { 559 // there can only be a single ledger write 560 if len(lsccrwset.Writes) != 1 { 561 return policyErr(fmt.Errorf("LSCC can only issue a single putState upon upgrade")) 562 } 563 } 564 565 /*****************************************************/ 566 /* security check 4 - check the instantiation policy */ 567 /*****************************************************/ 568 pol := cdLedger.InstantiationPolicy 569 if pol == nil { 570 return policyErr(fmt.Errorf("No instantiation policy was specified")) 571 } 572 // FIXME: could we actually pull the cds package from the 573 // file system to verify whether the policy that is specified 574 // here is the same as the one on disk? 575 // PROS: we prevent attacks where the policy is replaced 576 // CONS: this would be a point of non-determinism 577 err := vscc.checkInstantiationPolicy(chid, env, pol, payl) 578 if err != nil { 579 return err 580 } 581 582 /******************************************************************/ 583 /* security check 5 - check the instantiation policy in the rwset */ 584 /******************************************************************/ 585 if ac.V1_1Validation() { 586 polNew := cdRWSet.InstantiationPolicy 587 if polNew == nil { 588 return policyErr(fmt.Errorf("No instantiation policy was specified")) 589 } 590 591 // no point in checking it again if they are the same policy 592 if !bytes.Equal(polNew, pol) { 593 err = vscc.checkInstantiationPolicy(chid, env, polNew, payl) 594 if err != nil { 595 return err 596 } 597 } 598 } 599 } 600 601 // all is good! 602 return nil 603 default: 604 return policyErr(fmt.Errorf("VSCC error: committing an invocation of function %s of lscc is invalid", lsccFunc)) 605 } 606 } 607 608 func (vscc *Validator) getInstantiatedCC(chid, ccid string) (cd *ccprovider.ChaincodeData, exists bool, err error) { 609 qe, err := vscc.stateFetcher.FetchState() 610 if err != nil { 611 err = fmt.Errorf("could not retrieve QueryExecutor for channel %s, error %s", chid, err) 612 return 613 } 614 defer qe.Done() 615 channelState := &state{qe} 616 bytes, err := channelState.GetState("lscc", ccid) 617 if err != nil { 618 err = fmt.Errorf("could not retrieve state for chaincode %s on channel %s, error %s", ccid, chid, err) 619 return 620 } 621 622 if bytes == nil { 623 return 624 } 625 626 cd = &ccprovider.ChaincodeData{} 627 err = proto.Unmarshal(bytes, cd) 628 if err != nil { 629 err = fmt.Errorf("unmarshalling ChaincodeQueryResponse failed, error %s", err) 630 return 631 } 632 633 exists = true 634 return 635 } 636 637 type state struct { 638 vs.State 639 } 640 641 // GetState retrieves the value for the given key in the given namespace 642 func (s *state) GetState(namespace string, key string) ([]byte, error) { 643 values, err := s.GetStateMultipleKeys(namespace, []string{key}) 644 if err != nil { 645 return nil, err 646 } 647 if len(values) == 0 { 648 return nil, nil 649 } 650 return values[0], nil 651 }