github.com/hechain20/hechain@v0.0.0-20220316014945-b544036ba106/core/chaincode/lifecycle/lifecycle_test.go (about)

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