github.com/hechain20/hechain@v0.0.0-20220316014945-b544036ba106/core/chaincode/lifecycle/lifecycle_test.go (about) 1 /* 2 Copyright hechain. All Rights Reserved. 3 4 SPDX-License-Identifier: Apache-2.0 5 */ 6 7 package lifecycle_test 8 9 import ( 10 "fmt" 11 12 "github.com/golang/protobuf/proto" 13 "github.com/hechain20/hechain/common/chaincode" 14 "github.com/hechain20/hechain/common/channelconfig" 15 "github.com/hechain20/hechain/core/chaincode/lifecycle" 16 "github.com/hechain20/hechain/core/chaincode/lifecycle/mock" 17 "github.com/hechain20/hechain/core/chaincode/persistence" 18 "github.com/hechain20/hechain/core/container" 19 "github.com/hechain20/hechain/protoutil" 20 cb "github.com/hyperledger/fabric-protos-go/common" 21 pb "github.com/hyperledger/fabric-protos-go/peer" 22 lb "github.com/hyperledger/fabric-protos-go/peer/lifecycle" 23 "github.com/pkg/errors" 24 25 . "github.com/onsi/ginkgo" 26 . "github.com/onsi/gomega" 27 ) 28 29 var _ = Describe("ChaincodeParameters", func() { 30 var lhs, rhs *lifecycle.ChaincodeParameters 31 32 BeforeEach(func() { 33 lhs = &lifecycle.ChaincodeParameters{ 34 EndorsementInfo: &lb.ChaincodeEndorsementInfo{}, 35 ValidationInfo: &lb.ChaincodeValidationInfo{}, 36 Collections: &pb.CollectionConfigPackage{}, 37 } 38 39 rhs = &lifecycle.ChaincodeParameters{ 40 EndorsementInfo: &lb.ChaincodeEndorsementInfo{}, 41 ValidationInfo: &lb.ChaincodeValidationInfo{}, 42 Collections: &pb.CollectionConfigPackage{}, 43 } 44 }) 45 46 Describe("Equal", func() { 47 It("returns nil when the parameters match", func() { 48 Expect(lhs.Equal(rhs)).NotTo(HaveOccurred()) 49 }) 50 51 Context("when the EndorsementPlugin differs from the current definition", func() { 52 BeforeEach(func() { 53 rhs.EndorsementInfo.EndorsementPlugin = "different" 54 }) 55 56 It("returns an error", func() { 57 Expect(lhs.Equal(rhs)).To(MatchError("expected EndorsementPlugin '' does not match passed EndorsementPlugin 'different'")) 58 }) 59 }) 60 61 Context("when the InitRequired differs from the current definition", func() { 62 BeforeEach(func() { 63 rhs.EndorsementInfo.InitRequired = true 64 }) 65 66 It("returns an error", func() { 67 Expect(lhs.Equal(rhs)).To(MatchError("expected InitRequired 'false' does not match passed InitRequired 'true'")) 68 }) 69 }) 70 71 Context("when the ValidationPlugin differs from the current definition", func() { 72 BeforeEach(func() { 73 rhs.ValidationInfo.ValidationPlugin = "different" 74 }) 75 76 It("returns an error", func() { 77 Expect(lhs.Equal(rhs)).To(MatchError("expected ValidationPlugin '' does not match passed ValidationPlugin 'different'")) 78 }) 79 }) 80 81 Context("when the ValidationParameter differs from the current definition", func() { 82 BeforeEach(func() { 83 rhs.ValidationInfo.ValidationParameter = []byte("different") 84 }) 85 86 It("returns an error", func() { 87 Expect(lhs.Equal(rhs)).To(MatchError("expected ValidationParameter '' does not match passed ValidationParameter '646966666572656e74'")) 88 }) 89 }) 90 91 Context("when the Collections differ from the current definition", func() { 92 BeforeEach(func() { 93 rhs.Collections = &pb.CollectionConfigPackage{ 94 Config: []*pb.CollectionConfig{ 95 { 96 Payload: &pb.CollectionConfig_StaticCollectionConfig{ 97 StaticCollectionConfig: &pb.StaticCollectionConfig{Name: "foo"}, 98 }, 99 }, 100 }, 101 } 102 }) 103 104 It("returns an error", func() { 105 Expect(lhs.Equal(rhs)).To(MatchError("Collections do not match")) 106 }) 107 }) 108 }) 109 }) 110 111 var _ = Describe("Resources", func() { 112 var ( 113 resources *lifecycle.Resources 114 fakeChannelConfigSource *mock.ChannelConfigSource 115 fakeChannelConfig *mock.ChannelConfig 116 fakeApplicationConfig *mock.ApplicationConfig 117 fakeOrgConfigs []*mock.ApplicationOrgConfig 118 fakePolicyManager *mock.PolicyManager 119 ) 120 121 BeforeEach(func() { 122 fakeChannelConfigSource = &mock.ChannelConfigSource{} 123 fakeChannelConfig = &mock.ChannelConfig{} 124 fakeChannelConfigSource.GetStableChannelConfigReturns(fakeChannelConfig) 125 fakeApplicationConfig = &mock.ApplicationConfig{} 126 fakeChannelConfig.ApplicationConfigReturns(fakeApplicationConfig, true) 127 fakeOrgConfigs = []*mock.ApplicationOrgConfig{{}, {}} 128 fakeOrgConfigs[0].MSPIDReturns("first-mspid") 129 fakeOrgConfigs[1].MSPIDReturns("second-mspid") 130 fakePolicyManager = &mock.PolicyManager{} 131 fakePolicyManager.GetPolicyReturns(nil, true) 132 fakeChannelConfig.PolicyManagerReturns(fakePolicyManager) 133 134 fakeApplicationConfig.OrganizationsReturns(map[string]channelconfig.ApplicationOrg{ 135 "org0": fakeOrgConfigs[0], 136 "org1": fakeOrgConfigs[1], 137 }) 138 139 resources = &lifecycle.Resources{ 140 ChannelConfigSource: fakeChannelConfigSource, 141 Serializer: &lifecycle.Serializer{}, 142 } 143 }) 144 145 Describe("ChaincodeDefinitionIfDefined", func() { 146 var ( 147 fakePublicState MapLedgerShim 148 fakeReadableState *mock.ReadWritableState 149 ) 150 151 BeforeEach(func() { 152 fakePublicState = map[string][]byte{} 153 err := resources.Serializer.Serialize(lifecycle.NamespacesName, "cc-name", &lifecycle.ChaincodeDefinition{ 154 Sequence: 5, 155 EndorsementInfo: &lb.ChaincodeEndorsementInfo{ 156 Version: "version", 157 EndorsementPlugin: "my endorsement plugin", 158 }, 159 ValidationInfo: &lb.ChaincodeValidationInfo{ 160 ValidationPlugin: "my validation plugin", 161 ValidationParameter: []byte("some awesome policy"), 162 }, 163 Collections: &pb.CollectionConfigPackage{}, 164 }, fakePublicState) 165 Expect(err).NotTo(HaveOccurred()) 166 fakeReadableState = &mock.ReadWritableState{} 167 fakeReadableState.GetStateStub = fakePublicState.GetState 168 }) 169 170 It("returns that the chaincode is defined and that the chaincode definition can be converted to a string suitable for log messages", func() { 171 exists, definition, err := resources.ChaincodeDefinitionIfDefined("cc-name", fakeReadableState) 172 Expect(err).NotTo(HaveOccurred()) 173 Expect(exists).To(BeTrue()) 174 Expect(definition.EndorsementInfo.Version).To(Equal("version")) 175 Expect(fmt.Sprintf("{%s}", definition)).To(Equal("{sequence: 5, endorsement info: (version: 'version', plugin: 'my endorsement plugin', init required: false), validation info: (plugin: 'my validation plugin', policy: '736f6d6520617765736f6d6520706f6c696379'), collections: ()}")) 176 }) 177 178 Context("when the requested chaincode is _lifecycle", func() { 179 It("it returns true", func() { 180 exists, definition, err := resources.ChaincodeDefinitionIfDefined("_lifecycle", fakeReadableState) 181 Expect(err).NotTo(HaveOccurred()) 182 Expect(exists).To(BeTrue()) 183 Expect(definition).NotTo(BeNil()) 184 Expect(fakeReadableState.GetStateCallCount()).To(Equal(0)) 185 }) 186 }) 187 188 Context("when the metadata is not for a chaincode", func() { 189 BeforeEach(func() { 190 type badStruct struct{} 191 err := resources.Serializer.Serialize(lifecycle.NamespacesName, 192 "cc-name", 193 &badStruct{}, 194 fakePublicState, 195 ) 196 Expect(err).NotTo(HaveOccurred()) 197 }) 198 199 It("returns an error", func() { 200 _, _, err := resources.ChaincodeDefinitionIfDefined("cc-name", fakeReadableState) 201 Expect(err).To(MatchError("not a chaincode type: badStruct")) 202 }) 203 }) 204 205 Context("when the ledger returns an error", func() { 206 BeforeEach(func() { 207 fakeReadableState.GetStateReturns(nil, fmt.Errorf("state-error")) 208 }) 209 210 It("wraps and returns the error", func() { 211 _, _, err := resources.ChaincodeDefinitionIfDefined("cc-name", fakeReadableState) 212 Expect(err).To(MatchError("could not deserialize metadata for chaincode cc-name: could not query metadata for namespace namespaces/cc-name: state-error")) 213 }) 214 }) 215 }) 216 217 Describe("LifecycleEndorsementPolicyAsBytes", func() { 218 It("returns the endorsement policy for the lifecycle chaincode", func() { 219 b, err := resources.LifecycleEndorsementPolicyAsBytes("channel-id") 220 Expect(err).NotTo(HaveOccurred()) 221 Expect(b).NotTo(BeNil()) 222 policy := &cb.ApplicationPolicy{} 223 err = proto.Unmarshal(b, policy) 224 Expect(err).NotTo(HaveOccurred()) 225 Expect(policy.GetChannelConfigPolicyReference()).To(Equal("/Channel/Application/LifecycleEndorsement")) 226 }) 227 228 Context("when the endorsement policy reference is not found", func() { 229 BeforeEach(func() { 230 fakePolicyManager.GetPolicyReturns(nil, false) 231 }) 232 233 It("returns an error", func() { 234 b, err := resources.LifecycleEndorsementPolicyAsBytes("channel-id") 235 Expect(err).NotTo(HaveOccurred()) 236 policy := &cb.ApplicationPolicy{} 237 err = proto.Unmarshal(b, policy) 238 Expect(err).NotTo(HaveOccurred()) 239 Expect(policy.GetSignaturePolicy()).NotTo(BeNil()) 240 }) 241 242 Context("when the application config cannot be retrieved", func() { 243 BeforeEach(func() { 244 fakeChannelConfig.ApplicationConfigReturns(nil, false) 245 }) 246 247 It("returns an error", func() { 248 _, err := resources.LifecycleEndorsementPolicyAsBytes("channel-id") 249 Expect(err).To(MatchError("could not get application config for channel 'channel-id'")) 250 }) 251 }) 252 }) 253 254 Context("when the channel config cannot be retrieved", func() { 255 BeforeEach(func() { 256 fakeChannelConfigSource.GetStableChannelConfigReturns(nil) 257 }) 258 259 It("returns an error", func() { 260 _, err := resources.LifecycleEndorsementPolicyAsBytes("channel-id") 261 Expect(err).To(MatchError("could not get channel config for channel 'channel-id'")) 262 }) 263 }) 264 }) 265 }) 266 267 var _ = Describe("ExternalFunctions", func() { 268 var ( 269 resources *lifecycle.Resources 270 ef *lifecycle.ExternalFunctions 271 fakeCCStore *mock.ChaincodeStore 272 fakeChaincodeBuilder *mock.ChaincodeBuilder 273 fakeParser *mock.PackageParser 274 fakeListener *mock.InstallListener 275 fakeLister *mock.InstalledChaincodesLister 276 fakeChannelConfigSource *mock.ChannelConfigSource 277 fakeChannelConfig *mock.ChannelConfig 278 fakeApplicationConfig *mock.ApplicationConfig 279 fakeOrgConfigs []*mock.ApplicationOrgConfig 280 fakePolicyManager *mock.PolicyManager 281 ) 282 283 BeforeEach(func() { 284 fakeCCStore = &mock.ChaincodeStore{} 285 fakeChaincodeBuilder = &mock.ChaincodeBuilder{} 286 fakeParser = &mock.PackageParser{} 287 fakeListener = &mock.InstallListener{} 288 fakeLister = &mock.InstalledChaincodesLister{} 289 fakeChannelConfigSource = &mock.ChannelConfigSource{} 290 fakeChannelConfig = &mock.ChannelConfig{} 291 fakeChannelConfigSource.GetStableChannelConfigReturns(fakeChannelConfig) 292 fakeApplicationConfig = &mock.ApplicationConfig{} 293 fakeChannelConfig.ApplicationConfigReturns(fakeApplicationConfig, true) 294 fakeOrgConfigs = []*mock.ApplicationOrgConfig{{}, {}} 295 fakeOrgConfigs[0].MSPIDReturns("first-mspid") 296 fakeOrgConfigs[1].MSPIDReturns("second-mspid") 297 fakePolicyManager = &mock.PolicyManager{} 298 fakePolicyManager.GetPolicyReturns(nil, true) 299 fakeChannelConfig.PolicyManagerReturns(fakePolicyManager) 300 301 fakeApplicationConfig.OrganizationsReturns(map[string]channelconfig.ApplicationOrg{ 302 "org0": fakeOrgConfigs[0], 303 "org1": fakeOrgConfigs[1], 304 }) 305 306 resources = &lifecycle.Resources{ 307 PackageParser: fakeParser, 308 ChaincodeStore: fakeCCStore, 309 Serializer: &lifecycle.Serializer{}, 310 ChannelConfigSource: fakeChannelConfigSource, 311 } 312 313 ef = &lifecycle.ExternalFunctions{ 314 Resources: resources, 315 InstallListener: fakeListener, 316 InstalledChaincodesLister: fakeLister, 317 ChaincodeBuilder: fakeChaincodeBuilder, 318 BuildRegistry: &container.BuildRegistry{}, 319 } 320 }) 321 322 Describe("InstallChaincode", func() { 323 BeforeEach(func() { 324 fakeParser.ParseReturns(&persistence.ChaincodePackage{ 325 Metadata: &persistence.ChaincodePackageMetadata{ 326 Type: "cc-type", 327 Path: "cc-path", 328 Label: "cc-label", 329 }, 330 }, nil) 331 fakeCCStore.SaveReturns("fake-hash", nil) 332 }) 333 334 It("saves the chaincode", func() { 335 cc, err := ef.InstallChaincode([]byte("cc-package")) 336 Expect(err).NotTo(HaveOccurred()) 337 Expect(cc).To(Equal(&chaincode.InstalledChaincode{ 338 PackageID: "fake-hash", 339 Label: "cc-label", 340 })) 341 342 Expect(fakeParser.ParseCallCount()).To(Equal(1)) 343 Expect(fakeParser.ParseArgsForCall(0)).To(Equal([]byte("cc-package"))) 344 345 Expect(fakeCCStore.SaveCallCount()).To(Equal(1)) 346 name, msg := fakeCCStore.SaveArgsForCall(0) 347 Expect(name).To(Equal("cc-label")) 348 Expect(msg).To(Equal([]byte("cc-package"))) 349 350 Expect(fakeListener.HandleChaincodeInstalledCallCount()).To(Equal(1)) 351 md, packageID := fakeListener.HandleChaincodeInstalledArgsForCall(0) 352 Expect(md).To(Equal(&persistence.ChaincodePackageMetadata{ 353 Type: "cc-type", 354 Path: "cc-path", 355 Label: "cc-label", 356 })) 357 Expect(packageID).To(Equal("fake-hash")) 358 }) 359 360 It("builds the chaincode", func() { 361 _, err := ef.InstallChaincode([]byte("cc-package")) 362 Expect(err).NotTo(HaveOccurred()) 363 364 Expect(fakeChaincodeBuilder.BuildCallCount()).To(Equal(1)) 365 ccid := fakeChaincodeBuilder.BuildArgsForCall(0) 366 Expect(ccid).To(Equal("fake-hash")) 367 }) 368 369 When("building the chaincode fails", func() { 370 BeforeEach(func() { 371 fakeChaincodeBuilder.BuildReturns(fmt.Errorf("fake-build-error")) 372 }) 373 374 It("returns the wrapped error to the caller", func() { 375 _, err := ef.InstallChaincode([]byte("cc-package")) 376 Expect(err).To(MatchError("could not build chaincode: fake-build-error")) 377 }) 378 379 It("deletes the chaincode from disk", func() { 380 ef.InstallChaincode([]byte("cc-package")) 381 Expect(fakeCCStore.DeleteCallCount()).To(Equal(1)) 382 Expect(fakeCCStore.DeleteArgsForCall(0)).To(Equal("fake-hash")) 383 }) 384 }) 385 386 When("the chaincode is already being built and succeeds", func() { 387 BeforeEach(func() { 388 bs, ok := ef.BuildRegistry.BuildStatus("fake-hash") 389 Expect(ok).To(BeFalse()) 390 bs.Notify(nil) 391 }) 392 393 It("does not attempt to rebuild it itself", func() { 394 _, err := ef.InstallChaincode([]byte("cc-package")) 395 Expect(err).To(MatchError("chaincode already successfully installed (package ID 'fake-hash')")) 396 Expect(fakeChaincodeBuilder.BuildCallCount()).To(Equal(0)) 397 }) 398 }) 399 400 When("the chaincode is already being built and fails", func() { 401 BeforeEach(func() { 402 bs, ok := ef.BuildRegistry.BuildStatus("fake-hash") 403 Expect(ok).To(BeFalse()) 404 bs.Notify(fmt.Errorf("fake-other-builder-error")) 405 }) 406 407 It("attempts to rebuild it itself", func() { 408 _, err := ef.InstallChaincode([]byte("cc-package")) 409 Expect(err).To(BeNil()) 410 Expect(fakeChaincodeBuilder.BuildCallCount()).To(Equal(1)) 411 }) 412 }) 413 414 Context("when the package does not have metadata", func() { 415 BeforeEach(func() { 416 fakeParser.ParseReturns(&persistence.ChaincodePackage{}, nil) 417 }) 418 419 It("wraps and returns the error", func() { 420 hash, err := ef.InstallChaincode([]byte("fake-package")) 421 Expect(hash).To(BeNil()) 422 Expect(err.Error()).To(ContainSubstring("empty metadata for supplied chaincode")) 423 }) 424 }) 425 426 Context("when saving the chaincode fails", func() { 427 BeforeEach(func() { 428 fakeCCStore.SaveReturns("", fmt.Errorf("fake-error")) 429 }) 430 431 It("wraps and returns the error", func() { 432 cc, err := ef.InstallChaincode([]byte("cc-package")) 433 Expect(cc).To(BeNil()) 434 Expect(err).To(MatchError("could not save cc install package: fake-error")) 435 }) 436 }) 437 438 Context("when parsing the chaincode package fails", func() { 439 BeforeEach(func() { 440 fakeParser.ParseReturns(nil, fmt.Errorf("parse-error")) 441 }) 442 443 It("wraps and returns the error", func() { 444 hash, err := ef.InstallChaincode([]byte("fake-package")) 445 Expect(hash).To(BeNil()) 446 Expect(err).To(MatchError("could not parse as a chaincode install package: parse-error")) 447 }) 448 }) 449 }) 450 451 Describe("GetInstalledChaincodePackage", func() { 452 BeforeEach(func() { 453 fakeCCStore.LoadReturns([]byte("code-package"), nil) 454 }) 455 456 It("returns the chaincode install package", func() { 457 pkgBytes, err := ef.GetInstalledChaincodePackage("some-package-id") 458 Expect(err).NotTo(HaveOccurred()) 459 Expect(pkgBytes).To(Equal([]byte("code-package"))) 460 461 Expect(fakeCCStore.LoadCallCount()).To(Equal(1)) 462 packageID := fakeCCStore.LoadArgsForCall(0) 463 Expect(packageID).To(Equal("some-package-id")) 464 }) 465 466 Context("when loading the chaincode fails", func() { 467 BeforeEach(func() { 468 fakeCCStore.LoadReturns(nil, fmt.Errorf("fake-error")) 469 }) 470 471 It("wraps and returns the error", func() { 472 pkgBytes, err := ef.GetInstalledChaincodePackage("some-package-id") 473 Expect(pkgBytes).To(BeNil()) 474 Expect(err).To(MatchError("could not load cc install package: fake-error")) 475 }) 476 }) 477 }) 478 479 Describe("QueryInstalledChaincode", func() { 480 BeforeEach(func() { 481 fakeLister.GetInstalledChaincodeReturns(&chaincode.InstalledChaincode{ 482 Label: "installed-cc2", 483 PackageID: "installed-package-id2", 484 References: map[string][]*chaincode.Metadata{ 485 "test-channel": { 486 &chaincode.Metadata{ 487 Name: "test-chaincode", 488 Version: "test-version", 489 }, 490 &chaincode.Metadata{ 491 Name: "hello-chaincode", 492 Version: "hello-version", 493 }, 494 }, 495 "another-channel": { 496 &chaincode.Metadata{ 497 Name: "another-chaincode", 498 Version: "another-version", 499 }, 500 }, 501 }, 502 }, nil) 503 }) 504 505 It("returns installed chaincode information", func() { 506 result, err := ef.QueryInstalledChaincode("installed-package-id2") 507 Expect(err).NotTo(HaveOccurred()) 508 Expect(result).To(Equal( 509 &chaincode.InstalledChaincode{ 510 Label: "installed-cc2", 511 PackageID: "installed-package-id2", 512 References: map[string][]*chaincode.Metadata{ 513 "test-channel": { 514 &chaincode.Metadata{ 515 Name: "test-chaincode", 516 Version: "test-version", 517 }, 518 &chaincode.Metadata{ 519 Name: "hello-chaincode", 520 Version: "hello-version", 521 }, 522 }, 523 "another-channel": { 524 &chaincode.Metadata{ 525 Name: "another-chaincode", 526 Version: "another-version", 527 }, 528 }, 529 }, 530 }, 531 )) 532 }) 533 534 Context("when the chaincode isn't installed", func() { 535 BeforeEach(func() { 536 fakeLister.GetInstalledChaincodeReturns(nil, errors.New("another-fake-error")) 537 }) 538 539 It("returns an error", func() { 540 result, err := ef.QueryInstalledChaincode("not-there") 541 Expect(err.Error()).To(Equal("another-fake-error")) 542 Expect(result).To(BeNil()) 543 }) 544 }) 545 }) 546 547 Describe("QueryInstalledChaincodes", func() { 548 var chaincodes []*chaincode.InstalledChaincode 549 550 BeforeEach(func() { 551 chaincodes = []*chaincode.InstalledChaincode{ 552 { 553 Label: "installed-cc1", 554 PackageID: "installed-package-id1", 555 }, 556 { 557 Label: "installed-cc2", 558 PackageID: "installed-package-id2", 559 References: map[string][]*chaincode.Metadata{ 560 "test-channel": { 561 &chaincode.Metadata{ 562 Name: "test-chaincode", 563 Version: "test-version", 564 }, 565 &chaincode.Metadata{ 566 Name: "hello-chaincode", 567 Version: "hello-version", 568 }, 569 }, 570 "another-channel": { 571 &chaincode.Metadata{ 572 Name: "another-chaincode", 573 Version: "another-version", 574 }, 575 }, 576 }, 577 }, 578 } 579 580 fakeLister.ListInstalledChaincodesReturns(chaincodes) 581 }) 582 583 It("passes through to the cache", func() { 584 result := ef.QueryInstalledChaincodes() 585 Expect(result).To(ConsistOf( 586 &chaincode.InstalledChaincode{ 587 Label: "installed-cc1", 588 PackageID: "installed-package-id1", 589 }, 590 &chaincode.InstalledChaincode{ 591 Label: "installed-cc2", 592 PackageID: "installed-package-id2", 593 References: map[string][]*chaincode.Metadata{ 594 "test-channel": { 595 &chaincode.Metadata{ 596 Name: "test-chaincode", 597 Version: "test-version", 598 }, 599 &chaincode.Metadata{ 600 Name: "hello-chaincode", 601 Version: "hello-version", 602 }, 603 }, 604 "another-channel": { 605 &chaincode.Metadata{ 606 Name: "another-chaincode", 607 Version: "another-version", 608 }, 609 }, 610 }, 611 }, 612 )) 613 }) 614 }) 615 616 Describe("ApproveChaincodeDefinitionForOrg", func() { 617 var ( 618 fakePublicState *mock.ReadWritableState 619 fakeOrgState *mock.ReadWritableState 620 621 fakeOrgKVStore MapLedgerShim 622 fakePublicKVStore MapLedgerShim 623 624 testDefinition *lifecycle.ChaincodeDefinition 625 ) 626 627 BeforeEach(func() { 628 testDefinition = &lifecycle.ChaincodeDefinition{ 629 Sequence: 5, 630 EndorsementInfo: &lb.ChaincodeEndorsementInfo{ 631 Version: "version", 632 EndorsementPlugin: "my endorsement plugin", 633 }, 634 ValidationInfo: &lb.ChaincodeValidationInfo{ 635 ValidationPlugin: "my validation plugin", 636 ValidationParameter: []byte("some awesome policy"), 637 }, 638 Collections: &pb.CollectionConfigPackage{}, 639 } 640 641 fakePublicState = &mock.ReadWritableState{} 642 fakePublicKVStore = MapLedgerShim(map[string][]byte{}) 643 fakePublicState = &mock.ReadWritableState{} 644 fakePublicState.PutStateStub = fakePublicKVStore.PutState 645 fakePublicState.GetStateStub = fakePublicKVStore.GetState 646 647 fakeOrgKVStore = MapLedgerShim(map[string][]byte{}) 648 fakeOrgState = &mock.ReadWritableState{} 649 fakeOrgState.PutStateStub = fakeOrgKVStore.PutState 650 fakeOrgState.GetStateStub = fakeOrgKVStore.GetState 651 652 err := resources.Serializer.Serialize("namespaces", "cc-name", &lifecycle.ChaincodeDefinition{ 653 Sequence: 4, 654 }, fakePublicKVStore) 655 Expect(err).NotTo(HaveOccurred()) 656 }) 657 658 It("serializes the chaincode parameters to the org scoped collection", func() { 659 err := ef.ApproveChaincodeDefinitionForOrg("my-channel", "cc-name", testDefinition, "hash", fakePublicState, fakeOrgState) 660 Expect(err).NotTo(HaveOccurred()) 661 662 metadata, ok, err := resources.Serializer.DeserializeMetadata("namespaces", "cc-name#5", fakeOrgState) 663 Expect(err).NotTo(HaveOccurred()) 664 Expect(ok).To(BeTrue()) 665 committedDefinition := &lifecycle.ChaincodeParameters{} 666 err = resources.Serializer.Deserialize("namespaces", "cc-name#5", metadata, committedDefinition, fakeOrgState) 667 Expect(err).NotTo(HaveOccurred()) 668 Expect(committedDefinition.EndorsementInfo.Version).To(Equal("version")) 669 Expect(committedDefinition.EndorsementInfo.EndorsementPlugin).To(Equal("my endorsement plugin")) 670 Expect(proto.Equal(committedDefinition.ValidationInfo, &lb.ChaincodeValidationInfo{ 671 ValidationPlugin: "my validation plugin", 672 ValidationParameter: []byte("some awesome policy"), 673 })).To(BeTrue()) 674 Expect(proto.Equal(committedDefinition.Collections, &pb.CollectionConfigPackage{})).To(BeTrue()) 675 676 metadata, ok, err = resources.Serializer.DeserializeMetadata("chaincode-sources", "cc-name#5", fakeOrgState) 677 Expect(err).NotTo(HaveOccurred()) 678 Expect(ok).To(BeTrue()) 679 localPackage := &lifecycle.ChaincodeLocalPackage{} 680 err = resources.Serializer.Deserialize("chaincode-sources", "cc-name#5", metadata, localPackage, fakeOrgState) 681 Expect(err).NotTo(HaveOccurred()) 682 Expect(localPackage).To(Equal(&lifecycle.ChaincodeLocalPackage{ 683 PackageID: "hash", 684 })) 685 }) 686 687 Context("when the peer sets defaults", func() { 688 BeforeEach(func() { 689 testDefinition.EndorsementInfo.EndorsementPlugin = "" 690 testDefinition.ValidationInfo.ValidationPlugin = "" 691 testDefinition.ValidationInfo.ValidationParameter = nil 692 }) 693 694 It("uses appropriate defaults", func() { 695 err := ef.ApproveChaincodeDefinitionForOrg("my-channel", "cc-name", testDefinition, "hash", fakePublicState, fakeOrgState) 696 Expect(err).NotTo(HaveOccurred()) 697 698 metadata, ok, err := resources.Serializer.DeserializeMetadata("namespaces", "cc-name#5", fakeOrgState) 699 Expect(err).NotTo(HaveOccurred()) 700 Expect(ok).To(BeTrue()) 701 committedDefinition := &lifecycle.ChaincodeParameters{} 702 err = resources.Serializer.Deserialize("namespaces", "cc-name#5", metadata, committedDefinition, fakeOrgState) 703 Expect(err).NotTo(HaveOccurred()) 704 Expect(committedDefinition.EndorsementInfo.Version).To(Equal("version")) 705 Expect(committedDefinition.EndorsementInfo.EndorsementPlugin).To(Equal("escc")) 706 Expect(proto.Equal(committedDefinition.ValidationInfo, &lb.ChaincodeValidationInfo{ 707 ValidationPlugin: "vscc", 708 ValidationParameter: protoutil.MarshalOrPanic( 709 &pb.ApplicationPolicy{ 710 Type: &pb.ApplicationPolicy_ChannelConfigPolicyReference{ 711 ChannelConfigPolicyReference: "/Channel/Application/Endorsement", 712 }, 713 }), 714 })).To(BeTrue()) 715 Expect(proto.Equal(committedDefinition.Collections, &pb.CollectionConfigPackage{})).To(BeTrue()) 716 }) 717 718 Context("when no default endorsement policy is defined on thc channel", func() { 719 BeforeEach(func() { 720 fakePolicyManager.GetPolicyReturns(nil, false) 721 }) 722 723 It("returns an error", func() { 724 err := ef.ApproveChaincodeDefinitionForOrg("my-channel", "cc-name", testDefinition, "hash", fakePublicState, fakeOrgState) 725 Expect(err).To(MatchError(ContainSubstring("could not set defaults for chaincode definition in channel my-channel: policy '/Channel/Application/Endorsement' must be defined for channel 'my-channel' before chaincode operations can be attempted"))) 726 }) 727 }) 728 729 Context("when obtaining a stable channel config fails", func() { 730 BeforeEach(func() { 731 fakeChannelConfigSource.GetStableChannelConfigReturns(nil) 732 }) 733 734 It("returns an error", func() { 735 err := ef.ApproveChaincodeDefinitionForOrg("my-channel", "cc-name", testDefinition, "hash", fakePublicState, fakeOrgState) 736 Expect(err).To(MatchError(ContainSubstring("could not get channel config for channel 'my-channel'"))) 737 }) 738 }) 739 }) 740 741 Context("when the current sequence is undefined and the requested sequence is 0", func() { 742 BeforeEach(func() { 743 fakePublicKVStore = map[string][]byte{} 744 }) 745 746 It("returns an error", func() { 747 err := ef.ApproveChaincodeDefinitionForOrg("my-channel", "unknown-name", &lifecycle.ChaincodeDefinition{}, "hash", fakePublicState, fakeOrgState) 748 Expect(err).To(MatchError("requested sequence is 0, but first definable sequence number is 1")) 749 }) 750 }) 751 752 Context("when the sequence number already has a committed definition", func() { 753 BeforeEach(func() { 754 err := resources.Serializer.Serialize("namespaces", "cc-name", &lifecycle.ChaincodeDefinition{ 755 Sequence: 5, 756 EndorsementInfo: &lb.ChaincodeEndorsementInfo{ 757 Version: "version", 758 EndorsementPlugin: "my endorsement plugin", 759 }, 760 ValidationInfo: &lb.ChaincodeValidationInfo{ 761 ValidationPlugin: "my validation plugin", 762 ValidationParameter: []byte("some awesome policy"), 763 }, 764 }, fakePublicState) 765 Expect(err).NotTo(HaveOccurred()) 766 }) 767 768 It("verifies that the definition matches before writing", func() { 769 err := ef.ApproveChaincodeDefinitionForOrg("my-channel", "cc-name", testDefinition, "hash", fakePublicState, fakeOrgState) 770 Expect(err).NotTo(HaveOccurred()) 771 }) 772 773 Context("when the current definition is not found", func() { 774 BeforeEach(func() { 775 delete(fakePublicKVStore, "namespaces/metadata/cc-name") 776 }) 777 778 It("returns an error", func() { 779 err := ef.ApproveChaincodeDefinitionForOrg("my-channel", "cc-name", testDefinition, "hash", fakePublicState, fakeOrgState) 780 Expect(err).To(MatchError("missing metadata for currently committed sequence number (5)")) 781 }) 782 }) 783 784 Context("when the current definition is corrupt", func() { 785 BeforeEach(func() { 786 fakePublicKVStore["namespaces/metadata/cc-name"] = []byte("garbage") 787 }) 788 789 It("returns an error", func() { 790 err := ef.ApproveChaincodeDefinitionForOrg("my-channel", "cc-name", testDefinition, "hash", fakePublicState, fakeOrgState) 791 Expect(err).To(MatchError("could not fetch metadata for current definition: could not unmarshal metadata for namespace namespaces/cc-name: proto: can't skip unknown wire type 7")) 792 }) 793 }) 794 795 Context("when the current definition is not a chaincode", func() { 796 BeforeEach(func() { 797 fakePublicKVStore = map[string][]byte{} 798 type OtherStruct struct { 799 Sequence int64 800 } 801 err := resources.Serializer.Serialize("namespaces", "cc-name", &OtherStruct{ 802 Sequence: 5, 803 }, fakePublicState) 804 Expect(err).NotTo(HaveOccurred()) 805 }) 806 807 It("returns an error", func() { 808 err := ef.ApproveChaincodeDefinitionForOrg("my-channel", "cc-name", testDefinition, "hash", fakePublicState, fakeOrgState) 809 Expect(err).To(MatchError("could not deserialize namespace cc-name as chaincode: type name mismatch 'ChaincodeDefinition' != 'OtherStruct'")) 810 }) 811 }) 812 813 Context("when the Version in the new definition differs from the current definition", func() { 814 BeforeEach(func() { 815 fakePublicKVStore = map[string][]byte{} 816 817 err := resources.Serializer.Serialize("namespaces", "cc-name", &lifecycle.ChaincodeDefinition{ 818 Sequence: 5, 819 EndorsementInfo: &lb.ChaincodeEndorsementInfo{ 820 Version: "other-version", 821 }, 822 }, fakePublicState) 823 Expect(err).NotTo(HaveOccurred()) 824 }) 825 826 It("returns an error", func() { 827 err := ef.ApproveChaincodeDefinitionForOrg("my-channel", "cc-name", testDefinition, "hash", fakePublicState, fakeOrgState) 828 Expect(err).To(MatchError("attempted to redefine the current committed sequence (5) for namespace cc-name with different parameters: expected Version 'other-version' does not match passed Version 'version'")) 829 }) 830 }) 831 }) 832 833 Context("when the sequence number already has an uncommitted definition", func() { 834 BeforeEach(func() { 835 err := ef.ApproveChaincodeDefinitionForOrg("my-channel", "cc-name", testDefinition, "hash", fakePublicState, fakeOrgState) 836 Expect(err).NotTo(HaveOccurred()) 837 }) 838 839 Context("when uncommitted definition differs from update", func() { 840 It("succeeds", func() { 841 testDefinition.ValidationInfo.ValidationParameter = []byte("more awesome policy") 842 err := ef.ApproveChaincodeDefinitionForOrg("my-channel", "cc-name", testDefinition, "hash", fakePublicState, fakeOrgState) 843 Expect(err).NotTo(HaveOccurred()) 844 }) 845 }) 846 847 Context("when uncommitted definition is identical to update", func() { 848 It("returns error", func() { 849 err := ef.ApproveChaincodeDefinitionForOrg("my-channel", "cc-name", testDefinition, "hash", fakePublicState, fakeOrgState) 850 Expect(err).To(MatchError("attempted to redefine uncommitted sequence (5) for namespace cc-name with unchanged content")) 851 }) 852 }) 853 854 Context("when uncommitted definition has update of only package ID", func() { 855 It("succeeds", func() { 856 err := ef.ApproveChaincodeDefinitionForOrg("my-channel", "cc-name", testDefinition, "hash2", fakePublicState, fakeOrgState) 857 Expect(err).NotTo(HaveOccurred()) 858 }) 859 }) 860 861 Context("when deserializing chaincode-source metadata fails", func() { 862 BeforeEach(func() { 863 fakeOrgKVStore["chaincode-sources/metadata/cc-name#5"] = []byte("garbage") 864 }) 865 866 It("wraps and returns the error", func() { 867 err := ef.ApproveChaincodeDefinitionForOrg("my-channel", "cc-name", testDefinition, "hash", fakePublicState, fakeOrgState) 868 Expect(err).To(MatchError("could not deserialize chaincode-source metadata for cc-name#5: could not unmarshal metadata for namespace chaincode-sources/cc-name#5: proto: can't skip unknown wire type 7")) 869 }) 870 }) 871 872 Context("when deserializing chaincode package fails", func() { 873 BeforeEach(func() { 874 fakeOrgKVStore["chaincode-sources/fields/cc-name#5/PackageID"] = []byte("garbage") 875 }) 876 877 It("wraps and returns the error", func() { 878 err := ef.ApproveChaincodeDefinitionForOrg("my-channel", "cc-name", testDefinition, "hash", fakePublicState, fakeOrgState) 879 Expect(err).To(MatchError("could not deserialize chaincode package for cc-name#5: could not unmarshal state for key chaincode-sources/fields/cc-name#5/PackageID: proto: can't skip unknown wire type 7")) 880 }) 881 }) 882 }) 883 884 Context("when the definition is for an expired sequence number", func() { 885 BeforeEach(func() { 886 testDefinition.Sequence = 3 887 }) 888 889 It("fails", func() { 890 err := ef.ApproveChaincodeDefinitionForOrg("my-channel", "cc-name", testDefinition, "hash", fakePublicState, fakeOrgState) 891 Expect(err).To(MatchError("currently defined sequence 4 is larger than requested sequence 3")) 892 }) 893 }) 894 895 Context("when the definition is for a distant sequence number", func() { 896 BeforeEach(func() { 897 testDefinition.Sequence = 9 898 }) 899 900 It("fails", func() { 901 err := ef.ApproveChaincodeDefinitionForOrg("my-channel", "cc-name", testDefinition, "hash", fakePublicState, fakeOrgState) 902 Expect(err).To(MatchError("requested sequence 9 is larger than the next available sequence number 5")) 903 }) 904 }) 905 906 Context("when querying the public state fails", func() { 907 BeforeEach(func() { 908 fakePublicState.GetStateReturns(nil, fmt.Errorf("get-state-error")) 909 }) 910 911 It("wraps and returns the error", func() { 912 err := ef.ApproveChaincodeDefinitionForOrg("my-channel", "cc-name", testDefinition, "hash", fakePublicState, fakeOrgState) 913 Expect(err).To(MatchError("could not get current sequence: could not get state for key namespaces/fields/cc-name/Sequence: get-state-error")) 914 }) 915 }) 916 917 Context("when writing to the org state fails for the parameters", func() { 918 BeforeEach(func() { 919 fakeOrgState.PutStateReturns(fmt.Errorf("put-state-error")) 920 }) 921 922 It("wraps and returns the error", func() { 923 err := ef.ApproveChaincodeDefinitionForOrg("my-channel", "cc-name", testDefinition, "hash", fakePublicState, fakeOrgState) 924 Expect(err).To(MatchError("could not serialize chaincode parameters to state: could not write key into state: put-state-error")) 925 }) 926 }) 927 928 Context("when writing to the org state fails for the package", func() { 929 BeforeEach(func() { 930 fakeOrgState.PutStateReturnsOnCall(4, fmt.Errorf("put-state-error")) 931 }) 932 933 It("wraps and returns the error", func() { 934 err := ef.ApproveChaincodeDefinitionForOrg("my-channel", "cc-name", testDefinition, "hash", fakePublicState, fakeOrgState) 935 Expect(err).To(MatchError("could not serialize chaincode package info to state: could not write key into state: put-state-error")) 936 }) 937 }) 938 }) 939 940 Describe("CheckCommitReadiness", func() { 941 var ( 942 fakePublicState *mock.ReadWritableState 943 fakeOrgStates []*mock.ReadWritableState 944 945 testDefinition *lifecycle.ChaincodeDefinition 946 947 publicKVS, org0KVS, org1KVS MapLedgerShim 948 ) 949 950 BeforeEach(func() { 951 testDefinition = &lifecycle.ChaincodeDefinition{ 952 Sequence: 5, 953 EndorsementInfo: &lb.ChaincodeEndorsementInfo{ 954 Version: "version", 955 EndorsementPlugin: "endorsement-plugin", 956 }, 957 ValidationInfo: &lb.ChaincodeValidationInfo{ 958 ValidationPlugin: "validation-plugin", 959 ValidationParameter: []byte("validation-parameter"), 960 }, 961 } 962 963 publicKVS = MapLedgerShim(map[string][]byte{}) 964 fakePublicState = &mock.ReadWritableState{} 965 fakePublicState.GetStateStub = publicKVS.GetState 966 fakePublicState.PutStateStub = publicKVS.PutState 967 968 resources.Serializer.Serialize("namespaces", "cc-name", &lifecycle.ChaincodeDefinition{ 969 Sequence: 4, 970 EndorsementInfo: &lb.ChaincodeEndorsementInfo{ 971 Version: "version", 972 EndorsementPlugin: "endorsement-plugin", 973 }, 974 ValidationInfo: &lb.ChaincodeValidationInfo{ 975 ValidationPlugin: "validation-plugin", 976 ValidationParameter: []byte("validation-parameter"), 977 }, 978 }, publicKVS) 979 980 org0KVS = MapLedgerShim(map[string][]byte{}) 981 org1KVS = MapLedgerShim(map[string][]byte{}) 982 fakeOrg0State := &mock.ReadWritableState{} 983 fakeOrg0State.CollectionNameReturns("_implicit_org_org0") 984 fakeOrg1State := &mock.ReadWritableState{} 985 fakeOrg1State.CollectionNameReturns("_implicit_org_org1") 986 fakeOrgStates = []*mock.ReadWritableState{ 987 fakeOrg0State, 988 fakeOrg1State, 989 } 990 for i, kvs := range []MapLedgerShim{org0KVS, org1KVS} { 991 kvs := kvs 992 fakeOrgStates[i].GetStateStub = kvs.GetState 993 fakeOrgStates[i].GetStateHashStub = kvs.GetStateHash 994 fakeOrgStates[i].PutStateStub = kvs.PutState 995 } 996 997 resources.Serializer.Serialize("namespaces", "cc-name#5", testDefinition.Parameters(), fakeOrgStates[0]) 998 resources.Serializer.Serialize("namespaces", "cc-name#5", &lifecycle.ChaincodeParameters{}, fakeOrgStates[1]) 999 }) 1000 1001 It("checks the commit readiness of a chaincode definition and returns the approvals", func() { 1002 approvals, err := ef.CheckCommitReadiness("my-channel", "cc-name", testDefinition, fakePublicState, []lifecycle.OpaqueState{fakeOrgStates[0], fakeOrgStates[1]}) 1003 Expect(err).NotTo(HaveOccurred()) 1004 Expect(approvals).To(Equal(map[string]bool{ 1005 "org0": true, 1006 "org1": false, 1007 })) 1008 }) 1009 1010 Context("when IsSerialized fails", func() { 1011 BeforeEach(func() { 1012 fakeOrgStates[0].GetStateHashReturns(nil, errors.New("bad bad failure")) 1013 }) 1014 1015 It("wraps and returns an error", func() { 1016 _, err := ef.CheckCommitReadiness("my-channel", "cc-name", testDefinition, fakePublicState, []lifecycle.OpaqueState{fakeOrgStates[0], fakeOrgStates[1]}) 1017 Expect(err).To(MatchError(ContainSubstring("serialization check failed for key cc-name#5: could not get value for key namespaces/metadata/cc-name#5: bad bad failure"))) 1018 }) 1019 }) 1020 1021 Context("when the peer sets defaults", func() { 1022 BeforeEach(func() { 1023 testDefinition.EndorsementInfo.EndorsementPlugin = "escc" 1024 testDefinition.ValidationInfo.ValidationPlugin = "vscc" 1025 testDefinition.ValidationInfo.ValidationParameter = protoutil.MarshalOrPanic( 1026 &pb.ApplicationPolicy{ 1027 Type: &pb.ApplicationPolicy_ChannelConfigPolicyReference{ 1028 ChannelConfigPolicyReference: "/Channel/Application/Endorsement", 1029 }, 1030 }) 1031 1032 resources.Serializer.Serialize("namespaces", "cc-name#5", testDefinition.Parameters(), fakeOrgStates[0]) 1033 1034 testDefinition.EndorsementInfo.EndorsementPlugin = "" 1035 testDefinition.ValidationInfo.ValidationPlugin = "" 1036 testDefinition.ValidationInfo.ValidationParameter = nil 1037 1038 resources.Serializer.Serialize("namespaces", "cc-name#5", testDefinition.Parameters(), fakeOrgStates[1]) 1039 }) 1040 1041 It("applies the chaincode definition and returns the approvals", func() { 1042 approvals, err := ef.CheckCommitReadiness("my-channel", "cc-name", testDefinition, fakePublicState, []lifecycle.OpaqueState{fakeOrgStates[0], fakeOrgStates[1]}) 1043 Expect(err).NotTo(HaveOccurred()) 1044 Expect(approvals).To(Equal(map[string]bool{ 1045 "org0": true, 1046 "org1": false, 1047 })) 1048 }) 1049 1050 Context("when no default endorsement policy is defined on the channel", func() { 1051 BeforeEach(func() { 1052 fakePolicyManager.GetPolicyReturns(nil, false) 1053 }) 1054 1055 It("returns an error", func() { 1056 _, err := ef.CheckCommitReadiness("my-channel", "cc-name", testDefinition, fakePublicState, []lifecycle.OpaqueState{fakeOrgStates[0], fakeOrgStates[1]}) 1057 Expect(err).To(MatchError(ContainSubstring("could not set defaults for chaincode definition in " + 1058 "channel my-channel: policy '/Channel/Application/Endorsement' must be defined " + 1059 "for channel 'my-channel' before chaincode operations can be attempted"))) 1060 }) 1061 }) 1062 1063 Context("when obtaining a stable channel config fails", func() { 1064 BeforeEach(func() { 1065 fakeChannelConfigSource.GetStableChannelConfigReturns(nil) 1066 }) 1067 1068 It("returns an error", func() { 1069 _, err := ef.CheckCommitReadiness("my-channel", "cc-name", testDefinition, fakePublicState, []lifecycle.OpaqueState{fakeOrgStates[0], fakeOrgStates[1]}) 1070 Expect(err).To(MatchError(ContainSubstring("could not get channel config for channel 'my-channel'"))) 1071 }) 1072 }) 1073 1074 Context("when the public state is not readable", func() { 1075 BeforeEach(func() { 1076 fakePublicState.GetStateReturns(nil, fmt.Errorf("getstate-error")) 1077 }) 1078 1079 It("wraps and returns the error", func() { 1080 _, err := ef.CheckCommitReadiness("my-channel", "cc-name", testDefinition, fakePublicState, []lifecycle.OpaqueState{fakeOrgStates[0], fakeOrgStates[1]}) 1081 Expect(err).To(MatchError("could not get current sequence: could not get state for key namespaces/fields/cc-name/Sequence: getstate-error")) 1082 }) 1083 }) 1084 1085 Context("when the current sequence is not immediately prior to the new", func() { 1086 BeforeEach(func() { 1087 resources.Serializer.Serialize("namespaces", "cc-name", &lifecycle.ChaincodeDefinition{ 1088 Sequence: 3, 1089 EndorsementInfo: &lb.ChaincodeEndorsementInfo{ 1090 Version: "version", 1091 EndorsementPlugin: "endorsement-plugin", 1092 }, 1093 ValidationInfo: &lb.ChaincodeValidationInfo{ 1094 ValidationPlugin: "validation-plugin", 1095 ValidationParameter: []byte("validation-parameter"), 1096 }, 1097 }, fakePublicState) 1098 }) 1099 1100 It("returns an error", func() { 1101 _, err := ef.CheckCommitReadiness("my-channel", "cc-name", testDefinition, fakePublicState, []lifecycle.OpaqueState{fakeOrgStates[0], fakeOrgStates[1]}) 1102 Expect(err).To(MatchError("requested sequence is 5, but new definition must be sequence 4")) 1103 }) 1104 }) 1105 }) 1106 }) 1107 1108 Describe("QueryApprovedChaincodeDefinition", func() { 1109 var ( 1110 fakePublicState *mock.ReadWritableState 1111 fakeOrgStates []*mock.ReadWritableState 1112 1113 testDefinition *lifecycle.ChaincodeDefinition 1114 testChaincodeLocalPackage *lifecycle.ChaincodeLocalPackage 1115 1116 publicKVS, org0KVS, org1KVS MapLedgerShim 1117 ) 1118 1119 BeforeEach(func() { 1120 testDefinition = &lifecycle.ChaincodeDefinition{ 1121 Sequence: 4, 1122 EndorsementInfo: &lb.ChaincodeEndorsementInfo{ 1123 Version: "version", 1124 EndorsementPlugin: "endorsement-plugin", 1125 }, 1126 ValidationInfo: &lb.ChaincodeValidationInfo{ 1127 ValidationPlugin: "validation-plugin", 1128 ValidationParameter: []byte("validation-parameter"), 1129 }, 1130 } 1131 1132 testChaincodeLocalPackage = &lifecycle.ChaincodeLocalPackage{ 1133 PackageID: "hash", 1134 } 1135 1136 publicKVS = MapLedgerShim(map[string][]byte{}) 1137 fakePublicState = &mock.ReadWritableState{} 1138 fakePublicState.GetStateStub = publicKVS.GetState 1139 fakePublicState.PutStateStub = publicKVS.PutState 1140 1141 resources.Serializer.Serialize("namespaces", "cc-name", testDefinition, publicKVS) 1142 1143 org0KVS = MapLedgerShim(map[string][]byte{}) 1144 org1KVS = MapLedgerShim(map[string][]byte{}) 1145 fakeOrg0State := &mock.ReadWritableState{} 1146 fakeOrg0State.CollectionNameReturns("_implicit_org_org0") 1147 fakeOrg1State := &mock.ReadWritableState{} 1148 fakeOrg1State.CollectionNameReturns("_implicit_org_org1") 1149 fakeOrgStates = []*mock.ReadWritableState{ 1150 fakeOrg0State, 1151 fakeOrg1State, 1152 } 1153 for i, kvs := range []MapLedgerShim{org0KVS, org1KVS} { 1154 kvs := kvs 1155 fakeOrgStates[i].GetStateStub = kvs.GetState 1156 fakeOrgStates[i].GetStateHashStub = kvs.GetStateHash 1157 fakeOrgStates[i].PutStateStub = kvs.PutState 1158 } 1159 1160 resources.Serializer.Serialize("namespaces", "cc-name#3", testDefinition.Parameters(), fakeOrgStates[0]) 1161 resources.Serializer.Serialize("chaincode-sources", "cc-name#3", testChaincodeLocalPackage, fakeOrgStates[0]) 1162 resources.Serializer.Serialize("namespaces", "cc-name#3", testDefinition.Parameters(), fakeOrgStates[1]) 1163 resources.Serializer.Serialize("chaincode-sources", "cc-name#3", testChaincodeLocalPackage, fakeOrgStates[1]) 1164 1165 resources.Serializer.Serialize("namespaces", "cc-name#4", testDefinition.Parameters(), fakeOrgStates[0]) 1166 resources.Serializer.Serialize("chaincode-sources", "cc-name#4", testChaincodeLocalPackage, fakeOrgStates[0]) 1167 resources.Serializer.Serialize("namespaces", "cc-name#4", testDefinition.Parameters(), fakeOrgStates[1]) 1168 resources.Serializer.Serialize("chaincode-sources", "cc-name#4", testChaincodeLocalPackage, fakeOrgStates[1]) 1169 }) 1170 1171 It("returns the approved chaincode", func() { 1172 cc, err := ef.QueryApprovedChaincodeDefinition("my-channel", "cc-name", 3, fakePublicState, fakeOrgStates[0]) 1173 Expect(err).NotTo(HaveOccurred()) 1174 Expect(cc.Sequence).To(Equal(int64(3))) 1175 Expect(proto.Equal(cc.EndorsementInfo, &lb.ChaincodeEndorsementInfo{ 1176 Version: "version", 1177 EndorsementPlugin: "endorsement-plugin", 1178 })).To(BeTrue()) 1179 Expect(proto.Equal(cc.ValidationInfo, &lb.ChaincodeValidationInfo{ 1180 ValidationPlugin: "validation-plugin", 1181 ValidationParameter: []byte("validation-parameter"), 1182 })).To(BeTrue()) 1183 Expect(proto.Equal(cc.Collections, &pb.CollectionConfigPackage{})).To(BeTrue()) 1184 Expect(proto.Equal(cc.Source, &lb.ChaincodeSource{ 1185 Type: &lb.ChaincodeSource_LocalPackage{ 1186 LocalPackage: &lb.ChaincodeSource_Local{ 1187 PackageId: "hash", 1188 }, 1189 }, 1190 })).To(BeTrue()) 1191 }) 1192 1193 Context("when the next sequence is not defined and the sequence argument is not provided", func() { 1194 It("returns the approved chaincode for the current sequence", func() { 1195 cc, err := ef.QueryApprovedChaincodeDefinition("my-channel", "cc-name", 0, fakePublicState, fakeOrgStates[0]) 1196 Expect(err).NotTo(HaveOccurred()) 1197 Expect(cc.Sequence).To(Equal(int64(4))) 1198 Expect(proto.Equal(cc.EndorsementInfo, &lb.ChaincodeEndorsementInfo{ 1199 Version: "version", 1200 EndorsementPlugin: "endorsement-plugin", 1201 })).To(BeTrue()) 1202 Expect(proto.Equal(cc.ValidationInfo, &lb.ChaincodeValidationInfo{ 1203 ValidationPlugin: "validation-plugin", 1204 ValidationParameter: []byte("validation-parameter"), 1205 })).To(BeTrue()) 1206 Expect(proto.Equal(cc.Collections, &pb.CollectionConfigPackage{})).To(BeTrue()) 1207 Expect(proto.Equal(cc.Source, &lb.ChaincodeSource{ 1208 Type: &lb.ChaincodeSource_LocalPackage{ 1209 LocalPackage: &lb.ChaincodeSource_Local{ 1210 PackageId: "hash", 1211 }, 1212 }, 1213 })).To(BeTrue()) 1214 }) 1215 }) 1216 1217 Context("when the next sequence is defined and the sequence argument is not provided", func() { 1218 BeforeEach(func() { 1219 testChaincodeLocalPackage.PackageID = "" 1220 resources.Serializer.Serialize("namespaces", "cc-name#5", testDefinition.Parameters(), fakeOrgStates[0]) 1221 resources.Serializer.Serialize("chaincode-sources", "cc-name#5", testChaincodeLocalPackage, fakeOrgStates[0]) 1222 }) 1223 1224 It("returns the approved chaincode for the next sequence", func() { 1225 cc, err := ef.QueryApprovedChaincodeDefinition("my-channel", "cc-name", 0, fakePublicState, fakeOrgStates[0]) 1226 Expect(err).NotTo(HaveOccurred()) 1227 Expect(cc.Sequence).To(Equal(int64(5))) 1228 Expect(proto.Equal(cc.EndorsementInfo, &lb.ChaincodeEndorsementInfo{ 1229 Version: "version", 1230 EndorsementPlugin: "endorsement-plugin", 1231 })).To(BeTrue()) 1232 Expect(proto.Equal(cc.ValidationInfo, &lb.ChaincodeValidationInfo{ 1233 ValidationPlugin: "validation-plugin", 1234 ValidationParameter: []byte("validation-parameter"), 1235 })).To(BeTrue()) 1236 Expect(proto.Equal(cc.Collections, &pb.CollectionConfigPackage{})).To(BeTrue()) 1237 Expect(proto.Equal(cc.Source, &lb.ChaincodeSource{ 1238 Type: &lb.ChaincodeSource_Unavailable_{ 1239 Unavailable: &lb.ChaincodeSource_Unavailable{}, 1240 }, 1241 })).To(BeTrue()) 1242 }) 1243 1244 Context("and deserializing namespace metadata for next sequence fails", func() { 1245 BeforeEach(func() { 1246 org0KVS["namespaces/metadata/cc-name#5"] = []byte("garbage") 1247 }) 1248 1249 It("wraps and returns the error", func() { 1250 cc, err := ef.QueryApprovedChaincodeDefinition("my-channel", "cc-name", 0, fakePublicState, fakeOrgStates[0]) 1251 Expect(err).To(MatchError("could not deserialize namespace metadata for next sequence 5: could not unmarshal metadata for namespace namespaces/cc-name#5: proto: can't skip unknown wire type 7")) 1252 Expect(cc).To(BeNil()) 1253 }) 1254 }) 1255 }) 1256 1257 Context("when the next sequence is defined and the sequence argument is provided", func() { 1258 BeforeEach(func() { 1259 testChaincodeLocalPackage.PackageID = "hash" 1260 resources.Serializer.Serialize("namespaces", "cc-name#5", testDefinition.Parameters(), fakeOrgStates[0]) 1261 resources.Serializer.Serialize("chaincode-sources", "cc-name#5", testChaincodeLocalPackage, fakeOrgStates[0]) 1262 }) 1263 1264 It("returns the approved chaincode for the next sequence", func() { 1265 cc, err := ef.QueryApprovedChaincodeDefinition("my-channel", "cc-name", 5, fakePublicState, fakeOrgStates[0]) 1266 Expect(err).NotTo(HaveOccurred()) 1267 Expect(cc.Sequence).To(Equal(int64(5))) 1268 Expect(proto.Equal(cc.EndorsementInfo, &lb.ChaincodeEndorsementInfo{ 1269 Version: "version", 1270 EndorsementPlugin: "endorsement-plugin", 1271 })).To(BeTrue()) 1272 Expect(proto.Equal(cc.ValidationInfo, &lb.ChaincodeValidationInfo{ 1273 ValidationPlugin: "validation-plugin", 1274 ValidationParameter: []byte("validation-parameter"), 1275 })).To(BeTrue()) 1276 Expect(proto.Equal(cc.Collections, &pb.CollectionConfigPackage{})).To(BeTrue()) 1277 Expect(proto.Equal(cc.Source, &lb.ChaincodeSource{ 1278 Type: &lb.ChaincodeSource_LocalPackage{ 1279 LocalPackage: &lb.ChaincodeSource_Local{ 1280 PackageId: "hash", 1281 }, 1282 }, 1283 })).To(BeTrue()) 1284 }) 1285 }) 1286 1287 Context("when the requested sequence number is out of range", func() { 1288 It("wraps and returns the error", func() { 1289 cc, err := ef.QueryApprovedChaincodeDefinition("my-channel", "cc-name", 5, fakePublicState, fakeOrgStates[0]) 1290 Expect(err).To(MatchError("could not fetch approved chaincode definition (name: 'cc-name', sequence: '5') on channel 'my-channel'")) 1291 Expect(cc).To(BeNil()) 1292 }) 1293 }) 1294 1295 Context("when the sequence argument is not provided and querying the public state fails", func() { 1296 BeforeEach(func() { 1297 fakePublicState.GetStateReturns(nil, fmt.Errorf("get-state-error")) 1298 }) 1299 1300 It("wraps and returns the error", func() { 1301 cc, err := ef.QueryApprovedChaincodeDefinition("my-channel", "cc-name", 0, fakePublicState, fakeOrgStates[0]) 1302 Expect(err).To(MatchError("could not get current sequence: could not get state for key namespaces/fields/cc-name/Sequence: get-state-error")) 1303 Expect(cc).To(BeNil()) 1304 }) 1305 }) 1306 1307 Context("when deserializing namespace metadata for requested sequence fails", func() { 1308 BeforeEach(func() { 1309 org0KVS["namespaces/metadata/cc-name#4"] = []byte("garbage") 1310 }) 1311 1312 It("wraps and returns the error", func() { 1313 cc, err := ef.QueryApprovedChaincodeDefinition("my-channel", "cc-name", 4, fakePublicState, fakeOrgStates[0]) 1314 Expect(err).To(MatchError("could not deserialize namespace metadata for cc-name#4: could not unmarshal metadata for namespace namespaces/cc-name#4: proto: can't skip unknown wire type 7")) 1315 Expect(cc).To(BeNil()) 1316 }) 1317 }) 1318 1319 Context("when deserializing chaincode parameters fails", func() { 1320 BeforeEach(func() { 1321 org0KVS["namespaces/fields/cc-name#4/EndorsementInfo"] = []byte("garbage") 1322 }) 1323 1324 It("wraps and returns the error", func() { 1325 cc, err := ef.QueryApprovedChaincodeDefinition("my-channel", "cc-name", 4, fakePublicState, fakeOrgStates[0]) 1326 Expect(err).To(MatchError("could not deserialize chaincode parameters for cc-name#4: could not unmarshal state for key namespaces/fields/cc-name#4/EndorsementInfo: proto: can't skip unknown wire type 7")) 1327 Expect(cc).To(BeNil()) 1328 }) 1329 }) 1330 1331 Context("when deserializing chaincode-source metadata fails", func() { 1332 BeforeEach(func() { 1333 org0KVS["chaincode-sources/metadata/cc-name#4"] = []byte("garbage") 1334 }) 1335 1336 It("wraps and returns the error", func() { 1337 cc, err := ef.QueryApprovedChaincodeDefinition("my-channel", "cc-name", 4, fakePublicState, fakeOrgStates[0]) 1338 Expect(err).To(MatchError("could not deserialize chaincode-source metadata for cc-name#4: could not unmarshal metadata for namespace chaincode-sources/cc-name#4: proto: can't skip unknown wire type 7")) 1339 Expect(cc).To(BeNil()) 1340 }) 1341 }) 1342 1343 Context("when the requested cc parameters are found but the cc source is not found due to some inconsistency", func() { 1344 BeforeEach(func() { 1345 resources.Serializer.Serialize("namespaces", "cc-name#5", testDefinition.Parameters(), fakeOrgStates[0]) 1346 }) 1347 1348 It("wraps and returns the error", func() { 1349 cc, err := ef.QueryApprovedChaincodeDefinition("my-channel", "cc-name", 5, fakePublicState, fakeOrgStates[0]) 1350 Expect(err).To(MatchError("could not fetch approved chaincode definition (name: 'cc-name', sequence: '5') on channel 'my-channel'")) 1351 Expect(cc).To(BeNil()) 1352 }) 1353 }) 1354 1355 Context("when deserializing chaincode package fails", func() { 1356 BeforeEach(func() { 1357 org0KVS["chaincode-sources/fields/cc-name#4/PackageID"] = []byte("garbage") 1358 }) 1359 1360 It("wraps and returns the error", func() { 1361 cc, err := ef.QueryApprovedChaincodeDefinition("my-channel", "cc-name", 4, fakePublicState, fakeOrgStates[0]) 1362 Expect(err).To(MatchError("could not deserialize chaincode package for cc-name#4: could not unmarshal state for key chaincode-sources/fields/cc-name#4/PackageID: proto: can't skip unknown wire type 7")) 1363 Expect(cc).To(BeNil()) 1364 }) 1365 }) 1366 1367 Context("when the metadata is not for chaincode parameters", func() { 1368 BeforeEach(func() { 1369 type badStruct struct{} 1370 resources.Serializer.Serialize("namespaces", "cc-name#4", &badStruct{}, fakeOrgStates[0]) 1371 }) 1372 1373 It("wraps and returns the error", func() { 1374 cc, err := ef.QueryApprovedChaincodeDefinition("my-channel", "cc-name", 4, fakePublicState, fakeOrgStates[0]) 1375 Expect(err).To(MatchError("not a chaincode parameters type: badStruct")) 1376 Expect(cc).To(BeNil()) 1377 }) 1378 }) 1379 1380 Context("when the metadata is not for a chaincode local package", func() { 1381 BeforeEach(func() { 1382 type badStruct struct{} 1383 resources.Serializer.Serialize("chaincode-sources", "cc-name#4", &badStruct{}, fakeOrgStates[0]) 1384 }) 1385 1386 It("wraps and returns the error", func() { 1387 cc, err := ef.QueryApprovedChaincodeDefinition("my-channel", "cc-name", 4, fakePublicState, fakeOrgStates[0]) 1388 Expect(err).To(MatchError("not a chaincode local package type: badStruct")) 1389 Expect(cc).To(BeNil()) 1390 }) 1391 }) 1392 }) 1393 1394 Describe("CommitChaincodeDefinition", func() { 1395 var ( 1396 fakePublicState *mock.ReadWritableState 1397 fakeOrgStates []*mock.ReadWritableState 1398 1399 testDefinition *lifecycle.ChaincodeDefinition 1400 1401 publicKVS, org0KVS, org1KVS MapLedgerShim 1402 ) 1403 1404 BeforeEach(func() { 1405 testDefinition = &lifecycle.ChaincodeDefinition{ 1406 Sequence: 5, 1407 EndorsementInfo: &lb.ChaincodeEndorsementInfo{ 1408 Version: "version", 1409 EndorsementPlugin: "endorsement-plugin", 1410 }, 1411 ValidationInfo: &lb.ChaincodeValidationInfo{ 1412 ValidationPlugin: "validation-plugin", 1413 ValidationParameter: []byte("validation-parameter"), 1414 }, 1415 } 1416 1417 publicKVS = MapLedgerShim(map[string][]byte{}) 1418 fakePublicState = &mock.ReadWritableState{} 1419 fakePublicState.GetStateStub = publicKVS.GetState 1420 fakePublicState.PutStateStub = publicKVS.PutState 1421 1422 resources.Serializer.Serialize("namespaces", "cc-name", &lifecycle.ChaincodeDefinition{ 1423 Sequence: 4, 1424 EndorsementInfo: &lb.ChaincodeEndorsementInfo{ 1425 Version: "version", 1426 EndorsementPlugin: "endorsement-plugin", 1427 }, 1428 ValidationInfo: &lb.ChaincodeValidationInfo{ 1429 ValidationPlugin: "validation-plugin", 1430 ValidationParameter: []byte("validation-parameter"), 1431 }, 1432 }, publicKVS) 1433 1434 org0KVS = MapLedgerShim(map[string][]byte{}) 1435 org1KVS = MapLedgerShim(map[string][]byte{}) 1436 fakeOrg0State := &mock.ReadWritableState{} 1437 fakeOrg0State.CollectionNameReturns("_implicit_org_org0") 1438 fakeOrg1State := &mock.ReadWritableState{} 1439 fakeOrg1State.CollectionNameReturns("_implicit_org_org1") 1440 fakeOrgStates = []*mock.ReadWritableState{ 1441 fakeOrg0State, 1442 fakeOrg1State, 1443 } 1444 for i, kvs := range []MapLedgerShim{org0KVS, org1KVS} { 1445 kvs := kvs 1446 fakeOrgStates[i].GetStateStub = kvs.GetState 1447 fakeOrgStates[i].GetStateHashStub = kvs.GetStateHash 1448 fakeOrgStates[i].PutStateStub = kvs.PutState 1449 } 1450 1451 resources.Serializer.Serialize("namespaces", "cc-name#5", testDefinition.Parameters(), fakeOrgStates[0]) 1452 resources.Serializer.Serialize("namespaces", "cc-name#5", &lifecycle.ChaincodeParameters{}, fakeOrgStates[1]) 1453 }) 1454 1455 It("applies the chaincode definition and returns the approvals", func() { 1456 approvals, err := ef.CommitChaincodeDefinition("my-channel", "cc-name", testDefinition, fakePublicState, []lifecycle.OpaqueState{fakeOrgStates[0], fakeOrgStates[1]}) 1457 Expect(err).NotTo(HaveOccurred()) 1458 Expect(approvals).To(Equal(map[string]bool{ 1459 "org0": true, 1460 "org1": false, 1461 })) 1462 }) 1463 1464 Context("when IsSerialized fails", func() { 1465 BeforeEach(func() { 1466 fakeOrgStates[0].GetStateHashReturns(nil, errors.New("bad bad failure")) 1467 }) 1468 1469 It("wraps and returns an error", func() { 1470 _, err := ef.CommitChaincodeDefinition("my-channel", "cc-name", testDefinition, fakePublicState, []lifecycle.OpaqueState{fakeOrgStates[0], fakeOrgStates[1]}) 1471 Expect(err).To(MatchError(ContainSubstring("serialization check failed for key cc-name#5: could not get value for key namespaces/metadata/cc-name#5: bad bad failure"))) 1472 }) 1473 }) 1474 1475 Context("when the peer sets defaults", func() { 1476 BeforeEach(func() { 1477 testDefinition.EndorsementInfo.EndorsementPlugin = "escc" 1478 testDefinition.ValidationInfo.ValidationPlugin = "vscc" 1479 testDefinition.ValidationInfo.ValidationParameter = protoutil.MarshalOrPanic( 1480 &pb.ApplicationPolicy{ 1481 Type: &pb.ApplicationPolicy_ChannelConfigPolicyReference{ 1482 ChannelConfigPolicyReference: "/Channel/Application/Endorsement", 1483 }, 1484 }) 1485 1486 resources.Serializer.Serialize("namespaces", "cc-name#5", testDefinition.Parameters(), fakeOrgStates[0]) 1487 1488 testDefinition.EndorsementInfo.EndorsementPlugin = "" 1489 testDefinition.ValidationInfo.ValidationPlugin = "" 1490 testDefinition.ValidationInfo.ValidationParameter = nil 1491 1492 resources.Serializer.Serialize("namespaces", "cc-name#5", testDefinition.Parameters(), fakeOrgStates[1]) 1493 }) 1494 1495 It("applies the chaincode definition and returns the approvals", func() { 1496 approvals, err := ef.CommitChaincodeDefinition("my-channel", "cc-name", testDefinition, fakePublicState, []lifecycle.OpaqueState{fakeOrgStates[0], fakeOrgStates[1]}) 1497 Expect(err).NotTo(HaveOccurred()) 1498 Expect(approvals).To(Equal(map[string]bool{ 1499 "org0": true, 1500 "org1": false, 1501 })) 1502 }) 1503 1504 Context("when no default endorsement policy is defined on thc channel", func() { 1505 BeforeEach(func() { 1506 fakePolicyManager.GetPolicyReturns(nil, false) 1507 }) 1508 1509 It("returns an error", func() { 1510 _, err := ef.CommitChaincodeDefinition("my-channel", "cc-name", testDefinition, fakePublicState, []lifecycle.OpaqueState{fakeOrgStates[0], fakeOrgStates[1]}) 1511 Expect(err).To(MatchError(ContainSubstring("could not set defaults for chaincode definition in " + 1512 "channel my-channel: policy '/Channel/Application/Endorsement' must be defined " + 1513 "for channel 'my-channel' before chaincode operations can be attempted"))) 1514 }) 1515 }) 1516 1517 Context("when obtaining a stable channel config fails", func() { 1518 BeforeEach(func() { 1519 fakeChannelConfigSource.GetStableChannelConfigReturns(nil) 1520 }) 1521 1522 It("returns an error", func() { 1523 _, err := ef.CommitChaincodeDefinition("my-channel", "cc-name", testDefinition, fakePublicState, []lifecycle.OpaqueState{fakeOrgStates[0], fakeOrgStates[1]}) 1524 Expect(err).To(MatchError(ContainSubstring("could not get channel config for channel 'my-channel'"))) 1525 }) 1526 }) 1527 }) 1528 1529 Context("when the public state is not readable", func() { 1530 BeforeEach(func() { 1531 fakePublicState.GetStateReturns(nil, fmt.Errorf("getstate-error")) 1532 }) 1533 1534 It("wraps and returns the error", func() { 1535 _, err := ef.CommitChaincodeDefinition("my-channel", "cc-name", testDefinition, fakePublicState, []lifecycle.OpaqueState{fakeOrgStates[0], fakeOrgStates[1]}) 1536 Expect(err).To(MatchError("could not get current sequence: could not get state for key namespaces/fields/cc-name/Sequence: getstate-error")) 1537 }) 1538 }) 1539 1540 Context("when the public state is not writable", func() { 1541 BeforeEach(func() { 1542 fakePublicState.PutStateReturns(fmt.Errorf("putstate-error")) 1543 }) 1544 1545 It("wraps and returns the error", func() { 1546 _, err := ef.CommitChaincodeDefinition("my-channel", "cc-name", testDefinition, fakePublicState, []lifecycle.OpaqueState{fakeOrgStates[0], fakeOrgStates[1]}) 1547 Expect(err).To(MatchError("could not serialize chaincode definition: could not write key into state: putstate-error")) 1548 }) 1549 }) 1550 1551 Context("when the current sequence is not immediately prior to the new", func() { 1552 BeforeEach(func() { 1553 resources.Serializer.Serialize("namespaces", "cc-name", &lifecycle.ChaincodeDefinition{ 1554 Sequence: 3, 1555 EndorsementInfo: &lb.ChaincodeEndorsementInfo{ 1556 Version: "version", 1557 EndorsementPlugin: "endorsement-plugin", 1558 }, 1559 ValidationInfo: &lb.ChaincodeValidationInfo{ 1560 ValidationPlugin: "validation-plugin", 1561 ValidationParameter: []byte("validation-parameter"), 1562 }, 1563 }, fakePublicState) 1564 }) 1565 1566 It("returns an error", func() { 1567 _, err := ef.CommitChaincodeDefinition("my-channel", "cc-name", testDefinition, fakePublicState, []lifecycle.OpaqueState{fakeOrgStates[0], fakeOrgStates[1]}) 1568 Expect(err).To(MatchError("requested sequence is 5, but new definition must be sequence 4")) 1569 }) 1570 }) 1571 1572 Context("when the current sequence is the new sequence", func() { 1573 BeforeEach(func() { 1574 resources.Serializer.Serialize("namespaces", "cc-name", &lifecycle.ChaincodeDefinition{ 1575 Sequence: 5, 1576 EndorsementInfo: &lb.ChaincodeEndorsementInfo{ 1577 Version: "version", 1578 EndorsementPlugin: "endorsement-plugin", 1579 }, 1580 ValidationInfo: &lb.ChaincodeValidationInfo{ 1581 ValidationPlugin: "validation-plugin", 1582 ValidationParameter: []byte("validation-parameter"), 1583 }, 1584 }, fakePublicState) 1585 }) 1586 1587 It("returns an error", func() { 1588 _, err := ef.CommitChaincodeDefinition("my-channel", "cc-name", testDefinition, fakePublicState, []lifecycle.OpaqueState{fakeOrgStates[0], fakeOrgStates[1]}) 1589 Expect(err).To(MatchError("requested sequence is 5, but new definition must be sequence 6")) 1590 }) 1591 }) 1592 }) 1593 1594 Describe("QueryChaincodeDefinition", func() { 1595 var ( 1596 fakePublicState *mock.ReadWritableState 1597 fakeOrgStates []*mock.ReadWritableState 1598 1599 testDefinition *lifecycle.ChaincodeDefinition 1600 1601 publicKVS, org0KVS, org1KVS MapLedgerShim 1602 ) 1603 1604 BeforeEach(func() { 1605 publicKVS = MapLedgerShim(map[string][]byte{}) 1606 fakePublicState = &mock.ReadWritableState{} 1607 fakePublicState.GetStateStub = publicKVS.GetState 1608 fakePublicState.PutStateStub = publicKVS.PutState 1609 1610 testDefinition = &lifecycle.ChaincodeDefinition{ 1611 Sequence: 4, 1612 EndorsementInfo: &lb.ChaincodeEndorsementInfo{ 1613 Version: "version", 1614 EndorsementPlugin: "endorsement-plugin", 1615 }, 1616 ValidationInfo: &lb.ChaincodeValidationInfo{ 1617 ValidationPlugin: "validation-plugin", 1618 ValidationParameter: []byte("validation-parameter"), 1619 }, 1620 Collections: &pb.CollectionConfigPackage{}, 1621 } 1622 1623 resources.Serializer.Serialize("namespaces", "cc-name", testDefinition, publicKVS) 1624 1625 org0KVS = MapLedgerShim(map[string][]byte{}) 1626 org1KVS = MapLedgerShim(map[string][]byte{}) 1627 fakeOrg0State := &mock.ReadWritableState{} 1628 fakeOrg1State := &mock.ReadWritableState{} 1629 fakeOrgStates = []*mock.ReadWritableState{ 1630 fakeOrg0State, 1631 fakeOrg1State, 1632 } 1633 for i, kvs := range []MapLedgerShim{org0KVS, org1KVS} { 1634 kvs := kvs 1635 fakeOrgStates[i].GetStateStub = kvs.GetState 1636 fakeOrgStates[i].GetStateHashStub = kvs.GetStateHash 1637 fakeOrgStates[i].PutStateStub = kvs.PutState 1638 } 1639 1640 resources.Serializer.Serialize("namespaces", "cc-name#4", testDefinition.Parameters(), fakeOrgStates[0]) 1641 resources.Serializer.Serialize("namespaces", "cc-name#4", &lifecycle.ChaincodeParameters{}, fakeOrgStates[1]) 1642 }) 1643 1644 It("returns the defined chaincode", func() { 1645 cc, err := ef.QueryChaincodeDefinition("cc-name", fakePublicState) 1646 Expect(err).NotTo(HaveOccurred()) 1647 Expect(cc.Sequence).To(Equal(int64(4))) 1648 Expect(proto.Equal(cc.EndorsementInfo, &lb.ChaincodeEndorsementInfo{ 1649 Version: "version", 1650 EndorsementPlugin: "endorsement-plugin", 1651 })).To(BeTrue()) 1652 Expect(proto.Equal(cc.ValidationInfo, &lb.ChaincodeValidationInfo{ 1653 ValidationPlugin: "validation-plugin", 1654 ValidationParameter: []byte("validation-parameter"), 1655 })).To(BeTrue()) 1656 Expect(proto.Equal(cc.Collections, &pb.CollectionConfigPackage{})).To(BeTrue()) 1657 }) 1658 1659 Context("when the chaincode is not defined", func() { 1660 BeforeEach(func() { 1661 fakePublicState.GetStateReturns(nil, nil) 1662 }) 1663 1664 It("returns an error", func() { 1665 cc, err := ef.QueryChaincodeDefinition("cc-name", fakePublicState) 1666 Expect(err).To(MatchError("namespace cc-name is not defined")) 1667 Expect(cc).To(BeNil()) 1668 }) 1669 }) 1670 1671 Context("when getting the metadata fails", func() { 1672 BeforeEach(func() { 1673 fakePublicState.GetStateReturns(nil, fmt.Errorf("metadata-error")) 1674 }) 1675 1676 It("returns an error", func() { 1677 cc, err := ef.QueryChaincodeDefinition("cc-name", fakePublicState) //, nil) 1678 Expect(err).To(MatchError("could not fetch metadata for namespace cc-name: could not query metadata for namespace namespaces/cc-name: metadata-error")) 1679 Expect(cc).To(BeNil()) 1680 }) 1681 }) 1682 1683 Context("when deserializing the definition fails", func() { 1684 BeforeEach(func() { 1685 publicKVS["namespaces/fields/cc-name/EndorsementInfo"] = []byte("garbage") 1686 }) 1687 1688 It("returns an error", func() { 1689 cc, err := ef.QueryChaincodeDefinition("cc-name", fakePublicState) 1690 Expect(err).To(MatchError("could not deserialize namespace cc-name as chaincode: could not unmarshal state for key namespaces/fields/cc-name/EndorsementInfo: proto: can't skip unknown wire type 7")) 1691 Expect(cc).To(BeNil()) 1692 }) 1693 }) 1694 }) 1695 1696 Describe("QueryOrgApprovals", func() { 1697 var ( 1698 fakeOrgStates []*mock.ReadWritableState 1699 1700 testDefinition *lifecycle.ChaincodeDefinition 1701 1702 org0KVS, org1KVS MapLedgerShim 1703 ) 1704 1705 BeforeEach(func() { 1706 testDefinition = &lifecycle.ChaincodeDefinition{ 1707 Sequence: 4, 1708 EndorsementInfo: &lb.ChaincodeEndorsementInfo{ 1709 Version: "version", 1710 EndorsementPlugin: "endorsement-plugin", 1711 }, 1712 ValidationInfo: &lb.ChaincodeValidationInfo{ 1713 ValidationPlugin: "validation-plugin", 1714 ValidationParameter: []byte("validation-parameter"), 1715 }, 1716 Collections: &pb.CollectionConfigPackage{}, 1717 } 1718 1719 org0KVS = MapLedgerShim(map[string][]byte{}) 1720 org1KVS = MapLedgerShim(map[string][]byte{}) 1721 fakeOrg0State := &mock.ReadWritableState{} 1722 fakeOrg0State.CollectionNameReturns("_implicit_org_org0") 1723 fakeOrg1State := &mock.ReadWritableState{} 1724 fakeOrg1State.CollectionNameReturns("_implicit_org_org1") 1725 fakeOrgStates = []*mock.ReadWritableState{ 1726 fakeOrg0State, 1727 fakeOrg1State, 1728 } 1729 for i, kvs := range []MapLedgerShim{org0KVS, org1KVS} { 1730 kvs := kvs 1731 fakeOrgStates[i].GetStateStub = kvs.GetState 1732 fakeOrgStates[i].GetStateHashStub = kvs.GetStateHash 1733 fakeOrgStates[i].PutStateStub = kvs.PutState 1734 } 1735 1736 resources.Serializer.Serialize("namespaces", "cc-name#4", testDefinition.Parameters(), fakeOrgStates[0]) 1737 resources.Serializer.Serialize("namespaces", "cc-name#4", &lifecycle.ChaincodeParameters{}, fakeOrgStates[1]) 1738 }) 1739 1740 It("returns the org approvals", func() { 1741 approvals, err := ef.QueryOrgApprovals("cc-name", testDefinition, []lifecycle.OpaqueState{fakeOrgStates[0], fakeOrgStates[1]}) 1742 Expect(err).NotTo(HaveOccurred()) 1743 Expect(approvals).To(Equal(map[string]bool{ 1744 "org0": true, 1745 "org1": false, 1746 })) 1747 }) 1748 1749 Context("when the org state cannot be deserialized", func() { 1750 BeforeEach(func() { 1751 fakeOrgStates[0].GetStateHashReturns(nil, errors.New("owww that hurt")) 1752 }) 1753 1754 It("wraps and returns an error", func() { 1755 approvals, err := ef.QueryOrgApprovals("cc-name", testDefinition, []lifecycle.OpaqueState{fakeOrgStates[0], fakeOrgStates[1]}) 1756 Expect(err).To(MatchError("serialization check failed for key cc-name#4: could not get value for key namespaces/metadata/cc-name#4: owww that hurt")) 1757 Expect(approvals).To(BeNil()) 1758 }) 1759 }) 1760 }) 1761 1762 Describe("QueryNamespaceDefinitions", func() { 1763 var ( 1764 fakePublicState *mock.ReadWritableState 1765 1766 publicKVS MapLedgerShim 1767 ) 1768 1769 BeforeEach(func() { 1770 publicKVS = MapLedgerShim(map[string][]byte{}) 1771 fakePublicState = &mock.ReadWritableState{} 1772 fakePublicState.GetStateStub = publicKVS.GetState 1773 fakePublicState.GetStateRangeStub = publicKVS.GetStateRange 1774 resources.Serializer.Serialize("namespaces", "cc-name", &lifecycle.ChaincodeDefinition{}, publicKVS) 1775 resources.Serializer.Serialize("namespaces", "other-name", &lifecycle.ChaincodeParameters{}, publicKVS) 1776 }) 1777 1778 It("returns the defined namespaces", func() { 1779 result, err := ef.QueryNamespaceDefinitions(fakePublicState) 1780 Expect(err).NotTo(HaveOccurred()) 1781 Expect(result).To(Equal(map[string]string{ 1782 "cc-name": "Chaincode", 1783 "other-name": "ChaincodeParameters", 1784 })) 1785 }) 1786 1787 Context("when the range cannot be retrieved", func() { 1788 BeforeEach(func() { 1789 fakePublicState.GetStateRangeReturns(nil, fmt.Errorf("state-range-error")) 1790 }) 1791 1792 It("returns an error", func() { 1793 _, err := ef.QueryNamespaceDefinitions(fakePublicState) 1794 Expect(err).To(MatchError("could not query namespace metadata: could not get state range for namespace namespaces: state-range-error")) 1795 }) 1796 }) 1797 }) 1798 })