github.com/hechain20/hechain@v0.0.0-20220316014945-b544036ba106/core/chaincode/lifecycle/scc_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  	"bytes"
    11  	"encoding/gob"
    12  	"fmt"
    13  
    14  	"github.com/hechain20/hechain/core/ledger"
    15  
    16  	"github.com/golang/protobuf/proto"
    17  	"github.com/hechain20/hechain/common/chaincode"
    18  	"github.com/hechain20/hechain/common/channelconfig"
    19  	"github.com/hechain20/hechain/common/policydsl"
    20  	"github.com/hechain20/hechain/core/chaincode/lifecycle"
    21  	"github.com/hechain20/hechain/core/chaincode/lifecycle/mock"
    22  	"github.com/hechain20/hechain/core/chaincode/persistence"
    23  	"github.com/hechain20/hechain/core/dispatcher"
    24  	"github.com/hechain20/hechain/msp"
    25  	"github.com/hyperledger/fabric-chaincode-go/shim"
    26  	mspprotos "github.com/hyperledger/fabric-protos-go/msp"
    27  	pb "github.com/hyperledger/fabric-protos-go/peer"
    28  	lb "github.com/hyperledger/fabric-protos-go/peer/lifecycle"
    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: "package-id",
   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("package-id"))
   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': error validating chaincode definition: 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': error validating chaincode definition: 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': error validating chaincode definition: 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': error validating chaincode definition: 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': error validating chaincode definition: 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': error validating chaincode definition: 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': error validating chaincode definition: 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': error validating chaincode definition: 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': error validating chaincode definition: 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': error validating chaincode definition: 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': error validating chaincode definition: 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': error validating chaincode definition: 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': error validating chaincode definition: 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': error validating chaincode definition: 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': error validating chaincode definition: 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': error validating chaincode definition: 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': error validating chaincode definition: 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': error validating chaincode definition: 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': error validating chaincode definition: 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': error validating chaincode definition: 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 committedCollConfigs collectionConfigs
   821  				BeforeEach(func() {
   822  					committedCollConfigs = collConfigs.deepCopy()
   823  					committedCollConfigs[0].BlockToLive = committedCollConfigs[0].BlockToLive + 1
   824  					fakeDeployedCCInfoProvider.ChaincodeInfoReturns(
   825  						&ledger.DeployedChaincodeInfo{
   826  							ExplicitCollectionConfigPkg: committedCollConfigs.toProtoCollectionConfigPackage(),
   827  						},
   828  						nil,
   829  					)
   830  				})
   831  
   832  				It("wraps and returns error", func() {
   833  					res := scc.Invoke(fakeStub)
   834  					Expect(res.Status).To(Equal(int32(500)))
   835  					Expect(res.Message).To(Equal(
   836  						fmt.Sprintf(
   837  							"failed to invoke backing implementation of 'ApproveChaincodeDefinitionForMyOrg': error validating chaincode definition: the BlockToLive in an existing collection [test-collection] modified. Existing value [%d]",
   838  							committedCollConfigs[0].BlockToLive,
   839  						),
   840  					))
   841  				})
   842  			})
   843  
   844  			Context("when not able to get MSPManager for evaluating collection config", func() {
   845  				BeforeEach(func() {
   846  					fakeChannelConfig.MSPManagerReturns(nil)
   847  				})
   848  
   849  				It("wraps and returns error", func() {
   850  					res := scc.Invoke(fakeStub)
   851  					Expect(res.Status).To(Equal(int32(500)))
   852  					Expect(res.Message).To(Equal("failed to invoke backing implementation of 'ApproveChaincodeDefinitionForMyOrg': error validating chaincode definition: could not get MSP manager for channel 'test-channel'"))
   853  				})
   854  			})
   855  
   856  			Context("when not able to get MSPs for evaluating collection config", func() {
   857  				BeforeEach(func() {
   858  					fakeMSPManager.GetMSPsReturns(nil, errors.New("No MSPs"))
   859  				})
   860  
   861  				It("wraps and returns error", func() {
   862  					res := scc.Invoke(fakeStub)
   863  					Expect(res.Status).To(Equal(int32(500)))
   864  					Expect(res.Message).To(Equal("failed to invoke backing implementation of 'ApproveChaincodeDefinitionForMyOrg': error validating chaincode definition: could not get MSPs: No MSPs"))
   865  				})
   866  			})
   867  
   868  			Context("when not able to get committed definition for evaluating collection config", func() {
   869  				BeforeEach(func() {
   870  					fakeDeployedCCInfoProvider.ChaincodeInfoReturns(nil, errors.New("could not fetch definition"))
   871  				})
   872  
   873  				It("wraps and returns error", func() {
   874  					res := scc.Invoke(fakeStub)
   875  					Expect(res.Status).To(Equal(int32(500)))
   876  					Expect(res.Message).To(Equal("failed to invoke backing implementation of 'ApproveChaincodeDefinitionForMyOrg': error validating chaincode definition: could not retrieve committed definition for chaincode 'cc_name': could not fetch definition"))
   877  				})
   878  			})
   879  
   880  			Context("when the underlying function implementation fails", func() {
   881  				BeforeEach(func() {
   882  					fakeSCCFuncs.ApproveChaincodeDefinitionForOrgReturns(fmt.Errorf("underlying-error"))
   883  				})
   884  
   885  				It("wraps and returns the error", func() {
   886  					res := scc.Invoke(fakeStub)
   887  					Expect(res.Status).To(Equal(int32(500)))
   888  					Expect(res.Message).To(Equal("failed to invoke backing implementation of 'ApproveChaincodeDefinitionForMyOrg': underlying-error"))
   889  				})
   890  			})
   891  
   892  			Context("when the lifecycle capability is not enabled", func() {
   893  				BeforeEach(func() {
   894  					fakeCapabilities.LifecycleV20Returns(false)
   895  				})
   896  
   897  				It("returns an error", func() {
   898  					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")))
   899  				})
   900  			})
   901  		})
   902  
   903  		Describe("CommitChaincodeDefinition", func() {
   904  			var (
   905  				err            error
   906  				arg            *lb.CommitChaincodeDefinitionArgs
   907  				marshaledArg   []byte
   908  				fakeOrgConfigs []*mock.ApplicationOrgConfig
   909  			)
   910  
   911  			BeforeEach(func() {
   912  				arg = &lb.CommitChaincodeDefinitionArgs{
   913  					Sequence:            7,
   914  					Name:                "cc-name2",
   915  					Version:             "version-2+2",
   916  					EndorsementPlugin:   "endorsement-plugin",
   917  					ValidationPlugin:    "validation-plugin",
   918  					ValidationParameter: []byte("validation-parameter"),
   919  					Collections: &pb.CollectionConfigPackage{
   920  						Config: []*pb.CollectionConfig{
   921  							{
   922  								Payload: &pb.CollectionConfig_StaticCollectionConfig{
   923  									StaticCollectionConfig: &pb.StaticCollectionConfig{
   924  										Name: "test_collection",
   925  										MemberOrgsPolicy: &pb.CollectionPolicyConfig{
   926  											Payload: &pb.CollectionPolicyConfig_SignaturePolicy{
   927  												SignaturePolicy: policydsl.SignedByMspMember("org0"),
   928  											},
   929  										},
   930  									},
   931  								},
   932  							},
   933  						},
   934  					},
   935  					InitRequired: true,
   936  				}
   937  
   938  				marshaledArg, err = proto.Marshal(arg)
   939  				Expect(err).NotTo(HaveOccurred())
   940  
   941  				fakeStub.GetArgsReturns([][]byte{[]byte("CommitChaincodeDefinition"), marshaledArg})
   942  
   943  				fakeOrgConfigs = []*mock.ApplicationOrgConfig{{}, {}}
   944  				fakeOrgConfigs[0].MSPIDReturns("fake-mspid")
   945  				fakeOrgConfigs[1].MSPIDReturns("other-mspid")
   946  
   947  				fakeApplicationConfig.OrganizationsReturns(map[string]channelconfig.ApplicationOrg{
   948  					"org0": fakeOrgConfigs[0],
   949  					"org1": fakeOrgConfigs[1],
   950  				})
   951  
   952  				fakeSCCFuncs.CommitChaincodeDefinitionReturns(map[string]bool{
   953  					"fake-mspid":  true,
   954  					"other-mspid": true,
   955  				}, nil)
   956  
   957  				fakeMsp := &mock.MSP{}
   958  				fakeMSPManager.GetMSPsReturns(
   959  					map[string]msp.MSP{
   960  						"org0": fakeMsp,
   961  						"org1": fakeMsp,
   962  					},
   963  					nil,
   964  				)
   965  			})
   966  
   967  			It("passes the arguments to and returns the results from the backing scc function implementation", func() {
   968  				res := scc.Invoke(fakeStub)
   969  				Expect(res.Message).To(Equal(""))
   970  				Expect(res.Status).To(Equal(int32(200)))
   971  				payload := &lb.CommitChaincodeDefinitionResult{}
   972  				err = proto.Unmarshal(res.Payload, payload)
   973  				Expect(err).NotTo(HaveOccurred())
   974  
   975  				Expect(fakeSCCFuncs.CommitChaincodeDefinitionCallCount()).To(Equal(1))
   976  				chname, ccname, cd, pubState, orgStates := fakeSCCFuncs.CommitChaincodeDefinitionArgsForCall(0)
   977  				Expect(chname).To(Equal("test-channel"))
   978  				Expect(ccname).To(Equal("cc-name2"))
   979  				Expect(cd).To(Equal(&lifecycle.ChaincodeDefinition{
   980  					Sequence: 7,
   981  					EndorsementInfo: &lb.ChaincodeEndorsementInfo{
   982  						Version:           "version-2+2",
   983  						EndorsementPlugin: "endorsement-plugin",
   984  						InitRequired:      true,
   985  					},
   986  					ValidationInfo: &lb.ChaincodeValidationInfo{
   987  						ValidationPlugin:    "validation-plugin",
   988  						ValidationParameter: []byte("validation-parameter"),
   989  					},
   990  					Collections: &pb.CollectionConfigPackage{
   991  						Config: []*pb.CollectionConfig{
   992  							{
   993  								Payload: &pb.CollectionConfig_StaticCollectionConfig{
   994  									StaticCollectionConfig: &pb.StaticCollectionConfig{
   995  										Name: "test_collection",
   996  										MemberOrgsPolicy: &pb.CollectionPolicyConfig{
   997  											Payload: &pb.CollectionPolicyConfig_SignaturePolicy{
   998  												SignaturePolicy: policydsl.SignedByMspMember("org0"),
   999  											},
  1000  										},
  1001  									},
  1002  								},
  1003  							},
  1004  						},
  1005  					},
  1006  				}))
  1007  				Expect(pubState).To(Equal(fakeStub))
  1008  				Expect(len(orgStates)).To(Equal(2))
  1009  				Expect(orgStates[0]).To(BeAssignableToTypeOf(&lifecycle.ChaincodePrivateLedgerShim{}))
  1010  				Expect(orgStates[1]).To(BeAssignableToTypeOf(&lifecycle.ChaincodePrivateLedgerShim{}))
  1011  				collection0 := orgStates[0].(*lifecycle.ChaincodePrivateLedgerShim).Collection
  1012  				collection1 := orgStates[1].(*lifecycle.ChaincodePrivateLedgerShim).Collection
  1013  				Expect([]string{collection0, collection1}).To(ConsistOf("_implicit_org_fake-mspid", "_implicit_org_other-mspid"))
  1014  			})
  1015  
  1016  			Context("when the chaincode name begins with an invalid character", func() {
  1017  				BeforeEach(func() {
  1018  					arg.Name = "_invalid"
  1019  
  1020  					marshaledArg, err = proto.Marshal(arg)
  1021  					Expect(err).NotTo(HaveOccurred())
  1022  					fakeStub.GetArgsReturns([][]byte{[]byte("CommitChaincodeDefinition"), marshaledArg})
  1023  				})
  1024  
  1025  				It("wraps and returns the error", func() {
  1026  					res := scc.Invoke(fakeStub)
  1027  					Expect(res.Status).To(Equal(int32(500)))
  1028  					Expect(res.Message).To(Equal("failed to invoke backing implementation of 'CommitChaincodeDefinition': error validating chaincode definition: invalid chaincode name '_invalid'. Names can only consist of alphanumerics, '_', and '-' and can only begin with alphanumerics"))
  1029  				})
  1030  			})
  1031  
  1032  			Context("when the chaincode version contains invalid characters", func() {
  1033  				BeforeEach(func() {
  1034  					arg.Version = "$money$"
  1035  
  1036  					marshaledArg, err = proto.Marshal(arg)
  1037  					Expect(err).NotTo(HaveOccurred())
  1038  					fakeStub.GetArgsReturns([][]byte{[]byte("CommitChaincodeDefinition"), marshaledArg})
  1039  				})
  1040  
  1041  				It("wraps and returns the error", func() {
  1042  					res := scc.Invoke(fakeStub)
  1043  					Expect(res.Status).To(Equal(int32(500)))
  1044  					Expect(res.Message).To(Equal("failed to invoke backing implementation of 'CommitChaincodeDefinition': error validating chaincode definition: invalid chaincode version '$money$'. Versions can only consist of alphanumerics, '_', '-', '+', and '.'"))
  1045  				})
  1046  			})
  1047  
  1048  			Context("when the chaincode name matches an existing system chaincode name", func() {
  1049  				BeforeEach(func() {
  1050  					arg.Name = "qscc"
  1051  
  1052  					marshaledArg, err = proto.Marshal(arg)
  1053  					Expect(err).NotTo(HaveOccurred())
  1054  					fakeStub.GetArgsReturns([][]byte{[]byte("CommitChaincodeDefinition"), marshaledArg})
  1055  				})
  1056  
  1057  				It("wraps and returns the error", func() {
  1058  					res := scc.Invoke(fakeStub)
  1059  					Expect(res.Status).To(Equal(int32(500)))
  1060  					Expect(res.Message).To(Equal("failed to invoke backing implementation of 'CommitChaincodeDefinition': error validating chaincode definition: chaincode name 'qscc' is the name of a system chaincode"))
  1061  				})
  1062  			})
  1063  
  1064  			Context("when a collection name contains invalid characters", func() {
  1065  				BeforeEach(func() {
  1066  					arg.Collections = &pb.CollectionConfigPackage{
  1067  						Config: []*pb.CollectionConfig{
  1068  							{
  1069  								Payload: &pb.CollectionConfig_StaticCollectionConfig{
  1070  									StaticCollectionConfig: &pb.StaticCollectionConfig{
  1071  										Name: "collection(test",
  1072  									},
  1073  								},
  1074  							},
  1075  						},
  1076  					}
  1077  
  1078  					marshaledArg, err = proto.Marshal(arg)
  1079  					Expect(err).NotTo(HaveOccurred())
  1080  					fakeStub.GetArgsReturns([][]byte{[]byte("CommitChaincodeDefinition"), marshaledArg})
  1081  				})
  1082  
  1083  				It("wraps and returns the error", func() {
  1084  					res := scc.Invoke(fakeStub)
  1085  					Expect(res.Status).To(Equal(int32(500)))
  1086  					Expect(res.Message).To(Equal("failed to invoke backing implementation of 'CommitChaincodeDefinition': error validating chaincode definition: invalid collection name 'collection(test'. Names can only consist of alphanumerics, '_', and '-' and cannot begin with '_'"))
  1087  				})
  1088  			})
  1089  
  1090  			Context("when a collection name begins with an invalid character", func() {
  1091  				BeforeEach(func() {
  1092  					arg.Collections = &pb.CollectionConfigPackage{
  1093  						Config: []*pb.CollectionConfig{
  1094  							{
  1095  								Payload: &pb.CollectionConfig_StaticCollectionConfig{
  1096  									StaticCollectionConfig: &pb.StaticCollectionConfig{
  1097  										Name: "&collection",
  1098  									},
  1099  								},
  1100  							},
  1101  						},
  1102  					}
  1103  
  1104  					marshaledArg, err = proto.Marshal(arg)
  1105  					Expect(err).NotTo(HaveOccurred())
  1106  					fakeStub.GetArgsReturns([][]byte{[]byte("CommitChaincodeDefinition"), marshaledArg})
  1107  				})
  1108  
  1109  				It("wraps and returns the error", func() {
  1110  					res := scc.Invoke(fakeStub)
  1111  					Expect(res.Status).To(Equal(int32(500)))
  1112  					Expect(res.Message).To(Equal("failed to invoke backing implementation of 'CommitChaincodeDefinition': error validating chaincode definition: invalid collection name '&collection'. Names can only consist of alphanumerics, '_', and '-' and cannot begin with '_'"))
  1113  				})
  1114  			})
  1115  
  1116  			Context("when there is no agreement from this peer's org", func() {
  1117  				BeforeEach(func() {
  1118  					fakeSCCFuncs.CommitChaincodeDefinitionReturns(map[string]bool{
  1119  						"fake-mspid":  false,
  1120  						"other-mspid": false,
  1121  					}, nil)
  1122  				})
  1123  
  1124  				It("returns an error indicating the lack of agreement", func() {
  1125  					res := scc.Invoke(fakeStub)
  1126  					Expect(res.Status).To(Equal(int32(500)))
  1127  					Expect(res.Message).To(Equal("failed to invoke backing implementation of 'CommitChaincodeDefinition': chaincode definition not agreed to by this org (fake-mspid)"))
  1128  				})
  1129  			})
  1130  
  1131  			Context("when there is no match for this peer's org's MSPID", func() {
  1132  				BeforeEach(func() {
  1133  					fakeOrgConfigs[0].MSPIDReturns("other-mspid")
  1134  				})
  1135  
  1136  				It("returns an error indicating the lack of agreement", func() {
  1137  					res := scc.Invoke(fakeStub)
  1138  					Expect(res.Status).To(Equal(int32(500)))
  1139  					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"))
  1140  				})
  1141  			})
  1142  
  1143  			Context("when there is no channel config", func() {
  1144  				BeforeEach(func() {
  1145  					fakeChannelConfigSource.GetStableChannelConfigReturns(nil)
  1146  				})
  1147  
  1148  				It("returns an error indicating the lack of agreement", func() {
  1149  					res := scc.Invoke(fakeStub)
  1150  					Expect(res.Status).To(Equal(int32(500)))
  1151  					Expect(res.Message).To(Equal("could not get channelconfig for channel 'test-channel'"))
  1152  				})
  1153  			})
  1154  
  1155  			Context("when there is no application config", func() {
  1156  				BeforeEach(func() {
  1157  					fakeChannelConfig.ApplicationConfigReturns(nil, false)
  1158  				})
  1159  
  1160  				It("returns an error indicating the lack of agreement", func() {
  1161  					res := scc.Invoke(fakeStub)
  1162  					Expect(res.Status).To(Equal(int32(500)))
  1163  					Expect(res.Message).To(Equal("could not get application config for channel 'test-channel'"))
  1164  				})
  1165  
  1166  				Context("when there is no application config because there is no channel", func() {
  1167  					BeforeEach(func() {
  1168  						fakeStub.GetChannelIDReturns("")
  1169  					})
  1170  
  1171  					It("returns an error indicating the lack of agreement", func() {
  1172  						res := scc.Invoke(fakeStub)
  1173  						Expect(res.Status).To(Equal(int32(500)))
  1174  						Expect(res.Message).To(Equal("failed to invoke backing implementation of 'CommitChaincodeDefinition': no application config for channel ''"))
  1175  					})
  1176  				})
  1177  			})
  1178  
  1179  			Context("when the underlying function implementation fails", func() {
  1180  				BeforeEach(func() {
  1181  					fakeSCCFuncs.CommitChaincodeDefinitionReturns(nil, fmt.Errorf("underlying-error"))
  1182  				})
  1183  
  1184  				It("wraps and returns the error", func() {
  1185  					res := scc.Invoke(fakeStub)
  1186  					Expect(res.Status).To(Equal(int32(500)))
  1187  					Expect(res.Message).To(Equal("failed to invoke backing implementation of 'CommitChaincodeDefinition': underlying-error"))
  1188  				})
  1189  			})
  1190  		})
  1191  
  1192  		Describe("CheckCommitReadiness", func() {
  1193  			var (
  1194  				err            error
  1195  				arg            *lb.CheckCommitReadinessArgs
  1196  				marshaledArg   []byte
  1197  				fakeOrgConfigs []*mock.ApplicationOrgConfig
  1198  			)
  1199  
  1200  			BeforeEach(func() {
  1201  				arg = &lb.CheckCommitReadinessArgs{
  1202  					Sequence:            7,
  1203  					Name:                "name",
  1204  					Version:             "version",
  1205  					EndorsementPlugin:   "endorsement-plugin",
  1206  					ValidationPlugin:    "validation-plugin",
  1207  					ValidationParameter: []byte("validation-parameter"),
  1208  					Collections:         &pb.CollectionConfigPackage{},
  1209  					InitRequired:        true,
  1210  				}
  1211  
  1212  				marshaledArg, err = proto.Marshal(arg)
  1213  				Expect(err).NotTo(HaveOccurred())
  1214  
  1215  				fakeStub.GetArgsReturns([][]byte{[]byte("CheckCommitReadiness"), marshaledArg})
  1216  
  1217  				fakeOrgConfigs = []*mock.ApplicationOrgConfig{{}, {}}
  1218  				fakeOrgConfigs[0].MSPIDReturns("fake-mspid")
  1219  				fakeOrgConfigs[1].MSPIDReturns("other-mspid")
  1220  
  1221  				fakeApplicationConfig.OrganizationsReturns(map[string]channelconfig.ApplicationOrg{
  1222  					"org0": fakeOrgConfigs[0],
  1223  					"org1": fakeOrgConfigs[1],
  1224  				})
  1225  
  1226  				fakeSCCFuncs.CheckCommitReadinessReturns(map[string]bool{
  1227  					"fake-mspid":  true,
  1228  					"other-mspid": true,
  1229  				}, nil)
  1230  			})
  1231  
  1232  			It("passes the arguments to and returns the results from the backing scc function implementation", func() {
  1233  				res := scc.Invoke(fakeStub)
  1234  				Expect(res.Message).To(Equal(""))
  1235  				Expect(res.Status).To(Equal(int32(200)))
  1236  				payload := &lb.CheckCommitReadinessResult{}
  1237  				err = proto.Unmarshal(res.Payload, payload)
  1238  				Expect(err).NotTo(HaveOccurred())
  1239  
  1240  				orgApprovals := payload.GetApprovals()
  1241  				Expect(orgApprovals).NotTo(BeNil())
  1242  				Expect(len(orgApprovals)).To(Equal(2))
  1243  				Expect(orgApprovals["fake-mspid"]).To(BeTrue())
  1244  				Expect(orgApprovals["other-mspid"]).To(BeTrue())
  1245  
  1246  				Expect(fakeSCCFuncs.CheckCommitReadinessCallCount()).To(Equal(1))
  1247  				chname, ccname, cd, pubState, orgStates := fakeSCCFuncs.CheckCommitReadinessArgsForCall(0)
  1248  				Expect(chname).To(Equal("test-channel"))
  1249  				Expect(ccname).To(Equal("name"))
  1250  				Expect(cd).To(Equal(&lifecycle.ChaincodeDefinition{
  1251  					Sequence: 7,
  1252  					EndorsementInfo: &lb.ChaincodeEndorsementInfo{
  1253  						Version:           "version",
  1254  						EndorsementPlugin: "endorsement-plugin",
  1255  						InitRequired:      true,
  1256  					},
  1257  					ValidationInfo: &lb.ChaincodeValidationInfo{
  1258  						ValidationPlugin:    "validation-plugin",
  1259  						ValidationParameter: []byte("validation-parameter"),
  1260  					},
  1261  					Collections: arg.Collections,
  1262  				}))
  1263  				Expect(pubState).To(Equal(fakeStub))
  1264  				Expect(orgStates).To(HaveLen(2))
  1265  				Expect(orgStates[0]).To(BeAssignableToTypeOf(&lifecycle.ChaincodePrivateLedgerShim{}))
  1266  				Expect(orgStates[1]).To(BeAssignableToTypeOf(&lifecycle.ChaincodePrivateLedgerShim{}))
  1267  				collection0 := orgStates[0].(*lifecycle.ChaincodePrivateLedgerShim).Collection
  1268  				collection1 := orgStates[1].(*lifecycle.ChaincodePrivateLedgerShim).Collection
  1269  				Expect([]string{collection0, collection1}).To(ConsistOf("_implicit_org_fake-mspid", "_implicit_org_other-mspid"))
  1270  			})
  1271  
  1272  			Context("when there is no application config", func() {
  1273  				BeforeEach(func() {
  1274  					fakeChannelConfig.ApplicationConfigReturns(nil, false)
  1275  				})
  1276  
  1277  				It("returns an error", func() {
  1278  					res := scc.Invoke(fakeStub)
  1279  					Expect(res.Status).To(Equal(int32(500)))
  1280  					Expect(res.Message).To(Equal("could not get application config for channel 'test-channel'"))
  1281  				})
  1282  
  1283  				Context("when there is no application config because there is no channel", func() {
  1284  					BeforeEach(func() {
  1285  						fakeStub.GetChannelIDReturns("")
  1286  					})
  1287  
  1288  					It("returns an error", func() {
  1289  						res := scc.Invoke(fakeStub)
  1290  						Expect(res.Status).To(Equal(int32(500)))
  1291  						Expect(res.Message).To(Equal("failed to invoke backing implementation of 'CheckCommitReadiness': no application config for channel ''"))
  1292  					})
  1293  				})
  1294  			})
  1295  
  1296  			Context("when the underlying function implementation fails", func() {
  1297  				BeforeEach(func() {
  1298  					fakeSCCFuncs.CheckCommitReadinessReturns(nil, fmt.Errorf("underlying-error"))
  1299  				})
  1300  
  1301  				It("wraps and returns the error", func() {
  1302  					res := scc.Invoke(fakeStub)
  1303  					Expect(res.Status).To(Equal(int32(500)))
  1304  					Expect(res.Message).To(Equal("failed to invoke backing implementation of 'CheckCommitReadiness': underlying-error"))
  1305  				})
  1306  			})
  1307  		})
  1308  
  1309  		Describe("QueryApprovedChaincodeDefinition", func() {
  1310  			var (
  1311  				arg          *lb.QueryApprovedChaincodeDefinitionArgs
  1312  				marshaledArg []byte
  1313  			)
  1314  
  1315  			BeforeEach(func() {
  1316  				arg = &lb.QueryApprovedChaincodeDefinitionArgs{
  1317  					Sequence: 7,
  1318  					Name:     "cc_name",
  1319  				}
  1320  
  1321  				var err error
  1322  				marshaledArg, err = proto.Marshal(arg)
  1323  				Expect(err).NotTo(HaveOccurred())
  1324  
  1325  				fakeStub.GetArgsReturns([][]byte{[]byte("QueryApprovedChaincodeDefinition"), marshaledArg})
  1326  				fakeSCCFuncs.QueryApprovedChaincodeDefinitionReturns(
  1327  					&lifecycle.ApprovedChaincodeDefinition{
  1328  						Sequence: 7,
  1329  						EndorsementInfo: &lb.ChaincodeEndorsementInfo{
  1330  							Version:           "version",
  1331  							EndorsementPlugin: "endorsement-plugin",
  1332  							InitRequired:      true,
  1333  						},
  1334  						ValidationInfo: &lb.ChaincodeValidationInfo{
  1335  							ValidationPlugin:    "validation-plugin",
  1336  							ValidationParameter: []byte("validation-parameter"),
  1337  						},
  1338  						Collections: &pb.CollectionConfigPackage{},
  1339  						Source: &lb.ChaincodeSource{
  1340  							Type: &lb.ChaincodeSource_LocalPackage{
  1341  								LocalPackage: &lb.ChaincodeSource_Local{
  1342  									PackageId: "hash",
  1343  								},
  1344  							},
  1345  						},
  1346  					},
  1347  					nil,
  1348  				)
  1349  			})
  1350  
  1351  			It("passes the arguments to and returns the results from the backing scc function implementation", func() {
  1352  				res := scc.Invoke(fakeStub)
  1353  				Expect(res.Status).To(Equal(int32(200)))
  1354  				payload := &lb.QueryApprovedChaincodeDefinitionResult{}
  1355  				err := proto.Unmarshal(res.Payload, payload)
  1356  				Expect(err).NotTo(HaveOccurred())
  1357  				Expect(proto.Equal(payload, &lb.QueryApprovedChaincodeDefinitionResult{
  1358  					Sequence:            7,
  1359  					Version:             "version",
  1360  					EndorsementPlugin:   "endorsement-plugin",
  1361  					ValidationPlugin:    "validation-plugin",
  1362  					ValidationParameter: []byte("validation-parameter"),
  1363  					InitRequired:        true,
  1364  					Collections:         &pb.CollectionConfigPackage{},
  1365  					Source: &lb.ChaincodeSource{
  1366  						Type: &lb.ChaincodeSource_LocalPackage{
  1367  							LocalPackage: &lb.ChaincodeSource_Local{
  1368  								PackageId: "hash",
  1369  							},
  1370  						},
  1371  					},
  1372  				})).To(BeTrue())
  1373  
  1374  				Expect(fakeSCCFuncs.QueryApprovedChaincodeDefinitionCallCount()).To(Equal(1))
  1375  				chname, ccname, sequence, pubState, privState := fakeSCCFuncs.QueryApprovedChaincodeDefinitionArgsForCall(0)
  1376  
  1377  				Expect(chname).To(Equal("test-channel"))
  1378  				Expect(ccname).To(Equal("cc_name"))
  1379  				Expect(sequence).To(Equal(int64(7)))
  1380  
  1381  				Expect(pubState).To(Equal(fakeStub))
  1382  				Expect(privState).To(BeAssignableToTypeOf(&lifecycle.ChaincodePrivateLedgerShim{}))
  1383  				Expect(privState.(*lifecycle.ChaincodePrivateLedgerShim).Collection).To(Equal("_implicit_org_fake-mspid"))
  1384  			})
  1385  
  1386  			Context("when the underlying QueryApprovedChaincodeDefinition function implementation fails", func() {
  1387  				BeforeEach(func() {
  1388  					fakeSCCFuncs.QueryApprovedChaincodeDefinitionReturns(nil, fmt.Errorf("underlying-error"))
  1389  				})
  1390  
  1391  				It("wraps and returns the error", func() {
  1392  					res := scc.Invoke(fakeStub)
  1393  					Expect(res.Status).To(Equal(int32(500)))
  1394  					Expect(res.Message).To(Equal("failed to invoke backing implementation of 'QueryApprovedChaincodeDefinition': underlying-error"))
  1395  				})
  1396  			})
  1397  
  1398  			Context("when the underlying QueryApprovedChaincodeDefinition function implementation fails", func() {
  1399  				BeforeEach(func() {
  1400  					fakeSCCFuncs.QueryApprovedChaincodeDefinitionReturns(nil, fmt.Errorf("underlying-error"))
  1401  				})
  1402  
  1403  				It("wraps and returns the error", func() {
  1404  					res := scc.Invoke(fakeStub)
  1405  					Expect(res.Status).To(Equal(int32(500)))
  1406  					Expect(res.Message).To(Equal("failed to invoke backing implementation of 'QueryApprovedChaincodeDefinition': underlying-error"))
  1407  				})
  1408  			})
  1409  		})
  1410  
  1411  		Describe("QueryChaincodeDefinition", func() {
  1412  			var (
  1413  				arg            *lb.QueryChaincodeDefinitionArgs
  1414  				marshaledArg   []byte
  1415  				fakeOrgConfigs []*mock.ApplicationOrgConfig
  1416  			)
  1417  
  1418  			BeforeEach(func() {
  1419  				arg = &lb.QueryChaincodeDefinitionArgs{
  1420  					Name: "cc-name",
  1421  				}
  1422  
  1423  				var err error
  1424  				marshaledArg, err = proto.Marshal(arg)
  1425  				Expect(err).NotTo(HaveOccurred())
  1426  
  1427  				fakeOrgConfigs = []*mock.ApplicationOrgConfig{{}, {}}
  1428  				fakeOrgConfigs[0].MSPIDReturns("fake-mspid")
  1429  				fakeOrgConfigs[1].MSPIDReturns("other-mspid")
  1430  
  1431  				fakeApplicationConfig.OrganizationsReturns(map[string]channelconfig.ApplicationOrg{
  1432  					"org0": fakeOrgConfigs[0],
  1433  					"org1": fakeOrgConfigs[1],
  1434  				})
  1435  
  1436  				fakeStub.GetArgsReturns([][]byte{[]byte("QueryChaincodeDefinition"), marshaledArg})
  1437  				fakeSCCFuncs.QueryChaincodeDefinitionReturns(
  1438  					&lifecycle.ChaincodeDefinition{
  1439  						Sequence: 2,
  1440  						EndorsementInfo: &lb.ChaincodeEndorsementInfo{
  1441  							Version:           "version",
  1442  							EndorsementPlugin: "endorsement-plugin",
  1443  						},
  1444  						ValidationInfo: &lb.ChaincodeValidationInfo{
  1445  							ValidationPlugin:    "validation-plugin",
  1446  							ValidationParameter: []byte("validation-parameter"),
  1447  						},
  1448  						Collections: &pb.CollectionConfigPackage{},
  1449  					},
  1450  					nil,
  1451  				)
  1452  
  1453  				fakeSCCFuncs.QueryOrgApprovalsReturns(
  1454  					map[string]bool{
  1455  						"fake-mspid":  true,
  1456  						"other-mspid": true,
  1457  					},
  1458  					nil,
  1459  				)
  1460  			})
  1461  
  1462  			It("passes the arguments to and returns the results from the backing scc function implementation", func() {
  1463  				res := scc.Invoke(fakeStub)
  1464  				Expect(res.Status).To(Equal(int32(200)))
  1465  				payload := &lb.QueryChaincodeDefinitionResult{}
  1466  				err := proto.Unmarshal(res.Payload, payload)
  1467  				Expect(err).NotTo(HaveOccurred())
  1468  				Expect(proto.Equal(payload, &lb.QueryChaincodeDefinitionResult{
  1469  					Sequence:            2,
  1470  					Version:             "version",
  1471  					EndorsementPlugin:   "endorsement-plugin",
  1472  					ValidationPlugin:    "validation-plugin",
  1473  					ValidationParameter: []byte("validation-parameter"),
  1474  					Collections:         &pb.CollectionConfigPackage{},
  1475  					Approvals: map[string]bool{
  1476  						"fake-mspid":  true,
  1477  						"other-mspid": true,
  1478  					},
  1479  				})).To(BeTrue())
  1480  
  1481  				Expect(fakeSCCFuncs.QueryChaincodeDefinitionCallCount()).To(Equal(1))
  1482  				name, pubState := fakeSCCFuncs.QueryChaincodeDefinitionArgsForCall(0)
  1483  				Expect(name).To(Equal("cc-name"))
  1484  				Expect(pubState).To(Equal(fakeStub))
  1485  				name, _, orgStates := fakeSCCFuncs.QueryOrgApprovalsArgsForCall(0)
  1486  				Expect(name).To(Equal("cc-name"))
  1487  				Expect(orgStates).To(HaveLen(2))
  1488  				Expect(orgStates[0]).To(BeAssignableToTypeOf(&lifecycle.ChaincodePrivateLedgerShim{}))
  1489  				Expect(orgStates[1]).To(BeAssignableToTypeOf(&lifecycle.ChaincodePrivateLedgerShim{}))
  1490  				collection0 := orgStates[0].(*lifecycle.ChaincodePrivateLedgerShim).Collection
  1491  				collection1 := orgStates[1].(*lifecycle.ChaincodePrivateLedgerShim).Collection
  1492  				Expect([]string{collection0, collection1}).To(ConsistOf("_implicit_org_fake-mspid", "_implicit_org_other-mspid"))
  1493  			})
  1494  
  1495  			Context("when the underlying QueryChaincodeDefinition function implementation fails", func() {
  1496  				BeforeEach(func() {
  1497  					fakeSCCFuncs.QueryChaincodeDefinitionReturns(nil, fmt.Errorf("underlying-error"))
  1498  				})
  1499  
  1500  				It("wraps and returns the error", func() {
  1501  					res := scc.Invoke(fakeStub)
  1502  					Expect(res.Status).To(Equal(int32(500)))
  1503  					Expect(res.Message).To(Equal("failed to invoke backing implementation of 'QueryChaincodeDefinition': underlying-error"))
  1504  				})
  1505  			})
  1506  
  1507  			Context("when the underlying QueryOrgApprovals function implementation fails", func() {
  1508  				BeforeEach(func() {
  1509  					fakeSCCFuncs.QueryOrgApprovalsReturns(nil, fmt.Errorf("underlying-error"))
  1510  				})
  1511  
  1512  				It("wraps and returns the error", func() {
  1513  					res := scc.Invoke(fakeStub)
  1514  					Expect(res.Status).To(Equal(int32(500)))
  1515  					Expect(res.Message).To(Equal("failed to invoke backing implementation of 'QueryChaincodeDefinition': underlying-error"))
  1516  				})
  1517  			})
  1518  
  1519  			Context("when the namespace cannot be found", func() {
  1520  				BeforeEach(func() {
  1521  					fakeSCCFuncs.QueryChaincodeDefinitionReturns(nil, lifecycle.ErrNamespaceNotDefined{Namespace: "nicetry"})
  1522  				})
  1523  
  1524  				It("returns 404 Not Found", func() {
  1525  					res := scc.Invoke(fakeStub)
  1526  					Expect(res.Status).To(Equal(int32(404)))
  1527  					Expect(res.Message).To(Equal("namespace nicetry is not defined"))
  1528  				})
  1529  			})
  1530  
  1531  			Context("when there is no application config", func() {
  1532  				BeforeEach(func() {
  1533  					fakeChannelConfig.ApplicationConfigReturns(nil, false)
  1534  				})
  1535  
  1536  				It("returns an error", func() {
  1537  					res := scc.Invoke(fakeStub)
  1538  					Expect(res.Status).To(Equal(int32(500)))
  1539  					Expect(res.Message).To(Equal("could not get application config for channel 'test-channel'"))
  1540  				})
  1541  
  1542  				Context("when there is no application config because there is no channel", func() {
  1543  					BeforeEach(func() {
  1544  						fakeStub.GetChannelIDReturns("")
  1545  					})
  1546  
  1547  					It("returns an error", func() {
  1548  						res := scc.Invoke(fakeStub)
  1549  						Expect(res.Status).To(Equal(int32(500)))
  1550  						Expect(res.Message).To(Equal("failed to invoke backing implementation of 'QueryChaincodeDefinition': no application config for channel ''"))
  1551  					})
  1552  				})
  1553  			})
  1554  		})
  1555  
  1556  		Describe("QueryChaincodeDefinitions", func() {
  1557  			var (
  1558  				arg          *lb.QueryChaincodeDefinitionsArgs
  1559  				marshaledArg []byte
  1560  			)
  1561  
  1562  			BeforeEach(func() {
  1563  				arg = &lb.QueryChaincodeDefinitionsArgs{}
  1564  
  1565  				var err error
  1566  				marshaledArg, err = proto.Marshal(arg)
  1567  				Expect(err).NotTo(HaveOccurred())
  1568  
  1569  				fakeStub.GetArgsReturns([][]byte{[]byte("QueryChaincodeDefinitions"), marshaledArg})
  1570  				fakeSCCFuncs.QueryNamespaceDefinitionsReturns(map[string]string{
  1571  					"foo": "Chaincode",
  1572  					"bar": "Token",
  1573  					"woo": "Chaincode",
  1574  				}, nil)
  1575  				fakeSCCFuncs.QueryChaincodeDefinitionStub = func(name string, rs lifecycle.ReadableState) (*lifecycle.ChaincodeDefinition, error) {
  1576  					cd := &lifecycle.ChaincodeDefinition{
  1577  						Sequence: 2,
  1578  						EndorsementInfo: &lb.ChaincodeEndorsementInfo{
  1579  							Version:           "version",
  1580  							EndorsementPlugin: "endorsement-plugin",
  1581  						},
  1582  						ValidationInfo: &lb.ChaincodeValidationInfo{
  1583  							ValidationPlugin:    "validation-plugin",
  1584  							ValidationParameter: []byte("validation-parameter"),
  1585  						},
  1586  						Collections: &pb.CollectionConfigPackage{},
  1587  					}
  1588  
  1589  					if name == "woo" {
  1590  						cd.Sequence = 5
  1591  					}
  1592  
  1593  					return cd, nil
  1594  				}
  1595  			})
  1596  
  1597  			It("passes the arguments to and returns the results from the backing scc function implementation", func() {
  1598  				res := scc.Invoke(fakeStub)
  1599  				Expect(res.Status).To(Equal(int32(200)))
  1600  				payload := &lb.QueryChaincodeDefinitionsResult{}
  1601  				err := proto.Unmarshal(res.Payload, payload)
  1602  				Expect(err).NotTo(HaveOccurred())
  1603  				Expect(payload.GetChaincodeDefinitions()).To(ConsistOf(
  1604  					&lb.QueryChaincodeDefinitionsResult_ChaincodeDefinition{
  1605  						Name:                "foo",
  1606  						Sequence:            2,
  1607  						Version:             "version",
  1608  						EndorsementPlugin:   "endorsement-plugin",
  1609  						ValidationPlugin:    "validation-plugin",
  1610  						ValidationParameter: []byte("validation-parameter"),
  1611  						Collections:         &pb.CollectionConfigPackage{},
  1612  					},
  1613  					&lb.QueryChaincodeDefinitionsResult_ChaincodeDefinition{
  1614  						Name:                "woo",
  1615  						Sequence:            5,
  1616  						Version:             "version",
  1617  						EndorsementPlugin:   "endorsement-plugin",
  1618  						ValidationPlugin:    "validation-plugin",
  1619  						ValidationParameter: []byte("validation-parameter"),
  1620  						Collections:         &pb.CollectionConfigPackage{},
  1621  					},
  1622  				))
  1623  				Expect(fakeSCCFuncs.QueryNamespaceDefinitionsCallCount()).To(Equal(1))
  1624  				Expect(fakeSCCFuncs.QueryChaincodeDefinitionCallCount()).To(Equal(2))
  1625  			})
  1626  
  1627  			Context("when the underlying QueryChaincodeDefinition function implementation fails", func() {
  1628  				BeforeEach(func() {
  1629  					fakeSCCFuncs.QueryChaincodeDefinitionReturns(nil, fmt.Errorf("underlying-error"))
  1630  				})
  1631  
  1632  				It("wraps and returns the error", func() {
  1633  					res := scc.Invoke(fakeStub)
  1634  					Expect(res.Status).To(Equal(int32(500)))
  1635  					Expect(res.Message).To(Equal("failed to invoke backing implementation of 'QueryChaincodeDefinitions': underlying-error"))
  1636  				})
  1637  			})
  1638  
  1639  			Context("when the underlying QueryNamespaceDefinitions function implementation fails", func() {
  1640  				BeforeEach(func() {
  1641  					fakeSCCFuncs.QueryNamespaceDefinitionsReturns(nil, fmt.Errorf("underlying-error"))
  1642  				})
  1643  
  1644  				It("wraps and returns the error", func() {
  1645  					res := scc.Invoke(fakeStub)
  1646  					Expect(res.Status).To(Equal(int32(500)))
  1647  					Expect(res.Message).To(Equal("failed to invoke backing implementation of 'QueryChaincodeDefinitions': underlying-error"))
  1648  				})
  1649  			})
  1650  		})
  1651  	})
  1652  })
  1653  
  1654  type collectionConfigs []*collectionConfig
  1655  
  1656  func (ccs collectionConfigs) deepCopy() collectionConfigs {
  1657  	var buf bytes.Buffer
  1658  	enc := gob.NewEncoder(&buf)
  1659  	dec := gob.NewDecoder(&buf)
  1660  
  1661  	err := enc.Encode(ccs)
  1662  	Expect(err).NotTo(HaveOccurred())
  1663  	var newCCs collectionConfigs
  1664  	err = dec.Decode(&newCCs)
  1665  	Expect(err).NotTo(HaveOccurred())
  1666  	return newCCs
  1667  }
  1668  
  1669  func (ccs collectionConfigs) toProtoCollectionConfigPackage() *pb.CollectionConfigPackage {
  1670  	if len(ccs) == 0 {
  1671  		return nil
  1672  	}
  1673  	collConfigsProtos := make([]*pb.CollectionConfig, len(ccs))
  1674  	for i, c := range ccs {
  1675  		collConfigsProtos[i] = c.toCollectionConfigProto()
  1676  	}
  1677  	return &pb.CollectionConfigPackage{
  1678  		Config: collConfigsProtos,
  1679  	}
  1680  }
  1681  
  1682  type collectionConfig struct {
  1683  	Name              string
  1684  	RequiredPeerCount int32
  1685  	MaxPeerCount      int32
  1686  	BlockToLive       uint64
  1687  
  1688  	Policy                  string
  1689  	Identities              []*mspprotos.MSPPrincipal
  1690  	UseGivenMemberOrgPolicy bool
  1691  	MemberOrgPolicy         *pb.CollectionPolicyConfig
  1692  }
  1693  
  1694  func (cc *collectionConfig) toCollectionConfigProto() *pb.CollectionConfig {
  1695  	memberOrgPolicy := cc.MemberOrgPolicy
  1696  	if !cc.UseGivenMemberOrgPolicy {
  1697  		spe, err := policydsl.FromString(cc.Policy)
  1698  		Expect(err).NotTo(HaveOccurred())
  1699  		spe.Identities = cc.Identities
  1700  		memberOrgPolicy = &pb.CollectionPolicyConfig{
  1701  			Payload: &pb.CollectionPolicyConfig_SignaturePolicy{
  1702  				SignaturePolicy: spe,
  1703  			},
  1704  		}
  1705  	}
  1706  	return &pb.CollectionConfig{
  1707  		Payload: &pb.CollectionConfig_StaticCollectionConfig{
  1708  			StaticCollectionConfig: &pb.StaticCollectionConfig{
  1709  				Name:              cc.Name,
  1710  				MaximumPeerCount:  cc.MaxPeerCount,
  1711  				RequiredPeerCount: cc.RequiredPeerCount,
  1712  				BlockToLive:       cc.BlockToLive,
  1713  				MemberOrgsPolicy:  memberOrgPolicy,
  1714  			},
  1715  		},
  1716  	}
  1717  }