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