github.com/hechain20/hechain@v0.0.0-20220316014945-b544036ba106/core/scc/lscc/lscc.go (about) 1 /* 2 Copyright hechain. 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/hechain20/hechain/bccsp" 17 "github.com/hechain20/hechain/common/cauthdsl" 18 "github.com/hechain20/hechain/common/channelconfig" 19 "github.com/hechain20/hechain/common/flogging" 20 "github.com/hechain20/hechain/common/policies" 21 "github.com/hechain20/hechain/common/policydsl" 22 "github.com/hechain20/hechain/core/aclmgmt" 23 "github.com/hechain20/hechain/core/aclmgmt/resources" 24 "github.com/hechain20/hechain/core/chaincode/lifecycle" 25 "github.com/hechain20/hechain/core/common/ccprovider" 26 "github.com/hechain20/hechain/core/common/privdata" 27 "github.com/hechain20/hechain/core/common/sysccprovider" 28 "github.com/hechain20/hechain/core/container" 29 "github.com/hechain20/hechain/core/container/externalbuilder" 30 "github.com/hechain20/hechain/core/ledger" 31 "github.com/hechain20/hechain/core/ledger/cceventmgmt" 32 "github.com/hechain20/hechain/core/peer" 33 "github.com/hechain20/hechain/core/scc" 34 "github.com/hechain20/hechain/internal/ccmetadata" 35 "github.com/hechain20/hechain/msp" 36 "github.com/hechain20/hechain/protoutil" 37 "github.com/hyperledger/fabric-chaincode-go/shim" 38 mb "github.com/hyperledger/fabric-protos-go/msp" 39 pb "github.com/hyperledger/fabric-protos-go/peer" 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 // IDMSPManagerGetters used to get the MSP Manager for a channel. 138 type MSPManagerGetter func(string) msp.MSPManager 139 140 //---------- the LSCC ----------------- 141 142 // SCC implements chaincode lifecycle and policies around it 143 type SCC struct { 144 // aclProvider is responsible for access control evaluation 145 ACLProvider aclmgmt.ACLProvider 146 147 BuiltinSCCs scc.BuiltinSCCs 148 149 // SCCProvider is the interface which is passed into system chaincodes 150 // to access other parts of the system 151 SCCProvider sysccprovider.SystemChaincodeProvider 152 153 // Support provides the implementation of several 154 // static functions 155 Support FilesystemSupport 156 157 GetMSPIDs MSPIDsGetter 158 159 GetMSPManager MSPManagerGetter 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 definition matches 236 // what's on the filesystem, which, might include instantiation 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 := lscc.GetMSPManager(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 if err != nil { 562 return shim.Error(err.Error()) 563 } 564 defer itr.Close() 565 566 // array to store metadata for all chaincode entries from LSCC 567 var ccInfoArray []*pb.ChaincodeInfo 568 569 for itr.HasNext() { 570 response, err := itr.Next() 571 if err != nil { 572 return shim.Error(err.Error()) 573 } 574 575 // CollectionConfig isn't ChaincodeData 576 if privdata.IsCollectionConfigKey(response.Key) { 577 continue 578 } 579 580 ccdata := &ccprovider.ChaincodeData{} 581 if err = proto.Unmarshal(response.Value, ccdata); err != nil { 582 return shim.Error(err.Error()) 583 } 584 585 var path string 586 var input string 587 588 // if chaincode is not installed on the system we won't have 589 // data beyond name and version 590 ccpack, err := lscc.Support.GetChaincodeFromLocalStorage(ccdata.ChaincodeID()) 591 if err == nil { 592 path = ccpack.GetDepSpec().GetChaincodeSpec().ChaincodeId.Path 593 input = ccpack.GetDepSpec().GetChaincodeSpec().Input.String() 594 } 595 596 // add this specific chaincode's metadata to the array of all chaincodes 597 ccInfo := &pb.ChaincodeInfo{Name: ccdata.Name, Version: ccdata.Version, Path: path, Input: input, Escc: ccdata.Escc, Vscc: ccdata.Vscc} 598 ccInfoArray = append(ccInfoArray, ccInfo) 599 } 600 // add array with info about all instantiated chaincodes to the query 601 // response proto 602 cqr := &pb.ChaincodeQueryResponse{Chaincodes: ccInfoArray} 603 604 cqrbytes, err := proto.Marshal(cqr) 605 if err != nil { 606 return shim.Error(err.Error()) 607 } 608 609 return shim.Success(cqrbytes) 610 } 611 612 // getInstalledChaincodes returns all chaincodes installed on the peer 613 func (lscc *SCC) getInstalledChaincodes() pb.Response { 614 // get chaincode query response proto which contains information about all 615 // installed chaincodes 616 cqr, err := lscc.Support.GetChaincodesFromLocalStorage() 617 if err != nil { 618 return shim.Error(err.Error()) 619 } 620 621 cqrbytes, err := proto.Marshal(cqr) 622 if err != nil { 623 return shim.Error(err.Error()) 624 } 625 626 return shim.Success(cqrbytes) 627 } 628 629 // check validity of channel name 630 func (lscc *SCC) isValidChannelName(channel string) bool { 631 // TODO we probably need more checks 632 return channel != "" 633 } 634 635 // isValidChaincodeName checks the validity of chaincode name. Chaincode names 636 // should never be blank and should only consist of alphanumerics, '_', and '-' 637 func (lscc *SCC) isValidChaincodeName(chaincodeName string) error { 638 if !ChaincodeNameRegExp.MatchString(chaincodeName) { 639 return InvalidChaincodeNameErr(chaincodeName) 640 } 641 642 return nil 643 } 644 645 // isValidChaincodeVersion checks the validity of chaincode version. Versions 646 // should never be blank and should only consist of alphanumerics, '_', '-', 647 // '+', and '.' 648 func (lscc *SCC) isValidChaincodeVersion(chaincodeName string, version string) error { 649 if !ChaincodeVersionRegExp.MatchString(version) { 650 return InvalidVersionErr(version) 651 } 652 653 return nil 654 } 655 656 func isValidStatedbArtifactsTar(statedbArtifactsTar []byte) error { 657 // Extract the metadata files from the archive 658 // Passing an empty string for the databaseType will validate all artifacts in 659 // the archive 660 archiveFiles, err := ccprovider.ExtractFileEntries(statedbArtifactsTar, "") 661 if err != nil { 662 return err 663 } 664 // iterate through the files and validate 665 for _, archiveDirectoryFiles := range archiveFiles { 666 for _, fileEntry := range archiveDirectoryFiles { 667 indexData := fileEntry.FileContent 668 // Validation is based on the passed file name, e.g. META-INF/statedb/couchdb/indexes/indexname.json 669 err = ccmetadata.ValidateMetadataFile(fileEntry.FileHeader.Name, indexData) 670 if err != nil { 671 return err 672 } 673 } 674 } 675 676 return nil 677 } 678 679 // executeInstall implements the "install" Invoke transaction 680 func (lscc *SCC) executeInstall(stub shim.ChaincodeStubInterface, ccbytes []byte) error { 681 ccpack, err := ccprovider.GetCCPackage(ccbytes, lscc.BCCSP) 682 if err != nil { 683 return err 684 } 685 686 cds := ccpack.GetDepSpec() 687 688 if cds == nil { 689 return fmt.Errorf("nil deployment spec from the CC package") 690 } 691 692 if err = lscc.isValidChaincodeName(cds.ChaincodeSpec.ChaincodeId.Name); err != nil { 693 return err 694 } 695 696 if err = lscc.isValidChaincodeVersion(cds.ChaincodeSpec.ChaincodeId.Name, cds.ChaincodeSpec.ChaincodeId.Version); err != nil { 697 return err 698 } 699 700 if lscc.BuiltinSCCs.IsSysCC(cds.ChaincodeSpec.ChaincodeId.Name) { 701 return errors.Errorf("cannot install: %s is the name of a system chaincode", cds.ChaincodeSpec.ChaincodeId.Name) 702 } 703 704 // We must put the chaincode package on the filesystem prior to building it. 705 // This creates a race for endorsements coming in and executing the chaincode 706 // prior to indexes being installed, but, such is life, and this case is already 707 // present when an already installed chaincode is instantiated. 708 if err = lscc.Support.PutChaincodeToLocalStorage(ccpack); err != nil { 709 return err 710 } 711 712 ccid := ccpack.GetChaincodeData().Name + ":" + ccpack.GetChaincodeData().Version 713 buildStatus, building := lscc.BuildRegistry.BuildStatus(ccid) 714 if !building { 715 err := lscc.ChaincodeBuilder.Build(ccid) 716 buildStatus.Notify(err) 717 } 718 <-buildStatus.Done() 719 if err := buildStatus.Err(); err != nil { 720 return errors.WithMessage(err, "chaincode installed to peer but could not build chaincode") 721 } 722 723 md, err := lscc.EbMetadataProvider.PackageMetadata(ccid) 724 if err != nil { 725 return errors.WithMessage(err, "external builder release metadata found, but could not be packaged") 726 } 727 728 if md == nil { 729 // Get any statedb artifacts from the chaincode package, e.g. couchdb index definitions 730 md, err = ccprovider.ExtractStatedbArtifactsFromCCPackage(ccpack) 731 if err != nil { 732 return err 733 } 734 } 735 736 if err = isValidStatedbArtifactsTar(md); err != nil { 737 return InvalidStatedbArtifactsErr(err.Error()) 738 } 739 740 chaincodeDefinition := &cceventmgmt.ChaincodeDefinition{ 741 Name: ccpack.GetChaincodeData().Name, 742 Version: ccpack.GetChaincodeData().Version, 743 Hash: ccpack.GetId(), 744 } // Note - The chaincode 'id' is the hash of chaincode's (CodeHash || MetaDataHash), aka fingerprint 745 746 // HandleChaincodeInstall will apply any statedb artifacts (e.g. couchdb indexes) to 747 // any channel's statedb where the chaincode is already instantiated 748 // Note - this step is done prior to PutChaincodeToLocalStorage() since this step is idempotent and harmless until endorsements start, 749 // that is, if there are errors deploying the indexes the chaincode install can safely be re-attempted later. 750 err = cceventmgmt.GetMgr().HandleChaincodeInstall(chaincodeDefinition, md) 751 defer func() { 752 cceventmgmt.GetMgr().ChaincodeInstallDone(err == nil) 753 }() 754 if err != nil { 755 return err 756 } 757 758 logger.Infof("Installed Chaincode [%s] Version [%s] to peer", ccpack.GetChaincodeData().Name, ccpack.GetChaincodeData().Version) 759 760 return nil 761 } 762 763 // executeDeployOrUpgrade routes the code path either to executeDeploy or executeUpgrade 764 // depending on its function argument 765 func (lscc *SCC) executeDeployOrUpgrade( 766 stub shim.ChaincodeStubInterface, 767 chainname string, 768 cds *pb.ChaincodeDeploymentSpec, 769 policy, escc, vscc, collectionConfigBytes []byte, 770 function string, 771 ) (*ccprovider.ChaincodeData, error) { 772 chaincodeName := cds.ChaincodeSpec.ChaincodeId.Name 773 chaincodeVersion := cds.ChaincodeSpec.ChaincodeId.Version 774 775 if err := lscc.isValidChaincodeName(chaincodeName); err != nil { 776 return nil, err 777 } 778 779 if err := lscc.isValidChaincodeVersion(chaincodeName, chaincodeVersion); err != nil { 780 return nil, err 781 } 782 783 chaincodeNameVersion := chaincodeName + ":" + chaincodeVersion 784 785 ccpack, err := lscc.Support.GetChaincodeFromLocalStorage(chaincodeNameVersion) 786 if err != nil { 787 retErrMsg := fmt.Sprintf("cannot get package for chaincode (%s)", chaincodeNameVersion) 788 logger.Errorf("%s-err:%s", retErrMsg, err) 789 return nil, fmt.Errorf("%s", retErrMsg) 790 } 791 cd := ccpack.GetChaincodeData() 792 793 switch function { 794 case DEPLOY: 795 return lscc.executeDeploy(stub, chainname, cds, policy, escc, vscc, cd, ccpack, collectionConfigBytes) 796 case UPGRADE: 797 return lscc.executeUpgrade(stub, chainname, cds, policy, escc, vscc, cd, ccpack, collectionConfigBytes) 798 default: 799 logger.Panicf("Programming error, unexpected function '%s'", function) 800 panic("") // unreachable code 801 } 802 } 803 804 // executeDeploy implements the "instantiate" Invoke transaction 805 func (lscc *SCC) executeDeploy( 806 stub shim.ChaincodeStubInterface, 807 chainname string, 808 cds *pb.ChaincodeDeploymentSpec, 809 policy []byte, 810 escc []byte, 811 vscc []byte, 812 cdfs *ccprovider.ChaincodeData, 813 ccpackfs ccprovider.CCPackage, 814 collectionConfigBytes []byte, 815 ) (*ccprovider.ChaincodeData, error) { 816 // just test for existence of the chaincode in the LSCC 817 chaincodeName := cds.ChaincodeSpec.ChaincodeId.Name 818 _, err := lscc.getCCInstance(stub, chaincodeName) 819 if err == nil { 820 return nil, ExistsErr(chaincodeName) 821 } 822 823 // retain chaincode specific data and fill channel specific ones 824 cdfs.Escc = string(escc) 825 cdfs.Vscc = string(vscc) 826 cdfs.Policy = policy 827 828 // retrieve and evaluate instantiation policy 829 cdfs.InstantiationPolicy, err = lscc.Support.GetInstantiationPolicy(chainname, ccpackfs) 830 if err != nil { 831 return nil, err 832 } 833 // get the signed instantiation proposal 834 signedProp, err := stub.GetSignedProposal() 835 if err != nil { 836 return nil, err 837 } 838 err = lscc.Support.CheckInstantiationPolicy(signedProp, chainname, cdfs.InstantiationPolicy) 839 if err != nil { 840 return nil, err 841 } 842 843 err = lscc.putChaincodeData(stub, cdfs) 844 if err != nil { 845 return nil, err 846 } 847 848 err = lscc.putChaincodeCollectionData(stub, cdfs, collectionConfigBytes) 849 if err != nil { 850 return nil, err 851 } 852 853 return cdfs, nil 854 } 855 856 // executeUpgrade implements the "upgrade" Invoke transaction. 857 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) { 858 chaincodeName := cds.ChaincodeSpec.ChaincodeId.Name 859 860 // check for existence of chaincode instance only (it has to exist on the channel) 861 // we dont care about the old chaincode on the FS. In particular, user may even 862 // have deleted it 863 cdbytes, _ := lscc.getCCInstance(stub, chaincodeName) 864 if cdbytes == nil { 865 return nil, NotFoundErr(chaincodeName) 866 } 867 868 // we need the cd to compare the version 869 cdLedger, err := lscc.getChaincodeData(chaincodeName, cdbytes) 870 if err != nil { 871 return nil, err 872 } 873 874 // do not upgrade if same version 875 if cdLedger.Version == cds.ChaincodeSpec.ChaincodeId.Version { 876 return nil, IdenticalVersionErr(chaincodeName) 877 } 878 879 // do not upgrade if instantiation policy is violated 880 if cdLedger.InstantiationPolicy == nil { 881 return nil, InstantiationPolicyMissing("") 882 } 883 // get the signed instantiation proposal 884 signedProp, err := stub.GetSignedProposal() 885 if err != nil { 886 return nil, err 887 } 888 err = lscc.Support.CheckInstantiationPolicy(signedProp, chainName, cdLedger.InstantiationPolicy) 889 if err != nil { 890 return nil, err 891 } 892 893 // retain chaincode specific data and fill channel specific ones 894 cdfs.Escc = string(escc) 895 cdfs.Vscc = string(vscc) 896 cdfs.Policy = policy 897 898 // retrieve and evaluate new instantiation policy 899 cdfs.InstantiationPolicy, err = lscc.Support.GetInstantiationPolicy(chainName, ccpackfs) 900 if err != nil { 901 return nil, err 902 } 903 err = lscc.Support.CheckInstantiationPolicy(signedProp, chainName, cdfs.InstantiationPolicy) 904 if err != nil { 905 return nil, err 906 } 907 908 err = lscc.putChaincodeData(stub, cdfs) 909 if err != nil { 910 return nil, err 911 } 912 913 ac, exists := lscc.SCCProvider.GetApplicationConfig(chainName) 914 if !exists { 915 logger.Panicf("programming error, non-existent appplication config for channel '%s'", chainName) 916 } 917 918 if ac.Capabilities().CollectionUpgrade() { 919 err = lscc.putChaincodeCollectionData(stub, cdfs, collectionConfigBytes) 920 if err != nil { 921 return nil, err 922 } 923 } else { 924 if collectionConfigBytes != nil { 925 return nil, errors.New(CollectionsConfigUpgradesNotAllowed("").Error()) 926 } 927 } 928 929 lifecycleEvent := &pb.LifecycleEvent{ChaincodeName: chaincodeName} 930 lifecycleEventBytes := protoutil.MarshalOrPanic(lifecycleEvent) 931 stub.SetEvent(UPGRADE, lifecycleEventBytes) 932 return cdfs, nil 933 } 934 935 //-------------- the chaincode stub interface implementation ---------- 936 937 // Init is mostly useless for SCC 938 func (lscc *SCC) Init(stub shim.ChaincodeStubInterface) pb.Response { 939 return shim.Success(nil) 940 } 941 942 // Invoke implements lifecycle functions "deploy", "start", "stop", "upgrade". 943 // Deploy's arguments - {[]byte("deploy"), []byte(<chainname>), <unmarshalled pb.ChaincodeDeploymentSpec>} 944 // 945 // Invoke also implements some query-like functions 946 // Get chaincode arguments - {[]byte("getid"), []byte(<chainname>), []byte(<chaincodename>)} 947 func (lscc *SCC) Invoke(stub shim.ChaincodeStubInterface) pb.Response { 948 args := stub.GetArgs() 949 if len(args) < 1 { 950 return shim.Error(InvalidArgsLenErr(len(args)).Error()) 951 } 952 953 function := string(args[0]) 954 955 // Handle ACL: 956 // 1. get the signed proposal 957 sp, err := stub.GetSignedProposal() 958 if err != nil { 959 return shim.Error(fmt.Sprintf("Failed retrieving signed proposal on executing %s with error %s", function, err)) 960 } 961 962 switch function { 963 case INSTALL: 964 if len(args) < 2 { 965 return shim.Error(InvalidArgsLenErr(len(args)).Error()) 966 } 967 968 // 2. check install policy 969 if err = lscc.ACLProvider.CheckACL(resources.Lscc_Install, "", sp); err != nil { 970 return shim.Error(fmt.Sprintf("access denied for [%s]: %s", function, err)) 971 } 972 973 depSpec := args[1] 974 975 err := lscc.executeInstall(stub, depSpec) 976 if err != nil { 977 return shim.Error(err.Error()) 978 } 979 return shim.Success([]byte("OK")) 980 case DEPLOY, UPGRADE: 981 // we expect a minimum of 3 arguments, the function 982 // name, the chain name and deployment spec 983 if len(args) < 3 { 984 return shim.Error(InvalidArgsLenErr(len(args)).Error()) 985 } 986 987 // channel the chaincode should be associated with. It 988 // should be created with a register call 989 channel := string(args[1]) 990 991 if !lscc.isValidChannelName(channel) { 992 return shim.Error(InvalidChannelNameErr(channel).Error()) 993 } 994 995 ac, exists := lscc.SCCProvider.GetApplicationConfig(channel) 996 if !exists { 997 logger.Panicf("programming error, non-existent appplication config for channel '%s'", channel) 998 } 999 1000 if ac.Capabilities().LifecycleV20() { 1001 return shim.Error(fmt.Sprintf("Channel '%s' has been migrated to the new lifecycle, LSCC is now read-only", channel)) 1002 } 1003 1004 // the maximum number of arguments depends on the capability of the channel 1005 if !ac.Capabilities().PrivateChannelData() && len(args) > 6 { 1006 return shim.Error(PrivateChannelDataNotAvailable("").Error()) 1007 } 1008 if ac.Capabilities().PrivateChannelData() && len(args) > 7 { 1009 return shim.Error(InvalidArgsLenErr(len(args)).Error()) 1010 } 1011 1012 depSpec := args[2] 1013 cds := &pb.ChaincodeDeploymentSpec{} 1014 err := proto.Unmarshal(depSpec, cds) 1015 if err != nil { 1016 return shim.Error(fmt.Sprintf("error unmarshalling ChaincodeDeploymentSpec: %s", err)) 1017 } 1018 1019 // optional arguments here (they can each be nil and may or may not be present) 1020 // args[3] is a marshalled SignaturePolicyEnvelope representing the endorsement policy 1021 // args[4] is the name of escc 1022 // args[5] is the name of vscc 1023 // args[6] is a marshalled CollectionConfigPackage struct 1024 var EP []byte 1025 if len(args) > 3 && len(args[3]) > 0 { 1026 EP = args[3] 1027 } else { 1028 mspIDs := lscc.GetMSPIDs(channel) 1029 p := policydsl.SignedByAnyMember(mspIDs) 1030 EP, err = protoutil.Marshal(p) 1031 if err != nil { 1032 return shim.Error(err.Error()) 1033 } 1034 } 1035 1036 var escc []byte 1037 if len(args) > 4 && len(args[4]) > 0 { 1038 escc = args[4] 1039 } else { 1040 escc = []byte("escc") 1041 } 1042 1043 var vscc []byte 1044 if len(args) > 5 && len(args[5]) > 0 { 1045 vscc = args[5] 1046 } else { 1047 vscc = []byte("vscc") 1048 } 1049 1050 var collectionsConfig []byte 1051 // we proceed with a non-nil collection configuration only if 1052 // we Support the PrivateChannelData capability 1053 if ac.Capabilities().PrivateChannelData() && len(args) > 6 { 1054 collectionsConfig = args[6] 1055 } 1056 1057 cd, err := lscc.executeDeployOrUpgrade(stub, channel, cds, EP, escc, vscc, collectionsConfig, function) 1058 if err != nil { 1059 return shim.Error(err.Error()) 1060 } 1061 cdbytes, err := proto.Marshal(cd) 1062 if err != nil { 1063 return shim.Error(err.Error()) 1064 } 1065 return shim.Success(cdbytes) 1066 case CCEXISTS, CHAINCODEEXISTS, GETDEPSPEC, GETDEPLOYMENTSPEC, GETCCDATA, GETCHAINCODEDATA: 1067 if len(args) != 3 { 1068 return shim.Error(InvalidArgsLenErr(len(args)).Error()) 1069 } 1070 1071 channel := string(args[1]) 1072 ccname := string(args[2]) 1073 1074 // 2. check policy for ACL resource 1075 var resource string 1076 switch function { 1077 case CCEXISTS, CHAINCODEEXISTS: 1078 resource = resources.Lscc_ChaincodeExists 1079 case GETDEPSPEC, GETDEPLOYMENTSPEC: 1080 resource = resources.Lscc_GetDeploymentSpec 1081 case GETCCDATA, GETCHAINCODEDATA: 1082 resource = resources.Lscc_GetChaincodeData 1083 } 1084 if err = lscc.ACLProvider.CheckACL(resource, channel, sp); err != nil { 1085 return shim.Error(fmt.Sprintf("access denied for [%s][%s]: %s", function, channel, err)) 1086 } 1087 1088 cdbytes, err := lscc.getCCInstance(stub, ccname) 1089 if err != nil { 1090 logger.Errorf("error getting chaincode %s on channel [%s]: %s", ccname, channel, err) 1091 return shim.Error(err.Error()) 1092 } 1093 1094 switch function { 1095 case CCEXISTS, CHAINCODEEXISTS: 1096 cd, err := lscc.getChaincodeData(ccname, cdbytes) 1097 if err != nil { 1098 return shim.Error(err.Error()) 1099 } 1100 return shim.Success([]byte(cd.Name)) 1101 case GETCCDATA, GETCHAINCODEDATA: 1102 return shim.Success(cdbytes) 1103 case GETDEPSPEC, GETDEPLOYMENTSPEC: 1104 _, depspecbytes, err := lscc.getCCCode(ccname, cdbytes) 1105 if err != nil { 1106 return shim.Error(err.Error()) 1107 } 1108 return shim.Success(depspecbytes) 1109 default: 1110 panic("unreachable") 1111 } 1112 case GETCHAINCODES, GETCHAINCODESALIAS: 1113 if len(args) != 1 { 1114 return shim.Error(InvalidArgsLenErr(len(args)).Error()) 1115 } 1116 1117 if err = lscc.ACLProvider.CheckACL(resources.Lscc_GetInstantiatedChaincodes, stub.GetChannelID(), sp); err != nil { 1118 return shim.Error(fmt.Sprintf("access denied for [%s][%s]: %s", function, stub.GetChannelID(), err)) 1119 } 1120 1121 return lscc.getChaincodes(stub) 1122 case GETINSTALLEDCHAINCODES, GETINSTALLEDCHAINCODESALIAS: 1123 if len(args) != 1 { 1124 return shim.Error(InvalidArgsLenErr(len(args)).Error()) 1125 } 1126 1127 // 2. check Lscc_GetInstalledChaincodes policy 1128 if err = lscc.ACLProvider.CheckACL(resources.Lscc_GetInstalledChaincodes, "", sp); err != nil { 1129 return shim.Error(fmt.Sprintf("access denied for [%s]: %s", function, err)) 1130 } 1131 1132 return lscc.getInstalledChaincodes() 1133 case GETCOLLECTIONSCONFIG, GETCOLLECTIONSCONFIGALIAS: 1134 if len(args) != 2 { 1135 return shim.Error(InvalidArgsLenErr(len(args)).Error()) 1136 } 1137 1138 chaincodeName := string(args[1]) 1139 1140 logger.Debugf("GetCollectionsConfig, chaincodeName:%s, start to check ACL for current identity policy", chaincodeName) 1141 if err = lscc.ACLProvider.CheckACL(resources.Lscc_GetCollectionsConfig, stub.GetChannelID(), sp); err != nil { 1142 logger.Debugf("ACL Check Failed for channel:%s, chaincode:%s", stub.GetChannelID(), chaincodeName) 1143 return shim.Error(fmt.Sprintf("access denied for [%s]: %s", function, err)) 1144 } 1145 1146 return lscc.getChaincodeCollectionData(stub, chaincodeName) 1147 } 1148 1149 return shim.Error(InvalidFunctionErr(function).Error()) 1150 }