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