github.com/fnagchunpeng/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  })