github.com/defanghe/fabric@v2.1.1+incompatible/core/chaincode/lifecycle/lifecycle.go (about) 1 /* 2 Copyright IBM Corp. All Rights Reserved. 3 4 SPDX-License-Identifier: Apache-2.0 5 */ 6 7 package lifecycle 8 9 import ( 10 "bytes" 11 "fmt" 12 "sync" 13 14 cb "github.com/hyperledger/fabric-protos-go/common" 15 "github.com/hyperledger/fabric-protos-go/msp" 16 pb "github.com/hyperledger/fabric-protos-go/peer" 17 lb "github.com/hyperledger/fabric-protos-go/peer/lifecycle" 18 "github.com/hyperledger/fabric/common/chaincode" 19 "github.com/hyperledger/fabric/common/flogging" 20 "github.com/hyperledger/fabric/common/policydsl" 21 "github.com/hyperledger/fabric/core/chaincode/persistence" 22 "github.com/hyperledger/fabric/core/container" 23 "github.com/hyperledger/fabric/protoutil" 24 25 "github.com/golang/protobuf/proto" 26 "github.com/pkg/errors" 27 ) 28 29 var logger = flogging.MustGetLogger("lifecycle") 30 31 const ( 32 // NamespacesName is the prefix (or namespace) of the DB which will be used to store 33 // the information about other namespaces (for things like chaincodes) in the DB. 34 // We want a sub-namespaces within lifecycle in case other information needs to be stored here 35 // in the future. 36 NamespacesName = "namespaces" 37 38 // ChaincodeSourcesName is the namespace reserved for storing the information about where 39 // to find the chaincode (such as as a package on the local filesystem, or in the future, 40 // at some network resource). This namespace is only populated in the org implicit collection. 41 ChaincodeSourcesName = "chaincode-sources" 42 43 // ChaincodeDefinitionType is the name of the type used to store defined chaincodes 44 ChaincodeDefinitionType = "ChaincodeDefinition" 45 46 // FriendlyChaincodeDefinitionType is the name exposed to the outside world for the chaincode namespace 47 FriendlyChaincodeDefinitionType = "Chaincode" 48 49 // DefaultEndorsementPolicyRef is the name of the default endorsement policy for this channel 50 DefaultEndorsementPolicyRef = "/Channel/Application/Endorsement" 51 ) 52 53 var ( 54 DefaultEndorsementPolicyBytes = protoutil.MarshalOrPanic(&pb.ApplicationPolicy{ 55 Type: &pb.ApplicationPolicy_ChannelConfigPolicyReference{ 56 ChannelConfigPolicyReference: DefaultEndorsementPolicyRef, 57 }, 58 }) 59 ) 60 61 // Sequences are the underpinning of the definition framework for lifecycle. 62 // All definitions must have a Sequence field in the public state. This 63 // sequence is incremented by exactly 1 with each redefinition of the 64 // namespace. The private state org approvals also have a Sequence number 65 // embedded into the key which matches them either to the vote for the commit, 66 // or registers approval for an already committed definition. 67 // 68 // Public/World DB layout looks like the following: 69 // namespaces/metadata/<namespace> -> namespace metadata, including namespace type 70 // namespaces/fields/<namespace>/Sequence -> sequence for this namespace 71 // namespaces/fields/<namespace>/<field> -> field of namespace type 72 // 73 // So, for instance, a db might look like: 74 // 75 // namespaces/metadata/mycc: "ChaincodeDefinition" 76 // namespaces/fields/mycc/Sequence 1 (The current sequence) 77 // namespaces/fields/mycc/EndorsementInfo: {Version: "1.3", EndorsementPlugin: "builtin", InitRequired: true} 78 // namespaces/fields/mycc/ValidationInfo: {ValidationPlugin: "builtin", ValidationParameter: <application-policy>} 79 // namespaces/fields/mycc/Collections {<collection info>} 80 // 81 // Private/Org Scope Implcit Collection layout looks like the following 82 // namespaces/metadata/<namespace>#<sequence_number> -> namespace metadata, including type 83 // namespaces/fields/<namespace>#<sequence_number>/<field> -> field of namespace type 84 // 85 // namespaces/metadata/mycc#1: "ChaincodeParameters" 86 // namespaces/fields/mycc#1/EndorsementInfo: {Version: "1.3", EndorsementPlugin: "builtin", InitRequired: true} 87 // namespaces/fields/mycc#1/ValidationInfo: {ValidationPlugin: "builtin", ValidationParameter: <application-policy>} 88 // namespaces/fields/mycc#1/Collections {<collection info>} 89 // namespaces/metadata/mycc#2: "ChaincodeParameters" 90 // namespaces/fields/mycc#2/EndorsementInfo: {Version: "1.4", EndorsementPlugin: "builtin", InitRequired: true} 91 // namespaces/fields/mycc#2/ValidationInfo: {ValidationPlugin: "builtin", ValidationParameter: <application-policy>} 92 // namespaces/fields/mycc#2/Collections {<collection info>} 93 // 94 // chaincode-sources/metadata/mycc#1 "ChaincodeLocalPackage" 95 // chaincode-sources/fields/mycc#1/PackageID "hash1" 96 97 // ChaincodeLocalPackage is a type of chaincode-sources which may be serialized 98 // into the org's private data collection. 99 // WARNING: This structure is serialized/deserialized from the DB, re-ordering 100 // or adding fields will cause opaque checks to fail. 101 type ChaincodeLocalPackage struct { 102 PackageID string 103 } 104 105 // ChaincodeParameters are the parts of the chaincode definition which are serialized 106 // as values in the statedb. It is expected that any instance will have no nil fields once initialized. 107 // WARNING: This structure is serialized/deserialized from the DB, re-ordering or adding fields 108 // will cause opaque checks to fail. 109 type ChaincodeParameters struct { 110 EndorsementInfo *lb.ChaincodeEndorsementInfo 111 ValidationInfo *lb.ChaincodeValidationInfo 112 Collections *pb.CollectionConfigPackage 113 } 114 115 func (cp *ChaincodeParameters) Equal(ocp *ChaincodeParameters) error { 116 switch { 117 case cp.EndorsementInfo.Version != ocp.EndorsementInfo.Version: 118 return errors.Errorf("Version '%s' != '%s'", cp.EndorsementInfo.Version, ocp.EndorsementInfo.Version) 119 case cp.EndorsementInfo.EndorsementPlugin != ocp.EndorsementInfo.EndorsementPlugin: 120 return errors.Errorf("EndorsementPlugin '%s' != '%s'", cp.EndorsementInfo.EndorsementPlugin, ocp.EndorsementInfo.EndorsementPlugin) 121 case cp.EndorsementInfo.InitRequired != ocp.EndorsementInfo.InitRequired: 122 return errors.Errorf("InitRequired '%t' != '%t'", cp.EndorsementInfo.InitRequired, ocp.EndorsementInfo.InitRequired) 123 case cp.ValidationInfo.ValidationPlugin != ocp.ValidationInfo.ValidationPlugin: 124 return errors.Errorf("ValidationPlugin '%s' != '%s'", cp.ValidationInfo.ValidationPlugin, ocp.ValidationInfo.ValidationPlugin) 125 case !bytes.Equal(cp.ValidationInfo.ValidationParameter, ocp.ValidationInfo.ValidationParameter): 126 return errors.Errorf("ValidationParameter '%x' != '%x'", cp.ValidationInfo.ValidationParameter, ocp.ValidationInfo.ValidationParameter) 127 case !proto.Equal(cp.Collections, ocp.Collections): 128 return errors.Errorf("Collections do not match") 129 default: 130 } 131 return nil 132 } 133 134 // ChaincodeDefinition contains the chaincode parameters, as well as the sequence number of the definition. 135 // Note, it does not embed ChaincodeParameters so as not to complicate the serialization. It is expected 136 // that any instance will have no nil fields once initialized. 137 // WARNING: This structure is serialized/deserialized from the DB, re-ordering or adding fields 138 // will cause opaque checks to fail. 139 type ChaincodeDefinition struct { 140 Sequence int64 141 EndorsementInfo *lb.ChaincodeEndorsementInfo 142 ValidationInfo *lb.ChaincodeValidationInfo 143 Collections *pb.CollectionConfigPackage 144 } 145 146 // Parameters returns the non-sequence info of the chaincode definition 147 func (cd *ChaincodeDefinition) Parameters() *ChaincodeParameters { 148 return &ChaincodeParameters{ 149 EndorsementInfo: cd.EndorsementInfo, 150 ValidationInfo: cd.ValidationInfo, 151 Collections: cd.Collections, 152 } 153 } 154 155 func (cd *ChaincodeDefinition) String() string { 156 endorsementInfo := "endorsement info: <EMPTY>" 157 if cd.EndorsementInfo != nil { 158 endorsementInfo = fmt.Sprintf("endorsement info: (version: '%s', plugin: '%s', init required: %t)", 159 cd.EndorsementInfo.Version, 160 cd.EndorsementInfo.EndorsementPlugin, 161 cd.EndorsementInfo.InitRequired, 162 ) 163 } 164 165 validationInfo := "validation info: <EMPTY>" 166 if cd.ValidationInfo != nil { 167 validationInfo = fmt.Sprintf("validation info: (plugin: '%s', policy: '%x')", 168 cd.ValidationInfo.ValidationPlugin, 169 cd.ValidationInfo.ValidationParameter, 170 ) 171 } 172 173 return fmt.Sprintf("sequence: %d, %s, %s, collections: (%+v)", 174 cd.Sequence, 175 endorsementInfo, 176 validationInfo, 177 cd.Collections, 178 ) 179 } 180 181 //go:generate counterfeiter -o mock/chaincode_builder.go --fake-name ChaincodeBuilder . ChaincodeBuilder 182 183 type ChaincodeBuilder interface { 184 Build(ccid string) error 185 } 186 187 // ChaincodeStore provides a way to persist chaincodes 188 type ChaincodeStore interface { 189 Save(label string, ccInstallPkg []byte) (string, error) 190 ListInstalledChaincodes() ([]chaincode.InstalledChaincode, error) 191 Load(packageID string) (ccInstallPkg []byte, err error) 192 Delete(packageID string) error 193 } 194 195 type PackageParser interface { 196 Parse(data []byte) (*persistence.ChaincodePackage, error) 197 } 198 199 //go:generate counterfeiter -o mock/install_listener.go --fake-name InstallListener . InstallListener 200 type InstallListener interface { 201 HandleChaincodeInstalled(md *persistence.ChaincodePackageMetadata, packageID string) 202 } 203 204 //go:generate counterfeiter -o mock/installed_chaincodes_lister.go --fake-name InstalledChaincodesLister . InstalledChaincodesLister 205 type InstalledChaincodesLister interface { 206 ListInstalledChaincodes() []*chaincode.InstalledChaincode 207 GetInstalledChaincode(packageID string) (*chaincode.InstalledChaincode, error) 208 } 209 210 // Resources stores the common functions needed by all components of the lifecycle 211 // by the SCC as well as internally. It also has some utility methods attached to it 212 // for querying the lifecycle definitions. 213 type Resources struct { 214 ChannelConfigSource ChannelConfigSource 215 ChaincodeStore ChaincodeStore 216 PackageParser PackageParser 217 Serializer *Serializer 218 } 219 220 // ChaincodeDefinitionIfDefined returns whether the chaincode name is defined in the new lifecycle, a shim around 221 // the SimpleQueryExecutor to work with the serializer, or an error. If the namespace is defined, but it is 222 // not a chaincode, this is considered an error. 223 func (r *Resources) ChaincodeDefinitionIfDefined(chaincodeName string, state ReadableState) (bool, *ChaincodeDefinition, error) { 224 if chaincodeName == LifecycleNamespace { 225 return true, &ChaincodeDefinition{ 226 EndorsementInfo: &lb.ChaincodeEndorsementInfo{ 227 InitRequired: false, 228 }, 229 ValidationInfo: &lb.ChaincodeValidationInfo{}, 230 }, nil 231 } 232 233 metadata, ok, err := r.Serializer.DeserializeMetadata(NamespacesName, chaincodeName, state) 234 if err != nil { 235 return false, nil, errors.WithMessagef(err, "could not deserialize metadata for chaincode %s", chaincodeName) 236 } 237 238 if !ok { 239 return false, nil, nil 240 } 241 242 if metadata.Datatype != ChaincodeDefinitionType { 243 return false, nil, errors.Errorf("not a chaincode type: %s", metadata.Datatype) 244 } 245 246 definedChaincode := &ChaincodeDefinition{} 247 err = r.Serializer.Deserialize(NamespacesName, chaincodeName, metadata, definedChaincode, state) 248 if err != nil { 249 return false, nil, errors.WithMessagef(err, "could not deserialize chaincode definition for chaincode %s", chaincodeName) 250 } 251 252 return true, definedChaincode, nil 253 } 254 255 func (r *Resources) LifecycleEndorsementPolicyAsBytes(channelID string) ([]byte, error) { 256 channelConfig := r.ChannelConfigSource.GetStableChannelConfig(channelID) 257 if channelConfig == nil { 258 return nil, errors.Errorf("could not get channel config for channel '%s'", channelID) 259 } 260 261 if _, ok := channelConfig.PolicyManager().GetPolicy(LifecycleEndorsementPolicyRef); ok { 262 return LifecycleDefaultEndorsementPolicyBytes, nil 263 } 264 265 // This was a channel which was upgraded or did not define a lifecycle endorsement policy, use a default 266 // of "a majority of orgs must have a member sign". 267 ac, ok := channelConfig.ApplicationConfig() 268 if !ok { 269 return nil, errors.Errorf("could not get application config for channel '%s'", channelID) 270 } 271 orgs := ac.Organizations() 272 mspids := make([]string, 0, len(orgs)) 273 for _, org := range orgs { 274 mspids = append(mspids, org.MSPID()) 275 } 276 277 return protoutil.MarshalOrPanic(&cb.ApplicationPolicy{ 278 Type: &cb.ApplicationPolicy_SignaturePolicy{ 279 SignaturePolicy: policydsl.SignedByNOutOfGivenRole(int32(len(mspids)/2+1), msp.MSPRole_MEMBER, mspids), 280 }, 281 }), nil 282 } 283 284 // ExternalFunctions is intended primarily to support the SCC functions. 285 // In general, its methods signatures produce writes (which must be commmitted 286 // as part of an endorsement flow), or return human readable errors (for 287 // instance indicating a chaincode is not found) rather than sentinels. 288 // Instead, use the utility functions attached to the lifecycle Resources 289 // when needed. 290 type ExternalFunctions struct { 291 Resources *Resources 292 InstallListener InstallListener 293 InstalledChaincodesLister InstalledChaincodesLister 294 ChaincodeBuilder ChaincodeBuilder 295 BuildRegistry *container.BuildRegistry 296 mutex sync.Mutex 297 BuildLocks map[string]sync.Mutex 298 } 299 300 // CheckCommitReadiness takes a chaincode definition, checks that 301 // its sequence number is the next allowable sequence number and checks which 302 // organizations have approved the definition. 303 func (ef *ExternalFunctions) CheckCommitReadiness(chname, ccname string, cd *ChaincodeDefinition, publicState ReadWritableState, orgStates []OpaqueState) (map[string]bool, error) { 304 currentSequence, err := ef.Resources.Serializer.DeserializeFieldAsInt64(NamespacesName, ccname, "Sequence", publicState) 305 if err != nil { 306 return nil, errors.WithMessage(err, "could not get current sequence") 307 } 308 309 if cd.Sequence != currentSequence+1 { 310 return nil, errors.Errorf("requested sequence is %d, but new definition must be sequence %d", cd.Sequence, currentSequence+1) 311 } 312 313 if err := ef.SetChaincodeDefinitionDefaults(chname, cd); err != nil { 314 return nil, errors.WithMessagef(err, "could not set defaults for chaincode definition in channel %s", chname) 315 } 316 317 var approvals map[string]bool 318 if approvals, err = ef.QueryOrgApprovals(ccname, cd, orgStates); err != nil { 319 return nil, err 320 } 321 322 logger.Infof("Successfully checked commit readiness of chaincode name '%s' on channel '%s' with definition {%s}", ccname, chname, cd) 323 324 return approvals, nil 325 } 326 327 // CommitChaincodeDefinition takes a chaincode definition, checks that its 328 // sequence number is the next allowable sequence number, checks which 329 // organizations have approved the definition, and applies the definition to 330 // the public world state. It is the responsibility of the caller to check 331 // the approvals to determine if the result is valid (typically, this means 332 // checking that the peer's own org has approved the definition). 333 func (ef *ExternalFunctions) CommitChaincodeDefinition(chname, ccname string, cd *ChaincodeDefinition, publicState ReadWritableState, orgStates []OpaqueState) (map[string]bool, error) { 334 approvals, err := ef.CheckCommitReadiness(chname, ccname, cd, publicState, orgStates) 335 if err != nil { 336 return nil, err 337 } 338 339 if err = ef.Resources.Serializer.Serialize(NamespacesName, ccname, cd, publicState); err != nil { 340 return nil, errors.WithMessage(err, "could not serialize chaincode definition") 341 } 342 343 return approvals, nil 344 } 345 346 // DefaultEndorsementPolicyAsBytes returns a marshalled version 347 // of the default chaincode endorsement policy in the supplied channel 348 func (ef *ExternalFunctions) DefaultEndorsementPolicyAsBytes(channelID string) ([]byte, error) { 349 channelConfig := ef.Resources.ChannelConfigSource.GetStableChannelConfig(channelID) 350 if channelConfig == nil { 351 return nil, errors.Errorf("could not get channel config for channel '%s'", channelID) 352 } 353 354 // see if the channel defines a default 355 if _, ok := channelConfig.PolicyManager().GetPolicy(DefaultEndorsementPolicyRef); ok { 356 return DefaultEndorsementPolicyBytes, nil 357 } 358 359 return nil, errors.Errorf( 360 "policy '%s' must be defined for channel '%s' before chaincode operations can be attempted", 361 DefaultEndorsementPolicyRef, 362 channelID, 363 ) 364 } 365 366 // SetChaincodeDefinitionDefaults fills any empty fields in the 367 // supplied ChaincodeDefinition with the supplied channel's defaults 368 func (ef *ExternalFunctions) SetChaincodeDefinitionDefaults(chname string, cd *ChaincodeDefinition) error { 369 if cd.EndorsementInfo.EndorsementPlugin == "" { 370 // TODO: 371 // 1) rename to "default" or "builtin" 372 // 2) retrieve from channel config 373 cd.EndorsementInfo.EndorsementPlugin = "escc" 374 } 375 376 if cd.ValidationInfo.ValidationPlugin == "" { 377 // TODO: 378 // 1) rename to "default" or "builtin" 379 // 2) retrieve from channel config 380 cd.ValidationInfo.ValidationPlugin = "vscc" 381 } 382 383 if len(cd.ValidationInfo.ValidationParameter) == 0 { 384 policyBytes, err := ef.DefaultEndorsementPolicyAsBytes(chname) 385 if err != nil { 386 return err 387 } 388 389 cd.ValidationInfo.ValidationParameter = policyBytes 390 } 391 392 return nil 393 } 394 395 // ApproveChaincodeDefinitionForOrg adds a chaincode definition entry into the passed in Org state. The definition must be 396 // for either the currently defined sequence number or the next sequence number. If the definition is 397 // for the current sequence number, then it must match exactly the current definition or it will be rejected. 398 func (ef *ExternalFunctions) ApproveChaincodeDefinitionForOrg(chname, ccname string, cd *ChaincodeDefinition, packageID string, publicState ReadableState, orgState ReadWritableState) error { 399 // Get the current sequence from the public state 400 currentSequence, err := ef.Resources.Serializer.DeserializeFieldAsInt64(NamespacesName, ccname, "Sequence", publicState) 401 if err != nil { 402 return errors.WithMessage(err, "could not get current sequence") 403 } 404 405 requestedSequence := cd.Sequence 406 407 if currentSequence == requestedSequence && requestedSequence == 0 { 408 return errors.Errorf("requested sequence is 0, but first definable sequence number is 1") 409 } 410 411 if requestedSequence < currentSequence { 412 return errors.Errorf("currently defined sequence %d is larger than requested sequence %d", currentSequence, requestedSequence) 413 } 414 415 if requestedSequence > currentSequence+1 { 416 return errors.Errorf("requested sequence %d is larger than the next available sequence number %d", requestedSequence, currentSequence+1) 417 } 418 419 if err := ef.SetChaincodeDefinitionDefaults(chname, cd); err != nil { 420 return errors.WithMessagef(err, "could not set defaults for chaincode definition in channel %s", chname) 421 } 422 423 if requestedSequence == currentSequence { 424 metadata, ok, err := ef.Resources.Serializer.DeserializeMetadata(NamespacesName, ccname, publicState) 425 if err != nil { 426 return errors.WithMessage(err, "could not fetch metadata for current definition") 427 } 428 if !ok { 429 return errors.Errorf("missing metadata for currently committed sequence number (%d)", currentSequence) 430 } 431 432 definedChaincode := &ChaincodeDefinition{} 433 if err := ef.Resources.Serializer.Deserialize(NamespacesName, ccname, metadata, definedChaincode, publicState); err != nil { 434 return errors.WithMessagef(err, "could not deserialize namespace %s as chaincode", ccname) 435 } 436 437 if err := definedChaincode.Parameters().Equal(cd.Parameters()); err != nil { 438 return errors.WithMessagef(err, "attempted to define the current sequence (%d) for namespace %s, but", currentSequence, ccname) 439 } 440 } 441 442 privateName := fmt.Sprintf("%s#%d", ccname, requestedSequence) 443 444 // if requested sequence is not committed, and attempt is made to update its content, 445 // we need to check whether new definition actually contains updated content, to avoid 446 // empty write set. 447 if requestedSequence == currentSequence+1 { 448 uncommittedMetadata, ok, err := ef.Resources.Serializer.DeserializeMetadata(NamespacesName, privateName, orgState) 449 if err != nil { 450 return errors.WithMessage(err, "could not fetch uncommitted definition") 451 } 452 453 if ok { 454 logger.Debugf("Attempting to redefine uncommitted definition at sequence %d", requestedSequence) 455 456 uncommittedParameters := &ChaincodeParameters{} 457 if err := ef.Resources.Serializer.Deserialize(NamespacesName, privateName, uncommittedMetadata, uncommittedParameters, orgState); err != nil { 458 return errors.WithMessagef(err, "could not deserialize namespace %s as chaincode", privateName) 459 } 460 461 if err := uncommittedParameters.Equal(cd.Parameters()); err == nil { 462 // also check package ID updates 463 metadata, ok, err := ef.Resources.Serializer.DeserializeMetadata(ChaincodeSourcesName, privateName, orgState) 464 if err != nil { 465 return errors.WithMessagef(err, "could not deserialize chaincode-source metadata for %s", privateName) 466 } 467 if ok { 468 ccLocalPackage := &ChaincodeLocalPackage{} 469 if err := ef.Resources.Serializer.Deserialize(ChaincodeSourcesName, privateName, metadata, ccLocalPackage, orgState); err != nil { 470 return errors.WithMessagef(err, "could not deserialize chaincode package for %s", privateName) 471 } 472 473 if ccLocalPackage.PackageID == packageID { 474 return errors.Errorf("attempted to redefine uncommitted sequence (%d) for namespace %s with unchanged content", requestedSequence, ccname) 475 } 476 } 477 } 478 } 479 } 480 481 if err := ef.Resources.Serializer.Serialize(NamespacesName, privateName, cd.Parameters(), orgState); err != nil { 482 return errors.WithMessage(err, "could not serialize chaincode parameters to state") 483 } 484 485 // set the package id - whether empty or not. Setting 486 // an empty package ID means that the chaincode won't 487 // be invocable. The package might be set empty after 488 // the definition commits as a way of instructing the 489 // peers of an org no longer to endorse invocations 490 // for this chaincode 491 if err := ef.Resources.Serializer.Serialize(ChaincodeSourcesName, privateName, &ChaincodeLocalPackage{ 492 PackageID: packageID, 493 }, orgState); err != nil { 494 return errors.WithMessage(err, "could not serialize chaincode package info to state") 495 } 496 497 logger.Infof("Successfully endorsed chaincode approval with name '%s', package ID '%s', on channel '%s' with definition {%s}", ccname, packageID, chname, cd) 498 499 return nil 500 } 501 502 // ErrNamespaceNotDefined is the error returned when a namespace 503 // is not defined. This indicates that the chaincode definition 504 // has not been committed. 505 type ErrNamespaceNotDefined struct { 506 Namespace string 507 } 508 509 func (e ErrNamespaceNotDefined) Error() string { 510 return fmt.Sprintf("namespace %s is not defined", e.Namespace) 511 } 512 513 // QueryChaincodeDefinition returns the defined chaincode by the given name (if it is committed, and a chaincode) 514 // or otherwise returns an error. 515 func (ef *ExternalFunctions) QueryChaincodeDefinition(name string, publicState ReadableState) (*ChaincodeDefinition, error) { 516 metadata, ok, err := ef.Resources.Serializer.DeserializeMetadata(NamespacesName, name, publicState) 517 if err != nil { 518 return nil, errors.WithMessagef(err, "could not fetch metadata for namespace %s", name) 519 } 520 if !ok { 521 return nil, ErrNamespaceNotDefined{Namespace: name} 522 } 523 524 definedChaincode := &ChaincodeDefinition{} 525 if err := ef.Resources.Serializer.Deserialize(NamespacesName, name, metadata, definedChaincode, publicState); err != nil { 526 return nil, errors.WithMessagef(err, "could not deserialize namespace %s as chaincode", name) 527 } 528 529 logger.Infof("Successfully queried chaincode name '%s' with definition {%s},", name, definedChaincode) 530 531 return definedChaincode, nil 532 } 533 534 // QueryOrgApprovals returns a map containing the orgs whose orgStates were 535 // provided and whether or not they have approved a chaincode definition with 536 // the specified parameters. 537 func (ef *ExternalFunctions) QueryOrgApprovals(name string, cd *ChaincodeDefinition, orgStates []OpaqueState) (map[string]bool, error) { 538 approvals := map[string]bool{} 539 privateName := fmt.Sprintf("%s#%d", name, cd.Sequence) 540 for _, orgState := range orgStates { 541 match, err := ef.Resources.Serializer.IsSerialized(NamespacesName, privateName, cd.Parameters(), orgState) 542 if err != nil { 543 return nil, errors.WithMessagef(err, "serialization check failed for key %s", privateName) 544 } 545 546 org := OrgFromImplicitCollectionName(orgState.CollectionName()) 547 approvals[org] = match 548 } 549 550 return approvals, nil 551 } 552 553 // InstallChaincode installs a given chaincode to the peer's chaincode store. 554 // It returns the hash to reference the chaincode by or an error on failure. 555 func (ef *ExternalFunctions) InstallChaincode(chaincodeInstallPackage []byte) (*chaincode.InstalledChaincode, error) { 556 // Let's validate that the chaincodeInstallPackage is at least well formed before writing it 557 pkg, err := ef.Resources.PackageParser.Parse(chaincodeInstallPackage) 558 if err != nil { 559 return nil, errors.WithMessage(err, "could not parse as a chaincode install package") 560 } 561 562 if pkg.Metadata == nil { 563 return nil, errors.New("empty metadata for supplied chaincode") 564 } 565 566 packageID, err := ef.Resources.ChaincodeStore.Save(pkg.Metadata.Label, chaincodeInstallPackage) 567 if err != nil { 568 return nil, errors.WithMessage(err, "could not save cc install package") 569 } 570 571 buildLock := ef.getBuildLock(packageID) 572 buildLock.Lock() 573 defer buildLock.Unlock() 574 575 buildStatus, ok := ef.BuildRegistry.BuildStatus(packageID) 576 if ok { 577 // another invocation of lifecycle has concurrently 578 // installed a chaincode with this package id 579 <-buildStatus.Done() 580 if buildStatus.Err() == nil { 581 return nil, errors.New("chaincode already successfully installed") 582 } 583 buildStatus = ef.BuildRegistry.ResetBuildStatus(packageID) 584 } 585 err = ef.ChaincodeBuilder.Build(packageID) 586 buildStatus.Notify(err) 587 <-buildStatus.Done() 588 if err := buildStatus.Err(); err != nil { 589 ef.Resources.ChaincodeStore.Delete(packageID) 590 return nil, errors.WithMessage(err, "could not build chaincode") 591 } 592 593 if ef.InstallListener != nil { 594 ef.InstallListener.HandleChaincodeInstalled(pkg.Metadata, packageID) 595 } 596 597 logger.Infof("Successfully installed chaincode with package ID '%s'", packageID) 598 599 return &chaincode.InstalledChaincode{ 600 PackageID: packageID, 601 Label: pkg.Metadata.Label, 602 }, nil 603 } 604 605 func (ef *ExternalFunctions) getBuildLock(packageID string) *sync.Mutex { 606 ef.mutex.Lock() 607 defer ef.mutex.Unlock() 608 609 if ef.BuildLocks == nil { 610 ef.BuildLocks = map[string]sync.Mutex{} 611 } 612 613 buildLock, ok := ef.BuildLocks[packageID] 614 if !ok { 615 ef.BuildLocks[packageID] = sync.Mutex{} 616 } 617 618 return &buildLock 619 } 620 621 // GetInstalledChaincodePackage retrieves the installed chaincode with the given package ID 622 // from the peer's chaincode store. 623 func (ef *ExternalFunctions) GetInstalledChaincodePackage(packageID string) ([]byte, error) { 624 pkgBytes, err := ef.Resources.ChaincodeStore.Load(packageID) 625 if err != nil { 626 return nil, errors.WithMessage(err, "could not load cc install package") 627 } 628 629 return pkgBytes, nil 630 } 631 632 // QueryNamespaceDefinitions lists the publicly defined namespaces in a channel. Today it should only ever 633 // find Datatype encodings of 'ChaincodeDefinition'. 634 func (ef *ExternalFunctions) QueryNamespaceDefinitions(publicState RangeableState) (map[string]string, error) { 635 metadatas, err := ef.Resources.Serializer.DeserializeAllMetadata(NamespacesName, publicState) 636 if err != nil { 637 return nil, errors.WithMessage(err, "could not query namespace metadata") 638 } 639 640 result := map[string]string{} 641 for key, value := range metadatas { 642 switch value.Datatype { 643 case ChaincodeDefinitionType: 644 result[key] = FriendlyChaincodeDefinitionType 645 default: 646 // This should never execute, but seems preferable to returning an error 647 result[key] = value.Datatype 648 } 649 } 650 return result, nil 651 } 652 653 // QueryInstalledChaincode returns metadata for the chaincode with the supplied package ID. 654 func (ef *ExternalFunctions) QueryInstalledChaincode(packageID string) (*chaincode.InstalledChaincode, error) { 655 return ef.InstalledChaincodesLister.GetInstalledChaincode(packageID) 656 } 657 658 // QueryInstalledChaincodes returns a list of installed chaincodes 659 func (ef *ExternalFunctions) QueryInstalledChaincodes() []*chaincode.InstalledChaincode { 660 return ef.InstalledChaincodesLister.ListInstalledChaincodes() 661 }