Commit 4f903d92 authored by Senthil Nathan N's avatar Senthil Nathan N Committed by David Enyeart
Browse files

collACL: use cache to avoid repetative ACL check



This CR introduces a cache (i.e., Golang map) in the txContext
so that we can avoid repeating the same collection ACL check
for a given <ns, coll> during privateData access.

FAB-13040 #done

Change-Id: I3093c2079e78b2b349276a275b22e77d7bd9c871
Signed-off-by: default avatarsenthil <cendhu@gmail.com>
parent 2b966d17
......@@ -590,12 +590,26 @@ func errorIfCreatorHasNoReadAccess(chaincodeName, collection string, txContext *
}
func hasReadAccess(chaincodeName, collection string, txContext *TransactionContext) (bool, error) {
// check to see if read access has already been checked in the scope of this chaincode simulation
if txContext.AllowedCollectionAccess[collection] {
return true, nil
}
cc := common.CollectionCriteria{
Channel: txContext.ChainID,
Namespace: chaincodeName,
Collection: collection,
}
return txContext.CollectionStore.HasReadAccess(cc, txContext.SignedProp, txContext.TXSimulator)
accessAllowed, err := txContext.CollectionStore.HasReadAccess(cc, txContext.SignedProp, txContext.TXSimulator)
if err != nil {
return false, err
}
if accessAllowed {
txContext.AllowedCollectionAccess[collection] = accessAllowed
}
return accessAllowed, err
}
// Handles query to ledger to get state
......
......@@ -67,11 +67,12 @@ var _ = Describe("Handler", func() {
responseNotifier = make(chan *pb.ChaincodeMessage, 1)
txContext = &chaincode.TransactionContext{
ChainID: "channel-id",
TXSimulator: fakeTxSimulator,
HistoryQueryExecutor: fakeHistoryQueryExecutor,
ResponseNotifier: responseNotifier,
CollectionStore: fakeCollectionStore,
ChainID: "channel-id",
TXSimulator: fakeTxSimulator,
HistoryQueryExecutor: fakeHistoryQueryExecutor,
ResponseNotifier: responseNotifier,
CollectionStore: fakeCollectionStore,
AllowedCollectionAccess: make(map[string]bool),
}
fakeACLProvider = &mock.ACLProvider{}
......@@ -934,6 +935,25 @@ var _ = Describe("Handler", func() {
})
})
Context("and GetPrivateData returns the response message", func() {
BeforeEach(func() {
txContext.AllowedCollectionAccess["collection-name"] = true
fakeCollectionStore.HasReadAccessReturns(false, nil) // to
// ensure that the access cache is used
})
It("returns the the response message from GetPrivateData", func() {
resp, err := handler.HandleGetState(incomingMessage, txContext)
Expect(err).NotTo(HaveOccurred())
Expect(resp).To(Equal(&pb.ChaincodeMessage{
Type: pb.ChaincodeMessage_RESPONSE,
Payload: []byte("get-private-data-response"),
Txid: "tx-id",
ChannelId: "channel-id",
}))
})
})
It("returns the response message from GetPrivateData", func() {
resp, err := handler.HandleGetState(incomingMessage, txContext)
Expect(err).NotTo(HaveOccurred())
......
......@@ -29,6 +29,13 @@ type TransactionContext struct {
queryIteratorMap map[string]commonledger.ResultsIterator
pendingQueryResults map[string]*PendingQueryResult
totalReturnCount map[string]*int32
// cache used to save the result of collection acl
// as a transactionContext is created for every chaincode
// invoke (even in case of chaincode-calling-chaincode,
// we do not need to store the namespace in the map and
// collection alone is sufficient.
AllowedCollectionAccess map[string]bool
}
func (t *TransactionContext) InitializeQueryContext(queryID string, iter commonledger.ResultsIterator) {
......
......@@ -70,6 +70,8 @@ func (c *TransactionContexts) Create(txParams *ccprovider.TransactionParams) (*T
queryIteratorMap: map[string]commonledger.ResultsIterator{},
pendingQueryResults: map[string]*PendingQueryResult{},
AllowedCollectionAccess: make(map[string]bool),
}
c.contexts[ctxID] = txctx
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment