Commit 2b966d17 authored by Senthil Nathan N's avatar Senthil Nathan N
Browse files

collACL: perform ACL on private data access



using the simpleCollectionStore in transactionContext,
get the policy and evaluate it against the signedData to
decide whether a private data access should be allowed or not.

FAB-13039 #done

Change-Id: I9f66ae70aac5c439ec5dc943407c59d365ef5d84
Signed-off-by: default avatarsenthil <cendhu@gmail.com>
parent 4e17f53b
......@@ -11,6 +11,7 @@ import (
commonledger "github.com/hyperledger/fabric/common/ledger"
"github.com/hyperledger/fabric/core/chaincode"
"github.com/hyperledger/fabric/core/common/privdata"
"github.com/hyperledger/fabric/core/container/ccintf"
"github.com/hyperledger/fabric/core/ledger"
. "github.com/onsi/ginkgo"
......@@ -140,3 +141,8 @@ type registry interface {
type applicationConfigRetriever interface {
chaincode.ApplicationConfigRetriever
}
//go:generate counterfeiter -o mock/collection_store.go --fake-name CollectionStore . collectionStore
type collectionStore interface {
privdata.CollectionStore
}
......@@ -26,6 +26,7 @@ import (
"github.com/hyperledger/fabric/core/ledger"
"github.com/hyperledger/fabric/core/ledger/ledgerconfig"
"github.com/hyperledger/fabric/core/peer"
"github.com/hyperledger/fabric/protos/common"
pb "github.com/hyperledger/fabric/protos/peer"
"github.com/pkg/errors"
)
......@@ -576,6 +577,27 @@ func (h *Handler) checkMetadataCap(msg *pb.ChaincodeMessage) error {
return nil
}
func errorIfCreatorHasNoReadAccess(chaincodeName, collection string, txContext *TransactionContext) error {
accessAllowed, err := hasReadAccess(chaincodeName, collection, txContext)
if err != nil {
return err
}
if !accessAllowed {
return errors.Errorf("tx creator does not have read access permission on privatedata in chaincodeName:%s collectionName: %s",
chaincodeName, collection)
}
return nil
}
func hasReadAccess(chaincodeName, collection string, txContext *TransactionContext) (bool, error) {
cc := common.CollectionCriteria{
Channel: txContext.ChainID,
Namespace: chaincodeName,
Collection: collection,
}
return txContext.CollectionStore.HasReadAccess(cc, txContext.SignedProp, txContext.TXSimulator)
}
// Handles query to ledger to get state
func (h *Handler) HandleGetState(msg *pb.ChaincodeMessage, txContext *TransactionContext) (*pb.ChaincodeMessage, error) {
getState := &pb.GetState{}
......@@ -584,12 +606,16 @@ func (h *Handler) HandleGetState(msg *pb.ChaincodeMessage, txContext *Transactio
return nil, errors.Wrap(err, "unmarshal failed")
}
var res []byte
chaincodeName := h.ChaincodeName()
collection := getState.Collection
chaincodeLogger.Debugf("[%s] getting state for chaincode %s, key %s, channel %s", shorttxid(msg.Txid), chaincodeName, getState.Key, txContext.ChainID)
var res []byte
if isCollectionSet(getState.Collection) {
res, err = txContext.TXSimulator.GetPrivateData(chaincodeName, getState.Collection, getState.Key)
if isCollectionSet(collection) {
if err := errorIfCreatorHasNoReadAccess(chaincodeName, collection, txContext); err != nil {
return nil, err
}
res, err = txContext.TXSimulator.GetPrivateData(chaincodeName, collection, getState.Key)
} else {
res, err = txContext.TXSimulator.GetState(chaincodeName, getState.Key)
}
......@@ -618,11 +644,15 @@ func (h *Handler) HandleGetStateMetadata(msg *pb.ChaincodeMessage, txContext *Tr
}
chaincodeName := h.ChaincodeName()
collection := getStateMetadata.Collection
chaincodeLogger.Debugf("[%s] getting state metadata for chaincode %s, key %s, channel %s", shorttxid(msg.Txid), chaincodeName, getStateMetadata.Key, txContext.ChainID)
var metadata map[string][]byte
if isCollectionSet(getStateMetadata.Collection) {
metadata, err = txContext.TXSimulator.GetPrivateDataMetadata(chaincodeName, getStateMetadata.Collection, getStateMetadata.Key)
if isCollectionSet(collection) {
if err := errorIfCreatorHasNoReadAccess(chaincodeName, collection, txContext); err != nil {
return nil, err
}
metadata, err = txContext.TXSimulator.GetPrivateDataMetadata(chaincodeName, collection, getStateMetadata.Key)
} else {
metadata, err = txContext.TXSimulator.GetStateMetadata(chaincodeName, getStateMetadata.Key)
}
......@@ -659,15 +689,19 @@ func (h *Handler) HandleGetStateByRange(msg *pb.ChaincodeMessage, txContext *Tra
totalReturnLimit := calculateTotalReturnLimit(metadata)
iterID := h.UUIDGenerator.New()
chaincodeName := h.ChaincodeName()
var rangeIter commonledger.ResultsIterator
var paginationInfo map[string]interface{}
isPaginated := false
if isCollectionSet(getStateByRange.Collection) {
rangeIter, err = txContext.TXSimulator.GetPrivateDataRangeScanIterator(chaincodeName, getStateByRange.Collection,
chaincodeName := h.ChaincodeName()
collection := getStateByRange.Collection
if isCollectionSet(collection) {
if err := errorIfCreatorHasNoReadAccess(chaincodeName, collection, txContext); err != nil {
return nil, err
}
rangeIter, err = txContext.TXSimulator.GetPrivateDataRangeScanIterator(chaincodeName, collection,
getStateByRange.StartKey, getStateByRange.EndKey)
} else if isMetadataSetForPagination(metadata) {
paginationInfo, err = createPaginationInfoFromMetadata(metadata, totalReturnLimit, pb.ChaincodeMessage_GET_STATE_BY_RANGE)
......@@ -764,7 +798,6 @@ func (h *Handler) HandleQueryStateClose(msg *pb.ChaincodeMessage, txContext *Tra
// Handles query to ledger to execute query state
func (h *Handler) HandleGetQueryResult(msg *pb.ChaincodeMessage, txContext *TransactionContext) (*pb.ChaincodeMessage, error) {
iterID := h.UUIDGenerator.New()
chaincodeName := h.ChaincodeName()
getQueryResult := &pb.GetQueryResult{}
err := proto.Unmarshal(msg.Payload, getQueryResult)
......@@ -783,8 +816,13 @@ func (h *Handler) HandleGetQueryResult(msg *pb.ChaincodeMessage, txContext *Tran
var executeIter commonledger.ResultsIterator
var paginationInfo map[string]interface{}
if isCollectionSet(getQueryResult.Collection) {
executeIter, err = txContext.TXSimulator.ExecuteQueryOnPrivateData(chaincodeName, getQueryResult.Collection, getQueryResult.Query)
chaincodeName := h.ChaincodeName()
collection := getQueryResult.Collection
if isCollectionSet(collection) {
if err := errorIfCreatorHasNoReadAccess(chaincodeName, collection, txContext); err != nil {
return nil, err
}
executeIter, err = txContext.TXSimulator.ExecuteQueryOnPrivateData(chaincodeName, collection, getQueryResult.Query)
} else if isMetadataSetForPagination(metadata) {
paginationInfo, err = createPaginationInfoFromMetadata(metadata, totalReturnLimit, pb.ChaincodeMessage_GET_QUERY_RESULT)
if err != nil {
......@@ -952,8 +990,9 @@ func (h *Handler) HandlePutState(msg *pb.ChaincodeMessage, txContext *Transactio
}
chaincodeName := h.ChaincodeName()
if isCollectionSet(putState.Collection) {
err = txContext.TXSimulator.SetPrivateData(chaincodeName, putState.Collection, putState.Key, putState.Value)
collection := putState.Collection
if isCollectionSet(collection) {
err = txContext.TXSimulator.SetPrivateData(chaincodeName, collection, putState.Key, putState.Value)
} else {
err = txContext.TXSimulator.SetState(chaincodeName, putState.Key, putState.Value)
}
......@@ -980,8 +1019,9 @@ func (h *Handler) HandlePutStateMetadata(msg *pb.ChaincodeMessage, txContext *Tr
metadata[putStateMetadata.Metadata.Metakey] = putStateMetadata.Metadata.Value
chaincodeName := h.ChaincodeName()
if isCollectionSet(putStateMetadata.Collection) {
err = txContext.TXSimulator.SetPrivateDataMetadata(chaincodeName, putStateMetadata.Collection, putStateMetadata.Key, metadata)
collection := putStateMetadata.Collection
if isCollectionSet(collection) {
err = txContext.TXSimulator.SetPrivateDataMetadata(chaincodeName, collection, putStateMetadata.Key, metadata)
} else {
err = txContext.TXSimulator.SetStateMetadata(chaincodeName, putStateMetadata.Key, metadata)
}
......@@ -1000,8 +1040,9 @@ func (h *Handler) HandleDelState(msg *pb.ChaincodeMessage, txContext *Transactio
}
chaincodeName := h.ChaincodeName()
if isCollectionSet(delState.Collection) {
err = txContext.TXSimulator.DeletePrivateData(chaincodeName, delState.Collection, delState.Key)
collection := delState.Collection
if isCollectionSet(collection) {
err = txContext.TXSimulator.DeletePrivateData(chaincodeName, collection, delState.Key)
} else {
err = txContext.TXSimulator.DeleteState(chaincodeName, delState.Key)
}
......
......@@ -43,6 +43,7 @@ var _ = Describe("Handler", func() {
fakeLedgerGetter *mock.LedgerGetter
fakeHandlerRegistry *fake.Registry
fakeApplicationConfigRetriever *fake.ApplicationConfigRetriever
fakeCollectionStore *mock.CollectionStore
fakeShimRequestsReceived *metricsfakes.Counter
fakeShimRequestsCompleted *metricsfakes.Counter
fakeShimRequestDuration *metricsfakes.Histogram
......@@ -62,12 +63,15 @@ var _ = Describe("Handler", func() {
fakeTxSimulator = &mock.TxSimulator{}
fakeHistoryQueryExecutor = &mock.HistoryQueryExecutor{}
fakeCollectionStore = &mock.CollectionStore{}
responseNotifier = make(chan *pb.ChaincodeMessage, 1)
txContext = &chaincode.TransactionContext{
ChainID: "channel-id",
TXSimulator: fakeTxSimulator,
HistoryQueryExecutor: fakeHistoryQueryExecutor,
ResponseNotifier: responseNotifier,
CollectionStore: fakeCollectionStore,
}
fakeACLProvider = &mock.ACLProvider{}
......@@ -879,6 +883,7 @@ var _ = Describe("Handler", func() {
Expect(err).NotTo(HaveOccurred())
incomingMessage.Payload = payload
fakeCollectionStore.HasReadAccessReturns(true, nil)
fakeTxSimulator.GetPrivateDataReturns([]byte("get-private-data-response"), nil)
expectedResponse.Payload = []byte("get-private-data-response")
})
......@@ -894,7 +899,7 @@ var _ = Describe("Handler", func() {
Expect(key).To(Equal("get-state-key"))
})
Context("and GetPrivateData fails", func() {
Context("and GetPrivateData fails due to ledger error", func() {
BeforeEach(func() {
fakeTxSimulator.GetPrivateDataReturns(nil, errors.New("french fries"))
})
......@@ -905,6 +910,30 @@ var _ = Describe("Handler", func() {
})
})
Context("and GetPrivateData fails due to no read access", func() {
BeforeEach(func() {
fakeCollectionStore.HasReadAccessReturns(false, nil)
})
It("returns the error from errorIfCreatorHasNoReadAccess", func() {
_, err := handler.HandleGetState(incomingMessage, txContext)
Expect(err).To(MatchError("tx creator does not have read access" +
" permission on privatedata in chaincodeName:cc-instance-name" +
" collectionName: collection-name"))
})
})
Context("and GetPrivateData fails due to error in checking the read access", func() {
BeforeEach(func() {
fakeCollectionStore.HasReadAccessReturns(false, errors.New("no collection config"))
})
It("returns the error from errorIfCreatorHasNoReadAccess", func() {
_, err := handler.HandleGetState(incomingMessage, txContext)
Expect(err).To(MatchError("no collection config"))
})
})
It("returns the response message from GetPrivateData", func() {
resp, err := handler.HandleGetState(incomingMessage, txContext)
Expect(err).NotTo(HaveOccurred())
......@@ -1040,6 +1069,7 @@ var _ = Describe("Handler", func() {
metadata := map[string][]byte{
"get-state-metakey": []byte("get-private-metadata-response"),
}
fakeCollectionStore.HasReadAccessReturns(true, nil)
fakeTxSimulator.GetPrivateDataMetadataReturns(metadata, nil)
responsePayload, err := proto.Marshal(&pb.StateMetadataResult{
Entries: []*pb.StateMetadata{{
......@@ -1068,7 +1098,7 @@ var _ = Describe("Handler", func() {
Expect(resp).To(Equal(expectedResponse))
})
Context("and GetPrivateDataMetadata fails", func() {
Context("and GetPrivateDataMetadata fails due to ledger error", func() {
BeforeEach(func() {
fakeTxSimulator.GetPrivateDataMetadataReturns(nil, errors.New("french fries"))
})
......@@ -1078,6 +1108,30 @@ var _ = Describe("Handler", func() {
Expect(err).To(MatchError("french fries"))
})
})
Context("and GetPrivateDataMetadata fails due to no read access", func() {
BeforeEach(func() {
fakeCollectionStore.HasReadAccessReturns(false, nil)
})
It("returns the error from GetPrivateDataMetadata", func() {
_, err := handler.HandleGetStateMetadata(incomingMessage, txContext)
Expect(err).To(MatchError("tx creator does not have read access" +
" permission on privatedata in chaincodeName:cc-instance-name" +
" collectionName: collection-name"))
})
})
Context("and GetPrivateDataMetadata fails due to error in checking the read access", func() {
BeforeEach(func() {
fakeCollectionStore.HasReadAccessReturns(false, errors.New("no collection config"))
})
It("returns the error from GetPrivateDataMetadata", func() {
_, err := handler.HandleGetStateMetadata(incomingMessage, txContext)
Expect(err).To(MatchError("no collection config"))
})
})
})
Context("when collection is not set", func() {
......@@ -1226,6 +1280,7 @@ var _ = Describe("Handler", func() {
Expect(err).NotTo(HaveOccurred())
incomingMessage.Payload = payload
fakeCollectionStore.HasReadAccessReturns(true, nil)
fakeTxSimulator.GetPrivateDataRangeScanIteratorReturns(fakeIterator, nil)
})
......@@ -1241,7 +1296,7 @@ var _ = Describe("Handler", func() {
Expect(endKey).To(Equal("get-state-end-key"))
})
Context("and GetPrivateDataRangeScanIterator fails", func() {
Context("and GetPrivateDataRangeScanIterator fails due to ledger error", func() {
BeforeEach(func() {
fakeTxSimulator.GetPrivateDataRangeScanIteratorReturns(nil, errors.New("french fries"))
})
......@@ -1251,6 +1306,30 @@ var _ = Describe("Handler", func() {
Expect(err).To(MatchError("french fries"))
})
})
Context("and GetPrivateDataRangeScanIterator fails due to no read access", func() {
BeforeEach(func() {
fakeCollectionStore.HasReadAccessReturns(false, nil)
})
It("returns the error from GetPrivateDataRangeScanIterator", func() {
_, err := handler.HandleGetStateByRange(incomingMessage, txContext)
Expect(err).To(MatchError("tx creator does not have read access" +
" permission on privatedata in chaincodeName:cc-instance-name" +
" collectionName: collection-name"))
})
})
Context("and GetPrivateDataRangeScanIterator fails due to error in checking the read access", func() {
BeforeEach(func() {
fakeCollectionStore.HasReadAccessReturns(false, errors.New("no collection config"))
})
It("returns the error from GetPrivateDataRangeScanIterator", func() {
_, err := handler.HandleGetStateByRange(incomingMessage, txContext)
Expect(err).To(MatchError("no collection config"))
})
})
})
Context("when unmarshalling the request fails", func() {
......@@ -1560,6 +1639,7 @@ var _ = Describe("Handler", func() {
Expect(err).NotTo(HaveOccurred())
incomingMessage.Payload = payload
fakeCollectionStore.HasReadAccessReturns(true, nil)
fakeTxSimulator.ExecuteQueryOnPrivateDataReturns(fakeIterator, nil)
})
......@@ -1586,7 +1666,7 @@ var _ = Describe("Handler", func() {
Expect(*retCount).To(Equal(int32(0)))
})
Context("and ExecuteQueryOnPrivateData fails", func() {
Context("and ExecuteQueryOnPrivateData fails due to ledger error", func() {
BeforeEach(func() {
fakeTxSimulator.ExecuteQueryOnPrivateDataReturns(nil, errors.New("pizza"))
})
......@@ -1596,6 +1676,30 @@ var _ = Describe("Handler", func() {
Expect(err).To(MatchError("pizza"))
})
})
Context("and ExecuteQueryOnPrivateData fails due to no read access", func() {
BeforeEach(func() {
fakeCollectionStore.HasReadAccessReturns(false, nil)
})
It("returns the error", func() {
_, err := handler.HandleGetQueryResult(incomingMessage, txContext)
Expect(err).To(MatchError("tx creator does not have read access" +
" permission on privatedata in chaincodeName:cc-instance-name" +
" collectionName: collection-name"))
})
})
Context("and ExecuteQueryOnPrivateData fails due to error in checking the read access", func() {
BeforeEach(func() {
fakeCollectionStore.HasReadAccessReturns(false, errors.New("no collection config"))
})
It("returns the error", func() {
_, err := handler.HandleGetQueryResult(incomingMessage, txContext)
Expect(err).To(MatchError("no collection config"))
})
})
})
It("builds the query response", func() {
......
// Code generated by counterfeiter. DO NOT EDIT.
package mock
import (
sync "sync"
privdata "github.com/hyperledger/fabric/core/common/privdata"
ledger "github.com/hyperledger/fabric/core/ledger"
common "github.com/hyperledger/fabric/protos/common"
peer "github.com/hyperledger/fabric/protos/peer"
)
type CollectionStore struct {
AccessFilterStub func(string, *common.CollectionPolicyConfig) (privdata.Filter, error)
accessFilterMutex sync.RWMutex
accessFilterArgsForCall []struct {
arg1 string
arg2 *common.CollectionPolicyConfig
}
accessFilterReturns struct {
result1 privdata.Filter
result2 error
}
accessFilterReturnsOnCall map[int]struct {
result1 privdata.Filter
result2 error
}
HasReadAccessStub func(common.CollectionCriteria, *peer.SignedProposal, ledger.QueryExecutor) (bool, error)
hasReadAccessMutex sync.RWMutex
hasReadAccessArgsForCall []struct {
arg1 common.CollectionCriteria
arg2 *peer.SignedProposal
arg3 ledger.QueryExecutor
}
hasReadAccessReturns struct {
result1 bool
result2 error
}
hasReadAccessReturnsOnCall map[int]struct {
result1 bool
result2 error
}
RetrieveCollectionStub func(common.CollectionCriteria) (privdata.Collection, error)
retrieveCollectionMutex sync.RWMutex
retrieveCollectionArgsForCall []struct {
arg1 common.CollectionCriteria
}
retrieveCollectionReturns struct {
result1 privdata.Collection
result2 error
}
retrieveCollectionReturnsOnCall map[int]struct {
result1 privdata.Collection
result2 error
}
RetrieveCollectionAccessPolicyStub func(common.CollectionCriteria) (privdata.CollectionAccessPolicy, error)
retrieveCollectionAccessPolicyMutex sync.RWMutex
retrieveCollectionAccessPolicyArgsForCall []struct {
arg1 common.CollectionCriteria
}
retrieveCollectionAccessPolicyReturns struct {
result1 privdata.CollectionAccessPolicy
result2 error
}
retrieveCollectionAccessPolicyReturnsOnCall map[int]struct {
result1 privdata.CollectionAccessPolicy
result2 error
}
RetrieveCollectionConfigPackageStub func(common.CollectionCriteria) (*common.CollectionConfigPackage, error)
retrieveCollectionConfigPackageMutex sync.RWMutex
retrieveCollectionConfigPackageArgsForCall []struct {
arg1 common.CollectionCriteria
}
retrieveCollectionConfigPackageReturns struct {
result1 *common.CollectionConfigPackage
result2 error
}
retrieveCollectionConfigPackageReturnsOnCall map[int]struct {
result1 *common.CollectionConfigPackage
result2 error
}
RetrieveCollectionPersistenceConfigsStub func(common.CollectionCriteria) (privdata.CollectionPersistenceConfigs, error)
retrieveCollectionPersistenceConfigsMutex sync.RWMutex
retrieveCollectionPersistenceConfigsArgsForCall []struct {
arg1 common.CollectionCriteria
}
retrieveCollectionPersistenceConfigsReturns struct {
result1 privdata.CollectionPersistenceConfigs
result2 error
}
retrieveCollectionPersistenceConfigsReturnsOnCall map[int]struct {
result1 privdata.CollectionPersistenceConfigs
result2 error
}
invocations map[string][][]interface{}
invocationsMutex sync.RWMutex
}
func (fake *CollectionStore) AccessFilter(arg1 string, arg2 *common.CollectionPolicyConfig) (privdata.Filter, error) {
fake.accessFilterMutex.Lock()
ret, specificReturn := fake.accessFilterReturnsOnCall[len(fake.accessFilterArgsForCall)]
fake.accessFilterArgsForCall = append(fake.accessFilterArgsForCall, struct {
arg1 string
arg2 *common.CollectionPolicyConfig
}{arg1, arg2})
fake.recordInvocation("AccessFilter", []interface{}{arg1, arg2})
fake.accessFilterMutex.Unlock()
if fake.AccessFilterStub != nil {
return fake.AccessFilterStub(arg1, arg2)
}
if specificReturn {
return ret.result1, ret.result2
}
fakeReturns := fake.accessFilterReturns
return fakeReturns.result1, fakeReturns.result2
}
func (fake *CollectionStore) AccessFilterCallCount() int {
fake.accessFilterMutex.RLock()
defer fake.accessFilterMutex.RUnlock()
return len(fake.accessFilterArgsForCall)
}
func (fake *CollectionStore) AccessFilterCalls(stub func(string, *common.CollectionPolicyConfig) (privdata.Filter, error)) {
fake.accessFilterMutex.Lock()
defer fake.accessFilterMutex.Unlock()
fake.AccessFilterStub = stub
}
func (fake *CollectionStore) AccessFilterArgsForCall(i int) (string, *common.CollectionPolicyConfig) {
fake.accessFilterMutex.RLock()
defer fake.accessFilterMutex.RUnlock()
argsForCall := fake.accessFilterArgsForCall[i]
return argsForCall.arg1, argsForCall.arg2
}
func (fake *CollectionStore) AccessFilterReturns(result1 privdata.Filter, result2 error) {
fake.accessFilterMutex.Lock()
defer fake.accessFilterMutex.Unlock()
fake.AccessFilterStub = nil
fake.accessFilterReturns = struct {
result1 privdata.Filter
result2 error
}{result1, result2}
}
func (fake *CollectionStore) AccessFilterReturnsOnCall(i int, result1 privdata.Filter, result2 error) {
fake.accessFilterMutex.Lock()
defer fake.accessFilterMutex.Unlock()
fake.AccessFilterStub = nil
if fake.accessFilterReturnsOnCall == nil {
fake.accessFilterReturnsOnCall = make(map[int]struct {
result1 privdata.Filter
result2 error
})
}
fake.accessFilterReturnsOnCall[i] = struct {
result1 privdata.Filter
result2 error
}{result1, result2}
}
func (fake *CollectionStore) HasReadAccess(arg1 common.CollectionCriteria, arg2 *peer.SignedProposal, arg3 ledger.QueryExecutor) (bool, error) {
fake.hasReadAccessMutex.Lock()
ret, specificReturn := fake.hasReadAccessReturnsOnCall[len(fake.hasReadAccessArgsForCall)]
fake.hasReadAccessArgsForCall = append(fake.hasReadAccessArgsForCall, struct {
arg1 common.CollectionCriteria
arg2 *peer.SignedProposal
arg3 ledger.QueryExecutor
}{arg1, arg2, arg3})
fake.recordInvocation("HasReadAccess", []interface{}{arg1, arg2, arg3})
fake.hasReadAccessMutex.Unlock()
if fake.HasReadAccessStub != nil {
return fake.HasReadAccessStub(arg1, arg2, arg3)
}
if specificReturn {
return ret.result1, ret.result2
}
fakeReturns := fake.hasReadAccessReturns
return fakeReturns.result1, fakeReturns.result2
}
func (fake *CollectionStore) HasReadAccessCallCount() int {
fake.hasReadAccessMutex.RLock()
defer fake.hasReadAccessMutex.RUnlock()
return len(fake.hasReadAccessArgsForCall)
}
func (fake *CollectionStore) HasReadAccessCalls(stub func(common.CollectionCriteria, *peer.SignedProposal, ledger.QueryExecutor) (bool, error)) {
fake.hasReadAccessMutex.Lock()
defer fake.hasReadAccessMutex.Unlock()
fake.HasReadAccessStub = stub
}
func (fake *CollectionStore) HasReadAccessArgsForCall(i int) (common.CollectionCriteria, *peer.SignedProposal, ledger.QueryExecutor) {
fake.hasReadAccessMutex.RLock()
defer fake.hasReadAccessMutex.RUnlock()
argsForCall := fake.hasReadAccessArgsForCall[i]
return argsForCall.arg1, argsForCall.arg2, argsForCall.arg3
}
func (fake *CollectionStore) HasReadAccessReturns(result1 bool, result2 error) {
fake.hasReadAccessMutex.Lock()
defer fake.hasReadAccessMutex.Unlock()
fake.HasReadAccessStub = nil
fake.hasReadAccessReturns = struct {
result1 bool
result2 error
}{result1, result2}
}
func (fake *CollectionStore) HasReadAccessReturnsOnCall(i int, result1 bool, result2 error) {
fake.hasReadAccessMutex.Lock()
defer fake.hasReadAccessMutex.Unlock()
fake.HasReadAccessStub = nil
if fake.hasReadAccessReturnsOnCall == nil {
fake.hasReadAccessReturnsOnCall = make(map[int]struct {
result1 bool
result2 error
})