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