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

     1  /*
     2  Copyright hechain. All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  package lifecycle_test
     8  
     9  import (
    10  	"fmt"
    11  
    12  	"github.com/hechain20/hechain/core/chaincode/lifecycle"
    13  	"github.com/hechain20/hechain/core/chaincode/lifecycle/mock"
    14  	"github.com/hechain20/hechain/core/scc"
    15  	lb "github.com/hyperledger/fabric-protos-go/peer/lifecycle"
    16  
    17  	. "github.com/onsi/ginkgo"
    18  	. "github.com/onsi/gomega"
    19  )
    20  
    21  var _ = Describe("ChaincodeEndorsementInfoSource", func() {
    22  	var (
    23  		cei                     *lifecycle.ChaincodeEndorsementInfoSource
    24  		resources               *lifecycle.Resources
    25  		fakeLegacyImpl          *mock.LegacyLifecycle
    26  		fakePublicState         MapLedgerShim
    27  		fakeQueryExecutor       *mock.SimpleQueryExecutor
    28  		fakeCache               *mock.ChaincodeInfoCache
    29  		fakeChannelConfigSource *mock.ChannelConfigSource
    30  		fakeChannelConfig       *mock.ChannelConfig
    31  		fakeAppConfig           *mock.ApplicationConfig
    32  		fakeCapabilities        *mock.ApplicationCapabilities
    33  		testInfo                *lifecycle.LocalChaincodeInfo
    34  		builtinSCCs             scc.BuiltinSCCs
    35  	)
    36  
    37  	BeforeEach(func() {
    38  		fakeLegacyImpl = &mock.LegacyLifecycle{}
    39  		fakeChannelConfigSource = &mock.ChannelConfigSource{}
    40  		fakeChannelConfig = &mock.ChannelConfig{}
    41  		fakeAppConfig = &mock.ApplicationConfig{}
    42  		fakeCapabilities = &mock.ApplicationCapabilities{}
    43  		fakeChannelConfigSource.GetStableChannelConfigReturns(fakeChannelConfig)
    44  		fakeChannelConfig.ApplicationConfigReturns(fakeAppConfig, true)
    45  		fakeAppConfig.CapabilitiesReturns(fakeCapabilities)
    46  		fakeCapabilities.LifecycleV20Returns(true)
    47  
    48  		resources = &lifecycle.Resources{
    49  			Serializer:          &lifecycle.Serializer{},
    50  			ChannelConfigSource: fakeChannelConfigSource,
    51  		}
    52  
    53  		fakePublicState = MapLedgerShim(map[string][]byte{})
    54  		fakeQueryExecutor = &mock.SimpleQueryExecutor{}
    55  		fakeQueryExecutor.GetStateStub = func(namespace, key string) ([]byte, error) {
    56  			return fakePublicState.GetState(key)
    57  		}
    58  
    59  		builtinSCCs = map[string]struct{}{}
    60  
    61  		err := resources.Serializer.Serialize(lifecycle.NamespacesName,
    62  			"name",
    63  			&lifecycle.ChaincodeDefinition{
    64  				Sequence: 7,
    65  			},
    66  			fakePublicState,
    67  		)
    68  		Expect(err).NotTo(HaveOccurred())
    69  
    70  		testInfo = &lifecycle.LocalChaincodeInfo{
    71  			Definition: &lifecycle.ChaincodeDefinition{
    72  				Sequence: 7,
    73  				EndorsementInfo: &lb.ChaincodeEndorsementInfo{
    74  					Version:           "version",
    75  					EndorsementPlugin: "endorsement-plugin",
    76  				},
    77  				ValidationInfo: &lb.ChaincodeValidationInfo{
    78  					ValidationPlugin:    "validation-plugin",
    79  					ValidationParameter: []byte("validation-parameter"),
    80  				},
    81  			},
    82  			InstallInfo: &lifecycle.ChaincodeInstallInfo{
    83  				Path:      "fake-path",
    84  				Type:      "fake-type",
    85  				PackageID: "hash",
    86  			},
    87  			Approved: true,
    88  		}
    89  
    90  		fakeCache = &mock.ChaincodeInfoCache{}
    91  		fakeCache.ChaincodeInfoReturns(testInfo, nil)
    92  
    93  		cei = &lifecycle.ChaincodeEndorsementInfoSource{
    94  			LegacyImpl:  fakeLegacyImpl,
    95  			Resources:   resources,
    96  			Cache:       fakeCache,
    97  			BuiltinSCCs: builtinSCCs,
    98  		}
    99  	})
   100  
   101  	Describe("CachedChaincodeInfo", func() {
   102  		It("returns the info from the cache", func() {
   103  			info, ok, err := cei.CachedChaincodeInfo("channel-id", "name", fakeQueryExecutor)
   104  			Expect(err).NotTo(HaveOccurred())
   105  			Expect(ok).To(BeTrue())
   106  			Expect(info).To(Equal(&lifecycle.LocalChaincodeInfo{
   107  				Definition: &lifecycle.ChaincodeDefinition{
   108  					Sequence: 7,
   109  					EndorsementInfo: &lb.ChaincodeEndorsementInfo{
   110  						Version:           "version",
   111  						EndorsementPlugin: "endorsement-plugin",
   112  					},
   113  					ValidationInfo: &lb.ChaincodeValidationInfo{
   114  						ValidationPlugin:    "validation-plugin",
   115  						ValidationParameter: []byte("validation-parameter"),
   116  					},
   117  				},
   118  				InstallInfo: &lifecycle.ChaincodeInstallInfo{
   119  					Type:      "fake-type",
   120  					Path:      "fake-path",
   121  					PackageID: "hash",
   122  				},
   123  				Approved: true,
   124  			}))
   125  			Expect(fakeCache.ChaincodeInfoCallCount()).To(Equal(1))
   126  			channelID, chaincodeName := fakeCache.ChaincodeInfoArgsForCall(0)
   127  			Expect(channelID).To(Equal("channel-id"))
   128  			Expect(chaincodeName).To(Equal("name"))
   129  		})
   130  
   131  		Context("when the cache returns an error", func() {
   132  			BeforeEach(func() {
   133  				fakeCache.ChaincodeInfoReturns(nil, fmt.Errorf("cache-error"))
   134  			})
   135  
   136  			It("wraps and returns the error", func() {
   137  				_, _, err := cei.CachedChaincodeInfo("channel-id", "name", fakeQueryExecutor)
   138  				Expect(err).To(MatchError("could not get approved chaincode info from cache: cache-error"))
   139  			})
   140  		})
   141  
   142  		Context("when the cache has not been approved", func() {
   143  			BeforeEach(func() {
   144  				testInfo.Approved = false
   145  			})
   146  
   147  			It("returns an error", func() {
   148  				_, _, err := cei.CachedChaincodeInfo("channel-id", "name", fakeQueryExecutor)
   149  				Expect(err).To(MatchError("chaincode definition for 'name' at sequence 7 on channel 'channel-id' has not yet been approved by this org"))
   150  			})
   151  		})
   152  
   153  		Context("when the chaincode has not been installed", func() {
   154  			BeforeEach(func() {
   155  				testInfo.InstallInfo = nil
   156  			})
   157  
   158  			It("returns an error", func() {
   159  				_, _, err := cei.CachedChaincodeInfo("channel-id", "name", fakeQueryExecutor)
   160  				Expect(err).To(MatchError("chaincode definition for 'name' exists, but chaincode is not installed"))
   161  			})
   162  		})
   163  
   164  		Context("when the cache does not match the current sequence", func() {
   165  			BeforeEach(func() {
   166  				testInfo.Definition.Sequence = 5
   167  			})
   168  
   169  			It("returns an error", func() {
   170  				_, _, err := cei.CachedChaincodeInfo("channel-id", "name", fakeQueryExecutor)
   171  				Expect(err).To(MatchError("chaincode cache at sequence 5 but current sequence is 7, chaincode definition for 'name' changed during invoke"))
   172  			})
   173  		})
   174  
   175  		Context("when the sequence cannot be fetched from the state", func() {
   176  			BeforeEach(func() {
   177  				fakeQueryExecutor.GetStateReturns(nil, fmt.Errorf("state-error"))
   178  			})
   179  
   180  			It("wraps and returns an error", func() {
   181  				_, _, err := cei.CachedChaincodeInfo("channel-id", "name", fakeQueryExecutor)
   182  				Expect(err).To(MatchError("could not get current sequence for chaincode 'name' on channel 'channel-id': could not get state for key namespaces/fields/name/Sequence: state-error"))
   183  			})
   184  		})
   185  
   186  		Context("when the query executor is nil", func() {
   187  			It("uses the dummy query executor and returns an error", func() {
   188  				_, _, err := cei.CachedChaincodeInfo("", "name", nil)
   189  				Expect(err).To(MatchError("could not get current sequence for chaincode 'name' on channel '': could not get state for key namespaces/fields/name/Sequence: invalid channel-less operation"))
   190  			})
   191  		})
   192  
   193  		Context("when running chaincode in devmode", func() {
   194  			BeforeEach(func() {
   195  				testInfo.InstallInfo = nil
   196  				cei.UserRunsCC = true
   197  			})
   198  
   199  			It("set chaincode installInfo to {chaincodeName}:{chaincodeVersion}", func() {
   200  				info, ok, err := cei.CachedChaincodeInfo("channel-id", "name", fakeQueryExecutor)
   201  				Expect(err).NotTo(HaveOccurred())
   202  				Expect(ok).To(BeTrue())
   203  				Expect(info).To(Equal(&lifecycle.LocalChaincodeInfo{
   204  					Definition: &lifecycle.ChaincodeDefinition{
   205  						Sequence: 7,
   206  						EndorsementInfo: &lb.ChaincodeEndorsementInfo{
   207  							Version:           "version",
   208  							EndorsementPlugin: "endorsement-plugin",
   209  						},
   210  						ValidationInfo: &lb.ChaincodeValidationInfo{
   211  							ValidationPlugin:    "validation-plugin",
   212  							ValidationParameter: []byte("validation-parameter"),
   213  						},
   214  					},
   215  					InstallInfo: &lifecycle.ChaincodeInstallInfo{
   216  						PackageID: "name:version",
   217  					},
   218  					Approved: true,
   219  				}))
   220  				Expect(fakeCache.ChaincodeInfoCallCount()).To(Equal(1))
   221  				channelID, chaincodeName := fakeCache.ChaincodeInfoArgsForCall(0)
   222  				Expect(channelID).To(Equal("channel-id"))
   223  				Expect(chaincodeName).To(Equal("name"))
   224  			})
   225  		})
   226  	})
   227  
   228  	Describe("ChaincodeEndorsementInfo", func() {
   229  		It("adapts the underlying lifecycle response", func() {
   230  			def, err := cei.ChaincodeEndorsementInfo("channel-id", "name", fakeQueryExecutor)
   231  			Expect(err).NotTo(HaveOccurred())
   232  			Expect(def).To(Equal(&lifecycle.ChaincodeEndorsementInfo{
   233  				Version:           "version",
   234  				EndorsementPlugin: "endorsement-plugin",
   235  				ChaincodeID:       "hash",
   236  			}))
   237  		})
   238  
   239  		Context("when the chaincode is a builtin system chaincode", func() {
   240  			BeforeEach(func() {
   241  				builtinSCCs["test-syscc-name"] = struct{}{}
   242  			})
   243  
   244  			It("returns a static definition", func() {
   245  				res, err := cei.ChaincodeEndorsementInfo("channel-id", "test-syscc-name", fakeQueryExecutor)
   246  				Expect(err).NotTo(HaveOccurred())
   247  				Expect(res).To(Equal(&lifecycle.ChaincodeEndorsementInfo{
   248  					Version:           "syscc",
   249  					ChaincodeID:       "test-syscc-name.syscc",
   250  					EndorsementPlugin: "escc",
   251  				}))
   252  			})
   253  		})
   254  
   255  		Context("when the cache returns an error", func() {
   256  			BeforeEach(func() {
   257  				fakeCache.ChaincodeInfoReturns(nil, fmt.Errorf("cache-error"))
   258  			})
   259  
   260  			It("returns the wrapped error", func() {
   261  				_, err := cei.ChaincodeEndorsementInfo("channel-id", "name", fakeQueryExecutor)
   262  				Expect(err).To(MatchError("could not get approved chaincode info from cache: cache-error"))
   263  			})
   264  		})
   265  
   266  		Context("when the chaincode is not defined in the new lifecycle", func() {
   267  			BeforeEach(func() {
   268  				delete(fakePublicState, "namespaces/fields/name/Sequence")
   269  				fakeLegacyImpl.ChaincodeEndorsementInfoReturns(&lifecycle.ChaincodeEndorsementInfo{
   270  					Version:           "legacy-version",
   271  					EndorsementPlugin: "legacy-plugin",
   272  					ChaincodeID:       "legacy-id",
   273  				}, fmt.Errorf("fake-error"))
   274  			})
   275  
   276  			It("passes through the legacy implementation", func() {
   277  				res, err := cei.ChaincodeEndorsementInfo("channel-id", "cc-name", fakeQueryExecutor)
   278  				Expect(err).To(MatchError("fake-error"))
   279  				Expect(res).To(Equal(&lifecycle.ChaincodeEndorsementInfo{
   280  					Version:           "legacy-version",
   281  					EndorsementPlugin: "legacy-plugin",
   282  					ChaincodeID:       "legacy-id",
   283  				}))
   284  				Expect(fakeLegacyImpl.ChaincodeEndorsementInfoCallCount()).To(Equal(1))
   285  				channelID, name, qe := fakeLegacyImpl.ChaincodeEndorsementInfoArgsForCall(0)
   286  				Expect(channelID).To(Equal("channel-id"))
   287  				Expect(name).To(Equal("cc-name"))
   288  				Expect(qe).To(Equal(fakeQueryExecutor))
   289  			})
   290  		})
   291  	})
   292  
   293  	Context("when LifecycleV20 capability is not enabled", func() {
   294  		var ccEndorsementInfo *lifecycle.ChaincodeEndorsementInfo
   295  
   296  		BeforeEach(func() {
   297  			ccEndorsementInfo = &lifecycle.ChaincodeEndorsementInfo{
   298  				Version:           "legacy-version",
   299  				EndorsementPlugin: "legacy-plugin",
   300  				ChaincodeID:       "legacy-id",
   301  			}
   302  			fakeCapabilities.LifecycleV20Returns(false)
   303  			fakeLegacyImpl.ChaincodeEndorsementInfoReturns(ccEndorsementInfo, nil)
   304  		})
   305  
   306  		It("returns the legacy chaincode info", func() {
   307  			res, err := cei.ChaincodeEndorsementInfo("channel-id", "cc-name", fakeQueryExecutor)
   308  			Expect(err).NotTo(HaveOccurred())
   309  			Expect(res).To(Equal(ccEndorsementInfo))
   310  			Expect(fakeLegacyImpl.ChaincodeEndorsementInfoCallCount()).To(Equal(1))
   311  			channelID, name, qe := fakeLegacyImpl.ChaincodeEndorsementInfoArgsForCall(0)
   312  			Expect(channelID).To(Equal("channel-id"))
   313  			Expect(name).To(Equal("cc-name"))
   314  			Expect(qe).To(Equal(fakeQueryExecutor))
   315  		})
   316  	})
   317  
   318  	Context("when channel config is not found", func() {
   319  		BeforeEach(func() {
   320  			fakeChannelConfigSource.GetStableChannelConfigReturns(nil)
   321  		})
   322  
   323  		It("returns not get channel config error", func() {
   324  			_, err := cei.ChaincodeEndorsementInfo("channel-id", "cc-name", fakeQueryExecutor)
   325  			Expect(err).To(MatchError("could not get channel config for channel 'channel-id'"))
   326  		})
   327  	})
   328  
   329  	Context("when application config is not found", func() {
   330  		BeforeEach(func() {
   331  			fakeChannelConfig.ApplicationConfigReturns(nil, false)
   332  		})
   333  
   334  		It("returns not get application config error", func() {
   335  			_, err := cei.ChaincodeEndorsementInfo("channel-id", "cc-name", fakeQueryExecutor)
   336  			Expect(err).To(MatchError("could not get application config for channel 'channel-id'"))
   337  		})
   338  	})
   339  })