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