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