github.com/hyperledger-labs/bdls@v2.1.1+incompatible/core/chaincode/lifecycle/scc_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  	"bytes"
    11  	"encoding/gob"
    12  	"fmt"
    13  
    14  	"github.com/hyperledger/fabric/core/ledger"
    15  
    16  	"github.com/golang/protobuf/proto"
    17  	"github.com/hyperledger/fabric-chaincode-go/shim"
    18  	mspprotos "github.com/hyperledger/fabric-protos-go/msp"
    19  	pb "github.com/hyperledger/fabric-protos-go/peer"
    20  	lb "github.com/hyperledger/fabric-protos-go/peer/lifecycle"
    21  	"github.com/hyperledger/fabric/common/chaincode"
    22  	"github.com/hyperledger/fabric/common/channelconfig"
    23  	"github.com/hyperledger/fabric/common/policydsl"
    24  	"github.com/hyperledger/fabric/core/chaincode/lifecycle"
    25  	"github.com/hyperledger/fabric/core/chaincode/lifecycle/mock"
    26  	"github.com/hyperledger/fabric/core/chaincode/persistence"
    27  	"github.com/hyperledger/fabric/core/dispatcher"
    28  	"github.com/hyperledger/fabric/msp"
    29  	"github.com/pkg/errors"
    30  
    31  	. "github.com/onsi/ginkgo"
    32  	. "github.com/onsi/gomega"
    33  )
    34  
    35  var _ = Describe("SCC", func() {
    36  	var (
    37  		scc                        *lifecycle.SCC
    38  		fakeSCCFuncs               *mock.SCCFunctions
    39  		fakeChannelConfigSource    *mock.ChannelConfigSource
    40  		fakeChannelConfig          *mock.ChannelConfig
    41  		fakeApplicationConfig      *mock.ApplicationConfig
    42  		fakeCapabilities           *mock.ApplicationCapabilities
    43  		fakeACLProvider            *mock.ACLProvider
    44  		fakeMSPManager             *mock.MSPManager
    45  		fakeQueryExecutorProvider  *mock.QueryExecutorProvider
    46  		fakeQueryExecutor          *mock.SimpleQueryExecutor
    47  		fakeDeployedCCInfoProvider *mock.LegacyDeployedCCInfoProvider
    48  		fakeStub                   *mock.ChaincodeStub
    49  	)
    50  
    51  	BeforeEach(func() {
    52  		fakeSCCFuncs = &mock.SCCFunctions{}
    53  		fakeChannelConfigSource = &mock.ChannelConfigSource{}
    54  		fakeChannelConfig = &mock.ChannelConfig{}
    55  		fakeChannelConfigSource.GetStableChannelConfigReturns(fakeChannelConfig)
    56  		fakeApplicationConfig = &mock.ApplicationConfig{}
    57  		fakeChannelConfig.ApplicationConfigReturns(fakeApplicationConfig, true)
    58  		fakeCapabilities = &mock.ApplicationCapabilities{}
    59  		fakeCapabilities.LifecycleV20Returns(true)
    60  		fakeApplicationConfig.CapabilitiesReturns(fakeCapabilities)
    61  		fakeACLProvider = &mock.ACLProvider{}
    62  		fakeMSPManager = &mock.MSPManager{}
    63  		fakeChannelConfig.MSPManagerReturns(fakeMSPManager)
    64  		fakeQueryExecutorProvider = &mock.QueryExecutorProvider{}
    65  		fakeQueryExecutor = &mock.SimpleQueryExecutor{}
    66  		fakeQueryExecutorProvider.TxQueryExecutorReturns(fakeQueryExecutor)
    67  		fakeStub = &mock.ChaincodeStub{}
    68  		fakeDeployedCCInfoProvider = &mock.LegacyDeployedCCInfoProvider{}
    69  
    70  		scc = &lifecycle.SCC{
    71  			Dispatcher: &dispatcher.Dispatcher{
    72  				Protobuf: &dispatcher.ProtobufImpl{},
    73  			},
    74  			Functions:              fakeSCCFuncs,
    75  			OrgMSPID:               "fake-mspid",
    76  			ChannelConfigSource:    fakeChannelConfigSource,
    77  			ACLProvider:            fakeACLProvider,
    78  			QueryExecutorProvider:  fakeQueryExecutorProvider,
    79  			DeployedCCInfoProvider: fakeDeployedCCInfoProvider,
    80  		}
    81  	})
    82  
    83  	Describe("Name", func() {
    84  		It("returns the name", func() {
    85  			Expect(scc.Name()).To(Equal("_lifecycle"))
    86  		})
    87  	})
    88  
    89  	Describe("Chaincode", func() {
    90  		It("returns a reference to itself", func() {
    91  			Expect(scc.Chaincode()).To(Equal(scc))
    92  		})
    93  	})
    94  
    95  	Describe("Init", func() {
    96  		It("does nothing", func() {
    97  			Expect(scc.Init(nil)).To(Equal(shim.Success(nil)))
    98  		})
    99  	})
   100  
   101  	Describe("Invoke", func() {
   102  		BeforeEach(func() {
   103  			fakeStub.GetChannelIDReturns("test-channel")
   104  		})
   105  
   106  		Context("when no arguments are provided", func() {
   107  			It("returns an error", func() {
   108  				Expect(scc.Invoke(fakeStub)).To(Equal(shim.Error("lifecycle scc must be invoked with arguments")))
   109  			})
   110  		})
   111  
   112  		Context("when too many arguments are provided", func() {
   113  			BeforeEach(func() {
   114  				fakeStub.GetArgsReturns([][]byte{nil, nil, nil})
   115  			})
   116  
   117  			It("returns an error", func() {
   118  				Expect(scc.Invoke(fakeStub)).To(Equal(shim.Error("lifecycle scc operations require exactly two arguments but received 3")))
   119  			})
   120  		})
   121  
   122  		Context("when an unknown function is provided as the first argument", func() {
   123  			BeforeEach(func() {
   124  				fakeStub.GetArgsReturns([][]byte{[]byte("bad-function"), nil})
   125  			})
   126  
   127  			It("returns an error", func() {
   128  				Expect(scc.Invoke(fakeStub)).To(Equal(shim.Error("failed to invoke backing implementation of 'bad-function': receiver *lifecycle.Invocation.bad-function does not exist")))
   129  			})
   130  		})
   131  
   132  		Context("when the ACL provider disapproves of the function", func() {
   133  			BeforeEach(func() {
   134  				fakeStub.GetArgsReturns([][]byte{[]byte("any-function"), nil})
   135  				fakeACLProvider.CheckACLReturns(fmt.Errorf("acl-error"))
   136  			})
   137  
   138  			It("returns an error", func() {
   139  				Expect(scc.Invoke(fakeStub)).To(Equal(shim.Error("Failed to authorize invocation due to failed ACL check: acl-error")))
   140  			})
   141  
   142  			Context("when the signed data for the tx cannot be retrieved", func() {
   143  				BeforeEach(func() {
   144  					fakeStub.GetSignedProposalReturns(nil, fmt.Errorf("shim-error"))
   145  				})
   146  
   147  				It("returns an error", func() {
   148  					Expect(scc.Invoke(fakeStub)).To(Equal(shim.Error("Failed getting signed proposal from stub: [shim-error]")))
   149  				})
   150  			})
   151  		})
   152  
   153  		Describe("InstallChaincode", func() {
   154  			var (
   155  				arg          *lb.InstallChaincodeArgs
   156  				marshaledArg []byte
   157  			)
   158  
   159  			BeforeEach(func() {
   160  				arg = &lb.InstallChaincodeArgs{
   161  					ChaincodeInstallPackage: []byte("chaincode-package"),
   162  				}
   163  
   164  				var err error
   165  				marshaledArg, err = proto.Marshal(arg)
   166  				Expect(err).NotTo(HaveOccurred())
   167  
   168  				fakeStub.GetArgsReturns([][]byte{[]byte("InstallChaincode"), marshaledArg})
   169  
   170  				fakeSCCFuncs.InstallChaincodeReturns(&chaincode.InstalledChaincode{
   171  					Label:     "label",
   172  					PackageID: "packageid",
   173  				}, nil)
   174  			})
   175  
   176  			It("passes the arguments to and returns the results from the backing scc function implementation", func() {
   177  				res := scc.Invoke(fakeStub)
   178  				Expect(res.Status).To(Equal(int32(200)))
   179  				payload := &lb.InstallChaincodeResult{}
   180  				err := proto.Unmarshal(res.Payload, payload)
   181  				Expect(err).NotTo(HaveOccurred())
   182  				Expect(payload.PackageId).To(Equal("packageid"))
   183  
   184  				Expect(fakeSCCFuncs.InstallChaincodeCallCount()).To(Equal(1))
   185  				ccInstallPackage := fakeSCCFuncs.InstallChaincodeArgsForCall(0)
   186  				Expect(ccInstallPackage).To(Equal([]byte("chaincode-package")))
   187  			})
   188  
   189  			Context("when the underlying function implementation fails", func() {
   190  				BeforeEach(func() {
   191  					fakeSCCFuncs.InstallChaincodeReturns(nil, fmt.Errorf("underlying-error"))
   192  				})
   193  
   194  				It("wraps and returns the error", func() {
   195  					res := scc.Invoke(fakeStub)
   196  					Expect(res.Status).To(Equal(int32(500)))
   197  					Expect(res.Message).To(Equal("failed to invoke backing implementation of 'InstallChaincode': underlying-error"))
   198  				})
   199  			})
   200  		})
   201  
   202  		Describe("QueryInstalledChaincode", func() {
   203  			var (
   204  				arg          *lb.QueryInstalledChaincodeArgs
   205  				marshaledArg []byte
   206  			)
   207  
   208  			BeforeEach(func() {
   209  				arg = &lb.QueryInstalledChaincodeArgs{
   210  					PackageId: "awesome_package",
   211  				}
   212  
   213  				var err error
   214  				marshaledArg, err = proto.Marshal(arg)
   215  				Expect(err).NotTo(HaveOccurred())
   216  
   217  				fakeStub.GetArgsReturns([][]byte{[]byte("QueryInstalledChaincode"), marshaledArg})
   218  
   219  				fakeSCCFuncs.QueryInstalledChaincodeReturns(&chaincode.InstalledChaincode{
   220  					PackageID: "awesome_package",
   221  					Label:     "awesome_package_label",
   222  					References: map[string][]*chaincode.Metadata{
   223  						"test-channel": {
   224  							&chaincode.Metadata{
   225  								Name:    "cc0",
   226  								Version: "cc0-version",
   227  							},
   228  						},
   229  					},
   230  				}, nil)
   231  			})
   232  
   233  			It("passes the arguments to and returns the results from the backing scc function implementation", func() {
   234  				res := scc.Invoke(fakeStub)
   235  				Expect(res.Status).To(Equal(int32(200)))
   236  				payload := &lb.QueryInstalledChaincodeResult{}
   237  				err := proto.Unmarshal(res.Payload, payload)
   238  				Expect(err).NotTo(HaveOccurred())
   239  				Expect(payload.Label).To(Equal("awesome_package_label"))
   240  				Expect(payload.PackageId).To(Equal("awesome_package"))
   241  				Expect(payload.References).To(Equal(map[string]*lb.QueryInstalledChaincodeResult_References{
   242  					"test-channel": {
   243  						Chaincodes: []*lb.QueryInstalledChaincodeResult_Chaincode{
   244  							{
   245  								Name:    "cc0",
   246  								Version: "cc0-version",
   247  							},
   248  						},
   249  					},
   250  				}))
   251  
   252  				Expect(fakeSCCFuncs.QueryInstalledChaincodeCallCount()).To(Equal(1))
   253  				name := fakeSCCFuncs.QueryInstalledChaincodeArgsForCall(0)
   254  				Expect(name).To(Equal("awesome_package"))
   255  			})
   256  
   257  			Context("when the code package cannot be found", func() {
   258  				BeforeEach(func() {
   259  					fakeSCCFuncs.QueryInstalledChaincodeReturns(nil, persistence.CodePackageNotFoundErr{PackageID: "less_awesome_package"})
   260  				})
   261  
   262  				It("returns 404 Not Found", func() {
   263  					res := scc.Invoke(fakeStub)
   264  					Expect(res.Status).To(Equal(int32(404)))
   265  					Expect(res.Message).To(Equal("chaincode install package 'less_awesome_package' not found"))
   266  				})
   267  			})
   268  
   269  			Context("when the underlying function implementation fails", func() {
   270  				BeforeEach(func() {
   271  					fakeSCCFuncs.QueryInstalledChaincodeReturns(nil, fmt.Errorf("underlying-error"))
   272  				})
   273  
   274  				It("wraps and returns the error", func() {
   275  					res := scc.Invoke(fakeStub)
   276  					Expect(res.Status).To(Equal(int32(500)))
   277  					Expect(res.Message).To(Equal("failed to invoke backing implementation of 'QueryInstalledChaincode': underlying-error"))
   278  				})
   279  			})
   280  		})
   281  
   282  		Describe("GetInstalledChaincodePackage", func() {
   283  			var (
   284  				arg          *lb.GetInstalledChaincodePackageArgs
   285  				marshaledArg []byte
   286  			)
   287  
   288  			BeforeEach(func() {
   289  				arg = &lb.GetInstalledChaincodePackageArgs{
   290  					PackageId: "package-id",
   291  				}
   292  
   293  				var err error
   294  				marshaledArg, err = proto.Marshal(arg)
   295  				Expect(err).NotTo(HaveOccurred())
   296  
   297  				fakeStub.GetArgsReturns([][]byte{[]byte("GetInstalledChaincodePackage"), marshaledArg})
   298  
   299  				fakeSCCFuncs.GetInstalledChaincodePackageReturns([]byte("chaincode-package"), nil)
   300  			})
   301  
   302  			It("passes the arguments to and returns the results from the backing scc function implementation", func() {
   303  				res := scc.Invoke(fakeStub)
   304  				Expect(res.Status).To(Equal(int32(200)))
   305  				payload := &lb.GetInstalledChaincodePackageResult{}
   306  				err := proto.Unmarshal(res.Payload, payload)
   307  				Expect(err).NotTo(HaveOccurred())
   308  				Expect(payload.ChaincodeInstallPackage).To(Equal([]byte("chaincode-package")))
   309  
   310  				Expect(fakeSCCFuncs.GetInstalledChaincodePackageCallCount()).To(Equal(1))
   311  				packageID := fakeSCCFuncs.GetInstalledChaincodePackageArgsForCall(0)
   312  				Expect(packageID).To(Equal("package-id"))
   313  			})
   314  
   315  			Context("when the underlying function implementation fails", func() {
   316  				BeforeEach(func() {
   317  					fakeSCCFuncs.GetInstalledChaincodePackageReturns(nil, fmt.Errorf("underlying-error"))
   318  				})
   319  
   320  				It("wraps and returns the error", func() {
   321  					res := scc.Invoke(fakeStub)
   322  					Expect(res.Status).To(Equal(int32(500)))
   323  					Expect(res.Message).To(Equal("failed to invoke backing implementation of 'GetInstalledChaincodePackage': underlying-error"))
   324  				})
   325  			})
   326  		})
   327  
   328  		Describe("QueryInstalledChaincodes", func() {
   329  			var (
   330  				arg          *lb.QueryInstalledChaincodesArgs
   331  				marshaledArg []byte
   332  			)
   333  
   334  			BeforeEach(func() {
   335  				arg = &lb.QueryInstalledChaincodesArgs{}
   336  
   337  				var err error
   338  				marshaledArg, err = proto.Marshal(arg)
   339  				Expect(err).NotTo(HaveOccurred())
   340  
   341  				fakeStub.GetArgsReturns([][]byte{[]byte("QueryInstalledChaincodes"), marshaledArg})
   342  
   343  				fakeSCCFuncs.QueryInstalledChaincodesReturns([]*chaincode.InstalledChaincode{
   344  					{
   345  						Label:     "cc0-label",
   346  						PackageID: "cc0-package-id",
   347  						References: map[string][]*chaincode.Metadata{
   348  							"test-channel": {
   349  								&chaincode.Metadata{
   350  									Name:    "cc0",
   351  									Version: "cc0-version",
   352  								},
   353  							},
   354  						},
   355  					},
   356  					{
   357  						Label:     "cc1-label",
   358  						PackageID: "cc1-package-id",
   359  					},
   360  				})
   361  			})
   362  
   363  			It("passes the arguments to and returns the results from the backing scc function implementation", func() {
   364  				res := scc.Invoke(fakeStub)
   365  				Expect(res.Status).To(Equal(int32(200)))
   366  				payload := &lb.QueryInstalledChaincodesResult{}
   367  				err := proto.Unmarshal(res.Payload, payload)
   368  				Expect(err).NotTo(HaveOccurred())
   369  
   370  				Expect(payload.InstalledChaincodes).To(HaveLen(2))
   371  
   372  				Expect(payload.InstalledChaincodes[0].Label).To(Equal("cc0-label"))
   373  				Expect(payload.InstalledChaincodes[0].PackageId).To(Equal("cc0-package-id"))
   374  				Expect(payload.InstalledChaincodes[0].References).To(Equal(map[string]*lb.QueryInstalledChaincodesResult_References{
   375  					"test-channel": {
   376  						Chaincodes: []*lb.QueryInstalledChaincodesResult_Chaincode{
   377  							{
   378  								Name:    "cc0",
   379  								Version: "cc0-version",
   380  							},
   381  						},
   382  					},
   383  				}))
   384  
   385  				Expect(payload.InstalledChaincodes[1].Label).To(Equal("cc1-label"))
   386  				Expect(payload.InstalledChaincodes[1].PackageId).To(Equal("cc1-package-id"))
   387  
   388  				Expect(fakeSCCFuncs.QueryInstalledChaincodesCallCount()).To(Equal(1))
   389  			})
   390  		})
   391  
   392  		Describe("ApproveChaincodeDefinitionForMyOrg", func() {
   393  			var (
   394  				err         error
   395  				collConfigs collectionConfigs
   396  				fakeMsp     *mock.MSP
   397  
   398  				arg          *lb.ApproveChaincodeDefinitionForMyOrgArgs
   399  				marshaledArg []byte
   400  			)
   401  
   402  			BeforeEach(func() {
   403  				// identity1 of type MSPRole
   404  				mspPrincipal := &mspprotos.MSPRole{
   405  					MspIdentifier: "test-member-role",
   406  				}
   407  				mspPrincipalBytes, err := proto.Marshal(mspPrincipal)
   408  				Expect(err).NotTo(HaveOccurred())
   409  				identity1 := &mspprotos.MSPPrincipal{
   410  					PrincipalClassification: mspprotos.MSPPrincipal_ROLE,
   411  					Principal:               mspPrincipalBytes,
   412  				}
   413  
   414  				// identity2 of type OU
   415  				mspou := &mspprotos.OrganizationUnit{
   416  					MspIdentifier: "test-member-ou",
   417  				}
   418  				mspouBytes, err := proto.Marshal(mspou)
   419  				Expect(err).NotTo(HaveOccurred())
   420  				identity2 := &mspprotos.MSPPrincipal{
   421  					PrincipalClassification: mspprotos.MSPPrincipal_ORGANIZATION_UNIT,
   422  					Principal:               mspouBytes,
   423  				}
   424  
   425  				// identity3 of type identity
   426  				identity3 := &mspprotos.MSPPrincipal{
   427  					PrincipalClassification: mspprotos.MSPPrincipal_IDENTITY,
   428  					Principal:               []byte("test-member-identity"),
   429  				}
   430  
   431  				fakeIdentities := []*mspprotos.MSPPrincipal{
   432  					identity1, identity2, identity3,
   433  				}
   434  
   435  				fakeMsp = &mock.MSP{}
   436  				fakeMSPManager.GetMSPsReturns(
   437  					map[string]msp.MSP{
   438  						"test-member-role":     fakeMsp,
   439  						"test-member-ou":       fakeMsp,
   440  						"test-member-identity": fakeMsp,
   441  					},
   442  					nil,
   443  				)
   444  
   445  				collConfigs = []*collectionConfig{
   446  					{
   447  						Name:              "test-collection",
   448  						Policy:            "OR('fakeOrg1.member', 'fakeOrg2.member', 'fakeOrg3.member')",
   449  						RequiredPeerCount: 2,
   450  						MaxPeerCount:      3,
   451  						BlockToLive:       0,
   452  						Identities:        fakeIdentities,
   453  					},
   454  				}
   455  
   456  				arg = &lb.ApproveChaincodeDefinitionForMyOrgArgs{
   457  					Sequence:            7,
   458  					Name:                "cc_name",
   459  					Version:             "version_1.0",
   460  					EndorsementPlugin:   "endorsement-plugin",
   461  					ValidationPlugin:    "validation-plugin",
   462  					ValidationParameter: []byte("validation-parameter"),
   463  					InitRequired:        true,
   464  					Source: &lb.ChaincodeSource{
   465  						Type: &lb.ChaincodeSource_LocalPackage{
   466  							LocalPackage: &lb.ChaincodeSource_Local{
   467  								PackageId: "hash",
   468  							},
   469  						},
   470  					},
   471  				}
   472  			})
   473  
   474  			JustBeforeEach(func() {
   475  				arg.Collections = collConfigs.toProtoCollectionConfigPackage()
   476  				marshaledArg, err = proto.Marshal(arg)
   477  				Expect(err).NotTo(HaveOccurred())
   478  				fakeStub.GetArgsReturns([][]byte{[]byte("ApproveChaincodeDefinitionForMyOrg"), marshaledArg})
   479  			})
   480  
   481  			It("passes the arguments to and returns the results from the backing scc function implementation", func() {
   482  				res := scc.Invoke(fakeStub)
   483  				Expect(res.Status).To(Equal(int32(200)))
   484  				payload := &lb.ApproveChaincodeDefinitionForMyOrgResult{}
   485  				err = proto.Unmarshal(res.Payload, payload)
   486  				Expect(err).NotTo(HaveOccurred())
   487  
   488  				Expect(fakeSCCFuncs.ApproveChaincodeDefinitionForOrgCallCount()).To(Equal(1))
   489  				chname, ccname, cd, packageID, pubState, privState := fakeSCCFuncs.ApproveChaincodeDefinitionForOrgArgsForCall(0)
   490  				Expect(chname).To(Equal("test-channel"))
   491  				Expect(ccname).To(Equal("cc_name"))
   492  				Expect(cd.Sequence).To(Equal(int64(7)))
   493  				Expect(cd.EndorsementInfo).To(Equal(&lb.ChaincodeEndorsementInfo{
   494  					Version:           "version_1.0",
   495  					EndorsementPlugin: "endorsement-plugin",
   496  					InitRequired:      true,
   497  				}))
   498  				Expect(cd.ValidationInfo).To(Equal(&lb.ChaincodeValidationInfo{
   499  					ValidationPlugin:    "validation-plugin",
   500  					ValidationParameter: []byte("validation-parameter"),
   501  				}))
   502  				Expect(proto.Equal(
   503  					cd.Collections,
   504  					collConfigs.toProtoCollectionConfigPackage(),
   505  				)).Should(BeTrue())
   506  
   507  				Expect(packageID).To(Equal("hash"))
   508  				Expect(pubState).To(Equal(fakeStub))
   509  				Expect(privState).To(BeAssignableToTypeOf(&lifecycle.ChaincodePrivateLedgerShim{}))
   510  				Expect(privState.(*lifecycle.ChaincodePrivateLedgerShim).Collection).To(Equal("_implicit_org_fake-mspid"))
   511  			})
   512  
   513  			Context("when the chaincode name contains invalid characters", func() {
   514  				BeforeEach(func() {
   515  					arg.Name = "!nvalid"
   516  				})
   517  
   518  				It("wraps and returns the error", func() {
   519  					res := scc.Invoke(fakeStub)
   520  					Expect(res.Status).To(Equal(int32(500)))
   521  					Expect(res.Message).To(Equal("failed to invoke backing implementation of 'ApproveChaincodeDefinitionForMyOrg': invalid chaincode name '!nvalid'. Names can only consist of alphanumerics, '_', and '-' and can only begin with alphanumerics"))
   522  				})
   523  			})
   524  
   525  			Context("when the chaincode version contains invalid characters", func() {
   526  				BeforeEach(func() {
   527  					arg.Version = "$money$"
   528  				})
   529  
   530  				It("wraps and returns the error", func() {
   531  					res := scc.Invoke(fakeStub)
   532  					Expect(res.Status).To(Equal(int32(500)))
   533  					Expect(res.Message).To(Equal("failed to invoke backing implementation of 'ApproveChaincodeDefinitionForMyOrg': invalid chaincode version '$money$'. Versions can only consist of alphanumerics, '_', '-', '+', and '.'"))
   534  				})
   535  			})
   536  
   537  			Context("when the chaincode name matches an existing system chaincode name", func() {
   538  				BeforeEach(func() {
   539  					arg.Name = "cscc"
   540  				})
   541  
   542  				It("wraps and returns the error", func() {
   543  					res := scc.Invoke(fakeStub)
   544  					Expect(res.Status).To(Equal(int32(500)))
   545  					Expect(res.Message).To(Equal("failed to invoke backing implementation of 'ApproveChaincodeDefinitionForMyOrg': chaincode name 'cscc' is the name of a system chaincode"))
   546  				})
   547  			})
   548  
   549  			Context("when a collection name contains invalid characters", func() {
   550  				BeforeEach(func() {
   551  					collConfigs[0].Name = "collection@test"
   552  				})
   553  
   554  				It("wraps and returns the error", func() {
   555  					res := scc.Invoke(fakeStub)
   556  					Expect(res.Status).To(Equal(int32(500)))
   557  					Expect(res.Message).To(Equal("failed to invoke backing implementation of 'ApproveChaincodeDefinitionForMyOrg': invalid collection name 'collection@test'. Names can only consist of alphanumerics, '_', and '-' and cannot begin with '_'"))
   558  				})
   559  			})
   560  
   561  			Context("when a collection name begins with an invalid character", func() {
   562  				BeforeEach(func() {
   563  					collConfigs[0].Name = "_collection"
   564  				})
   565  
   566  				It("wraps and returns the error", func() {
   567  					res := scc.Invoke(fakeStub)
   568  					Expect(res.Status).To(Equal(int32(500)))
   569  					Expect(res.Message).To(Equal("failed to invoke backing implementation of 'ApproveChaincodeDefinitionForMyOrg': invalid collection name '_collection'. Names can only consist of alphanumerics, '_', and '-' and cannot begin with '_'"))
   570  				})
   571  			})
   572  
   573  			Context("when collection member-org-policy is nil", func() {
   574  				BeforeEach(func() {
   575  					collConfigs[0].UseGivenMemberOrgPolicy = true
   576  					collConfigs[0].MemberOrgPolicy = nil
   577  				})
   578  
   579  				It("wraps and returns error", func() {
   580  					res := scc.Invoke(fakeStub)
   581  					Expect(res.Status).To(Equal(int32(500)))
   582  					Expect(res.Message).To(Equal("failed to invoke backing implementation of 'ApproveChaincodeDefinitionForMyOrg': collection member policy is not set for collection 'test-collection'"))
   583  				})
   584  			})
   585  
   586  			Context("when collection member-org-policy signature policy is nil", func() {
   587  				BeforeEach(func() {
   588  					collConfigs[0].UseGivenMemberOrgPolicy = true
   589  					collConfigs[0].MemberOrgPolicy = &pb.CollectionPolicyConfig{}
   590  				})
   591  
   592  				It("wraps and returns error", func() {
   593  					res := scc.Invoke(fakeStub)
   594  					Expect(res.Status).To(Equal(int32(500)))
   595  					Expect(res.Message).To(Equal("failed to invoke backing implementation of 'ApproveChaincodeDefinitionForMyOrg': collection member org policy is empty for collection 'test-collection'"))
   596  				})
   597  			})
   598  
   599  			Context("when collection member-org-policy signature policy is not an OR only policy", func() {
   600  				BeforeEach(func() {
   601  					collConfigs[0].Policy = "OR('fakeOrg1.member', AND('fakeOrg2.member', 'fakeOrg3.member'))"
   602  				})
   603  
   604  				It("wraps and returns error", func() {
   605  					res := scc.Invoke(fakeStub)
   606  					Expect(res.Status).To(Equal(int32(500)))
   607  					Expect(res.Message).To(Equal("failed to invoke backing implementation of 'ApproveChaincodeDefinitionForMyOrg': collection-name: test-collection -- error in member org policy: signature policy is not an OR concatenation, NOutOf 2"))
   608  				})
   609  			})
   610  
   611  			Context("when collection member-org-policy signature policy contains unmarshable MSPRole", func() {
   612  				BeforeEach(func() {
   613  					collConfigs[0].Identities[0] = &mspprotos.MSPPrincipal{
   614  						PrincipalClassification: mspprotos.MSPPrincipal_ROLE,
   615  						Principal:               []byte("unmarshable bytes"),
   616  					}
   617  				})
   618  
   619  				It("wraps and returns error", func() {
   620  					res := scc.Invoke(fakeStub)
   621  					Expect(res.Status).To(Equal(int32(500)))
   622  					Expect(res.Message).Should(ContainSubstring("failed to invoke backing implementation of 'ApproveChaincodeDefinitionForMyOrg': collection-name: test-collection -- cannot unmarshal identity bytes into MSPRole"))
   623  				})
   624  			})
   625  
   626  			Context("when collection member-org-policy signature policy contains too few principals", func() {
   627  				BeforeEach(func() {
   628  					collConfigs[0].Identities = collConfigs[0].Identities[0:1]
   629  				})
   630  
   631  				It("wraps and returns error", func() {
   632  					res := scc.Invoke(fakeStub)
   633  					Expect(res.Status).To(Equal(int32(500)))
   634  					Expect(res.Message).Should(ContainSubstring("failed to invoke backing implementation of 'ApproveChaincodeDefinitionForMyOrg': invalid member org policy for collection 'test-collection': identity index out of range, requested 1, but identities length is 1"))
   635  				})
   636  			})
   637  
   638  			Context("when collection MSPRole in member-org-policy in not a channel member", func() {
   639  				BeforeEach(func() {
   640  					fakeMSPManager.GetMSPsReturns(
   641  						map[string]msp.MSP{
   642  							"test-member-ou":       fakeMsp,
   643  							"test-member-identity": fakeMsp,
   644  						},
   645  						nil,
   646  					)
   647  				})
   648  
   649  				It("wraps and returns error", func() {
   650  					res := scc.Invoke(fakeStub)
   651  					Expect(res.Status).To(Equal(int32(500)))
   652  					Expect(res.Message).Should(ContainSubstring("failed to invoke backing implementation of 'ApproveChaincodeDefinitionForMyOrg': collection-name: test-collection -- collection member 'test-member-role' is not part of the channel"))
   653  				})
   654  			})
   655  
   656  			Context("when collection member-org-policy signature policy contains unmarshable ORGANIZATION_UNIT", func() {
   657  				BeforeEach(func() {
   658  					collConfigs[0].Identities[0] = &mspprotos.MSPPrincipal{
   659  						PrincipalClassification: mspprotos.MSPPrincipal_ORGANIZATION_UNIT,
   660  						Principal:               []byte("unmarshable bytes"),
   661  					}
   662  				})
   663  
   664  				It("wraps and returns error", func() {
   665  					res := scc.Invoke(fakeStub)
   666  					Expect(res.Status).To(Equal(int32(500)))
   667  					Expect(res.Message).Should(ContainSubstring("failed to invoke backing implementation of 'ApproveChaincodeDefinitionForMyOrg': collection-name: test-collection -- cannot unmarshal identity bytes into OrganizationUnit"))
   668  				})
   669  			})
   670  
   671  			Context("when collection MSPOU in member-org-policy in not a channel member", func() {
   672  				BeforeEach(func() {
   673  					fakeMSPManager.GetMSPsReturns(
   674  						map[string]msp.MSP{
   675  							"test-member-role":     fakeMsp,
   676  							"test-member-identity": fakeMsp,
   677  						},
   678  						nil,
   679  					)
   680  				})
   681  
   682  				It("wraps and returns error", func() {
   683  					res := scc.Invoke(fakeStub)
   684  					Expect(res.Status).To(Equal(int32(500)))
   685  					Expect(res.Message).To(Equal("failed to invoke backing implementation of 'ApproveChaincodeDefinitionForMyOrg': collection-name: test-collection -- collection member 'test-member-ou' is not part of the channel"))
   686  				})
   687  			})
   688  
   689  			Context("when collection MSP identity in member-org-policy in not a channel member", func() {
   690  				BeforeEach(func() {
   691  					fakeMSPManager.DeserializeIdentityReturns(nil, errors.New("Nope"))
   692  				})
   693  
   694  				It("wraps and returns error", func() {
   695  					res := scc.Invoke(fakeStub)
   696  					Expect(res.Status).To(Equal(int32(500)))
   697  					Expect(res.Message).To(Equal("failed to invoke backing implementation of 'ApproveChaincodeDefinitionForMyOrg': collection-name: test-collection -- contains an identity that is not part of the channel"))
   698  				})
   699  			})
   700  
   701  			Context("when collection member-org-policy signature policy contains unsupported principal type", func() {
   702  				BeforeEach(func() {
   703  					collConfigs[0].Identities[0] = &mspprotos.MSPPrincipal{
   704  						PrincipalClassification: mspprotos.MSPPrincipal_ANONYMITY,
   705  					}
   706  				})
   707  
   708  				It("wraps and returns error", func() {
   709  					res := scc.Invoke(fakeStub)
   710  					Expect(res.Status).To(Equal(int32(500)))
   711  					Expect(res.Message).To(Equal("failed to invoke backing implementation of 'ApproveChaincodeDefinitionForMyOrg': collection-name: test-collection -- principal type ANONYMITY is not supported"))
   712  				})
   713  			})
   714  
   715  			Context("when collection config contains duplicate collections", func() {
   716  				BeforeEach(func() {
   717  					collConfigs = append(collConfigs, collConfigs[0])
   718  				})
   719  
   720  				It("wraps and returns error", func() {
   721  					res := scc.Invoke(fakeStub)
   722  					Expect(res.Status).To(Equal(int32(500)))
   723  					Expect(res.Message).To(Equal("failed to invoke backing implementation of 'ApproveChaincodeDefinitionForMyOrg': collection-name: test-collection -- found duplicate in collection configuration"))
   724  				})
   725  			})
   726  
   727  			Context("when collection config contains requiredPeerCount < zero", func() {
   728  				BeforeEach(func() {
   729  					collConfigs[0].RequiredPeerCount = -2
   730  				})
   731  
   732  				It("wraps and returns error", func() {
   733  					res := scc.Invoke(fakeStub)
   734  					Expect(res.Status).To(Equal(int32(500)))
   735  					Expect(res.Message).To(Equal("failed to invoke backing implementation of 'ApproveChaincodeDefinitionForMyOrg': collection-name: test-collection -- requiredPeerCount (-2) cannot be less than zero"))
   736  				})
   737  			})
   738  
   739  			Context("when collection config contains requiredPeerCount > maxPeerCount", func() {
   740  				BeforeEach(func() {
   741  					collConfigs[0].MaxPeerCount = 10
   742  					collConfigs[0].RequiredPeerCount = 20
   743  				})
   744  
   745  				It("wraps and returns error", func() {
   746  					res := scc.Invoke(fakeStub)
   747  					Expect(res.Status).To(Equal(int32(500)))
   748  					Expect(res.Message).To(Equal("failed to invoke backing implementation of 'ApproveChaincodeDefinitionForMyOrg': collection-name: test-collection -- maximum peer count (10) cannot be less than the required peer count (20)"))
   749  				})
   750  			})
   751  
   752  			Context("when committed definition and proposed definition both contains no collection config", func() {
   753  				BeforeEach(func() {
   754  					fakeDeployedCCInfoProvider.ChaincodeInfoReturns(&ledger.DeployedChaincodeInfo{}, nil)
   755  					arg.Collections = nil
   756  				})
   757  
   758  				It("does not return error", func() {
   759  					res := scc.Invoke(fakeStub)
   760  					Expect(res.Status).To(Equal(int32(200)))
   761  				})
   762  			})
   763  
   764  			Context("when committed definition and proposed definition both contains same collection config", func() {
   765  				BeforeEach(func() {
   766  					fakeDeployedCCInfoProvider.ChaincodeInfoReturns(
   767  						&ledger.DeployedChaincodeInfo{
   768  							ExplicitCollectionConfigPkg: collConfigs.toProtoCollectionConfigPackage(),
   769  						},
   770  						nil,
   771  					)
   772  				})
   773  
   774  				It("does not return error", func() {
   775  					res := scc.Invoke(fakeStub)
   776  					Expect(res.Status).To(Equal(int32(200)))
   777  				})
   778  			})
   779  
   780  			Context("when committed definition contains collection config and the proposed definition contains no collection config", func() {
   781  				BeforeEach(func() {
   782  					fakeDeployedCCInfoProvider.ChaincodeInfoReturns(
   783  						&ledger.DeployedChaincodeInfo{
   784  							ExplicitCollectionConfigPkg: collConfigs.toProtoCollectionConfigPackage(),
   785  						},
   786  						nil,
   787  					)
   788  					collConfigs = nil
   789  				})
   790  
   791  				It("wraps and returns error", func() {
   792  					res := scc.Invoke(fakeStub)
   793  					Expect(res.Status).To(Equal(int32(500)))
   794  					Expect(res.Message).To(Equal("failed to invoke backing implementation of 'ApproveChaincodeDefinitionForMyOrg': the proposed collection config does not contain previously defined collections"))
   795  				})
   796  			})
   797  
   798  			Context("when committed definition contains a collection that is not defined in the proposed definition", func() {
   799  				BeforeEach(func() {
   800  					committedCollConfigs := collConfigs.deepCopy()
   801  					additionalCommittedConfigs := collConfigs.deepCopy()
   802  					additionalCommittedConfigs[0].Name = "missing-collection"
   803  					committedCollConfigs = append(committedCollConfigs, additionalCommittedConfigs...)
   804  					fakeDeployedCCInfoProvider.ChaincodeInfoReturns(
   805  						&ledger.DeployedChaincodeInfo{
   806  							ExplicitCollectionConfigPkg: committedCollConfigs.toProtoCollectionConfigPackage(),
   807  						},
   808  						nil,
   809  					)
   810  				})
   811  
   812  				It("wraps and returns error", func() {
   813  					res := scc.Invoke(fakeStub)
   814  					Expect(res.Status).To(Equal(int32(500)))
   815  					Expect(res.Message).To(Equal("failed to invoke backing implementation of 'ApproveChaincodeDefinitionForMyOrg': existing collection [missing-collection] missing in the proposed collection configuration"))
   816  				})
   817  			})
   818  
   819  			Context("when committed definition contains a collection that has different BTL than defined in the proposed definition", func() {
   820  				var (
   821  					committedCollConfigs collectionConfigs
   822  				)
   823  				BeforeEach(func() {
   824  					committedCollConfigs = collConfigs.deepCopy()
   825  					committedCollConfigs[0].BlockToLive = committedCollConfigs[0].BlockToLive + 1
   826  					fakeDeployedCCInfoProvider.ChaincodeInfoReturns(
   827  						&ledger.DeployedChaincodeInfo{
   828  							ExplicitCollectionConfigPkg: committedCollConfigs.toProtoCollectionConfigPackage(),
   829  						},
   830  						nil,
   831  					)
   832  				})
   833  
   834  				It("wraps and returns error", func() {
   835  					res := scc.Invoke(fakeStub)
   836  					Expect(res.Status).To(Equal(int32(500)))
   837  					Expect(res.Message).To(Equal(
   838  						fmt.Sprintf(
   839  							"failed to invoke backing implementation of 'ApproveChaincodeDefinitionForMyOrg': the BlockToLive in an existing collection [test-collection] modified. Existing value [%d]",
   840  							committedCollConfigs[0].BlockToLive,
   841  						),
   842  					))
   843  				})
   844  			})
   845  
   846  			Context("when not able to get MSPManager for evaluating collection config", func() {
   847  				BeforeEach(func() {
   848  					fakeChannelConfig.MSPManagerReturns(nil)
   849  				})
   850  
   851  				It("wraps and returns error", func() {
   852  					res := scc.Invoke(fakeStub)
   853  					Expect(res.Status).To(Equal(int32(500)))
   854  					Expect(res.Message).To(Equal("failed to invoke backing implementation of 'ApproveChaincodeDefinitionForMyOrg': could not get MSP manager for channel 'test-channel'"))
   855  				})
   856  			})
   857  
   858  			Context("when not able to get MSPs for evaluating collection config", func() {
   859  				BeforeEach(func() {
   860  					fakeMSPManager.GetMSPsReturns(nil, errors.New("No MSPs"))
   861  				})
   862  
   863  				It("wraps and returns error", func() {
   864  					res := scc.Invoke(fakeStub)
   865  					Expect(res.Status).To(Equal(int32(500)))
   866  					Expect(res.Message).To(Equal("failed to invoke backing implementation of 'ApproveChaincodeDefinitionForMyOrg': could not get MSPs: No MSPs"))
   867  				})
   868  			})
   869  
   870  			Context("when not able to get committed definition for evaluating collection config", func() {
   871  				BeforeEach(func() {
   872  					fakeDeployedCCInfoProvider.ChaincodeInfoReturns(nil, errors.New("could not fetch definition"))
   873  				})
   874  
   875  				It("wraps and returns error", func() {
   876  					res := scc.Invoke(fakeStub)
   877  					Expect(res.Status).To(Equal(int32(500)))
   878  					Expect(res.Message).To(Equal("failed to invoke backing implementation of 'ApproveChaincodeDefinitionForMyOrg': could not retrieve committed definition for chaincode 'cc_name': could not fetch definition"))
   879  				})
   880  			})
   881  
   882  			Context("when the underlying function implementation fails", func() {
   883  				BeforeEach(func() {
   884  					fakeSCCFuncs.ApproveChaincodeDefinitionForOrgReturns(fmt.Errorf("underlying-error"))
   885  				})
   886  
   887  				It("wraps and returns the error", func() {
   888  					res := scc.Invoke(fakeStub)
   889  					Expect(res.Status).To(Equal(int32(500)))
   890  					Expect(res.Message).To(Equal("failed to invoke backing implementation of 'ApproveChaincodeDefinitionForMyOrg': underlying-error"))
   891  				})
   892  			})
   893  
   894  			Context("when the lifecycle capability is not enabled", func() {
   895  				BeforeEach(func() {
   896  					fakeCapabilities.LifecycleV20Returns(false)
   897  				})
   898  
   899  				It("returns an error", func() {
   900  					Expect(scc.Invoke(fakeStub)).To(Equal(shim.Error("cannot use new lifecycle for channel 'test-channel' as it does not have the required capabilities enabled")))
   901  				})
   902  			})
   903  		})
   904  
   905  		Describe("CommitChaincodeDefinition", func() {
   906  			var (
   907  				err            error
   908  				arg            *lb.CommitChaincodeDefinitionArgs
   909  				marshaledArg   []byte
   910  				fakeOrgConfigs []*mock.ApplicationOrgConfig
   911  			)
   912  
   913  			BeforeEach(func() {
   914  				arg = &lb.CommitChaincodeDefinitionArgs{
   915  					Sequence:            7,
   916  					Name:                "cc-name2",
   917  					Version:             "version-2+2",
   918  					EndorsementPlugin:   "endorsement-plugin",
   919  					ValidationPlugin:    "validation-plugin",
   920  					ValidationParameter: []byte("validation-parameter"),
   921  					Collections: &pb.CollectionConfigPackage{
   922  						Config: []*pb.CollectionConfig{
   923  							{
   924  								Payload: &pb.CollectionConfig_StaticCollectionConfig{
   925  									StaticCollectionConfig: &pb.StaticCollectionConfig{
   926  										Name: "test_collection",
   927  										MemberOrgsPolicy: &pb.CollectionPolicyConfig{
   928  											Payload: &pb.CollectionPolicyConfig_SignaturePolicy{
   929  												SignaturePolicy: policydsl.SignedByMspMember("org0"),
   930  											},
   931  										},
   932  									},
   933  								},
   934  							},
   935  						},
   936  					},
   937  					InitRequired: true,
   938  				}
   939  
   940  				marshaledArg, err = proto.Marshal(arg)
   941  				Expect(err).NotTo(HaveOccurred())
   942  
   943  				fakeStub.GetArgsReturns([][]byte{[]byte("CommitChaincodeDefinition"), marshaledArg})
   944  
   945  				fakeOrgConfigs = []*mock.ApplicationOrgConfig{{}, {}}
   946  				fakeOrgConfigs[0].MSPIDReturns("fake-mspid")
   947  				fakeOrgConfigs[1].MSPIDReturns("other-mspid")
   948  
   949  				fakeApplicationConfig.OrganizationsReturns(map[string]channelconfig.ApplicationOrg{
   950  					"org0": fakeOrgConfigs[0],
   951  					"org1": fakeOrgConfigs[1],
   952  				})
   953  
   954  				fakeSCCFuncs.CommitChaincodeDefinitionReturns(map[string]bool{
   955  					"fake-mspid":  true,
   956  					"other-mspid": true,
   957  				}, nil)
   958  
   959  				fakeMsp := &mock.MSP{}
   960  				fakeMSPManager.GetMSPsReturns(
   961  					map[string]msp.MSP{
   962  						"org0": fakeMsp,
   963  						"org1": fakeMsp,
   964  					},
   965  					nil,
   966  				)
   967  			})
   968  
   969  			It("passes the arguments to and returns the results from the backing scc function implementation", func() {
   970  				res := scc.Invoke(fakeStub)
   971  				Expect(res.Message).To(Equal(""))
   972  				Expect(res.Status).To(Equal(int32(200)))
   973  				payload := &lb.CommitChaincodeDefinitionResult{}
   974  				err = proto.Unmarshal(res.Payload, payload)
   975  				Expect(err).NotTo(HaveOccurred())
   976  
   977  				Expect(fakeSCCFuncs.CommitChaincodeDefinitionCallCount()).To(Equal(1))
   978  				chname, ccname, cd, pubState, orgStates := fakeSCCFuncs.CommitChaincodeDefinitionArgsForCall(0)
   979  				Expect(chname).To(Equal("test-channel"))
   980  				Expect(ccname).To(Equal("cc-name2"))
   981  				Expect(cd).To(Equal(&lifecycle.ChaincodeDefinition{
   982  					Sequence: 7,
   983  					EndorsementInfo: &lb.ChaincodeEndorsementInfo{
   984  						Version:           "version-2+2",
   985  						EndorsementPlugin: "endorsement-plugin",
   986  						InitRequired:      true,
   987  					},
   988  					ValidationInfo: &lb.ChaincodeValidationInfo{
   989  						ValidationPlugin:    "validation-plugin",
   990  						ValidationParameter: []byte("validation-parameter"),
   991  					},
   992  					Collections: &pb.CollectionConfigPackage{
   993  						Config: []*pb.CollectionConfig{
   994  							{
   995  								Payload: &pb.CollectionConfig_StaticCollectionConfig{
   996  									StaticCollectionConfig: &pb.StaticCollectionConfig{
   997  										Name: "test_collection",
   998  										MemberOrgsPolicy: &pb.CollectionPolicyConfig{
   999  											Payload: &pb.CollectionPolicyConfig_SignaturePolicy{
  1000  												SignaturePolicy: policydsl.SignedByMspMember("org0"),
  1001  											},
  1002  										},
  1003  									},
  1004  								},
  1005  							},
  1006  						},
  1007  					},
  1008  				}))
  1009  				Expect(pubState).To(Equal(fakeStub))
  1010  				Expect(len(orgStates)).To(Equal(2))
  1011  				Expect(orgStates[0]).To(BeAssignableToTypeOf(&lifecycle.ChaincodePrivateLedgerShim{}))
  1012  				Expect(orgStates[1]).To(BeAssignableToTypeOf(&lifecycle.ChaincodePrivateLedgerShim{}))
  1013  				collection0 := orgStates[0].(*lifecycle.ChaincodePrivateLedgerShim).Collection
  1014  				collection1 := orgStates[1].(*lifecycle.ChaincodePrivateLedgerShim).Collection
  1015  				Expect([]string{collection0, collection1}).To(ConsistOf("_implicit_org_fake-mspid", "_implicit_org_other-mspid"))
  1016  			})
  1017  
  1018  			Context("when the chaincode name begins with an invalid character", func() {
  1019  				BeforeEach(func() {
  1020  					arg.Name = "_invalid"
  1021  
  1022  					marshaledArg, err = proto.Marshal(arg)
  1023  					Expect(err).NotTo(HaveOccurred())
  1024  					fakeStub.GetArgsReturns([][]byte{[]byte("CommitChaincodeDefinition"), marshaledArg})
  1025  				})
  1026  
  1027  				It("wraps and returns the error", func() {
  1028  					res := scc.Invoke(fakeStub)
  1029  					Expect(res.Status).To(Equal(int32(500)))
  1030  					Expect(res.Message).To(Equal("failed to invoke backing implementation of 'CommitChaincodeDefinition': invalid chaincode name '_invalid'. Names can only consist of alphanumerics, '_', and '-' and can only begin with alphanumerics"))
  1031  				})
  1032  			})
  1033  
  1034  			Context("when the chaincode version contains invalid characters", func() {
  1035  				BeforeEach(func() {
  1036  					arg.Version = "$money$"
  1037  
  1038  					marshaledArg, err = proto.Marshal(arg)
  1039  					Expect(err).NotTo(HaveOccurred())
  1040  					fakeStub.GetArgsReturns([][]byte{[]byte("CommitChaincodeDefinition"), marshaledArg})
  1041  				})
  1042  
  1043  				It("wraps and returns the error", func() {
  1044  					res := scc.Invoke(fakeStub)
  1045  					Expect(res.Status).To(Equal(int32(500)))
  1046  					Expect(res.Message).To(Equal("failed to invoke backing implementation of 'CommitChaincodeDefinition': invalid chaincode version '$money$'. Versions can only consist of alphanumerics, '_', '-', '+', and '.'"))
  1047  				})
  1048  			})
  1049  
  1050  			Context("when the chaincode name matches an existing system chaincode name", func() {
  1051  				BeforeEach(func() {
  1052  					arg.Name = "qscc"
  1053  
  1054  					marshaledArg, err = proto.Marshal(arg)
  1055  					Expect(err).NotTo(HaveOccurred())
  1056  					fakeStub.GetArgsReturns([][]byte{[]byte("CommitChaincodeDefinition"), marshaledArg})
  1057  				})
  1058  
  1059  				It("wraps and returns the error", func() {
  1060  					res := scc.Invoke(fakeStub)
  1061  					Expect(res.Status).To(Equal(int32(500)))
  1062  					Expect(res.Message).To(Equal("failed to invoke backing implementation of 'CommitChaincodeDefinition': chaincode name 'qscc' is the name of a system chaincode"))
  1063  				})
  1064  			})
  1065  
  1066  			Context("when a collection name contains invalid characters", func() {
  1067  				BeforeEach(func() {
  1068  					arg.Collections = &pb.CollectionConfigPackage{
  1069  						Config: []*pb.CollectionConfig{
  1070  							{
  1071  								Payload: &pb.CollectionConfig_StaticCollectionConfig{
  1072  									StaticCollectionConfig: &pb.StaticCollectionConfig{
  1073  										Name: "collection(test",
  1074  									},
  1075  								},
  1076  							},
  1077  						},
  1078  					}
  1079  
  1080  					marshaledArg, err = proto.Marshal(arg)
  1081  					Expect(err).NotTo(HaveOccurred())
  1082  					fakeStub.GetArgsReturns([][]byte{[]byte("CommitChaincodeDefinition"), marshaledArg})
  1083  				})
  1084  
  1085  				It("wraps and returns the error", func() {
  1086  					res := scc.Invoke(fakeStub)
  1087  					Expect(res.Status).To(Equal(int32(500)))
  1088  					Expect(res.Message).To(Equal("failed to invoke backing implementation of 'CommitChaincodeDefinition': invalid collection name 'collection(test'. Names can only consist of alphanumerics, '_', and '-' and cannot begin with '_'"))
  1089  				})
  1090  			})
  1091  
  1092  			Context("when a collection name begins with an invalid character", func() {
  1093  				BeforeEach(func() {
  1094  					arg.Collections = &pb.CollectionConfigPackage{
  1095  						Config: []*pb.CollectionConfig{
  1096  							{
  1097  								Payload: &pb.CollectionConfig_StaticCollectionConfig{
  1098  									StaticCollectionConfig: &pb.StaticCollectionConfig{
  1099  										Name: "&collection",
  1100  									},
  1101  								},
  1102  							},
  1103  						},
  1104  					}
  1105  
  1106  					marshaledArg, err = proto.Marshal(arg)
  1107  					Expect(err).NotTo(HaveOccurred())
  1108  					fakeStub.GetArgsReturns([][]byte{[]byte("CommitChaincodeDefinition"), marshaledArg})
  1109  				})
  1110  
  1111  				It("wraps and returns the error", func() {
  1112  					res := scc.Invoke(fakeStub)
  1113  					Expect(res.Status).To(Equal(int32(500)))
  1114  					Expect(res.Message).To(Equal("failed to invoke backing implementation of 'CommitChaincodeDefinition': invalid collection name '&collection'. Names can only consist of alphanumerics, '_', and '-' and cannot begin with '_'"))
  1115  				})
  1116  			})
  1117  
  1118  			Context("when there is no agreement from this peer's org", func() {
  1119  				BeforeEach(func() {
  1120  					fakeSCCFuncs.CommitChaincodeDefinitionReturns(map[string]bool{
  1121  						"fake-mspid":  false,
  1122  						"other-mspid": false,
  1123  					}, nil)
  1124  				})
  1125  
  1126  				It("returns an error indicating the lack of agreement", func() {
  1127  					res := scc.Invoke(fakeStub)
  1128  					Expect(res.Status).To(Equal(int32(500)))
  1129  					Expect(res.Message).To(Equal("failed to invoke backing implementation of 'CommitChaincodeDefinition': chaincode definition not agreed to by this org (fake-mspid)"))
  1130  				})
  1131  			})
  1132  
  1133  			Context("when there is no match for this peer's org's MSPID", func() {
  1134  				BeforeEach(func() {
  1135  					fakeOrgConfigs[0].MSPIDReturns("other-mspid")
  1136  				})
  1137  
  1138  				It("returns an error indicating the lack of agreement", func() {
  1139  					res := scc.Invoke(fakeStub)
  1140  					Expect(res.Status).To(Equal(int32(500)))
  1141  					Expect(res.Message).To(Equal("failed to invoke backing implementation of 'CommitChaincodeDefinition': impossibly, this peer's org is processing requests for a channel it is not a member of"))
  1142  				})
  1143  			})
  1144  
  1145  			Context("when there is no channel config", func() {
  1146  				BeforeEach(func() {
  1147  					fakeChannelConfigSource.GetStableChannelConfigReturns(nil)
  1148  				})
  1149  
  1150  				It("returns an error indicating the lack of agreement", func() {
  1151  					res := scc.Invoke(fakeStub)
  1152  					Expect(res.Status).To(Equal(int32(500)))
  1153  					Expect(res.Message).To(Equal("could not get channelconfig for channel 'test-channel'"))
  1154  				})
  1155  			})
  1156  
  1157  			Context("when there is no application config", func() {
  1158  				BeforeEach(func() {
  1159  					fakeChannelConfig.ApplicationConfigReturns(nil, false)
  1160  				})
  1161  
  1162  				It("returns an error indicating the lack of agreement", func() {
  1163  					res := scc.Invoke(fakeStub)
  1164  					Expect(res.Status).To(Equal(int32(500)))
  1165  					Expect(res.Message).To(Equal("could not get application config for channel 'test-channel'"))
  1166  				})
  1167  
  1168  				Context("when there is no application config because there is no channel", func() {
  1169  					BeforeEach(func() {
  1170  						fakeStub.GetChannelIDReturns("")
  1171  					})
  1172  
  1173  					It("returns an error indicating the lack of agreement", func() {
  1174  						res := scc.Invoke(fakeStub)
  1175  						Expect(res.Status).To(Equal(int32(500)))
  1176  						Expect(res.Message).To(Equal("failed to invoke backing implementation of 'CommitChaincodeDefinition': no application config for channel ''"))
  1177  					})
  1178  				})
  1179  			})
  1180  
  1181  			Context("when the underlying function implementation fails", func() {
  1182  				BeforeEach(func() {
  1183  					fakeSCCFuncs.CommitChaincodeDefinitionReturns(nil, fmt.Errorf("underlying-error"))
  1184  				})
  1185  
  1186  				It("wraps and returns the error", func() {
  1187  					res := scc.Invoke(fakeStub)
  1188  					Expect(res.Status).To(Equal(int32(500)))
  1189  					Expect(res.Message).To(Equal("failed to invoke backing implementation of 'CommitChaincodeDefinition': underlying-error"))
  1190  				})
  1191  			})
  1192  		})
  1193  
  1194  		Describe("CheckCommitReadiness", func() {
  1195  			var (
  1196  				err            error
  1197  				arg            *lb.CheckCommitReadinessArgs
  1198  				marshaledArg   []byte
  1199  				fakeOrgConfigs []*mock.ApplicationOrgConfig
  1200  			)
  1201  
  1202  			BeforeEach(func() {
  1203  				arg = &lb.CheckCommitReadinessArgs{
  1204  					Sequence:            7,
  1205  					Name:                "name",
  1206  					Version:             "version",
  1207  					EndorsementPlugin:   "endorsement-plugin",
  1208  					ValidationPlugin:    "validation-plugin",
  1209  					ValidationParameter: []byte("validation-parameter"),
  1210  					Collections:         &pb.CollectionConfigPackage{},
  1211  					InitRequired:        true,
  1212  				}
  1213  
  1214  				marshaledArg, err = proto.Marshal(arg)
  1215  				Expect(err).NotTo(HaveOccurred())
  1216  
  1217  				fakeStub.GetArgsReturns([][]byte{[]byte("CheckCommitReadiness"), marshaledArg})
  1218  
  1219  				fakeOrgConfigs = []*mock.ApplicationOrgConfig{{}, {}}
  1220  				fakeOrgConfigs[0].MSPIDReturns("fake-mspid")
  1221  				fakeOrgConfigs[1].MSPIDReturns("other-mspid")
  1222  
  1223  				fakeApplicationConfig.OrganizationsReturns(map[string]channelconfig.ApplicationOrg{
  1224  					"org0": fakeOrgConfigs[0],
  1225  					"org1": fakeOrgConfigs[1],
  1226  				})
  1227  
  1228  				fakeSCCFuncs.CheckCommitReadinessReturns(map[string]bool{
  1229  					"fake-mspid":  true,
  1230  					"other-mspid": true,
  1231  				}, nil)
  1232  			})
  1233  
  1234  			It("passes the arguments to and returns the results from the backing scc function implementation", func() {
  1235  				res := scc.Invoke(fakeStub)
  1236  				Expect(res.Message).To(Equal(""))
  1237  				Expect(res.Status).To(Equal(int32(200)))
  1238  				payload := &lb.CheckCommitReadinessResult{}
  1239  				err = proto.Unmarshal(res.Payload, payload)
  1240  				Expect(err).NotTo(HaveOccurred())
  1241  
  1242  				orgApprovals := payload.GetApprovals()
  1243  				Expect(orgApprovals).NotTo(BeNil())
  1244  				Expect(len(orgApprovals)).To(Equal(2))
  1245  				Expect(orgApprovals["fake-mspid"]).To(BeTrue())
  1246  				Expect(orgApprovals["other-mspid"]).To(BeTrue())
  1247  
  1248  				Expect(fakeSCCFuncs.CheckCommitReadinessCallCount()).To(Equal(1))
  1249  				chname, ccname, cd, pubState, orgStates := fakeSCCFuncs.CheckCommitReadinessArgsForCall(0)
  1250  				Expect(chname).To(Equal("test-channel"))
  1251  				Expect(ccname).To(Equal("name"))
  1252  				Expect(cd).To(Equal(&lifecycle.ChaincodeDefinition{
  1253  					Sequence: 7,
  1254  					EndorsementInfo: &lb.ChaincodeEndorsementInfo{
  1255  						Version:           "version",
  1256  						EndorsementPlugin: "endorsement-plugin",
  1257  						InitRequired:      true,
  1258  					},
  1259  					ValidationInfo: &lb.ChaincodeValidationInfo{
  1260  						ValidationPlugin:    "validation-plugin",
  1261  						ValidationParameter: []byte("validation-parameter"),
  1262  					},
  1263  					Collections: arg.Collections,
  1264  				}))
  1265  				Expect(pubState).To(Equal(fakeStub))
  1266  				Expect(orgStates).To(HaveLen(2))
  1267  				Expect(orgStates[0]).To(BeAssignableToTypeOf(&lifecycle.ChaincodePrivateLedgerShim{}))
  1268  				Expect(orgStates[1]).To(BeAssignableToTypeOf(&lifecycle.ChaincodePrivateLedgerShim{}))
  1269  				collection0 := orgStates[0].(*lifecycle.ChaincodePrivateLedgerShim).Collection
  1270  				collection1 := orgStates[1].(*lifecycle.ChaincodePrivateLedgerShim).Collection
  1271  				Expect([]string{collection0, collection1}).To(ConsistOf("_implicit_org_fake-mspid", "_implicit_org_other-mspid"))
  1272  			})
  1273  
  1274  			Context("when there is no application config", func() {
  1275  				BeforeEach(func() {
  1276  					fakeChannelConfig.ApplicationConfigReturns(nil, false)
  1277  				})
  1278  
  1279  				It("returns an error", func() {
  1280  					res := scc.Invoke(fakeStub)
  1281  					Expect(res.Status).To(Equal(int32(500)))
  1282  					Expect(res.Message).To(Equal("could not get application config for channel 'test-channel'"))
  1283  				})
  1284  
  1285  				Context("when there is no application config because there is no channel", func() {
  1286  					BeforeEach(func() {
  1287  						fakeStub.GetChannelIDReturns("")
  1288  					})
  1289  
  1290  					It("returns an error", func() {
  1291  						res := scc.Invoke(fakeStub)
  1292  						Expect(res.Status).To(Equal(int32(500)))
  1293  						Expect(res.Message).To(Equal("failed to invoke backing implementation of 'CheckCommitReadiness': no application config for channel ''"))
  1294  					})
  1295  				})
  1296  			})
  1297  
  1298  			Context("when the underlying function implementation fails", func() {
  1299  				BeforeEach(func() {
  1300  					fakeSCCFuncs.CheckCommitReadinessReturns(nil, fmt.Errorf("underlying-error"))
  1301  				})
  1302  
  1303  				It("wraps and returns the error", func() {
  1304  					res := scc.Invoke(fakeStub)
  1305  					Expect(res.Status).To(Equal(int32(500)))
  1306  					Expect(res.Message).To(Equal("failed to invoke backing implementation of 'CheckCommitReadiness': underlying-error"))
  1307  				})
  1308  			})
  1309  		})
  1310  
  1311  		Describe("QueryChaincodeDefinition", func() {
  1312  			var (
  1313  				arg            *lb.QueryChaincodeDefinitionArgs
  1314  				marshaledArg   []byte
  1315  				fakeOrgConfigs []*mock.ApplicationOrgConfig
  1316  			)
  1317  
  1318  			BeforeEach(func() {
  1319  				arg = &lb.QueryChaincodeDefinitionArgs{
  1320  					Name: "cc-name",
  1321  				}
  1322  
  1323  				var err error
  1324  				marshaledArg, err = proto.Marshal(arg)
  1325  				Expect(err).NotTo(HaveOccurred())
  1326  
  1327  				fakeOrgConfigs = []*mock.ApplicationOrgConfig{{}, {}}
  1328  				fakeOrgConfigs[0].MSPIDReturns("fake-mspid")
  1329  				fakeOrgConfigs[1].MSPIDReturns("other-mspid")
  1330  
  1331  				fakeApplicationConfig.OrganizationsReturns(map[string]channelconfig.ApplicationOrg{
  1332  					"org0": fakeOrgConfigs[0],
  1333  					"org1": fakeOrgConfigs[1],
  1334  				})
  1335  
  1336  				fakeStub.GetArgsReturns([][]byte{[]byte("QueryChaincodeDefinition"), marshaledArg})
  1337  				fakeSCCFuncs.QueryChaincodeDefinitionReturns(
  1338  					&lifecycle.ChaincodeDefinition{
  1339  						Sequence: 2,
  1340  						EndorsementInfo: &lb.ChaincodeEndorsementInfo{
  1341  							Version:           "version",
  1342  							EndorsementPlugin: "endorsement-plugin",
  1343  						},
  1344  						ValidationInfo: &lb.ChaincodeValidationInfo{
  1345  							ValidationPlugin:    "validation-plugin",
  1346  							ValidationParameter: []byte("validation-parameter"),
  1347  						},
  1348  						Collections: &pb.CollectionConfigPackage{},
  1349  					},
  1350  					nil,
  1351  				)
  1352  
  1353  				fakeSCCFuncs.QueryOrgApprovalsReturns(
  1354  					map[string]bool{
  1355  						"fake-mspid":  true,
  1356  						"other-mspid": true,
  1357  					},
  1358  					nil,
  1359  				)
  1360  			})
  1361  
  1362  			It("passes the arguments to and returns the results from the backing scc function implementation", func() {
  1363  				res := scc.Invoke(fakeStub)
  1364  				Expect(res.Status).To(Equal(int32(200)))
  1365  				payload := &lb.QueryChaincodeDefinitionResult{}
  1366  				err := proto.Unmarshal(res.Payload, payload)
  1367  				Expect(err).NotTo(HaveOccurred())
  1368  				Expect(proto.Equal(payload, &lb.QueryChaincodeDefinitionResult{
  1369  					Sequence:            2,
  1370  					Version:             "version",
  1371  					EndorsementPlugin:   "endorsement-plugin",
  1372  					ValidationPlugin:    "validation-plugin",
  1373  					ValidationParameter: []byte("validation-parameter"),
  1374  					Collections:         &pb.CollectionConfigPackage{},
  1375  					Approvals: map[string]bool{
  1376  						"fake-mspid":  true,
  1377  						"other-mspid": true,
  1378  					},
  1379  				})).To(BeTrue())
  1380  
  1381  				Expect(fakeSCCFuncs.QueryChaincodeDefinitionCallCount()).To(Equal(1))
  1382  				name, pubState := fakeSCCFuncs.QueryChaincodeDefinitionArgsForCall(0)
  1383  				Expect(name).To(Equal("cc-name"))
  1384  				Expect(pubState).To(Equal(fakeStub))
  1385  				name, _, orgStates := fakeSCCFuncs.QueryOrgApprovalsArgsForCall(0)
  1386  				Expect(name).To(Equal("cc-name"))
  1387  				Expect(orgStates).To(HaveLen(2))
  1388  				Expect(orgStates[0]).To(BeAssignableToTypeOf(&lifecycle.ChaincodePrivateLedgerShim{}))
  1389  				Expect(orgStates[1]).To(BeAssignableToTypeOf(&lifecycle.ChaincodePrivateLedgerShim{}))
  1390  				collection0 := orgStates[0].(*lifecycle.ChaincodePrivateLedgerShim).Collection
  1391  				collection1 := orgStates[1].(*lifecycle.ChaincodePrivateLedgerShim).Collection
  1392  				Expect([]string{collection0, collection1}).To(ConsistOf("_implicit_org_fake-mspid", "_implicit_org_other-mspid"))
  1393  			})
  1394  
  1395  			Context("when the underlying QueryChaincodeDefinition function implementation fails", func() {
  1396  				BeforeEach(func() {
  1397  					fakeSCCFuncs.QueryChaincodeDefinitionReturns(nil, fmt.Errorf("underlying-error"))
  1398  				})
  1399  
  1400  				It("wraps and returns the error", func() {
  1401  					res := scc.Invoke(fakeStub)
  1402  					Expect(res.Status).To(Equal(int32(500)))
  1403  					Expect(res.Message).To(Equal("failed to invoke backing implementation of 'QueryChaincodeDefinition': underlying-error"))
  1404  				})
  1405  			})
  1406  
  1407  			Context("when the underlying QueryOrgApprovals function implementation fails", func() {
  1408  				BeforeEach(func() {
  1409  					fakeSCCFuncs.QueryOrgApprovalsReturns(nil, fmt.Errorf("underlying-error"))
  1410  				})
  1411  
  1412  				It("wraps and returns the error", func() {
  1413  					res := scc.Invoke(fakeStub)
  1414  					Expect(res.Status).To(Equal(int32(500)))
  1415  					Expect(res.Message).To(Equal("failed to invoke backing implementation of 'QueryChaincodeDefinition': underlying-error"))
  1416  				})
  1417  			})
  1418  
  1419  			Context("when the namespace cannot be found", func() {
  1420  				BeforeEach(func() {
  1421  					fakeSCCFuncs.QueryChaincodeDefinitionReturns(nil, lifecycle.ErrNamespaceNotDefined{Namespace: "nicetry"})
  1422  				})
  1423  
  1424  				It("returns 404 Not Found", func() {
  1425  					res := scc.Invoke(fakeStub)
  1426  					Expect(res.Status).To(Equal(int32(404)))
  1427  					Expect(res.Message).To(Equal("namespace nicetry is not defined"))
  1428  				})
  1429  			})
  1430  
  1431  			Context("when there is no application config", func() {
  1432  				BeforeEach(func() {
  1433  					fakeChannelConfig.ApplicationConfigReturns(nil, false)
  1434  				})
  1435  
  1436  				It("returns an error", func() {
  1437  					res := scc.Invoke(fakeStub)
  1438  					Expect(res.Status).To(Equal(int32(500)))
  1439  					Expect(res.Message).To(Equal("could not get application config for channel 'test-channel'"))
  1440  				})
  1441  
  1442  				Context("when there is no application config because there is no channel", func() {
  1443  					BeforeEach(func() {
  1444  						fakeStub.GetChannelIDReturns("")
  1445  					})
  1446  
  1447  					It("returns an error", func() {
  1448  						res := scc.Invoke(fakeStub)
  1449  						Expect(res.Status).To(Equal(int32(500)))
  1450  						Expect(res.Message).To(Equal("failed to invoke backing implementation of 'QueryChaincodeDefinition': no application config for channel ''"))
  1451  					})
  1452  				})
  1453  			})
  1454  		})
  1455  
  1456  		Describe("QueryChaincodeDefinitions", func() {
  1457  			var (
  1458  				arg          *lb.QueryChaincodeDefinitionsArgs
  1459  				marshaledArg []byte
  1460  			)
  1461  
  1462  			BeforeEach(func() {
  1463  				arg = &lb.QueryChaincodeDefinitionsArgs{}
  1464  
  1465  				var err error
  1466  				marshaledArg, err = proto.Marshal(arg)
  1467  				Expect(err).NotTo(HaveOccurred())
  1468  
  1469  				fakeStub.GetArgsReturns([][]byte{[]byte("QueryChaincodeDefinitions"), marshaledArg})
  1470  				fakeSCCFuncs.QueryNamespaceDefinitionsReturns(map[string]string{
  1471  					"foo": "Chaincode",
  1472  					"bar": "Token",
  1473  					"woo": "Chaincode",
  1474  				}, nil)
  1475  				fakeSCCFuncs.QueryChaincodeDefinitionStub = func(name string, rs lifecycle.ReadableState) (*lifecycle.ChaincodeDefinition, error) {
  1476  					cd := &lifecycle.ChaincodeDefinition{
  1477  						Sequence: 2,
  1478  						EndorsementInfo: &lb.ChaincodeEndorsementInfo{
  1479  							Version:           "version",
  1480  							EndorsementPlugin: "endorsement-plugin",
  1481  						},
  1482  						ValidationInfo: &lb.ChaincodeValidationInfo{
  1483  							ValidationPlugin:    "validation-plugin",
  1484  							ValidationParameter: []byte("validation-parameter"),
  1485  						},
  1486  						Collections: &pb.CollectionConfigPackage{},
  1487  					}
  1488  
  1489  					if name == "woo" {
  1490  						cd.Sequence = 5
  1491  					}
  1492  
  1493  					return cd, nil
  1494  				}
  1495  			})
  1496  
  1497  			It("passes the arguments to and returns the results from the backing scc function implementation", func() {
  1498  				res := scc.Invoke(fakeStub)
  1499  				Expect(res.Status).To(Equal(int32(200)))
  1500  				payload := &lb.QueryChaincodeDefinitionsResult{}
  1501  				err := proto.Unmarshal(res.Payload, payload)
  1502  				Expect(err).NotTo(HaveOccurred())
  1503  				Expect(payload.GetChaincodeDefinitions()).To(ConsistOf(
  1504  					&lb.QueryChaincodeDefinitionsResult_ChaincodeDefinition{
  1505  						Name:                "foo",
  1506  						Sequence:            2,
  1507  						Version:             "version",
  1508  						EndorsementPlugin:   "endorsement-plugin",
  1509  						ValidationPlugin:    "validation-plugin",
  1510  						ValidationParameter: []byte("validation-parameter"),
  1511  						Collections:         &pb.CollectionConfigPackage{},
  1512  					},
  1513  					&lb.QueryChaincodeDefinitionsResult_ChaincodeDefinition{
  1514  						Name:                "woo",
  1515  						Sequence:            5,
  1516  						Version:             "version",
  1517  						EndorsementPlugin:   "endorsement-plugin",
  1518  						ValidationPlugin:    "validation-plugin",
  1519  						ValidationParameter: []byte("validation-parameter"),
  1520  						Collections:         &pb.CollectionConfigPackage{},
  1521  					},
  1522  				))
  1523  				Expect(fakeSCCFuncs.QueryNamespaceDefinitionsCallCount()).To(Equal(1))
  1524  				Expect(fakeSCCFuncs.QueryChaincodeDefinitionCallCount()).To(Equal(2))
  1525  			})
  1526  
  1527  			Context("when the underlying QueryChaincodeDefinition function implementation fails", func() {
  1528  				BeforeEach(func() {
  1529  					fakeSCCFuncs.QueryChaincodeDefinitionReturns(nil, fmt.Errorf("underlying-error"))
  1530  				})
  1531  
  1532  				It("wraps and returns the error", func() {
  1533  					res := scc.Invoke(fakeStub)
  1534  					Expect(res.Status).To(Equal(int32(500)))
  1535  					Expect(res.Message).To(Equal("failed to invoke backing implementation of 'QueryChaincodeDefinitions': underlying-error"))
  1536  				})
  1537  			})
  1538  
  1539  			Context("when the underlying QueryNamespaceDefinitions function implementation fails", func() {
  1540  				BeforeEach(func() {
  1541  					fakeSCCFuncs.QueryNamespaceDefinitionsReturns(nil, fmt.Errorf("underlying-error"))
  1542  				})
  1543  
  1544  				It("wraps and returns the error", func() {
  1545  					res := scc.Invoke(fakeStub)
  1546  					Expect(res.Status).To(Equal(int32(500)))
  1547  					Expect(res.Message).To(Equal("failed to invoke backing implementation of 'QueryChaincodeDefinitions': underlying-error"))
  1548  				})
  1549  			})
  1550  		})
  1551  	})
  1552  })
  1553  
  1554  type collectionConfigs []*collectionConfig
  1555  
  1556  func (ccs collectionConfigs) deepCopy() collectionConfigs {
  1557  	var buf bytes.Buffer
  1558  	enc := gob.NewEncoder(&buf)
  1559  	dec := gob.NewDecoder(&buf)
  1560  
  1561  	err := enc.Encode(ccs)
  1562  	Expect(err).NotTo(HaveOccurred())
  1563  	var newCCs collectionConfigs
  1564  	err = dec.Decode(&newCCs)
  1565  	Expect(err).NotTo(HaveOccurred())
  1566  	return newCCs
  1567  }
  1568  
  1569  func (ccs collectionConfigs) toProtoCollectionConfigPackage() *pb.CollectionConfigPackage {
  1570  	if len(ccs) == 0 {
  1571  		return nil
  1572  	}
  1573  	collConfigsProtos := make([]*pb.CollectionConfig, len(ccs))
  1574  	for i, c := range ccs {
  1575  		collConfigsProtos[i] = c.toCollectionConfigProto()
  1576  	}
  1577  	return &pb.CollectionConfigPackage{
  1578  		Config: collConfigsProtos,
  1579  	}
  1580  }
  1581  
  1582  type collectionConfig struct {
  1583  	Name              string
  1584  	RequiredPeerCount int32
  1585  	MaxPeerCount      int32
  1586  	BlockToLive       uint64
  1587  
  1588  	Policy                  string
  1589  	Identities              []*mspprotos.MSPPrincipal
  1590  	UseGivenMemberOrgPolicy bool
  1591  	MemberOrgPolicy         *pb.CollectionPolicyConfig
  1592  }
  1593  
  1594  func (cc *collectionConfig) toCollectionConfigProto() *pb.CollectionConfig {
  1595  	memberOrgPolicy := cc.MemberOrgPolicy
  1596  	if !cc.UseGivenMemberOrgPolicy {
  1597  		spe, err := policydsl.FromString(cc.Policy)
  1598  		Expect(err).NotTo(HaveOccurred())
  1599  		spe.Identities = cc.Identities
  1600  		memberOrgPolicy = &pb.CollectionPolicyConfig{
  1601  			Payload: &pb.CollectionPolicyConfig_SignaturePolicy{
  1602  				SignaturePolicy: spe,
  1603  			},
  1604  		}
  1605  	}
  1606  	return &pb.CollectionConfig{
  1607  		Payload: &pb.CollectionConfig_StaticCollectionConfig{
  1608  			StaticCollectionConfig: &pb.StaticCollectionConfig{
  1609  				Name:              cc.Name,
  1610  				MaximumPeerCount:  cc.MaxPeerCount,
  1611  				RequiredPeerCount: cc.RequiredPeerCount,
  1612  				BlockToLive:       cc.BlockToLive,
  1613  				MemberOrgsPolicy:  memberOrgPolicy,
  1614  			},
  1615  		},
  1616  	}
  1617  }