github.com/true-sqn/fabric@v2.1.1+incompatible/core/scc/lscc/lscc.go (about) 1 /* 2 Copyright IBM Corp. All Rights Reserved. 3 4 SPDX-License-Identifier: Apache-2.0 5 */ 6 7 package lscc 8 9 import ( 10 "bytes" 11 "fmt" 12 "regexp" 13 "sync" 14 15 "github.com/golang/protobuf/proto" 16 "github.com/hyperledger/fabric-chaincode-go/shim" 17 mb "github.com/hyperledger/fabric-protos-go/msp" 18 pb "github.com/hyperledger/fabric-protos-go/peer" 19 "github.com/hyperledger/fabric/bccsp" 20 "github.com/hyperledger/fabric/common/cauthdsl" 21 "github.com/hyperledger/fabric/common/channelconfig" 22 "github.com/hyperledger/fabric/common/flogging" 23 "github.com/hyperledger/fabric/common/policies" 24 "github.com/hyperledger/fabric/common/policydsl" 25 "github.com/hyperledger/fabric/core/aclmgmt" 26 "github.com/hyperledger/fabric/core/aclmgmt/resources" 27 "github.com/hyperledger/fabric/core/chaincode/lifecycle" 28 "github.com/hyperledger/fabric/core/common/ccprovider" 29 "github.com/hyperledger/fabric/core/common/privdata" 30 "github.com/hyperledger/fabric/core/common/sysccprovider" 31 "github.com/hyperledger/fabric/core/container" 32 "github.com/hyperledger/fabric/core/container/externalbuilder" 33 "github.com/hyperledger/fabric/core/ledger" 34 "github.com/hyperledger/fabric/core/ledger/cceventmgmt" 35 "github.com/hyperledger/fabric/core/peer" 36 "github.com/hyperledger/fabric/core/policy" 37 "github.com/hyperledger/fabric/core/scc" 38 "github.com/hyperledger/fabric/internal/ccmetadata" 39 "github.com/hyperledger/fabric/msp" 40 "github.com/hyperledger/fabric/msp/mgmt" 41 "github.com/hyperledger/fabric/protoutil" 42 "github.com/pkg/errors" 43 ) 44 45 // The lifecycle system chaincode manages chaincodes deployed 46 // on this peer. It manages chaincodes via Invoke proposals. 47 // "Args":["deploy",<ChaincodeDeploymentSpec>] 48 // "Args":["upgrade",<ChaincodeDeploymentSpec>] 49 // "Args":["stop",<ChaincodeInvocationSpec>] 50 // "Args":["start",<ChaincodeInvocationSpec>] 51 52 var ( 53 logger = flogging.MustGetLogger("lscc") 54 // NOTE these regular expressions should stay in sync with those defined in 55 // core/chaincode/lifecycle/scc.go until LSCC has been removed. 56 ChaincodeNameRegExp = regexp.MustCompile("^[a-zA-Z0-9]+([-_][a-zA-Z0-9]+)*$") 57 ChaincodeVersionRegExp = regexp.MustCompile("^[A-Za-z0-9_.+-]+$") 58 ) 59 60 const ( 61 // chaincode lifecycle commands 62 63 // INSTALL install command 64 INSTALL = "install" 65 66 // DEPLOY deploy command 67 DEPLOY = "deploy" 68 69 // UPGRADE upgrade chaincode 70 UPGRADE = "upgrade" 71 72 // CCEXISTS get chaincode 73 CCEXISTS = "getid" 74 75 // CHAINCODEEXISTS get chaincode alias 76 CHAINCODEEXISTS = "ChaincodeExists" 77 78 // GETDEPSPEC get ChaincodeDeploymentSpec 79 GETDEPSPEC = "getdepspec" 80 81 // GETDEPLOYMENTSPEC get ChaincodeDeploymentSpec alias 82 GETDEPLOYMENTSPEC = "GetDeploymentSpec" 83 84 // GETCCDATA get ChaincodeData 85 GETCCDATA = "getccdata" 86 87 // GETCHAINCODEDATA get ChaincodeData alias 88 GETCHAINCODEDATA = "GetChaincodeData" 89 90 // GETCHAINCODES gets the instantiated chaincodes on a channel 91 GETCHAINCODES = "getchaincodes" 92 93 // GETCHAINCODESALIAS gets the instantiated chaincodes on a channel 94 GETCHAINCODESALIAS = "GetChaincodes" 95 96 // GETINSTALLEDCHAINCODES gets the installed chaincodes on a peer 97 GETINSTALLEDCHAINCODES = "getinstalledchaincodes" 98 99 // GETINSTALLEDCHAINCODESALIAS gets the installed chaincodes on a peer 100 GETINSTALLEDCHAINCODESALIAS = "GetInstalledChaincodes" 101 102 // GETCOLLECTIONSCONFIG gets the collections config for a chaincode 103 GETCOLLECTIONSCONFIG = "GetCollectionsConfig" 104 105 // GETCOLLECTIONSCONFIGALIAS gets the collections config for a chaincode 106 GETCOLLECTIONSCONFIGALIAS = "getcollectionsconfig" 107 ) 108 109 // FilesystemSupport contains functions that LSCC requires to execute its tasks 110 type FilesystemSupport interface { 111 // PutChaincodeToLocalStorage stores the supplied chaincode 112 // package to local storage (i.e. the file system) 113 PutChaincodeToLocalStorage(ccprovider.CCPackage) error 114 115 // GetChaincodeFromLocalStorage retrieves the chaincode package 116 // for the requested chaincode, specified by name and version 117 GetChaincodeFromLocalStorage(ccNameVersion string) (ccprovider.CCPackage, error) 118 119 // GetChaincodesFromLocalStorage returns an array of all chaincode 120 // data that have previously been persisted to local storage 121 GetChaincodesFromLocalStorage() (*pb.ChaincodeQueryResponse, error) 122 123 // GetInstantiationPolicy returns the instantiation policy for the 124 // supplied chaincode (or the channel's default if none was specified) 125 GetInstantiationPolicy(channel string, ccpack ccprovider.CCPackage) ([]byte, error) 126 127 // CheckInstantiationPolicy checks whether the supplied signed proposal 128 // complies with the supplied instantiation policy 129 CheckInstantiationPolicy(signedProposal *pb.SignedProposal, chainName string, instantiationPolicy []byte) error 130 } 131 132 type ChaincodeBuilder interface { 133 Build(ccid string) error 134 } 135 136 // MSPsIDGetter is used to get the MSP IDs for a channel. 137 type MSPIDsGetter func(string) []string 138 139 //---------- the LSCC ----------------- 140 141 // SCC implements chaincode lifecycle and policies around it 142 type SCC struct { 143 // aclProvider is responsible for access control evaluation 144 ACLProvider aclmgmt.ACLProvider 145 146 BuiltinSCCs scc.BuiltinSCCs 147 148 // SCCProvider is the interface which is passed into system chaincodes 149 // to access other parts of the system 150 SCCProvider sysccprovider.SystemChaincodeProvider 151 152 // PolicyChecker is the interface used to perform 153 // access control 154 PolicyChecker policy.PolicyChecker 155 156 // Support provides the implementation of several 157 // static functions 158 Support FilesystemSupport 159 160 GetMSPIDs MSPIDsGetter 161 162 BuildRegistry *container.BuildRegistry 163 164 ChaincodeBuilder ChaincodeBuilder 165 166 EbMetadataProvider *externalbuilder.MetadataProvider 167 168 // BCCSP instance 169 BCCSP bccsp.BCCSP 170 171 PackageCache PackageCache 172 } 173 174 // PeerShim adapts the peer instance for use with LSCC by providing methods 175 // previously provided by the scc provider. If the lscc code weren't all getting 176 // deleted soon, it would probably be worth rewriting it to use these APIs directly 177 // rather that go through this shim, but it will be gone soon. 178 type PeerShim struct { 179 Peer *peer.Peer 180 } 181 182 // GetQueryExecutorForLedger returns a query executor for the specified channel 183 func (p *PeerShim) GetQueryExecutorForLedger(cid string) (ledger.QueryExecutor, error) { 184 l := p.Peer.GetLedger(cid) 185 if l == nil { 186 return nil, fmt.Errorf("Could not retrieve ledger for channel %s", cid) 187 } 188 189 return l.NewQueryExecutor() 190 } 191 192 // GetApplicationConfig returns the configtxapplication.SharedConfig for the channel 193 // and whether the Application config exists 194 func (p *PeerShim) GetApplicationConfig(cid string) (channelconfig.Application, bool) { 195 return p.Peer.GetApplicationConfig(cid) 196 } 197 198 // Returns the policy manager associated to the passed channel 199 // and whether the policy manager exists 200 func (p *PeerShim) PolicyManager(channelID string) (policies.Manager, bool) { 201 m := p.Peer.GetPolicyManager(channelID) 202 return m, (m != nil) 203 } 204 205 func (lscc *SCC) Name() string { return "lscc" } 206 func (lscc *SCC) Chaincode() shim.Chaincode { return lscc } 207 208 type PackageCache struct { 209 Mutex sync.RWMutex 210 ValidatedPackages map[string]*ccprovider.ChaincodeData 211 } 212 213 type LegacySecurity struct { 214 Support FilesystemSupport 215 PackageCache *PackageCache 216 } 217 218 func (ls *LegacySecurity) SecurityCheckLegacyChaincode(cd *ccprovider.ChaincodeData) error { 219 ccid := cd.ChaincodeID() 220 221 ls.PackageCache.Mutex.RLock() 222 fsData, ok := ls.PackageCache.ValidatedPackages[ccid] 223 ls.PackageCache.Mutex.RUnlock() 224 225 if !ok { 226 ls.PackageCache.Mutex.Lock() 227 defer ls.PackageCache.Mutex.Unlock() 228 fsData, ok = ls.PackageCache.ValidatedPackages[ccid] 229 if !ok { 230 ccpack, err := ls.Support.GetChaincodeFromLocalStorage(cd.ChaincodeID()) 231 if err != nil { 232 return InvalidDeploymentSpecErr(err.Error()) 233 } 234 235 // This is 'the big security check', though it's no clear what's being accomplished 236 // here. Basically, it seems to try to verify that the chaincode defintion matches 237 // what's on the filesystem, which, might include instanatiation policy, but it's 238 // not obvious from the code, and was being checked separately, so we check it 239 // explicitly below. 240 if err = ccpack.ValidateCC(cd); err != nil { 241 return InvalidCCOnFSError(err.Error()) 242 } 243 244 if ls.PackageCache.ValidatedPackages == nil { 245 ls.PackageCache.ValidatedPackages = map[string]*ccprovider.ChaincodeData{} 246 } 247 248 fsData = ccpack.GetChaincodeData() 249 ls.PackageCache.ValidatedPackages[ccid] = fsData 250 } 251 } 252 253 // we have the info from the fs, check that the policy 254 // matches the one on the file system if one was specified; 255 // this check is required because the admin of this peer 256 // might have specified instantiation policies for their 257 // chaincode, for example to make sure that the chaincode 258 // is only instantiated on certain channels; a malicious 259 // peer on the other hand might have created a deploy 260 // transaction that attempts to bypass the instantiation 261 // policy. This check is there to ensure that this will not 262 // happen, i.e. that the peer will refuse to invoke the 263 // chaincode under these conditions. More info on 264 // https://jira.hyperledger.org/browse/FAB-3156 265 if fsData.InstantiationPolicy != nil { 266 if !bytes.Equal(fsData.InstantiationPolicy, cd.InstantiationPolicy) { 267 return fmt.Errorf("Instantiation policy mismatch for cc %s", cd.ChaincodeID()) 268 } 269 } 270 271 return nil 272 } 273 274 func (lscc *SCC) ChaincodeEndorsementInfo(channelID, chaincodeName string, qe ledger.SimpleQueryExecutor) (*lifecycle.ChaincodeEndorsementInfo, error) { 275 chaincodeDataBytes, err := qe.GetState("lscc", chaincodeName) 276 if err != nil { 277 return nil, errors.Wrapf(err, "could not retrieve state for chaincode %s", chaincodeName) 278 } 279 280 if chaincodeDataBytes == nil { 281 return nil, errors.Errorf("chaincode %s not found", chaincodeName) 282 } 283 284 chaincodeData := &ccprovider.ChaincodeData{} 285 err = proto.Unmarshal(chaincodeDataBytes, chaincodeData) 286 if err != nil { 287 return nil, errors.Wrapf(err, "chaincode %s has bad definition", chaincodeName) 288 } 289 290 ls := &LegacySecurity{ 291 Support: lscc.Support, 292 PackageCache: &lscc.PackageCache, 293 } 294 295 err = ls.SecurityCheckLegacyChaincode(chaincodeData) 296 if err != nil { 297 return nil, errors.WithMessage(err, "failed security checks") 298 } 299 300 return &lifecycle.ChaincodeEndorsementInfo{ 301 Version: chaincodeData.Version, 302 EndorsementPlugin: chaincodeData.Escc, 303 ChaincodeID: chaincodeData.Name + ":" + chaincodeData.Version, 304 }, nil 305 } 306 307 // ValidationInfo returns name&arguments of the validation plugin for the supplied chaincode. 308 // The function returns two types of errors, unexpected errors and validation errors. The 309 // reason for this is that this function is to be called from the validation code, which 310 // needs to tell apart the two types of error to halt processing on the channel if the 311 // unexpected error is not nil and mark the transaction as invalid if the validation error 312 // is not nil. 313 func (lscc *SCC) ValidationInfo(channelID, chaincodeName string, qe ledger.SimpleQueryExecutor) (plugin string, args []byte, unexpectedErr error, validationErr error) { 314 chaincodeDataBytes, err := qe.GetState("lscc", chaincodeName) 315 if err != nil { 316 // failure to access the ledger is clearly an unexpected 317 // error since we expect the ledger to be reachable 318 unexpectedErr = errors.Wrapf(err, "could not retrieve state for chaincode %s", chaincodeName) 319 return 320 } 321 322 if chaincodeDataBytes == nil { 323 // no chaincode definition is a validation error since 324 // we're trying to retrieve chaincode definitions for a non-existent chaincode 325 validationErr = errors.Errorf("chaincode %s not found", chaincodeName) 326 return 327 } 328 329 chaincodeData := &ccprovider.ChaincodeData{} 330 err = proto.Unmarshal(chaincodeDataBytes, chaincodeData) 331 if err != nil { 332 // this kind of data corruption is unexpected since our code 333 // always marshals ChaincodeData into these keys 334 unexpectedErr = errors.Wrapf(err, "chaincode %s has bad definition", chaincodeName) 335 return 336 } 337 338 plugin = chaincodeData.Vscc 339 args = chaincodeData.Policy 340 return 341 } 342 343 //create the chaincode on the given chain 344 func (lscc *SCC) putChaincodeData(stub shim.ChaincodeStubInterface, cd *ccprovider.ChaincodeData) error { 345 cdbytes, err := proto.Marshal(cd) 346 if err != nil { 347 return err 348 } 349 350 if cdbytes == nil { 351 return MarshallErr(cd.Name) 352 } 353 354 err = stub.PutState(cd.Name, cdbytes) 355 356 return err 357 } 358 359 // checkCollectionMemberPolicy checks whether the supplied collection configuration 360 // complies to the given msp configuration and performs semantic validation. 361 // Channel config may change afterwards (i.e., after endorsement or commit of this transaction). 362 // Fabric will deal with the situation where some collection configs are no longer meaningful. 363 // Therefore, the use of channel config for verifying during endorsement is more 364 // towards catching manual errors in the config as oppose to any attempt of serializability. 365 func checkCollectionMemberPolicy(collectionConfig *pb.CollectionConfig, mspmgr msp.MSPManager) error { 366 if mspmgr == nil { 367 return fmt.Errorf("msp manager not set") 368 } 369 msps, err := mspmgr.GetMSPs() 370 if err != nil { 371 return errors.Wrapf(err, "error getting channel msp") 372 } 373 if collectionConfig == nil { 374 return fmt.Errorf("collection configuration is not set") 375 } 376 coll := collectionConfig.GetStaticCollectionConfig() 377 if coll == nil { 378 return fmt.Errorf("collection configuration is empty") 379 } 380 if coll.MemberOrgsPolicy == nil { 381 return fmt.Errorf("collection member policy is not set") 382 } 383 if coll.MemberOrgsPolicy.GetSignaturePolicy() == nil { 384 return fmt.Errorf("collection member org policy is empty") 385 } 386 // make sure that the orgs listed are actually part of the channel 387 // check all principals in the signature policy 388 for _, principal := range coll.MemberOrgsPolicy.GetSignaturePolicy().Identities { 389 found := false 390 var orgID string 391 // the member org policy only supports certain principal types 392 switch principal.PrincipalClassification { 393 394 case mb.MSPPrincipal_ROLE: 395 msprole := &mb.MSPRole{} 396 err := proto.Unmarshal(principal.Principal, msprole) 397 if err != nil { 398 return errors.Wrapf(err, "collection-name: %s -- cannot unmarshal identities", coll.GetName()) 399 } 400 orgID = msprole.MspIdentifier 401 // the msp map is indexed using msp IDs - this behavior is implementation specific, making the following check a bit of a hack 402 for mspid := range msps { 403 if mspid == orgID { 404 found = true 405 break 406 } 407 } 408 409 case mb.MSPPrincipal_ORGANIZATION_UNIT: 410 mspou := &mb.OrganizationUnit{} 411 err := proto.Unmarshal(principal.Principal, mspou) 412 if err != nil { 413 return errors.Wrapf(err, "collection-name: %s -- cannot unmarshal identities", coll.GetName()) 414 } 415 orgID = mspou.MspIdentifier 416 // the msp map is indexed using msp IDs - this behavior is implementation specific, making the following check a bit of a hack 417 for mspid := range msps { 418 if mspid == orgID { 419 found = true 420 break 421 } 422 } 423 424 case mb.MSPPrincipal_IDENTITY: 425 orgID = "identity principal" 426 for _, msp := range msps { 427 _, err := msp.DeserializeIdentity(principal.Principal) 428 if err == nil { 429 found = true 430 break 431 } 432 } 433 default: 434 return fmt.Errorf("collection-name: %s -- principal type %v is not supported", coll.GetName(), principal.PrincipalClassification) 435 } 436 if !found { 437 logger.Warningf("collection-name: %s collection member %s is not part of the channel", coll.GetName(), orgID) 438 } 439 } 440 441 // Call the constructor for SignaturePolicyEnvelope evaluators to perform extra semantic validation. 442 // Among other things, this validation catches any out-of-range references to the identities array. 443 policyProvider := &cauthdsl.EnvelopeBasedPolicyProvider{Deserializer: mspmgr} 444 if _, err := policyProvider.NewPolicy(coll.MemberOrgsPolicy.GetSignaturePolicy()); err != nil { 445 logger.Errorf("Invalid member org policy for collection '%s', error: %s", coll.Name, err) 446 return errors.WithMessage(err, fmt.Sprintf("invalid member org policy for collection '%s'", coll.Name)) 447 } 448 449 return nil 450 } 451 452 // putChaincodeCollectionData adds collection data for the chaincode 453 func (lscc *SCC) putChaincodeCollectionData(stub shim.ChaincodeStubInterface, cd *ccprovider.ChaincodeData, collectionConfigBytes []byte) error { 454 if cd == nil { 455 return errors.New("nil ChaincodeData") 456 } 457 458 if len(collectionConfigBytes) == 0 { 459 logger.Debug("No collection configuration specified") 460 return nil 461 } 462 463 collections := &pb.CollectionConfigPackage{} 464 err := proto.Unmarshal(collectionConfigBytes, collections) 465 if err != nil { 466 return errors.Errorf("invalid collection configuration supplied for chaincode %s:%s", cd.Name, cd.Version) 467 } 468 469 mspmgr := mgmt.GetManagerForChain(stub.GetChannelID()) 470 if mspmgr == nil { 471 return fmt.Errorf("could not get MSP manager for channel %s", stub.GetChannelID()) 472 } 473 for _, collectionConfig := range collections.Config { 474 err = checkCollectionMemberPolicy(collectionConfig, mspmgr) 475 if err != nil { 476 return errors.Wrapf(err, "collection member policy check failed") 477 } 478 } 479 480 key := privdata.BuildCollectionKVSKey(cd.Name) 481 482 err = stub.PutState(key, collectionConfigBytes) 483 if err != nil { 484 return errors.WithMessagef(err, "error putting collection for chaincode %s:%s", cd.Name, cd.Version) 485 } 486 487 return nil 488 } 489 490 // getChaincodeCollectionData retrieve collections config. 491 func (lscc *SCC) getChaincodeCollectionData(stub shim.ChaincodeStubInterface, chaincodeName string) pb.Response { 492 key := privdata.BuildCollectionKVSKey(chaincodeName) 493 collectionsConfigBytes, err := stub.GetState(key) 494 if err != nil { 495 return shim.Error(err.Error()) 496 } 497 if len(collectionsConfigBytes) == 0 { 498 return shim.Error(fmt.Sprintf("collections config not defined for chaincode %s", chaincodeName)) 499 } 500 return shim.Success(collectionsConfigBytes) 501 } 502 503 //checks for existence of chaincode on the given channel 504 func (lscc *SCC) getCCInstance(stub shim.ChaincodeStubInterface, ccname string) ([]byte, error) { 505 cdbytes, err := stub.GetState(ccname) 506 if err != nil { 507 return nil, TXNotFoundErr(err.Error()) 508 } 509 if cdbytes == nil { 510 return nil, NotFoundErr(ccname) 511 } 512 513 return cdbytes, nil 514 } 515 516 //gets the cd out of the bytes 517 func (lscc *SCC) getChaincodeData(ccname string, cdbytes []byte) (*ccprovider.ChaincodeData, error) { 518 cd := &ccprovider.ChaincodeData{} 519 err := proto.Unmarshal(cdbytes, cd) 520 if err != nil { 521 return nil, MarshallErr(ccname) 522 } 523 524 //this should not happen but still a sanity check is not a bad thing 525 if cd.Name != ccname { 526 return nil, ChaincodeMismatchErr(fmt.Sprintf("%s!=%s", ccname, cd.Name)) 527 } 528 529 return cd, nil 530 } 531 532 //checks for existence of chaincode on the given chain 533 func (lscc *SCC) getCCCode(ccname string, cdbytes []byte) (*pb.ChaincodeDeploymentSpec, []byte, error) { 534 cd, err := lscc.getChaincodeData(ccname, cdbytes) 535 if err != nil { 536 return nil, nil, err 537 } 538 539 ccpack, err := lscc.Support.GetChaincodeFromLocalStorage(cd.ChaincodeID()) 540 if err != nil { 541 return nil, nil, InvalidDeploymentSpecErr(err.Error()) 542 } 543 544 //this is the big test and the reason every launch should go through 545 //getChaincode call. We validate the chaincode entry against the 546 //the chaincode in FS 547 if err = ccpack.ValidateCC(cd); err != nil { 548 return nil, nil, InvalidCCOnFSError(err.Error()) 549 } 550 551 //these are guaranteed to be non-nil because we got a valid ccpack 552 depspec := ccpack.GetDepSpec() 553 depspecbytes := ccpack.GetDepSpecBytes() 554 555 return depspec, depspecbytes, nil 556 } 557 558 // getChaincodes returns all chaincodes instantiated on this LSCC's channel 559 func (lscc *SCC) getChaincodes(stub shim.ChaincodeStubInterface) pb.Response { 560 // get all rows from LSCC 561 itr, err := stub.GetStateByRange("", "") 562 563 if err != nil { 564 return shim.Error(err.Error()) 565 } 566 defer itr.Close() 567 568 // array to store metadata for all chaincode entries from LSCC 569 var ccInfoArray []*pb.ChaincodeInfo 570 571 for itr.HasNext() { 572 response, err := itr.Next() 573 if err != nil { 574 return shim.Error(err.Error()) 575 } 576 577 // CollectionConfig isn't ChaincodeData 578 if privdata.IsCollectionConfigKey(response.Key) { 579 continue 580 } 581 582 ccdata := &ccprovider.ChaincodeData{} 583 if err = proto.Unmarshal(response.Value, ccdata); err != nil { 584 return shim.Error(err.Error()) 585 } 586 587 var path string 588 var input string 589 590 // if chaincode is not installed on the system we won't have 591 // data beyond name and version 592 ccpack, err := lscc.Support.GetChaincodeFromLocalStorage(ccdata.ChaincodeID()) 593 if err == nil { 594 path = ccpack.GetDepSpec().GetChaincodeSpec().ChaincodeId.Path 595 input = ccpack.GetDepSpec().GetChaincodeSpec().Input.String() 596 } 597 598 // add this specific chaincode's metadata to the array of all chaincodes 599 ccInfo := &pb.ChaincodeInfo{Name: ccdata.Name, Version: ccdata.Version, Path: path, Input: input, Escc: ccdata.Escc, Vscc: ccdata.Vscc} 600 ccInfoArray = append(ccInfoArray, ccInfo) 601 } 602 // add array with info about all instantiated chaincodes to the query 603 // response proto 604 cqr := &pb.ChaincodeQueryResponse{Chaincodes: ccInfoArray} 605 606 cqrbytes, err := proto.Marshal(cqr) 607 if err != nil { 608 return shim.Error(err.Error()) 609 } 610 611 return shim.Success(cqrbytes) 612 } 613 614 // getInstalledChaincodes returns all chaincodes installed on the peer 615 func (lscc *SCC) getInstalledChaincodes() pb.Response { 616 // get chaincode query response proto which contains information about all 617 // installed chaincodes 618 cqr, err := lscc.Support.GetChaincodesFromLocalStorage() 619 if err != nil { 620 return shim.Error(err.Error()) 621 } 622 623 cqrbytes, err := proto.Marshal(cqr) 624 if err != nil { 625 return shim.Error(err.Error()) 626 } 627 628 return shim.Success(cqrbytes) 629 } 630 631 // check validity of channel name 632 func (lscc *SCC) isValidChannelName(channel string) bool { 633 // TODO we probably need more checks 634 if channel == "" { 635 return false 636 } 637 return true 638 } 639 640 // isValidChaincodeName checks the validity of chaincode name. Chaincode names 641 // should never be blank and should only consist of alphanumerics, '_', and '-' 642 func (lscc *SCC) isValidChaincodeName(chaincodeName string) error { 643 if !ChaincodeNameRegExp.MatchString(chaincodeName) { 644 return InvalidChaincodeNameErr(chaincodeName) 645 } 646 647 return nil 648 } 649 650 // isValidChaincodeVersion checks the validity of chaincode version. Versions 651 // should never be blank and should only consist of alphanumerics, '_', '-', 652 // '+', and '.' 653 func (lscc *SCC) isValidChaincodeVersion(chaincodeName string, version string) error { 654 if !ChaincodeVersionRegExp.MatchString(version) { 655 return InvalidVersionErr(version) 656 } 657 658 return nil 659 } 660 661 func isValidStatedbArtifactsTar(statedbArtifactsTar []byte) error { 662 // Extract the metadata files from the archive 663 // Passing an empty string for the databaseType will validate all artifacts in 664 // the archive 665 archiveFiles, err := ccprovider.ExtractFileEntries(statedbArtifactsTar, "") 666 if err != nil { 667 return err 668 } 669 // iterate through the files and validate 670 for _, archiveDirectoryFiles := range archiveFiles { 671 for _, fileEntry := range archiveDirectoryFiles { 672 indexData := fileEntry.FileContent 673 // Validation is based on the passed file name, e.g. META-INF/statedb/couchdb/indexes/indexname.json 674 err = ccmetadata.ValidateMetadataFile(fileEntry.FileHeader.Name, indexData) 675 if err != nil { 676 return err 677 } 678 } 679 } 680 681 return nil 682 } 683 684 // executeInstall implements the "install" Invoke transaction 685 func (lscc *SCC) executeInstall(stub shim.ChaincodeStubInterface, ccbytes []byte) error { 686 ccpack, err := ccprovider.GetCCPackage(ccbytes, lscc.BCCSP) 687 if err != nil { 688 return err 689 } 690 691 cds := ccpack.GetDepSpec() 692 693 if cds == nil { 694 return fmt.Errorf("nil deployment spec from the CC package") 695 } 696 697 if err = lscc.isValidChaincodeName(cds.ChaincodeSpec.ChaincodeId.Name); err != nil { 698 return err 699 } 700 701 if err = lscc.isValidChaincodeVersion(cds.ChaincodeSpec.ChaincodeId.Name, cds.ChaincodeSpec.ChaincodeId.Version); err != nil { 702 return err 703 } 704 705 if lscc.BuiltinSCCs.IsSysCC(cds.ChaincodeSpec.ChaincodeId.Name) { 706 return errors.Errorf("cannot install: %s is the name of a system chaincode", cds.ChaincodeSpec.ChaincodeId.Name) 707 } 708 709 // We must put the chaincode package on the filesystem prior to building it. 710 // This creates a race for endorsements coming in and executing the chaincode 711 // prior to indexes being installed, but, such is life, and this case is already 712 // present when an already installed chaincode is instantiated. 713 if err = lscc.Support.PutChaincodeToLocalStorage(ccpack); err != nil { 714 return err 715 } 716 717 ccid := ccpack.GetChaincodeData().Name + ":" + ccpack.GetChaincodeData().Version 718 buildStatus, building := lscc.BuildRegistry.BuildStatus(ccid) 719 if !building { 720 err := lscc.ChaincodeBuilder.Build(ccid) 721 buildStatus.Notify(err) 722 } 723 <-buildStatus.Done() 724 if err := buildStatus.Err(); err != nil { 725 return errors.WithMessage(err, "chaincode installed to peer but could not build chaincode") 726 } 727 728 md, err := lscc.EbMetadataProvider.PackageMetadata(ccid) 729 if err != nil { 730 return errors.WithMessage(err, "external builder release metadata found, but could not be packaged") 731 } 732 733 if md == nil { 734 // Get any statedb artifacts from the chaincode package, e.g. couchdb index definitions 735 md, err = ccprovider.ExtractStatedbArtifactsFromCCPackage(ccpack) 736 if err != nil { 737 return err 738 } 739 } 740 741 if err = isValidStatedbArtifactsTar(md); err != nil { 742 return InvalidStatedbArtifactsErr(err.Error()) 743 } 744 745 chaincodeDefinition := &cceventmgmt.ChaincodeDefinition{ 746 Name: ccpack.GetChaincodeData().Name, 747 Version: ccpack.GetChaincodeData().Version, 748 Hash: ccpack.GetId()} // Note - The chaincode 'id' is the hash of chaincode's (CodeHash || MetaDataHash), aka fingerprint 749 750 // HandleChaincodeInstall will apply any statedb artifacts (e.g. couchdb indexes) to 751 // any channel's statedb where the chaincode is already instantiated 752 // Note - this step is done prior to PutChaincodeToLocalStorage() since this step is idempotent and harmless until endorsements start, 753 // that is, if there are errors deploying the indexes the chaincode install can safely be re-attempted later. 754 err = cceventmgmt.GetMgr().HandleChaincodeInstall(chaincodeDefinition, md) 755 defer func() { 756 cceventmgmt.GetMgr().ChaincodeInstallDone(err == nil) 757 }() 758 if err != nil { 759 return err 760 } 761 762 logger.Infof("Installed Chaincode [%s] Version [%s] to peer", ccpack.GetChaincodeData().Name, ccpack.GetChaincodeData().Version) 763 764 return nil 765 } 766 767 // executeDeployOrUpgrade routes the code path either to executeDeploy or executeUpgrade 768 // depending on its function argument 769 func (lscc *SCC) executeDeployOrUpgrade( 770 stub shim.ChaincodeStubInterface, 771 chainname string, 772 cds *pb.ChaincodeDeploymentSpec, 773 policy, escc, vscc, collectionConfigBytes []byte, 774 function string, 775 ) (*ccprovider.ChaincodeData, error) { 776 777 chaincodeName := cds.ChaincodeSpec.ChaincodeId.Name 778 chaincodeVersion := cds.ChaincodeSpec.ChaincodeId.Version 779 780 if err := lscc.isValidChaincodeName(chaincodeName); err != nil { 781 return nil, err 782 } 783 784 if err := lscc.isValidChaincodeVersion(chaincodeName, chaincodeVersion); err != nil { 785 return nil, err 786 } 787 788 chaincodeNameVersion := chaincodeName + ":" + chaincodeVersion 789 790 ccpack, err := lscc.Support.GetChaincodeFromLocalStorage(chaincodeNameVersion) 791 if err != nil { 792 retErrMsg := fmt.Sprintf("cannot get package for chaincode (%s)", chaincodeNameVersion) 793 logger.Errorf("%s-err:%s", retErrMsg, err) 794 return nil, fmt.Errorf("%s", retErrMsg) 795 } 796 cd := ccpack.GetChaincodeData() 797 798 switch function { 799 case DEPLOY: 800 return lscc.executeDeploy(stub, chainname, cds, policy, escc, vscc, cd, ccpack, collectionConfigBytes) 801 case UPGRADE: 802 return lscc.executeUpgrade(stub, chainname, cds, policy, escc, vscc, cd, ccpack, collectionConfigBytes) 803 default: 804 logger.Panicf("Programming error, unexpected function '%s'", function) 805 panic("") // unreachable code 806 } 807 } 808 809 // executeDeploy implements the "instantiate" Invoke transaction 810 func (lscc *SCC) executeDeploy( 811 stub shim.ChaincodeStubInterface, 812 chainname string, 813 cds *pb.ChaincodeDeploymentSpec, 814 policy []byte, 815 escc []byte, 816 vscc []byte, 817 cdfs *ccprovider.ChaincodeData, 818 ccpackfs ccprovider.CCPackage, 819 collectionConfigBytes []byte, 820 ) (*ccprovider.ChaincodeData, error) { 821 //just test for existence of the chaincode in the LSCC 822 chaincodeName := cds.ChaincodeSpec.ChaincodeId.Name 823 _, err := lscc.getCCInstance(stub, chaincodeName) 824 if err == nil { 825 return nil, ExistsErr(chaincodeName) 826 } 827 828 //retain chaincode specific data and fill channel specific ones 829 cdfs.Escc = string(escc) 830 cdfs.Vscc = string(vscc) 831 cdfs.Policy = policy 832 833 // retrieve and evaluate instantiation policy 834 cdfs.InstantiationPolicy, err = lscc.Support.GetInstantiationPolicy(chainname, ccpackfs) 835 if err != nil { 836 return nil, err 837 } 838 // get the signed instantiation proposal 839 signedProp, err := stub.GetSignedProposal() 840 if err != nil { 841 return nil, err 842 } 843 err = lscc.Support.CheckInstantiationPolicy(signedProp, chainname, cdfs.InstantiationPolicy) 844 if err != nil { 845 return nil, err 846 } 847 848 err = lscc.putChaincodeData(stub, cdfs) 849 if err != nil { 850 return nil, err 851 } 852 853 err = lscc.putChaincodeCollectionData(stub, cdfs, collectionConfigBytes) 854 if err != nil { 855 return nil, err 856 } 857 858 return cdfs, nil 859 } 860 861 // executeUpgrade implements the "upgrade" Invoke transaction. 862 func (lscc *SCC) executeUpgrade(stub shim.ChaincodeStubInterface, chainName string, cds *pb.ChaincodeDeploymentSpec, policy []byte, escc []byte, vscc []byte, cdfs *ccprovider.ChaincodeData, ccpackfs ccprovider.CCPackage, collectionConfigBytes []byte) (*ccprovider.ChaincodeData, error) { 863 864 chaincodeName := cds.ChaincodeSpec.ChaincodeId.Name 865 866 // check for existence of chaincode instance only (it has to exist on the channel) 867 // we dont care about the old chaincode on the FS. In particular, user may even 868 // have deleted it 869 cdbytes, _ := lscc.getCCInstance(stub, chaincodeName) 870 if cdbytes == nil { 871 return nil, NotFoundErr(chaincodeName) 872 } 873 874 //we need the cd to compare the version 875 cdLedger, err := lscc.getChaincodeData(chaincodeName, cdbytes) 876 if err != nil { 877 return nil, err 878 } 879 880 //do not upgrade if same version 881 if cdLedger.Version == cds.ChaincodeSpec.ChaincodeId.Version { 882 return nil, IdenticalVersionErr(chaincodeName) 883 } 884 885 //do not upgrade if instantiation policy is violated 886 if cdLedger.InstantiationPolicy == nil { 887 return nil, InstantiationPolicyMissing("") 888 } 889 // get the signed instantiation proposal 890 signedProp, err := stub.GetSignedProposal() 891 if err != nil { 892 return nil, err 893 } 894 err = lscc.Support.CheckInstantiationPolicy(signedProp, chainName, cdLedger.InstantiationPolicy) 895 if err != nil { 896 return nil, err 897 } 898 899 //retain chaincode specific data and fill channel specific ones 900 cdfs.Escc = string(escc) 901 cdfs.Vscc = string(vscc) 902 cdfs.Policy = policy 903 904 // retrieve and evaluate new instantiation policy 905 cdfs.InstantiationPolicy, err = lscc.Support.GetInstantiationPolicy(chainName, ccpackfs) 906 if err != nil { 907 return nil, err 908 } 909 err = lscc.Support.CheckInstantiationPolicy(signedProp, chainName, cdfs.InstantiationPolicy) 910 if err != nil { 911 return nil, err 912 } 913 914 err = lscc.putChaincodeData(stub, cdfs) 915 if err != nil { 916 return nil, err 917 } 918 919 ac, exists := lscc.SCCProvider.GetApplicationConfig(chainName) 920 if !exists { 921 logger.Panicf("programming error, non-existent appplication config for channel '%s'", chainName) 922 } 923 924 if ac.Capabilities().CollectionUpgrade() { 925 err = lscc.putChaincodeCollectionData(stub, cdfs, collectionConfigBytes) 926 if err != nil { 927 return nil, err 928 } 929 } else { 930 if collectionConfigBytes != nil { 931 return nil, errors.New(CollectionsConfigUpgradesNotAllowed("").Error()) 932 } 933 } 934 935 lifecycleEvent := &pb.LifecycleEvent{ChaincodeName: chaincodeName} 936 lifecycleEventBytes := protoutil.MarshalOrPanic(lifecycleEvent) 937 stub.SetEvent(UPGRADE, lifecycleEventBytes) 938 return cdfs, nil 939 } 940 941 //-------------- the chaincode stub interface implementation ---------- 942 943 //Init is mostly useless for SCC 944 func (lscc *SCC) Init(stub shim.ChaincodeStubInterface) pb.Response { 945 return shim.Success(nil) 946 } 947 948 // Invoke implements lifecycle functions "deploy", "start", "stop", "upgrade". 949 // Deploy's arguments - {[]byte("deploy"), []byte(<chainname>), <unmarshalled pb.ChaincodeDeploymentSpec>} 950 // 951 // Invoke also implements some query-like functions 952 // Get chaincode arguments - {[]byte("getid"), []byte(<chainname>), []byte(<chaincodename>)} 953 func (lscc *SCC) Invoke(stub shim.ChaincodeStubInterface) pb.Response { 954 args := stub.GetArgs() 955 if len(args) < 1 { 956 return shim.Error(InvalidArgsLenErr(len(args)).Error()) 957 } 958 959 function := string(args[0]) 960 961 // Handle ACL: 962 // 1. get the signed proposal 963 sp, err := stub.GetSignedProposal() 964 if err != nil { 965 return shim.Error(fmt.Sprintf("Failed retrieving signed proposal on executing %s with error %s", function, err)) 966 } 967 968 switch function { 969 case INSTALL: 970 if len(args) < 2 { 971 return shim.Error(InvalidArgsLenErr(len(args)).Error()) 972 } 973 974 // 2. check install policy 975 if err = lscc.ACLProvider.CheckACL(resources.Lscc_Install, "", sp); err != nil { 976 return shim.Error(fmt.Sprintf("access denied for [%s]: %s", function, err)) 977 } 978 979 depSpec := args[1] 980 981 err := lscc.executeInstall(stub, depSpec) 982 if err != nil { 983 return shim.Error(err.Error()) 984 } 985 return shim.Success([]byte("OK")) 986 case DEPLOY, UPGRADE: 987 // we expect a minimum of 3 arguments, the function 988 // name, the chain name and deployment spec 989 if len(args) < 3 { 990 return shim.Error(InvalidArgsLenErr(len(args)).Error()) 991 } 992 993 // channel the chaincode should be associated with. It 994 // should be created with a register call 995 channel := string(args[1]) 996 997 if !lscc.isValidChannelName(channel) { 998 return shim.Error(InvalidChannelNameErr(channel).Error()) 999 } 1000 1001 ac, exists := lscc.SCCProvider.GetApplicationConfig(channel) 1002 if !exists { 1003 logger.Panicf("programming error, non-existent appplication config for channel '%s'", channel) 1004 } 1005 1006 if ac.Capabilities().LifecycleV20() { 1007 return shim.Error(fmt.Sprintf("Channel '%s' has been migrated to the new lifecycle, LSCC is now read-only", channel)) 1008 } 1009 1010 // the maximum number of arguments depends on the capability of the channel 1011 if !ac.Capabilities().PrivateChannelData() && len(args) > 6 { 1012 return shim.Error(PrivateChannelDataNotAvailable("").Error()) 1013 } 1014 if ac.Capabilities().PrivateChannelData() && len(args) > 7 { 1015 return shim.Error(InvalidArgsLenErr(len(args)).Error()) 1016 } 1017 1018 depSpec := args[2] 1019 cds := &pb.ChaincodeDeploymentSpec{} 1020 err := proto.Unmarshal(depSpec, cds) 1021 if err != nil { 1022 return shim.Error(fmt.Sprintf("error unmarshaling ChaincodeDeploymentSpec: %s", err)) 1023 } 1024 1025 // optional arguments here (they can each be nil and may or may not be present) 1026 // args[3] is a marshalled SignaturePolicyEnvelope representing the endorsement policy 1027 // args[4] is the name of escc 1028 // args[5] is the name of vscc 1029 // args[6] is a marshalled CollectionConfigPackage struct 1030 var EP []byte 1031 if len(args) > 3 && len(args[3]) > 0 { 1032 EP = args[3] 1033 } else { 1034 mspIDs := lscc.GetMSPIDs(channel) 1035 p := policydsl.SignedByAnyMember(mspIDs) 1036 EP, err = protoutil.Marshal(p) 1037 if err != nil { 1038 return shim.Error(err.Error()) 1039 } 1040 } 1041 1042 var escc []byte 1043 if len(args) > 4 && len(args[4]) > 0 { 1044 escc = args[4] 1045 } else { 1046 escc = []byte("escc") 1047 } 1048 1049 var vscc []byte 1050 if len(args) > 5 && len(args[5]) > 0 { 1051 vscc = args[5] 1052 } else { 1053 vscc = []byte("vscc") 1054 } 1055 1056 var collectionsConfig []byte 1057 // we proceed with a non-nil collection configuration only if 1058 // we Support the PrivateChannelData capability 1059 if ac.Capabilities().PrivateChannelData() && len(args) > 6 { 1060 collectionsConfig = args[6] 1061 } 1062 1063 cd, err := lscc.executeDeployOrUpgrade(stub, channel, cds, EP, escc, vscc, collectionsConfig, function) 1064 if err != nil { 1065 return shim.Error(err.Error()) 1066 } 1067 cdbytes, err := proto.Marshal(cd) 1068 if err != nil { 1069 return shim.Error(err.Error()) 1070 } 1071 return shim.Success(cdbytes) 1072 case CCEXISTS, CHAINCODEEXISTS, GETDEPSPEC, GETDEPLOYMENTSPEC, GETCCDATA, GETCHAINCODEDATA: 1073 if len(args) != 3 { 1074 return shim.Error(InvalidArgsLenErr(len(args)).Error()) 1075 } 1076 1077 channel := string(args[1]) 1078 ccname := string(args[2]) 1079 1080 // 2. check policy for ACL resource 1081 var resource string 1082 switch function { 1083 case CCEXISTS, CHAINCODEEXISTS: 1084 resource = resources.Lscc_ChaincodeExists 1085 case GETDEPSPEC, GETDEPLOYMENTSPEC: 1086 resource = resources.Lscc_GetDeploymentSpec 1087 case GETCCDATA, GETCHAINCODEDATA: 1088 resource = resources.Lscc_GetChaincodeData 1089 } 1090 if err = lscc.ACLProvider.CheckACL(resource, channel, sp); err != nil { 1091 return shim.Error(fmt.Sprintf("access denied for [%s][%s]: %s", function, channel, err)) 1092 } 1093 1094 cdbytes, err := lscc.getCCInstance(stub, ccname) 1095 if err != nil { 1096 logger.Errorf("error getting chaincode %s on channel [%s]: %s", ccname, channel, err) 1097 return shim.Error(err.Error()) 1098 } 1099 1100 switch function { 1101 case CCEXISTS, CHAINCODEEXISTS: 1102 cd, err := lscc.getChaincodeData(ccname, cdbytes) 1103 if err != nil { 1104 return shim.Error(err.Error()) 1105 } 1106 return shim.Success([]byte(cd.Name)) 1107 case GETCCDATA, GETCHAINCODEDATA: 1108 return shim.Success(cdbytes) 1109 case GETDEPSPEC, GETDEPLOYMENTSPEC: 1110 _, depspecbytes, err := lscc.getCCCode(ccname, cdbytes) 1111 if err != nil { 1112 return shim.Error(err.Error()) 1113 } 1114 return shim.Success(depspecbytes) 1115 default: 1116 panic("unreachable") 1117 } 1118 case GETCHAINCODES, GETCHAINCODESALIAS: 1119 if len(args) != 1 { 1120 return shim.Error(InvalidArgsLenErr(len(args)).Error()) 1121 } 1122 1123 if err = lscc.ACLProvider.CheckACL(resources.Lscc_GetInstantiatedChaincodes, stub.GetChannelID(), sp); err != nil { 1124 return shim.Error(fmt.Sprintf("access denied for [%s][%s]: %s", function, stub.GetChannelID(), err)) 1125 } 1126 1127 return lscc.getChaincodes(stub) 1128 case GETINSTALLEDCHAINCODES, GETINSTALLEDCHAINCODESALIAS: 1129 if len(args) != 1 { 1130 return shim.Error(InvalidArgsLenErr(len(args)).Error()) 1131 } 1132 1133 // 2. check Lscc_GetInstalledChaincodes policy 1134 if err = lscc.ACLProvider.CheckACL(resources.Lscc_GetInstalledChaincodes, "", sp); err != nil { 1135 return shim.Error(fmt.Sprintf("access denied for [%s]: %s", function, err)) 1136 } 1137 1138 return lscc.getInstalledChaincodes() 1139 case GETCOLLECTIONSCONFIG, GETCOLLECTIONSCONFIGALIAS: 1140 if len(args) != 2 { 1141 return shim.Error(InvalidArgsLenErr(len(args)).Error()) 1142 } 1143 1144 chaincodeName := string(args[1]) 1145 1146 logger.Debugf("GetCollectionsConfig, chaincodeName:%s, start to check ACL for current identity policy", chaincodeName) 1147 if err = lscc.ACLProvider.CheckACL(resources.Lscc_GetCollectionsConfig, stub.GetChannelID(), sp); err != nil { 1148 logger.Debugf("ACL Check Failed for channel:%s, chaincode:%s", stub.GetChannelID(), chaincodeName) 1149 return shim.Error(fmt.Sprintf("access denied for [%s]: %s", function, err)) 1150 } 1151 1152 return lscc.getChaincodeCollectionData(stub, chaincodeName) 1153 } 1154 1155 return shim.Error(InvalidFunctionErr(function).Error()) 1156 }