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